1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
221fdeec65Sjoyce mcintosh  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23adee6784SGordon Ross  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
246a23a4b8SGordon Ross  * Copyright 2021 RackTop Systems, Inc.
25da6c28aaSamw  */
26da6c28aaSamw 
27da6c28aaSamw /*
28da6c28aaSamw  * Utility functions to support the RPC interface library.
29da6c28aaSamw  */
30da6c28aaSamw 
31da6c28aaSamw #include <stdio.h>
32da6c28aaSamw #include <stdarg.h>
33da6c28aaSamw #include <strings.h>
34da6c28aaSamw #include <unistd.h>
35da6c28aaSamw #include <netdb.h>
36da6c28aaSamw #include <stdlib.h>
37da6c28aaSamw #include <sys/time.h>
38da6c28aaSamw #include <sys/systm.h>
39b819cea2SGordon Ross #include <note.h>
40fc724630SAlan Wright #include <syslog.h>
41da6c28aaSamw 
42da6c28aaSamw #include <smbsrv/libsmb.h>
43da6c28aaSamw #include <smbsrv/libsmbns.h>
44da6c28aaSamw #include <smbsrv/libmlsvc.h>
45adee6784SGordon Ross #include <smb/ntaccess.h>
46da6c28aaSamw #include <smbsrv/smbinfo.h>
47b3700b07SGordon Ross #include <smbsrv/netrauth.h>
48ed9aabc7SGordon Ross #include <libsmbrdr.h>
498d7e4166Sjose borrego #include <lsalib.h>
508d7e4166Sjose borrego #include <samlib.h>
51b3700b07SGordon Ross #include <mlsvc.h>
52da6c28aaSamw 
531ed6b69aSGordon Ross static DWORD
541ed6b69aSGordon Ross mlsvc_join_rpc(smb_domainex_t *dxi,
556a23a4b8SGordon Ross     char *admin_user, char *admin_pw,
566a23a4b8SGordon Ross     char *machine_name, char *machine_pw);
571ed6b69aSGordon Ross static DWORD
581ed6b69aSGordon Ross mlsvc_join_noauth(smb_domainex_t *dxi,
596a23a4b8SGordon Ross     char *machine_name, char *machine_pw);
601ed6b69aSGordon Ross 
61975041ddSGordon Ross /*
62975041ddSGordon Ross  * This is called by smbd_dc_update just after we've learned about a
63975041ddSGordon Ross  * new domain controller.  Make sure we can authenticate with this DC.
64975041ddSGordon Ross  */
65faa1795aSjb DWORD
mlsvc_netlogon(char * server,char * domain)66faa1795aSjb mlsvc_netlogon(char *server, char *domain)
67faa1795aSjb {
68faa1795aSjb 	DWORD status;
69faa1795aSjb 
70975041ddSGordon Ross 	status = smb_netlogon_check(server, domain);
71b3700b07SGordon Ross 	if (status != NT_STATUS_SUCCESS) {
72b3700b07SGordon Ross 		syslog(LOG_NOTICE, "Failed to establish NETLOGON "
73b3700b07SGordon Ross 		    "credential chain with DC: %s (%s)", server,
74b3700b07SGordon Ross 		    xlate_nt_status(status));
75b3700b07SGordon Ross 		syslog(LOG_NOTICE, "The machine account information on the "
76b3700b07SGordon Ross 		    "domain controller does not match the local storage.");
77b3700b07SGordon Ross 		syslog(LOG_NOTICE, "To correct this, use 'smbadm join'");
78b3700b07SGordon Ross 	}
79b3700b07SGordon Ross 
80faa1795aSjb 	return (status);
81faa1795aSjb }
82faa1795aSjb 
83da6c28aaSamw /*
841ed6b69aSGordon Ross  * Join the specified domain.  The method varies depending on whether
851ed6b69aSGordon Ross  * we're using "secure join" (using an administrative account to join)
861ed6b69aSGordon Ross  * or "unsecure join" (using a pre-created machine account).  In the
871ed6b69aSGordon Ross  * latter case, the machine account is created "by hand" before this
881ed6b69aSGordon Ross  * machine attempts to join, and we just change the password from the
891ed6b69aSGordon Ross  * (weak) default password for a new machine account to a random one.
90eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  *
91da6c28aaSamw  * Returns NT status codes.
92da6c28aaSamw  */
93b3700b07SGordon Ross void
mlsvc_join(smb_joininfo_t * info,smb_joinres_t * res)94b3700b07SGordon Ross mlsvc_join(smb_joininfo_t *info, smb_joinres_t *res)
95da6c28aaSamw {
96b3700b07SGordon Ross 	static unsigned char zero_hash[SMBAUTH_HASH_SZ];
971ed6b69aSGordon Ross 	char machine_name[SMB_SAMACCT_MAXLEN];
981ed6b69aSGordon Ross 	char machine_pw[NETR_MACHINE_ACCT_PASSWD_MAX];
991ed6b69aSGordon Ross 	unsigned char passwd_hash[SMBAUTH_HASH_SZ];
1006a23a4b8SGordon Ross 	char addrbuf[INET6_ADDRSTRLEN];
101b3700b07SGordon Ross 	smb_domainex_t dxi;
102b3700b07SGordon Ross 	smb_domain_t *di = &dxi.d_primary;
103*857c33c4SGordon Ross 	char *container;
104*857c33c4SGordon Ross 	char *username;
105da6c28aaSamw 	DWORD status;
1061ed6b69aSGordon Ross 	int rc;
107da6c28aaSamw 
108b3700b07SGordon Ross 	bzero(&dxi, sizeof (dxi));
109b3700b07SGordon Ross 
110*857c33c4SGordon Ross 	if (info->container_name[0] != '\0')
111*857c33c4SGordon Ross 		container = info->container_name;
112*857c33c4SGordon Ross 	else
113*857c33c4SGordon Ross 		container = NULL;
114*857c33c4SGordon Ross 	if (info->domain_username[0] != '\0')
115*857c33c4SGordon Ross 		username = info->domain_username;
116*857c33c4SGordon Ross 	else
117*857c33c4SGordon Ross 		username = NULL;
118*857c33c4SGordon Ross 
1191ed6b69aSGordon Ross 	/*
1201ed6b69aSGordon Ross 	 * Domain join support: AD (Kerberos+LDAP) or MS-RPC?
1211ed6b69aSGordon Ross 	 */
1221ed6b69aSGordon Ross 	boolean_t ads_enabled = smb_config_get_ads_enable();
123da6c28aaSamw 
124b3700b07SGordon Ross 	if (smb_getsamaccount(machine_name, sizeof (machine_name)) != 0) {
125b3700b07SGordon Ross 		res->status = NT_STATUS_INVALID_COMPUTER_NAME;
126b3700b07SGordon Ross 		return;
127b3700b07SGordon Ross 	}
128eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
1291ed6b69aSGordon Ross 	(void) smb_gen_random_passwd(machine_pw, sizeof (machine_pw));
130da6c28aaSamw 
1311ed6b69aSGordon Ross 	/*
132b3700b07SGordon Ross 	 * Ensure that any previous membership of this domain has
133b3700b07SGordon Ross 	 * been cleared from the environment before we start. This
134b3700b07SGordon Ross 	 * will ensure that we don't attempt a NETLOGON_SAMLOGON
135b3700b07SGordon Ross 	 * when attempting to find the PDC.
1361ed6b69aSGordon Ross 	 */
137b3700b07SGordon Ross 	(void) smb_config_setbool(SMB_CI_DOMAIN_MEMB, B_FALSE);
138b3700b07SGordon Ross 
139*857c33c4SGordon Ross 	if (username != NULL) {
140b3700b07SGordon Ross 		(void) smb_auth_ntlm_hash(info->domain_passwd, passwd_hash);
141*857c33c4SGordon Ross 		smb_ipc_set(username, passwd_hash);
142*857c33c4SGordon Ross 		syslog(LOG_INFO, "smbd: joining with user %s", username);
143b3700b07SGordon Ross 	} else {
144b3700b07SGordon Ross 		smb_ipc_set(MLSVC_ANON_USER, zero_hash);
1456a23a4b8SGordon Ross 		syslog(LOG_INFO, "smbd: joining with anonymous");
146b3700b07SGordon Ross 	}
147b3700b07SGordon Ross 
148b3700b07SGordon Ross 	/*
149b3700b07SGordon Ross 	 * Tentatively set the idmap domain to the one we're joining,
150b3700b07SGordon Ross 	 * so that the DC locator in idmap knows what to look for.
151b3700b07SGordon Ross 	 * Ditto the SMB server domain.
152b3700b07SGordon Ross 	 */
153b3700b07SGordon Ross 	if (smb_config_set_idmap_domain(info->domain_name) != 0)
154b3700b07SGordon Ross 		syslog(LOG_NOTICE, "Failed to set idmap domain name");
155b3700b07SGordon Ross 	if (smb_config_refresh_idmap() != 0)
156b3700b07SGordon Ross 		syslog(LOG_NOTICE, "Failed to refresh idmap service");
1576a23a4b8SGordon Ross 	syslog(LOG_INFO, "smbd: set idmap domain %s", info->domain_name);
158b3700b07SGordon Ross 
159b3700b07SGordon Ross 	/* Clear DNS local (ADS) lookup cache. */
160b3700b07SGordon Ross 	smb_ads_refresh(B_FALSE);
161b3700b07SGordon Ross 
162b3700b07SGordon Ross 	/*
163b3700b07SGordon Ross 	 * Locate a DC for this domain.  Intentionally bypass the
164b3700b07SGordon Ross 	 * ddiscover service here because we're still joining.
165b3700b07SGordon Ross 	 * This also allows better reporting of any failures.
166b3700b07SGordon Ross 	 */
167b3700b07SGordon Ross 	status = smb_ads_lookup_msdcs(info->domain_name, &dxi.d_dci);
168b3700b07SGordon Ross 	if (status != NT_STATUS_SUCCESS) {
169b3700b07SGordon Ross 		syslog(LOG_ERR,
170b3700b07SGordon Ross 		    "smbd: failed to locate AD server for domain %s (%s)",
171b3700b07SGordon Ross 		    info->domain_name, xlate_nt_status(status));
172b3700b07SGordon Ross 		goto out;
173b3700b07SGordon Ross 	}
174b3700b07SGordon Ross 
175b3700b07SGordon Ross 	/*
176b3700b07SGordon Ross 	 * Found a DC.  Report what we found along with the return status
177b3700b07SGordon Ross 	 * so that admin will know which AD server we were talking to.
178b3700b07SGordon Ross 	 */
179b3700b07SGordon Ross 	(void) strlcpy(res->dc_name, dxi.d_dci.dc_name, MAXHOSTNAMELEN);
1806a23a4b8SGordon Ross 	if (smb_inet_ntop(&dxi.d_dci.dc_addr,
1816a23a4b8SGordon Ross 	    addrbuf, sizeof (addrbuf)) == NULL)
1826a23a4b8SGordon Ross 		strcpy(addrbuf, "?");
1836a23a4b8SGordon Ross 	syslog(LOG_INFO, "smbd: found AD server %s (%s)",
1846a23a4b8SGordon Ross 	    dxi.d_dci.dc_name, addrbuf);
185dc20a302Sas 
186b3700b07SGordon Ross 	/*
187b3700b07SGordon Ross 	 * Domain discovery needs to authenticate with the AD server.
188b3700b07SGordon Ross 	 * Disconnect any existing connection with the domain controller
189b3700b07SGordon Ross 	 * to make sure we won't use any prior authentication context
190b3700b07SGordon Ross 	 * our redirector might have.
191b3700b07SGordon Ross 	 */
192b3700b07SGordon Ross 	mlsvc_disconnect(dxi.d_dci.dc_name);
193b3700b07SGordon Ross 
194b3700b07SGordon Ross 	/*
195b3700b07SGordon Ross 	 * Get the domain policy info (domain SID etc).
196b3700b07SGordon Ross 	 * Here too, bypass the smb_ddiscover_service.
197b3700b07SGordon Ross 	 */
198b3700b07SGordon Ross 	status = smb_ddiscover_main(info->domain_name, &dxi);
199b3700b07SGordon Ross 	if (status != NT_STATUS_SUCCESS) {
200b3700b07SGordon Ross 		syslog(LOG_ERR,
201b3700b07SGordon Ross 		    "smbd: failed getting domain info for %s (%s)",
202b3700b07SGordon Ross 		    info->domain_name, xlate_nt_status(status));
203b3700b07SGordon Ross 		goto out;
204b3700b07SGordon Ross 	}
205b3700b07SGordon Ross 	/*
206b3700b07SGordon Ross 	 * After a successful smbd_ddiscover_main() call
207b3700b07SGordon Ross 	 * we should call smb_domain_save() to update the
208b3700b07SGordon Ross 	 * data shown by smbadm list.  Do that at the end,
209b3700b07SGordon Ross 	 * only if all goes well with joining the domain.
210b3700b07SGordon Ross 	 */
211b3700b07SGordon Ross 
2126a23a4b8SGordon Ross 	/*
2136a23a4b8SGordon Ross 	 * Log info about the domain from ddiscover
2146a23a4b8SGordon Ross 	 */
2156a23a4b8SGordon Ross 	syslog(LOG_INFO, "smbd_join: domain FQN=%s", di->di_fqname);
2166a23a4b8SGordon Ross 	syslog(LOG_INFO, "smbd_join: domain NBN=%s", di->di_nbname);
2176a23a4b8SGordon Ross 	syslog(LOG_INFO, "smbd_join: domain SID=%s", di->di_sid);
2186a23a4b8SGordon Ross 
219b3700b07SGordon Ross 	/*
220b3700b07SGordon Ross 	 * Create or update our machine account on the DC.
221b3700b07SGordon Ross 	 * A non-null user means we do "secure join".
222b3700b07SGordon Ross 	 */
223*857c33c4SGordon Ross 	if (username != NULL) {
2241ed6b69aSGordon Ross 		/*
2251ed6b69aSGordon Ross 		 * If enabled, try to join using AD Services.
2261ed6b69aSGordon Ross 		 */
2271ed6b69aSGordon Ross 		status = NT_STATUS_UNSUCCESSFUL;
2281ed6b69aSGordon Ross 		if (ads_enabled) {
2296a23a4b8SGordon Ross 			syslog(LOG_INFO, "use_ads=true (LDAP join)");
230*857c33c4SGordon Ross 			res->join_err = smb_ads_join(di->di_fqname, container,
231b3700b07SGordon Ross 			    info->domain_username, info->domain_passwd,
232b3700b07SGordon Ross 			    machine_pw);
233b3700b07SGordon Ross 			if (res->join_err == SMB_ADS_SUCCESS) {
2341ed6b69aSGordon Ross 				status = NT_STATUS_SUCCESS;
235da6c28aaSamw 			}
236b3700b07SGordon Ross 		} else {
2376a23a4b8SGordon Ross 			syslog(LOG_INFO, "use_ads=false (RPC join)");
238b3700b07SGordon Ross 
239b3700b07SGordon Ross 			/*
240b3700b07SGordon Ross 			 * If ADS was disabled, join using RPC.
241b3700b07SGordon Ross 			 */
242b3700b07SGordon Ross 			status = mlsvc_join_rpc(&dxi,
243b3700b07SGordon Ross 			    info->domain_username,
244b3700b07SGordon Ross 			    info->domain_passwd,
2451ed6b69aSGordon Ross 			    machine_name, machine_pw);
246da6c28aaSamw 		}
2471ed6b69aSGordon Ross 
248da6c28aaSamw 	} else {
2491ed6b69aSGordon Ross 		/*
2501ed6b69aSGordon Ross 		 * Doing "Unsecure join" (pre-created account)
2511ed6b69aSGordon Ross 		 */
252b3700b07SGordon Ross 		status = mlsvc_join_noauth(&dxi, machine_name, machine_pw);
253da6c28aaSamw 	}
254da6c28aaSamw 
2551ed6b69aSGordon Ross 	if (status != NT_STATUS_SUCCESS)
2561ed6b69aSGordon Ross 		goto out;
2571ed6b69aSGordon Ross 
2581ed6b69aSGordon Ross 	/*
2591ed6b69aSGordon Ross 	 * Make sure we can authenticate using the
2601ed6b69aSGordon Ross 	 * (new, or updated) machine account.
2611ed6b69aSGordon Ross 	 */
2621ed6b69aSGordon Ross 	(void) smb_auth_ntlm_hash(machine_pw, passwd_hash);
2631ed6b69aSGordon Ross 	smb_ipc_set(machine_name, passwd_hash);
264b3700b07SGordon Ross 	rc = smbrdr_logon(dxi.d_dci.dc_name, di->di_nbname, machine_name);
2651ed6b69aSGordon Ross 	if (rc != 0) {
2661ed6b69aSGordon Ross 		syslog(LOG_NOTICE, "Authenticate with "
2671ed6b69aSGordon Ross 		    "new/updated machine account: %s",
2681ed6b69aSGordon Ross 		    strerror(rc));
269b3700b07SGordon Ross 		res->join_err = SMB_ADJOIN_ERR_AUTH_NETLOGON;
2701ed6b69aSGordon Ross 		status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
2711ed6b69aSGordon Ross 		goto out;
2721ed6b69aSGordon Ross 	}
2731ed6b69aSGordon Ross 
2741ed6b69aSGordon Ross 	/*
275b3700b07SGordon Ross 	 * Store the new machine account password, and
276b3700b07SGordon Ross 	 * SMB_CI_DOMAIN_MEMB etc.
2771ed6b69aSGordon Ross 	 */
278b3700b07SGordon Ross 	rc = smb_setdomainprops(NULL, dxi.d_dci.dc_name, machine_pw);
2791ed6b69aSGordon Ross 	if (rc != 0) {
2801ed6b69aSGordon Ross 		syslog(LOG_NOTICE,
2811ed6b69aSGordon Ross 		    "Failed to save machine account password");
282b3700b07SGordon Ross 		res->join_err = SMB_ADJOIN_ERR_STORE_PROPS;
2831ed6b69aSGordon Ross 		status = NT_STATUS_INTERNAL_DB_ERROR;
2841ed6b69aSGordon Ross 		goto out;
2851ed6b69aSGordon Ross 	}
2861ed6b69aSGordon Ross 
2871ed6b69aSGordon Ross 	/*
288b3700b07SGordon Ross 	 * Update idmap config?
289b3700b07SGordon Ross 	 * Already set the domain_name above.
2901ed6b69aSGordon Ross 	 */
2911ed6b69aSGordon Ross 
2921ed6b69aSGordon Ross 	/*
293b3700b07SGordon Ross 	 * Save the SMB server config.  Sets: SMB_CI_DOMAIN_*
294b3700b07SGordon Ross 	 * Should unify SMB vs idmap configs.
2951ed6b69aSGordon Ross 	 */
296b3700b07SGordon Ross 	smb_config_setdomaininfo(di->di_nbname, di->di_fqname,
297b3700b07SGordon Ross 	    di->di_sid,
298b3700b07SGordon Ross 	    di->di_u.di_dns.ddi_forest,
299b3700b07SGordon Ross 	    di->di_u.di_dns.ddi_guid);
300b3700b07SGordon Ross 	smb_ipc_commit();
301b3700b07SGordon Ross 	smb_domain_save();
302b3700b07SGordon Ross 
3031ed6b69aSGordon Ross 	status = 0;
3041ed6b69aSGordon Ross 
3051ed6b69aSGordon Ross out:
306b3700b07SGordon Ross 
307b3700b07SGordon Ross 	if (status != 0) {
308b3700b07SGordon Ross 		/*
309b3700b07SGordon Ross 		 * Undo the tentative domain settings.
310b3700b07SGordon Ross 		 */
311b3700b07SGordon Ross 		(void) smb_config_set_idmap_domain("");
312b3700b07SGordon Ross 		(void) smb_config_refresh_idmap();
313b3700b07SGordon Ross 		smb_ipc_rollback();
314b3700b07SGordon Ross 	}
315b3700b07SGordon Ross 
3161ed6b69aSGordon Ross 	/* Avoid leaving cleartext passwords around. */
3171ed6b69aSGordon Ross 	bzero(machine_pw, sizeof (machine_pw));
3181ed6b69aSGordon Ross 	bzero(passwd_hash, sizeof (passwd_hash));
3191ed6b69aSGordon Ross 
320b3700b07SGordon Ross 	res->status = status;
3211ed6b69aSGordon Ross }
3221ed6b69aSGordon Ross 
3231ed6b69aSGordon Ross static DWORD
mlsvc_join_rpc(smb_domainex_t * dxi,char * admin_user,char * admin_pw,char * machine_name,char * machine_pw)3241ed6b69aSGordon Ross mlsvc_join_rpc(smb_domainex_t *dxi,
3256a23a4b8SGordon Ross     char *admin_user, char *admin_pw,
3266a23a4b8SGordon Ross     char *machine_name,  char *machine_pw)
3271ed6b69aSGordon Ross {
3281ed6b69aSGordon Ross 	mlsvc_handle_t samr_handle;
3291ed6b69aSGordon Ross 	mlsvc_handle_t domain_handle;
3301ed6b69aSGordon Ross 	mlsvc_handle_t user_handle;
3311ed6b69aSGordon Ross 	smb_account_t ainfo;
332b3700b07SGordon Ross 	char *server = dxi->d_dci.dc_name;
3331ed6b69aSGordon Ross 	smb_domain_t *di = &dxi->d_primary;
3341ed6b69aSGordon Ross 	DWORD account_flags;
3351ed6b69aSGordon Ross 	DWORD rid;
3361ed6b69aSGordon Ross 	DWORD status;
3371ed6b69aSGordon Ross 	int rc;
3381ed6b69aSGordon Ross 
3391ed6b69aSGordon Ross 	/* Caller did smb_ipc_set() so we don't need the pw for now. */
3401ed6b69aSGordon Ross 	_NOTE(ARGUNUSED(admin_pw));
3411ed6b69aSGordon Ross 
3421ed6b69aSGordon Ross 	rc = samr_open(server, di->di_nbname, admin_user,
3431ed6b69aSGordon Ross 	    MAXIMUM_ALLOWED, &samr_handle);
3441ed6b69aSGordon Ross 	if (rc != 0) {
3451ed6b69aSGordon Ross 		syslog(LOG_NOTICE, "sam_connect to server %s failed", server);
3461ed6b69aSGordon Ross 		return (RPC_NT_SERVER_UNAVAILABLE);
3471ed6b69aSGordon Ross 	}
3481ed6b69aSGordon Ross 	/* have samr_handle */
3491ed6b69aSGordon Ross 
3501ed6b69aSGordon Ross 	status = samr_open_domain(&samr_handle, MAXIMUM_ALLOWED,
3511ed6b69aSGordon Ross 	    (struct samr_sid *)di->di_binsid, &domain_handle);
3521ed6b69aSGordon Ross 	if (status != NT_STATUS_SUCCESS)
3531ed6b69aSGordon Ross 		goto out_samr_handle;
3541ed6b69aSGordon Ross 	/* have domain_handle */
3551ed6b69aSGordon Ross 
3561ed6b69aSGordon Ross 	account_flags = SAMR_AF_WORKSTATION_TRUST_ACCOUNT;
3571ed6b69aSGordon Ross 	status = samr_create_user(&domain_handle, machine_name,
3581ed6b69aSGordon Ross 	    account_flags, &rid, &user_handle);
3591ed6b69aSGordon Ross 	if (status == NT_STATUS_USER_EXISTS) {
3601ed6b69aSGordon Ross 		status = samr_lookup_domain_names(&domain_handle,
3611ed6b69aSGordon Ross 		    machine_name, &ainfo);
3621ed6b69aSGordon Ross 		if (status != NT_STATUS_SUCCESS)
3631ed6b69aSGordon Ross 			goto out_domain_handle;
3641ed6b69aSGordon Ross 		status = samr_open_user(&domain_handle, MAXIMUM_ALLOWED,
3651ed6b69aSGordon Ross 		    ainfo.a_rid, &user_handle);
3661ed6b69aSGordon Ross 	}
3671ed6b69aSGordon Ross 	if (status != NT_STATUS_SUCCESS) {
3681ed6b69aSGordon Ross 		syslog(LOG_NOTICE,
369b3700b07SGordon Ross 		    "smbd: failed to open machine account (%s)",
3701ed6b69aSGordon Ross 		    xlate_nt_status(status));
3711ed6b69aSGordon Ross 		goto out_domain_handle;
3721ed6b69aSGordon Ross 	}
3731ed6b69aSGordon Ross 
3741ed6b69aSGordon Ross 	/*
3751ed6b69aSGordon Ross 	 * The account exists, and we have user_handle open
3761ed6b69aSGordon Ross 	 * on that account.  Set the password and flags.
3771ed6b69aSGordon Ross 	 */
3781ed6b69aSGordon Ross 
3791ed6b69aSGordon Ross 	status = netr_set_user_password(&user_handle, machine_pw);
3801ed6b69aSGordon Ross 	if (status != NT_STATUS_SUCCESS) {
3811ed6b69aSGordon Ross 		syslog(LOG_NOTICE,
382b3700b07SGordon Ross 		    "smbd: failed to set machine account password (%s)",
3831ed6b69aSGordon Ross 		    xlate_nt_status(status));
3841ed6b69aSGordon Ross 		goto out_user_handle;
3851ed6b69aSGordon Ross 	}
3861ed6b69aSGordon Ross 
3871ed6b69aSGordon Ross 	account_flags |= SAMR_AF_DONT_EXPIRE_PASSWD;
3881ed6b69aSGordon Ross 	status = netr_set_user_control(&user_handle, account_flags);
3891ed6b69aSGordon Ross 	if (status != NT_STATUS_SUCCESS) {
3901ed6b69aSGordon Ross 		syslog(LOG_NOTICE,
3911ed6b69aSGordon Ross 		    "Set machine account control flags: %s",
3921ed6b69aSGordon Ross 		    xlate_nt_status(status));
3931ed6b69aSGordon Ross 		goto out_user_handle;
3941ed6b69aSGordon Ross 	}
3951ed6b69aSGordon Ross 
3961ed6b69aSGordon Ross out_user_handle:
3971ed6b69aSGordon Ross 	(void) samr_close_handle(&user_handle);
3981ed6b69aSGordon Ross out_domain_handle:
3991ed6b69aSGordon Ross 	(void) samr_close_handle(&domain_handle);
4001ed6b69aSGordon Ross out_samr_handle:
4011ed6b69aSGordon Ross 	(void) samr_close_handle(&samr_handle);
4021ed6b69aSGordon Ross 
4031ed6b69aSGordon Ross 	return (status);
4041ed6b69aSGordon Ross }
4051ed6b69aSGordon Ross 
4061ed6b69aSGordon Ross /*
4071ed6b69aSGordon Ross  * Doing "Unsecure join" (using a pre-created machine account).
4081ed6b69aSGordon Ross  * All we need to do is change the password from the default
4091ed6b69aSGordon Ross  * to a random string.
4101ed6b69aSGordon Ross  *
4111ed6b69aSGordon Ross  * Note: this is a work in progres.  Nexenta issue 11960
4121ed6b69aSGordon Ross  * (allow joining an AD domain using a pre-created computer account)
4131ed6b69aSGordon Ross  * It turns out that to change the machine account password,
4141ed6b69aSGordon Ross  * we need to use a different RPC call, performed over the
4151ed6b69aSGordon Ross  * NetLogon secure channel.  (See netr_server_password_set2)
4161ed6b69aSGordon Ross  */
4171ed6b69aSGordon Ross static DWORD
mlsvc_join_noauth(smb_domainex_t * dxi,char * machine_name,char * machine_pw)4181ed6b69aSGordon Ross mlsvc_join_noauth(smb_domainex_t *dxi,
4196a23a4b8SGordon Ross     char *machine_name, char *machine_pw)
4201ed6b69aSGordon Ross {
4211ed6b69aSGordon Ross 	char old_pw[SMB_SAMACCT_MAXLEN];
4221ed6b69aSGordon Ross 	DWORD status;
4231ed6b69aSGordon Ross 
4241ed6b69aSGordon Ross 	/*
4251ed6b69aSGordon Ross 	 * Compose the current (default) password for the
4261ed6b69aSGordon Ross 	 * pre-created machine account, which is just the
4271ed6b69aSGordon Ross 	 * account name in lower case, truncated to 14
4281ed6b69aSGordon Ross 	 * characters.
4291ed6b69aSGordon Ross 	 */
4301ed6b69aSGordon Ross 	if (smb_gethostname(old_pw, sizeof (old_pw), SMB_CASE_LOWER) != 0)
4311ed6b69aSGordon Ross 		return (NT_STATUS_INTERNAL_ERROR);
4321ed6b69aSGordon Ross 	old_pw[14] = '\0';
4331ed6b69aSGordon Ross 
434b3700b07SGordon Ross 	status = netr_change_password(dxi->d_dci.dc_name, machine_name,
4351ed6b69aSGordon Ross 	    old_pw, machine_pw);
4361ed6b69aSGordon Ross 	if (status != NT_STATUS_SUCCESS) {
4371ed6b69aSGordon Ross 		syslog(LOG_NOTICE,
4381ed6b69aSGordon Ross 		    "Change machine account password: %s",
4391ed6b69aSGordon Ross 		    xlate_nt_status(status));
4401ed6b69aSGordon Ross 	}
441da6c28aaSamw 	return (status);
442da6c28aaSamw }
443a0aa776eSAlan Wright 
444a0aa776eSAlan Wright void
mlsvc_disconnect(const char * server)445a0aa776eSAlan Wright mlsvc_disconnect(const char *server)
446a0aa776eSAlan Wright {
447a0aa776eSAlan Wright 	smbrdr_disconnect(server);
448a0aa776eSAlan Wright }
4493299f39fSGordon Ross 
4503299f39fSGordon Ross /*
4513299f39fSGordon Ross  * A few more helper functions for RPC services.
4523299f39fSGordon Ross  */
4533299f39fSGordon Ross 
4543299f39fSGordon Ross /*
4553299f39fSGordon Ross  * Check whether or not the specified user has administrator privileges,
4563299f39fSGordon Ross  * i.e. is a member of Domain Admins or Administrators.
4573299f39fSGordon Ross  * Returns true if the user is an administrator, otherwise returns false.
4583299f39fSGordon Ross  */
4593299f39fSGordon Ross boolean_t
ndr_is_admin(ndr_xa_t * xa)4603299f39fSGordon Ross ndr_is_admin(ndr_xa_t *xa)
4613299f39fSGordon Ross {
4623299f39fSGordon Ross 	smb_netuserinfo_t *ctx = xa->pipe->np_user;
4633299f39fSGordon Ross 
4643299f39fSGordon Ross 	return (ctx->ui_flags & SMB_ATF_ADMIN);
4653299f39fSGordon Ross }
4663299f39fSGordon Ross 
4673299f39fSGordon Ross /*
4683299f39fSGordon Ross  * Check whether or not the specified user has power-user privileges,
4693299f39fSGordon Ross  * i.e. is a member of Domain Admins, Administrators or Power Users.
4703299f39fSGordon Ross  * This is typically required for operations such as managing shares.
4713299f39fSGordon Ross  * Returns true if the user is a power user, otherwise returns false.
4723299f39fSGordon Ross  */
4733299f39fSGordon Ross boolean_t
ndr_is_poweruser(ndr_xa_t * xa)4743299f39fSGordon Ross ndr_is_poweruser(ndr_xa_t *xa)
4753299f39fSGordon Ross {
4763299f39fSGordon Ross 	smb_netuserinfo_t *ctx = xa->pipe->np_user;
4773299f39fSGordon Ross 
4783299f39fSGordon Ross 	return ((ctx->ui_flags & SMB_ATF_ADMIN) ||
4793299f39fSGordon Ross 	    (ctx->ui_flags & SMB_ATF_POWERUSER));
4803299f39fSGordon Ross }
4813299f39fSGordon Ross 
4823299f39fSGordon Ross int32_t
ndr_native_os(ndr_xa_t * xa)4833299f39fSGordon Ross ndr_native_os(ndr_xa_t *xa)
4843299f39fSGordon Ross {
4853299f39fSGordon Ross 	smb_netuserinfo_t *ctx = xa->pipe->np_user;
4863299f39fSGordon Ross 
4873299f39fSGordon Ross 	return (ctx->ui_native_os);
4883299f39fSGordon Ross }
489