xref: /titanic_41/usr/src/lib/smbsrv/libsmb/common/smb_sam.c (revision 7206bf49b1fe641544165ee97f63856da95e0868)
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.
24*7206bf49SGordon Ross  *
25*7206bf49SGordon Ross  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
267f667e74Sjose borrego  */
277f667e74Sjose borrego 
287f667e74Sjose borrego #include <strings.h>
297f667e74Sjose borrego #include <smbsrv/libsmb.h>
307f667e74Sjose borrego 
317f667e74Sjose borrego extern int smb_pwd_num(void);
329fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States extern int smb_lgrp_numbydomain(smb_domain_type_t, int *);
337f667e74Sjose borrego 
347f667e74Sjose borrego static uint32_t smb_sam_lookup_user(char *, smb_sid_t **);
357f667e74Sjose borrego static uint32_t smb_sam_lookup_group(char *, smb_sid_t **);
367f667e74Sjose borrego 
377f667e74Sjose borrego /*
3829bd2886SAlan Wright  * Local well-known accounts data structure table and prototypes
3929bd2886SAlan Wright  */
4029bd2886SAlan Wright typedef struct smb_lwka {
4129bd2886SAlan Wright 	uint32_t	lwka_rid;
4229bd2886SAlan Wright 	char		*lwka_name;
4329bd2886SAlan Wright 	uint16_t	lwka_type;
4429bd2886SAlan Wright } smb_lwka_t;
4529bd2886SAlan Wright 
4629bd2886SAlan Wright static smb_lwka_t lwka_tbl[] = {
4729bd2886SAlan Wright 	{ 500, "Administrator", SidTypeUser },
4829bd2886SAlan Wright 	{ 501, "Guest", SidTypeUser },
4929bd2886SAlan Wright 	{ 502, "KRBTGT", SidTypeUser },
5029bd2886SAlan Wright 	{ 512, "Domain Admins", SidTypeGroup },
5129bd2886SAlan Wright 	{ 513, "Domain Users", SidTypeGroup },
5229bd2886SAlan Wright 	{ 514, "Domain Guests", SidTypeGroup },
5329bd2886SAlan Wright 	{ 516, "Domain Controllers", SidTypeGroup },
5429bd2886SAlan Wright 	{ 517, "Cert Publishers", SidTypeGroup },
5529bd2886SAlan Wright 	{ 518, "Schema Admins", SidTypeGroup },
5629bd2886SAlan Wright 	{ 519, "Enterprise Admins", SidTypeGroup },
5729bd2886SAlan Wright 	{ 520, "Global Policy Creator Owners", SidTypeGroup },
5829bd2886SAlan Wright 	{ 533, "RAS and IAS Servers", SidTypeGroup }
5929bd2886SAlan Wright };
6029bd2886SAlan Wright 
6129bd2886SAlan Wright #define	SMB_LWKA_NUM	(sizeof (lwka_tbl)/sizeof (lwka_tbl[0]))
6229bd2886SAlan Wright 
6329bd2886SAlan Wright static smb_lwka_t *smb_lwka_lookup_name(char *);
6429bd2886SAlan Wright static smb_lwka_t *smb_lwka_lookup_sid(smb_sid_t *);
6529bd2886SAlan Wright 
6629bd2886SAlan Wright /*
677f667e74Sjose borrego  * Looks up the given name in local account databases:
687f667e74Sjose borrego  *
697f667e74Sjose borrego  * SMB Local users are looked up in /var/smb/smbpasswd
707f667e74Sjose borrego  * SMB Local groups are looked up in /var/smb/smbgroup.db
717f667e74Sjose borrego  *
727f667e74Sjose borrego  * If the account is found, its information is populated
737f667e74Sjose borrego  * in the passed smb_account_t structure. Caller must free
747f667e74Sjose borrego  * allocated memories by calling smb_account_free() upon
757f667e74Sjose borrego  * successful return.
767f667e74Sjose borrego  *
777f667e74Sjose borrego  * The type of account is specified by 'type', which can be user,
787f667e74Sjose borrego  * alias (local group) or unknown. If the caller doesn't know
797f667e74Sjose borrego  * whether the name is a user or group name then SidTypeUnknown
807f667e74Sjose borrego  * should be passed.
817f667e74Sjose borrego  *
827f667e74Sjose borrego  * If a local user and group have the same name, the user will
837f667e74Sjose borrego  * always be picked. Note that this situation cannot happen on
847f667e74Sjose borrego  * Windows systems.
857f667e74Sjose borrego  *
867f667e74Sjose borrego  * If a SMB local user/group is found but it turns out that
877f667e74Sjose borrego  * it'll be mapped to a domain user/group the lookup is considered
887f667e74Sjose borrego  * failed and NT_STATUS_NONE_MAPPED is returned.
897f667e74Sjose borrego  *
907f667e74Sjose borrego  * Return status:
917f667e74Sjose borrego  *
927f667e74Sjose borrego  *   NT_STATUS_NOT_FOUND	This is not a local account
937f667e74Sjose borrego  *   NT_STATUS_NONE_MAPPED	It's a local account but cannot be
947f667e74Sjose borrego  *   				translated.
957f667e74Sjose borrego  *   other error status codes.
967f667e74Sjose borrego  */
977f667e74Sjose borrego uint32_t
smb_sam_lookup_name(char * domain,char * name,uint16_t type,smb_account_t * account)987f667e74Sjose borrego smb_sam_lookup_name(char *domain, char *name, uint16_t type,
997f667e74Sjose borrego     smb_account_t *account)
1007f667e74Sjose borrego {
101a0aa776eSAlan Wright 	smb_domain_t di;
1027f667e74Sjose borrego 	smb_sid_t *sid;
1037f667e74Sjose borrego 	uint32_t status;
10429bd2886SAlan Wright 	smb_lwka_t *lwka;
1057f667e74Sjose borrego 
1067f667e74Sjose borrego 	bzero(account, sizeof (smb_account_t));
1077f667e74Sjose borrego 
1087f667e74Sjose borrego 	if (domain != NULL) {
109a0aa776eSAlan Wright 		if (!smb_domain_lookup_name(domain, &di) ||
110a0aa776eSAlan Wright 		    (di.di_type != SMB_DOMAIN_LOCAL))
1117f667e74Sjose borrego 			return (NT_STATUS_NOT_FOUND);
1127f667e74Sjose borrego 
1137f667e74Sjose borrego 		/* Only Netbios hostname is accepted */
114bbf6f00cSJordan Brown 		if (smb_strcasecmp(domain, di.di_nbname, 0) != 0)
1157f667e74Sjose borrego 			return (NT_STATUS_NONE_MAPPED);
11629bd2886SAlan Wright 	} else {
117a0aa776eSAlan Wright 		if (!smb_domain_lookup_type(SMB_DOMAIN_LOCAL, &di))
11829bd2886SAlan Wright 			return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
1197f667e74Sjose borrego 	}
1207f667e74Sjose borrego 
121bbf6f00cSJordan Brown 	if (smb_strcasecmp(name, di.di_nbname, 0) == 0) {
12229bd2886SAlan Wright 		/* This is the local domain name */
12329bd2886SAlan Wright 		account->a_type = SidTypeDomain;
12429bd2886SAlan Wright 		account->a_name = strdup("");
12529bd2886SAlan Wright 		account->a_domain = strdup(di.di_nbname);
12629bd2886SAlan Wright 		account->a_sid = smb_sid_dup(di.di_binsid);
12729bd2886SAlan Wright 		account->a_domsid = smb_sid_dup(di.di_binsid);
12829bd2886SAlan Wright 		account->a_rid = (uint32_t)-1;
12929bd2886SAlan Wright 
13029bd2886SAlan Wright 		if (!smb_account_validate(account)) {
13129bd2886SAlan Wright 			smb_account_free(account);
13229bd2886SAlan Wright 			return (NT_STATUS_NO_MEMORY);
13329bd2886SAlan Wright 		}
13429bd2886SAlan Wright 
13529bd2886SAlan Wright 		return (NT_STATUS_SUCCESS);
13629bd2886SAlan Wright 	}
13729bd2886SAlan Wright 
13829bd2886SAlan Wright 	if ((lwka = smb_lwka_lookup_name(name)) != NULL) {
13929bd2886SAlan Wright 		sid = smb_sid_splice(di.di_binsid, lwka->lwka_rid);
14029bd2886SAlan Wright 		type = lwka->lwka_type;
14129bd2886SAlan Wright 	} else {
1427f667e74Sjose borrego 		switch (type) {
1437f667e74Sjose borrego 		case SidTypeUser:
1447f667e74Sjose borrego 			status = smb_sam_lookup_user(name, &sid);
1457f667e74Sjose borrego 			if (status != NT_STATUS_SUCCESS)
1467f667e74Sjose borrego 				return (status);
1477f667e74Sjose borrego 			break;
1487f667e74Sjose borrego 
1497f667e74Sjose borrego 		case SidTypeAlias:
1507f667e74Sjose borrego 			status = smb_sam_lookup_group(name, &sid);
1517f667e74Sjose borrego 			if (status != NT_STATUS_SUCCESS)
1527f667e74Sjose borrego 				return (status);
1537f667e74Sjose borrego 			break;
1547f667e74Sjose borrego 
1557f667e74Sjose borrego 		case SidTypeUnknown:
1567f667e74Sjose borrego 			type = SidTypeUser;
1577f667e74Sjose borrego 			status = smb_sam_lookup_user(name, &sid);
1587f667e74Sjose borrego 			if (status == NT_STATUS_SUCCESS)
1597f667e74Sjose borrego 				break;
1607f667e74Sjose borrego 
1617f667e74Sjose borrego 			if (status == NT_STATUS_NONE_MAPPED)
1627f667e74Sjose borrego 				return (status);
1637f667e74Sjose borrego 
1647f667e74Sjose borrego 			type = SidTypeAlias;
1657f667e74Sjose borrego 			status = smb_sam_lookup_group(name, &sid);
1667f667e74Sjose borrego 			if (status != NT_STATUS_SUCCESS)
1677f667e74Sjose borrego 				return (status);
1687f667e74Sjose borrego 			break;
1697f667e74Sjose borrego 
1707f667e74Sjose borrego 		default:
1717f667e74Sjose borrego 			return (NT_STATUS_INVALID_PARAMETER);
1727f667e74Sjose borrego 		}
17329bd2886SAlan Wright 	}
1747f667e74Sjose borrego 
1757f667e74Sjose borrego 	account->a_name = strdup(name);
1767f667e74Sjose borrego 	account->a_sid = sid;
17729bd2886SAlan Wright 	account->a_domain = strdup(di.di_nbname);
1787f667e74Sjose borrego 	account->a_domsid = smb_sid_split(sid, &account->a_rid);
1797f667e74Sjose borrego 	account->a_type = type;
1807f667e74Sjose borrego 
1817f667e74Sjose borrego 	if (!smb_account_validate(account)) {
1827f667e74Sjose borrego 		smb_account_free(account);
1837f667e74Sjose borrego 		return (NT_STATUS_NO_MEMORY);
1847f667e74Sjose borrego 	}
1857f667e74Sjose borrego 
1867f667e74Sjose borrego 	return (NT_STATUS_SUCCESS);
1877f667e74Sjose borrego }
1887f667e74Sjose borrego 
1897f667e74Sjose borrego /*
1907f667e74Sjose borrego  * Looks up the given SID in local account databases:
1917f667e74Sjose borrego  *
1927f667e74Sjose borrego  * SMB Local users are looked up in /var/smb/smbpasswd
1937f667e74Sjose borrego  * SMB Local groups are looked up in /var/smb/smbgroup.db
1947f667e74Sjose borrego  *
1957f667e74Sjose borrego  * If the account is found, its information is populated
1967f667e74Sjose borrego  * in the passed smb_account_t structure. Caller must free
1977f667e74Sjose borrego  * allocated memories by calling smb_account_free() upon
1987f667e74Sjose borrego  * successful return.
1997f667e74Sjose borrego  *
2007f667e74Sjose borrego  * Return status:
2017f667e74Sjose borrego  *
2027f667e74Sjose borrego  *   NT_STATUS_NOT_FOUND	This is not a local account
2037f667e74Sjose borrego  *   NT_STATUS_NONE_MAPPED	It's a local account but cannot be
2047f667e74Sjose borrego  *   				translated.
2057f667e74Sjose borrego  *   other error status codes.
2067f667e74Sjose borrego  */
2077f667e74Sjose borrego uint32_t
smb_sam_lookup_sid(smb_sid_t * sid,smb_account_t * account)2087f667e74Sjose borrego smb_sam_lookup_sid(smb_sid_t *sid, smb_account_t *account)
2097f667e74Sjose borrego {
2107f667e74Sjose borrego 	char hostname[MAXHOSTNAMELEN];
2117f667e74Sjose borrego 	smb_passwd_t smbpw;
2127f667e74Sjose borrego 	smb_group_t grp;
21329bd2886SAlan Wright 	smb_lwka_t *lwka;
214a0aa776eSAlan Wright 	smb_domain_t di;
2157f667e74Sjose borrego 	uint32_t rid;
2167f667e74Sjose borrego 	uid_t id;
2177f667e74Sjose borrego 	int id_type;
2187f667e74Sjose borrego 	int rc;
2197f667e74Sjose borrego 
2207f667e74Sjose borrego 	bzero(account, sizeof (smb_account_t));
2217f667e74Sjose borrego 
222a0aa776eSAlan Wright 	if (!smb_domain_lookup_type(SMB_DOMAIN_LOCAL, &di))
22329bd2886SAlan Wright 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
2247f667e74Sjose borrego 
22529bd2886SAlan Wright 	if (smb_sid_cmp(sid, di.di_binsid)) {
22629bd2886SAlan Wright 		/* This is the local domain SID */
22729bd2886SAlan Wright 		account->a_type = SidTypeDomain;
22829bd2886SAlan Wright 		account->a_name = strdup("");
22929bd2886SAlan Wright 		account->a_domain = strdup(di.di_nbname);
23029bd2886SAlan Wright 		account->a_sid = smb_sid_dup(sid);
23129bd2886SAlan Wright 		account->a_domsid = smb_sid_dup(sid);
23229bd2886SAlan Wright 		account->a_rid = (uint32_t)-1;
23329bd2886SAlan Wright 
23429bd2886SAlan Wright 		if (!smb_account_validate(account)) {
23529bd2886SAlan Wright 			smb_account_free(account);
23629bd2886SAlan Wright 			return (NT_STATUS_NO_MEMORY);
23729bd2886SAlan Wright 		}
23829bd2886SAlan Wright 
23929bd2886SAlan Wright 		return (NT_STATUS_SUCCESS);
24029bd2886SAlan Wright 	}
24129bd2886SAlan Wright 
24229bd2886SAlan Wright 	if (!smb_sid_indomain(di.di_binsid, sid)) {
24329bd2886SAlan Wright 		/* This is not a local SID */
24429bd2886SAlan Wright 		return (NT_STATUS_NOT_FOUND);
24529bd2886SAlan Wright 	}
24629bd2886SAlan Wright 
24729bd2886SAlan Wright 	if ((lwka = smb_lwka_lookup_sid(sid)) != NULL) {
24829bd2886SAlan Wright 		account->a_type = lwka->lwka_type;
24929bd2886SAlan Wright 		account->a_name = strdup(lwka->lwka_name);
25029bd2886SAlan Wright 	} else {
2517f667e74Sjose borrego 		id_type = SMB_IDMAP_UNKNOWN;
2527f667e74Sjose borrego 		if (smb_idmap_getid(sid, &id, &id_type) != IDMAP_SUCCESS)
2537f667e74Sjose borrego 			return (NT_STATUS_NONE_MAPPED);
2547f667e74Sjose borrego 
2557f667e74Sjose borrego 		switch (id_type) {
2567f667e74Sjose borrego 		case SMB_IDMAP_USER:
2577f667e74Sjose borrego 			account->a_type = SidTypeUser;
2587f667e74Sjose borrego 			if (smb_pwd_getpwuid(id, &smbpw) == NULL)
2597f667e74Sjose borrego 				return (NT_STATUS_NO_SUCH_USER);
2607f667e74Sjose borrego 
2617f667e74Sjose borrego 			account->a_name = strdup(smbpw.pw_name);
2627f667e74Sjose borrego 			break;
2637f667e74Sjose borrego 
2647f667e74Sjose borrego 		case SMB_IDMAP_GROUP:
2657f667e74Sjose borrego 			account->a_type = SidTypeAlias;
2667f667e74Sjose borrego 			(void) smb_sid_getrid(sid, &rid);
2679fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			rc = smb_lgrp_getbyrid(rid, SMB_DOMAIN_LOCAL, &grp);
2687f667e74Sjose borrego 			if (rc != SMB_LGRP_SUCCESS)
2697f667e74Sjose borrego 				return (NT_STATUS_NO_SUCH_ALIAS);
2707f667e74Sjose borrego 
2717f667e74Sjose borrego 			account->a_name = strdup(grp.sg_name);
2727f667e74Sjose borrego 			smb_lgrp_free(&grp);
2737f667e74Sjose borrego 			break;
2747f667e74Sjose borrego 
2757f667e74Sjose borrego 		default:
2767f667e74Sjose borrego 			return (NT_STATUS_NONE_MAPPED);
2777f667e74Sjose borrego 		}
27829bd2886SAlan Wright 	}
2797f667e74Sjose borrego 
2807f667e74Sjose borrego 	if (smb_getnetbiosname(hostname, MAXHOSTNAMELEN) == 0)
2817f667e74Sjose borrego 		account->a_domain = strdup(hostname);
2827f667e74Sjose borrego 	account->a_sid = smb_sid_dup(sid);
2837f667e74Sjose borrego 	account->a_domsid = smb_sid_split(sid, &account->a_rid);
2847f667e74Sjose borrego 
2857f667e74Sjose borrego 	if (!smb_account_validate(account)) {
2867f667e74Sjose borrego 		smb_account_free(account);
2877f667e74Sjose borrego 		return (NT_STATUS_NO_MEMORY);
2887f667e74Sjose borrego 	}
2897f667e74Sjose borrego 
2907f667e74Sjose borrego 	return (NT_STATUS_SUCCESS);
2917f667e74Sjose borrego }
2927f667e74Sjose borrego 
2937f667e74Sjose borrego /*
2947f667e74Sjose borrego  * Returns number of SMB users, i.e. users who have entry
2957f667e74Sjose borrego  * in /var/smb/smbpasswd
2967f667e74Sjose borrego  */
2977f667e74Sjose borrego int
smb_sam_usr_cnt(void)2987f667e74Sjose borrego smb_sam_usr_cnt(void)
2997f667e74Sjose borrego {
3007f667e74Sjose borrego 	return (smb_pwd_num());
3017f667e74Sjose borrego }
3027f667e74Sjose borrego 
3037f667e74Sjose borrego /*
30436a00406SGordon Ross  * Updates a list of groups in which the given user is a member
30536a00406SGordon Ross  * by adding any local (SAM) groups.
30636a00406SGordon Ross  *
30736a00406SGordon Ross  * We are a member of local groups where the local group
30836a00406SGordon Ross  * contains either the user's primary SID, or any of their
30936a00406SGordon Ross  * other SIDs such as from domain groups, SID history, etc.
31036a00406SGordon Ross  * We can have indirect membership via domain groups.
3117f667e74Sjose borrego  */
3127f667e74Sjose borrego uint32_t
smb_sam_usr_groups(smb_sid_t * user_sid,smb_ids_t * gids)3137f667e74Sjose borrego smb_sam_usr_groups(smb_sid_t *user_sid, smb_ids_t *gids)
3147f667e74Sjose borrego {
31536a00406SGordon Ross 	smb_ids_t new_gids;
31636a00406SGordon Ross 	smb_id_t *ids, *new_ids;
3177f667e74Sjose borrego 	smb_giter_t gi;
3187f667e74Sjose borrego 	smb_group_t lgrp;
31936a00406SGordon Ross 	int i, gcnt, total_cnt;
32036a00406SGordon Ross 	uint32_t ret;
32136a00406SGordon Ross 	boolean_t member;
3227f667e74Sjose borrego 
32336a00406SGordon Ross 	/*
32436a00406SGordon Ross 	 * First pass: count groups to be added (gcnt)
32536a00406SGordon Ross 	 */
3267f667e74Sjose borrego 	gcnt = 0;
3277f667e74Sjose borrego 	if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS)
3287f667e74Sjose borrego 		return (NT_STATUS_INTERNAL_ERROR);
3297f667e74Sjose borrego 
3307f667e74Sjose borrego 	while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) {
33136a00406SGordon Ross 		member = B_FALSE;
3327f667e74Sjose borrego 		if (smb_lgrp_is_member(&lgrp, user_sid))
33336a00406SGordon Ross 			member = B_TRUE;
33436a00406SGordon Ross 		else for (i = 0, ids = gids->i_ids;
33536a00406SGordon Ross 		    i < gids->i_cnt; i++, ids++) {
33636a00406SGordon Ross 			if (smb_lgrp_is_member(&lgrp, ids->i_sid)) {
33736a00406SGordon Ross 				member = B_TRUE;
33836a00406SGordon Ross 				break;
33936a00406SGordon Ross 			}
34036a00406SGordon Ross 		}
34136a00406SGordon Ross 		/* Careful: only count lgrp once */
34236a00406SGordon Ross 		if (member)
3437f667e74Sjose borrego 			gcnt++;
3447f667e74Sjose borrego 		smb_lgrp_free(&lgrp);
3457f667e74Sjose borrego 	}
3467f667e74Sjose borrego 	smb_lgrp_iterclose(&gi);
3477f667e74Sjose borrego 
3487f667e74Sjose borrego 	if (gcnt == 0)
3497f667e74Sjose borrego 		return (NT_STATUS_SUCCESS);
3507f667e74Sjose borrego 
35136a00406SGordon Ross 	/*
35236a00406SGordon Ross 	 * Second pass: add to groups list.
35336a00406SGordon Ross 	 * Do not modify gcnt after here.
35436a00406SGordon Ross 	 */
3557f667e74Sjose borrego 	if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS)
3567f667e74Sjose borrego 		return (NT_STATUS_INTERNAL_ERROR);
3577f667e74Sjose borrego 
35836a00406SGordon Ross 	/*
35936a00406SGordon Ross 	 * Expand the list (copy to a new, larger one)
36036a00406SGordon Ross 	 * Note: were're copying pointers from the old
36136a00406SGordon Ross 	 * array to the new (larger) array, and then
36236a00406SGordon Ross 	 * adding new pointers after what we copied.
36336a00406SGordon Ross 	 */
36436a00406SGordon Ross 	ret = 0;
36536a00406SGordon Ross 	new_gids.i_cnt = gids->i_cnt;
36636a00406SGordon Ross 	total_cnt = gids->i_cnt + gcnt;
36736a00406SGordon Ross 	new_gids.i_ids = malloc(total_cnt * sizeof (smb_id_t));
36836a00406SGordon Ross 	if (new_gids.i_ids == NULL) {
36936a00406SGordon Ross 		ret = NT_STATUS_NO_MEMORY;
37036a00406SGordon Ross 		goto out;
37136a00406SGordon Ross 	}
37236a00406SGordon Ross 	(void) memcpy(new_gids.i_ids, gids->i_ids,
37336a00406SGordon Ross 	    gids->i_cnt * sizeof (smb_id_t));
37436a00406SGordon Ross 	new_ids = new_gids.i_ids + gids->i_cnt;
37536a00406SGordon Ross 	(void) memset(new_ids, 0, gcnt * sizeof (smb_id_t));
37636a00406SGordon Ross 
37736a00406SGordon Ross 	/*
37836a00406SGordon Ross 	 * Add group SIDs starting at the end of the
37936a00406SGordon Ross 	 * previous list.  (new_ids)
38036a00406SGordon Ross 	 */
3817f667e74Sjose borrego 	while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) {
38236a00406SGordon Ross 		member = B_FALSE;
38336a00406SGordon Ross 		if (smb_lgrp_is_member(&lgrp, user_sid))
38436a00406SGordon Ross 			member = B_TRUE;
38536a00406SGordon Ross 		else for (i = 0, ids = gids->i_ids;
38636a00406SGordon Ross 		    i < gids->i_cnt; i++, ids++) {
38736a00406SGordon Ross 			if (smb_lgrp_is_member(&lgrp, ids->i_sid)) {
38836a00406SGordon Ross 				member = B_TRUE;
3897f667e74Sjose borrego 				break;
3907f667e74Sjose borrego 			}
3917f667e74Sjose borrego 		}
39236a00406SGordon Ross 		if (member && (new_gids.i_cnt < (gids->i_cnt + gcnt))) {
39336a00406SGordon Ross 			new_ids->i_sid = smb_sid_dup(lgrp.sg_id.gs_sid);
39436a00406SGordon Ross 			if (new_ids->i_sid == NULL) {
39536a00406SGordon Ross 				smb_lgrp_free(&lgrp);
39636a00406SGordon Ross 				ret = NT_STATUS_NO_MEMORY;
39736a00406SGordon Ross 				goto out;
39836a00406SGordon Ross 			}
39936a00406SGordon Ross 			new_ids->i_attrs = lgrp.sg_attr;
40036a00406SGordon Ross 			new_ids++;
40136a00406SGordon Ross 			new_gids.i_cnt++;
4027f667e74Sjose borrego 		}
4037f667e74Sjose borrego 		smb_lgrp_free(&lgrp);
4047f667e74Sjose borrego 	}
40536a00406SGordon Ross 
40636a00406SGordon Ross out:
4077f667e74Sjose borrego 	smb_lgrp_iterclose(&gi);
4087f667e74Sjose borrego 
40936a00406SGordon Ross 	if (ret != 0) {
41036a00406SGordon Ross 		if (new_gids.i_ids != NULL) {
41136a00406SGordon Ross 			/*
41236a00406SGordon Ross 			 * Free only the new sids we added.
41336a00406SGordon Ross 			 * The old ones were copied ptrs.
41436a00406SGordon Ross 			 */
41536a00406SGordon Ross 			ids = new_gids.i_ids + gids->i_cnt;
41636a00406SGordon Ross 			for (i = 0; i < gcnt; i++, ids++) {
41736a00406SGordon Ross 				smb_sid_free(ids->i_sid);
41836a00406SGordon Ross 			}
41936a00406SGordon Ross 			free(new_gids.i_ids);
42036a00406SGordon Ross 		}
42136a00406SGordon Ross 		return (ret);
42236a00406SGordon Ross 	}
42336a00406SGordon Ross 
42436a00406SGordon Ross 	/*
42536a00406SGordon Ross 	 * Success! Update passed gids and
42636a00406SGordon Ross 	 * free the old array.
42736a00406SGordon Ross 	 */
42836a00406SGordon Ross 	free(gids->i_ids);
42936a00406SGordon Ross 	*gids = new_gids;
43036a00406SGordon Ross 
4317f667e74Sjose borrego 	return (NT_STATUS_SUCCESS);
4327f667e74Sjose borrego }
4337f667e74Sjose borrego 
4347f667e74Sjose borrego /*
4357f667e74Sjose borrego  * Returns the number of built-in or local groups stored
4367f667e74Sjose borrego  * in /var/smb/smbgroup.db
4377f667e74Sjose borrego  */
4387f667e74Sjose borrego int
smb_sam_grp_cnt(smb_domain_type_t dtype)439a0aa776eSAlan Wright smb_sam_grp_cnt(smb_domain_type_t dtype)
4407f667e74Sjose borrego {
4417f667e74Sjose borrego 	int grpcnt;
4427f667e74Sjose borrego 	int rc;
4437f667e74Sjose borrego 
4447f667e74Sjose borrego 	switch (dtype) {
445a0aa776eSAlan Wright 	case SMB_DOMAIN_BUILTIN:
4469fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_lgrp_numbydomain(SMB_DOMAIN_BUILTIN, &grpcnt);
4477f667e74Sjose borrego 		break;
4487f667e74Sjose borrego 
449a0aa776eSAlan Wright 	case SMB_DOMAIN_LOCAL:
4509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_lgrp_numbydomain(SMB_DOMAIN_LOCAL, &grpcnt);
4517f667e74Sjose borrego 		break;
4527f667e74Sjose borrego 
4537f667e74Sjose borrego 	default:
4547f667e74Sjose borrego 		rc = SMB_LGRP_INVALID_ARG;
4557f667e74Sjose borrego 	}
4567f667e74Sjose borrego 
4577f667e74Sjose borrego 	return ((rc == SMB_LGRP_SUCCESS) ? grpcnt : 0);
4587f667e74Sjose borrego }
4597f667e74Sjose borrego 
4607f667e74Sjose borrego /*
4617f667e74Sjose borrego  * Determines whether the given SID is a member of the group
4627f667e74Sjose borrego  * specified by gname.
4637f667e74Sjose borrego  */
4647f667e74Sjose borrego boolean_t
smb_sam_grp_ismember(const char * gname,smb_sid_t * sid)4657f667e74Sjose borrego smb_sam_grp_ismember(const char *gname, smb_sid_t *sid)
4667f667e74Sjose borrego {
4677f667e74Sjose borrego 	smb_group_t grp;
4687f667e74Sjose borrego 	boolean_t ismember = B_FALSE;
4697f667e74Sjose borrego 
4707f667e74Sjose borrego 	if (smb_lgrp_getbyname((char *)gname, &grp) == SMB_LGRP_SUCCESS) {
4717f667e74Sjose borrego 		ismember = smb_lgrp_is_member(&grp, sid);
4727f667e74Sjose borrego 		smb_lgrp_free(&grp);
4737f667e74Sjose borrego 	}
4747f667e74Sjose borrego 
4757f667e74Sjose borrego 	return (ismember);
4767f667e74Sjose borrego }
4777f667e74Sjose borrego 
4787f667e74Sjose borrego /*
4797f667e74Sjose borrego  * Frees memories allocated for the passed account fields.
4807f667e74Sjose borrego  */
4817f667e74Sjose borrego void
smb_account_free(smb_account_t * account)4827f667e74Sjose borrego smb_account_free(smb_account_t *account)
4837f667e74Sjose borrego {
4847f667e74Sjose borrego 	free(account->a_name);
4857f667e74Sjose borrego 	free(account->a_domain);
4867f667e74Sjose borrego 	smb_sid_free(account->a_sid);
4877f667e74Sjose borrego 	smb_sid_free(account->a_domsid);
4887f667e74Sjose borrego }
4897f667e74Sjose borrego 
4907f667e74Sjose borrego /*
4917f667e74Sjose borrego  * Validates the given account.
4927f667e74Sjose borrego  */
4937f667e74Sjose borrego boolean_t
smb_account_validate(smb_account_t * account)4947f667e74Sjose borrego smb_account_validate(smb_account_t *account)
4957f667e74Sjose borrego {
4967f667e74Sjose borrego 	return ((account->a_name != NULL) && (account->a_sid != NULL) &&
4977f667e74Sjose borrego 	    (account->a_domain != NULL) && (account->a_domsid != NULL));
4987f667e74Sjose borrego }
4997f667e74Sjose borrego 
5007f667e74Sjose borrego /*
5017f667e74Sjose borrego  * Lookup local SMB user account database (/var/smb/smbpasswd)
5027f667e74Sjose borrego  * if there's a match query its SID from idmap service and make
5037f667e74Sjose borrego  * sure the SID is a local SID.
5047f667e74Sjose borrego  *
5057f667e74Sjose borrego  * The memory for the returned SID must be freed by the caller.
5067f667e74Sjose borrego  */
5077f667e74Sjose borrego static uint32_t
smb_sam_lookup_user(char * name,smb_sid_t ** sid)5087f667e74Sjose borrego smb_sam_lookup_user(char *name, smb_sid_t **sid)
5097f667e74Sjose borrego {
5107f667e74Sjose borrego 	smb_passwd_t smbpw;
5117f667e74Sjose borrego 
5127f667e74Sjose borrego 	if (smb_pwd_getpwnam(name, &smbpw) == NULL)
5137f667e74Sjose borrego 		return (NT_STATUS_NO_SUCH_USER);
5147f667e74Sjose borrego 
5157f667e74Sjose borrego 	if (smb_idmap_getsid(smbpw.pw_uid, SMB_IDMAP_USER, sid)
5167f667e74Sjose borrego 	    != IDMAP_SUCCESS)
5177f667e74Sjose borrego 		return (NT_STATUS_NONE_MAPPED);
5187f667e74Sjose borrego 
5197f667e74Sjose borrego 	if (!smb_sid_islocal(*sid)) {
5207f667e74Sjose borrego 		smb_sid_free(*sid);
5217f667e74Sjose borrego 		return (NT_STATUS_NONE_MAPPED);
5227f667e74Sjose borrego 	}
5237f667e74Sjose borrego 
5247f667e74Sjose borrego 	return (NT_STATUS_SUCCESS);
5257f667e74Sjose borrego }
5267f667e74Sjose borrego 
5277f667e74Sjose borrego /*
5287f667e74Sjose borrego  * Lookup local SMB group account database (/var/smb/smbgroup.db)
5297f667e74Sjose borrego  * The memory for the returned SID must be freed by the caller.
5307f667e74Sjose borrego  */
5317f667e74Sjose borrego static uint32_t
smb_sam_lookup_group(char * name,smb_sid_t ** sid)5327f667e74Sjose borrego smb_sam_lookup_group(char *name, smb_sid_t **sid)
5337f667e74Sjose borrego {
5347f667e74Sjose borrego 	smb_group_t grp;
5357f667e74Sjose borrego 
5367f667e74Sjose borrego 	if (smb_lgrp_getbyname(name, &grp) != SMB_LGRP_SUCCESS)
5377f667e74Sjose borrego 		return (NT_STATUS_NO_SUCH_ALIAS);
5387f667e74Sjose borrego 
5397f667e74Sjose borrego 	*sid = smb_sid_dup(grp.sg_id.gs_sid);
5407f667e74Sjose borrego 	smb_lgrp_free(&grp);
5417f667e74Sjose borrego 
5427f667e74Sjose borrego 	return ((*sid == NULL) ? NT_STATUS_NO_MEMORY : NT_STATUS_SUCCESS);
5437f667e74Sjose borrego }
54429bd2886SAlan Wright 
54529bd2886SAlan Wright static smb_lwka_t *
smb_lwka_lookup_name(char * name)54629bd2886SAlan Wright smb_lwka_lookup_name(char *name)
54729bd2886SAlan Wright {
54829bd2886SAlan Wright 	int i;
54929bd2886SAlan Wright 
55029bd2886SAlan Wright 	for (i = 0; i < SMB_LWKA_NUM; i++) {
551bbf6f00cSJordan Brown 		if (smb_strcasecmp(name, lwka_tbl[i].lwka_name, 0) == 0)
55229bd2886SAlan Wright 			return (&lwka_tbl[i]);
55329bd2886SAlan Wright 	}
55429bd2886SAlan Wright 
55529bd2886SAlan Wright 	return (NULL);
55629bd2886SAlan Wright }
55729bd2886SAlan Wright 
55829bd2886SAlan Wright static smb_lwka_t *
smb_lwka_lookup_sid(smb_sid_t * sid)55929bd2886SAlan Wright smb_lwka_lookup_sid(smb_sid_t *sid)
56029bd2886SAlan Wright {
56129bd2886SAlan Wright 	uint32_t rid;
56229bd2886SAlan Wright 	int i;
56329bd2886SAlan Wright 
56429bd2886SAlan Wright 	(void) smb_sid_getrid(sid, &rid);
56529bd2886SAlan Wright 	if (rid > 999)
56629bd2886SAlan Wright 		return (NULL);
56729bd2886SAlan Wright 
56829bd2886SAlan Wright 	for (i = 0; i < SMB_LWKA_NUM; i++) {
56929bd2886SAlan Wright 		if (rid == lwka_tbl[i].lwka_rid)
57029bd2886SAlan Wright 			return (&lwka_tbl[i]);
57129bd2886SAlan Wright 	}
57229bd2886SAlan Wright 
57329bd2886SAlan Wright 	return (NULL);
57429bd2886SAlan Wright }
575*7206bf49SGordon Ross 
576*7206bf49SGordon Ross /*
577*7206bf49SGordon Ross  * smb_sid_islocal
578*7206bf49SGordon Ross  *
579*7206bf49SGordon Ross  * Check a SID to see if it belongs to the local domain.
580*7206bf49SGordon Ross  */
581*7206bf49SGordon Ross boolean_t
smb_sid_islocal(smb_sid_t * sid)582*7206bf49SGordon Ross smb_sid_islocal(smb_sid_t *sid)
583*7206bf49SGordon Ross {
584*7206bf49SGordon Ross 	smb_domain_t di;
585*7206bf49SGordon Ross 	boolean_t islocal = B_FALSE;
586*7206bf49SGordon Ross 
587*7206bf49SGordon Ross 	if (smb_domain_lookup_type(SMB_DOMAIN_LOCAL, &di))
588*7206bf49SGordon Ross 		islocal = smb_sid_indomain(di.di_binsid, sid);
589*7206bf49SGordon Ross 
590*7206bf49SGordon Ross 	return (islocal);
591*7206bf49SGordon Ross }
592*7206bf49SGordon Ross 
593*7206bf49SGordon Ross void
smb_ids_free(smb_ids_t * ids)594*7206bf49SGordon Ross smb_ids_free(smb_ids_t *ids)
595*7206bf49SGordon Ross {
596*7206bf49SGordon Ross 	smb_id_t *id;
597*7206bf49SGordon Ross 	int i;
598*7206bf49SGordon Ross 
599*7206bf49SGordon Ross 	if ((ids != NULL) && (ids->i_ids != NULL)) {
600*7206bf49SGordon Ross 		id = ids->i_ids;
601*7206bf49SGordon Ross 		for (i = 0; i < ids->i_cnt; i++, id++)
602*7206bf49SGordon Ross 			smb_sid_free(id->i_sid);
603*7206bf49SGordon Ross 
604*7206bf49SGordon Ross 		free(ids->i_ids);
605*7206bf49SGordon Ross 	}
606*7206bf49SGordon Ross }
607