xref: /titanic_44/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c (revision b819cea2f73f98c5662230cc9affc8cc84f77fcf)
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.
231ed6b69aSGordon Ross  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw /*
27da6c28aaSamw  * Utility functions to support the RPC interface library.
28da6c28aaSamw  */
29da6c28aaSamw 
30da6c28aaSamw #include <stdio.h>
31da6c28aaSamw #include <stdarg.h>
32da6c28aaSamw #include <strings.h>
33da6c28aaSamw #include <unistd.h>
34da6c28aaSamw #include <netdb.h>
35da6c28aaSamw #include <stdlib.h>
36da6c28aaSamw #include <sys/time.h>
37da6c28aaSamw #include <sys/systm.h>
38*b819cea2SGordon Ross #include <note.h>
39fc724630SAlan Wright #include <syslog.h>
40da6c28aaSamw 
41da6c28aaSamw #include <smbsrv/libsmb.h>
42da6c28aaSamw #include <smbsrv/libsmbns.h>
43da6c28aaSamw #include <smbsrv/libmlsvc.h>
441ed6b69aSGordon Ross #include <smbsrv/ntaccess.h>
45da6c28aaSamw #include <smbsrv/smbinfo.h>
46ed9aabc7SGordon Ross #include <libsmbrdr.h>
478d7e4166Sjose borrego #include <lsalib.h>
488d7e4166Sjose borrego #include <samlib.h>
498d7e4166Sjose borrego #include <smbsrv/netrauth.h>
50da6c28aaSamw 
51da6c28aaSamw extern int netr_open(char *, char *, mlsvc_handle_t *);
52da6c28aaSamw extern int netr_close(mlsvc_handle_t *);
53da6c28aaSamw extern DWORD netlogon_auth(char *, mlsvc_handle_t *, DWORD);
54da6c28aaSamw 
551ed6b69aSGordon Ross static DWORD
561ed6b69aSGordon Ross mlsvc_join_rpc(smb_domainex_t *dxi,
571ed6b69aSGordon Ross 	char *admin_user, char *admin_pw,
581ed6b69aSGordon Ross 	char *machine_name, char *machine_pw);
591ed6b69aSGordon Ross static DWORD
601ed6b69aSGordon Ross mlsvc_join_noauth(smb_domainex_t *dxi,
611ed6b69aSGordon Ross 	char *machine_name, char *machine_pw);
621ed6b69aSGordon Ross 
631ed6b69aSGordon Ross 
64faa1795aSjb150015 DWORD
mlsvc_netlogon(char * server,char * domain)65faa1795aSjb150015 mlsvc_netlogon(char *server, char *domain)
66faa1795aSjb150015 {
67faa1795aSjb150015 	mlsvc_handle_t netr_handle;
68faa1795aSjb150015 	DWORD status;
69faa1795aSjb150015 
70faa1795aSjb150015 	if (netr_open(server, domain, &netr_handle) == 0) {
71fc724630SAlan Wright 		if ((status = netlogon_auth(server, &netr_handle,
72fc724630SAlan Wright 		    NETR_FLG_INIT)) != NT_STATUS_SUCCESS)
73fc724630SAlan Wright 			syslog(LOG_NOTICE, "Failed to establish NETLOGON "
74fc724630SAlan Wright 			    "credential chain");
75faa1795aSjb150015 		(void) netr_close(&netr_handle);
76faa1795aSjb150015 	} else {
771ed6b69aSGordon Ross 		syslog(LOG_NOTICE, "Failed to connect to %s "
781ed6b69aSGordon Ross 		    "for domain %s", server, domain);
791ed6b69aSGordon Ross 		status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
80faa1795aSjb150015 	}
81faa1795aSjb150015 
82faa1795aSjb150015 	return (status);
83faa1795aSjb150015 }
84faa1795aSjb150015 
85da6c28aaSamw /*
861ed6b69aSGordon Ross  * Join the specified domain.  The method varies depending on whether
871ed6b69aSGordon Ross  * we're using "secure join" (using an administrative account to join)
881ed6b69aSGordon Ross  * or "unsecure join" (using a pre-created machine account).  In the
891ed6b69aSGordon Ross  * latter case, the machine account is created "by hand" before this
901ed6b69aSGordon Ross  * machine attempts to join, and we just change the password from the
911ed6b69aSGordon Ross  * (weak) default password for a new machine account to a random one.
92eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  *
931ed6b69aSGordon Ross  * Note that the caller has already done "DC discovery" and passes the
941ed6b69aSGordon Ross  * domain info. in the first arg.
95da6c28aaSamw  *
96da6c28aaSamw  * Returns NT status codes.
97da6c28aaSamw  */
98da6c28aaSamw DWORD
mlsvc_join(smb_domainex_t * dxi,char * admin_user,char * admin_pw)991ed6b69aSGordon Ross mlsvc_join(smb_domainex_t *dxi, char *admin_user, char *admin_pw)
100da6c28aaSamw {
1011ed6b69aSGordon Ross 	char machine_name[SMB_SAMACCT_MAXLEN];
1021ed6b69aSGordon Ross 	char machine_pw[NETR_MACHINE_ACCT_PASSWD_MAX];
1031ed6b69aSGordon Ross 	unsigned char passwd_hash[SMBAUTH_HASH_SZ];
1041ed6b69aSGordon Ross 	smb_domain_t *di = &dxi->d_primary;
105da6c28aaSamw 	DWORD status;
1061ed6b69aSGordon Ross 	int rc;
107da6c28aaSamw 
1081ed6b69aSGordon Ross 	/*
1091ed6b69aSGordon Ross 	 * Domain join support: AD (Kerberos+LDAP) or MS-RPC?
1101ed6b69aSGordon Ross 	 * Leave the AD code path disabled until it can be
1111ed6b69aSGordon Ross 	 * fixed up so that the SMB server is in complete
1121ed6b69aSGordon Ross 	 * control of which AD server we talk to.  See:
1131ed6b69aSGordon Ross 	 * NX 12427 (Re-enable Kerberos+LDAP with...)
1141ed6b69aSGordon Ross 	 */
1151ed6b69aSGordon Ross 	boolean_t ads_enabled = smb_config_get_ads_enable();
116da6c28aaSamw 
1171ed6b69aSGordon Ross 	if (smb_getsamaccount(machine_name, sizeof (machine_name)) != 0)
1181ed6b69aSGordon Ross 		return (NT_STATUS_INTERNAL_ERROR);
119da6c28aaSamw 
1201ed6b69aSGordon Ross 	(void) smb_gen_random_passwd(machine_pw, sizeof (machine_pw));
121eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
1221ed6b69aSGordon Ross 	/*
1231ed6b69aSGordon Ross 	 * A non-null user means we do "secure join".
1241ed6b69aSGordon Ross 	 */
1251ed6b69aSGordon Ross 	if (admin_user != NULL && admin_user[0] != '\0') {
1261ed6b69aSGordon Ross 		/*
1271ed6b69aSGordon Ross 		 * Doing "secure join", so authenticate as the
1281ed6b69aSGordon Ross 		 * specified user (with admin. rights).
1291ed6b69aSGordon Ross 		 */
1301ed6b69aSGordon Ross 		(void) smb_auth_ntlm_hash(admin_pw, passwd_hash);
1311ed6b69aSGordon Ross 		smb_ipc_set(admin_user, passwd_hash);
132da6c28aaSamw 
1331ed6b69aSGordon Ross 		/*
1341ed6b69aSGordon Ross 		 * If enabled, try to join using AD Services.
1351ed6b69aSGordon Ross 		 * The ADS code needs work.  Not enabled yet.
1361ed6b69aSGordon Ross 		 */
137da6c28aaSamw 		status = NT_STATUS_UNSUCCESSFUL;
1381ed6b69aSGordon Ross 		if (ads_enabled) {
1391ed6b69aSGordon Ross 			smb_adjoin_status_t err;
1401ed6b69aSGordon Ross 			err = smb_ads_join(di->di_fqname,
1411ed6b69aSGordon Ross 			    admin_user, admin_pw, machine_pw);
1421ed6b69aSGordon Ross 			if (err != SMB_ADJOIN_SUCCESS) {
1431ed6b69aSGordon Ross 				smb_ads_join_errmsg(err);
144da6c28aaSamw 			} else {
1451ed6b69aSGordon Ross 				status = NT_STATUS_SUCCESS;
146da6c28aaSamw 			}
147da6c28aaSamw 		}
148da6c28aaSamw 
1491ed6b69aSGordon Ross 		/*
1501ed6b69aSGordon Ross 		 * If ADS was disabled or gave an error,
1511ed6b69aSGordon Ross 		 * fall-back and try to join using RPC.
1521ed6b69aSGordon Ross 		 */
1531ed6b69aSGordon Ross 		if (status != NT_STATUS_SUCCESS) {
1541ed6b69aSGordon Ross 			status = mlsvc_join_rpc(dxi,
1551ed6b69aSGordon Ross 			    admin_user, admin_pw,
1561ed6b69aSGordon Ross 			    machine_name, machine_pw);
1571ed6b69aSGordon Ross 		}
1581ed6b69aSGordon Ross 
1591ed6b69aSGordon Ross 	} else {
1601ed6b69aSGordon Ross 		/*
1611ed6b69aSGordon Ross 		 * Doing "Unsecure join" (pre-created account)
1621ed6b69aSGordon Ross 		 */
1631ed6b69aSGordon Ross 		bzero(passwd_hash, sizeof (passwd_hash));
1641ed6b69aSGordon Ross 		smb_ipc_set(MLSVC_ANON_USER, passwd_hash);
1651ed6b69aSGordon Ross 
1661ed6b69aSGordon Ross 		status = mlsvc_join_noauth(dxi, machine_name, machine_pw);
1671ed6b69aSGordon Ross 	}
1681ed6b69aSGordon Ross 
1691ed6b69aSGordon Ross 	if (status != NT_STATUS_SUCCESS)
1701ed6b69aSGordon Ross 		goto out;
1711ed6b69aSGordon Ross 
1721ed6b69aSGordon Ross 	/*
1731ed6b69aSGordon Ross 	 * Make sure we can authenticate using the
1741ed6b69aSGordon Ross 	 * (new, or updated) machine account.
1751ed6b69aSGordon Ross 	 */
1761ed6b69aSGordon Ross 	(void) smb_auth_ntlm_hash(machine_pw, passwd_hash);
1771ed6b69aSGordon Ross 	smb_ipc_set(machine_name, passwd_hash);
1781ed6b69aSGordon Ross 	rc = smbrdr_logon(dxi->d_dc, di->di_nbname, machine_name);
1791ed6b69aSGordon Ross 	if (rc != 0) {
1801ed6b69aSGordon Ross 		syslog(LOG_NOTICE, "Authenticate with "
1811ed6b69aSGordon Ross 		    "new/updated machine account: %s",
1821ed6b69aSGordon Ross 		    strerror(rc));
1831ed6b69aSGordon Ross 		status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1841ed6b69aSGordon Ross 		goto out;
1851ed6b69aSGordon Ross 	}
1861ed6b69aSGordon Ross 
1871ed6b69aSGordon Ross 	/*
1881ed6b69aSGordon Ross 	 * Store the new machine account password.
1891ed6b69aSGordon Ross 	 */
1901ed6b69aSGordon Ross 	rc = smb_setdomainprops(NULL, dxi->d_dc, machine_pw);
1911ed6b69aSGordon Ross 	if (rc != 0) {
1929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		syslog(LOG_NOTICE,
1931ed6b69aSGordon Ross 		    "Failed to save machine account password");
1941ed6b69aSGordon Ross 		status = NT_STATUS_INTERNAL_DB_ERROR;
1951ed6b69aSGordon Ross 		goto out;
196fc724630SAlan Wright 	}
197da6c28aaSamw 
1981ed6b69aSGordon Ross 	/*
1991ed6b69aSGordon Ross 	 * Update idmap config
2001ed6b69aSGordon Ross 	 */
2011ed6b69aSGordon Ross 	if (smb_config_set_idmap_domain(di->di_fqname) != 0)
2021ed6b69aSGordon Ross 		syslog(LOG_NOTICE, "Failed to set idmap domain name");
2031ed6b69aSGordon Ross 	if (smb_config_refresh_idmap() != 0)
2041ed6b69aSGordon Ross 		syslog(LOG_NOTICE, "Failed to refresh idmap service");
2051ed6b69aSGordon Ross 
2061ed6b69aSGordon Ross 	/*
2071ed6b69aSGordon Ross 	 * Note: The caller (smbd) saves the "secmode" and
2081ed6b69aSGordon Ross 	 * domain info (via smb_config_setdomaininfo) and
2091ed6b69aSGordon Ross 	 * and does smb_ipc_commit (or rollback).
2101ed6b69aSGordon Ross 	 */
2111ed6b69aSGordon Ross 	status = 0;
2121ed6b69aSGordon Ross 
2131ed6b69aSGordon Ross out:
2141ed6b69aSGordon Ross 	/* Avoid leaving cleartext passwords around. */
2151ed6b69aSGordon Ross 	bzero(machine_pw, sizeof (machine_pw));
2161ed6b69aSGordon Ross 	bzero(passwd_hash, sizeof (passwd_hash));
2171ed6b69aSGordon Ross 
2181ed6b69aSGordon Ross 	return (status);
219da6c28aaSamw }
220da6c28aaSamw 
2211ed6b69aSGordon Ross static DWORD
mlsvc_join_rpc(smb_domainex_t * dxi,char * admin_user,char * admin_pw,char * machine_name,char * machine_pw)2221ed6b69aSGordon Ross mlsvc_join_rpc(smb_domainex_t *dxi,
2231ed6b69aSGordon Ross 	char *admin_user, char *admin_pw,
2241ed6b69aSGordon Ross 	char *machine_name,  char *machine_pw)
2251ed6b69aSGordon Ross {
2261ed6b69aSGordon Ross 	mlsvc_handle_t samr_handle;
2271ed6b69aSGordon Ross 	mlsvc_handle_t domain_handle;
2281ed6b69aSGordon Ross 	mlsvc_handle_t user_handle;
2291ed6b69aSGordon Ross 	smb_account_t ainfo;
2301ed6b69aSGordon Ross 	char *server = dxi->d_dc;
2311ed6b69aSGordon Ross 	smb_domain_t *di = &dxi->d_primary;
2321ed6b69aSGordon Ross 	DWORD account_flags;
2331ed6b69aSGordon Ross 	DWORD rid;
2341ed6b69aSGordon Ross 	DWORD status;
2351ed6b69aSGordon Ross 	int rc;
2361ed6b69aSGordon Ross 
2371ed6b69aSGordon Ross 	/* Caller did smb_ipc_set() so we don't need the pw for now. */
2381ed6b69aSGordon Ross 	_NOTE(ARGUNUSED(admin_pw));
2391ed6b69aSGordon Ross 
2401ed6b69aSGordon Ross 	rc = samr_open(server, di->di_nbname, admin_user,
2411ed6b69aSGordon Ross 	    MAXIMUM_ALLOWED, &samr_handle);
2421ed6b69aSGordon Ross 	if (rc != 0) {
2431ed6b69aSGordon Ross 		syslog(LOG_NOTICE, "sam_connect to server %s failed", server);
2441ed6b69aSGordon Ross 		return (RPC_NT_SERVER_UNAVAILABLE);
2451ed6b69aSGordon Ross 	}
2461ed6b69aSGordon Ross 	/* have samr_handle */
2471ed6b69aSGordon Ross 
2481ed6b69aSGordon Ross 	status = samr_open_domain(&samr_handle, MAXIMUM_ALLOWED,
2491ed6b69aSGordon Ross 	    (struct samr_sid *)di->di_binsid, &domain_handle);
2501ed6b69aSGordon Ross 	if (status != NT_STATUS_SUCCESS)
2511ed6b69aSGordon Ross 		goto out_samr_handle;
2521ed6b69aSGordon Ross 	/* have domain_handle */
2531ed6b69aSGordon Ross 
2541ed6b69aSGordon Ross 	account_flags = SAMR_AF_WORKSTATION_TRUST_ACCOUNT;
2551ed6b69aSGordon Ross 	status = samr_create_user(&domain_handle, machine_name,
2561ed6b69aSGordon Ross 	    account_flags, &rid, &user_handle);
2571ed6b69aSGordon Ross 	if (status == NT_STATUS_USER_EXISTS) {
2581ed6b69aSGordon Ross 		status = samr_lookup_domain_names(&domain_handle,
2591ed6b69aSGordon Ross 		    machine_name, &ainfo);
2601ed6b69aSGordon Ross 		if (status != NT_STATUS_SUCCESS)
2611ed6b69aSGordon Ross 			goto out_domain_handle;
2621ed6b69aSGordon Ross 		status = samr_open_user(&domain_handle, MAXIMUM_ALLOWED,
2631ed6b69aSGordon Ross 		    ainfo.a_rid, &user_handle);
2641ed6b69aSGordon Ross 	}
2651ed6b69aSGordon Ross 	if (status != NT_STATUS_SUCCESS) {
2661ed6b69aSGordon Ross 		syslog(LOG_NOTICE,
2671ed6b69aSGordon Ross 		    "Create or open machine account: %s",
2681ed6b69aSGordon Ross 		    xlate_nt_status(status));
2691ed6b69aSGordon Ross 		goto out_domain_handle;
2701ed6b69aSGordon Ross 	}
2711ed6b69aSGordon Ross 
2721ed6b69aSGordon Ross 	/*
2731ed6b69aSGordon Ross 	 * The account exists, and we have user_handle open
2741ed6b69aSGordon Ross 	 * on that account.  Set the password and flags.
2751ed6b69aSGordon Ross 	 */
2761ed6b69aSGordon Ross 
2771ed6b69aSGordon Ross 	status = netr_set_user_password(&user_handle, machine_pw);
2781ed6b69aSGordon Ross 	if (status != NT_STATUS_SUCCESS) {
2791ed6b69aSGordon Ross 		syslog(LOG_NOTICE,
2801ed6b69aSGordon Ross 		    "Set machine account password: %s",
2811ed6b69aSGordon Ross 		    xlate_nt_status(status));
2821ed6b69aSGordon Ross 		goto out_user_handle;
2831ed6b69aSGordon Ross 	}
2841ed6b69aSGordon Ross 
2851ed6b69aSGordon Ross 	account_flags |= SAMR_AF_DONT_EXPIRE_PASSWD;
2861ed6b69aSGordon Ross 	status = netr_set_user_control(&user_handle, account_flags);
2871ed6b69aSGordon Ross 	if (status != NT_STATUS_SUCCESS) {
2881ed6b69aSGordon Ross 		syslog(LOG_NOTICE,
2891ed6b69aSGordon Ross 		    "Set machine account control flags: %s",
2901ed6b69aSGordon Ross 		    xlate_nt_status(status));
2911ed6b69aSGordon Ross 		goto out_user_handle;
2921ed6b69aSGordon Ross 	}
2931ed6b69aSGordon Ross 
2941ed6b69aSGordon Ross out_user_handle:
2951ed6b69aSGordon Ross 	(void) samr_close_handle(&user_handle);
2961ed6b69aSGordon Ross out_domain_handle:
2971ed6b69aSGordon Ross 	(void) samr_close_handle(&domain_handle);
2981ed6b69aSGordon Ross out_samr_handle:
2991ed6b69aSGordon Ross 	(void) samr_close_handle(&samr_handle);
3001ed6b69aSGordon Ross 
3011ed6b69aSGordon Ross 	return (status);
3021ed6b69aSGordon Ross }
3031ed6b69aSGordon Ross 
3041ed6b69aSGordon Ross /*
3051ed6b69aSGordon Ross  * Doing "Unsecure join" (using a pre-created machine account).
3061ed6b69aSGordon Ross  * All we need to do is change the password from the default
3071ed6b69aSGordon Ross  * to a random string.
3081ed6b69aSGordon Ross  *
3091ed6b69aSGordon Ross  * Note: this is a work in progres.  Nexenta issue 11960
3101ed6b69aSGordon Ross  * (allow joining an AD domain using a pre-created computer account)
3111ed6b69aSGordon Ross  * It turns out that to change the machine account password,
3121ed6b69aSGordon Ross  * we need to use a different RPC call, performed over the
3131ed6b69aSGordon Ross  * NetLogon secure channel.  (See netr_server_password_set2)
3141ed6b69aSGordon Ross  */
3151ed6b69aSGordon Ross static DWORD
mlsvc_join_noauth(smb_domainex_t * dxi,char * machine_name,char * machine_pw)3161ed6b69aSGordon Ross mlsvc_join_noauth(smb_domainex_t *dxi,
3171ed6b69aSGordon Ross 	char *machine_name, char *machine_pw)
3181ed6b69aSGordon Ross {
3191ed6b69aSGordon Ross 	char old_pw[SMB_SAMACCT_MAXLEN];
3201ed6b69aSGordon Ross 	DWORD status;
3211ed6b69aSGordon Ross 
3221ed6b69aSGordon Ross 	/*
3231ed6b69aSGordon Ross 	 * Compose the current (default) password for the
3241ed6b69aSGordon Ross 	 * pre-created machine account, which is just the
3251ed6b69aSGordon Ross 	 * account name in lower case, truncated to 14
3261ed6b69aSGordon Ross 	 * characters.
3271ed6b69aSGordon Ross 	 */
3281ed6b69aSGordon Ross 	if (smb_gethostname(old_pw, sizeof (old_pw), SMB_CASE_LOWER) != 0)
3291ed6b69aSGordon Ross 		return (NT_STATUS_INTERNAL_ERROR);
3301ed6b69aSGordon Ross 	old_pw[14] = '\0';
3311ed6b69aSGordon Ross 
3321ed6b69aSGordon Ross 	status = netr_change_password(dxi->d_dc, machine_name,
3331ed6b69aSGordon Ross 	    old_pw, machine_pw);
3341ed6b69aSGordon Ross 	if (status != NT_STATUS_SUCCESS) {
3351ed6b69aSGordon Ross 		syslog(LOG_NOTICE,
3361ed6b69aSGordon Ross 		    "Change machine account password: %s",
3371ed6b69aSGordon Ross 		    xlate_nt_status(status));
3381ed6b69aSGordon Ross 	}
339da6c28aaSamw 	return (status);
340da6c28aaSamw }
341a0aa776eSAlan Wright 
342a0aa776eSAlan Wright void
mlsvc_disconnect(const char * server)343a0aa776eSAlan Wright mlsvc_disconnect(const char *server)
344a0aa776eSAlan Wright {
345a0aa776eSAlan Wright 	smbrdr_disconnect(server);
346a0aa776eSAlan Wright }
347