xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c (revision 8334:5f1c6a3b0fad)
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 #include <sys/time.h>
375331Samw #include <sys/systm.h>
385331Samw 
395331Samw #include <smbsrv/libsmb.h>
405331Samw #include <smbsrv/libsmbrdr.h>
415331Samw #include <smbsrv/libsmbns.h>
425331Samw #include <smbsrv/libmlsvc.h>
435331Samw #include <smbsrv/smbinfo.h>
44*8334SJose.Borrego@Sun.COM #include <lsalib.h>
45*8334SJose.Borrego@Sun.COM #include <samlib.h>
46*8334SJose.Borrego@Sun.COM #include <smbsrv/netrauth.h>
475331Samw 
485772Sas200622 /* Domain join support (using MS-RPC) */
495772Sas200622 static boolean_t mlsvc_ntjoin_support = B_FALSE;
505772Sas200622 
515331Samw extern int netr_open(char *, char *, mlsvc_handle_t *);
525331Samw extern int netr_close(mlsvc_handle_t *);
535331Samw extern DWORD netlogon_auth(char *, mlsvc_handle_t *, DWORD);
545331Samw extern int mlsvc_user_getauth(char *, char *, smb_auth_info_t *);
555331Samw 
565331Samw /*
575331Samw  * Compare the supplied domain name with the local hostname.
585331Samw  * We need to deal with both server names and fully-qualified
595331Samw  * domain names.
605331Samw  *
615331Samw  * Returns:
625331Samw  *	0	The specified domain is not the local domain,
635331Samw  *	1	The Specified domain is the local domain.
645331Samw  *	-1	Invalid parameter or unable to get the local
655331Samw  *		system information.
665331Samw  */
675331Samw int
685331Samw mlsvc_is_local_domain(const char *domain)
695331Samw {
705331Samw 	char hostname[MAXHOSTNAMELEN];
715331Samw 	int rc;
725331Samw 
735772Sas200622 	if (smb_config_get_secmode() == SMB_SECMODE_WORKGRP)
745772Sas200622 		return (1);
755772Sas200622 
765331Samw 	if (strchr(domain, '.') != NULL)
775331Samw 		rc = smb_getfqhostname(hostname, MAXHOSTNAMELEN);
787961SNatalie.Li@Sun.COM 	else {
797961SNatalie.Li@Sun.COM 		if (strlen(domain) < NETBIOS_NAME_SZ)
807961SNatalie.Li@Sun.COM 			rc = smb_getnetbiosname(hostname, MAXHOSTNAMELEN);
817961SNatalie.Li@Sun.COM 		else
827961SNatalie.Li@Sun.COM 			rc = smb_gethostname(hostname, MAXHOSTNAMELEN, 1);
837961SNatalie.Li@Sun.COM 	}
845331Samw 
855331Samw 	if (rc != 0)
865331Samw 		return (-1);
875331Samw 
885772Sas200622 	if (strcasecmp(domain, hostname) == 0)
895331Samw 		return (1);
905331Samw 
915331Samw 	return (0);
925331Samw }
935331Samw 
945331Samw /*
955331Samw  * mlsvc_lookup_name
965331Samw  *
975772Sas200622  * This is just a wrapper for lsa_lookup_name.
985331Samw  *
995772Sas200622  * The memory for the sid is allocated using malloc so the caller should
1005772Sas200622  * call free when it is no longer required.
1015331Samw  */
1025772Sas200622 uint32_t
1036432Sas200622 mlsvc_lookup_name(char *account, smb_sid_t **sid, uint16_t *sid_type)
1045331Samw {
1055772Sas200622 	smb_userinfo_t *ainfo;
1065772Sas200622 	uint32_t status;
1075331Samw 
1085772Sas200622 	if ((ainfo = mlsvc_alloc_user_info()) == NULL)
1095772Sas200622 		return (NT_STATUS_NO_MEMORY);
1105331Samw 
111*8334SJose.Borrego@Sun.COM 	status = lsa_lookup_name(account, *sid_type, ainfo);
1125772Sas200622 	if (status == NT_STATUS_SUCCESS) {
1135772Sas200622 		*sid = ainfo->user_sid;
1145772Sas200622 		ainfo->user_sid = NULL;
1155772Sas200622 		*sid_type = ainfo->sid_name_use;
1165772Sas200622 	}
1175331Samw 
1185772Sas200622 	mlsvc_free_user_info(ainfo);
1195772Sas200622 	return (status);
1205331Samw }
1215331Samw 
1225331Samw /*
1235331Samw  * mlsvc_lookup_sid
1245331Samw  *
1255772Sas200622  * This is just a wrapper for lsa_lookup_sid.
1265772Sas200622  *
1275772Sas200622  * The allocated memory for the returned name must be freed by caller upon
1285772Sas200622  * successful return.
1295331Samw  */
1305772Sas200622 uint32_t
1316432Sas200622 mlsvc_lookup_sid(smb_sid_t *sid, char **name)
1325331Samw {
1335772Sas200622 	smb_userinfo_t *ainfo;
1345772Sas200622 	uint32_t status;
1355772Sas200622 	int namelen;
1365331Samw 
1375772Sas200622 	if ((ainfo = mlsvc_alloc_user_info()) == NULL)
1385772Sas200622 		return (NT_STATUS_NO_MEMORY);
1395331Samw 
1405772Sas200622 	status = lsa_lookup_sid(sid, ainfo);
1415772Sas200622 	if (status == NT_STATUS_SUCCESS) {
1425772Sas200622 		namelen = strlen(ainfo->domain_name) + strlen(ainfo->name) + 2;
1435772Sas200622 		if ((*name = malloc(namelen)) == NULL) {
1445772Sas200622 			mlsvc_free_user_info(ainfo);
1455772Sas200622 			return (NT_STATUS_NO_MEMORY);
1465331Samw 		}
1475772Sas200622 		(void) snprintf(*name, namelen, "%s\\%s",
1485772Sas200622 		    ainfo->domain_name, ainfo->name);
1495331Samw 	}
1505331Samw 
1515772Sas200622 	mlsvc_free_user_info(ainfo);
1525772Sas200622 	return (status);
1535331Samw }
1545331Samw 
1555331Samw /*
1565331Samw  * mlsvc_alloc_user_info
1575331Samw  *
1585331Samw  * Allocate a user_info structure and set the contents to zero. A
1595331Samw  * pointer to the user_info structure is returned.
1605331Samw  */
1615331Samw smb_userinfo_t *
1625331Samw mlsvc_alloc_user_info(void)
1635331Samw {
1645331Samw 	smb_userinfo_t *user_info;
1655331Samw 
1665331Samw 	user_info = (smb_userinfo_t *)malloc(sizeof (smb_userinfo_t));
1675331Samw 	if (user_info == NULL)
1685331Samw 		return (NULL);
1695331Samw 
1705331Samw 	bzero(user_info, sizeof (smb_userinfo_t));
1715331Samw 	return (user_info);
1725331Samw }
1735331Samw 
1745331Samw /*
1755331Samw  * mlsvc_free_user_info
1765331Samw  *
1775331Samw  * Free a user_info structure. This function ensures that the contents
1785331Samw  * of the user_info are freed as well as the user_info itself.
1795331Samw  */
1805331Samw void
1815331Samw mlsvc_free_user_info(smb_userinfo_t *user_info)
1825331Samw {
1835331Samw 	if (user_info) {
1845331Samw 		mlsvc_release_user_info(user_info);
1855331Samw 		free(user_info);
1865331Samw 	}
1875331Samw }
1885331Samw 
1895331Samw /*
1905331Samw  * mlsvc_release_user_info
1915331Samw  *
1925331Samw  * Release the contents of a user_info structure and zero out the
1935331Samw  * elements but do not free the user_info structure itself. This
1945331Samw  * function cleans out the structure so that it can be reused without
1955331Samw  * worrying about stale contents.
1965331Samw  */
1975331Samw void
1985331Samw mlsvc_release_user_info(smb_userinfo_t *user_info)
1995331Samw {
2005331Samw 	int i;
2015331Samw 
2025331Samw 	if (user_info == NULL)
2035331Samw 		return;
2045331Samw 
2055331Samw 	free(user_info->name);
2065331Samw 	free(user_info->domain_sid);
2075331Samw 	free(user_info->domain_name);
2085331Samw 	free(user_info->groups);
2095331Samw 
2105331Samw 	if (user_info->n_other_grps) {
2115331Samw 		for (i = 0; i < user_info->n_other_grps; i++)
2125331Samw 			free(user_info->other_grps[i].sid);
2135331Samw 
2145331Samw 		free(user_info->other_grps);
2155331Samw 	}
2165331Samw 
2176849Sjb150015 	free(user_info->session_key);
2185331Samw 	free(user_info->user_sid);
2195331Samw 	free(user_info->pgrp_sid);
2205331Samw 	bzero(user_info, sizeof (smb_userinfo_t));
2215331Samw }
2225331Samw 
2235331Samw /*
2245331Samw  * mlsvc_setadmin_user_info
2255331Samw  *
2265331Samw  * Determines if the given user is the domain Administrator or a
2275331Samw  * member of Domain Admins or Administrators group and set the
2285331Samw  * user_info->flags accordingly.
2295331Samw  */
2305331Samw void
2315331Samw mlsvc_setadmin_user_info(smb_userinfo_t *user_info)
2325331Samw {
2335331Samw 	nt_domain_t *domain;
2345772Sas200622 	smb_group_t grp;
2355772Sas200622 	int rc, i;
2365331Samw 
2375331Samw 	if ((domain = nt_domain_lookupbytype(NT_DOMAIN_PRIMARY)) == NULL)
2385331Samw 		return;
2395331Samw 
2406432Sas200622 	if (!smb_sid_cmp((smb_sid_t *)user_info->domain_sid, domain->sid))
2415331Samw 		return;
2425331Samw 
2435331Samw 	if (user_info->rid == DOMAIN_USER_RID_ADMIN)
2445331Samw 		user_info->flags |= SMB_UINFO_FLAG_DADMIN;
2455331Samw 	else if (user_info->primary_group_rid == DOMAIN_GROUP_RID_ADMINS)
2465331Samw 		user_info->flags |= SMB_UINFO_FLAG_DADMIN;
2475331Samw 	else {
2485331Samw 		for (i = 0; i < user_info->n_groups; i++)
2495331Samw 			if (user_info->groups[i].rid == DOMAIN_GROUP_RID_ADMINS)
2505331Samw 				user_info->flags |= SMB_UINFO_FLAG_DADMIN;
2515331Samw 	}
2525331Samw 
2535772Sas200622 	rc = smb_lgrp_getbyname("Administrators", &grp);
2545772Sas200622 	if (rc == SMB_LGRP_SUCCESS) {
2555772Sas200622 		if (smb_lgrp_is_member(&grp, user_info->user_sid))
2565331Samw 			user_info->flags |= SMB_UINFO_FLAG_LADMIN;
2575772Sas200622 		smb_lgrp_free(&grp);
2585331Samw 	}
2595331Samw }
2605331Samw 
2616139Sjb150015 DWORD
2626139Sjb150015 mlsvc_netlogon(char *server, char *domain)
2636139Sjb150015 {
2646139Sjb150015 	mlsvc_handle_t netr_handle;
2656139Sjb150015 	DWORD status;
2666139Sjb150015 
2676139Sjb150015 	if (netr_open(server, domain, &netr_handle) == 0) {
2686139Sjb150015 		status = netlogon_auth(server, &netr_handle,
2696139Sjb150015 		    NETR_FLG_INIT);
2706139Sjb150015 		(void) netr_close(&netr_handle);
2716139Sjb150015 	} else {
2726139Sjb150015 		status = NT_STATUS_OPEN_FAILED;
2736139Sjb150015 	}
2746139Sjb150015 
2756139Sjb150015 	return (status);
2766139Sjb150015 }
2776139Sjb150015 
2785331Samw /*
2795521Sas200622  * mlsvc_join
2805331Samw  *
2815331Samw  * Returns NT status codes.
2825331Samw  */
2835331Samw DWORD
284*8334SJose.Borrego@Sun.COM mlsvc_join(smb_domain_t *dinfo, char *user, char *plain_text)
2855331Samw {
2865331Samw 	smb_auth_info_t auth;
2875331Samw 	int erc;
2885331Samw 	DWORD status;
289*8334SJose.Borrego@Sun.COM 	char machine_passwd[NETR_MACHINE_ACCT_PASSWD_MAX];
2905331Samw 
2915331Samw 	machine_passwd[0] = '\0';
2925331Samw 
2935331Samw 	/*
2945331Samw 	 * Ensure that the domain name is uppercase.
2955331Samw 	 */
296*8334SJose.Borrego@Sun.COM 	(void) utf8_strupr(dinfo->d_nbdomain);
2975331Samw 
298*8334SJose.Borrego@Sun.COM 	erc = mlsvc_logon(dinfo->d_dc, dinfo->d_nbdomain, user);
2995331Samw 
3005331Samw 	if (erc == AUTH_USER_GRANT) {
3015772Sas200622 		if (mlsvc_ntjoin_support == B_FALSE) {
3025331Samw 
303*8334SJose.Borrego@Sun.COM 			if (smb_ads_join(dinfo->d_fqdomain, user, plain_text,
3045772Sas200622 			    machine_passwd, sizeof (machine_passwd))
3057052Samw 			    == SMB_ADJOIN_SUCCESS)
3065331Samw 				status = NT_STATUS_SUCCESS;
3075521Sas200622 			else
3085331Samw 				status = NT_STATUS_UNSUCCESSFUL;
3095331Samw 		} else {
310*8334SJose.Borrego@Sun.COM 			if (mlsvc_user_getauth(dinfo->d_dc, user, &auth)
3115331Samw 			    != 0) {
3125331Samw 				status = NT_STATUS_INVALID_PARAMETER;
3135331Samw 				return (status);
3145331Samw 			}
3155331Samw 
316*8334SJose.Borrego@Sun.COM 			status = sam_create_trust_account(dinfo->d_dc,
317*8334SJose.Borrego@Sun.COM 			    dinfo->d_nbdomain, &auth);
3185331Samw 			if (status == NT_STATUS_SUCCESS) {
3197961SNatalie.Li@Sun.COM 				(void) smb_getnetbiosname(machine_passwd,
3207961SNatalie.Li@Sun.COM 				    sizeof (machine_passwd));
3215331Samw 				(void) utf8_strlwr(machine_passwd);
3225331Samw 			}
3235331Samw 		}
3245331Samw 
3255331Samw 		if (status == NT_STATUS_SUCCESS) {
326*8334SJose.Borrego@Sun.COM 			erc = smb_setdomainprops(NULL, dinfo->d_dc,
3275772Sas200622 			    machine_passwd);
3286139Sjb150015 			if (erc != 0)
3295331Samw 				return (NT_STATUS_UNSUCCESSFUL);
3305331Samw 
331*8334SJose.Borrego@Sun.COM 			status = mlsvc_netlogon(dinfo->d_dc, dinfo->d_nbdomain);
3325331Samw 		}
3335331Samw 	} else {
3345331Samw 		status = NT_STATUS_LOGON_FAILURE;
3355331Samw 	}
3365331Samw 
3375331Samw 	return (status);
3385331Samw }
339