17f667e74Sjose borrego /*
27f667e74Sjose borrego  * CDDL HEADER START
37f667e74Sjose borrego  *
47f667e74Sjose borrego  * The contents of this file are subject to the terms of the
57f667e74Sjose borrego  * Common Development and Distribution License (the "License").
67f667e74Sjose borrego  * You may not use this file except in compliance with the License.
77f667e74Sjose borrego  *
87f667e74Sjose borrego  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97f667e74Sjose borrego  * or http://www.opensolaris.org/os/licensing.
107f667e74Sjose borrego  * See the License for the specific language governing permissions
117f667e74Sjose borrego  * and limitations under the License.
127f667e74Sjose borrego  *
137f667e74Sjose borrego  * When distributing Covered Code, include this CDDL HEADER in each
147f667e74Sjose borrego  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157f667e74Sjose borrego  * If applicable, add the following below this CDDL HEADER, with the
167f667e74Sjose borrego  * fields enclosed by brackets "[]" replaced with your own identifying
177f667e74Sjose borrego  * information: Portions Copyright [yyyy] [name of copyright owner]
187f667e74Sjose borrego  *
197f667e74Sjose borrego  * CDDL HEADER END
207f667e74Sjose borrego  */
217f667e74Sjose borrego /*
229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237f667e74Sjose borrego  * Use is subject to license terms.
24b819cea2SGordon Ross  *
25*9242c919SMatt Barden  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
2662f63298SVitaliy Gusev  * Copyright 2018 RackTop Systems.
277f667e74Sjose borrego  */
287f667e74Sjose borrego 
297f667e74Sjose borrego #include <strings.h>
307f667e74Sjose borrego #include <smbsrv/libsmb.h>
317f667e74Sjose borrego 
327f667e74Sjose borrego extern int smb_pwd_num(void);
339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States extern int smb_lgrp_numbydomain(smb_domain_type_t, int *);
347f667e74Sjose borrego 
357f667e74Sjose borrego static uint32_t smb_sam_lookup_user(char *, smb_sid_t **);
367f667e74Sjose borrego static uint32_t smb_sam_lookup_group(char *, smb_sid_t **);
377f667e74Sjose borrego 
3829bd2886SAlan Wright /*
3929bd2886SAlan Wright  * Local well-known accounts data structure table and prototypes
4029bd2886SAlan Wright  */
4129bd2886SAlan Wright typedef struct smb_lwka {
4229bd2886SAlan Wright 	uint32_t	lwka_rid;
4329bd2886SAlan Wright 	char		*lwka_name;
4429bd2886SAlan Wright 	uint16_t	lwka_type;
4529bd2886SAlan Wright } smb_lwka_t;
4629bd2886SAlan Wright 
4729bd2886SAlan Wright static smb_lwka_t lwka_tbl[] = {
4829bd2886SAlan Wright 	{ 500, "Administrator", SidTypeUser },
4929bd2886SAlan Wright 	{ 501, "Guest", SidTypeUser },
5029bd2886SAlan Wright 	{ 502, "KRBTGT", SidTypeUser },
5129bd2886SAlan Wright 	{ 512, "Domain Admins", SidTypeGroup },
5229bd2886SAlan Wright 	{ 513, "Domain Users", SidTypeGroup },
5329bd2886SAlan Wright 	{ 514, "Domain Guests", SidTypeGroup },
5429bd2886SAlan Wright 	{ 516, "Domain Controllers", SidTypeGroup },
5529bd2886SAlan Wright 	{ 517, "Cert Publishers", SidTypeGroup },
5629bd2886SAlan Wright 	{ 518, "Schema Admins", SidTypeGroup },
5729bd2886SAlan Wright 	{ 519, "Enterprise Admins", SidTypeGroup },
5829bd2886SAlan Wright 	{ 520, "Global Policy Creator Owners", SidTypeGroup },
5929bd2886SAlan Wright 	{ 533, "RAS and IAS Servers", SidTypeGroup }
6029bd2886SAlan Wright };
6129bd2886SAlan Wright 
6229bd2886SAlan Wright #define	SMB_LWKA_NUM	(sizeof (lwka_tbl)/sizeof (lwka_tbl[0]))
6329bd2886SAlan Wright 
6429bd2886SAlan Wright static smb_lwka_t *smb_lwka_lookup_name(char *);
6529bd2886SAlan Wright static smb_lwka_t *smb_lwka_lookup_sid(smb_sid_t *);
6629bd2886SAlan Wright 
677f667e74Sjose borrego /*
687f667e74Sjose borrego  * Looks up the given name in local account databases:
697f667e74Sjose borrego  *
707f667e74Sjose borrego  * SMB Local users are looked up in /var/smb/smbpasswd
717f667e74Sjose borrego  * SMB Local groups are looked up in /var/smb/smbgroup.db
727f667e74Sjose borrego  *
737f667e74Sjose borrego  * If the account is found, its information is populated
747f667e74Sjose borrego  * in the passed smb_account_t structure. Caller must free
757f667e74Sjose borrego  * allocated memories by calling smb_account_free() upon
767f667e74Sjose borrego  * successful return.
777f667e74Sjose borrego  *
787f667e74Sjose borrego  * The type of account is specified by 'type', which can be user,
797f667e74Sjose borrego  * alias (local group) or unknown. If the caller doesn't know
807f667e74Sjose borrego  * whether the name is a user or group name then SidTypeUnknown
817f667e74Sjose borrego  * should be passed.
827f667e74Sjose borrego  *
837f667e74Sjose borrego  * If a local user and group have the same name, the user will
847f667e74Sjose borrego  * always be picked. Note that this situation cannot happen on
857f667e74Sjose borrego  * Windows systems.
867f667e74Sjose borrego  *
877f667e74Sjose borrego  * If a SMB local user/group is found but it turns out that
887f667e74Sjose borrego  * it'll be mapped to a domain user/group the lookup is considered
897f667e74Sjose borrego  * failed and NT_STATUS_NONE_MAPPED is returned.
907f667e74Sjose borrego  *
917f667e74Sjose borrego  * Return status:
927f667e74Sjose borrego  *
937f667e74Sjose borrego  *   NT_STATUS_NOT_FOUND	This is not a local account
947f667e74Sjose borrego  *   NT_STATUS_NONE_MAPPED	It's a local account but cannot be
9562f63298SVitaliy Gusev  *				translated.
967f667e74Sjose borrego  *   other error status codes.
977f667e74Sjose borrego  */
987f667e74Sjose borrego uint32_t
smb_sam_lookup_name(char * domain,char * name,uint16_t type,smb_account_t * account)997f667e74Sjose borrego smb_sam_lookup_name(char *domain, char *name, uint16_t type,
1007f667e74Sjose borrego     smb_account_t *account)
1017f667e74Sjose borrego {
102a0aa776eSAlan Wright 	smb_domain_t di;
1037f667e74Sjose borrego 	smb_sid_t *sid;
1047f667e74Sjose borrego 	uint32_t status;
10529bd2886SAlan Wright 	smb_lwka_t *lwka;
1067f667e74Sjose borrego 
1077f667e74Sjose borrego 	bzero(account, sizeof (smb_account_t));
1087f667e74Sjose borrego 
1097f667e74Sjose borrego 	if (domain != NULL) {
110a0aa776eSAlan Wright 		if (!smb_domain_lookup_name(domain, &di) ||
111a0aa776eSAlan Wright 		    (di.di_type != SMB_DOMAIN_LOCAL))
1127f667e74Sjose borrego 			return (NT_STATUS_NOT_FOUND);
1137f667e74Sjose borrego 
1147f667e74Sjose borrego 		/* Only Netbios hostname is accepted */
115bbf6f00cSJordan Brown 		if (smb_strcasecmp(domain, di.di_nbname, 0) != 0)
1167f667e74Sjose borrego 			return (NT_STATUS_NONE_MAPPED);
11729bd2886SAlan Wright 	} else {
118a0aa776eSAlan Wright 		if (!smb_domain_lookup_type(SMB_DOMAIN_LOCAL, &di))
11929bd2886SAlan Wright 			return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
1207f667e74Sjose borrego 	}
1217f667e74Sjose borrego 
122bbf6f00cSJordan Brown 	if (smb_strcasecmp(name, di.di_nbname, 0) == 0) {
12329bd2886SAlan Wright 		/* This is the local domain name */
12429bd2886SAlan Wright 		account->a_type = SidTypeDomain;
12529bd2886SAlan Wright 		account->a_name = strdup("");
12629bd2886SAlan Wright 		account->a_domain = strdup(di.di_nbname);
12729bd2886SAlan Wright 		account->a_sid = smb_sid_dup(di.di_binsid);
12829bd2886SAlan Wright 		account->a_domsid = smb_sid_dup(di.di_binsid);
12929bd2886SAlan Wright 		account->a_rid = (uint32_t)-1;
13029bd2886SAlan Wright 
13129bd2886SAlan Wright 		if (!smb_account_validate(account)) {
13229bd2886SAlan Wright 			smb_account_free(account);
13329bd2886SAlan Wright 			return (NT_STATUS_NO_MEMORY);
13429bd2886SAlan Wright 		}
1357f667e74Sjose borrego 
13629bd2886SAlan Wright 		return (NT_STATUS_SUCCESS);
13729bd2886SAlan Wright 	}
1387f667e74Sjose borrego 
13929bd2886SAlan Wright 	if ((lwka = smb_lwka_lookup_name(name)) != NULL) {
14029bd2886SAlan Wright 		sid = smb_sid_splice(di.di_binsid, lwka->lwka_rid);
14129bd2886SAlan Wright 		type = lwka->lwka_type;
14229bd2886SAlan Wright 	} else {
14329bd2886SAlan Wright 		switch (type) {
14429bd2886SAlan Wright 		case SidTypeUser:
14529bd2886SAlan Wright 			status = smb_sam_lookup_user(name, &sid);
14629bd2886SAlan Wright 			if (status != NT_STATUS_SUCCESS)
14729bd2886SAlan Wright 				return (status);
1487f667e74Sjose borrego 			break;
1497f667e74Sjose borrego 
15029bd2886SAlan Wright 		case SidTypeAlias:
15129bd2886SAlan Wright 			status = smb_sam_lookup_group(name, &sid);
15229bd2886SAlan Wright 			if (status != NT_STATUS_SUCCESS)
15329bd2886SAlan Wright 				return (status);
15429bd2886SAlan Wright 			break;
1557f667e74Sjose borrego 
15629bd2886SAlan Wright 		case SidTypeUnknown:
15729bd2886SAlan Wright 			type = SidTypeUser;
15829bd2886SAlan Wright 			status = smb_sam_lookup_user(name, &sid);
15929bd2886SAlan Wright 			if (status == NT_STATUS_SUCCESS)
16029bd2886SAlan Wright 				break;
1617f667e74Sjose borrego 
16229bd2886SAlan Wright 			if (status == NT_STATUS_NONE_MAPPED)
16329bd2886SAlan Wright 				return (status);
16429bd2886SAlan Wright 
16529bd2886SAlan Wright 			type = SidTypeAlias;
16629bd2886SAlan Wright 			status = smb_sam_lookup_group(name, &sid);
16729bd2886SAlan Wright 			if (status != NT_STATUS_SUCCESS)
16829bd2886SAlan Wright 				return (status);
16929bd2886SAlan Wright 			break;
17029bd2886SAlan Wright 
17129bd2886SAlan Wright 		default:
17229bd2886SAlan Wright 			return (NT_STATUS_INVALID_PARAMETER);
17329bd2886SAlan Wright 		}
1747f667e74Sjose borrego 	}
1757f667e74Sjose borrego 
1767f667e74Sjose borrego 	account->a_name = strdup(name);
1777f667e74Sjose borrego 	account->a_sid = sid;
17829bd2886SAlan Wright 	account->a_domain = strdup(di.di_nbname);
1797f667e74Sjose borrego 	account->a_domsid = smb_sid_split(sid, &account->a_rid);
1807f667e74Sjose borrego 	account->a_type = type;
1817f667e74Sjose borrego 
1827f667e74Sjose borrego 	if (!smb_account_validate(account)) {
1837f667e74Sjose borrego 		smb_account_free(account);
1847f667e74Sjose borrego 		return (NT_STATUS_NO_MEMORY);
1857f667e74Sjose borrego 	}
1867f667e74Sjose borrego 
1877f667e74Sjose borrego 	return (NT_STATUS_SUCCESS);
1887f667e74Sjose borrego }
1897f667e74Sjose borrego 
1907f667e74Sjose borrego /*
1917f667e74Sjose borrego  * Looks up the given SID in local account databases:
1927f667e74Sjose borrego  *
1937f667e74Sjose borrego  * SMB Local users are looked up in /var/smb/smbpasswd
1947f667e74Sjose borrego  * SMB Local groups are looked up in /var/smb/smbgroup.db
1957f667e74Sjose borrego  *
1967f667e74Sjose borrego  * If the account is found, its information is populated
1977f667e74Sjose borrego  * in the passed smb_account_t structure. Caller must free
1987f667e74Sjose borrego  * allocated memories by calling smb_account_free() upon
1997f667e74Sjose borrego  * successful return.
2007f667e74Sjose borrego  *
2017f667e74Sjose borrego  * Return status:
2027f667e74Sjose borrego  *
2037f667e74Sjose borrego  *   NT_STATUS_NOT_FOUND	This is not a local account
2047f667e74Sjose borrego  *   NT_STATUS_NONE_MAPPED	It's a local account but cannot be
20562f63298SVitaliy Gusev  *				translated.
2067f667e74Sjose borrego  *   other error status codes.
2077f667e74Sjose borrego  */
2087f667e74Sjose borrego uint32_t
smb_sam_lookup_sid(smb_sid_t * sid,smb_account_t * account)2097f667e74Sjose borrego smb_sam_lookup_sid(smb_sid_t *sid, smb_account_t *account)
2107f667e74Sjose borrego {
2117f667e74Sjose borrego 	char hostname[MAXHOSTNAMELEN];
2127f667e74Sjose borrego 	smb_passwd_t smbpw;
2137f667e74Sjose borrego 	smb_group_t grp;
21429bd2886SAlan Wright 	smb_lwka_t *lwka;
215a0aa776eSAlan Wright 	smb_domain_t di;
2167f667e74Sjose borrego 	uint32_t rid;
2177f667e74Sjose borrego 	uid_t id;
2187f667e74Sjose borrego 	int id_type;
2197f667e74Sjose borrego 	int rc;
2207f667e74Sjose borrego 
2217f667e74Sjose borrego 	bzero(account, sizeof (smb_account_t));
2227f667e74Sjose borrego 
223a0aa776eSAlan Wright 	if (!smb_domain_lookup_type(SMB_DOMAIN_LOCAL, &di))
22429bd2886SAlan Wright 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
22529bd2886SAlan Wright 
22629bd2886SAlan Wright 	if (smb_sid_cmp(sid, di.di_binsid)) {
22729bd2886SAlan Wright 		/* This is the local domain SID */
22829bd2886SAlan Wright 		account->a_type = SidTypeDomain;
22929bd2886SAlan Wright 		account->a_name = strdup("");
23029bd2886SAlan Wright 		account->a_domain = strdup(di.di_nbname);
23129bd2886SAlan Wright 		account->a_sid = smb_sid_dup(sid);
23229bd2886SAlan Wright 		account->a_domsid = smb_sid_dup(sid);
23329bd2886SAlan Wright 		account->a_rid = (uint32_t)-1;
23429bd2886SAlan Wright 
23529bd2886SAlan Wright 		if (!smb_account_validate(account)) {
23629bd2886SAlan Wright 			smb_account_free(account);
23729bd2886SAlan Wright 			return (NT_STATUS_NO_MEMORY);
23829bd2886SAlan Wright 		}
23929bd2886SAlan Wright 
24029bd2886SAlan Wright 		return (NT_STATUS_SUCCESS);
24129bd2886SAlan Wright 	}
24229bd2886SAlan Wright 
24329bd2886SAlan Wright 	if (!smb_sid_indomain(di.di_binsid, sid)) {
24429bd2886SAlan Wright 		/* This is not a local SID */
2457f667e74Sjose borrego 		return (NT_STATUS_NOT_FOUND);
24629bd2886SAlan Wright 	}
2477f667e74Sjose borrego 
24829bd2886SAlan Wright 	if ((lwka = smb_lwka_lookup_sid(sid)) != NULL) {
24929bd2886SAlan Wright 		account->a_type = lwka->lwka_type;
25029bd2886SAlan Wright 		account->a_name = strdup(lwka->lwka_name);
25129bd2886SAlan Wright 	} else {
25229bd2886SAlan Wright 		id_type = SMB_IDMAP_UNKNOWN;
25329bd2886SAlan Wright 		if (smb_idmap_getid(sid, &id, &id_type) != IDMAP_SUCCESS)
25429bd2886SAlan Wright 			return (NT_STATUS_NONE_MAPPED);
2557f667e74Sjose borrego 
25629bd2886SAlan Wright 		switch (id_type) {
25729bd2886SAlan Wright 		case SMB_IDMAP_USER:
25829bd2886SAlan Wright 			account->a_type = SidTypeUser;
25929bd2886SAlan Wright 			if (smb_pwd_getpwuid(id, &smbpw) == NULL)
26029bd2886SAlan Wright 				return (NT_STATUS_NO_SUCH_USER);
2617f667e74Sjose borrego 
26229bd2886SAlan Wright 			account->a_name = strdup(smbpw.pw_name);
263*9242c919SMatt Barden 			account->a_flags = smbpw.pw_flags;
26429bd2886SAlan Wright 			break;
2657f667e74Sjose borrego 
26629bd2886SAlan Wright 		case SMB_IDMAP_GROUP:
26729bd2886SAlan Wright 			account->a_type = SidTypeAlias;
26829bd2886SAlan Wright 			(void) smb_sid_getrid(sid, &rid);
2699fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_lgrp_getbyrid(rid, SMB_DOMAIN_LOCAL, &grp);
27029bd2886SAlan Wright 			if (rc != SMB_LGRP_SUCCESS)
27129bd2886SAlan Wright 				return (NT_STATUS_NO_SUCH_ALIAS);
2727f667e74Sjose borrego 
27329bd2886SAlan Wright 			account->a_name = strdup(grp.sg_name);
27429bd2886SAlan Wright 			smb_lgrp_free(&grp);
27529bd2886SAlan Wright 			break;
2767f667e74Sjose borrego 
27729bd2886SAlan Wright 		default:
27829bd2886SAlan Wright 			return (NT_STATUS_NONE_MAPPED);
27929bd2886SAlan Wright 		}
2807f667e74Sjose borrego 	}
2817f667e74Sjose borrego 
2827f667e74Sjose borrego 	if (smb_getnetbiosname(hostname, MAXHOSTNAMELEN) == 0)
2837f667e74Sjose borrego 		account->a_domain = strdup(hostname);
2847f667e74Sjose borrego 	account->a_sid = smb_sid_dup(sid);
2857f667e74Sjose borrego 	account->a_domsid = smb_sid_split(sid, &account->a_rid);
2867f667e74Sjose borrego 
2877f667e74Sjose borrego 	if (!smb_account_validate(account)) {
2887f667e74Sjose borrego 		smb_account_free(account);
2897f667e74Sjose borrego 		return (NT_STATUS_NO_MEMORY);
2907f667e74Sjose borrego 	}
2917f667e74Sjose borrego 
2927f667e74Sjose borrego 	return (NT_STATUS_SUCCESS);
2937f667e74Sjose borrego }
2947f667e74Sjose borrego 
2957f667e74Sjose borrego /*
2967f667e74Sjose borrego  * Returns number of SMB users, i.e. users who have entry
2977f667e74Sjose borrego  * in /var/smb/smbpasswd
2987f667e74Sjose borrego  */
2997f667e74Sjose borrego int
smb_sam_usr_cnt(void)3007f667e74Sjose borrego smb_sam_usr_cnt(void)
3017f667e74Sjose borrego {
3027f667e74Sjose borrego 	return (smb_pwd_num());
3037f667e74Sjose borrego }
3047f667e74Sjose borrego 
3057f667e74Sjose borrego /*
30636a00406SGordon Ross  * Updates a list of groups in which the given user is a member
30736a00406SGordon Ross  * by adding any local (SAM) groups.
30836a00406SGordon Ross  *
30936a00406SGordon Ross  * We are a member of local groups where the local group
31036a00406SGordon Ross  * contains either the user's primary SID, or any of their
31136a00406SGordon Ross  * other SIDs such as from domain groups, SID history, etc.
31236a00406SGordon Ross  * We can have indirect membership via domain groups.
3137f667e74Sjose borrego  */
3147f667e74Sjose borrego uint32_t
smb_sam_usr_groups(smb_sid_t * user_sid,smb_ids_t * gids)3157f667e74Sjose borrego smb_sam_usr_groups(smb_sid_t *user_sid, smb_ids_t *gids)
3167f667e74Sjose borrego {
31736a00406SGordon Ross 	smb_ids_t new_gids;
31836a00406SGordon Ross 	smb_id_t *ids, *new_ids;
3197f667e74Sjose borrego 	smb_giter_t gi;
3207f667e74Sjose borrego 	smb_group_t lgrp;
32136a00406SGordon Ross 	int i, gcnt, total_cnt;
32236a00406SGordon Ross 	uint32_t ret;
32336a00406SGordon Ross 	boolean_t member;
3247f667e74Sjose borrego 
32536a00406SGordon Ross 	/*
32636a00406SGordon Ross 	 * First pass: count groups to be added (gcnt)
32736a00406SGordon Ross 	 */
3287f667e74Sjose borrego 	gcnt = 0;
3297f667e74Sjose borrego 	if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS)
3307f667e74Sjose borrego 		return (NT_STATUS_INTERNAL_ERROR);
3317f667e74Sjose borrego 
3327f667e74Sjose borrego 	while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) {
33336a00406SGordon Ross 		member = B_FALSE;
3347f667e74Sjose borrego 		if (smb_lgrp_is_member(&lgrp, user_sid))
33536a00406SGordon Ross 			member = B_TRUE;
33636a00406SGordon Ross 		else for (i = 0, ids = gids->i_ids;
33736a00406SGordon Ross 		    i < gids->i_cnt; i++, ids++) {
33836a00406SGordon Ross 			if (smb_lgrp_is_member(&lgrp, ids->i_sid)) {
33936a00406SGordon Ross 				member = B_TRUE;
34036a00406SGordon Ross 				break;
34136a00406SGordon Ross 			}
34236a00406SGordon Ross 		}
34336a00406SGordon Ross 		/* Careful: only count lgrp once */
34436a00406SGordon Ross 		if (member)
3457f667e74Sjose borrego 			gcnt++;
3467f667e74Sjose borrego 		smb_lgrp_free(&lgrp);
3477f667e74Sjose borrego 	}
3487f667e74Sjose borrego 	smb_lgrp_iterclose(&gi);
3497f667e74Sjose borrego 
3507f667e74Sjose borrego 	if (gcnt == 0)
3517f667e74Sjose borrego 		return (NT_STATUS_SUCCESS);
3527f667e74Sjose borrego 
35336a00406SGordon Ross 	/*
35436a00406SGordon Ross 	 * Second pass: add to groups list.
35536a00406SGordon Ross 	 * Do not modify gcnt after here.
35636a00406SGordon Ross 	 */
3577f667e74Sjose borrego 	if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS)
3587f667e74Sjose borrego 		return (NT_STATUS_INTERNAL_ERROR);
3597f667e74Sjose borrego 
36036a00406SGordon Ross 	/*
36136a00406SGordon Ross 	 * Expand the list (copy to a new, larger one)
36236a00406SGordon Ross 	 * Note: were're copying pointers from the old
36336a00406SGordon Ross 	 * array to the new (larger) array, and then
36436a00406SGordon Ross 	 * adding new pointers after what we copied.
36536a00406SGordon Ross 	 */
36636a00406SGordon Ross 	ret = 0;
36736a00406SGordon Ross 	new_gids.i_cnt = gids->i_cnt;
36836a00406SGordon Ross 	total_cnt = gids->i_cnt + gcnt;
36936a00406SGordon Ross 	new_gids.i_ids = malloc(total_cnt * sizeof (smb_id_t));
37036a00406SGordon Ross 	if (new_gids.i_ids == NULL) {
37136a00406SGordon Ross 		ret = NT_STATUS_NO_MEMORY;
37236a00406SGordon Ross 		goto out;
37336a00406SGordon Ross 	}
37436a00406SGordon Ross 	(void) memcpy(new_gids.i_ids, gids->i_ids,
37536a00406SGordon Ross 	    gids->i_cnt * sizeof (smb_id_t));
37636a00406SGordon Ross 	new_ids = new_gids.i_ids + gids->i_cnt;
37736a00406SGordon Ross 	(void) memset(new_ids, 0, gcnt * sizeof (smb_id_t));
37836a00406SGordon Ross 
37936a00406SGordon Ross 	/*
38036a00406SGordon Ross 	 * Add group SIDs starting at the end of the
38136a00406SGordon Ross 	 * previous list.  (new_ids)
38236a00406SGordon Ross 	 */
3837f667e74Sjose borrego 	while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) {
38436a00406SGordon Ross 		member = B_FALSE;
38536a00406SGordon Ross 		if (smb_lgrp_is_member(&lgrp, user_sid))
38636a00406SGordon Ross 			member = B_TRUE;
38736a00406SGordon Ross 		else for (i = 0, ids = gids->i_ids;
38836a00406SGordon Ross 		    i < gids->i_cnt; i++, ids++) {
38936a00406SGordon Ross 			if (smb_lgrp_is_member(&lgrp, ids->i_sid)) {
39036a00406SGordon Ross 				member = B_TRUE;
39136a00406SGordon Ross 				break;
39236a00406SGordon Ross 			}
3937f667e74Sjose borrego 		}
39436a00406SGordon Ross 		if (member && (new_gids.i_cnt < (gids->i_cnt + gcnt))) {
39536a00406SGordon Ross 			new_ids->i_sid = smb_sid_dup(lgrp.sg_id.gs_sid);
39636a00406SGordon Ross 			if (new_ids->i_sid == NULL) {
3977f667e74Sjose borrego 				smb_lgrp_free(&lgrp);
39836a00406SGordon Ross 				ret = NT_STATUS_NO_MEMORY;
39936a00406SGordon Ross 				goto out;
4007f667e74Sjose borrego 			}
40136a00406SGordon Ross 			new_ids->i_attrs = lgrp.sg_attr;
40236a00406SGordon Ross 			new_ids++;
40336a00406SGordon Ross 			new_gids.i_cnt++;
4047f667e74Sjose borrego 		}
4057f667e74Sjose borrego 		smb_lgrp_free(&lgrp);
4067f667e74Sjose borrego 	}
40736a00406SGordon Ross 
40836a00406SGordon Ross out:
4097f667e74Sjose borrego 	smb_lgrp_iterclose(&gi);
4107f667e74Sjose borrego 
41136a00406SGordon Ross 	if (ret != 0) {
41236a00406SGordon Ross 		if (new_gids.i_ids != NULL) {
41336a00406SGordon Ross 			/*
41436a00406SGordon Ross 			 * Free only the new sids we added.
41536a00406SGordon Ross 			 * The old ones were copied ptrs.
41636a00406SGordon Ross 			 */
41736a00406SGordon Ross 			ids = new_gids.i_ids + gids->i_cnt;
41836a00406SGordon Ross 			for (i = 0; i < gcnt; i++, ids++) {
41936a00406SGordon Ross 				smb_sid_free(ids->i_sid);
42036a00406SGordon Ross 			}
42136a00406SGordon Ross 			free(new_gids.i_ids);
42236a00406SGordon Ross 		}
42336a00406SGordon Ross 		return (ret);
42436a00406SGordon Ross 	}
42536a00406SGordon Ross 
42636a00406SGordon Ross 	/*
42736a00406SGordon Ross 	 * Success! Update passed gids and
42836a00406SGordon Ross 	 * free the old array.
42936a00406SGordon Ross 	 */
43036a00406SGordon Ross 	free(gids->i_ids);
43136a00406SGordon Ross 	*gids = new_gids;
43236a00406SGordon Ross 
4337f667e74Sjose borrego 	return (NT_STATUS_SUCCESS);
4347f667e74Sjose borrego }
4357f667e74Sjose borrego 
4367f667e74Sjose borrego /*
4377f667e74Sjose borrego  * Returns the number of built-in or local groups stored
4387f667e74Sjose borrego  * in /var/smb/smbgroup.db
4397f667e74Sjose borrego  */
4407f667e74Sjose borrego int
smb_sam_grp_cnt(smb_domain_type_t dtype)441a0aa776eSAlan Wright smb_sam_grp_cnt(smb_domain_type_t dtype)
4427f667e74Sjose borrego {
4437f667e74Sjose borrego 	int grpcnt;
4447f667e74Sjose borrego 	int rc;
4457f667e74Sjose borrego 
4467f667e74Sjose borrego 	switch (dtype) {
447a0aa776eSAlan Wright 	case SMB_DOMAIN_BUILTIN:
4489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_lgrp_numbydomain(SMB_DOMAIN_BUILTIN, &grpcnt);
4497f667e74Sjose borrego 		break;
4507f667e74Sjose borrego 
451a0aa776eSAlan Wright 	case SMB_DOMAIN_LOCAL:
4529fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_lgrp_numbydomain(SMB_DOMAIN_LOCAL, &grpcnt);
4537f667e74Sjose borrego 		break;
4547f667e74Sjose borrego 
4557f667e74Sjose borrego 	default:
4567f667e74Sjose borrego 		rc = SMB_LGRP_INVALID_ARG;
4577f667e74Sjose borrego 	}
4587f667e74Sjose borrego 
4597f667e74Sjose borrego 	return ((rc == SMB_LGRP_SUCCESS) ? grpcnt : 0);
4607f667e74Sjose borrego }
4617f667e74Sjose borrego 
4627f667e74Sjose borrego /*
4637f667e74Sjose borrego  * Determines whether the given SID is a member of the group
4647f667e74Sjose borrego  * specified by gname.
4657f667e74Sjose borrego  */
4667f667e74Sjose borrego boolean_t
smb_sam_grp_ismember(const char * gname,smb_sid_t * sid)4677f667e74Sjose borrego smb_sam_grp_ismember(const char *gname, smb_sid_t *sid)
4687f667e74Sjose borrego {
4697f667e74Sjose borrego 	smb_group_t grp;
4707f667e74Sjose borrego 	boolean_t ismember = B_FALSE;
4717f667e74Sjose borrego 
4727f667e74Sjose borrego 	if (smb_lgrp_getbyname((char *)gname, &grp) == SMB_LGRP_SUCCESS) {
4737f667e74Sjose borrego 		ismember = smb_lgrp_is_member(&grp, sid);
4747f667e74Sjose borrego 		smb_lgrp_free(&grp);
4757f667e74Sjose borrego 	}
4767f667e74Sjose borrego 
4777f667e74Sjose borrego 	return (ismember);
4787f667e74Sjose borrego }
4797f667e74Sjose borrego 
4807f667e74Sjose borrego /*
4817f667e74Sjose borrego  * Frees memories allocated for the passed account fields.
48262f63298SVitaliy Gusev  * Initializes @account after all.
4837f667e74Sjose borrego  */
4847f667e74Sjose borrego void
smb_account_free(smb_account_t * account)4857f667e74Sjose borrego smb_account_free(smb_account_t *account)
4867f667e74Sjose borrego {
4877f667e74Sjose borrego 	free(account->a_name);
4887f667e74Sjose borrego 	free(account->a_domain);
4897f667e74Sjose borrego 	smb_sid_free(account->a_sid);
4907f667e74Sjose borrego 	smb_sid_free(account->a_domsid);
49162f63298SVitaliy Gusev 
49262f63298SVitaliy Gusev 	bzero(account, sizeof (smb_account_t));
4937f667e74Sjose borrego }
4947f667e74Sjose borrego 
4957f667e74Sjose borrego /*
4967f667e74Sjose borrego  * Validates the given account.
4977f667e74Sjose borrego  */
4987f667e74Sjose borrego boolean_t
smb_account_validate(smb_account_t * account)4997f667e74Sjose borrego smb_account_validate(smb_account_t *account)
5007f667e74Sjose borrego {
5017f667e74Sjose borrego 	return ((account->a_name != NULL) && (account->a_sid != NULL) &&
5027f667e74Sjose borrego 	    (account->a_domain != NULL) && (account->a_domsid != NULL));
5037f667e74Sjose borrego }
5047f667e74Sjose borrego 
5057f667e74Sjose borrego /*
5067f667e74Sjose borrego  * Lookup local SMB user account database (/var/smb/smbpasswd)
5077f667e74Sjose borrego  * if there's a match query its SID from idmap service and make
5087f667e74Sjose borrego  * sure the SID is a local SID.
5097f667e74Sjose borrego  *
5107f667e74Sjose borrego  * The memory for the returned SID must be freed by the caller.
5117f667e74Sjose borrego  */
5127f667e74Sjose borrego static uint32_t
smb_sam_lookup_user(char * name,smb_sid_t ** sid)5137f667e74Sjose borrego smb_sam_lookup_user(char *name, smb_sid_t **sid)
5147f667e74Sjose borrego {
5157f667e74Sjose borrego 	smb_passwd_t smbpw;
5167f667e74Sjose borrego 
5177f667e74Sjose borrego 	if (smb_pwd_getpwnam(name, &smbpw) == NULL)
5187f667e74Sjose borrego 		return (NT_STATUS_NO_SUCH_USER);
5197f667e74Sjose borrego 
5207f667e74Sjose borrego 	if (smb_idmap_getsid(smbpw.pw_uid, SMB_IDMAP_USER, sid)
5217f667e74Sjose borrego 	    != IDMAP_SUCCESS)
5227f667e74Sjose borrego 		return (NT_STATUS_NONE_MAPPED);
5237f667e74Sjose borrego 
5247f667e74Sjose borrego 	if (!smb_sid_islocal(*sid)) {
5257f667e74Sjose borrego 		smb_sid_free(*sid);
5267f667e74Sjose borrego 		return (NT_STATUS_NONE_MAPPED);
5277f667e74Sjose borrego 	}
5287f667e74Sjose borrego 
5297f667e74Sjose borrego 	return (NT_STATUS_SUCCESS);
5307f667e74Sjose borrego }
5317f667e74Sjose borrego 
5327f667e74Sjose borrego /*
5337f667e74Sjose borrego  * Lookup local SMB group account database (/var/smb/smbgroup.db)
5347f667e74Sjose borrego  * The memory for the returned SID must be freed by the caller.
5357f667e74Sjose borrego  */
5367f667e74Sjose borrego static uint32_t
smb_sam_lookup_group(char * name,smb_sid_t ** sid)5377f667e74Sjose borrego smb_sam_lookup_group(char *name, smb_sid_t **sid)
5387f667e74Sjose borrego {
5397f667e74Sjose borrego 	smb_group_t grp;
5407f667e74Sjose borrego 
5417f667e74Sjose borrego 	if (smb_lgrp_getbyname(name, &grp) != SMB_LGRP_SUCCESS)
5427f667e74Sjose borrego 		return (NT_STATUS_NO_SUCH_ALIAS);
5437f667e74Sjose borrego 
5447f667e74Sjose borrego 	*sid = smb_sid_dup(grp.sg_id.gs_sid);
5457f667e74Sjose borrego 	smb_lgrp_free(&grp);
5467f667e74Sjose borrego 
5477f667e74Sjose borrego 	return ((*sid == NULL) ? NT_STATUS_NO_MEMORY : NT_STATUS_SUCCESS);
5487f667e74Sjose borrego }
54929bd2886SAlan Wright 
55029bd2886SAlan Wright static smb_lwka_t *
smb_lwka_lookup_name(char * name)55129bd2886SAlan Wright smb_lwka_lookup_name(char *name)
55229bd2886SAlan Wright {
55329bd2886SAlan Wright 	int i;
55429bd2886SAlan Wright 
55529bd2886SAlan Wright 	for (i = 0; i < SMB_LWKA_NUM; i++) {
556bbf6f00cSJordan Brown 		if (smb_strcasecmp(name, lwka_tbl[i].lwka_name, 0) == 0)
55729bd2886SAlan Wright 			return (&lwka_tbl[i]);
55829bd2886SAlan Wright 	}
55929bd2886SAlan Wright 
56029bd2886SAlan Wright 	return (NULL);
56129bd2886SAlan Wright }
56229bd2886SAlan Wright 
56329bd2886SAlan Wright static smb_lwka_t *
smb_lwka_lookup_sid(smb_sid_t * sid)56429bd2886SAlan Wright smb_lwka_lookup_sid(smb_sid_t *sid)
56529bd2886SAlan Wright {
56629bd2886SAlan Wright 	uint32_t rid;
56729bd2886SAlan Wright 	int i;
56829bd2886SAlan Wright 
56929bd2886SAlan Wright 	(void) smb_sid_getrid(sid, &rid);
57029bd2886SAlan Wright 	if (rid > 999)
57129bd2886SAlan Wright 		return (NULL);
57229bd2886SAlan Wright 
57329bd2886SAlan Wright 	for (i = 0; i < SMB_LWKA_NUM; i++) {
57429bd2886SAlan Wright 		if (rid == lwka_tbl[i].lwka_rid)
57529bd2886SAlan Wright 			return (&lwka_tbl[i]);
57629bd2886SAlan Wright 	}
57729bd2886SAlan Wright 
57829bd2886SAlan Wright 	return (NULL);
57929bd2886SAlan Wright }
580b819cea2SGordon Ross 
581b819cea2SGordon Ross /*
582b819cea2SGordon Ross  * smb_sid_islocal
583b819cea2SGordon Ross  *
584b819cea2SGordon Ross  * Check a SID to see if it belongs to the local domain.
585b819cea2SGordon Ross  */
586b819cea2SGordon Ross boolean_t
smb_sid_islocal(smb_sid_t * sid)587b819cea2SGordon Ross smb_sid_islocal(smb_sid_t *sid)
588b819cea2SGordon Ross {
589b819cea2SGordon Ross 	smb_domain_t di;
590b819cea2SGordon Ross 	boolean_t islocal = B_FALSE;
591b819cea2SGordon Ross 
592b819cea2SGordon Ross 	if (smb_domain_lookup_type(SMB_DOMAIN_LOCAL, &di))
593b819cea2SGordon Ross 		islocal = smb_sid_indomain(di.di_binsid, sid);
594b819cea2SGordon Ross 
595b819cea2SGordon Ross 	return (islocal);
596b819cea2SGordon Ross }
597b819cea2SGordon Ross 
598b819cea2SGordon Ross void
smb_ids_free(smb_ids_t * ids)599b819cea2SGordon Ross smb_ids_free(smb_ids_t *ids)
600b819cea2SGordon Ross {
601b819cea2SGordon Ross 	smb_id_t *id;
602b819cea2SGordon Ross 	int i;
603b819cea2SGordon Ross 
604b819cea2SGordon Ross 	if ((ids != NULL) && (ids->i_ids != NULL)) {
605b819cea2SGordon Ross 		id = ids->i_ids;
606b819cea2SGordon Ross 		for (i = 0; i < ids->i_cnt; i++, id++)
607b819cea2SGordon Ross 			smb_sid_free(id->i_sid);
608b819cea2SGordon Ross 
609b819cea2SGordon Ross 		free(ids->i_ids);
610b819cea2SGordon Ross 	}
611b819cea2SGordon Ross }
612