17568150aSgwr /*
27568150aSgwr  * CDDL HEADER START
37568150aSgwr  *
47568150aSgwr  * The contents of this file are subject to the terms of the
57568150aSgwr  * Common Development and Distribution License (the "License").
67568150aSgwr  * You may not use this file except in compliance with the License.
77568150aSgwr  *
87568150aSgwr  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97568150aSgwr  * or http://www.opensolaris.org/os/licensing.
107568150aSgwr  * See the License for the specific language governing permissions
117568150aSgwr  * and limitations under the License.
127568150aSgwr  *
137568150aSgwr  * When distributing Covered Code, include this CDDL HEADER in each
147568150aSgwr  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157568150aSgwr  * If applicable, add the following below this CDDL HEADER, with the
167568150aSgwr  * fields enclosed by brackets "[]" replaced with your own identifying
177568150aSgwr  * information: Portions Copyright [yyyy] [name of copyright owner]
187568150aSgwr  *
197568150aSgwr  * CDDL HEADER END
207568150aSgwr  */
217568150aSgwr 
227568150aSgwr /*
231fdeec65Sjoyce mcintosh  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24*8329232eSGordon Ross  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
257568150aSgwr  */
267568150aSgwr 
277568150aSgwr /*
2802d09e03SGordon Ross  * ACL conversion support for smbfs
2902d09e03SGordon Ross  * (To/from NT/ZFS-style ACLs.)
307568150aSgwr  */
317568150aSgwr 
327568150aSgwr #include <sys/types.h>
337568150aSgwr #include <sys/errno.h>
3402d09e03SGordon Ross #include <sys/acl.h>
3502d09e03SGordon Ross #include <sys/byteorder.h>
3602d09e03SGordon Ross 
37*8329232eSGordon Ross #if defined(_KERNEL) || defined(_FAKE_KERNEL)
3802d09e03SGordon Ross 
397568150aSgwr #include <sys/cred.h>
407568150aSgwr #include <sys/cmn_err.h>
417568150aSgwr #include <sys/kmem.h>
427568150aSgwr #include <sys/sunddi.h>
437568150aSgwr #include <sys/vnode.h>
447568150aSgwr #include <sys/vfs.h>
457568150aSgwr 
46*8329232eSGordon Ross #else	/* _KERNEL || _FAKE_KERNEL */
4702d09e03SGordon Ross 
487568150aSgwr #include <stdio.h>
4902d09e03SGordon Ross #include <stdlib.h>
507568150aSgwr #include <strings.h>
517568150aSgwr 
52*8329232eSGordon Ross #endif	/* _KERNEL || _FAKE_KERNEL */
537568150aSgwr 
54*8329232eSGordon Ross #ifdef _KERNEL
55*8329232eSGordon Ross #include <sys/kidmap.h>
56*8329232eSGordon Ross #else	/* _KERNEL */
57*8329232eSGordon Ross #include <idmap.h>
5802d09e03SGordon Ross #endif	/* _KERNEL */
597568150aSgwr 
60613a2f6bSGordon Ross #include <netsmb/mchain.h>
61613a2f6bSGordon Ross #include <netsmb/smb.h>
6202d09e03SGordon Ross #include "smbfs_ntacl.h"
637568150aSgwr 
64bd7c6f51SGordon Ross #define	NT_SD_REVISION	1
65bd7c6f51SGordon Ross #define	NT_ACL_REVISION	2
66bd7c6f51SGordon Ross 
67*8329232eSGordon Ross #if defined(_KERNEL) || defined(_FAKE_KERNEL)
687568150aSgwr #define	MALLOC(size) kmem_alloc(size, KM_SLEEP)
697568150aSgwr #define	FREESZ(p, sz) kmem_free(p, sz)
707568150aSgwr #else	/* _KERNEL */
717568150aSgwr #define	MALLOC(size) malloc(size)
72a1a46df0SToomas Soome /*
73a1a46df0SToomas Soome  * Define FREESZ() as inline function so the compiler will not
74a1a46df0SToomas Soome  * trigger variable set but not used warning for sz in calling function.
75a1a46df0SToomas Soome  */
767568150aSgwr /* ARGSUSED */
77a1a46df0SToomas Soome static inline void
FREESZ(void * p,size_t sz __unused)78a1a46df0SToomas Soome FREESZ(void *p, size_t sz __unused)
797568150aSgwr {
807568150aSgwr 	free(p);
817568150aSgwr }
827568150aSgwr #endif	/* _KERNEL */
837568150aSgwr 
847568150aSgwr #define	ERRCHK(expr)	if ((error = expr) != 0) goto errout
857568150aSgwr 
867568150aSgwr /*
877568150aSgwr  * Security IDentifier (SID)
887568150aSgwr  */
897568150aSgwr static void
ifree_sid(i_ntsid_t * sid)907568150aSgwr ifree_sid(i_ntsid_t *sid)
917568150aSgwr {
927568150aSgwr 	size_t sz;
937568150aSgwr 
947568150aSgwr 	if (sid == NULL)
957568150aSgwr 		return;
967568150aSgwr 
977568150aSgwr 	sz = I_SID_SIZE(sid->sid_subauthcount);
987568150aSgwr 	FREESZ(sid, sz);
997568150aSgwr }
1007568150aSgwr 
1017568150aSgwr static int
md_get_sid(mdchain_t * mdp,i_ntsid_t ** sidp)10202d09e03SGordon Ross md_get_sid(mdchain_t *mdp, i_ntsid_t **sidp)
1037568150aSgwr {
1047568150aSgwr 	i_ntsid_t *sid = NULL;
1057568150aSgwr 	uint8_t revision, subauthcount;
1067568150aSgwr 	uint32_t *subauthp;
1077568150aSgwr 	size_t sidsz;
1087568150aSgwr 	int error, i;
1097568150aSgwr 
11002d09e03SGordon Ross 	if ((error = md_get_uint8(mdp, &revision)) != 0)
1117568150aSgwr 		return (error);
11202d09e03SGordon Ross 	if ((error = md_get_uint8(mdp, &subauthcount)) != 0)
1137568150aSgwr 		return (error);
1147568150aSgwr 
1157568150aSgwr 	sidsz = I_SID_SIZE(subauthcount);
1167568150aSgwr 
1177568150aSgwr 	if ((sid = MALLOC(sidsz)) == NULL)
1187568150aSgwr 		return (ENOMEM);
1197568150aSgwr 
1207568150aSgwr 	bzero(sid, sidsz);
1217568150aSgwr 	sid->sid_revision = revision;
1227568150aSgwr 	sid->sid_subauthcount = subauthcount;
12302d09e03SGordon Ross 	ERRCHK(md_get_mem(mdp, sid->sid_authority, 6, MB_MSYSTEM));
1247568150aSgwr 
1257568150aSgwr 	subauthp = &sid->sid_subauthvec[0];
1267568150aSgwr 	for (i = 0; i < subauthcount; i++) {
12702d09e03SGordon Ross 		ERRCHK(md_get_uint32le(mdp, subauthp));
1287568150aSgwr 		subauthp++;
1297568150aSgwr 	}
1307568150aSgwr 
1317568150aSgwr 	/* Success! */
1327568150aSgwr 	*sidp = sid;
1337568150aSgwr 	return (0);
1347568150aSgwr 
1357568150aSgwr errout:
1367568150aSgwr 	ifree_sid(sid);
1377568150aSgwr 	return (error);
1387568150aSgwr }
1397568150aSgwr 
1407568150aSgwr static int
mb_put_sid(mbchain_t * mbp,i_ntsid_t * sid)14102d09e03SGordon Ross mb_put_sid(mbchain_t *mbp, i_ntsid_t *sid)
1427568150aSgwr {
1437568150aSgwr 	uint32_t *subauthp;
1447568150aSgwr 	int error, i;
1457568150aSgwr 
1467568150aSgwr 	if (sid == NULL)
1477568150aSgwr 		return (EINVAL);
1487568150aSgwr 
1497568150aSgwr 	ERRCHK(mb_put_uint8(mbp, sid->sid_revision));
1507568150aSgwr 	ERRCHK(mb_put_uint8(mbp, sid->sid_subauthcount));
15102d09e03SGordon Ross 	ERRCHK(mb_put_mem(mbp, sid->sid_authority, 6, MB_MSYSTEM));
1527568150aSgwr 
1537568150aSgwr 	subauthp = &sid->sid_subauthvec[0];
1547568150aSgwr 	for (i = 0; i < sid->sid_subauthcount; i++) {
1557568150aSgwr 		ERRCHK(mb_put_uint32le(mbp, *subauthp));
1567568150aSgwr 		subauthp++;
1577568150aSgwr 	}
1587568150aSgwr 
1597568150aSgwr 	/* Success! */
1607568150aSgwr 	return (0);
1617568150aSgwr 
1627568150aSgwr errout:
1637568150aSgwr 	return (error);
1647568150aSgwr }
1657568150aSgwr 
1667568150aSgwr 
1677568150aSgwr /*
1687568150aSgwr  * Access Control Entry (ACE)
1697568150aSgwr  */
1707568150aSgwr static void
ifree_ace(i_ntace_t * ace)1717568150aSgwr ifree_ace(i_ntace_t *ace)
1727568150aSgwr {
1737568150aSgwr 
1747568150aSgwr 	if (ace == NULL)
1757568150aSgwr 		return;
1767568150aSgwr 
177bd7c6f51SGordon Ross 	switch (ace->ace_hdr.ace_type) {
178bd7c6f51SGordon Ross 	case ACCESS_ALLOWED_ACE_TYPE:
179bd7c6f51SGordon Ross 	case ACCESS_DENIED_ACE_TYPE:
180bd7c6f51SGordon Ross 	case SYSTEM_AUDIT_ACE_TYPE:
181bd7c6f51SGordon Ross 	case SYSTEM_ALARM_ACE_TYPE:
182bd7c6f51SGordon Ross 		ifree_sid(ace->ace_v2.ace_sid);
183bd7c6f51SGordon Ross 		FREESZ(ace, sizeof (i_ntace_v2_t));
184bd7c6f51SGordon Ross 		break;
185bd7c6f51SGordon Ross 	/* other types todo */
186bd7c6f51SGordon Ross 	default:
187bd7c6f51SGordon Ross 		break;
188bd7c6f51SGordon Ross 	}
1897568150aSgwr }
1907568150aSgwr 
1917568150aSgwr static int
md_get_ace(mdchain_t * mdp,i_ntace_t ** acep)19202d09e03SGordon Ross md_get_ace(mdchain_t *mdp, i_ntace_t **acep)
1937568150aSgwr {
19402d09e03SGordon Ross 	mdchain_t tmp_md;
195bd7c6f51SGordon Ross 	i_ntace_hdr_t ace_hdr;
1967568150aSgwr 	i_ntace_t *ace = NULL;
197bd7c6f51SGordon Ross 	uint16_t alloc_size;
1987568150aSgwr 	int error;
1997568150aSgwr 
2009c9af259SGordon Ross 	/*
2019c9af259SGordon Ross 	 * The ACE is realy variable length,
2029c9af259SGordon Ross 	 * with format determined by the type.
2039c9af259SGordon Ross 	 *
2049c9af259SGordon Ross 	 * There may also be padding after it, so
205bd7c6f51SGordon Ross 	 * decode it using a copy of the mdchain,
2069c9af259SGordon Ross 	 * and then consume the specified length.
2079c9af259SGordon Ross 	 */
20802d09e03SGordon Ross 	tmp_md = *mdp;
2099c9af259SGordon Ross 
210bd7c6f51SGordon Ross 	/* Fixed-size ACE header */
211bd7c6f51SGordon Ross 	ERRCHK(md_get_uint8(&tmp_md, &ace_hdr.ace_type));
212bd7c6f51SGordon Ross 	ERRCHK(md_get_uint8(&tmp_md, &ace_hdr.ace_flags));
213bd7c6f51SGordon Ross 	ERRCHK(md_get_uint16le(&tmp_md, &ace_hdr.ace_size));
214bd7c6f51SGordon Ross 
215bd7c6f51SGordon Ross 	switch (ace_hdr.ace_type) {
216bd7c6f51SGordon Ross 	case ACCESS_ALLOWED_ACE_TYPE:
217bd7c6f51SGordon Ross 	case ACCESS_DENIED_ACE_TYPE:
218bd7c6f51SGordon Ross 	case SYSTEM_AUDIT_ACE_TYPE:
219bd7c6f51SGordon Ross 	case SYSTEM_ALARM_ACE_TYPE:
220bd7c6f51SGordon Ross 		alloc_size = sizeof (i_ntace_v2_t);
221bd7c6f51SGordon Ross 		if ((ace = MALLOC(alloc_size)) == NULL)
222bd7c6f51SGordon Ross 			return (ENOMEM);
223bd7c6f51SGordon Ross 		bzero(ace, alloc_size);
224bd7c6f51SGordon Ross 		/* ACE header */
225bd7c6f51SGordon Ross 		ace->ace_hdr.ace_type = ace_hdr.ace_type;
226bd7c6f51SGordon Ross 		ace->ace_hdr.ace_flags = ace_hdr.ace_flags;
227bd7c6f51SGordon Ross 		ace->ace_hdr.ace_size = alloc_size;
228bd7c6f51SGordon Ross 		/* Type-specific data. */
229bd7c6f51SGordon Ross 		ERRCHK(md_get_uint32le(&tmp_md, &ace->ace_v2.ace_rights));
230bd7c6f51SGordon Ross 		ERRCHK(md_get_sid(&tmp_md, &ace->ace_v2.ace_sid));
231bd7c6f51SGordon Ross 		break;
2327568150aSgwr 
233bd7c6f51SGordon Ross 	/* other types todo */
234bd7c6f51SGordon Ross 	default:
235bd7c6f51SGordon Ross 		error = EIO;
236bd7c6f51SGordon Ross 		goto errout;
237bd7c6f51SGordon Ross 	}
2389c9af259SGordon Ross 
239bd7c6f51SGordon Ross 	/* Now actually consume ace_hdr.ace_size */
240bd7c6f51SGordon Ross 	ERRCHK(md_get_mem(mdp, NULL, ace_hdr.ace_size, MB_MSYSTEM));
2417568150aSgwr 
2427568150aSgwr 	/* Success! */
2437568150aSgwr 	*acep = ace;
2447568150aSgwr 	return (0);
2457568150aSgwr 
2467568150aSgwr errout:
2477568150aSgwr 	ifree_ace(ace);
2487568150aSgwr 	return (error);
2497568150aSgwr }
2507568150aSgwr 
2517568150aSgwr static int
mb_put_ace(mbchain_t * mbp,i_ntace_t * ace)25202d09e03SGordon Ross mb_put_ace(mbchain_t *mbp, i_ntace_t *ace)
2537568150aSgwr {
2547568150aSgwr 	int cnt0, error;
2559c9af259SGordon Ross 	uint16_t ace_len, *ace_len_p;
2567568150aSgwr 
2577568150aSgwr 	if (ace == NULL)
2587568150aSgwr 		return (EINVAL);
2597568150aSgwr 
2607568150aSgwr 	cnt0 = mbp->mb_count;
2617568150aSgwr 
262bd7c6f51SGordon Ross 	/*
263bd7c6f51SGordon Ross 	 * Put the (fixed-size) ACE header
264bd7c6f51SGordon Ross 	 * Will fill in the length later.
265bd7c6f51SGordon Ross 	 */
266bd7c6f51SGordon Ross 	ERRCHK(mb_put_uint8(mbp, ace->ace_hdr.ace_type));
267bd7c6f51SGordon Ross 	ERRCHK(mb_put_uint8(mbp, ace->ace_hdr.ace_flags));
26802d09e03SGordon Ross 	ace_len_p = mb_reserve(mbp, sizeof (*ace_len_p));
26902d09e03SGordon Ross 	if (ace_len_p == NULL) {
27002d09e03SGordon Ross 		error = ENOMEM;
27102d09e03SGordon Ross 		goto errout;
27202d09e03SGordon Ross 	}
2737568150aSgwr 
274bd7c6f51SGordon Ross 	switch (ace->ace_hdr.ace_type) {
275bd7c6f51SGordon Ross 	case ACCESS_ALLOWED_ACE_TYPE:
276bd7c6f51SGordon Ross 	case ACCESS_DENIED_ACE_TYPE:
277bd7c6f51SGordon Ross 	case SYSTEM_AUDIT_ACE_TYPE:
278bd7c6f51SGordon Ross 	case SYSTEM_ALARM_ACE_TYPE:
279bd7c6f51SGordon Ross 		/* Put type-specific data. */
280bd7c6f51SGordon Ross 		ERRCHK(mb_put_uint32le(mbp, ace->ace_v2.ace_rights));
281bd7c6f51SGordon Ross 		ERRCHK(mb_put_sid(mbp, ace->ace_v2.ace_sid));
282bd7c6f51SGordon Ross 		break;
2837568150aSgwr 
284bd7c6f51SGordon Ross 	/* other types todo */
285bd7c6f51SGordon Ross 	default:
286bd7c6f51SGordon Ross 		error = EIO;
287bd7c6f51SGordon Ross 		goto errout;
288bd7c6f51SGordon Ross 	}
289bd7c6f51SGordon Ross 
290bd7c6f51SGordon Ross 	/* Fill in the (OtW) ACE length. */
2917568150aSgwr 	ace_len = mbp->mb_count - cnt0;
2929c9af259SGordon Ross 	*ace_len_p = htoles(ace_len);
2937568150aSgwr 
2947568150aSgwr 	/* Success! */
2957568150aSgwr 	return (0);
2967568150aSgwr 
2977568150aSgwr errout:
2987568150aSgwr 	return (error);
2997568150aSgwr }
3007568150aSgwr 
3017568150aSgwr 
3027568150aSgwr /*
3037568150aSgwr  * Access Control List (ACL)
3047568150aSgwr  */
3057568150aSgwr 
3067568150aSgwr /* Not an OTW structure, so size can be at our convenience. */
3077568150aSgwr #define	I_ACL_SIZE(cnt)	(sizeof (i_ntacl_t) + (cnt) * sizeof (void *))
3087568150aSgwr 
3097568150aSgwr static void
ifree_acl(i_ntacl_t * acl)3107568150aSgwr ifree_acl(i_ntacl_t *acl)
3117568150aSgwr {
3127568150aSgwr 	i_ntace_t **acep;
3137568150aSgwr 	size_t sz;
3147568150aSgwr 	int i;
3157568150aSgwr 
3167568150aSgwr 	if (acl == NULL)
3177568150aSgwr 		return;
3187568150aSgwr 
3197568150aSgwr 	acep = &acl->acl_acevec[0];
3207568150aSgwr 	for (i = 0; i < acl->acl_acecount; i++) {
3217568150aSgwr 		ifree_ace(*acep);
3227568150aSgwr 		acep++;
3237568150aSgwr 	}
3247568150aSgwr 	sz = I_ACL_SIZE(acl->acl_acecount);
3257568150aSgwr 	FREESZ(acl, sz);
3267568150aSgwr }
3277568150aSgwr 
3287568150aSgwr static int
md_get_acl(mdchain_t * mdp,i_ntacl_t ** aclp)32902d09e03SGordon Ross md_get_acl(mdchain_t *mdp, i_ntacl_t **aclp)
3307568150aSgwr {
3317568150aSgwr 	i_ntacl_t *acl = NULL;
3327568150aSgwr 	i_ntace_t **acep;
3337568150aSgwr 	uint8_t revision;
3347568150aSgwr 	uint16_t acl_len, acecount;
3357568150aSgwr 	size_t aclsz;
3367568150aSgwr 	int i, error;
3377568150aSgwr 
33802d09e03SGordon Ross 	if ((error = md_get_uint8(mdp, &revision)) != 0)
3397568150aSgwr 		return (error);
340bd7c6f51SGordon Ross 	if ((error = md_get_uint8(mdp, NULL)) != 0) /* pad1 */
3417568150aSgwr 		return (error);
34202d09e03SGordon Ross 	if ((error = md_get_uint16le(mdp, &acl_len)) != 0)
3437568150aSgwr 		return (error);
34402d09e03SGordon Ross 	if ((error = md_get_uint16le(mdp, &acecount)) != 0)
3457568150aSgwr 		return (error);
346bd7c6f51SGordon Ross 	if ((error = md_get_uint16le(mdp, NULL)) != 0) /* pad2 */
3477568150aSgwr 		return (error);
3487568150aSgwr 
3497568150aSgwr 	aclsz = I_ACL_SIZE(acecount);
3507568150aSgwr 	if ((acl = MALLOC(aclsz)) == NULL)
3517568150aSgwr 		return (ENOMEM);
3527568150aSgwr 	bzero(acl, aclsz);
3537568150aSgwr 	acl->acl_revision = revision;
3547568150aSgwr 	acl->acl_acecount = acecount;
3557568150aSgwr 
3567568150aSgwr 	acep = &acl->acl_acevec[0];
3577568150aSgwr 	for (i = 0; i < acl->acl_acecount; i++) {
35802d09e03SGordon Ross 		ERRCHK(md_get_ace(mdp, acep));
3597568150aSgwr 		acep++;
3607568150aSgwr 	}
3619c9af259SGordon Ross 	/*
3629c9af259SGordon Ross 	 * There may be more data here, but
3639c9af259SGordon Ross 	 * the caller takes care of that.
3649c9af259SGordon Ross 	 */
3657568150aSgwr 
3667568150aSgwr 	/* Success! */
3677568150aSgwr 	*aclp = acl;
3687568150aSgwr 	return (0);
3697568150aSgwr 
3707568150aSgwr errout:
3717568150aSgwr 	ifree_acl(acl);
3727568150aSgwr 	return (error);
3737568150aSgwr }
3747568150aSgwr 
3757568150aSgwr static int
mb_put_acl(mbchain_t * mbp,i_ntacl_t * acl)37602d09e03SGordon Ross mb_put_acl(mbchain_t *mbp, i_ntacl_t *acl)
3777568150aSgwr {
3787568150aSgwr 	i_ntace_t **acep;
3799c9af259SGordon Ross 	uint16_t acl_len, *acl_len_p;
3807568150aSgwr 	int i, cnt0, error;
3817568150aSgwr 
3827568150aSgwr 	cnt0 = mbp->mb_count;
3837568150aSgwr 
3847568150aSgwr 	ERRCHK(mb_put_uint8(mbp, acl->acl_revision));
3857568150aSgwr 	ERRCHK(mb_put_uint8(mbp, 0)); /* pad1 */
38602d09e03SGordon Ross 	acl_len_p = mb_reserve(mbp, sizeof (*acl_len_p));
38702d09e03SGordon Ross 	if (acl_len_p == NULL) {
38802d09e03SGordon Ross 		error = ENOMEM;
38902d09e03SGordon Ross 		goto errout;
39002d09e03SGordon Ross 	}
3917568150aSgwr 	ERRCHK(mb_put_uint16le(mbp, acl->acl_acecount));
3927568150aSgwr 	ERRCHK(mb_put_uint16le(mbp, 0)); /* pad2 */
3937568150aSgwr 
3947568150aSgwr 	acep = &acl->acl_acevec[0];
3957568150aSgwr 	for (i = 0; i < acl->acl_acecount; i++) {
3967568150aSgwr 		ERRCHK(mb_put_ace(mbp, *acep));
3977568150aSgwr 		acep++;
3987568150aSgwr 	}
3997568150aSgwr 
4007568150aSgwr 	/* Fill in acl_len_p */
4017568150aSgwr 	acl_len = mbp->mb_count - cnt0;
4029c9af259SGordon Ross 	*acl_len_p = htoles(acl_len);
4037568150aSgwr 
4047568150aSgwr 	/* Success! */
4057568150aSgwr 	return (0);
4067568150aSgwr 
4077568150aSgwr errout:
4087568150aSgwr 	return (error);
4097568150aSgwr }
4107568150aSgwr 
4117568150aSgwr 
4127568150aSgwr /*
4137568150aSgwr  * Security Descriptor
4147568150aSgwr  */
4157568150aSgwr void
smbfs_acl_free_sd(i_ntsd_t * sd)4167568150aSgwr smbfs_acl_free_sd(i_ntsd_t *sd)
4177568150aSgwr {
4187568150aSgwr 
4197568150aSgwr 	if (sd == NULL)
4207568150aSgwr 		return;
4217568150aSgwr 
4227568150aSgwr 	ifree_sid(sd->sd_owner);
4237568150aSgwr 	ifree_sid(sd->sd_group);
4247568150aSgwr 	ifree_acl(sd->sd_sacl);
4257568150aSgwr 	ifree_acl(sd->sd_dacl);
4267568150aSgwr 
4277568150aSgwr 	FREESZ(sd, sizeof (*sd));
4287568150aSgwr }
4297568150aSgwr 
4307568150aSgwr /*
4317568150aSgwr  * Import a raw SD (mb chain) into "internal" form.
4327568150aSgwr  * (like "absolute" form per. NT docs)
4337568150aSgwr  * Returns allocated data in sdp
4347568150aSgwr  *
43502d09e03SGordon Ross  * Note: does NOT consume all the mdp data, so the
4367568150aSgwr  * caller has to take care of that if necessary.
4377568150aSgwr  */
4387568150aSgwr int
md_get_ntsd(mdchain_t * mdp,i_ntsd_t ** sdp)43902d09e03SGordon Ross md_get_ntsd(mdchain_t *mdp, i_ntsd_t **sdp)
4407568150aSgwr {
4417568150aSgwr 	i_ntsd_t *sd = NULL;
44202d09e03SGordon Ross 	mdchain_t top_md, tmp_md;
4437568150aSgwr 	uint32_t owneroff, groupoff, sacloff, dacloff;
4447568150aSgwr 	int error;
4457568150aSgwr 
4467568150aSgwr 	if ((sd = MALLOC(sizeof (*sd))) == NULL)
4477568150aSgwr 		return (ENOMEM);
4487568150aSgwr 	bzero(sd, sizeof (*sd));
4497568150aSgwr 
4507568150aSgwr 	/*
4517568150aSgwr 	 * Offsets below are relative to this point,
45202d09e03SGordon Ross 	 * so save the mdp state for use below.
4537568150aSgwr 	 */
45402d09e03SGordon Ross 	top_md = *mdp;
4557568150aSgwr 
45602d09e03SGordon Ross 	ERRCHK(md_get_uint8(mdp, &sd->sd_revision));
45702d09e03SGordon Ross 	ERRCHK(md_get_uint8(mdp, &sd->sd_rmctl));
45802d09e03SGordon Ross 	ERRCHK(md_get_uint16le(mdp, &sd->sd_flags));
45902d09e03SGordon Ross 	ERRCHK(md_get_uint32le(mdp, &owneroff));
46002d09e03SGordon Ross 	ERRCHK(md_get_uint32le(mdp, &groupoff));
46102d09e03SGordon Ross 	ERRCHK(md_get_uint32le(mdp, &sacloff));
46202d09e03SGordon Ross 	ERRCHK(md_get_uint32le(mdp, &dacloff));
4637568150aSgwr 
464bd7c6f51SGordon Ross 	/*
465bd7c6f51SGordon Ross 	 * The SD is "self-relative" on the wire,
466bd7c6f51SGordon Ross 	 * but not after this decodes it.
467bd7c6f51SGordon Ross 	 */
468bd7c6f51SGordon Ross 	sd->sd_flags &= ~SD_SELF_RELATIVE;
469bd7c6f51SGordon Ross 
4707568150aSgwr 	/*
4717568150aSgwr 	 * For each section make a temporary copy of the
47202d09e03SGordon Ross 	 * top_md state, advance to the given offset, and
47302d09e03SGordon Ross 	 * pass that to the lower md_get_xxx functions.
4747568150aSgwr 	 * These could be marshalled in any order, but
4757568150aSgwr 	 * are normally found in the order shown here.
4767568150aSgwr 	 */
4777568150aSgwr 	if (sacloff) {
47802d09e03SGordon Ross 		tmp_md = top_md;
47902d09e03SGordon Ross 		md_get_mem(&tmp_md, NULL, sacloff, MB_MSYSTEM);
48002d09e03SGordon Ross 		ERRCHK(md_get_acl(&tmp_md, &sd->sd_sacl));
4817568150aSgwr 	}
4827568150aSgwr 	if (dacloff) {
48302d09e03SGordon Ross 		tmp_md = top_md;
48402d09e03SGordon Ross 		md_get_mem(&tmp_md, NULL, dacloff, MB_MSYSTEM);
48502d09e03SGordon Ross 		ERRCHK(md_get_acl(&tmp_md, &sd->sd_dacl));
4867568150aSgwr 	}
4877568150aSgwr 	if (owneroff) {
48802d09e03SGordon Ross 		tmp_md = top_md;
48902d09e03SGordon Ross 		md_get_mem(&tmp_md, NULL, owneroff, MB_MSYSTEM);
49002d09e03SGordon Ross 		ERRCHK(md_get_sid(&tmp_md, &sd->sd_owner));
4917568150aSgwr 	}
4927568150aSgwr 	if (groupoff) {
49302d09e03SGordon Ross 		tmp_md = top_md;
49402d09e03SGordon Ross 		md_get_mem(&tmp_md, NULL, groupoff, MB_MSYSTEM);
49502d09e03SGordon Ross 		ERRCHK(md_get_sid(&tmp_md, &sd->sd_group));
4967568150aSgwr 	}
4977568150aSgwr 
4987568150aSgwr 	/* Success! */
4997568150aSgwr 	*sdp = sd;
5007568150aSgwr 	return (0);
5017568150aSgwr 
5027568150aSgwr errout:
5037568150aSgwr 	smbfs_acl_free_sd(sd);
5047568150aSgwr 	return (error);
5057568150aSgwr }
5067568150aSgwr 
5077568150aSgwr /*
5087568150aSgwr  * Export an "internal" SD into an raw SD (mb chain).
5097568150aSgwr  * (a.k.a "self-relative" form per. NT docs)
5107568150aSgwr  * Returns allocated mbchain in mbp.
5117568150aSgwr  */
5127568150aSgwr int
mb_put_ntsd(mbchain_t * mbp,i_ntsd_t * sd)51302d09e03SGordon Ross mb_put_ntsd(mbchain_t *mbp, i_ntsd_t *sd)
5147568150aSgwr {
5159c9af259SGordon Ross 	uint32_t *owneroffp, *groupoffp, *sacloffp, *dacloffp;
5167568150aSgwr 	uint32_t owneroff, groupoff, sacloff, dacloff;
517bd7c6f51SGordon Ross 	uint16_t flags;
5187568150aSgwr 	int cnt0, error;
5197568150aSgwr 
5207568150aSgwr 	cnt0 = mbp->mb_count;
5217568150aSgwr 	owneroff = groupoff = sacloff = dacloff = 0;
5227568150aSgwr 
523bd7c6f51SGordon Ross 	/* The SD is "self-relative" on the wire. */
524bd7c6f51SGordon Ross 	flags = sd->sd_flags | SD_SELF_RELATIVE;
525bd7c6f51SGordon Ross 
5267568150aSgwr 	ERRCHK(mb_put_uint8(mbp, sd->sd_revision));
52702d09e03SGordon Ross 	ERRCHK(mb_put_uint8(mbp, sd->sd_rmctl));
528bd7c6f51SGordon Ross 	ERRCHK(mb_put_uint16le(mbp, flags));
52902d09e03SGordon Ross 
53002d09e03SGordon Ross 	owneroffp = mb_reserve(mbp, sizeof (*owneroffp));
53102d09e03SGordon Ross 	groupoffp = mb_reserve(mbp, sizeof (*groupoffp));
53202d09e03SGordon Ross 	sacloffp  = mb_reserve(mbp, sizeof (*sacloffp));
53302d09e03SGordon Ross 	dacloffp  = mb_reserve(mbp, sizeof (*dacloffp));
53402d09e03SGordon Ross 	if (owneroffp == NULL || groupoffp == NULL ||
53502d09e03SGordon Ross 	    sacloffp == NULL || dacloffp == NULL) {
53602d09e03SGordon Ross 		error = ENOMEM;
53702d09e03SGordon Ross 		goto errout;
53802d09e03SGordon Ross 	}
5397568150aSgwr 
5407568150aSgwr 	/*
5417568150aSgwr 	 * These could be marshalled in any order, but
5427568150aSgwr 	 * are normally found in the order shown here.
5437568150aSgwr 	 */
5447568150aSgwr 	if (sd->sd_sacl) {
5457568150aSgwr 		sacloff = mbp->mb_count - cnt0;
5467568150aSgwr 		ERRCHK(mb_put_acl(mbp, sd->sd_sacl));
5477568150aSgwr 	}
5487568150aSgwr 	if (sd->sd_dacl) {
5497568150aSgwr 		dacloff = mbp->mb_count - cnt0;
5507568150aSgwr 		ERRCHK(mb_put_acl(mbp, sd->sd_dacl));
5517568150aSgwr 	}
5527568150aSgwr 	if (sd->sd_owner) {
5537568150aSgwr 		owneroff = mbp->mb_count - cnt0;
5547568150aSgwr 		ERRCHK(mb_put_sid(mbp, sd->sd_owner));
5557568150aSgwr 	}
5567568150aSgwr 	if (sd->sd_group) {
5577568150aSgwr 		groupoff = mbp->mb_count - cnt0;
5587568150aSgwr 		ERRCHK(mb_put_sid(mbp, sd->sd_group));
5597568150aSgwr 	}
5607568150aSgwr 
5617568150aSgwr 	/* Fill in the offsets */
5629c9af259SGordon Ross 	*owneroffp = htolel(owneroff);
5639c9af259SGordon Ross 	*groupoffp = htolel(groupoff);
5649c9af259SGordon Ross 	*sacloffp  = htolel(sacloff);
5659c9af259SGordon Ross 	*dacloffp  = htolel(dacloff);
5667568150aSgwr 
5677568150aSgwr 	/* Success! */
5687568150aSgwr 	return (0);
5697568150aSgwr 
5707568150aSgwr errout:
5717568150aSgwr 	return (error);
5727568150aSgwr }
5737568150aSgwr 
574bd7c6f51SGordon Ross /*
575bd7c6f51SGordon Ross  * ================================================================
576bd7c6f51SGordon Ross  * Support for ACL fetch, including conversions
577bd7c6f51SGordon Ross  * from Windows ACLs to NFSv4-style ACLs.
578bd7c6f51SGordon Ross  * ================================================================
579bd7c6f51SGordon Ross  */
580bd7c6f51SGordon Ross 
581bd7c6f51SGordon Ross #define	GENERIC_RIGHTS_MASK \
582bd7c6f51SGordon Ross 	(GENERIC_RIGHT_READ_ACCESS | GENERIC_RIGHT_WRITE_ACCESS |\
583bd7c6f51SGordon Ross 	GENERIC_RIGHT_EXECUTE_ACCESS | GENERIC_RIGHT_ALL_ACCESS)
5847568150aSgwr 
5857568150aSgwr /*
586bd7c6f51SGordon Ross  * Table for converting NT GENERIC_RIGHT_... to specific rights
587bd7c6f51SGordon Ross  * appropriate for objects of type file.
5887568150aSgwr  */
589bd7c6f51SGordon Ross struct gen2fsr {
590bd7c6f51SGordon Ross 	uint32_t	gf_generic;
591bd7c6f51SGordon Ross 	uint32_t	gf_specific;
592bd7c6f51SGordon Ross };
593bd7c6f51SGordon Ross static const struct gen2fsr
594bd7c6f51SGordon Ross smbfs_gen2fsr[] = {
595bd7c6f51SGordon Ross 	{
596bd7c6f51SGordon Ross 		GENERIC_RIGHT_READ_ACCESS,
597bd7c6f51SGordon Ross 		STD_RIGHT_SYNCHRONIZE_ACCESS |
598bd7c6f51SGordon Ross 		STD_RIGHT_READ_CONTROL_ACCESS |
599bd7c6f51SGordon Ross 		SA_RIGHT_FILE_READ_ATTRIBUTES |
600bd7c6f51SGordon Ross 		SA_RIGHT_FILE_READ_EA |
601bd7c6f51SGordon Ross 		SA_RIGHT_FILE_READ_DATA },
602bd7c6f51SGordon Ross 	{
603bd7c6f51SGordon Ross 		GENERIC_RIGHT_WRITE_ACCESS,
604bd7c6f51SGordon Ross 		STD_RIGHT_SYNCHRONIZE_ACCESS |
605bd7c6f51SGordon Ross 		STD_RIGHT_READ_CONTROL_ACCESS |
606bd7c6f51SGordon Ross 		SA_RIGHT_FILE_WRITE_ATTRIBUTES |
607bd7c6f51SGordon Ross 		SA_RIGHT_FILE_WRITE_EA |
608bd7c6f51SGordon Ross 		SA_RIGHT_FILE_APPEND_DATA |
609bd7c6f51SGordon Ross 		SA_RIGHT_FILE_WRITE_DATA },
610bd7c6f51SGordon Ross 	{
611bd7c6f51SGordon Ross 		GENERIC_RIGHT_EXECUTE_ACCESS,
612bd7c6f51SGordon Ross 		STD_RIGHT_SYNCHRONIZE_ACCESS |
613bd7c6f51SGordon Ross 		STD_RIGHT_READ_CONTROL_ACCESS |
614bd7c6f51SGordon Ross 		SA_RIGHT_FILE_READ_ATTRIBUTES |
615bd7c6f51SGordon Ross 		SA_RIGHT_FILE_EXECUTE },
616bd7c6f51SGordon Ross 	{
617bd7c6f51SGordon Ross 		GENERIC_RIGHT_ALL_ACCESS,
618bd7c6f51SGordon Ross 		STD_RIGHT_SYNCHRONIZE_ACCESS |
619bd7c6f51SGordon Ross 		STD_RIGHT_WRITE_OWNER_ACCESS |
620bd7c6f51SGordon Ross 		STD_RIGHT_WRITE_DAC_ACCESS |
621bd7c6f51SGordon Ross 		STD_RIGHT_READ_CONTROL_ACCESS |
622bd7c6f51SGordon Ross 		STD_RIGHT_DELETE_ACCESS |
623bd7c6f51SGordon Ross 		SA_RIGHT_FILE_ALL_ACCESS },
624bd7c6f51SGordon Ross 	{ 0, 0 }
625bd7c6f51SGordon Ross };
6267568150aSgwr 
627bd7c6f51SGordon Ross /*
628bd7c6f51SGordon Ross  * Table for translating ZFS ACE flags to NT ACE flags.
629bd7c6f51SGordon Ross  * The low four bits are the same, but not others.
630bd7c6f51SGordon Ross  */
631bd7c6f51SGordon Ross struct zaf2naf {
632bd7c6f51SGordon Ross 	uint16_t	za_flag;
633bd7c6f51SGordon Ross 	uint8_t		na_flag;
634bd7c6f51SGordon Ross };
635bd7c6f51SGordon Ross static const struct zaf2naf
636bd7c6f51SGordon Ross smbfs_zaf2naf[] = {
637bd7c6f51SGordon Ross 	{ ACE_FILE_INHERIT_ACE,		OBJECT_INHERIT_ACE_FLAG },
638bd7c6f51SGordon Ross 	{ ACE_DIRECTORY_INHERIT_ACE,	CONTAINER_INHERIT_ACE_FLAG },
639bd7c6f51SGordon Ross 	{ ACE_NO_PROPAGATE_INHERIT_ACE,	NO_PROPAGATE_INHERIT_ACE_FLAG },
640bd7c6f51SGordon Ross 	{ ACE_INHERIT_ONLY_ACE,		INHERIT_ONLY_ACE_FLAG },
641bd7c6f51SGordon Ross 	{ ACE_INHERITED_ACE,		INHERITED_ACE_FLAG },
642bd7c6f51SGordon Ross 	{ ACE_SUCCESSFUL_ACCESS_ACE_FLAG, SUCCESSFUL_ACCESS_ACE_FLAG },
643bd7c6f51SGordon Ross 	{ ACE_FAILED_ACCESS_ACE_FLAG,	FAILED_ACCESS_ACE_FLAG },
644bd7c6f51SGordon Ross 	{ 0, 0 }
645bd7c6f51SGordon Ross };
6467568150aSgwr 
6477568150aSgwr /*
6487568150aSgwr  * Convert an NT SID to a string. Optionally return the
6497568150aSgwr  * last sub-authority (or "relative ID" -- RID) in *ridp
6507568150aSgwr  * and truncate the output string after the domain part.
6517568150aSgwr  * If ridp==NULL, the output string is the whole SID,
6527568150aSgwr  * including both the domain and RID.
6537568150aSgwr  *
6547568150aSgwr  * Return length written, or -1 on error.
6557568150aSgwr  */
6567568150aSgwr int
smbfs_sid2str(i_ntsid_t * sid,char * obuf,size_t osz,uint32_t * ridp)6577568150aSgwr smbfs_sid2str(i_ntsid_t *sid,
6587568150aSgwr 	char *obuf, size_t osz, uint32_t *ridp)
6597568150aSgwr {
6607568150aSgwr 	char *s = obuf;
6617568150aSgwr 	uint64_t auth = 0;
6627568150aSgwr 	uint_t i, n;
6637568150aSgwr 	uint32_t subs, *ip;
6647568150aSgwr 
6657568150aSgwr 	n = snprintf(s, osz, "S-%u", sid->sid_revision);
6667568150aSgwr 	if (n > osz)
6677568150aSgwr 		return (-1);
6687568150aSgwr 	s += n; osz -= n;
6697568150aSgwr 
6707568150aSgwr 	for (i = 0; i < 6; i++)
6717568150aSgwr 		auth = (auth << 8) | sid->sid_authority[i];
67202d09e03SGordon Ross 	n = snprintf(s, osz, "-%llu", (u_longlong_t)auth);
6737568150aSgwr 	if (n > osz)
6747568150aSgwr 		return (-1);
6757568150aSgwr 	s += n; osz -= n;
6767568150aSgwr 
6777568150aSgwr 	subs = sid->sid_subauthcount;
6787568150aSgwr 	if (subs < 1 || subs > 15)
6797568150aSgwr 		return (-1);
6807568150aSgwr 	if (ridp)
6817568150aSgwr 		subs--;
6827568150aSgwr 
6837568150aSgwr 	ip = &sid->sid_subauthvec[0];
6847568150aSgwr 	for (; subs; subs--, ip++) {
6857568150aSgwr 		n = snprintf(s, osz, "-%u", *ip);
6867568150aSgwr 		if (n > osz)
6877568150aSgwr 			return (-1);
6887568150aSgwr 		s += n; osz -= n;
6897568150aSgwr 	}
6907568150aSgwr 	if (ridp)
6917568150aSgwr 		*ridp = *ip;
6927568150aSgwr 
69302d09e03SGordon Ross 	/* LINTED E_PTRDIFF_OVERFLOW */
6947568150aSgwr 	return (s - obuf);
6957568150aSgwr }
6967568150aSgwr 
6977568150aSgwr /*
6987568150aSgwr  * Our interface to the idmap service.
69902d09e03SGordon Ross  *
70002d09e03SGordon Ross  * The idmap API is _almost_ the same between
70102d09e03SGordon Ross  * kernel and user-level.  But not quite...
70202d09e03SGordon Ross  * Hope this improves readability below.
7037568150aSgwr  */
7047568150aSgwr #ifdef	_KERNEL
70502d09e03SGordon Ross 
706bd7c6f51SGordon Ross #define	I_getuidbysid(GH, SPP, RID, UIDP, SP) \
707bd7c6f51SGordon Ross 	kidmap_batch_getuidbysid(GH, SPP, RID, UIDP, SP)
708bd7c6f51SGordon Ross 
709bd7c6f51SGordon Ross #define	I_getgidbysid(GH, SPP, RID, GIDP, SP) \
710bd7c6f51SGordon Ross 	kidmap_batch_getgidbysid(GH, SPP, RID, GIDP, SP)
711bd7c6f51SGordon Ross 
712bd7c6f51SGordon Ross #define	I_getpidbysid(GH, SPP, RID, PIDP, ISUP, SP) \
71302d09e03SGordon Ross 	kidmap_batch_getpidbysid(GH, SPP, RID, PIDP, ISUP, SP)
714bd7c6f51SGordon Ross 
715bd7c6f51SGordon Ross #define	I_getmappings kidmap_get_mappings
71602d09e03SGordon Ross 
7177568150aSgwr #else /* _KERNEL */
71802d09e03SGordon Ross 
719bd7c6f51SGordon Ross #define	I_getuidbysid(GH, SPP, RID, UIDP, SP) \
720bd7c6f51SGordon Ross 	idmap_get_uidbysid(GH, SPP, RID, 0, UIDP, SP)
721bd7c6f51SGordon Ross 
722bd7c6f51SGordon Ross #define	I_getgidbysid(GH, SPP, RID, GIDP, SP) \
723bd7c6f51SGordon Ross 	idmap_get_gidbysid(GH, SPP, RID, 0, GIDP, SP)
724bd7c6f51SGordon Ross 
725bd7c6f51SGordon Ross #define	I_getpidbysid(GH, SPP, RID, PIDP, ISUP, SP) \
72602d09e03SGordon Ross 	idmap_get_pidbysid(GH, SPP, RID, 0, PIDP, ISUP, SP)
727bd7c6f51SGordon Ross 
728bd7c6f51SGordon Ross #define	I_getmappings idmap_get_mappings
72902d09e03SGordon Ross 
7307568150aSgwr #endif /* _KERNEL */
7317568150aSgwr 
7327568150aSgwr 
7337568150aSgwr /*
734bd7c6f51SGordon Ross  * The idmap request types, chosen so they also
735bd7c6f51SGordon Ross  * match the values returned in mi_isuser.
736bd7c6f51SGordon Ross  */
737bd7c6f51SGordon Ross #define	IDM_TYPE_ANY	-1
738bd7c6f51SGordon Ross #define	IDM_TYPE_GROUP	0
739bd7c6f51SGordon Ross #define	IDM_TYPE_USER	1
740bd7c6f51SGordon Ross 
741bd7c6f51SGordon Ross /*
742bd7c6f51SGordon Ross  * A sentinel value for mi_isuser (below) to indicate
7437568150aSgwr  * that the SID is the well-known "Everyone" (S-1-1-0).
7447568150aSgwr  * The idmap library only uses -1, 0, 1, so this value
7457568150aSgwr  * is arbitrary but must not overlap w/ idmap values.
7467568150aSgwr  * XXX: Could use a way for idmap to tell us when
7477568150aSgwr  * it recognizes this well-known SID.
7487568150aSgwr  */
749bd7c6f51SGordon Ross #define	IDM_EVERYONE	11
750bd7c6f51SGordon Ross 
751bd7c6f51SGordon Ross struct mapinfo2uid {
752bd7c6f51SGordon Ross 	uid_t	mi_uid; /* or gid, or pid */
753bd7c6f51SGordon Ross 	int	mi_isuser; /* IDM_TYPE */
754bd7c6f51SGordon Ross 	idmap_stat mi_status;
755bd7c6f51SGordon Ross };
7567568150aSgwr 
7577568150aSgwr /*
7587568150aSgwr  * Build an idmap request.  Cleanup is
7597568150aSgwr  * handled by the caller (error or not)
7607568150aSgwr  */
7617568150aSgwr static int
mkrq_idmap_sid2ux(idmap_get_handle_t * idmap_gh,struct mapinfo2uid * mip,i_ntsid_t * sid,int req_type)7627568150aSgwr mkrq_idmap_sid2ux(
7637568150aSgwr 	idmap_get_handle_t *idmap_gh,
764bd7c6f51SGordon Ross 	struct mapinfo2uid *mip,
7657568150aSgwr 	i_ntsid_t *sid,
766bd7c6f51SGordon Ross 	int req_type)
7677568150aSgwr {
768bd7c6f51SGordon Ross 	char strbuf[256];
769bd7c6f51SGordon Ross 	char *sid_prefix;
7707568150aSgwr 	uint32_t	rid;
7717568150aSgwr 	idmap_stat	idms;
7727568150aSgwr 
773bd7c6f51SGordon Ross 	if (smbfs_sid2str(sid, strbuf, sizeof (strbuf), &rid) < 0)
7747568150aSgwr 		return (EINVAL);
775bd7c6f51SGordon Ross 	sid_prefix = strbuf;
7767568150aSgwr 
7777568150aSgwr 	/*
7787568150aSgwr 	 * Give the "Everyone" group special treatment.
7797568150aSgwr 	 */
7807568150aSgwr 	if (strcmp(sid_prefix, "S-1-1") == 0 && rid == 0) {
7817568150aSgwr 		/* This is "Everyone" */
7827568150aSgwr 		mip->mi_uid = (uid_t)-1;
783bd7c6f51SGordon Ross 		mip->mi_isuser = IDM_EVERYONE;
7847568150aSgwr 		mip->mi_status = 0;
7857568150aSgwr 		return (0);
7867568150aSgwr 	}
7877568150aSgwr 
788bd7c6f51SGordon Ross 	switch (req_type) {
789bd7c6f51SGordon Ross 
790bd7c6f51SGordon Ross 	case IDM_TYPE_USER:
791bd7c6f51SGordon Ross 		mip->mi_isuser = req_type;
792bd7c6f51SGordon Ross 		idms = I_getuidbysid(idmap_gh, sid_prefix, rid,
793bd7c6f51SGordon Ross 		    &mip->mi_uid, &mip->mi_status);
794bd7c6f51SGordon Ross 		break;
795bd7c6f51SGordon Ross 
796bd7c6f51SGordon Ross 	case IDM_TYPE_GROUP:
797bd7c6f51SGordon Ross 		mip->mi_isuser = req_type;
798bd7c6f51SGordon Ross 		idms = I_getgidbysid(idmap_gh, sid_prefix, rid,
799bd7c6f51SGordon Ross 		    &mip->mi_uid, &mip->mi_status);
800bd7c6f51SGordon Ross 		break;
801bd7c6f51SGordon Ross 
802bd7c6f51SGordon Ross 	case IDM_TYPE_ANY:
803bd7c6f51SGordon Ross 		idms = I_getpidbysid(idmap_gh, sid_prefix, rid,
804bd7c6f51SGordon Ross 		    &mip->mi_uid, &mip->mi_isuser, &mip->mi_status);
805bd7c6f51SGordon Ross 		break;
806bd7c6f51SGordon Ross 
807bd7c6f51SGordon Ross 	default:
808bd7c6f51SGordon Ross 		idms = IDMAP_ERR_OTHER;
809bd7c6f51SGordon Ross 		break;
810bd7c6f51SGordon Ross 	}
811bd7c6f51SGordon Ross 
8127568150aSgwr 	if (idms != IDMAP_SUCCESS)
8137568150aSgwr 		return (EINVAL);
8147568150aSgwr 
8157568150aSgwr 	return (0);
8167568150aSgwr }
8177568150aSgwr 
818bd7c6f51SGordon Ross /*
819bd7c6f51SGordon Ross  * Convert an NT ACE to a ZFS ACE.
820bd7c6f51SGordon Ross  * ACE type was already validated.
821bd7c6f51SGordon Ross  */
8227568150aSgwr static void
ntace2zace(ace_t * zacep,i_ntace_t * ntace,struct mapinfo2uid * mip)823bd7c6f51SGordon Ross ntace2zace(ace_t *zacep, i_ntace_t *ntace, struct mapinfo2uid *mip)
8247568150aSgwr {
825bd7c6f51SGordon Ross 	const struct zaf2naf *znaf;
826bd7c6f51SGordon Ross 	uid_t zwho;
8277568150aSgwr 	uint32_t zamask;
828bd7c6f51SGordon Ross 	uint16_t zflags;
8297568150aSgwr 
8307568150aSgwr 	/*
831bd7c6f51SGordon Ross 	 * Set the "ID type" flags in the ZFS ace flags.
8327568150aSgwr 	 */
8337568150aSgwr 	zflags = 0;
8347568150aSgwr 	switch (mip->mi_isuser) {
835bd7c6f51SGordon Ross 	case IDM_EVERYONE:
836bd7c6f51SGordon Ross 		zflags = ACE_EVERYONE;
837bd7c6f51SGordon Ross 		zwho = (uid_t)-1;
8387568150aSgwr 		break;
839bd7c6f51SGordon Ross 
840bd7c6f51SGordon Ross 	case IDM_TYPE_GROUP: /* it's a GID */
841bd7c6f51SGordon Ross 		zflags = ACE_IDENTIFIER_GROUP;
842bd7c6f51SGordon Ross 		zwho = mip->mi_uid;
8437568150aSgwr 		break;
844bd7c6f51SGordon Ross 
8457568150aSgwr 	default:
846bd7c6f51SGordon Ross 	case IDM_TYPE_USER: /* it's a UID */
847bd7c6f51SGordon Ross 		zflags = 0;
848bd7c6f51SGordon Ross 		zwho = mip->mi_uid;
8497568150aSgwr 		break;
8507568150aSgwr 	}
8517568150aSgwr 
8527568150aSgwr 	/*
853bd7c6f51SGordon Ross 	 * Translate NT ACE flags to ZFS ACE flags.
8547568150aSgwr 	 */
855bd7c6f51SGordon Ross 	for (znaf = smbfs_zaf2naf; znaf->za_flag; znaf++)
856bd7c6f51SGordon Ross 		if (ntace->ace_hdr.ace_flags & znaf->na_flag)
857bd7c6f51SGordon Ross 			zflags |= znaf->za_flag;
8587568150aSgwr 
8597568150aSgwr 	/*
860bd7c6f51SGordon Ross 	 * The "normal" access mask bits are the same, but
861bd7c6f51SGordon Ross 	 * if the ACE has any GENERIC_RIGHT_... convert those
862bd7c6f51SGordon Ross 	 * to specific rights.  GENERIC bits are rarely seen,
863bd7c6f51SGordon Ross 	 * but reportedly can happen with inherit-only ACEs.
8647568150aSgwr 	 */
865bd7c6f51SGordon Ross 	zamask = ntace->ace_v2.ace_rights & ACE_ALL_PERMS;
866bd7c6f51SGordon Ross 	if (ntace->ace_v2.ace_rights & GENERIC_RIGHTS_MASK) {
867bd7c6f51SGordon Ross 		const struct gen2fsr *gf;
868bd7c6f51SGordon Ross 		for (gf = smbfs_gen2fsr; gf->gf_generic; gf++)
869bd7c6f51SGordon Ross 			if (ntace->ace_v2.ace_rights & gf->gf_generic)
870bd7c6f51SGordon Ross 				zamask |= gf->gf_specific;
8717568150aSgwr 	}
8727568150aSgwr 
8737568150aSgwr 	/*
8747568150aSgwr 	 * Fill in the ZFS-style ACE
8757568150aSgwr 	 */
876bd7c6f51SGordon Ross 	zacep->a_who = zwho;
8777568150aSgwr 	zacep->a_access_mask = zamask;
8787568150aSgwr 	zacep->a_flags = zflags;
879bd7c6f51SGordon Ross 	zacep->a_type = ntace->ace_hdr.ace_type;
8807568150aSgwr }
8817568150aSgwr 
8827568150aSgwr /*
8837568150aSgwr  * Convert an internal SD to a ZFS-style ACL.
8847568150aSgwr  * Note optional args: vsa/acl, uidp, gidp.
885bd7c6f51SGordon Ross  *
886bd7c6f51SGordon Ross  * This makes two passes over the SD, the first building a
887bd7c6f51SGordon Ross  * "batch" request for idmap with results in mapinfo, the
888bd7c6f51SGordon Ross  * second building a ZFS-style ACL using the idmap results.
8897568150aSgwr  */
8907568150aSgwr int
smbfs_acl_sd2zfs(i_ntsd_t * sd,vsecattr_t * acl_info,uid_t * uidp,gid_t * gidp)8917568150aSgwr smbfs_acl_sd2zfs(
8927568150aSgwr 	i_ntsd_t *sd,
893*8329232eSGordon Ross #if defined(_KERNEL) || defined(_FAKE_KERNEL)
8947568150aSgwr 	vsecattr_t *acl_info,
8957568150aSgwr #else /* _KERNEL */
8967568150aSgwr 	acl_t *acl_info,
8977568150aSgwr #endif /* _KERNEL */
8987568150aSgwr 	uid_t *uidp, gid_t *gidp)
8997568150aSgwr {
900bd7c6f51SGordon Ross 	struct mapinfo2uid *mip, *mapinfo = NULL;
9017568150aSgwr 	int error, i, mapcnt, zacecnt, zacl_size;
902bd7c6f51SGordon Ross 	ace_t *zacep0, *zacep;
903bd7c6f51SGordon Ross 	uid_t own_uid = (uid_t)-1;
904bd7c6f51SGordon Ross 	gid_t own_gid = (gid_t)-1;
9057568150aSgwr 	i_ntacl_t *ntacl;
9067568150aSgwr 	i_ntace_t **ntacep;
9077568150aSgwr 	idmap_get_handle_t *idmap_gh = NULL;
9087568150aSgwr 	idmap_stat	idms;
9097568150aSgwr 
9107568150aSgwr 	/*
9117568150aSgwr 	 * sanity checks
9127568150aSgwr 	 */
9137568150aSgwr 	if (acl_info) {
914*8329232eSGordon Ross #if !defined(_KERNEL) && !defined(_FAKE_KERNEL)
9157568150aSgwr 		if (acl_info->acl_type != ACE_T ||
9167568150aSgwr 		    acl_info->acl_aclp != NULL ||
9177568150aSgwr 		    acl_info->acl_entry_size != sizeof (ace_t))
9187568150aSgwr 			return (EINVAL);
919*8329232eSGordon Ross #endif /* !_KERNEL */
920bd7c6f51SGordon Ross 		if ((sd->sd_flags & SD_DACL_PRESENT) == 0)
921bd7c6f51SGordon Ross 			return (EINVAL);
922bd7c6f51SGordon Ross 	}
9237568150aSgwr 
9247568150aSgwr 	/*
925bd7c6f51SGordon Ross 	 * How many SID mappings will we need?
9267568150aSgwr 	 */
9277568150aSgwr 	mapcnt = 0;
9287568150aSgwr 	if (sd->sd_owner)
9297568150aSgwr 		mapcnt++;
9307568150aSgwr 	if (sd->sd_group)
9317568150aSgwr 		mapcnt++;
932bd7c6f51SGordon Ross 	if ((sd->sd_flags & SD_SACL_PRESENT) &&
933bd7c6f51SGordon Ross 	    (sd->sd_sacl != NULL))
9347568150aSgwr 		mapcnt += sd->sd_sacl->acl_acecount;
935bd7c6f51SGordon Ross 	if ((sd->sd_flags & SD_DACL_PRESENT) &&
936bd7c6f51SGordon Ross 	    (sd->sd_dacl != NULL))
9377568150aSgwr 		mapcnt += sd->sd_dacl->acl_acecount;
938bd7c6f51SGordon Ross 	if (mapcnt == 0) {
939bd7c6f51SGordon Ross 		/*
940bd7c6f51SGordon Ross 		 * We have a NULL DACL, SACL, and don't
941bd7c6f51SGordon Ross 		 * have an owner or group, so there's no
942bd7c6f51SGordon Ross 		 * idmap work to do.  This is very rare,
943bd7c6f51SGordon Ross 		 * so rather than complicate things below,
944bd7c6f51SGordon Ross 		 * pretend we need one mapping slot.
945bd7c6f51SGordon Ross 		 */
946bd7c6f51SGordon Ross 		mapcnt = 1;
947bd7c6f51SGordon Ross 	}
9487568150aSgwr 
9497568150aSgwr 	mapinfo = MALLOC(mapcnt * sizeof (*mapinfo));
9507568150aSgwr 	if (mapinfo == NULL) {
9517568150aSgwr 		error = ENOMEM;
9527568150aSgwr 		goto errout;
9537568150aSgwr 	}
9547568150aSgwr 	bzero(mapinfo, mapcnt * sizeof (*mapinfo));
9557568150aSgwr 
9567568150aSgwr 
9577568150aSgwr 	/*
958bd7c6f51SGordon Ross 	 * Get an imap "batch" request handle.
9597568150aSgwr 	 */
9607568150aSgwr #ifdef	_KERNEL
9617568150aSgwr 	idmap_gh = kidmap_get_create(curproc->p_zone);
9627568150aSgwr #else /* _KERNEL */
9631fdeec65Sjoyce mcintosh 	idms = idmap_get_create(&idmap_gh);
9647568150aSgwr 	if (idms != IDMAP_SUCCESS) {
9657568150aSgwr 		error = ENOTACTIVE;
9667568150aSgwr 		goto errout;
9677568150aSgwr 	}
9687568150aSgwr #endif /* _KERNEL */
9697568150aSgwr 
970bd7c6f51SGordon Ross 	/*
971bd7c6f51SGordon Ross 	 * Build our request to the idmap deamon,
972bd7c6f51SGordon Ross 	 * getting Unix IDs for every SID.
973bd7c6f51SGordon Ross 	 */
9747568150aSgwr 	mip = mapinfo;
9757568150aSgwr 	if (sd->sd_owner) {
976bd7c6f51SGordon Ross 		error = mkrq_idmap_sid2ux(idmap_gh, mip,
977bd7c6f51SGordon Ross 		    sd->sd_owner, IDM_TYPE_USER);
9787568150aSgwr 		if (error)
9797568150aSgwr 			goto errout;
9807568150aSgwr 		mip++;
9817568150aSgwr 	}
9827568150aSgwr 	if (sd->sd_group) {
983bd7c6f51SGordon Ross 		error = mkrq_idmap_sid2ux(idmap_gh, mip,
984bd7c6f51SGordon Ross 		    sd->sd_group, IDM_TYPE_GROUP);
9857568150aSgwr 		if (error)
9867568150aSgwr 			goto errout;
9877568150aSgwr 		mip++;
9887568150aSgwr 	}
989bd7c6f51SGordon Ross 	if ((sd->sd_flags & SD_SACL_PRESENT) &&
990bd7c6f51SGordon Ross 	    (sd->sd_sacl != NULL)) {
9917568150aSgwr 		ntacl = sd->sd_sacl;
9927568150aSgwr 		ntacep = &ntacl->acl_acevec[0];
9937568150aSgwr 		for (i = 0; i < ntacl->acl_acecount; i++) {
994bd7c6f51SGordon Ross 			error = mkrq_idmap_sid2ux(idmap_gh, mip,
995bd7c6f51SGordon Ross 			    (*ntacep)->ace_v2.ace_sid, IDM_TYPE_ANY);
9967568150aSgwr 			if (error)
9977568150aSgwr 				goto errout;
9987568150aSgwr 			ntacep++;
9997568150aSgwr 			mip++;
10007568150aSgwr 		}
10017568150aSgwr 	}
1002bd7c6f51SGordon Ross 	if ((sd->sd_flags & SD_DACL_PRESENT) &&
1003bd7c6f51SGordon Ross 	    (sd->sd_dacl != NULL)) {
10047568150aSgwr 		ntacl = sd->sd_dacl;
10057568150aSgwr 		ntacep = &ntacl->acl_acevec[0];
10067568150aSgwr 		for (i = 0; i < ntacl->acl_acecount; i++) {
1007bd7c6f51SGordon Ross 			error = mkrq_idmap_sid2ux(idmap_gh, mip,
1008bd7c6f51SGordon Ross 			    (*ntacep)->ace_v2.ace_sid, IDM_TYPE_ANY);
10097568150aSgwr 			if (error)
10107568150aSgwr 				goto errout;
10117568150aSgwr 			ntacep++;
10127568150aSgwr 			mip++;
10137568150aSgwr 		}
10147568150aSgwr 	}
10157568150aSgwr 
1016bd7c6f51SGordon Ross 	if (mip != mapinfo) {
1017bd7c6f51SGordon Ross 		idms = I_getmappings(idmap_gh);
1018bd7c6f51SGordon Ross 		if (idms != IDMAP_SUCCESS) {
1019bd7c6f51SGordon Ross 			/* creative error choice */
1020bd7c6f51SGordon Ross 			error = EIDRM;
1021bd7c6f51SGordon Ross 			goto errout;
1022bd7c6f51SGordon Ross 		}
10237568150aSgwr 	}
10247568150aSgwr 
10257568150aSgwr 	/*
10267568150aSgwr 	 * With any luck, we now have Unix user/group IDs
10277568150aSgwr 	 * for every Windows SID in the security descriptor.
10287568150aSgwr 	 * The remaining work is just format conversion.
10297568150aSgwr 	 */
10307568150aSgwr 	mip = mapinfo;
10317568150aSgwr 	if (sd->sd_owner) {
1032bd7c6f51SGordon Ross 		own_uid = mip->mi_uid;
10337568150aSgwr 		mip++;
10347568150aSgwr 	}
10357568150aSgwr 	if (sd->sd_group) {
1036bd7c6f51SGordon Ross 		own_gid = mip->mi_uid;
10377568150aSgwr 		mip++;
10387568150aSgwr 	}
10397568150aSgwr 
1040bd7c6f51SGordon Ross 	if (uidp)
1041bd7c6f51SGordon Ross 		*uidp = own_uid;
1042bd7c6f51SGordon Ross 	if (gidp)
1043bd7c6f51SGordon Ross 		*gidp = own_gid;
1044bd7c6f51SGordon Ross 
10457568150aSgwr 	if (acl_info == NULL) {
10467568150aSgwr 		/* Caller only wanted uid/gid */
1047bd7c6f51SGordon Ross 		goto done;
10487568150aSgwr 	}
10497568150aSgwr 
10507568150aSgwr 	/*
10517568150aSgwr 	 * Build the ZFS-style ACL
1052bd7c6f51SGordon Ross 	 * First, allocate the most ZFS ACEs we'll need.
10537568150aSgwr 	 */
10547568150aSgwr 	zacecnt = 0;
1055bd7c6f51SGordon Ross 	if ((sd->sd_flags & SD_SACL_PRESENT) &&
1056bd7c6f51SGordon Ross 	    (sd->sd_sacl != NULL))
10577568150aSgwr 		zacecnt += sd->sd_sacl->acl_acecount;
1058bd7c6f51SGordon Ross 
1059bd7c6f51SGordon Ross 	/* NB, have: (sd->sd_flags & SD_DACL_PRESENT) */
1060bd7c6f51SGordon Ross 	if ((sd->sd_dacl != NULL) &&
1061bd7c6f51SGordon Ross 	    (sd->sd_dacl->acl_acecount > 0)) {
10627568150aSgwr 		zacecnt += sd->sd_dacl->acl_acecount;
1063bd7c6f51SGordon Ross 	} else {
1064bd7c6f51SGordon Ross 		/*
1065bd7c6f51SGordon Ross 		 * DACL is NULL or empty. Either way,
1066bd7c6f51SGordon Ross 		 * we'll need to add a ZFS ACE below.
1067bd7c6f51SGordon Ross 		 */
1068bd7c6f51SGordon Ross 		zacecnt++;
1069bd7c6f51SGordon Ross 	}
10707568150aSgwr 	zacl_size = zacecnt * sizeof (ace_t);
1071bd7c6f51SGordon Ross 	zacep0 = MALLOC(zacl_size);
1072bd7c6f51SGordon Ross 	if (zacep0 == NULL) {
10737568150aSgwr 		error = ENOMEM;
10747568150aSgwr 		goto errout;
10757568150aSgwr 	}
1076bd7c6f51SGordon Ross 	zacep = zacep0;
10777568150aSgwr 
1078bd7c6f51SGordon Ross 	if ((sd->sd_flags & SD_SACL_PRESENT) &&
1079bd7c6f51SGordon Ross 	    (sd->sd_sacl != NULL)) {
10807568150aSgwr 		ntacl = sd->sd_sacl;
10817568150aSgwr 		ntacep = &ntacl->acl_acevec[0];
10827568150aSgwr 		for (i = 0; i < ntacl->acl_acecount; i++) {
10837568150aSgwr 			ntace2zace(zacep, *ntacep, mip);
10847568150aSgwr 			zacep++;
10857568150aSgwr 			ntacep++;
10867568150aSgwr 			mip++;
10877568150aSgwr 		}
10887568150aSgwr 	}
1089bd7c6f51SGordon Ross 
1090bd7c6f51SGordon Ross 	/* NB, have: (sd->sd_flags & SD_DACL_PRESENT) */
1091bd7c6f51SGordon Ross 	if (sd->sd_dacl != NULL) {
10927568150aSgwr 		ntacl = sd->sd_dacl;
10937568150aSgwr 		ntacep = &ntacl->acl_acevec[0];
10947568150aSgwr 		for (i = 0; i < ntacl->acl_acecount; i++) {
10957568150aSgwr 			ntace2zace(zacep, *ntacep, mip);
10967568150aSgwr 			zacep++;
10977568150aSgwr 			ntacep++;
10987568150aSgwr 			mip++;
10997568150aSgwr 		}
11007568150aSgwr 	}
1101bd7c6f51SGordon Ross 	if (sd->sd_dacl == NULL) {
1102bd7c6f51SGordon Ross 		/*
1103bd7c6f51SGordon Ross 		 * The SD has a NULL DACL.  That means
1104bd7c6f51SGordon Ross 		 * everyone@, full-control
1105bd7c6f51SGordon Ross 		 */
1106bd7c6f51SGordon Ross 		zacep->a_who = (uid_t)-1;
1107bd7c6f51SGordon Ross 		zacep->a_access_mask = ACE_ALL_PERMS;
1108bd7c6f51SGordon Ross 		zacep->a_flags = ACE_EVERYONE;
1109bd7c6f51SGordon Ross 		zacep->a_type = ACCESS_ALLOWED_ACE_TYPE;
1110bd7c6f51SGordon Ross 	} else if (sd->sd_dacl->acl_acecount == 0) {
1111bd7c6f51SGordon Ross 		/*
1112bd7c6f51SGordon Ross 		 * The SD has an Empty DACL.  We need
1113bd7c6f51SGordon Ross 		 * at least one ACE, so add one giving
1114bd7c6f51SGordon Ross 		 * the owner the usual implied access.
1115bd7c6f51SGordon Ross 		 */
1116bd7c6f51SGordon Ross 		zacep->a_who = (uid_t)-1;
1117bd7c6f51SGordon Ross 		zacep->a_access_mask = ACE_READ_ATTRIBUTES | \
1118bd7c6f51SGordon Ross 		    ACE_READ_ACL | ACE_WRITE_ACL;
1119bd7c6f51SGordon Ross 		zacep->a_flags = ACE_OWNER;
1120bd7c6f51SGordon Ross 		zacep->a_type = ACCESS_ALLOWED_ACE_TYPE;
1121bd7c6f51SGordon Ross 	}
11227568150aSgwr 
1123*8329232eSGordon Ross #if defined(_KERNEL) || defined(_FAKE_KERNEL)
1124bd7c6f51SGordon Ross 	acl_info->vsa_aclcnt = zacecnt;
1125bd7c6f51SGordon Ross 	acl_info->vsa_aclentp = zacep0;
1126bd7c6f51SGordon Ross 	acl_info->vsa_aclentsz = zacl_size;
1127bd7c6f51SGordon Ross #else	/* _KERNEL */
1128bd7c6f51SGordon Ross 	acl_info->acl_cnt = zacecnt;
1129bd7c6f51SGordon Ross 	acl_info->acl_aclp = zacep0;
1130bd7c6f51SGordon Ross #endif	/* _KERNEL */
1131bd7c6f51SGordon Ross 
1132bd7c6f51SGordon Ross done:
11337568150aSgwr 	error = 0;
11347568150aSgwr 
11357568150aSgwr errout:
1136bd7c6f51SGordon Ross 	if (mapinfo != NULL)
11377568150aSgwr 		FREESZ(mapinfo, mapcnt * sizeof (*mapinfo));
1138bd7c6f51SGordon Ross #ifdef	_KERNEL
1139bd7c6f51SGordon Ross 	if (idmap_gh != NULL)
1140bd7c6f51SGordon Ross 		kidmap_get_destroy(idmap_gh);
1141bd7c6f51SGordon Ross #else /* _KERNEL */
1142bd7c6f51SGordon Ross 	if (idmap_gh != NULL)
1143bd7c6f51SGordon Ross 		idmap_get_destroy(idmap_gh);
1144bd7c6f51SGordon Ross #endif /* _KERNEL */
11457568150aSgwr 
11467568150aSgwr 	return (error);
11477568150aSgwr }
11487568150aSgwr 
11497568150aSgwr 
11507568150aSgwr /*
1151bd7c6f51SGordon Ross  * ================================================================
1152bd7c6f51SGordon Ross  * Support for ACL store, including conversions
1153bd7c6f51SGordon Ross  * from NFSv4-style ACLs to Windows ACLs.
1154bd7c6f51SGordon Ross  * ================================================================
11557568150aSgwr  */
1156bd7c6f51SGordon Ross 
1157bd7c6f51SGordon Ross /*
1158bd7c6f51SGordon Ross  * Convert a "sid-prefix" string plus RID into an NT SID.
1159bd7c6f51SGordon Ross  *
1160bd7c6f51SGordon Ross  * If successful, sets *osid and returns zero,
1161bd7c6f51SGordon Ross  * otherwise returns an errno value.
1162bd7c6f51SGordon Ross  */
1163bd7c6f51SGordon Ross int
smbfs_str2sid(const char * sid_prefix,uint32_t * ridp,i_ntsid_t ** osidp)1164bd7c6f51SGordon Ross smbfs_str2sid(const char *sid_prefix, uint32_t *ridp, i_ntsid_t **osidp)
1165bd7c6f51SGordon Ross {
1166bd7c6f51SGordon Ross 	i_ntsid_t *sid = NULL;
1167bd7c6f51SGordon Ross 	u_longlong_t auth = 0;
1168bd7c6f51SGordon Ross 	ulong_t sa;
1169bd7c6f51SGordon Ross 	uint8_t sacnt;
1170bd7c6f51SGordon Ross 	const char *p;
1171bd7c6f51SGordon Ross 	char *np;
1172bd7c6f51SGordon Ross 	size_t size;
1173bd7c6f51SGordon Ross 	int i;
1174bd7c6f51SGordon Ross 	int err;
1175bd7c6f51SGordon Ross 
1176bd7c6f51SGordon Ross 	if (sid_prefix == NULL)
1177bd7c6f51SGordon Ross 		return (EINVAL);
1178bd7c6f51SGordon Ross 
1179bd7c6f51SGordon Ross 	p = sid_prefix;
1180bd7c6f51SGordon Ross 	if (strncmp(p, "S-1-", 4) != 0)
1181bd7c6f51SGordon Ross 		return (EINVAL);
1182bd7c6f51SGordon Ross 	p += 4;
1183bd7c6f51SGordon Ross 
1184bd7c6f51SGordon Ross 	/* Parse the "authority" */
11857568150aSgwr #ifdef	_KERNEL
1186bd7c6f51SGordon Ross 	err = ddi_strtoull(p, &np, 10, &auth);
1187bd7c6f51SGordon Ross 	if (err != 0)
1188bd7c6f51SGordon Ross 		return (err);
1189bd7c6f51SGordon Ross #else	/* _KERNEL */
1190bd7c6f51SGordon Ross 	auth = strtoull(p, &np, 10);
1191bd7c6f51SGordon Ross 	if (p == np)
1192bd7c6f51SGordon Ross 		return (EINVAL);
1193bd7c6f51SGordon Ross #endif	/* _KERNEL */
1194bd7c6f51SGordon Ross 
1195bd7c6f51SGordon Ross 	/*
1196bd7c6f51SGordon Ross 	 * Count the sub-authorities.  Here, np points to
1197bd7c6f51SGordon Ross 	 * the "-" before the first sub-authority.
1198bd7c6f51SGordon Ross 	 */
1199bd7c6f51SGordon Ross 	sacnt = 0;
1200bd7c6f51SGordon Ross 	for (p = np; *p; p++) {
1201bd7c6f51SGordon Ross 		if (*p == '-')
1202bd7c6f51SGordon Ross 			sacnt++;
1203bd7c6f51SGordon Ross 	}
1204bd7c6f51SGordon Ross 	if (ridp != NULL)
1205bd7c6f51SGordon Ross 		sacnt++;
1206bd7c6f51SGordon Ross 
1207bd7c6f51SGordon Ross 	/* Allocate the internal SID. */
1208bd7c6f51SGordon Ross 	size = I_SID_SIZE(sacnt);
1209bd7c6f51SGordon Ross 	sid = MALLOC(size);
1210bd7c6f51SGordon Ross 	if (sid == NULL)
1211bd7c6f51SGordon Ross 		return (ENOMEM);
1212bd7c6f51SGordon Ross 	bzero(sid, size);
1213bd7c6f51SGordon Ross 
1214bd7c6f51SGordon Ross 	/* Fill it in. */
1215bd7c6f51SGordon Ross 	sid->sid_revision = 1;
1216bd7c6f51SGordon Ross 	sid->sid_subauthcount = sacnt;
1217bd7c6f51SGordon Ross 	for (i = 5; i >= 0; i--) {
1218bd7c6f51SGordon Ross 		sid->sid_authority[i] = auth & 0xFF;
1219bd7c6f51SGordon Ross 		auth = auth >> 8;
1220bd7c6f51SGordon Ross 	}
1221bd7c6f51SGordon Ross 
1222bd7c6f51SGordon Ross 	err = EINVAL;
1223bd7c6f51SGordon Ross 	if (ridp != NULL)
1224bd7c6f51SGordon Ross 		sacnt--; /* Last SA not from string */
1225bd7c6f51SGordon Ross 	p = np;
1226bd7c6f51SGordon Ross 	for (i = 0; i < sacnt; i++) {
1227bd7c6f51SGordon Ross 		if (*p != '-') {
1228bd7c6f51SGordon Ross 			err = EINVAL;
1229bd7c6f51SGordon Ross 			goto out;
1230bd7c6f51SGordon Ross 		}
1231bd7c6f51SGordon Ross 		p++;
1232*8329232eSGordon Ross #if defined(_KERNEL) || defined(_FAKE_KERNEL)
1233bd7c6f51SGordon Ross 		err = ddi_strtoul(p, &np, 10, &sa);
1234bd7c6f51SGordon Ross 		if (err != 0)
1235bd7c6f51SGordon Ross 			goto out;
1236bd7c6f51SGordon Ross #else	/* _KERNEL */
1237bd7c6f51SGordon Ross 		sa = strtoul(p, &np, 10);
1238bd7c6f51SGordon Ross 		if (p == np) {
1239bd7c6f51SGordon Ross 			err = EINVAL;
1240bd7c6f51SGordon Ross 			goto out;
1241bd7c6f51SGordon Ross 		}
1242bd7c6f51SGordon Ross #endif	/* _KERNEL */
1243bd7c6f51SGordon Ross 		sid->sid_subauthvec[i] = (uint32_t)sa;
1244bd7c6f51SGordon Ross 		p = np;
1245bd7c6f51SGordon Ross 	}
1246bd7c6f51SGordon Ross 	if (*p != '\0')
1247bd7c6f51SGordon Ross 		goto out;
1248bd7c6f51SGordon Ross 	if (ridp != NULL)
1249bd7c6f51SGordon Ross 		sid->sid_subauthvec[i] = *ridp;
1250bd7c6f51SGordon Ross 	err = 0;
1251bd7c6f51SGordon Ross 
1252bd7c6f51SGordon Ross out:
1253bd7c6f51SGordon Ross 	if (err)
1254bd7c6f51SGordon Ross 		FREESZ(sid, size);
1255bd7c6f51SGordon Ross 	else
1256bd7c6f51SGordon Ross 		*osidp = sid;
1257bd7c6f51SGordon Ross 
1258bd7c6f51SGordon Ross 	return (err);
1259bd7c6f51SGordon Ross }
1260bd7c6f51SGordon Ross 
1261bd7c6f51SGordon Ross /*
1262bd7c6f51SGordon Ross  * The idmap API is _almost_ the same between
1263bd7c6f51SGordon Ross  * kernel and user-level.  But not quite...
1264bd7c6f51SGordon Ross  * Hope this improves readability below.
1265bd7c6f51SGordon Ross  */
1266bd7c6f51SGordon Ross #ifdef	_KERNEL
1267bd7c6f51SGordon Ross 
1268bd7c6f51SGordon Ross #define	I_getsidbyuid(GH, UID, SPP, RP, ST) \
1269bd7c6f51SGordon Ross 	kidmap_batch_getsidbyuid(GH, UID, SPP, RP, ST)
1270bd7c6f51SGordon Ross 
1271bd7c6f51SGordon Ross #define	I_getsidbygid(GH, GID, SPP, RP, ST) \
1272bd7c6f51SGordon Ross 	kidmap_batch_getsidbygid(GH, GID, SPP, RP, ST)
1273bd7c6f51SGordon Ross 
12747568150aSgwr #else /* _KERNEL */
1275bd7c6f51SGordon Ross 
1276bd7c6f51SGordon Ross #define	I_getsidbyuid(GH, UID, SPP, RP, ST) \
1277bd7c6f51SGordon Ross 	idmap_get_sidbyuid(GH, UID, 0, SPP, RP, ST)
1278bd7c6f51SGordon Ross 
1279bd7c6f51SGordon Ross #define	I_getsidbygid(GH, GID, SPP, RP, ST) \
1280bd7c6f51SGordon Ross 	idmap_get_sidbygid(GH, GID, 0, SPP, RP, ST)
1281bd7c6f51SGordon Ross 
12827568150aSgwr #endif /* _KERNEL */
1283bd7c6f51SGordon Ross 
1284bd7c6f51SGordon Ross struct mapinfo2sid {
1285bd7c6f51SGordon Ross 	/* Yet another kernel vs. user difference. */
1286bd7c6f51SGordon Ross #ifdef	_KERNEL
1287bd7c6f51SGordon Ross 	const char *mi_dsid;	/* domain SID */
1288bd7c6f51SGordon Ross #else /* _KERNEL */
1289bd7c6f51SGordon Ross 	char *mi_dsid;
1290bd7c6f51SGordon Ross #endif /* _KERNEL */
1291bd7c6f51SGordon Ross 	uint32_t mi_rid;	/* relative ID */
1292bd7c6f51SGordon Ross 	idmap_stat mi_status;
1293bd7c6f51SGordon Ross };
1294bd7c6f51SGordon Ross 
1295bd7c6f51SGordon Ross /*
1296bd7c6f51SGordon Ross  * Build an idmap request.  Cleanup is
1297bd7c6f51SGordon Ross  * handled by the caller (error or not)
1298bd7c6f51SGordon Ross  */
1299bd7c6f51SGordon Ross static int
mkrq_idmap_ux2sid(idmap_get_handle_t * idmap_gh,struct mapinfo2sid * mip,uid_t uid,int req_type)1300bd7c6f51SGordon Ross mkrq_idmap_ux2sid(
1301bd7c6f51SGordon Ross 	idmap_get_handle_t *idmap_gh,
1302bd7c6f51SGordon Ross 	struct mapinfo2sid *mip,
1303bd7c6f51SGordon Ross 	uid_t	uid, /* or gid */
1304bd7c6f51SGordon Ross 	int req_type)
1305bd7c6f51SGordon Ross {
1306bd7c6f51SGordon Ross 	idmap_stat	idms;
1307bd7c6f51SGordon Ross 
1308bd7c6f51SGordon Ross 	switch (req_type) {
1309bd7c6f51SGordon Ross 
1310bd7c6f51SGordon Ross 	case IDM_TYPE_USER:
1311bd7c6f51SGordon Ross 		if (uid == (uid_t)-1)
1312bd7c6f51SGordon Ross 			return (EINVAL);
1313bd7c6f51SGordon Ross 		idms = I_getsidbyuid(idmap_gh, uid,
1314bd7c6f51SGordon Ross 		    &mip->mi_dsid, &mip->mi_rid, &mip->mi_status);
1315bd7c6f51SGordon Ross 		break;
1316bd7c6f51SGordon Ross 
1317bd7c6f51SGordon Ross 	case IDM_TYPE_GROUP:
1318bd7c6f51SGordon Ross 		if (uid == (uid_t)-1)
1319bd7c6f51SGordon Ross 			return (EINVAL);
1320bd7c6f51SGordon Ross 		idms = I_getsidbygid(idmap_gh, uid,
1321bd7c6f51SGordon Ross 		    &mip->mi_dsid, &mip->mi_rid, &mip->mi_status);
1322bd7c6f51SGordon Ross 		break;
1323bd7c6f51SGordon Ross 
1324bd7c6f51SGordon Ross 	case IDM_EVERYONE:
1325bd7c6f51SGordon Ross 		mip->mi_dsid = "S-1-1";
1326bd7c6f51SGordon Ross 		mip->mi_rid = 0;
1327bd7c6f51SGordon Ross 		mip->mi_status = 0;
1328bd7c6f51SGordon Ross 		idms = IDMAP_SUCCESS;
1329bd7c6f51SGordon Ross 		break;
1330bd7c6f51SGordon Ross 
1331bd7c6f51SGordon Ross 	default:
1332bd7c6f51SGordon Ross 		idms = IDMAP_ERR_OTHER;
1333bd7c6f51SGordon Ross 		break;
1334bd7c6f51SGordon Ross 	}
1335bd7c6f51SGordon Ross 
1336bd7c6f51SGordon Ross 	if (idms != IDMAP_SUCCESS)
1337bd7c6f51SGordon Ross 		return (EINVAL);
1338bd7c6f51SGordon Ross 
1339bd7c6f51SGordon Ross 	return (0);
1340bd7c6f51SGordon Ross }
1341bd7c6f51SGordon Ross 
1342bd7c6f51SGordon Ross /*
1343bd7c6f51SGordon Ross  * Convert a ZFS ACE to an NT ACE.
1344bd7c6f51SGordon Ross  * ACE type was already validated.
1345bd7c6f51SGordon Ross  */
1346bd7c6f51SGordon Ross static int
zace2ntace(i_ntace_t ** ntacep,ace_t * zacep,struct mapinfo2sid * mip)1347bd7c6f51SGordon Ross zace2ntace(i_ntace_t **ntacep, ace_t *zacep, struct mapinfo2sid *mip)
1348bd7c6f51SGordon Ross {
1349bd7c6f51SGordon Ross 	const struct zaf2naf *znaf;
1350bd7c6f51SGordon Ross 	uint8_t aflags;
1351bd7c6f51SGordon Ross 	uint16_t alloc_size;
1352bd7c6f51SGordon Ross 	uint32_t rights;
1353bd7c6f51SGordon Ross 	i_ntace_t *ntace = NULL;
1354bd7c6f51SGordon Ross 	i_ntsid_t *sid = NULL;
1355bd7c6f51SGordon Ross 	int error;
1356bd7c6f51SGordon Ross 
1357bd7c6f51SGordon Ross 	if (mip->mi_dsid == NULL || mip->mi_status != 0) {
1358bd7c6f51SGordon Ross 		return (EINVAL);
1359bd7c6f51SGordon Ross 	}
1360bd7c6f51SGordon Ross 
1361bd7c6f51SGordon Ross 	/*
1362bd7c6f51SGordon Ross 	 * Translate ZFS ACE flags to NT ACE flags.
1363bd7c6f51SGordon Ross 	 */
1364bd7c6f51SGordon Ross 	aflags = 0;
1365bd7c6f51SGordon Ross 	for (znaf = smbfs_zaf2naf; znaf->za_flag; znaf++)
1366bd7c6f51SGordon Ross 		if (zacep->a_flags & znaf->za_flag)
1367bd7c6f51SGordon Ross 			aflags |= znaf->na_flag;
1368bd7c6f51SGordon Ross 
1369bd7c6f51SGordon Ross 	/*
1370bd7c6f51SGordon Ross 	 * The access rights bits are OK as-is.
1371bd7c6f51SGordon Ross 	 */
1372bd7c6f51SGordon Ross 	rights = zacep->a_access_mask;
1373bd7c6f51SGordon Ross 
1374bd7c6f51SGordon Ross 	/*
1375bd7c6f51SGordon Ross 	 * Make sure we can get the SID.
1376bd7c6f51SGordon Ross 	 * Note: allocates sid.
1377bd7c6f51SGordon Ross 	 */
1378bd7c6f51SGordon Ross 	error = smbfs_str2sid(mip->mi_dsid, &mip->mi_rid, &sid);
1379bd7c6f51SGordon Ross 	if (error)
1380bd7c6f51SGordon Ross 		return (error);
1381bd7c6f51SGordon Ross 
1382bd7c6f51SGordon Ross 	/*
1383bd7c6f51SGordon Ross 	 * Allocate the NT ACE and fill it in.
1384bd7c6f51SGordon Ross 	 */
1385bd7c6f51SGordon Ross 	alloc_size = sizeof (i_ntace_v2_t);
1386bd7c6f51SGordon Ross 	if ((ntace = MALLOC(alloc_size)) == NULL) {
1387bd7c6f51SGordon Ross 		ifree_sid(sid);
1388bd7c6f51SGordon Ross 		return (ENOMEM);
1389bd7c6f51SGordon Ross 	}
1390bd7c6f51SGordon Ross 	bzero(ntace, alloc_size);
1391bd7c6f51SGordon Ross 
1392bd7c6f51SGordon Ross 	ntace->ace_hdr.ace_type = zacep->a_type;
1393bd7c6f51SGordon Ross 	ntace->ace_hdr.ace_flags = aflags;
1394bd7c6f51SGordon Ross 	ntace->ace_hdr.ace_size = alloc_size;
1395bd7c6f51SGordon Ross 	ntace->ace_v2.ace_rights = rights;
1396bd7c6f51SGordon Ross 	ntace->ace_v2.ace_sid = sid;
1397bd7c6f51SGordon Ross 
1398bd7c6f51SGordon Ross 	*ntacep = ntace;
1399bd7c6f51SGordon Ross 	return (0);
1400bd7c6f51SGordon Ross }
1401bd7c6f51SGordon Ross 
1402bd7c6f51SGordon Ross /*
1403bd7c6f51SGordon Ross  * Convert a ZFS-style ACL to an internal SD.
1404bd7c6f51SGordon Ross  * Set owner/group too if selector indicates.
1405bd7c6f51SGordon Ross  * Always need to pass uid+gid, either the new
1406bd7c6f51SGordon Ross  * (when setting them) or existing, so that any
1407bd7c6f51SGordon Ross  * owner@ or group@ ACEs can be translated.
1408bd7c6f51SGordon Ross  *
1409bd7c6f51SGordon Ross  * This makes two passes over the ZFS ACL.  The first builds a
1410bd7c6f51SGordon Ross  * "batch" request for idmap with results in mapinfo, and the
1411bd7c6f51SGordon Ross  * second builds the NT SD using the idmap SID results.
1412bd7c6f51SGordon Ross  */
1413bd7c6f51SGordon Ross int
smbfs_acl_zfs2sd(vsecattr_t * acl_info,uid_t own_uid,gid_t own_gid,uint32_t selector,i_ntsd_t ** sdp)1414bd7c6f51SGordon Ross smbfs_acl_zfs2sd(
1415*8329232eSGordon Ross #if defined(_KERNEL) || defined(_FAKE_KERNEL)
1416bd7c6f51SGordon Ross 	vsecattr_t *acl_info,
1417bd7c6f51SGordon Ross #else /* _KERNEL */
1418bd7c6f51SGordon Ross 	acl_t *acl_info,
1419bd7c6f51SGordon Ross #endif /* _KERNEL */
1420bd7c6f51SGordon Ross 	uid_t own_uid,
1421bd7c6f51SGordon Ross 	gid_t own_gid,
1422bd7c6f51SGordon Ross 	uint32_t selector,
14237568150aSgwr 	i_ntsd_t **sdp)
14247568150aSgwr {
1425bd7c6f51SGordon Ross 	struct mapinfo2sid *mip, *mip_acl, *mapinfo = NULL;
1426bd7c6f51SGordon Ross 	int aclsz, error, i, mapcnt;
1427bd7c6f51SGordon Ross 	int dacl_acecnt = 0;
1428bd7c6f51SGordon Ross 	int sacl_acecnt = 0;
1429bd7c6f51SGordon Ross 	int zacecnt = 0;
1430bd7c6f51SGordon Ross 	ace_t *zacevec = NULL;
1431bd7c6f51SGordon Ross 	ace_t *zacep;
1432bd7c6f51SGordon Ross 	i_ntsd_t *sd = NULL;
1433bd7c6f51SGordon Ross 	i_ntacl_t *acl = NULL;
1434bd7c6f51SGordon Ross 	i_ntace_t **acep = NULL;
1435bd7c6f51SGordon Ross 	idmap_get_handle_t *idmap_gh = NULL;
1436bd7c6f51SGordon Ross 	idmap_stat	idms;
1437bd7c6f51SGordon Ross 
1438bd7c6f51SGordon Ross 	/*
1439bd7c6f51SGordon Ross 	 * First, get all the UID+GID to SID mappings.
1440bd7c6f51SGordon Ross 	 * How many?  Also sanity checks.
1441bd7c6f51SGordon Ross 	 */
1442bd7c6f51SGordon Ross 	mapcnt = 0;
1443bd7c6f51SGordon Ross 	if (selector & OWNER_SECURITY_INFORMATION) {
1444bd7c6f51SGordon Ross 		if (own_uid == (uid_t)-1)
1445bd7c6f51SGordon Ross 			return (EINVAL);
1446bd7c6f51SGordon Ross 		mapcnt++;
1447bd7c6f51SGordon Ross 	}
1448bd7c6f51SGordon Ross 	if (selector & GROUP_SECURITY_INFORMATION) {
1449bd7c6f51SGordon Ross 		if (own_gid == (gid_t)-1)
1450bd7c6f51SGordon Ross 			return (EINVAL);
1451bd7c6f51SGordon Ross 		mapcnt++;
1452bd7c6f51SGordon Ross 	}
1453bd7c6f51SGordon Ross 	if (selector & (DACL_SECURITY_INFORMATION |
1454bd7c6f51SGordon Ross 	    SACL_SECURITY_INFORMATION)) {
1455bd7c6f51SGordon Ross 		if (acl_info == NULL)
1456bd7c6f51SGordon Ross 			return (EINVAL);
1457bd7c6f51SGordon Ross 		if (own_uid == (uid_t)-1)
1458bd7c6f51SGordon Ross 			return (EINVAL);
1459bd7c6f51SGordon Ross 		if (own_gid == (gid_t)-1)
1460bd7c6f51SGordon Ross 			return (EINVAL);
1461*8329232eSGordon Ross #if defined(_KERNEL) || defined(_FAKE_KERNEL)
1462bd7c6f51SGordon Ross 		if ((acl_info->vsa_mask & VSA_ACE) == 0)
1463bd7c6f51SGordon Ross 			return (EINVAL);
1464bd7c6f51SGordon Ross 		zacecnt = acl_info->vsa_aclcnt;
1465bd7c6f51SGordon Ross 		zacevec = acl_info->vsa_aclentp;
1466bd7c6f51SGordon Ross #else	/* _KERNEL */
1467bd7c6f51SGordon Ross 		if (acl_info->acl_type != ACE_T ||
1468bd7c6f51SGordon Ross 		    acl_info->acl_entry_size != sizeof (ace_t))
1469bd7c6f51SGordon Ross 			return (EINVAL);
1470bd7c6f51SGordon Ross 		zacecnt = acl_info->acl_cnt;
1471bd7c6f51SGordon Ross 		zacevec = acl_info->acl_aclp;
1472bd7c6f51SGordon Ross #endif	/* _KERNEL */
1473bd7c6f51SGordon Ross 		if (zacecnt == 0 || zacevec == NULL)
1474bd7c6f51SGordon Ross 			return (EINVAL);
1475bd7c6f51SGordon Ross 		mapcnt += zacecnt;
1476bd7c6f51SGordon Ross 	}
1477bd7c6f51SGordon Ross 	if (mapcnt == 0)
1478bd7c6f51SGordon Ross 		return (EINVAL);
1479bd7c6f51SGordon Ross 	mapinfo = MALLOC(mapcnt * sizeof (*mapinfo));
1480bd7c6f51SGordon Ross 	if (mapinfo == NULL)
1481bd7c6f51SGordon Ross 		return (ENOMEM);
1482bd7c6f51SGordon Ross 	bzero(mapinfo, mapcnt * sizeof (*mapinfo));
1483bd7c6f51SGordon Ross 	/* no more returns until errout */
1484bd7c6f51SGordon Ross 
1485bd7c6f51SGordon Ross 	/*
1486bd7c6f51SGordon Ross 	 * Get an imap "batch" request handle.
1487bd7c6f51SGordon Ross 	 */
1488bd7c6f51SGordon Ross #ifdef	_KERNEL
1489bd7c6f51SGordon Ross 	idmap_gh = kidmap_get_create(curproc->p_zone);
1490bd7c6f51SGordon Ross #else /* _KERNEL */
14911fdeec65Sjoyce mcintosh 	idms = idmap_get_create(&idmap_gh);
1492bd7c6f51SGordon Ross 	if (idms != IDMAP_SUCCESS) {
1493bd7c6f51SGordon Ross 		error = ENOTACTIVE;
1494bd7c6f51SGordon Ross 		goto errout;
1495bd7c6f51SGordon Ross 	}
1496bd7c6f51SGordon Ross #endif /* _KERNEL */
1497bd7c6f51SGordon Ross 
1498bd7c6f51SGordon Ross 	/*
1499bd7c6f51SGordon Ross 	 * Build our request to the idmap deamon,
1500bd7c6f51SGordon Ross 	 * getting SIDs for every Unix UID/GID.
1501bd7c6f51SGordon Ross 	 * Also count DACL and SACL ACEs here.
1502bd7c6f51SGordon Ross 	 */
1503bd7c6f51SGordon Ross 	mip = mapinfo;
1504bd7c6f51SGordon Ross 	if (selector & OWNER_SECURITY_INFORMATION) {
1505bd7c6f51SGordon Ross 		error = mkrq_idmap_ux2sid(idmap_gh, mip,
1506bd7c6f51SGordon Ross 		    own_uid, IDM_TYPE_USER);
1507bd7c6f51SGordon Ross 		if (error)
1508bd7c6f51SGordon Ross 			goto errout;
1509bd7c6f51SGordon Ross 		mip++;
1510bd7c6f51SGordon Ross 	}
1511bd7c6f51SGordon Ross 	if (selector & GROUP_SECURITY_INFORMATION) {
1512bd7c6f51SGordon Ross 		error = mkrq_idmap_ux2sid(idmap_gh, mip,
1513bd7c6f51SGordon Ross 		    own_gid, IDM_TYPE_GROUP);
1514bd7c6f51SGordon Ross 		if (error)
1515bd7c6f51SGordon Ross 			goto errout;
1516bd7c6f51SGordon Ross 		mip++;
1517bd7c6f51SGordon Ross 	}
1518bd7c6f51SGordon Ross 	if (selector & (DACL_SECURITY_INFORMATION |
1519bd7c6f51SGordon Ross 	    SACL_SECURITY_INFORMATION)) {
1520bd7c6f51SGordon Ross 		int rqtype;
1521bd7c6f51SGordon Ross 		uid_t uid;
1522bd7c6f51SGordon Ross 
1523bd7c6f51SGordon Ross 		zacep = zacevec;
1524bd7c6f51SGordon Ross 		for (i = 0; i < zacecnt; i++) {
1525bd7c6f51SGordon Ross 
1526bd7c6f51SGordon Ross 			switch (zacep->a_type) {
1527bd7c6f51SGordon Ross 			case ACE_ACCESS_ALLOWED_ACE_TYPE:
1528bd7c6f51SGordon Ross 			case ACE_ACCESS_DENIED_ACE_TYPE:
1529bd7c6f51SGordon Ross 				dacl_acecnt++;
1530bd7c6f51SGordon Ross 				break;
1531bd7c6f51SGordon Ross 			case ACE_SYSTEM_AUDIT_ACE_TYPE:
1532bd7c6f51SGordon Ross 			case ACE_SYSTEM_ALARM_ACE_TYPE:
1533bd7c6f51SGordon Ross 				sacl_acecnt++;
1534bd7c6f51SGordon Ross 				break;
1535bd7c6f51SGordon Ross 			/* other types todo */
1536bd7c6f51SGordon Ross 			}
1537bd7c6f51SGordon Ross 
1538bd7c6f51SGordon Ross 			if (zacep->a_flags & ACE_EVERYONE) {
1539bd7c6f51SGordon Ross 				rqtype = IDM_EVERYONE;
1540bd7c6f51SGordon Ross 				uid = (uid_t)-1;
1541bd7c6f51SGordon Ross 			} else if (zacep->a_flags & ACE_GROUP) {
1542bd7c6f51SGordon Ross 				/* owning group (a_who = -1) */
1543bd7c6f51SGordon Ross 				rqtype = IDM_TYPE_GROUP;
1544bd7c6f51SGordon Ross 				uid = (uid_t)own_gid;
1545bd7c6f51SGordon Ross 			} else if (zacep->a_flags & ACE_OWNER) {
1546bd7c6f51SGordon Ross 				/* owning user (a_who = -1) */
1547bd7c6f51SGordon Ross 				rqtype = IDM_TYPE_USER;
1548bd7c6f51SGordon Ross 				uid = (uid_t)own_uid;
1549bd7c6f51SGordon Ross 			} else if (zacep->a_flags & ACE_IDENTIFIER_GROUP) {
1550bd7c6f51SGordon Ross 				/* regular group */
1551bd7c6f51SGordon Ross 				rqtype = IDM_TYPE_GROUP;
1552bd7c6f51SGordon Ross 				uid = zacep->a_who;
1553bd7c6f51SGordon Ross 			} else {
1554bd7c6f51SGordon Ross 				rqtype = IDM_TYPE_USER;
1555bd7c6f51SGordon Ross 				uid = zacep->a_who;
1556bd7c6f51SGordon Ross 			}
1557bd7c6f51SGordon Ross 
1558bd7c6f51SGordon Ross 			error = mkrq_idmap_ux2sid(idmap_gh, mip, uid, rqtype);
1559bd7c6f51SGordon Ross 			if (error)
1560bd7c6f51SGordon Ross 				goto errout;
1561bd7c6f51SGordon Ross 			zacep++;
1562bd7c6f51SGordon Ross 			mip++;
1563bd7c6f51SGordon Ross 		}
1564bd7c6f51SGordon Ross 	}
1565bd7c6f51SGordon Ross 
1566bd7c6f51SGordon Ross 	idms = I_getmappings(idmap_gh);
1567bd7c6f51SGordon Ross 	if (idms != IDMAP_SUCCESS) {
1568bd7c6f51SGordon Ross 		/* creative error choice */
1569bd7c6f51SGordon Ross 		error = EIDRM;
1570bd7c6f51SGordon Ross 		goto errout;
1571bd7c6f51SGordon Ross 	}
1572bd7c6f51SGordon Ross 
1573bd7c6f51SGordon Ross 	/*
1574bd7c6f51SGordon Ross 	 * With any luck, we now have a Windows SID for
1575bd7c6f51SGordon Ross 	 * every Unix UID or GID in the NFS/ZFS ACL.
1576bd7c6f51SGordon Ross 	 * The remaining work is just format conversion,
1577bd7c6f51SGordon Ross 	 * memory allocation, etc.
1578bd7c6f51SGordon Ross 	 */
1579bd7c6f51SGordon Ross 	if ((sd = MALLOC(sizeof (*sd))) == NULL) {
1580bd7c6f51SGordon Ross 		error = ENOMEM;
1581bd7c6f51SGordon Ross 		goto errout;
1582bd7c6f51SGordon Ross 	}
1583bd7c6f51SGordon Ross 	bzero(sd, sizeof (*sd));
1584bd7c6f51SGordon Ross 	sd->sd_revision = NT_SD_REVISION;
1585bd7c6f51SGordon Ross 
1586bd7c6f51SGordon Ross 	mip = mapinfo;
1587bd7c6f51SGordon Ross 	if (selector & OWNER_SECURITY_INFORMATION) {
1588bd7c6f51SGordon Ross 		error = smbfs_str2sid(mip->mi_dsid, &mip->mi_rid,
1589bd7c6f51SGordon Ross 		    &sd->sd_owner);
1590bd7c6f51SGordon Ross 		mip++;
1591bd7c6f51SGordon Ross 	}
1592bd7c6f51SGordon Ross 	if (selector & GROUP_SECURITY_INFORMATION) {
1593bd7c6f51SGordon Ross 		error = smbfs_str2sid(mip->mi_dsid, &mip->mi_rid,
1594bd7c6f51SGordon Ross 		    &sd->sd_group);
1595bd7c6f51SGordon Ross 		mip++;
1596bd7c6f51SGordon Ross 	}
1597bd7c6f51SGordon Ross 
1598bd7c6f51SGordon Ross 	/*
1599bd7c6f51SGordon Ross 	 * If setting both DACL and SACL, we will
1600bd7c6f51SGordon Ross 	 * make two passes starting here in mapinfo.
1601bd7c6f51SGordon Ross 	 */
1602bd7c6f51SGordon Ross 	mip_acl = mip;
1603bd7c6f51SGordon Ross 
1604bd7c6f51SGordon Ross 	if (selector & DACL_SECURITY_INFORMATION) {
1605bd7c6f51SGordon Ross 		/*
1606bd7c6f51SGordon Ross 		 * Caller wants to set the DACL.
1607bd7c6f51SGordon Ross 		 */
1608bd7c6f51SGordon Ross 		aclsz = I_ACL_SIZE(dacl_acecnt);
1609bd7c6f51SGordon Ross 		if ((acl = MALLOC(aclsz)) == NULL) {
1610bd7c6f51SGordon Ross 			error = ENOMEM;
1611bd7c6f51SGordon Ross 			goto errout;
1612bd7c6f51SGordon Ross 		}
1613bd7c6f51SGordon Ross 		bzero(acl, aclsz);
1614bd7c6f51SGordon Ross 
1615bd7c6f51SGordon Ross 		acl->acl_revision = NT_ACL_REVISION;
1616bd7c6f51SGordon Ross 		acl->acl_acecount = (uint16_t)dacl_acecnt;
1617bd7c6f51SGordon Ross 		acep = &acl->acl_acevec[0];
1618bd7c6f51SGordon Ross 
1619bd7c6f51SGordon Ross 		/* 1st pass - scan for DACL ACE types. */
1620bd7c6f51SGordon Ross 		mip = mip_acl;
1621bd7c6f51SGordon Ross 		zacep = zacevec;
1622bd7c6f51SGordon Ross 		for (i = 0; i < zacecnt; i++) {
1623bd7c6f51SGordon Ross 
1624bd7c6f51SGordon Ross 			switch (zacep->a_type) {
1625bd7c6f51SGordon Ross 			case ACE_ACCESS_ALLOWED_ACE_TYPE:
1626bd7c6f51SGordon Ross 			case ACE_ACCESS_DENIED_ACE_TYPE:
1627bd7c6f51SGordon Ross 				error = zace2ntace(acep, zacep, mip);
1628bd7c6f51SGordon Ross 				if (error != 0)
1629bd7c6f51SGordon Ross 					goto errout;
1630bd7c6f51SGordon Ross 				acep++;
1631bd7c6f51SGordon Ross 				break;
1632bd7c6f51SGordon Ross 
1633bd7c6f51SGordon Ross 			case ACE_SYSTEM_AUDIT_ACE_TYPE:
1634bd7c6f51SGordon Ross 			case ACE_SYSTEM_ALARM_ACE_TYPE:
1635bd7c6f51SGordon Ross 				break;
1636bd7c6f51SGordon Ross 			/* other types todo */
1637bd7c6f51SGordon Ross 			}
1638bd7c6f51SGordon Ross 			zacep++;
1639bd7c6f51SGordon Ross 			mip++;
1640bd7c6f51SGordon Ross 		}
1641bd7c6f51SGordon Ross 		sd->sd_dacl = acl;
1642bd7c6f51SGordon Ross 		acl = NULL;
1643bd7c6f51SGordon Ross 		sd->sd_flags |= SD_DACL_PRESENT;
1644bd7c6f51SGordon Ross 	}
1645bd7c6f51SGordon Ross 
1646bd7c6f51SGordon Ross 	if (selector & SACL_SECURITY_INFORMATION) {
1647bd7c6f51SGordon Ross 		/*
1648bd7c6f51SGordon Ross 		 * Caller wants to set the SACL.
1649bd7c6f51SGordon Ross 		 */
1650bd7c6f51SGordon Ross 		aclsz = I_ACL_SIZE(sacl_acecnt);
1651bd7c6f51SGordon Ross 		if ((acl = MALLOC(aclsz)) == NULL) {
1652bd7c6f51SGordon Ross 			error = ENOMEM;
1653bd7c6f51SGordon Ross 			goto errout;
1654bd7c6f51SGordon Ross 		}
1655bd7c6f51SGordon Ross 		bzero(acl, aclsz);
1656bd7c6f51SGordon Ross 
1657bd7c6f51SGordon Ross 		acl->acl_revision = NT_ACL_REVISION;
1658bd7c6f51SGordon Ross 		acl->acl_acecount = (uint16_t)sacl_acecnt;
1659bd7c6f51SGordon Ross 		acep = &acl->acl_acevec[0];
1660bd7c6f51SGordon Ross 
1661bd7c6f51SGordon Ross 		/* 2nd pass - scan for SACL ACE types. */
1662bd7c6f51SGordon Ross 		mip = mip_acl;
1663bd7c6f51SGordon Ross 		zacep = zacevec;
1664bd7c6f51SGordon Ross 		for (i = 0; i < zacecnt; i++) {
1665bd7c6f51SGordon Ross 
1666bd7c6f51SGordon Ross 			switch (zacep->a_type) {
1667bd7c6f51SGordon Ross 			case ACE_ACCESS_ALLOWED_ACE_TYPE:
1668bd7c6f51SGordon Ross 			case ACE_ACCESS_DENIED_ACE_TYPE:
1669bd7c6f51SGordon Ross 				break;
1670bd7c6f51SGordon Ross 
1671bd7c6f51SGordon Ross 			case ACE_SYSTEM_AUDIT_ACE_TYPE:
1672bd7c6f51SGordon Ross 			case ACE_SYSTEM_ALARM_ACE_TYPE:
1673bd7c6f51SGordon Ross 				error = zace2ntace(acep, zacep, mip);
1674bd7c6f51SGordon Ross 				if (error != 0)
1675bd7c6f51SGordon Ross 					goto errout;
1676bd7c6f51SGordon Ross 				acep++;
1677bd7c6f51SGordon Ross 				break;
1678bd7c6f51SGordon Ross 			/* other types todo */
1679bd7c6f51SGordon Ross 			}
1680bd7c6f51SGordon Ross 			zacep++;
1681bd7c6f51SGordon Ross 			mip++;
1682bd7c6f51SGordon Ross 		}
1683bd7c6f51SGordon Ross 		sd->sd_sacl = acl;
1684bd7c6f51SGordon Ross 		acl = NULL;
1685bd7c6f51SGordon Ross 		sd->sd_flags |= SD_SACL_PRESENT;
1686bd7c6f51SGordon Ross 	}
1687bd7c6f51SGordon Ross 
1688bd7c6f51SGordon Ross 	*sdp = sd;
1689bd7c6f51SGordon Ross 	error = 0;
1690bd7c6f51SGordon Ross 
1691bd7c6f51SGordon Ross errout:
1692bd7c6f51SGordon Ross 	if (error != 0) {
1693bd7c6f51SGordon Ross 		if (acl != NULL)
1694bd7c6f51SGordon Ross 			ifree_acl(acl);
1695bd7c6f51SGordon Ross 		if (sd != NULL)
1696bd7c6f51SGordon Ross 			smbfs_acl_free_sd(sd);
1697bd7c6f51SGordon Ross 	}
1698bd7c6f51SGordon Ross 	if (mapinfo != NULL)
1699bd7c6f51SGordon Ross 		FREESZ(mapinfo, mapcnt * sizeof (*mapinfo));
1700bd7c6f51SGordon Ross #ifdef	_KERNEL
1701bd7c6f51SGordon Ross 	if (idmap_gh != NULL)
1702bd7c6f51SGordon Ross 		kidmap_get_destroy(idmap_gh);
1703bd7c6f51SGordon Ross #else /* _KERNEL */
1704bd7c6f51SGordon Ross 	if (idmap_gh != NULL)
1705bd7c6f51SGordon Ross 		idmap_get_destroy(idmap_gh);
1706bd7c6f51SGordon Ross #endif /* _KERNEL */
1707bd7c6f51SGordon Ross 
1708bd7c6f51SGordon Ross 	return (error);
17097568150aSgwr }
1710