xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c (revision 7961:4b5e3051f38b)
15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
215331Samw /*
225772Sas200622  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
235331Samw  * Use is subject to license terms.
245331Samw  */
255331Samw 
265331Samw /*
275331Samw  * Utility functions to support the RPC interface library.
285331Samw  */
295331Samw 
305331Samw #include <stdio.h>
315331Samw #include <stdarg.h>
325331Samw #include <strings.h>
335331Samw #include <unistd.h>
345331Samw #include <netdb.h>
355331Samw #include <stdlib.h>
365331Samw 
375331Samw #include <sys/time.h>
385331Samw #include <sys/systm.h>
395331Samw 
405331Samw #include <smbsrv/libsmb.h>
415331Samw #include <smbsrv/libsmbrdr.h>
425331Samw #include <smbsrv/libsmbns.h>
435331Samw #include <smbsrv/libmlsvc.h>
445331Samw 
455331Samw #include <smbsrv/smbinfo.h>
465331Samw #include <smbsrv/lsalib.h>
475331Samw #include <smbsrv/samlib.h>
485331Samw #include <smbsrv/mlsvc_util.h>
495331Samw #include <smbsrv/mlsvc.h>
505331Samw 
515772Sas200622 /* Domain join support (using MS-RPC) */
525772Sas200622 static boolean_t mlsvc_ntjoin_support = B_FALSE;
535772Sas200622 
545331Samw extern int netr_open(char *, char *, mlsvc_handle_t *);
555331Samw extern int netr_close(mlsvc_handle_t *);
565331Samw extern DWORD netlogon_auth(char *, mlsvc_handle_t *, DWORD);
575331Samw extern int mlsvc_user_getauth(char *, char *, smb_auth_info_t *);
585331Samw 
595331Samw /*
605331Samw  * Compare the supplied domain name with the local hostname.
615331Samw  * We need to deal with both server names and fully-qualified
625331Samw  * domain names.
635331Samw  *
645331Samw  * Returns:
655331Samw  *	0	The specified domain is not the local domain,
665331Samw  *	1	The Specified domain is the local domain.
675331Samw  *	-1	Invalid parameter or unable to get the local
685331Samw  *		system information.
695331Samw  */
705331Samw int
715331Samw mlsvc_is_local_domain(const char *domain)
725331Samw {
735331Samw 	char hostname[MAXHOSTNAMELEN];
745331Samw 	int rc;
755331Samw 
765772Sas200622 	if (smb_config_get_secmode() == SMB_SECMODE_WORKGRP)
775772Sas200622 		return (1);
785772Sas200622 
795331Samw 	if (strchr(domain, '.') != NULL)
805331Samw 		rc = smb_getfqhostname(hostname, MAXHOSTNAMELEN);
81*7961SNatalie.Li@Sun.COM 	else {
82*7961SNatalie.Li@Sun.COM 		if (strlen(domain) < NETBIOS_NAME_SZ)
83*7961SNatalie.Li@Sun.COM 			rc = smb_getnetbiosname(hostname, MAXHOSTNAMELEN);
84*7961SNatalie.Li@Sun.COM 		else
85*7961SNatalie.Li@Sun.COM 			rc = smb_gethostname(hostname, MAXHOSTNAMELEN, 1);
86*7961SNatalie.Li@Sun.COM 	}
875331Samw 
885331Samw 	if (rc != 0)
895331Samw 		return (-1);
905331Samw 
915772Sas200622 	if (strcasecmp(domain, hostname) == 0)
925331Samw 		return (1);
935331Samw 
945331Samw 	return (0);
955331Samw }
965331Samw 
975331Samw /*
985331Samw  * mlsvc_lookup_name
995331Samw  *
1005772Sas200622  * This is just a wrapper for lsa_lookup_name.
1015331Samw  *
1025772Sas200622  * The memory for the sid is allocated using malloc so the caller should
1035772Sas200622  * call free when it is no longer required.
1045331Samw  */
1055772Sas200622 uint32_t
1066432Sas200622 mlsvc_lookup_name(char *account, smb_sid_t **sid, uint16_t *sid_type)
1075331Samw {
1085772Sas200622 	smb_userinfo_t *ainfo;
1095772Sas200622 	uint32_t status;
1105331Samw 
1115772Sas200622 	if ((ainfo = mlsvc_alloc_user_info()) == NULL)
1125772Sas200622 		return (NT_STATUS_NO_MEMORY);
1135331Samw 
1145772Sas200622 	status = lsa_lookup_name(NULL, account, *sid_type, ainfo);
1155772Sas200622 	if (status == NT_STATUS_SUCCESS) {
1165772Sas200622 		*sid = ainfo->user_sid;
1175772Sas200622 		ainfo->user_sid = NULL;
1185772Sas200622 		*sid_type = ainfo->sid_name_use;
1195772Sas200622 	}
1205331Samw 
1215772Sas200622 	mlsvc_free_user_info(ainfo);
1225772Sas200622 	return (status);
1235331Samw }
1245331Samw 
1255331Samw /*
1265331Samw  * mlsvc_lookup_sid
1275331Samw  *
1285772Sas200622  * This is just a wrapper for lsa_lookup_sid.
1295772Sas200622  *
1305772Sas200622  * The allocated memory for the returned name must be freed by caller upon
1315772Sas200622  * successful return.
1325331Samw  */
1335772Sas200622 uint32_t
1346432Sas200622 mlsvc_lookup_sid(smb_sid_t *sid, char **name)
1355331Samw {
1365772Sas200622 	smb_userinfo_t *ainfo;
1375772Sas200622 	uint32_t status;
1385772Sas200622 	int namelen;
1395331Samw 
1405772Sas200622 	if ((ainfo = mlsvc_alloc_user_info()) == NULL)
1415772Sas200622 		return (NT_STATUS_NO_MEMORY);
1425331Samw 
1435772Sas200622 	status = lsa_lookup_sid(sid, ainfo);
1445772Sas200622 	if (status == NT_STATUS_SUCCESS) {
1455772Sas200622 		namelen = strlen(ainfo->domain_name) + strlen(ainfo->name) + 2;
1465772Sas200622 		if ((*name = malloc(namelen)) == NULL) {
1475772Sas200622 			mlsvc_free_user_info(ainfo);
1485772Sas200622 			return (NT_STATUS_NO_MEMORY);
1495331Samw 		}
1505772Sas200622 		(void) snprintf(*name, namelen, "%s\\%s",
1515772Sas200622 		    ainfo->domain_name, ainfo->name);
1525331Samw 	}
1535331Samw 
1545772Sas200622 	mlsvc_free_user_info(ainfo);
1555772Sas200622 	return (status);
1565331Samw }
1575331Samw 
1585331Samw /*
1595331Samw  * mlsvc_alloc_user_info
1605331Samw  *
1615331Samw  * Allocate a user_info structure and set the contents to zero. A
1625331Samw  * pointer to the user_info structure is returned.
1635331Samw  */
1645331Samw smb_userinfo_t *
1655331Samw mlsvc_alloc_user_info(void)
1665331Samw {
1675331Samw 	smb_userinfo_t *user_info;
1685331Samw 
1695331Samw 	user_info = (smb_userinfo_t *)malloc(sizeof (smb_userinfo_t));
1705331Samw 	if (user_info == NULL)
1715331Samw 		return (NULL);
1725331Samw 
1735331Samw 	bzero(user_info, sizeof (smb_userinfo_t));
1745331Samw 	return (user_info);
1755331Samw }
1765331Samw 
1775331Samw /*
1785331Samw  * mlsvc_free_user_info
1795331Samw  *
1805331Samw  * Free a user_info structure. This function ensures that the contents
1815331Samw  * of the user_info are freed as well as the user_info itself.
1825331Samw  */
1835331Samw void
1845331Samw mlsvc_free_user_info(smb_userinfo_t *user_info)
1855331Samw {
1865331Samw 	if (user_info) {
1875331Samw 		mlsvc_release_user_info(user_info);
1885331Samw 		free(user_info);
1895331Samw 	}
1905331Samw }
1915331Samw 
1925331Samw /*
1935331Samw  * mlsvc_release_user_info
1945331Samw  *
1955331Samw  * Release the contents of a user_info structure and zero out the
1965331Samw  * elements but do not free the user_info structure itself. This
1975331Samw  * function cleans out the structure so that it can be reused without
1985331Samw  * worrying about stale contents.
1995331Samw  */
2005331Samw void
2015331Samw mlsvc_release_user_info(smb_userinfo_t *user_info)
2025331Samw {
2035331Samw 	int i;
2045331Samw 
2055331Samw 	if (user_info == NULL)
2065331Samw 		return;
2075331Samw 
2085331Samw 	free(user_info->name);
2095331Samw 	free(user_info->domain_sid);
2105331Samw 	free(user_info->domain_name);
2115331Samw 	free(user_info->groups);
2125331Samw 
2135331Samw 	if (user_info->n_other_grps) {
2145331Samw 		for (i = 0; i < user_info->n_other_grps; i++)
2155331Samw 			free(user_info->other_grps[i].sid);
2165331Samw 
2175331Samw 		free(user_info->other_grps);
2185331Samw 	}
2195331Samw 
2206849Sjb150015 	free(user_info->session_key);
2215331Samw 	free(user_info->user_sid);
2225331Samw 	free(user_info->pgrp_sid);
2235331Samw 	bzero(user_info, sizeof (smb_userinfo_t));
2245331Samw }
2255331Samw 
2265331Samw /*
2275331Samw  * mlsvc_setadmin_user_info
2285331Samw  *
2295331Samw  * Determines if the given user is the domain Administrator or a
2305331Samw  * member of Domain Admins or Administrators group and set the
2315331Samw  * user_info->flags accordingly.
2325331Samw  */
2335331Samw void
2345331Samw mlsvc_setadmin_user_info(smb_userinfo_t *user_info)
2355331Samw {
2365331Samw 	nt_domain_t *domain;
2375772Sas200622 	smb_group_t grp;
2385772Sas200622 	int rc, i;
2395331Samw 
2405331Samw 	if ((domain = nt_domain_lookupbytype(NT_DOMAIN_PRIMARY)) == NULL)
2415331Samw 		return;
2425331Samw 
2436432Sas200622 	if (!smb_sid_cmp((smb_sid_t *)user_info->domain_sid, domain->sid))
2445331Samw 		return;
2455331Samw 
2465331Samw 	if (user_info->rid == DOMAIN_USER_RID_ADMIN)
2475331Samw 		user_info->flags |= SMB_UINFO_FLAG_DADMIN;
2485331Samw 	else if (user_info->primary_group_rid == DOMAIN_GROUP_RID_ADMINS)
2495331Samw 		user_info->flags |= SMB_UINFO_FLAG_DADMIN;
2505331Samw 	else {
2515331Samw 		for (i = 0; i < user_info->n_groups; i++)
2525331Samw 			if (user_info->groups[i].rid == DOMAIN_GROUP_RID_ADMINS)
2535331Samw 				user_info->flags |= SMB_UINFO_FLAG_DADMIN;
2545331Samw 	}
2555331Samw 
2565772Sas200622 	rc = smb_lgrp_getbyname("Administrators", &grp);
2575772Sas200622 	if (rc == SMB_LGRP_SUCCESS) {
2585772Sas200622 		if (smb_lgrp_is_member(&grp, user_info->user_sid))
2595331Samw 			user_info->flags |= SMB_UINFO_FLAG_LADMIN;
2605772Sas200622 		smb_lgrp_free(&grp);
2615331Samw 	}
2625331Samw }
2635331Samw 
2645331Samw /*
2655331Samw  * mlsvc_string_save
2665331Samw  *
2675331Samw  * This is a convenience function to prepare strings for an RPC call.
2685331Samw  * An ms_string_t is set up with the appropriate lengths and str is
2695331Samw  * set up to point to a copy of the original string on the heap. The
2705331Samw  * macro MLRPC_HEAP_STRSAVE is an alias for mlrpc_heap_strsave, which
2715331Samw  * extends the heap and copies the string into the new area.
2725331Samw  */
2735331Samw int
2745331Samw mlsvc_string_save(ms_string_t *ms, char *str, struct mlrpc_xaction *mxa)
2755331Samw {
2765521Sas200622 	if (str == NULL)
2775331Samw 		return (0);
2785331Samw 
2795521Sas200622 	ms->length = mts_wcequiv_strlen(str);
2805521Sas200622 	ms->allosize = ms->length + sizeof (mts_wchar_t);
2815331Samw 
2825521Sas200622 	if ((ms->str = MLRPC_HEAP_STRSAVE(mxa, str)) == NULL)
2835521Sas200622 		return (0);
2845331Samw 
2855331Samw 	return (1);
2865331Samw }
2875331Samw 
2885331Samw /*
2895331Samw  * mlsvc_sid_save
2905331Samw  *
2915331Samw  * Expand the heap and copy the sid into the new area.
2925331Samw  * Returns a pointer to the copy of the sid on the heap.
2935331Samw  */
2946432Sas200622 smb_sid_t *
2956432Sas200622 mlsvc_sid_save(smb_sid_t *sid, struct mlrpc_xaction *mxa)
2965331Samw {
2976432Sas200622 	smb_sid_t *heap_sid;
2985331Samw 	unsigned size;
2995331Samw 
3005331Samw 	if (sid == NULL)
3015331Samw 		return (NULL);
3025331Samw 
3036432Sas200622 	size = smb_sid_len(sid);
3045331Samw 
3056432Sas200622 	if ((heap_sid = (smb_sid_t *)MLRPC_HEAP_MALLOC(mxa, size)) == NULL)
3065331Samw 		return (0);
3075331Samw 
3085331Samw 	bcopy(sid, heap_sid, size);
3095331Samw 	return (heap_sid);
3105331Samw }
3115331Samw 
3125331Samw /*
3135331Samw  * mlsvc_is_null_handle
3145331Samw  *
3155331Samw  * Check a handle against a null handle. Returns 1 if the handle is
3165331Samw  * null. Otherwise returns 0.
3175331Samw  */
3185331Samw int
3195331Samw mlsvc_is_null_handle(mlsvc_handle_t *handle)
3205331Samw {
3215331Samw 	static ms_handle_t zero_handle;
3225331Samw 
3235331Samw 	if (handle == NULL || handle->context == NULL)
3245331Samw 		return (1);
3255331Samw 
3265331Samw 	if (!memcmp(&handle->handle, &zero_handle, sizeof (ms_handle_t)))
3275331Samw 		return (1);
3285331Samw 
3295331Samw 	return (0);
3305331Samw }
3315331Samw 
3326139Sjb150015 DWORD
3336139Sjb150015 mlsvc_netlogon(char *server, char *domain)
3346139Sjb150015 {
3356139Sjb150015 	mlsvc_handle_t netr_handle;
3366139Sjb150015 	DWORD status;
3376139Sjb150015 
3386139Sjb150015 	if (netr_open(server, domain, &netr_handle) == 0) {
3396139Sjb150015 		status = netlogon_auth(server, &netr_handle,
3406139Sjb150015 		    NETR_FLG_INIT);
3416139Sjb150015 		(void) netr_close(&netr_handle);
3426139Sjb150015 	} else {
3436139Sjb150015 		status = NT_STATUS_OPEN_FAILED;
3446139Sjb150015 	}
3456139Sjb150015 
3466139Sjb150015 	return (status);
3476139Sjb150015 }
3486139Sjb150015 
3495331Samw /*
3505521Sas200622  * mlsvc_join
3515331Samw  *
3525331Samw  * Returns NT status codes.
3535331Samw  */
3545331Samw DWORD
3555521Sas200622 mlsvc_join(char *server, char *domain, char *plain_user, char *plain_text)
3565331Samw {
3575331Samw 	smb_auth_info_t auth;
3585331Samw 	smb_ntdomain_t *di;
3595331Samw 	int erc;
3605331Samw 	DWORD status;
3615331Samw 	char machine_passwd[MLSVC_MACHINE_ACCT_PASSWD_MAX];
3625772Sas200622 	char fqdn[MAXHOSTNAMELEN];
3635331Samw 
3645331Samw 	machine_passwd[0] = '\0';
3655331Samw 
3665331Samw 	/*
3675331Samw 	 * Ensure that the domain name is uppercase.
3685331Samw 	 */
3695331Samw 	(void) utf8_strupr(domain);
3705331Samw 
3715331Samw 	/*
3725331Samw 	 * There is no point continuing if the domain information is
3735331Samw 	 * not available. Wait for up to 10 seconds and then give up.
3745331Samw 	 */
3755331Samw 	if ((di = smb_getdomaininfo(10)) == 0) {
3765331Samw 		status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
3775331Samw 		return (status);
3785331Samw 	}
3795331Samw 
3805331Samw 	if (strcasecmp(domain, di->domain) != 0) {
3815331Samw 		status = NT_STATUS_INVALID_PARAMETER;
3825331Samw 		return (status);
3835331Samw 	}
3845331Samw 
3855521Sas200622 	erc = mlsvc_logon(server, domain, plain_user);
3865331Samw 
3875331Samw 	if (erc == AUTH_USER_GRANT) {
3885772Sas200622 		if (mlsvc_ntjoin_support == B_FALSE) {
3895772Sas200622 			if (smb_resolve_fqdn(domain, fqdn, MAXHOSTNAMELEN) != 1)
3905772Sas200622 				return (NT_STATUS_INVALID_PARAMETER);
3915331Samw 
3927052Samw 			if (smb_ads_join(fqdn, plain_user, plain_text,
3935772Sas200622 			    machine_passwd, sizeof (machine_passwd))
3947052Samw 			    == SMB_ADJOIN_SUCCESS)
3955331Samw 				status = NT_STATUS_SUCCESS;
3965521Sas200622 			else
3975331Samw 				status = NT_STATUS_UNSUCCESSFUL;
3985331Samw 		} else {
3995331Samw 			if (mlsvc_user_getauth(server, plain_user, &auth)
4005331Samw 			    != 0) {
4015331Samw 				status = NT_STATUS_INVALID_PARAMETER;
4025331Samw 				return (status);
4035331Samw 			}
4045331Samw 
4055331Samw 			status = sam_create_trust_account(server, domain,
4065331Samw 			    &auth);
4075331Samw 			if (status == NT_STATUS_SUCCESS) {
408*7961SNatalie.Li@Sun.COM 				(void) smb_getnetbiosname(machine_passwd,
409*7961SNatalie.Li@Sun.COM 				    sizeof (machine_passwd));
4105331Samw 				(void) utf8_strlwr(machine_passwd);
4115331Samw 			}
4125331Samw 		}
4135331Samw 
4145331Samw 		if (status == NT_STATUS_SUCCESS) {
4156139Sjb150015 			erc = smb_setdomainprops(NULL, server,
4165772Sas200622 			    machine_passwd);
4176139Sjb150015 			if (erc != 0)
4185331Samw 				return (NT_STATUS_UNSUCCESSFUL);
4195331Samw 
4206139Sjb150015 			status = mlsvc_netlogon(server, domain);
4215331Samw 		}
4225331Samw 	} else {
4235331Samw 		status = NT_STATUS_LOGON_FAILURE;
4245331Samw 	}
4255331Samw 
4265331Samw 	return (status);
4275331Samw }
428