xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c (revision 6849:56d4aff9b8ab)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
275331Samw 
285331Samw /*
295331Samw  * Utility functions to support the RPC interface library.
305331Samw  */
315331Samw 
325331Samw #include <stdio.h>
335331Samw #include <stdarg.h>
345331Samw #include <strings.h>
355331Samw #include <unistd.h>
365331Samw #include <netdb.h>
375331Samw #include <stdlib.h>
385331Samw 
395331Samw #include <sys/time.h>
405331Samw #include <sys/systm.h>
415331Samw 
425331Samw #include <smbsrv/libsmb.h>
435331Samw #include <smbsrv/libsmbrdr.h>
445331Samw #include <smbsrv/libsmbns.h>
455331Samw #include <smbsrv/libmlsvc.h>
465331Samw 
475331Samw #include <smbsrv/smbinfo.h>
485331Samw #include <smbsrv/lsalib.h>
495331Samw #include <smbsrv/samlib.h>
505331Samw #include <smbsrv/mlsvc_util.h>
515331Samw #include <smbsrv/mlsvc.h>
525331Samw 
535772Sas200622 /* Domain join support (using MS-RPC) */
545772Sas200622 static boolean_t mlsvc_ntjoin_support = B_FALSE;
555772Sas200622 
565331Samw extern int netr_open(char *, char *, mlsvc_handle_t *);
575331Samw extern int netr_close(mlsvc_handle_t *);
585331Samw extern DWORD netlogon_auth(char *, mlsvc_handle_t *, DWORD);
595331Samw extern int mlsvc_user_getauth(char *, char *, smb_auth_info_t *);
605331Samw 
615331Samw /*
625331Samw  * Compare the supplied domain name with the local hostname.
635331Samw  * We need to deal with both server names and fully-qualified
645331Samw  * domain names.
655331Samw  *
665331Samw  * Returns:
675331Samw  *	0	The specified domain is not the local domain,
685331Samw  *	1	The Specified domain is the local domain.
695331Samw  *	-1	Invalid parameter or unable to get the local
705331Samw  *		system information.
715331Samw  */
725331Samw int
735331Samw mlsvc_is_local_domain(const char *domain)
745331Samw {
755331Samw 	char hostname[MAXHOSTNAMELEN];
765331Samw 	int rc;
775331Samw 
785772Sas200622 	if (smb_config_get_secmode() == SMB_SECMODE_WORKGRP)
795772Sas200622 		return (1);
805772Sas200622 
815331Samw 	if (strchr(domain, '.') != NULL)
825331Samw 		rc = smb_getfqhostname(hostname, MAXHOSTNAMELEN);
835331Samw 	else
845331Samw 		rc = smb_gethostname(hostname, MAXHOSTNAMELEN, 1);
855331Samw 
865331Samw 	if (rc != 0)
875331Samw 		return (-1);
885331Samw 
895772Sas200622 	if (strcasecmp(domain, hostname) == 0)
905331Samw 		return (1);
915331Samw 
925331Samw 	return (0);
935331Samw }
945331Samw 
955331Samw /*
965331Samw  * mlsvc_lookup_name
975331Samw  *
985772Sas200622  * This is just a wrapper for lsa_lookup_name.
995331Samw  *
1005772Sas200622  * The memory for the sid is allocated using malloc so the caller should
1015772Sas200622  * call free when it is no longer required.
1025331Samw  */
1035772Sas200622 uint32_t
1046432Sas200622 mlsvc_lookup_name(char *account, smb_sid_t **sid, uint16_t *sid_type)
1055331Samw {
1065772Sas200622 	smb_userinfo_t *ainfo;
1075772Sas200622 	uint32_t status;
1085331Samw 
1095772Sas200622 	if ((ainfo = mlsvc_alloc_user_info()) == NULL)
1105772Sas200622 		return (NT_STATUS_NO_MEMORY);
1115331Samw 
1125772Sas200622 	status = lsa_lookup_name(NULL, account, *sid_type, ainfo);
1135772Sas200622 	if (status == NT_STATUS_SUCCESS) {
1145772Sas200622 		*sid = ainfo->user_sid;
1155772Sas200622 		ainfo->user_sid = NULL;
1165772Sas200622 		*sid_type = ainfo->sid_name_use;
1175772Sas200622 	}
1185331Samw 
1195772Sas200622 	mlsvc_free_user_info(ainfo);
1205772Sas200622 	return (status);
1215331Samw }
1225331Samw 
1235331Samw /*
1245331Samw  * mlsvc_lookup_sid
1255331Samw  *
1265772Sas200622  * This is just a wrapper for lsa_lookup_sid.
1275772Sas200622  *
1285772Sas200622  * The allocated memory for the returned name must be freed by caller upon
1295772Sas200622  * successful return.
1305331Samw  */
1315772Sas200622 uint32_t
1326432Sas200622 mlsvc_lookup_sid(smb_sid_t *sid, char **name)
1335331Samw {
1345772Sas200622 	smb_userinfo_t *ainfo;
1355772Sas200622 	uint32_t status;
1365772Sas200622 	int namelen;
1375331Samw 
1385772Sas200622 	if ((ainfo = mlsvc_alloc_user_info()) == NULL)
1395772Sas200622 		return (NT_STATUS_NO_MEMORY);
1405331Samw 
1415772Sas200622 	status = lsa_lookup_sid(sid, ainfo);
1425772Sas200622 	if (status == NT_STATUS_SUCCESS) {
1435772Sas200622 		namelen = strlen(ainfo->domain_name) + strlen(ainfo->name) + 2;
1445772Sas200622 		if ((*name = malloc(namelen)) == NULL) {
1455772Sas200622 			mlsvc_free_user_info(ainfo);
1465772Sas200622 			return (NT_STATUS_NO_MEMORY);
1475331Samw 		}
1485772Sas200622 		(void) snprintf(*name, namelen, "%s\\%s",
1495772Sas200622 		    ainfo->domain_name, ainfo->name);
1505331Samw 	}
1515331Samw 
1525772Sas200622 	mlsvc_free_user_info(ainfo);
1535772Sas200622 	return (status);
1545331Samw }
1555331Samw 
1565331Samw /*
1575331Samw  * mlsvc_alloc_user_info
1585331Samw  *
1595331Samw  * Allocate a user_info structure and set the contents to zero. A
1605331Samw  * pointer to the user_info structure is returned.
1615331Samw  */
1625331Samw smb_userinfo_t *
1635331Samw mlsvc_alloc_user_info(void)
1645331Samw {
1655331Samw 	smb_userinfo_t *user_info;
1665331Samw 
1675331Samw 	user_info = (smb_userinfo_t *)malloc(sizeof (smb_userinfo_t));
1685331Samw 	if (user_info == NULL)
1695331Samw 		return (NULL);
1705331Samw 
1715331Samw 	bzero(user_info, sizeof (smb_userinfo_t));
1725331Samw 	return (user_info);
1735331Samw }
1745331Samw 
1755331Samw /*
1765331Samw  * mlsvc_free_user_info
1775331Samw  *
1785331Samw  * Free a user_info structure. This function ensures that the contents
1795331Samw  * of the user_info are freed as well as the user_info itself.
1805331Samw  */
1815331Samw void
1825331Samw mlsvc_free_user_info(smb_userinfo_t *user_info)
1835331Samw {
1845331Samw 	if (user_info) {
1855331Samw 		mlsvc_release_user_info(user_info);
1865331Samw 		free(user_info);
1875331Samw 	}
1885331Samw }
1895331Samw 
1905331Samw /*
1915331Samw  * mlsvc_release_user_info
1925331Samw  *
1935331Samw  * Release the contents of a user_info structure and zero out the
1945331Samw  * elements but do not free the user_info structure itself. This
1955331Samw  * function cleans out the structure so that it can be reused without
1965331Samw  * worrying about stale contents.
1975331Samw  */
1985331Samw void
1995331Samw mlsvc_release_user_info(smb_userinfo_t *user_info)
2005331Samw {
2015331Samw 	int i;
2025331Samw 
2035331Samw 	if (user_info == NULL)
2045331Samw 		return;
2055331Samw 
2065331Samw 	free(user_info->name);
2075331Samw 	free(user_info->domain_sid);
2085331Samw 	free(user_info->domain_name);
2095331Samw 	free(user_info->groups);
2105331Samw 
2115331Samw 	if (user_info->n_other_grps) {
2125331Samw 		for (i = 0; i < user_info->n_other_grps; i++)
2135331Samw 			free(user_info->other_grps[i].sid);
2145331Samw 
2155331Samw 		free(user_info->other_grps);
2165331Samw 	}
2175331Samw 
218*6849Sjb150015 	free(user_info->session_key);
2195331Samw 	free(user_info->user_sid);
2205331Samw 	free(user_info->pgrp_sid);
2215331Samw 	bzero(user_info, sizeof (smb_userinfo_t));
2225331Samw }
2235331Samw 
2245331Samw /*
2255331Samw  * mlsvc_setadmin_user_info
2265331Samw  *
2275331Samw  * Determines if the given user is the domain Administrator or a
2285331Samw  * member of Domain Admins or Administrators group and set the
2295331Samw  * user_info->flags accordingly.
2305331Samw  */
2315331Samw void
2325331Samw mlsvc_setadmin_user_info(smb_userinfo_t *user_info)
2335331Samw {
2345331Samw 	nt_domain_t *domain;
2355772Sas200622 	smb_group_t grp;
2365772Sas200622 	int rc, i;
2375331Samw 
2385331Samw 	if ((domain = nt_domain_lookupbytype(NT_DOMAIN_PRIMARY)) == NULL)
2395331Samw 		return;
2405331Samw 
2416432Sas200622 	if (!smb_sid_cmp((smb_sid_t *)user_info->domain_sid, domain->sid))
2425331Samw 		return;
2435331Samw 
2445331Samw 	if (user_info->rid == DOMAIN_USER_RID_ADMIN)
2455331Samw 		user_info->flags |= SMB_UINFO_FLAG_DADMIN;
2465331Samw 	else if (user_info->primary_group_rid == DOMAIN_GROUP_RID_ADMINS)
2475331Samw 		user_info->flags |= SMB_UINFO_FLAG_DADMIN;
2485331Samw 	else {
2495331Samw 		for (i = 0; i < user_info->n_groups; i++)
2505331Samw 			if (user_info->groups[i].rid == DOMAIN_GROUP_RID_ADMINS)
2515331Samw 				user_info->flags |= SMB_UINFO_FLAG_DADMIN;
2525331Samw 	}
2535331Samw 
2545772Sas200622 	rc = smb_lgrp_getbyname("Administrators", &grp);
2555772Sas200622 	if (rc == SMB_LGRP_SUCCESS) {
2565772Sas200622 		if (smb_lgrp_is_member(&grp, user_info->user_sid))
2575331Samw 			user_info->flags |= SMB_UINFO_FLAG_LADMIN;
2585772Sas200622 		smb_lgrp_free(&grp);
2595331Samw 	}
2605331Samw }
2615331Samw 
2625331Samw /*
2635331Samw  * mlsvc_string_save
2645331Samw  *
2655331Samw  * This is a convenience function to prepare strings for an RPC call.
2665331Samw  * An ms_string_t is set up with the appropriate lengths and str is
2675331Samw  * set up to point to a copy of the original string on the heap. The
2685331Samw  * macro MLRPC_HEAP_STRSAVE is an alias for mlrpc_heap_strsave, which
2695331Samw  * extends the heap and copies the string into the new area.
2705331Samw  */
2715331Samw int
2725331Samw mlsvc_string_save(ms_string_t *ms, char *str, struct mlrpc_xaction *mxa)
2735331Samw {
2745521Sas200622 	if (str == NULL)
2755331Samw 		return (0);
2765331Samw 
2775521Sas200622 	ms->length = mts_wcequiv_strlen(str);
2785521Sas200622 	ms->allosize = ms->length + sizeof (mts_wchar_t);
2795331Samw 
2805521Sas200622 	if ((ms->str = MLRPC_HEAP_STRSAVE(mxa, str)) == NULL)
2815521Sas200622 		return (0);
2825331Samw 
2835331Samw 	return (1);
2845331Samw }
2855331Samw 
2865331Samw /*
2875331Samw  * mlsvc_sid_save
2885331Samw  *
2895331Samw  * Expand the heap and copy the sid into the new area.
2905331Samw  * Returns a pointer to the copy of the sid on the heap.
2915331Samw  */
2926432Sas200622 smb_sid_t *
2936432Sas200622 mlsvc_sid_save(smb_sid_t *sid, struct mlrpc_xaction *mxa)
2945331Samw {
2956432Sas200622 	smb_sid_t *heap_sid;
2965331Samw 	unsigned size;
2975331Samw 
2985331Samw 	if (sid == NULL)
2995331Samw 		return (NULL);
3005331Samw 
3016432Sas200622 	size = smb_sid_len(sid);
3025331Samw 
3036432Sas200622 	if ((heap_sid = (smb_sid_t *)MLRPC_HEAP_MALLOC(mxa, size)) == NULL)
3045331Samw 		return (0);
3055331Samw 
3065331Samw 	bcopy(sid, heap_sid, size);
3075331Samw 	return (heap_sid);
3085331Samw }
3095331Samw 
3105331Samw /*
3115331Samw  * mlsvc_is_null_handle
3125331Samw  *
3135331Samw  * Check a handle against a null handle. Returns 1 if the handle is
3145331Samw  * null. Otherwise returns 0.
3155331Samw  */
3165331Samw int
3175331Samw mlsvc_is_null_handle(mlsvc_handle_t *handle)
3185331Samw {
3195331Samw 	static ms_handle_t zero_handle;
3205331Samw 
3215331Samw 	if (handle == NULL || handle->context == NULL)
3225331Samw 		return (1);
3235331Samw 
3245331Samw 	if (!memcmp(&handle->handle, &zero_handle, sizeof (ms_handle_t)))
3255331Samw 		return (1);
3265331Samw 
3275331Samw 	return (0);
3285331Samw }
3295331Samw 
3306139Sjb150015 DWORD
3316139Sjb150015 mlsvc_netlogon(char *server, char *domain)
3326139Sjb150015 {
3336139Sjb150015 	mlsvc_handle_t netr_handle;
3346139Sjb150015 	DWORD status;
3356139Sjb150015 
3366139Sjb150015 	if (netr_open(server, domain, &netr_handle) == 0) {
3376139Sjb150015 		status = netlogon_auth(server, &netr_handle,
3386139Sjb150015 		    NETR_FLG_INIT);
3396139Sjb150015 		(void) netr_close(&netr_handle);
3406139Sjb150015 	} else {
3416139Sjb150015 		status = NT_STATUS_OPEN_FAILED;
3426139Sjb150015 	}
3436139Sjb150015 
3446139Sjb150015 	return (status);
3456139Sjb150015 }
3466139Sjb150015 
3475331Samw /*
3485521Sas200622  * mlsvc_join
3495331Samw  *
3505331Samw  * Returns NT status codes.
3515331Samw  */
3525331Samw DWORD
3535521Sas200622 mlsvc_join(char *server, char *domain, char *plain_user, char *plain_text)
3545331Samw {
3555331Samw 	smb_auth_info_t auth;
3565331Samw 	smb_ntdomain_t *di;
3575331Samw 	int erc;
3585331Samw 	DWORD status;
3595331Samw 	char machine_passwd[MLSVC_MACHINE_ACCT_PASSWD_MAX];
3605772Sas200622 	char fqdn[MAXHOSTNAMELEN];
3615331Samw 
3625331Samw 	machine_passwd[0] = '\0';
3635331Samw 
3645331Samw 	/*
3655331Samw 	 * Ensure that the domain name is uppercase.
3665331Samw 	 */
3675331Samw 	(void) utf8_strupr(domain);
3685331Samw 
3695331Samw 	/*
3705331Samw 	 * There is no point continuing if the domain information is
3715331Samw 	 * not available. Wait for up to 10 seconds and then give up.
3725331Samw 	 */
3735331Samw 	if ((di = smb_getdomaininfo(10)) == 0) {
3745331Samw 		status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
3755331Samw 		return (status);
3765331Samw 	}
3775331Samw 
3785331Samw 	if (strcasecmp(domain, di->domain) != 0) {
3795331Samw 		status = NT_STATUS_INVALID_PARAMETER;
3805331Samw 		return (status);
3815331Samw 	}
3825331Samw 
3835521Sas200622 	erc = mlsvc_logon(server, domain, plain_user);
3845331Samw 
3855331Samw 	if (erc == AUTH_USER_GRANT) {
3865772Sas200622 		if (mlsvc_ntjoin_support == B_FALSE) {
3875772Sas200622 			if (smb_resolve_fqdn(domain, fqdn, MAXHOSTNAMELEN) != 1)
3885772Sas200622 				return (NT_STATUS_INVALID_PARAMETER);
3895331Samw 
3905772Sas200622 			if (ads_join(fqdn, plain_user, plain_text,
3915772Sas200622 			    machine_passwd, sizeof (machine_passwd))
3925772Sas200622 			    == ADJOIN_SUCCESS)
3935331Samw 				status = NT_STATUS_SUCCESS;
3945521Sas200622 			else
3955331Samw 				status = NT_STATUS_UNSUCCESSFUL;
3965331Samw 		} else {
3975331Samw 			if (mlsvc_user_getauth(server, plain_user, &auth)
3985331Samw 			    != 0) {
3995331Samw 				status = NT_STATUS_INVALID_PARAMETER;
4005331Samw 				return (status);
4015331Samw 			}
4025331Samw 
4035331Samw 			status = sam_create_trust_account(server, domain,
4045331Samw 			    &auth);
4055331Samw 			if (status == NT_STATUS_SUCCESS) {
4065331Samw 				(void) smb_gethostname(machine_passwd,
4075331Samw 				    sizeof (machine_passwd), 0);
4085331Samw 				(void) utf8_strlwr(machine_passwd);
4095331Samw 			}
4105331Samw 		}
4115331Samw 
4125331Samw 		if (status == NT_STATUS_SUCCESS) {
4136139Sjb150015 			erc = smb_setdomainprops(NULL, server,
4145772Sas200622 			    machine_passwd);
4156139Sjb150015 			if (erc != 0)
4165331Samw 				return (NT_STATUS_UNSUCCESSFUL);
4175331Samw 
4186139Sjb150015 			status = mlsvc_netlogon(server, domain);
4195331Samw 		}
4205331Samw 	} else {
4215331Samw 		status = NT_STATUS_LOGON_FAILURE;
4225331Samw 	}
4235331Samw 
4245331Samw 	return (status);
4255331Samw }
426