xref: /titanic_44/usr/src/common/smbclnt/smbfs_ntacl.c (revision bd7c6f51f14365fc31d408903b38c02177384d3d)
102d09e03SGordon Ross /*
202d09e03SGordon Ross  * CDDL HEADER START
302d09e03SGordon Ross  *
402d09e03SGordon Ross  * The contents of this file are subject to the terms of the
502d09e03SGordon Ross  * Common Development and Distribution License (the "License").
602d09e03SGordon Ross  * You may not use this file except in compliance with the License.
702d09e03SGordon Ross  *
802d09e03SGordon Ross  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
902d09e03SGordon Ross  * or http://www.opensolaris.org/os/licensing.
1002d09e03SGordon Ross  * See the License for the specific language governing permissions
1102d09e03SGordon Ross  * and limitations under the License.
1202d09e03SGordon Ross  *
1302d09e03SGordon Ross  * When distributing Covered Code, include this CDDL HEADER in each
1402d09e03SGordon Ross  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1502d09e03SGordon Ross  * If applicable, add the following below this CDDL HEADER, with the
1602d09e03SGordon Ross  * fields enclosed by brackets "[]" replaced with your own identifying
1702d09e03SGordon Ross  * information: Portions Copyright [yyyy] [name of copyright owner]
1802d09e03SGordon Ross  *
1902d09e03SGordon Ross  * CDDL HEADER END
2002d09e03SGordon Ross  */
2102d09e03SGordon Ross 
2202d09e03SGordon Ross /*
23*bd7c6f51SGordon Ross  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2402d09e03SGordon Ross  * Use is subject to license terms.
2502d09e03SGordon Ross  */
2602d09e03SGordon Ross 
2702d09e03SGordon Ross /*
2802d09e03SGordon Ross  * ACL conversion support for smbfs
2902d09e03SGordon Ross  * (To/from NT/ZFS-style ACLs.)
3002d09e03SGordon Ross  */
3102d09e03SGordon Ross 
3202d09e03SGordon Ross #include <sys/types.h>
3302d09e03SGordon Ross #include <sys/errno.h>
3402d09e03SGordon Ross #include <sys/acl.h>
3502d09e03SGordon Ross #include <sys/byteorder.h>
3602d09e03SGordon Ross 
3702d09e03SGordon Ross #ifdef _KERNEL
3802d09e03SGordon Ross 
3902d09e03SGordon Ross #include <sys/cred.h>
4002d09e03SGordon Ross #include <sys/cmn_err.h>
4102d09e03SGordon Ross #include <sys/kmem.h>
4202d09e03SGordon Ross #include <sys/sunddi.h>
4302d09e03SGordon Ross #include <sys/vnode.h>
4402d09e03SGordon Ross #include <sys/vfs.h>
4502d09e03SGordon Ross 
4602d09e03SGordon Ross #include <sys/kidmap.h>
4702d09e03SGordon Ross 
4802d09e03SGordon Ross #else	/* _KERNEL */
4902d09e03SGordon Ross 
5002d09e03SGordon Ross #include <stdio.h>
5102d09e03SGordon Ross #include <stdlib.h>
5202d09e03SGordon Ross #include <strings.h>
5302d09e03SGordon Ross 
5402d09e03SGordon Ross #include <idmap.h>
5502d09e03SGordon Ross 
5602d09e03SGordon Ross #endif	/* _KERNEL */
5702d09e03SGordon Ross 
5802d09e03SGordon Ross #include <netsmb/mchain.h>
5902d09e03SGordon Ross #include <netsmb/smb.h>
6002d09e03SGordon Ross #include "smbfs_ntacl.h"
6102d09e03SGordon Ross 
62*bd7c6f51SGordon Ross #define	NT_SD_REVISION	1
63*bd7c6f51SGordon Ross #define	NT_ACL_REVISION	2
64*bd7c6f51SGordon Ross 
6502d09e03SGordon Ross #ifdef _KERNEL
6602d09e03SGordon Ross #define	MALLOC(size) kmem_alloc(size, KM_SLEEP)
6702d09e03SGordon Ross #define	FREESZ(p, sz) kmem_free(p, sz)
6802d09e03SGordon Ross #else	/* _KERNEL */
6902d09e03SGordon Ross #define	MALLOC(size) malloc(size)
7002d09e03SGordon Ross #ifndef lint
7102d09e03SGordon Ross #define	FREESZ(p, sz) free(p)
7202d09e03SGordon Ross #else	/* lint */
7302d09e03SGordon Ross /* ARGSUSED */
7402d09e03SGordon Ross static void
7502d09e03SGordon Ross FREESZ(void *p, size_t sz)
7602d09e03SGordon Ross {
7702d09e03SGordon Ross 	free(p);
7802d09e03SGordon Ross }
7902d09e03SGordon Ross #endif	/* lint */
8002d09e03SGordon Ross #endif	/* _KERNEL */
8102d09e03SGordon Ross 
8202d09e03SGordon Ross #define	ERRCHK(expr)	if ((error = expr) != 0) goto errout
8302d09e03SGordon Ross 
8402d09e03SGordon Ross /*
8502d09e03SGordon Ross  * Security IDentifier (SID)
8602d09e03SGordon Ross  */
8702d09e03SGordon Ross static void
8802d09e03SGordon Ross ifree_sid(i_ntsid_t *sid)
8902d09e03SGordon Ross {
9002d09e03SGordon Ross 	size_t sz;
9102d09e03SGordon Ross 
9202d09e03SGordon Ross 	if (sid == NULL)
9302d09e03SGordon Ross 		return;
9402d09e03SGordon Ross 
9502d09e03SGordon Ross 	sz = I_SID_SIZE(sid->sid_subauthcount);
9602d09e03SGordon Ross 	FREESZ(sid, sz);
9702d09e03SGordon Ross }
9802d09e03SGordon Ross 
9902d09e03SGordon Ross static int
10002d09e03SGordon Ross md_get_sid(mdchain_t *mdp, i_ntsid_t **sidp)
10102d09e03SGordon Ross {
10202d09e03SGordon Ross 	i_ntsid_t *sid = NULL;
10302d09e03SGordon Ross 	uint8_t revision, subauthcount;
10402d09e03SGordon Ross 	uint32_t *subauthp;
10502d09e03SGordon Ross 	size_t sidsz;
10602d09e03SGordon Ross 	int error, i;
10702d09e03SGordon Ross 
10802d09e03SGordon Ross 	if ((error = md_get_uint8(mdp, &revision)) != 0)
10902d09e03SGordon Ross 		return (error);
11002d09e03SGordon Ross 	if ((error = md_get_uint8(mdp, &subauthcount)) != 0)
11102d09e03SGordon Ross 		return (error);
11202d09e03SGordon Ross 
11302d09e03SGordon Ross 	sidsz = I_SID_SIZE(subauthcount);
11402d09e03SGordon Ross 
11502d09e03SGordon Ross 	if ((sid = MALLOC(sidsz)) == NULL)
11602d09e03SGordon Ross 		return (ENOMEM);
11702d09e03SGordon Ross 
11802d09e03SGordon Ross 	bzero(sid, sidsz);
11902d09e03SGordon Ross 	sid->sid_revision = revision;
12002d09e03SGordon Ross 	sid->sid_subauthcount = subauthcount;
12102d09e03SGordon Ross 	ERRCHK(md_get_mem(mdp, sid->sid_authority, 6, MB_MSYSTEM));
12202d09e03SGordon Ross 
12302d09e03SGordon Ross 	subauthp = &sid->sid_subauthvec[0];
12402d09e03SGordon Ross 	for (i = 0; i < subauthcount; i++) {
12502d09e03SGordon Ross 		ERRCHK(md_get_uint32le(mdp, subauthp));
12602d09e03SGordon Ross 		subauthp++;
12702d09e03SGordon Ross 	}
12802d09e03SGordon Ross 
12902d09e03SGordon Ross 	/* Success! */
13002d09e03SGordon Ross 	*sidp = sid;
13102d09e03SGordon Ross 	return (0);
13202d09e03SGordon Ross 
13302d09e03SGordon Ross errout:
13402d09e03SGordon Ross 	ifree_sid(sid);
13502d09e03SGordon Ross 	return (error);
13602d09e03SGordon Ross }
13702d09e03SGordon Ross 
13802d09e03SGordon Ross static int
13902d09e03SGordon Ross mb_put_sid(mbchain_t *mbp, i_ntsid_t *sid)
14002d09e03SGordon Ross {
14102d09e03SGordon Ross 	uint32_t *subauthp;
14202d09e03SGordon Ross 	int error, i;
14302d09e03SGordon Ross 
14402d09e03SGordon Ross 	if (sid == NULL)
14502d09e03SGordon Ross 		return (EINVAL);
14602d09e03SGordon Ross 
14702d09e03SGordon Ross 	ERRCHK(mb_put_uint8(mbp, sid->sid_revision));
14802d09e03SGordon Ross 	ERRCHK(mb_put_uint8(mbp, sid->sid_subauthcount));
14902d09e03SGordon Ross 	ERRCHK(mb_put_mem(mbp, sid->sid_authority, 6, MB_MSYSTEM));
15002d09e03SGordon Ross 
15102d09e03SGordon Ross 	subauthp = &sid->sid_subauthvec[0];
15202d09e03SGordon Ross 	for (i = 0; i < sid->sid_subauthcount; i++) {
15302d09e03SGordon Ross 		ERRCHK(mb_put_uint32le(mbp, *subauthp));
15402d09e03SGordon Ross 		subauthp++;
15502d09e03SGordon Ross 	}
15602d09e03SGordon Ross 
15702d09e03SGordon Ross 	/* Success! */
15802d09e03SGordon Ross 	return (0);
15902d09e03SGordon Ross 
16002d09e03SGordon Ross errout:
16102d09e03SGordon Ross 	return (error);
16202d09e03SGordon Ross }
16302d09e03SGordon Ross 
16402d09e03SGordon Ross 
16502d09e03SGordon Ross /*
16602d09e03SGordon Ross  * Access Control Entry (ACE)
16702d09e03SGordon Ross  */
16802d09e03SGordon Ross static void
16902d09e03SGordon Ross ifree_ace(i_ntace_t *ace)
17002d09e03SGordon Ross {
17102d09e03SGordon Ross 
17202d09e03SGordon Ross 	if (ace == NULL)
17302d09e03SGordon Ross 		return;
17402d09e03SGordon Ross 
175*bd7c6f51SGordon Ross 	switch (ace->ace_hdr.ace_type) {
176*bd7c6f51SGordon Ross 	case ACCESS_ALLOWED_ACE_TYPE:
177*bd7c6f51SGordon Ross 	case ACCESS_DENIED_ACE_TYPE:
178*bd7c6f51SGordon Ross 	case SYSTEM_AUDIT_ACE_TYPE:
179*bd7c6f51SGordon Ross 	case SYSTEM_ALARM_ACE_TYPE:
180*bd7c6f51SGordon Ross 		ifree_sid(ace->ace_v2.ace_sid);
181*bd7c6f51SGordon Ross 		FREESZ(ace, sizeof (i_ntace_v2_t));
182*bd7c6f51SGordon Ross 		break;
183*bd7c6f51SGordon Ross 	/* other types todo */
184*bd7c6f51SGordon Ross 	default:
185*bd7c6f51SGordon Ross 		break;
186*bd7c6f51SGordon Ross 	}
18702d09e03SGordon Ross }
18802d09e03SGordon Ross 
18902d09e03SGordon Ross static int
19002d09e03SGordon Ross md_get_ace(mdchain_t *mdp, i_ntace_t **acep)
19102d09e03SGordon Ross {
19202d09e03SGordon Ross 	mdchain_t tmp_md;
193*bd7c6f51SGordon Ross 	i_ntace_hdr_t ace_hdr;
19402d09e03SGordon Ross 	i_ntace_t *ace = NULL;
195*bd7c6f51SGordon Ross 	uint16_t alloc_size;
19602d09e03SGordon Ross 	int error;
19702d09e03SGordon Ross 
19802d09e03SGordon Ross 	/*
19902d09e03SGordon Ross 	 * The ACE is realy variable length,
20002d09e03SGordon Ross 	 * with format determined by the type.
20102d09e03SGordon Ross 	 *
20202d09e03SGordon Ross 	 * There may also be padding after it, so
203*bd7c6f51SGordon Ross 	 * decode it using a copy of the mdchain,
20402d09e03SGordon Ross 	 * and then consume the specified length.
20502d09e03SGordon Ross 	 */
20602d09e03SGordon Ross 	tmp_md = *mdp;
20702d09e03SGordon Ross 
208*bd7c6f51SGordon Ross 	/* Fixed-size ACE header */
209*bd7c6f51SGordon Ross 	ERRCHK(md_get_uint8(&tmp_md, &ace_hdr.ace_type));
210*bd7c6f51SGordon Ross 	ERRCHK(md_get_uint8(&tmp_md, &ace_hdr.ace_flags));
211*bd7c6f51SGordon Ross 	ERRCHK(md_get_uint16le(&tmp_md, &ace_hdr.ace_size));
21202d09e03SGordon Ross 
213*bd7c6f51SGordon Ross 	switch (ace_hdr.ace_type) {
214*bd7c6f51SGordon Ross 	case ACCESS_ALLOWED_ACE_TYPE:
215*bd7c6f51SGordon Ross 	case ACCESS_DENIED_ACE_TYPE:
216*bd7c6f51SGordon Ross 	case SYSTEM_AUDIT_ACE_TYPE:
217*bd7c6f51SGordon Ross 	case SYSTEM_ALARM_ACE_TYPE:
218*bd7c6f51SGordon Ross 		alloc_size = sizeof (i_ntace_v2_t);
219*bd7c6f51SGordon Ross 		if ((ace = MALLOC(alloc_size)) == NULL)
220*bd7c6f51SGordon Ross 			return (ENOMEM);
221*bd7c6f51SGordon Ross 		bzero(ace, alloc_size);
222*bd7c6f51SGordon Ross 		/* ACE header */
223*bd7c6f51SGordon Ross 		ace->ace_hdr.ace_type = ace_hdr.ace_type;
224*bd7c6f51SGordon Ross 		ace->ace_hdr.ace_flags = ace_hdr.ace_flags;
225*bd7c6f51SGordon Ross 		ace->ace_hdr.ace_size = alloc_size;
226*bd7c6f51SGordon Ross 		/* Type-specific data. */
227*bd7c6f51SGordon Ross 		ERRCHK(md_get_uint32le(&tmp_md, &ace->ace_v2.ace_rights));
228*bd7c6f51SGordon Ross 		ERRCHK(md_get_sid(&tmp_md, &ace->ace_v2.ace_sid));
229*bd7c6f51SGordon Ross 		break;
23002d09e03SGordon Ross 
231*bd7c6f51SGordon Ross 	/* other types todo */
232*bd7c6f51SGordon Ross 	default:
233*bd7c6f51SGordon Ross 		error = EIO;
234*bd7c6f51SGordon Ross 		goto errout;
235*bd7c6f51SGordon Ross 	}
236*bd7c6f51SGordon Ross 
237*bd7c6f51SGordon Ross 	/* Now actually consume ace_hdr.ace_size */
238*bd7c6f51SGordon Ross 	ERRCHK(md_get_mem(mdp, NULL, ace_hdr.ace_size, MB_MSYSTEM));
23902d09e03SGordon Ross 
24002d09e03SGordon Ross 	/* Success! */
24102d09e03SGordon Ross 	*acep = ace;
24202d09e03SGordon Ross 	return (0);
24302d09e03SGordon Ross 
24402d09e03SGordon Ross errout:
24502d09e03SGordon Ross 	ifree_ace(ace);
24602d09e03SGordon Ross 	return (error);
24702d09e03SGordon Ross }
24802d09e03SGordon Ross 
24902d09e03SGordon Ross static int
25002d09e03SGordon Ross mb_put_ace(mbchain_t *mbp, i_ntace_t *ace)
25102d09e03SGordon Ross {
25202d09e03SGordon Ross 	int cnt0, error;
25302d09e03SGordon Ross 	uint16_t ace_len, *ace_len_p;
25402d09e03SGordon Ross 
25502d09e03SGordon Ross 	if (ace == NULL)
25602d09e03SGordon Ross 		return (EINVAL);
25702d09e03SGordon Ross 
25802d09e03SGordon Ross 	cnt0 = mbp->mb_count;
25902d09e03SGordon Ross 
260*bd7c6f51SGordon Ross 	/*
261*bd7c6f51SGordon Ross 	 * Put the (fixed-size) ACE header
262*bd7c6f51SGordon Ross 	 * Will fill in the length later.
263*bd7c6f51SGordon Ross 	 */
264*bd7c6f51SGordon Ross 	ERRCHK(mb_put_uint8(mbp, ace->ace_hdr.ace_type));
265*bd7c6f51SGordon Ross 	ERRCHK(mb_put_uint8(mbp, ace->ace_hdr.ace_flags));
26602d09e03SGordon Ross 	ace_len_p = mb_reserve(mbp, sizeof (*ace_len_p));
26702d09e03SGordon Ross 	if (ace_len_p == NULL) {
26802d09e03SGordon Ross 		error = ENOMEM;
26902d09e03SGordon Ross 		goto errout;
27002d09e03SGordon Ross 	}
27102d09e03SGordon Ross 
272*bd7c6f51SGordon Ross 	switch (ace->ace_hdr.ace_type) {
273*bd7c6f51SGordon Ross 	case ACCESS_ALLOWED_ACE_TYPE:
274*bd7c6f51SGordon Ross 	case ACCESS_DENIED_ACE_TYPE:
275*bd7c6f51SGordon Ross 	case SYSTEM_AUDIT_ACE_TYPE:
276*bd7c6f51SGordon Ross 	case SYSTEM_ALARM_ACE_TYPE:
277*bd7c6f51SGordon Ross 		/* Put type-specific data. */
278*bd7c6f51SGordon Ross 		ERRCHK(mb_put_uint32le(mbp, ace->ace_v2.ace_rights));
279*bd7c6f51SGordon Ross 		ERRCHK(mb_put_sid(mbp, ace->ace_v2.ace_sid));
280*bd7c6f51SGordon Ross 		break;
28102d09e03SGordon Ross 
282*bd7c6f51SGordon Ross 	/* other types todo */
283*bd7c6f51SGordon Ross 	default:
284*bd7c6f51SGordon Ross 		error = EIO;
285*bd7c6f51SGordon Ross 		goto errout;
286*bd7c6f51SGordon Ross 	}
287*bd7c6f51SGordon Ross 
288*bd7c6f51SGordon Ross 	/* Fill in the (OtW) ACE length. */
28902d09e03SGordon Ross 	ace_len = mbp->mb_count - cnt0;
29002d09e03SGordon Ross 	*ace_len_p = htoles(ace_len);
29102d09e03SGordon Ross 
29202d09e03SGordon Ross 	/* Success! */
29302d09e03SGordon Ross 	return (0);
29402d09e03SGordon Ross 
29502d09e03SGordon Ross errout:
29602d09e03SGordon Ross 	return (error);
29702d09e03SGordon Ross }
29802d09e03SGordon Ross 
29902d09e03SGordon Ross 
30002d09e03SGordon Ross /*
30102d09e03SGordon Ross  * Access Control List (ACL)
30202d09e03SGordon Ross  */
30302d09e03SGordon Ross 
30402d09e03SGordon Ross /* Not an OTW structure, so size can be at our convenience. */
30502d09e03SGordon Ross #define	I_ACL_SIZE(cnt)	(sizeof (i_ntacl_t) + (cnt) * sizeof (void *))
30602d09e03SGordon Ross 
30702d09e03SGordon Ross static void
30802d09e03SGordon Ross ifree_acl(i_ntacl_t *acl)
30902d09e03SGordon Ross {
31002d09e03SGordon Ross 	i_ntace_t **acep;
31102d09e03SGordon Ross 	size_t sz;
31202d09e03SGordon Ross 	int i;
31302d09e03SGordon Ross 
31402d09e03SGordon Ross 	if (acl == NULL)
31502d09e03SGordon Ross 		return;
31602d09e03SGordon Ross 
31702d09e03SGordon Ross 	acep = &acl->acl_acevec[0];
31802d09e03SGordon Ross 	for (i = 0; i < acl->acl_acecount; i++) {
31902d09e03SGordon Ross 		ifree_ace(*acep);
32002d09e03SGordon Ross 		acep++;
32102d09e03SGordon Ross 	}
32202d09e03SGordon Ross 	sz = I_ACL_SIZE(acl->acl_acecount);
32302d09e03SGordon Ross 	FREESZ(acl, sz);
32402d09e03SGordon Ross }
32502d09e03SGordon Ross 
32602d09e03SGordon Ross static int
32702d09e03SGordon Ross md_get_acl(mdchain_t *mdp, i_ntacl_t **aclp)
32802d09e03SGordon Ross {
32902d09e03SGordon Ross 	i_ntacl_t *acl = NULL;
33002d09e03SGordon Ross 	i_ntace_t **acep;
33102d09e03SGordon Ross 	uint8_t revision;
33202d09e03SGordon Ross 	uint16_t acl_len, acecount;
33302d09e03SGordon Ross 	size_t aclsz;
33402d09e03SGordon Ross 	int i, error;
33502d09e03SGordon Ross 
33602d09e03SGordon Ross 	if ((error = md_get_uint8(mdp, &revision)) != 0)
33702d09e03SGordon Ross 		return (error);
338*bd7c6f51SGordon Ross 	if ((error = md_get_uint8(mdp, NULL)) != 0) /* pad1 */
33902d09e03SGordon Ross 		return (error);
34002d09e03SGordon Ross 	if ((error = md_get_uint16le(mdp, &acl_len)) != 0)
34102d09e03SGordon Ross 		return (error);
34202d09e03SGordon Ross 	if ((error = md_get_uint16le(mdp, &acecount)) != 0)
34302d09e03SGordon Ross 		return (error);
344*bd7c6f51SGordon Ross 	if ((error = md_get_uint16le(mdp, NULL)) != 0) /* pad2 */
34502d09e03SGordon Ross 		return (error);
34602d09e03SGordon Ross 
34702d09e03SGordon Ross 	aclsz = I_ACL_SIZE(acecount);
34802d09e03SGordon Ross 	if ((acl = MALLOC(aclsz)) == NULL)
34902d09e03SGordon Ross 		return (ENOMEM);
35002d09e03SGordon Ross 	bzero(acl, aclsz);
35102d09e03SGordon Ross 	acl->acl_revision = revision;
35202d09e03SGordon Ross 	acl->acl_acecount = acecount;
35302d09e03SGordon Ross 
35402d09e03SGordon Ross 	acep = &acl->acl_acevec[0];
35502d09e03SGordon Ross 	for (i = 0; i < acl->acl_acecount; i++) {
35602d09e03SGordon Ross 		ERRCHK(md_get_ace(mdp, acep));
35702d09e03SGordon Ross 		acep++;
35802d09e03SGordon Ross 	}
35902d09e03SGordon Ross 	/*
36002d09e03SGordon Ross 	 * There may be more data here, but
36102d09e03SGordon Ross 	 * the caller takes care of that.
36202d09e03SGordon Ross 	 */
36302d09e03SGordon Ross 
36402d09e03SGordon Ross 	/* Success! */
36502d09e03SGordon Ross 	*aclp = acl;
36602d09e03SGordon Ross 	return (0);
36702d09e03SGordon Ross 
36802d09e03SGordon Ross errout:
36902d09e03SGordon Ross 	ifree_acl(acl);
37002d09e03SGordon Ross 	return (error);
37102d09e03SGordon Ross }
37202d09e03SGordon Ross 
37302d09e03SGordon Ross static int
37402d09e03SGordon Ross mb_put_acl(mbchain_t *mbp, i_ntacl_t *acl)
37502d09e03SGordon Ross {
37602d09e03SGordon Ross 	i_ntace_t **acep;
37702d09e03SGordon Ross 	uint16_t acl_len, *acl_len_p;
37802d09e03SGordon Ross 	int i, cnt0, error;
37902d09e03SGordon Ross 
38002d09e03SGordon Ross 	cnt0 = mbp->mb_count;
38102d09e03SGordon Ross 
38202d09e03SGordon Ross 	ERRCHK(mb_put_uint8(mbp, acl->acl_revision));
38302d09e03SGordon Ross 	ERRCHK(mb_put_uint8(mbp, 0)); /* pad1 */
38402d09e03SGordon Ross 	acl_len_p = mb_reserve(mbp, sizeof (*acl_len_p));
38502d09e03SGordon Ross 	if (acl_len_p == NULL) {
38602d09e03SGordon Ross 		error = ENOMEM;
38702d09e03SGordon Ross 		goto errout;
38802d09e03SGordon Ross 	}
38902d09e03SGordon Ross 	ERRCHK(mb_put_uint16le(mbp, acl->acl_acecount));
39002d09e03SGordon Ross 	ERRCHK(mb_put_uint16le(mbp, 0)); /* pad2 */
39102d09e03SGordon Ross 
39202d09e03SGordon Ross 	acep = &acl->acl_acevec[0];
39302d09e03SGordon Ross 	for (i = 0; i < acl->acl_acecount; i++) {
39402d09e03SGordon Ross 		ERRCHK(mb_put_ace(mbp, *acep));
39502d09e03SGordon Ross 		acep++;
39602d09e03SGordon Ross 	}
39702d09e03SGordon Ross 
39802d09e03SGordon Ross 	/* Fill in acl_len_p */
39902d09e03SGordon Ross 	acl_len = mbp->mb_count - cnt0;
40002d09e03SGordon Ross 	*acl_len_p = htoles(acl_len);
40102d09e03SGordon Ross 
40202d09e03SGordon Ross 	/* Success! */
40302d09e03SGordon Ross 	return (0);
40402d09e03SGordon Ross 
40502d09e03SGordon Ross errout:
40602d09e03SGordon Ross 	return (error);
40702d09e03SGordon Ross }
40802d09e03SGordon Ross 
40902d09e03SGordon Ross 
41002d09e03SGordon Ross /*
41102d09e03SGordon Ross  * Security Descriptor
41202d09e03SGordon Ross  */
41302d09e03SGordon Ross void
41402d09e03SGordon Ross smbfs_acl_free_sd(i_ntsd_t *sd)
41502d09e03SGordon Ross {
41602d09e03SGordon Ross 
41702d09e03SGordon Ross 	if (sd == NULL)
41802d09e03SGordon Ross 		return;
41902d09e03SGordon Ross 
42002d09e03SGordon Ross 	ifree_sid(sd->sd_owner);
42102d09e03SGordon Ross 	ifree_sid(sd->sd_group);
42202d09e03SGordon Ross 	ifree_acl(sd->sd_sacl);
42302d09e03SGordon Ross 	ifree_acl(sd->sd_dacl);
42402d09e03SGordon Ross 
42502d09e03SGordon Ross 	FREESZ(sd, sizeof (*sd));
42602d09e03SGordon Ross }
42702d09e03SGordon Ross 
42802d09e03SGordon Ross /*
42902d09e03SGordon Ross  * Import a raw SD (mb chain) into "internal" form.
43002d09e03SGordon Ross  * (like "absolute" form per. NT docs)
43102d09e03SGordon Ross  * Returns allocated data in sdp
43202d09e03SGordon Ross  *
43302d09e03SGordon Ross  * Note: does NOT consume all the mdp data, so the
43402d09e03SGordon Ross  * caller has to take care of that if necessary.
43502d09e03SGordon Ross  */
43602d09e03SGordon Ross int
43702d09e03SGordon Ross md_get_ntsd(mdchain_t *mdp, i_ntsd_t **sdp)
43802d09e03SGordon Ross {
43902d09e03SGordon Ross 	i_ntsd_t *sd = NULL;
44002d09e03SGordon Ross 	mdchain_t top_md, tmp_md;
44102d09e03SGordon Ross 	uint32_t owneroff, groupoff, sacloff, dacloff;
44202d09e03SGordon Ross 	int error;
44302d09e03SGordon Ross 
44402d09e03SGordon Ross 	if ((sd = MALLOC(sizeof (*sd))) == NULL)
44502d09e03SGordon Ross 		return (ENOMEM);
44602d09e03SGordon Ross 	bzero(sd, sizeof (*sd));
44702d09e03SGordon Ross 
44802d09e03SGordon Ross 	/*
44902d09e03SGordon Ross 	 * Offsets below are relative to this point,
45002d09e03SGordon Ross 	 * so save the mdp state for use below.
45102d09e03SGordon Ross 	 */
45202d09e03SGordon Ross 	top_md = *mdp;
45302d09e03SGordon Ross 
45402d09e03SGordon Ross 	ERRCHK(md_get_uint8(mdp, &sd->sd_revision));
45502d09e03SGordon Ross 	ERRCHK(md_get_uint8(mdp, &sd->sd_rmctl));
45602d09e03SGordon Ross 	ERRCHK(md_get_uint16le(mdp, &sd->sd_flags));
45702d09e03SGordon Ross 	ERRCHK(md_get_uint32le(mdp, &owneroff));
45802d09e03SGordon Ross 	ERRCHK(md_get_uint32le(mdp, &groupoff));
45902d09e03SGordon Ross 	ERRCHK(md_get_uint32le(mdp, &sacloff));
46002d09e03SGordon Ross 	ERRCHK(md_get_uint32le(mdp, &dacloff));
46102d09e03SGordon Ross 
46202d09e03SGordon Ross 	/*
463*bd7c6f51SGordon Ross 	 * The SD is "self-relative" on the wire,
464*bd7c6f51SGordon Ross 	 * but not after this decodes it.
465*bd7c6f51SGordon Ross 	 */
466*bd7c6f51SGordon Ross 	sd->sd_flags &= ~SD_SELF_RELATIVE;
467*bd7c6f51SGordon Ross 
468*bd7c6f51SGordon Ross 	/*
46902d09e03SGordon Ross 	 * For each section make a temporary copy of the
47002d09e03SGordon Ross 	 * top_md state, advance to the given offset, and
47102d09e03SGordon Ross 	 * pass that to the lower md_get_xxx functions.
47202d09e03SGordon Ross 	 * These could be marshalled in any order, but
47302d09e03SGordon Ross 	 * are normally found in the order shown here.
47402d09e03SGordon Ross 	 */
47502d09e03SGordon Ross 	if (sacloff) {
47602d09e03SGordon Ross 		tmp_md = top_md;
47702d09e03SGordon Ross 		md_get_mem(&tmp_md, NULL, sacloff, MB_MSYSTEM);
47802d09e03SGordon Ross 		ERRCHK(md_get_acl(&tmp_md, &sd->sd_sacl));
47902d09e03SGordon Ross 	}
48002d09e03SGordon Ross 	if (dacloff) {
48102d09e03SGordon Ross 		tmp_md = top_md;
48202d09e03SGordon Ross 		md_get_mem(&tmp_md, NULL, dacloff, MB_MSYSTEM);
48302d09e03SGordon Ross 		ERRCHK(md_get_acl(&tmp_md, &sd->sd_dacl));
48402d09e03SGordon Ross 	}
48502d09e03SGordon Ross 	if (owneroff) {
48602d09e03SGordon Ross 		tmp_md = top_md;
48702d09e03SGordon Ross 		md_get_mem(&tmp_md, NULL, owneroff, MB_MSYSTEM);
48802d09e03SGordon Ross 		ERRCHK(md_get_sid(&tmp_md, &sd->sd_owner));
48902d09e03SGordon Ross 	}
49002d09e03SGordon Ross 	if (groupoff) {
49102d09e03SGordon Ross 		tmp_md = top_md;
49202d09e03SGordon Ross 		md_get_mem(&tmp_md, NULL, groupoff, MB_MSYSTEM);
49302d09e03SGordon Ross 		ERRCHK(md_get_sid(&tmp_md, &sd->sd_group));
49402d09e03SGordon Ross 	}
49502d09e03SGordon Ross 
49602d09e03SGordon Ross 	/* Success! */
49702d09e03SGordon Ross 	*sdp = sd;
49802d09e03SGordon Ross 	return (0);
49902d09e03SGordon Ross 
50002d09e03SGordon Ross errout:
50102d09e03SGordon Ross 	smbfs_acl_free_sd(sd);
50202d09e03SGordon Ross 	return (error);
50302d09e03SGordon Ross }
50402d09e03SGordon Ross 
50502d09e03SGordon Ross /*
50602d09e03SGordon Ross  * Export an "internal" SD into an raw SD (mb chain).
50702d09e03SGordon Ross  * (a.k.a "self-relative" form per. NT docs)
50802d09e03SGordon Ross  * Returns allocated mbchain in mbp.
50902d09e03SGordon Ross  */
51002d09e03SGordon Ross int
51102d09e03SGordon Ross mb_put_ntsd(mbchain_t *mbp, i_ntsd_t *sd)
51202d09e03SGordon Ross {
51302d09e03SGordon Ross 	uint32_t *owneroffp, *groupoffp, *sacloffp, *dacloffp;
51402d09e03SGordon Ross 	uint32_t owneroff, groupoff, sacloff, dacloff;
515*bd7c6f51SGordon Ross 	uint16_t flags;
51602d09e03SGordon Ross 	int cnt0, error;
51702d09e03SGordon Ross 
51802d09e03SGordon Ross 	cnt0 = mbp->mb_count;
51902d09e03SGordon Ross 	owneroff = groupoff = sacloff = dacloff = 0;
52002d09e03SGordon Ross 
521*bd7c6f51SGordon Ross 	/* The SD is "self-relative" on the wire. */
522*bd7c6f51SGordon Ross 	flags = sd->sd_flags | SD_SELF_RELATIVE;
523*bd7c6f51SGordon Ross 
52402d09e03SGordon Ross 	ERRCHK(mb_put_uint8(mbp, sd->sd_revision));
52502d09e03SGordon Ross 	ERRCHK(mb_put_uint8(mbp, sd->sd_rmctl));
526*bd7c6f51SGordon Ross 	ERRCHK(mb_put_uint16le(mbp, flags));
52702d09e03SGordon Ross 
52802d09e03SGordon Ross 	owneroffp = mb_reserve(mbp, sizeof (*owneroffp));
52902d09e03SGordon Ross 	groupoffp = mb_reserve(mbp, sizeof (*groupoffp));
53002d09e03SGordon Ross 	sacloffp  = mb_reserve(mbp, sizeof (*sacloffp));
53102d09e03SGordon Ross 	dacloffp  = mb_reserve(mbp, sizeof (*dacloffp));
53202d09e03SGordon Ross 	if (owneroffp == NULL || groupoffp == NULL ||
53302d09e03SGordon Ross 	    sacloffp == NULL || dacloffp == NULL) {
53402d09e03SGordon Ross 		error = ENOMEM;
53502d09e03SGordon Ross 		goto errout;
53602d09e03SGordon Ross 	}
53702d09e03SGordon Ross 
53802d09e03SGordon Ross 	/*
53902d09e03SGordon Ross 	 * These could be marshalled in any order, but
54002d09e03SGordon Ross 	 * are normally found in the order shown here.
54102d09e03SGordon Ross 	 */
54202d09e03SGordon Ross 	if (sd->sd_sacl) {
54302d09e03SGordon Ross 		sacloff = mbp->mb_count - cnt0;
54402d09e03SGordon Ross 		ERRCHK(mb_put_acl(mbp, sd->sd_sacl));
54502d09e03SGordon Ross 	}
54602d09e03SGordon Ross 	if (sd->sd_dacl) {
54702d09e03SGordon Ross 		dacloff = mbp->mb_count - cnt0;
54802d09e03SGordon Ross 		ERRCHK(mb_put_acl(mbp, sd->sd_dacl));
54902d09e03SGordon Ross 	}
55002d09e03SGordon Ross 	if (sd->sd_owner) {
55102d09e03SGordon Ross 		owneroff = mbp->mb_count - cnt0;
55202d09e03SGordon Ross 		ERRCHK(mb_put_sid(mbp, sd->sd_owner));
55302d09e03SGordon Ross 	}
55402d09e03SGordon Ross 	if (sd->sd_group) {
55502d09e03SGordon Ross 		groupoff = mbp->mb_count - cnt0;
55602d09e03SGordon Ross 		ERRCHK(mb_put_sid(mbp, sd->sd_group));
55702d09e03SGordon Ross 	}
55802d09e03SGordon Ross 
55902d09e03SGordon Ross 	/* Fill in the offsets */
56002d09e03SGordon Ross 	*owneroffp = htolel(owneroff);
56102d09e03SGordon Ross 	*groupoffp = htolel(groupoff);
56202d09e03SGordon Ross 	*sacloffp  = htolel(sacloff);
56302d09e03SGordon Ross 	*dacloffp  = htolel(dacloff);
56402d09e03SGordon Ross 
56502d09e03SGordon Ross 	/* Success! */
56602d09e03SGordon Ross 	return (0);
56702d09e03SGordon Ross 
56802d09e03SGordon Ross errout:
56902d09e03SGordon Ross 	return (error);
57002d09e03SGordon Ross }
57102d09e03SGordon Ross 
57202d09e03SGordon Ross /*
573*bd7c6f51SGordon Ross  * ================================================================
574*bd7c6f51SGordon Ross  * Support for ACL fetch, including conversions
575*bd7c6f51SGordon Ross  * from Windows ACLs to NFSv4-style ACLs.
576*bd7c6f51SGordon Ross  * ================================================================
57702d09e03SGordon Ross  */
57802d09e03SGordon Ross 
579*bd7c6f51SGordon Ross #define	GENERIC_RIGHTS_MASK \
580*bd7c6f51SGordon Ross 	(GENERIC_RIGHT_READ_ACCESS | GENERIC_RIGHT_WRITE_ACCESS |\
581*bd7c6f51SGordon Ross 	GENERIC_RIGHT_EXECUTE_ACCESS | GENERIC_RIGHT_ALL_ACCESS)
582*bd7c6f51SGordon Ross 
583*bd7c6f51SGordon Ross /*
584*bd7c6f51SGordon Ross  * Table for converting NT GENERIC_RIGHT_... to specific rights
585*bd7c6f51SGordon Ross  * appropriate for objects of type file.
586*bd7c6f51SGordon Ross  */
587*bd7c6f51SGordon Ross struct gen2fsr {
588*bd7c6f51SGordon Ross 	uint32_t	gf_generic;
589*bd7c6f51SGordon Ross 	uint32_t	gf_specific;
590*bd7c6f51SGordon Ross };
591*bd7c6f51SGordon Ross static const struct gen2fsr
592*bd7c6f51SGordon Ross smbfs_gen2fsr[] = {
593*bd7c6f51SGordon Ross 	{
594*bd7c6f51SGordon Ross 		GENERIC_RIGHT_READ_ACCESS,
595*bd7c6f51SGordon Ross 		STD_RIGHT_SYNCHRONIZE_ACCESS |
596*bd7c6f51SGordon Ross 		STD_RIGHT_READ_CONTROL_ACCESS |
597*bd7c6f51SGordon Ross 		SA_RIGHT_FILE_READ_ATTRIBUTES |
598*bd7c6f51SGordon Ross 		SA_RIGHT_FILE_READ_EA |
599*bd7c6f51SGordon Ross 		SA_RIGHT_FILE_READ_DATA },
600*bd7c6f51SGordon Ross 	{
601*bd7c6f51SGordon Ross 		GENERIC_RIGHT_WRITE_ACCESS,
602*bd7c6f51SGordon Ross 		STD_RIGHT_SYNCHRONIZE_ACCESS |
603*bd7c6f51SGordon Ross 		STD_RIGHT_READ_CONTROL_ACCESS |
604*bd7c6f51SGordon Ross 		SA_RIGHT_FILE_WRITE_ATTRIBUTES |
605*bd7c6f51SGordon Ross 		SA_RIGHT_FILE_WRITE_EA |
606*bd7c6f51SGordon Ross 		SA_RIGHT_FILE_APPEND_DATA |
607*bd7c6f51SGordon Ross 		SA_RIGHT_FILE_WRITE_DATA },
608*bd7c6f51SGordon Ross 	{
609*bd7c6f51SGordon Ross 		GENERIC_RIGHT_EXECUTE_ACCESS,
610*bd7c6f51SGordon Ross 		STD_RIGHT_SYNCHRONIZE_ACCESS |
611*bd7c6f51SGordon Ross 		STD_RIGHT_READ_CONTROL_ACCESS |
612*bd7c6f51SGordon Ross 		SA_RIGHT_FILE_READ_ATTRIBUTES |
613*bd7c6f51SGordon Ross 		SA_RIGHT_FILE_EXECUTE },
614*bd7c6f51SGordon Ross 	{
615*bd7c6f51SGordon Ross 		GENERIC_RIGHT_ALL_ACCESS,
616*bd7c6f51SGordon Ross 		STD_RIGHT_SYNCHRONIZE_ACCESS |
617*bd7c6f51SGordon Ross 		STD_RIGHT_WRITE_OWNER_ACCESS |
618*bd7c6f51SGordon Ross 		STD_RIGHT_WRITE_DAC_ACCESS |
619*bd7c6f51SGordon Ross 		STD_RIGHT_READ_CONTROL_ACCESS |
620*bd7c6f51SGordon Ross 		STD_RIGHT_DELETE_ACCESS |
621*bd7c6f51SGordon Ross 		SA_RIGHT_FILE_ALL_ACCESS },
622*bd7c6f51SGordon Ross 	{ 0, 0 }
623*bd7c6f51SGordon Ross };
624*bd7c6f51SGordon Ross 
625*bd7c6f51SGordon Ross /*
626*bd7c6f51SGordon Ross  * Table for translating ZFS ACE flags to NT ACE flags.
627*bd7c6f51SGordon Ross  * The low four bits are the same, but not others.
628*bd7c6f51SGordon Ross  */
629*bd7c6f51SGordon Ross struct zaf2naf {
630*bd7c6f51SGordon Ross 	uint16_t	za_flag;
631*bd7c6f51SGordon Ross 	uint8_t		na_flag;
632*bd7c6f51SGordon Ross };
633*bd7c6f51SGordon Ross static const struct zaf2naf
634*bd7c6f51SGordon Ross smbfs_zaf2naf[] = {
635*bd7c6f51SGordon Ross 	{ ACE_FILE_INHERIT_ACE,		OBJECT_INHERIT_ACE_FLAG },
636*bd7c6f51SGordon Ross 	{ ACE_DIRECTORY_INHERIT_ACE,	CONTAINER_INHERIT_ACE_FLAG },
637*bd7c6f51SGordon Ross 	{ ACE_NO_PROPAGATE_INHERIT_ACE,	NO_PROPAGATE_INHERIT_ACE_FLAG },
638*bd7c6f51SGordon Ross 	{ ACE_INHERIT_ONLY_ACE,		INHERIT_ONLY_ACE_FLAG },
639*bd7c6f51SGordon Ross 	{ ACE_INHERITED_ACE,		INHERITED_ACE_FLAG },
640*bd7c6f51SGordon Ross 	{ ACE_SUCCESSFUL_ACCESS_ACE_FLAG, SUCCESSFUL_ACCESS_ACE_FLAG },
641*bd7c6f51SGordon Ross 	{ ACE_FAILED_ACCESS_ACE_FLAG,	FAILED_ACCESS_ACE_FLAG },
642*bd7c6f51SGordon Ross 	{ 0, 0 }
643*bd7c6f51SGordon Ross };
64402d09e03SGordon Ross 
64502d09e03SGordon Ross /*
64602d09e03SGordon Ross  * Convert an NT SID to a string. Optionally return the
64702d09e03SGordon Ross  * last sub-authority (or "relative ID" -- RID) in *ridp
64802d09e03SGordon Ross  * and truncate the output string after the domain part.
64902d09e03SGordon Ross  * If ridp==NULL, the output string is the whole SID,
65002d09e03SGordon Ross  * including both the domain and RID.
65102d09e03SGordon Ross  *
65202d09e03SGordon Ross  * Return length written, or -1 on error.
65302d09e03SGordon Ross  */
65402d09e03SGordon Ross int
65502d09e03SGordon Ross smbfs_sid2str(i_ntsid_t *sid,
65602d09e03SGordon Ross 	char *obuf, size_t osz, uint32_t *ridp)
65702d09e03SGordon Ross {
65802d09e03SGordon Ross 	char *s = obuf;
65902d09e03SGordon Ross 	uint64_t auth = 0;
66002d09e03SGordon Ross 	uint_t i, n;
66102d09e03SGordon Ross 	uint32_t subs, *ip;
66202d09e03SGordon Ross 
66302d09e03SGordon Ross 	n = snprintf(s, osz, "S-%u", sid->sid_revision);
66402d09e03SGordon Ross 	if (n > osz)
66502d09e03SGordon Ross 		return (-1);
66602d09e03SGordon Ross 	s += n; osz -= n;
66702d09e03SGordon Ross 
66802d09e03SGordon Ross 	for (i = 0; i < 6; i++)
66902d09e03SGordon Ross 		auth = (auth << 8) | sid->sid_authority[i];
67002d09e03SGordon Ross 	n = snprintf(s, osz, "-%llu", (u_longlong_t)auth);
67102d09e03SGordon Ross 	if (n > osz)
67202d09e03SGordon Ross 		return (-1);
67302d09e03SGordon Ross 	s += n; osz -= n;
67402d09e03SGordon Ross 
67502d09e03SGordon Ross 	subs = sid->sid_subauthcount;
67602d09e03SGordon Ross 	if (subs < 1 || subs > 15)
67702d09e03SGordon Ross 		return (-1);
67802d09e03SGordon Ross 	if (ridp)
67902d09e03SGordon Ross 		subs--;
68002d09e03SGordon Ross 
68102d09e03SGordon Ross 	ip = &sid->sid_subauthvec[0];
68202d09e03SGordon Ross 	for (; subs; subs--, ip++) {
68302d09e03SGordon Ross 		n = snprintf(s, osz, "-%u", *ip);
68402d09e03SGordon Ross 		if (n > osz)
68502d09e03SGordon Ross 			return (-1);
68602d09e03SGordon Ross 		s += n; osz -= n;
68702d09e03SGordon Ross 	}
68802d09e03SGordon Ross 	if (ridp)
68902d09e03SGordon Ross 		*ridp = *ip;
69002d09e03SGordon Ross 
69102d09e03SGordon Ross 	/* LINTED E_PTRDIFF_OVERFLOW */
69202d09e03SGordon Ross 	return (s - obuf);
69302d09e03SGordon Ross }
69402d09e03SGordon Ross 
69502d09e03SGordon Ross /*
69602d09e03SGordon Ross  * Our interface to the idmap service.
69702d09e03SGordon Ross  *
69802d09e03SGordon Ross  * The idmap API is _almost_ the same between
69902d09e03SGordon Ross  * kernel and user-level.  But not quite...
70002d09e03SGordon Ross  * Hope this improves readability below.
70102d09e03SGordon Ross  */
70202d09e03SGordon Ross #ifdef	_KERNEL
70302d09e03SGordon Ross 
704*bd7c6f51SGordon Ross #define	I_getuidbysid(GH, SPP, RID, UIDP, SP) \
705*bd7c6f51SGordon Ross 	kidmap_batch_getuidbysid(GH, SPP, RID, UIDP, SP)
706*bd7c6f51SGordon Ross 
707*bd7c6f51SGordon Ross #define	I_getgidbysid(GH, SPP, RID, GIDP, SP) \
708*bd7c6f51SGordon Ross 	kidmap_batch_getgidbysid(GH, SPP, RID, GIDP, SP)
709*bd7c6f51SGordon Ross 
710*bd7c6f51SGordon Ross #define	I_getpidbysid(GH, SPP, RID, PIDP, ISUP, SP) \
71102d09e03SGordon Ross 	kidmap_batch_getpidbysid(GH, SPP, RID, PIDP, ISUP, SP)
712*bd7c6f51SGordon Ross 
713*bd7c6f51SGordon Ross #define	I_getmappings kidmap_get_mappings
71402d09e03SGordon Ross 
71502d09e03SGordon Ross #else /* _KERNEL */
71602d09e03SGordon Ross 
717*bd7c6f51SGordon Ross #define	I_getuidbysid(GH, SPP, RID, UIDP, SP) \
718*bd7c6f51SGordon Ross 	idmap_get_uidbysid(GH, SPP, RID, 0, UIDP, SP)
719*bd7c6f51SGordon Ross 
720*bd7c6f51SGordon Ross #define	I_getgidbysid(GH, SPP, RID, GIDP, SP) \
721*bd7c6f51SGordon Ross 	idmap_get_gidbysid(GH, SPP, RID, 0, GIDP, SP)
722*bd7c6f51SGordon Ross 
723*bd7c6f51SGordon Ross #define	I_getpidbysid(GH, SPP, RID, PIDP, ISUP, SP) \
72402d09e03SGordon Ross 	idmap_get_pidbysid(GH, SPP, RID, 0, PIDP, ISUP, SP)
725*bd7c6f51SGordon Ross 
726*bd7c6f51SGordon Ross #define	I_getmappings idmap_get_mappings
72702d09e03SGordon Ross 
72802d09e03SGordon Ross #endif /* _KERNEL */
72902d09e03SGordon Ross 
73002d09e03SGordon Ross 
73102d09e03SGordon Ross /*
732*bd7c6f51SGordon Ross  * The idmap request types, chosen so they also
733*bd7c6f51SGordon Ross  * match the values returned in mi_isuser.
734*bd7c6f51SGordon Ross  */
735*bd7c6f51SGordon Ross #define	IDM_TYPE_ANY	-1
736*bd7c6f51SGordon Ross #define	IDM_TYPE_GROUP	0
737*bd7c6f51SGordon Ross #define	IDM_TYPE_USER	1
738*bd7c6f51SGordon Ross 
739*bd7c6f51SGordon Ross /*
740*bd7c6f51SGordon Ross  * A sentinel value for mi_isuser (below) to indicate
74102d09e03SGordon Ross  * that the SID is the well-known "Everyone" (S-1-1-0).
74202d09e03SGordon Ross  * The idmap library only uses -1, 0, 1, so this value
74302d09e03SGordon Ross  * is arbitrary but must not overlap w/ idmap values.
74402d09e03SGordon Ross  * XXX: Could use a way for idmap to tell us when
74502d09e03SGordon Ross  * it recognizes this well-known SID.
74602d09e03SGordon Ross  */
747*bd7c6f51SGordon Ross #define	IDM_EVERYONE	11
748*bd7c6f51SGordon Ross 
749*bd7c6f51SGordon Ross struct mapinfo2uid {
750*bd7c6f51SGordon Ross 	uid_t	mi_uid; /* or gid, or pid */
751*bd7c6f51SGordon Ross 	int	mi_isuser; /* IDM_TYPE */
752*bd7c6f51SGordon Ross 	idmap_stat mi_status;
753*bd7c6f51SGordon Ross };
75402d09e03SGordon Ross 
75502d09e03SGordon Ross /*
75602d09e03SGordon Ross  * Build an idmap request.  Cleanup is
75702d09e03SGordon Ross  * handled by the caller (error or not)
75802d09e03SGordon Ross  */
75902d09e03SGordon Ross static int
76002d09e03SGordon Ross mkrq_idmap_sid2ux(
76102d09e03SGordon Ross 	idmap_get_handle_t *idmap_gh,
762*bd7c6f51SGordon Ross 	struct mapinfo2uid *mip,
76302d09e03SGordon Ross 	i_ntsid_t *sid,
764*bd7c6f51SGordon Ross 	int req_type)
76502d09e03SGordon Ross {
766*bd7c6f51SGordon Ross 	char strbuf[256];
767*bd7c6f51SGordon Ross 	char *sid_prefix;
76802d09e03SGordon Ross 	uint32_t	rid;
76902d09e03SGordon Ross 	idmap_stat	idms;
77002d09e03SGordon Ross 
771*bd7c6f51SGordon Ross 	if (smbfs_sid2str(sid, strbuf, sizeof (strbuf), &rid) < 0)
77202d09e03SGordon Ross 		return (EINVAL);
773*bd7c6f51SGordon Ross 	sid_prefix = strbuf;
77402d09e03SGordon Ross 
77502d09e03SGordon Ross 	/*
77602d09e03SGordon Ross 	 * Give the "Everyone" group special treatment.
77702d09e03SGordon Ross 	 */
77802d09e03SGordon Ross 	if (strcmp(sid_prefix, "S-1-1") == 0 && rid == 0) {
77902d09e03SGordon Ross 		/* This is "Everyone" */
78002d09e03SGordon Ross 		mip->mi_uid = (uid_t)-1;
781*bd7c6f51SGordon Ross 		mip->mi_isuser = IDM_EVERYONE;
78202d09e03SGordon Ross 		mip->mi_status = 0;
78302d09e03SGordon Ross 		return (0);
78402d09e03SGordon Ross 	}
78502d09e03SGordon Ross 
786*bd7c6f51SGordon Ross 	switch (req_type) {
787*bd7c6f51SGordon Ross 
788*bd7c6f51SGordon Ross 	case IDM_TYPE_USER:
789*bd7c6f51SGordon Ross 		mip->mi_isuser = req_type;
790*bd7c6f51SGordon Ross 		idms = I_getuidbysid(idmap_gh, sid_prefix, rid,
791*bd7c6f51SGordon Ross 		    &mip->mi_uid, &mip->mi_status);
792*bd7c6f51SGordon Ross 		break;
793*bd7c6f51SGordon Ross 
794*bd7c6f51SGordon Ross 	case IDM_TYPE_GROUP:
795*bd7c6f51SGordon Ross 		mip->mi_isuser = req_type;
796*bd7c6f51SGordon Ross 		idms = I_getgidbysid(idmap_gh, sid_prefix, rid,
797*bd7c6f51SGordon Ross 		    &mip->mi_uid, &mip->mi_status);
798*bd7c6f51SGordon Ross 		break;
799*bd7c6f51SGordon Ross 
800*bd7c6f51SGordon Ross 	case IDM_TYPE_ANY:
801*bd7c6f51SGordon Ross 		idms = I_getpidbysid(idmap_gh, sid_prefix, rid,
80202d09e03SGordon Ross 		    &mip->mi_uid, &mip->mi_isuser, &mip->mi_status);
803*bd7c6f51SGordon Ross 		break;
804*bd7c6f51SGordon Ross 
805*bd7c6f51SGordon Ross 	default:
806*bd7c6f51SGordon Ross 		idms = IDMAP_ERR_OTHER;
807*bd7c6f51SGordon Ross 		break;
808*bd7c6f51SGordon Ross 	}
809*bd7c6f51SGordon Ross 
81002d09e03SGordon Ross 	if (idms != IDMAP_SUCCESS)
81102d09e03SGordon Ross 		return (EINVAL);
81202d09e03SGordon Ross 
81302d09e03SGordon Ross 	return (0);
81402d09e03SGordon Ross }
81502d09e03SGordon Ross 
816*bd7c6f51SGordon Ross /*
817*bd7c6f51SGordon Ross  * Convert an NT ACE to a ZFS ACE.
818*bd7c6f51SGordon Ross  * ACE type was already validated.
819*bd7c6f51SGordon Ross  */
82002d09e03SGordon Ross static void
821*bd7c6f51SGordon Ross ntace2zace(ace_t *zacep, i_ntace_t *ntace, struct mapinfo2uid *mip)
82202d09e03SGordon Ross {
823*bd7c6f51SGordon Ross 	const struct zaf2naf *znaf;
824*bd7c6f51SGordon Ross 	uid_t zwho;
82502d09e03SGordon Ross 	uint32_t zamask;
826*bd7c6f51SGordon Ross 	uint16_t zflags;
82702d09e03SGordon Ross 
82802d09e03SGordon Ross 	/*
829*bd7c6f51SGordon Ross 	 * Set the "ID type" flags in the ZFS ace flags.
83002d09e03SGordon Ross 	 */
83102d09e03SGordon Ross 	zflags = 0;
83202d09e03SGordon Ross 	switch (mip->mi_isuser) {
833*bd7c6f51SGordon Ross 	case IDM_EVERYONE:
834*bd7c6f51SGordon Ross 		zflags = ACE_EVERYONE;
835*bd7c6f51SGordon Ross 		zwho = (uid_t)-1;
83602d09e03SGordon Ross 		break;
837*bd7c6f51SGordon Ross 
838*bd7c6f51SGordon Ross 	case IDM_TYPE_GROUP: /* it's a GID */
839*bd7c6f51SGordon Ross 		zflags = ACE_IDENTIFIER_GROUP;
840*bd7c6f51SGordon Ross 		zwho = mip->mi_uid;
84102d09e03SGordon Ross 		break;
842*bd7c6f51SGordon Ross 
84302d09e03SGordon Ross 	default:
844*bd7c6f51SGordon Ross 	case IDM_TYPE_USER: /* it's a UID */
845*bd7c6f51SGordon Ross 		zflags = 0;
846*bd7c6f51SGordon Ross 		zwho = mip->mi_uid;
84702d09e03SGordon Ross 		break;
84802d09e03SGordon Ross 	}
84902d09e03SGordon Ross 
85002d09e03SGordon Ross 	/*
851*bd7c6f51SGordon Ross 	 * Translate NT ACE flags to ZFS ACE flags.
85202d09e03SGordon Ross 	 */
853*bd7c6f51SGordon Ross 	for (znaf = smbfs_zaf2naf; znaf->za_flag; znaf++)
854*bd7c6f51SGordon Ross 		if (ntace->ace_hdr.ace_flags & znaf->na_flag)
855*bd7c6f51SGordon Ross 			zflags |= znaf->za_flag;
85602d09e03SGordon Ross 
85702d09e03SGordon Ross 	/*
858*bd7c6f51SGordon Ross 	 * The "normal" access mask bits are the same, but
859*bd7c6f51SGordon Ross 	 * if the ACE has any GENERIC_RIGHT_... convert those
860*bd7c6f51SGordon Ross 	 * to specific rights.  GENERIC bits are rarely seen,
861*bd7c6f51SGordon Ross 	 * but reportedly can happen with inherit-only ACEs.
86202d09e03SGordon Ross 	 */
863*bd7c6f51SGordon Ross 	zamask = ntace->ace_v2.ace_rights & ACE_ALL_PERMS;
864*bd7c6f51SGordon Ross 	if (ntace->ace_v2.ace_rights & GENERIC_RIGHTS_MASK) {
865*bd7c6f51SGordon Ross 		const struct gen2fsr *gf;
866*bd7c6f51SGordon Ross 		for (gf = smbfs_gen2fsr; gf->gf_generic; gf++)
867*bd7c6f51SGordon Ross 			if (ntace->ace_v2.ace_rights & gf->gf_generic)
868*bd7c6f51SGordon Ross 				zamask |= gf->gf_specific;
86902d09e03SGordon Ross 	}
87002d09e03SGordon Ross 
87102d09e03SGordon Ross 	/*
87202d09e03SGordon Ross 	 * Fill in the ZFS-style ACE
87302d09e03SGordon Ross 	 */
874*bd7c6f51SGordon Ross 	zacep->a_who = zwho;
87502d09e03SGordon Ross 	zacep->a_access_mask = zamask;
87602d09e03SGordon Ross 	zacep->a_flags = zflags;
877*bd7c6f51SGordon Ross 	zacep->a_type = ntace->ace_hdr.ace_type;
87802d09e03SGordon Ross }
87902d09e03SGordon Ross 
88002d09e03SGordon Ross /*
88102d09e03SGordon Ross  * Convert an internal SD to a ZFS-style ACL.
88202d09e03SGordon Ross  * Note optional args: vsa/acl, uidp, gidp.
883*bd7c6f51SGordon Ross  *
884*bd7c6f51SGordon Ross  * This makes two passes over the SD, the first building a
885*bd7c6f51SGordon Ross  * "batch" request for idmap with results in mapinfo, the
886*bd7c6f51SGordon Ross  * second building a ZFS-style ACL using the idmap results.
88702d09e03SGordon Ross  */
88802d09e03SGordon Ross int
88902d09e03SGordon Ross smbfs_acl_sd2zfs(
89002d09e03SGordon Ross 	i_ntsd_t *sd,
89102d09e03SGordon Ross #ifdef	_KERNEL
89202d09e03SGordon Ross 	vsecattr_t *acl_info,
89302d09e03SGordon Ross #else /* _KERNEL */
89402d09e03SGordon Ross 	acl_t *acl_info,
89502d09e03SGordon Ross #endif /* _KERNEL */
89602d09e03SGordon Ross 	uid_t *uidp, gid_t *gidp)
89702d09e03SGordon Ross {
898*bd7c6f51SGordon Ross 	struct mapinfo2uid *mip, *mapinfo = NULL;
89902d09e03SGordon Ross 	int error, i, mapcnt, zacecnt, zacl_size;
900*bd7c6f51SGordon Ross 	ace_t *zacep0, *zacep;
901*bd7c6f51SGordon Ross 	uid_t own_uid = (uid_t)-1;
902*bd7c6f51SGordon Ross 	gid_t own_gid = (gid_t)-1;
90302d09e03SGordon Ross 	i_ntacl_t *ntacl;
90402d09e03SGordon Ross 	i_ntace_t **ntacep;
90502d09e03SGordon Ross #ifndef	_KERNEL
90602d09e03SGordon Ross 	idmap_handle_t *idmap_h = NULL;
90702d09e03SGordon Ross #endif /* _KERNEL */
90802d09e03SGordon Ross 	idmap_get_handle_t *idmap_gh = NULL;
90902d09e03SGordon Ross 	idmap_stat	idms;
91002d09e03SGordon Ross 
91102d09e03SGordon Ross 	/*
91202d09e03SGordon Ross 	 * sanity checks
91302d09e03SGordon Ross 	 */
91402d09e03SGordon Ross 	if (acl_info) {
915*bd7c6f51SGordon Ross #ifndef	_KERNEL
91602d09e03SGordon Ross 		if (acl_info->acl_type != ACE_T ||
91702d09e03SGordon Ross 		    acl_info->acl_aclp != NULL ||
91802d09e03SGordon Ross 		    acl_info->acl_entry_size != sizeof (ace_t))
91902d09e03SGordon Ross 			return (EINVAL);
92002d09e03SGordon Ross #endif /* _KERNEL */
921*bd7c6f51SGordon Ross 		if ((sd->sd_flags & SD_DACL_PRESENT) == 0)
922*bd7c6f51SGordon Ross 			return (EINVAL);
923*bd7c6f51SGordon Ross 	}
92402d09e03SGordon Ross 
92502d09e03SGordon Ross 	/*
926*bd7c6f51SGordon Ross 	 * How many SID mappings will we need?
92702d09e03SGordon Ross 	 */
92802d09e03SGordon Ross 	mapcnt = 0;
92902d09e03SGordon Ross 	if (sd->sd_owner)
93002d09e03SGordon Ross 		mapcnt++;
93102d09e03SGordon Ross 	if (sd->sd_group)
93202d09e03SGordon Ross 		mapcnt++;
933*bd7c6f51SGordon Ross 	if ((sd->sd_flags & SD_SACL_PRESENT) &&
934*bd7c6f51SGordon Ross 	    (sd->sd_sacl != NULL))
93502d09e03SGordon Ross 		mapcnt += sd->sd_sacl->acl_acecount;
936*bd7c6f51SGordon Ross 	if ((sd->sd_flags & SD_DACL_PRESENT) &&
937*bd7c6f51SGordon Ross 	    (sd->sd_dacl != NULL))
93802d09e03SGordon Ross 		mapcnt += sd->sd_dacl->acl_acecount;
939*bd7c6f51SGordon Ross 	if (mapcnt == 0) {
940*bd7c6f51SGordon Ross 		/*
941*bd7c6f51SGordon Ross 		 * We have a NULL DACL, SACL, and don't
942*bd7c6f51SGordon Ross 		 * have an owner or group, so there's no
943*bd7c6f51SGordon Ross 		 * idmap work to do.  This is very rare,
944*bd7c6f51SGordon Ross 		 * so rather than complicate things below,
945*bd7c6f51SGordon Ross 		 * pretend we need one mapping slot.
946*bd7c6f51SGordon Ross 		 */
947*bd7c6f51SGordon Ross 		mapcnt = 1;
948*bd7c6f51SGordon Ross 	}
94902d09e03SGordon Ross 
95002d09e03SGordon Ross 	mapinfo = MALLOC(mapcnt * sizeof (*mapinfo));
95102d09e03SGordon Ross 	if (mapinfo == NULL) {
95202d09e03SGordon Ross 		error = ENOMEM;
95302d09e03SGordon Ross 		goto errout;
95402d09e03SGordon Ross 	}
95502d09e03SGordon Ross 	bzero(mapinfo, mapcnt * sizeof (*mapinfo));
95602d09e03SGordon Ross 
95702d09e03SGordon Ross 
95802d09e03SGordon Ross 	/*
959*bd7c6f51SGordon Ross 	 * Get an imap "batch" request handle.
96002d09e03SGordon Ross 	 */
96102d09e03SGordon Ross #ifdef	_KERNEL
96202d09e03SGordon Ross 	idmap_gh = kidmap_get_create(curproc->p_zone);
96302d09e03SGordon Ross #else /* _KERNEL */
96402d09e03SGordon Ross 	idms = idmap_init(&idmap_h);
96502d09e03SGordon Ross 	if (idms != IDMAP_SUCCESS) {
96602d09e03SGordon Ross 		error = ENOTACTIVE;
96702d09e03SGordon Ross 		goto errout;
96802d09e03SGordon Ross 	}
96902d09e03SGordon Ross 	idms = idmap_get_create(idmap_h, &idmap_gh);
97002d09e03SGordon Ross 	if (idms != IDMAP_SUCCESS) {
97102d09e03SGordon Ross 		error = ENOTACTIVE;
97202d09e03SGordon Ross 		goto errout;
97302d09e03SGordon Ross 	}
97402d09e03SGordon Ross #endif /* _KERNEL */
97502d09e03SGordon Ross 
976*bd7c6f51SGordon Ross 	/*
977*bd7c6f51SGordon Ross 	 * Build our request to the idmap deamon,
978*bd7c6f51SGordon Ross 	 * getting Unix IDs for every SID.
979*bd7c6f51SGordon Ross 	 */
98002d09e03SGordon Ross 	mip = mapinfo;
98102d09e03SGordon Ross 	if (sd->sd_owner) {
982*bd7c6f51SGordon Ross 		error = mkrq_idmap_sid2ux(idmap_gh, mip,
983*bd7c6f51SGordon Ross 		    sd->sd_owner, IDM_TYPE_USER);
98402d09e03SGordon Ross 		if (error)
98502d09e03SGordon Ross 			goto errout;
98602d09e03SGordon Ross 		mip++;
98702d09e03SGordon Ross 	}
98802d09e03SGordon Ross 	if (sd->sd_group) {
989*bd7c6f51SGordon Ross 		error = mkrq_idmap_sid2ux(idmap_gh, mip,
990*bd7c6f51SGordon Ross 		    sd->sd_group, IDM_TYPE_GROUP);
99102d09e03SGordon Ross 		if (error)
99202d09e03SGordon Ross 			goto errout;
99302d09e03SGordon Ross 		mip++;
99402d09e03SGordon Ross 	}
995*bd7c6f51SGordon Ross 	if ((sd->sd_flags & SD_SACL_PRESENT) &&
996*bd7c6f51SGordon Ross 	    (sd->sd_sacl != NULL)) {
99702d09e03SGordon Ross 		ntacl = sd->sd_sacl;
99802d09e03SGordon Ross 		ntacep = &ntacl->acl_acevec[0];
99902d09e03SGordon Ross 		for (i = 0; i < ntacl->acl_acecount; i++) {
1000*bd7c6f51SGordon Ross 			error = mkrq_idmap_sid2ux(idmap_gh, mip,
1001*bd7c6f51SGordon Ross 			    (*ntacep)->ace_v2.ace_sid, IDM_TYPE_ANY);
100202d09e03SGordon Ross 			if (error)
100302d09e03SGordon Ross 				goto errout;
100402d09e03SGordon Ross 			ntacep++;
100502d09e03SGordon Ross 			mip++;
100602d09e03SGordon Ross 		}
100702d09e03SGordon Ross 	}
1008*bd7c6f51SGordon Ross 	if ((sd->sd_flags & SD_DACL_PRESENT) &&
1009*bd7c6f51SGordon Ross 	    (sd->sd_dacl != NULL)) {
101002d09e03SGordon Ross 		ntacl = sd->sd_dacl;
101102d09e03SGordon Ross 		ntacep = &ntacl->acl_acevec[0];
101202d09e03SGordon Ross 		for (i = 0; i < ntacl->acl_acecount; i++) {
1013*bd7c6f51SGordon Ross 			error = mkrq_idmap_sid2ux(idmap_gh, mip,
1014*bd7c6f51SGordon Ross 			    (*ntacep)->ace_v2.ace_sid, IDM_TYPE_ANY);
101502d09e03SGordon Ross 			if (error)
101602d09e03SGordon Ross 				goto errout;
101702d09e03SGordon Ross 			ntacep++;
101802d09e03SGordon Ross 			mip++;
101902d09e03SGordon Ross 		}
102002d09e03SGordon Ross 	}
102102d09e03SGordon Ross 
1022*bd7c6f51SGordon Ross 	if (mip != mapinfo) {
1023*bd7c6f51SGordon Ross 		idms = I_getmappings(idmap_gh);
102402d09e03SGordon Ross 		if (idms != IDMAP_SUCCESS) {
102502d09e03SGordon Ross 			/* creative error choice */
102602d09e03SGordon Ross 			error = EIDRM;
102702d09e03SGordon Ross 			goto errout;
102802d09e03SGordon Ross 		}
1029*bd7c6f51SGordon Ross 	}
103002d09e03SGordon Ross 
103102d09e03SGordon Ross 	/*
103202d09e03SGordon Ross 	 * With any luck, we now have Unix user/group IDs
103302d09e03SGordon Ross 	 * for every Windows SID in the security descriptor.
103402d09e03SGordon Ross 	 * The remaining work is just format conversion.
103502d09e03SGordon Ross 	 */
103602d09e03SGordon Ross 	mip = mapinfo;
103702d09e03SGordon Ross 	if (sd->sd_owner) {
1038*bd7c6f51SGordon Ross 		own_uid = mip->mi_uid;
103902d09e03SGordon Ross 		mip++;
104002d09e03SGordon Ross 	}
104102d09e03SGordon Ross 	if (sd->sd_group) {
1042*bd7c6f51SGordon Ross 		own_gid = mip->mi_uid;
104302d09e03SGordon Ross 		mip++;
104402d09e03SGordon Ross 	}
104502d09e03SGordon Ross 
1046*bd7c6f51SGordon Ross 	if (uidp)
1047*bd7c6f51SGordon Ross 		*uidp = own_uid;
1048*bd7c6f51SGordon Ross 	if (gidp)
1049*bd7c6f51SGordon Ross 		*gidp = own_gid;
1050*bd7c6f51SGordon Ross 
105102d09e03SGordon Ross 	if (acl_info == NULL) {
105202d09e03SGordon Ross 		/* Caller only wanted uid/gid */
1053*bd7c6f51SGordon Ross 		goto done;
105402d09e03SGordon Ross 	}
105502d09e03SGordon Ross 
105602d09e03SGordon Ross 	/*
105702d09e03SGordon Ross 	 * Build the ZFS-style ACL
1058*bd7c6f51SGordon Ross 	 * First, allocate the most ZFS ACEs we'll need.
105902d09e03SGordon Ross 	 */
106002d09e03SGordon Ross 	zacecnt = 0;
1061*bd7c6f51SGordon Ross 	if ((sd->sd_flags & SD_SACL_PRESENT) &&
1062*bd7c6f51SGordon Ross 	    (sd->sd_sacl != NULL))
106302d09e03SGordon Ross 		zacecnt += sd->sd_sacl->acl_acecount;
1064*bd7c6f51SGordon Ross 
1065*bd7c6f51SGordon Ross 	/* NB, have: (sd->sd_flags & SD_DACL_PRESENT) */
1066*bd7c6f51SGordon Ross 	if ((sd->sd_dacl != NULL) &&
1067*bd7c6f51SGordon Ross 	    (sd->sd_dacl->acl_acecount > 0)) {
106802d09e03SGordon Ross 		zacecnt += sd->sd_dacl->acl_acecount;
1069*bd7c6f51SGordon Ross 	} else {
1070*bd7c6f51SGordon Ross 		/*
1071*bd7c6f51SGordon Ross 		 * DACL is NULL or empty. Either way,
1072*bd7c6f51SGordon Ross 		 * we'll need to add a ZFS ACE below.
1073*bd7c6f51SGordon Ross 		 */
1074*bd7c6f51SGordon Ross 		zacecnt++;
1075*bd7c6f51SGordon Ross 	}
107602d09e03SGordon Ross 	zacl_size = zacecnt * sizeof (ace_t);
1077*bd7c6f51SGordon Ross 	zacep0 = MALLOC(zacl_size);
1078*bd7c6f51SGordon Ross 	if (zacep0 == NULL) {
107902d09e03SGordon Ross 		error = ENOMEM;
108002d09e03SGordon Ross 		goto errout;
108102d09e03SGordon Ross 	}
1082*bd7c6f51SGordon Ross 	zacep = zacep0;
108302d09e03SGordon Ross 
1084*bd7c6f51SGordon Ross 	if ((sd->sd_flags & SD_SACL_PRESENT) &&
1085*bd7c6f51SGordon Ross 	    (sd->sd_sacl != NULL)) {
108602d09e03SGordon Ross 		ntacl = sd->sd_sacl;
108702d09e03SGordon Ross 		ntacep = &ntacl->acl_acevec[0];
108802d09e03SGordon Ross 		for (i = 0; i < ntacl->acl_acecount; i++) {
108902d09e03SGordon Ross 			ntace2zace(zacep, *ntacep, mip);
109002d09e03SGordon Ross 			zacep++;
109102d09e03SGordon Ross 			ntacep++;
109202d09e03SGordon Ross 			mip++;
109302d09e03SGordon Ross 		}
109402d09e03SGordon Ross 	}
1095*bd7c6f51SGordon Ross 
1096*bd7c6f51SGordon Ross 	/* NB, have: (sd->sd_flags & SD_DACL_PRESENT) */
1097*bd7c6f51SGordon Ross 	if (sd->sd_dacl != NULL) {
109802d09e03SGordon Ross 		ntacl = sd->sd_dacl;
109902d09e03SGordon Ross 		ntacep = &ntacl->acl_acevec[0];
110002d09e03SGordon Ross 		for (i = 0; i < ntacl->acl_acecount; i++) {
110102d09e03SGordon Ross 			ntace2zace(zacep, *ntacep, mip);
110202d09e03SGordon Ross 			zacep++;
110302d09e03SGordon Ross 			ntacep++;
110402d09e03SGordon Ross 			mip++;
110502d09e03SGordon Ross 		}
110602d09e03SGordon Ross 	}
1107*bd7c6f51SGordon Ross 	if (sd->sd_dacl == NULL) {
1108*bd7c6f51SGordon Ross 		/*
1109*bd7c6f51SGordon Ross 		 * The SD has a NULL DACL.  That means
1110*bd7c6f51SGordon Ross 		 * everyone@, full-control
1111*bd7c6f51SGordon Ross 		 */
1112*bd7c6f51SGordon Ross 		zacep->a_who = (uid_t)-1;
1113*bd7c6f51SGordon Ross 		zacep->a_access_mask = ACE_ALL_PERMS;
1114*bd7c6f51SGordon Ross 		zacep->a_flags = ACE_EVERYONE;
1115*bd7c6f51SGordon Ross 		zacep->a_type = ACCESS_ALLOWED_ACE_TYPE;
1116*bd7c6f51SGordon Ross 	} else if (sd->sd_dacl->acl_acecount == 0) {
1117*bd7c6f51SGordon Ross 		/*
1118*bd7c6f51SGordon Ross 		 * The SD has an Empty DACL.  We need
1119*bd7c6f51SGordon Ross 		 * at least one ACE, so add one giving
1120*bd7c6f51SGordon Ross 		 * the owner the usual implied access.
1121*bd7c6f51SGordon Ross 		 */
1122*bd7c6f51SGordon Ross 		zacep->a_who = (uid_t)-1;
1123*bd7c6f51SGordon Ross 		zacep->a_access_mask = ACE_READ_ATTRIBUTES | \
1124*bd7c6f51SGordon Ross 		    ACE_READ_ACL | ACE_WRITE_ACL;
1125*bd7c6f51SGordon Ross 		zacep->a_flags = ACE_OWNER;
1126*bd7c6f51SGordon Ross 		zacep->a_type = ACCESS_ALLOWED_ACE_TYPE;
1127*bd7c6f51SGordon Ross 	}
112802d09e03SGordon Ross 
1129*bd7c6f51SGordon Ross #ifdef _KERNEL
1130*bd7c6f51SGordon Ross 	acl_info->vsa_aclcnt = zacecnt;
1131*bd7c6f51SGordon Ross 	acl_info->vsa_aclentp = zacep0;
1132*bd7c6f51SGordon Ross 	acl_info->vsa_aclentsz = zacl_size;
1133*bd7c6f51SGordon Ross #else	/* _KERNEL */
1134*bd7c6f51SGordon Ross 	acl_info->acl_cnt = zacecnt;
1135*bd7c6f51SGordon Ross 	acl_info->acl_aclp = zacep0;
1136*bd7c6f51SGordon Ross #endif	/* _KERNEL */
1137*bd7c6f51SGordon Ross 
1138*bd7c6f51SGordon Ross done:
113902d09e03SGordon Ross 	error = 0;
114002d09e03SGordon Ross 
114102d09e03SGordon Ross errout:
1142*bd7c6f51SGordon Ross 	if (mapinfo != NULL)
114302d09e03SGordon Ross 		FREESZ(mapinfo, mapcnt * sizeof (*mapinfo));
1144*bd7c6f51SGordon Ross #ifdef	_KERNEL
1145*bd7c6f51SGordon Ross 	if (idmap_gh != NULL)
1146*bd7c6f51SGordon Ross 		kidmap_get_destroy(idmap_gh);
1147*bd7c6f51SGordon Ross #else /* _KERNEL */
1148*bd7c6f51SGordon Ross 	if (idmap_gh != NULL)
1149*bd7c6f51SGordon Ross 		idmap_get_destroy(idmap_gh);
1150*bd7c6f51SGordon Ross 	if (idmap_h != NULL)
1151*bd7c6f51SGordon Ross 		(void) idmap_fini(idmap_h);
1152*bd7c6f51SGordon Ross #endif /* _KERNEL */
115302d09e03SGordon Ross 
115402d09e03SGordon Ross 	return (error);
115502d09e03SGordon Ross }
115602d09e03SGordon Ross 
115702d09e03SGordon Ross 
115802d09e03SGordon Ross /*
1159*bd7c6f51SGordon Ross  * ================================================================
1160*bd7c6f51SGordon Ross  * Support for ACL store, including conversions
1161*bd7c6f51SGordon Ross  * from NFSv4-style ACLs to Windows ACLs.
1162*bd7c6f51SGordon Ross  * ================================================================
116302d09e03SGordon Ross  */
1164*bd7c6f51SGordon Ross 
1165*bd7c6f51SGordon Ross /*
1166*bd7c6f51SGordon Ross  * Convert a "sid-prefix" string plus RID into an NT SID.
1167*bd7c6f51SGordon Ross  *
1168*bd7c6f51SGordon Ross  * If successful, sets *osid and returns zero,
1169*bd7c6f51SGordon Ross  * otherwise returns an errno value.
1170*bd7c6f51SGordon Ross  */
1171*bd7c6f51SGordon Ross int
1172*bd7c6f51SGordon Ross smbfs_str2sid(const char *sid_prefix, uint32_t *ridp, i_ntsid_t **osidp)
1173*bd7c6f51SGordon Ross {
1174*bd7c6f51SGordon Ross 	i_ntsid_t *sid = NULL;
1175*bd7c6f51SGordon Ross 	u_longlong_t auth = 0;
1176*bd7c6f51SGordon Ross 	ulong_t sa;
1177*bd7c6f51SGordon Ross 	uint8_t sacnt;
1178*bd7c6f51SGordon Ross 	const char *p;
1179*bd7c6f51SGordon Ross 	char *np;
1180*bd7c6f51SGordon Ross 	size_t size;
1181*bd7c6f51SGordon Ross 	int i;
1182*bd7c6f51SGordon Ross 	int err;
1183*bd7c6f51SGordon Ross 
1184*bd7c6f51SGordon Ross 	if (sid_prefix == NULL)
1185*bd7c6f51SGordon Ross 		return (EINVAL);
1186*bd7c6f51SGordon Ross 
1187*bd7c6f51SGordon Ross 	p = sid_prefix;
1188*bd7c6f51SGordon Ross 	if (strncmp(p, "S-1-", 4) != 0)
1189*bd7c6f51SGordon Ross 		return (EINVAL);
1190*bd7c6f51SGordon Ross 	p += 4;
1191*bd7c6f51SGordon Ross 
1192*bd7c6f51SGordon Ross 	/* Parse the "authority" */
119302d09e03SGordon Ross #ifdef	_KERNEL
1194*bd7c6f51SGordon Ross 	err = ddi_strtoull(p, &np, 10, &auth);
1195*bd7c6f51SGordon Ross 	if (err != 0)
1196*bd7c6f51SGordon Ross 		return (err);
119702d09e03SGordon Ross #else	/* _KERNEL */
1198*bd7c6f51SGordon Ross 	auth = strtoull(p, &np, 10);
1199*bd7c6f51SGordon Ross 	if (p == np)
1200*bd7c6f51SGordon Ross 		return (EINVAL);
120102d09e03SGordon Ross #endif	/* _KERNEL */
1202*bd7c6f51SGordon Ross 
1203*bd7c6f51SGordon Ross 	/*
1204*bd7c6f51SGordon Ross 	 * Count the sub-authorities.  Here, np points to
1205*bd7c6f51SGordon Ross 	 * the "-" before the first sub-authority.
1206*bd7c6f51SGordon Ross 	 */
1207*bd7c6f51SGordon Ross 	sacnt = 0;
1208*bd7c6f51SGordon Ross 	for (p = np; *p; p++) {
1209*bd7c6f51SGordon Ross 		if (*p == '-')
1210*bd7c6f51SGordon Ross 			sacnt++;
1211*bd7c6f51SGordon Ross 	}
1212*bd7c6f51SGordon Ross 	if (ridp != NULL)
1213*bd7c6f51SGordon Ross 		sacnt++;
1214*bd7c6f51SGordon Ross 
1215*bd7c6f51SGordon Ross 	/* Allocate the internal SID. */
1216*bd7c6f51SGordon Ross 	size = I_SID_SIZE(sacnt);
1217*bd7c6f51SGordon Ross 	sid = MALLOC(size);
1218*bd7c6f51SGordon Ross 	if (sid == NULL)
1219*bd7c6f51SGordon Ross 		return (ENOMEM);
1220*bd7c6f51SGordon Ross 	bzero(sid, size);
1221*bd7c6f51SGordon Ross 
1222*bd7c6f51SGordon Ross 	/* Fill it in. */
1223*bd7c6f51SGordon Ross 	sid->sid_revision = 1;
1224*bd7c6f51SGordon Ross 	sid->sid_subauthcount = sacnt;
1225*bd7c6f51SGordon Ross 	for (i = 5; i >= 0; i--) {
1226*bd7c6f51SGordon Ross 		sid->sid_authority[i] = auth & 0xFF;
1227*bd7c6f51SGordon Ross 		auth = auth >> 8;
1228*bd7c6f51SGordon Ross 	}
1229*bd7c6f51SGordon Ross 
1230*bd7c6f51SGordon Ross 	err = EINVAL;
1231*bd7c6f51SGordon Ross 	if (ridp != NULL)
1232*bd7c6f51SGordon Ross 		sacnt--; /* Last SA not from string */
1233*bd7c6f51SGordon Ross 	p = np;
1234*bd7c6f51SGordon Ross 	for (i = 0; i < sacnt; i++) {
1235*bd7c6f51SGordon Ross 		if (*p != '-') {
1236*bd7c6f51SGordon Ross 			err = EINVAL;
1237*bd7c6f51SGordon Ross 			goto out;
1238*bd7c6f51SGordon Ross 		}
1239*bd7c6f51SGordon Ross 		p++;
1240*bd7c6f51SGordon Ross #ifdef	_KERNEL
1241*bd7c6f51SGordon Ross 		err = ddi_strtoul(p, &np, 10, &sa);
1242*bd7c6f51SGordon Ross 		if (err != 0)
1243*bd7c6f51SGordon Ross 			goto out;
1244*bd7c6f51SGordon Ross #else	/* _KERNEL */
1245*bd7c6f51SGordon Ross 		sa = strtoul(p, &np, 10);
1246*bd7c6f51SGordon Ross 		if (p == np) {
1247*bd7c6f51SGordon Ross 			err = EINVAL;
1248*bd7c6f51SGordon Ross 			goto out;
1249*bd7c6f51SGordon Ross 		}
1250*bd7c6f51SGordon Ross #endif	/* _KERNEL */
1251*bd7c6f51SGordon Ross 		sid->sid_subauthvec[i] = (uint32_t)sa;
1252*bd7c6f51SGordon Ross 		p = np;
1253*bd7c6f51SGordon Ross 	}
1254*bd7c6f51SGordon Ross 	if (*p != '\0')
1255*bd7c6f51SGordon Ross 		goto out;
1256*bd7c6f51SGordon Ross 	if (ridp != NULL)
1257*bd7c6f51SGordon Ross 		sid->sid_subauthvec[i] = *ridp;
1258*bd7c6f51SGordon Ross 	err = 0;
1259*bd7c6f51SGordon Ross 
1260*bd7c6f51SGordon Ross out:
1261*bd7c6f51SGordon Ross 	if (err)
1262*bd7c6f51SGordon Ross 		FREESZ(sid, size);
1263*bd7c6f51SGordon Ross 	else
1264*bd7c6f51SGordon Ross 		*osidp = sid;
1265*bd7c6f51SGordon Ross 
1266*bd7c6f51SGordon Ross 	return (err);
1267*bd7c6f51SGordon Ross }
1268*bd7c6f51SGordon Ross 
1269*bd7c6f51SGordon Ross /*
1270*bd7c6f51SGordon Ross  * The idmap API is _almost_ the same between
1271*bd7c6f51SGordon Ross  * kernel and user-level.  But not quite...
1272*bd7c6f51SGordon Ross  * Hope this improves readability below.
1273*bd7c6f51SGordon Ross  */
1274*bd7c6f51SGordon Ross #ifdef	_KERNEL
1275*bd7c6f51SGordon Ross 
1276*bd7c6f51SGordon Ross #define	I_getsidbyuid(GH, UID, SPP, RP, ST) \
1277*bd7c6f51SGordon Ross 	kidmap_batch_getsidbyuid(GH, UID, SPP, RP, ST)
1278*bd7c6f51SGordon Ross 
1279*bd7c6f51SGordon Ross #define	I_getsidbygid(GH, GID, SPP, RP, ST) \
1280*bd7c6f51SGordon Ross 	kidmap_batch_getsidbygid(GH, GID, SPP, RP, ST)
1281*bd7c6f51SGordon Ross 
1282*bd7c6f51SGordon Ross #else /* _KERNEL */
1283*bd7c6f51SGordon Ross 
1284*bd7c6f51SGordon Ross #define	I_getsidbyuid(GH, UID, SPP, RP, ST) \
1285*bd7c6f51SGordon Ross 	idmap_get_sidbyuid(GH, UID, 0, SPP, RP, ST)
1286*bd7c6f51SGordon Ross 
1287*bd7c6f51SGordon Ross #define	I_getsidbygid(GH, GID, SPP, RP, ST) \
1288*bd7c6f51SGordon Ross 	idmap_get_sidbygid(GH, GID, 0, SPP, RP, ST)
1289*bd7c6f51SGordon Ross 
1290*bd7c6f51SGordon Ross #endif /* _KERNEL */
1291*bd7c6f51SGordon Ross 
1292*bd7c6f51SGordon Ross struct mapinfo2sid {
1293*bd7c6f51SGordon Ross 	/* Yet another kernel vs. user difference. */
1294*bd7c6f51SGordon Ross #ifdef	_KERNEL
1295*bd7c6f51SGordon Ross 	const char *mi_dsid;	/* domain SID */
1296*bd7c6f51SGordon Ross #else /* _KERNEL */
1297*bd7c6f51SGordon Ross 	char *mi_dsid;
1298*bd7c6f51SGordon Ross #endif /* _KERNEL */
1299*bd7c6f51SGordon Ross 	uint32_t mi_rid;	/* relative ID */
1300*bd7c6f51SGordon Ross 	idmap_stat mi_status;
1301*bd7c6f51SGordon Ross };
1302*bd7c6f51SGordon Ross 
1303*bd7c6f51SGordon Ross /*
1304*bd7c6f51SGordon Ross  * Build an idmap request.  Cleanup is
1305*bd7c6f51SGordon Ross  * handled by the caller (error or not)
1306*bd7c6f51SGordon Ross  */
1307*bd7c6f51SGordon Ross static int
1308*bd7c6f51SGordon Ross mkrq_idmap_ux2sid(
1309*bd7c6f51SGordon Ross 	idmap_get_handle_t *idmap_gh,
1310*bd7c6f51SGordon Ross 	struct mapinfo2sid *mip,
1311*bd7c6f51SGordon Ross 	uid_t	uid, /* or gid */
1312*bd7c6f51SGordon Ross 	int req_type)
1313*bd7c6f51SGordon Ross {
1314*bd7c6f51SGordon Ross 	idmap_stat	idms;
1315*bd7c6f51SGordon Ross 
1316*bd7c6f51SGordon Ross 	switch (req_type) {
1317*bd7c6f51SGordon Ross 
1318*bd7c6f51SGordon Ross 	case IDM_TYPE_USER:
1319*bd7c6f51SGordon Ross 		if (uid == (uid_t)-1)
1320*bd7c6f51SGordon Ross 			return (EINVAL);
1321*bd7c6f51SGordon Ross 		idms = I_getsidbyuid(idmap_gh, uid,
1322*bd7c6f51SGordon Ross 		    &mip->mi_dsid, &mip->mi_rid, &mip->mi_status);
1323*bd7c6f51SGordon Ross 		break;
1324*bd7c6f51SGordon Ross 
1325*bd7c6f51SGordon Ross 	case IDM_TYPE_GROUP:
1326*bd7c6f51SGordon Ross 		if (uid == (uid_t)-1)
1327*bd7c6f51SGordon Ross 			return (EINVAL);
1328*bd7c6f51SGordon Ross 		idms = I_getsidbygid(idmap_gh, uid,
1329*bd7c6f51SGordon Ross 		    &mip->mi_dsid, &mip->mi_rid, &mip->mi_status);
1330*bd7c6f51SGordon Ross 		break;
1331*bd7c6f51SGordon Ross 
1332*bd7c6f51SGordon Ross 	case IDM_EVERYONE:
1333*bd7c6f51SGordon Ross 		mip->mi_dsid = "S-1-1";
1334*bd7c6f51SGordon Ross 		mip->mi_rid = 0;
1335*bd7c6f51SGordon Ross 		mip->mi_status = 0;
1336*bd7c6f51SGordon Ross 		idms = IDMAP_SUCCESS;
1337*bd7c6f51SGordon Ross 		break;
1338*bd7c6f51SGordon Ross 
1339*bd7c6f51SGordon Ross 	default:
1340*bd7c6f51SGordon Ross 		idms = IDMAP_ERR_OTHER;
1341*bd7c6f51SGordon Ross 		break;
1342*bd7c6f51SGordon Ross 	}
1343*bd7c6f51SGordon Ross 
1344*bd7c6f51SGordon Ross 	if (idms != IDMAP_SUCCESS)
1345*bd7c6f51SGordon Ross 		return (EINVAL);
1346*bd7c6f51SGordon Ross 
1347*bd7c6f51SGordon Ross 	return (0);
1348*bd7c6f51SGordon Ross }
1349*bd7c6f51SGordon Ross 
1350*bd7c6f51SGordon Ross /*
1351*bd7c6f51SGordon Ross  * Convert a ZFS ACE to an NT ACE.
1352*bd7c6f51SGordon Ross  * ACE type was already validated.
1353*bd7c6f51SGordon Ross  */
1354*bd7c6f51SGordon Ross static int
1355*bd7c6f51SGordon Ross zace2ntace(i_ntace_t **ntacep, ace_t *zacep, struct mapinfo2sid *mip)
1356*bd7c6f51SGordon Ross {
1357*bd7c6f51SGordon Ross 	const struct zaf2naf *znaf;
1358*bd7c6f51SGordon Ross 	uint8_t aflags;
1359*bd7c6f51SGordon Ross 	uint16_t alloc_size;
1360*bd7c6f51SGordon Ross 	uint32_t rights;
1361*bd7c6f51SGordon Ross 	i_ntace_t *ntace = NULL;
1362*bd7c6f51SGordon Ross 	i_ntsid_t *sid = NULL;
1363*bd7c6f51SGordon Ross 	int error;
1364*bd7c6f51SGordon Ross 
1365*bd7c6f51SGordon Ross 	if (mip->mi_dsid == NULL || mip->mi_status != 0) {
1366*bd7c6f51SGordon Ross 		return (EINVAL);
1367*bd7c6f51SGordon Ross 	}
1368*bd7c6f51SGordon Ross 
1369*bd7c6f51SGordon Ross 	/*
1370*bd7c6f51SGordon Ross 	 * Translate ZFS ACE flags to NT ACE flags.
1371*bd7c6f51SGordon Ross 	 */
1372*bd7c6f51SGordon Ross 	aflags = 0;
1373*bd7c6f51SGordon Ross 	for (znaf = smbfs_zaf2naf; znaf->za_flag; znaf++)
1374*bd7c6f51SGordon Ross 		if (zacep->a_flags & znaf->za_flag)
1375*bd7c6f51SGordon Ross 			aflags |= znaf->na_flag;
1376*bd7c6f51SGordon Ross 
1377*bd7c6f51SGordon Ross 	/*
1378*bd7c6f51SGordon Ross 	 * The access rights bits are OK as-is.
1379*bd7c6f51SGordon Ross 	 */
1380*bd7c6f51SGordon Ross 	rights = zacep->a_access_mask;
1381*bd7c6f51SGordon Ross 
1382*bd7c6f51SGordon Ross 	/*
1383*bd7c6f51SGordon Ross 	 * Make sure we can get the SID.
1384*bd7c6f51SGordon Ross 	 * Note: allocates sid.
1385*bd7c6f51SGordon Ross 	 */
1386*bd7c6f51SGordon Ross 	error = smbfs_str2sid(mip->mi_dsid, &mip->mi_rid, &sid);
1387*bd7c6f51SGordon Ross 	if (error)
1388*bd7c6f51SGordon Ross 		return (error);
1389*bd7c6f51SGordon Ross 
1390*bd7c6f51SGordon Ross 	/*
1391*bd7c6f51SGordon Ross 	 * Allocate the NT ACE and fill it in.
1392*bd7c6f51SGordon Ross 	 */
1393*bd7c6f51SGordon Ross 	alloc_size = sizeof (i_ntace_v2_t);
1394*bd7c6f51SGordon Ross 	if ((ntace = MALLOC(alloc_size)) == NULL) {
1395*bd7c6f51SGordon Ross 		ifree_sid(sid);
1396*bd7c6f51SGordon Ross 		return (ENOMEM);
1397*bd7c6f51SGordon Ross 	}
1398*bd7c6f51SGordon Ross 	bzero(ntace, alloc_size);
1399*bd7c6f51SGordon Ross 
1400*bd7c6f51SGordon Ross 	ntace->ace_hdr.ace_type = zacep->a_type;
1401*bd7c6f51SGordon Ross 	ntace->ace_hdr.ace_flags = aflags;
1402*bd7c6f51SGordon Ross 	ntace->ace_hdr.ace_size = alloc_size;
1403*bd7c6f51SGordon Ross 	ntace->ace_v2.ace_rights = rights;
1404*bd7c6f51SGordon Ross 	ntace->ace_v2.ace_sid = sid;
1405*bd7c6f51SGordon Ross 
1406*bd7c6f51SGordon Ross 	*ntacep = ntace;
1407*bd7c6f51SGordon Ross 	return (0);
1408*bd7c6f51SGordon Ross }
1409*bd7c6f51SGordon Ross 
1410*bd7c6f51SGordon Ross /*
1411*bd7c6f51SGordon Ross  * Convert a ZFS-style ACL to an internal SD.
1412*bd7c6f51SGordon Ross  * Set owner/group too if selector indicates.
1413*bd7c6f51SGordon Ross  * Always need to pass uid+gid, either the new
1414*bd7c6f51SGordon Ross  * (when setting them) or existing, so that any
1415*bd7c6f51SGordon Ross  * owner@ or group@ ACEs can be translated.
1416*bd7c6f51SGordon Ross  *
1417*bd7c6f51SGordon Ross  * This makes two passes over the ZFS ACL.  The first builds a
1418*bd7c6f51SGordon Ross  * "batch" request for idmap with results in mapinfo, and the
1419*bd7c6f51SGordon Ross  * second builds the NT SD using the idmap SID results.
1420*bd7c6f51SGordon Ross  */
1421*bd7c6f51SGordon Ross int
1422*bd7c6f51SGordon Ross smbfs_acl_zfs2sd(
1423*bd7c6f51SGordon Ross #ifdef	_KERNEL
1424*bd7c6f51SGordon Ross 	vsecattr_t *acl_info,
1425*bd7c6f51SGordon Ross #else /* _KERNEL */
1426*bd7c6f51SGordon Ross 	acl_t *acl_info,
1427*bd7c6f51SGordon Ross #endif /* _KERNEL */
1428*bd7c6f51SGordon Ross 	uid_t own_uid,
1429*bd7c6f51SGordon Ross 	gid_t own_gid,
1430*bd7c6f51SGordon Ross 	uint32_t selector,
143102d09e03SGordon Ross 	i_ntsd_t **sdp)
143202d09e03SGordon Ross {
1433*bd7c6f51SGordon Ross 	struct mapinfo2sid *mip, *mip_acl, *mapinfo = NULL;
1434*bd7c6f51SGordon Ross 	int aclsz, error, i, mapcnt;
1435*bd7c6f51SGordon Ross 	int dacl_acecnt = 0;
1436*bd7c6f51SGordon Ross 	int sacl_acecnt = 0;
1437*bd7c6f51SGordon Ross 	int zacecnt = 0;
1438*bd7c6f51SGordon Ross 	ace_t *zacevec = NULL;
1439*bd7c6f51SGordon Ross 	ace_t *zacep;
1440*bd7c6f51SGordon Ross 	i_ntsd_t *sd = NULL;
1441*bd7c6f51SGordon Ross 	i_ntacl_t *acl = NULL;
1442*bd7c6f51SGordon Ross 	i_ntace_t **acep = NULL;
1443*bd7c6f51SGordon Ross #ifndef	_KERNEL
1444*bd7c6f51SGordon Ross 	idmap_handle_t *idmap_h = NULL;
1445*bd7c6f51SGordon Ross #endif /* _KERNEL */
1446*bd7c6f51SGordon Ross 	idmap_get_handle_t *idmap_gh = NULL;
1447*bd7c6f51SGordon Ross 	idmap_stat	idms;
1448*bd7c6f51SGordon Ross 
1449*bd7c6f51SGordon Ross 	/*
1450*bd7c6f51SGordon Ross 	 * First, get all the UID+GID to SID mappings.
1451*bd7c6f51SGordon Ross 	 * How many?  Also sanity checks.
1452*bd7c6f51SGordon Ross 	 */
1453*bd7c6f51SGordon Ross 	mapcnt = 0;
1454*bd7c6f51SGordon Ross 	if (selector & OWNER_SECURITY_INFORMATION) {
1455*bd7c6f51SGordon Ross 		if (own_uid == (uid_t)-1)
1456*bd7c6f51SGordon Ross 			return (EINVAL);
1457*bd7c6f51SGordon Ross 		mapcnt++;
1458*bd7c6f51SGordon Ross 	}
1459*bd7c6f51SGordon Ross 	if (selector & GROUP_SECURITY_INFORMATION) {
1460*bd7c6f51SGordon Ross 		if (own_gid == (gid_t)-1)
1461*bd7c6f51SGordon Ross 			return (EINVAL);
1462*bd7c6f51SGordon Ross 		mapcnt++;
1463*bd7c6f51SGordon Ross 	}
1464*bd7c6f51SGordon Ross 	if (selector & (DACL_SECURITY_INFORMATION |
1465*bd7c6f51SGordon Ross 	    SACL_SECURITY_INFORMATION)) {
1466*bd7c6f51SGordon Ross 		if (acl_info == NULL)
1467*bd7c6f51SGordon Ross 			return (EINVAL);
1468*bd7c6f51SGordon Ross 		if (own_uid == (uid_t)-1)
1469*bd7c6f51SGordon Ross 			return (EINVAL);
1470*bd7c6f51SGordon Ross 		if (own_gid == (gid_t)-1)
1471*bd7c6f51SGordon Ross 			return (EINVAL);
1472*bd7c6f51SGordon Ross #ifdef	_KERNEL
1473*bd7c6f51SGordon Ross 		if ((acl_info->vsa_mask & VSA_ACE) == 0)
1474*bd7c6f51SGordon Ross 			return (EINVAL);
1475*bd7c6f51SGordon Ross 		zacecnt = acl_info->vsa_aclcnt;
1476*bd7c6f51SGordon Ross 		zacevec = acl_info->vsa_aclentp;
1477*bd7c6f51SGordon Ross #else	/* _KERNEL */
1478*bd7c6f51SGordon Ross 		if (acl_info->acl_type != ACE_T ||
1479*bd7c6f51SGordon Ross 		    acl_info->acl_entry_size != sizeof (ace_t))
1480*bd7c6f51SGordon Ross 			return (EINVAL);
1481*bd7c6f51SGordon Ross 		zacecnt = acl_info->acl_cnt;
1482*bd7c6f51SGordon Ross 		zacevec = acl_info->acl_aclp;
1483*bd7c6f51SGordon Ross #endif	/* _KERNEL */
1484*bd7c6f51SGordon Ross 		if (zacecnt == 0 || zacevec == NULL)
1485*bd7c6f51SGordon Ross 			return (EINVAL);
1486*bd7c6f51SGordon Ross 		mapcnt += zacecnt;
1487*bd7c6f51SGordon Ross 	}
1488*bd7c6f51SGordon Ross 	if (mapcnt == 0)
1489*bd7c6f51SGordon Ross 		return (EINVAL);
1490*bd7c6f51SGordon Ross 	mapinfo = MALLOC(mapcnt * sizeof (*mapinfo));
1491*bd7c6f51SGordon Ross 	if (mapinfo == NULL)
1492*bd7c6f51SGordon Ross 		return (ENOMEM);
1493*bd7c6f51SGordon Ross 	bzero(mapinfo, mapcnt * sizeof (*mapinfo));
1494*bd7c6f51SGordon Ross 	/* no more returns until errout */
1495*bd7c6f51SGordon Ross 
1496*bd7c6f51SGordon Ross 	/*
1497*bd7c6f51SGordon Ross 	 * Get an imap "batch" request handle.
1498*bd7c6f51SGordon Ross 	 */
1499*bd7c6f51SGordon Ross #ifdef	_KERNEL
1500*bd7c6f51SGordon Ross 	idmap_gh = kidmap_get_create(curproc->p_zone);
1501*bd7c6f51SGordon Ross #else /* _KERNEL */
1502*bd7c6f51SGordon Ross 	idms = idmap_init(&idmap_h);
1503*bd7c6f51SGordon Ross 	if (idms != IDMAP_SUCCESS) {
1504*bd7c6f51SGordon Ross 		error = ENOTACTIVE;
1505*bd7c6f51SGordon Ross 		goto errout;
1506*bd7c6f51SGordon Ross 	}
1507*bd7c6f51SGordon Ross 	idms = idmap_get_create(idmap_h, &idmap_gh);
1508*bd7c6f51SGordon Ross 	if (idms != IDMAP_SUCCESS) {
1509*bd7c6f51SGordon Ross 		error = ENOTACTIVE;
1510*bd7c6f51SGordon Ross 		goto errout;
1511*bd7c6f51SGordon Ross 	}
1512*bd7c6f51SGordon Ross #endif /* _KERNEL */
1513*bd7c6f51SGordon Ross 
1514*bd7c6f51SGordon Ross 	/*
1515*bd7c6f51SGordon Ross 	 * Build our request to the idmap deamon,
1516*bd7c6f51SGordon Ross 	 * getting SIDs for every Unix UID/GID.
1517*bd7c6f51SGordon Ross 	 * Also count DACL and SACL ACEs here.
1518*bd7c6f51SGordon Ross 	 */
1519*bd7c6f51SGordon Ross 	mip = mapinfo;
1520*bd7c6f51SGordon Ross 	if (selector & OWNER_SECURITY_INFORMATION) {
1521*bd7c6f51SGordon Ross 		error = mkrq_idmap_ux2sid(idmap_gh, mip,
1522*bd7c6f51SGordon Ross 		    own_uid, IDM_TYPE_USER);
1523*bd7c6f51SGordon Ross 		if (error)
1524*bd7c6f51SGordon Ross 			goto errout;
1525*bd7c6f51SGordon Ross 		mip++;
1526*bd7c6f51SGordon Ross 	}
1527*bd7c6f51SGordon Ross 	if (selector & GROUP_SECURITY_INFORMATION) {
1528*bd7c6f51SGordon Ross 		error = mkrq_idmap_ux2sid(idmap_gh, mip,
1529*bd7c6f51SGordon Ross 		    own_gid, IDM_TYPE_GROUP);
1530*bd7c6f51SGordon Ross 		if (error)
1531*bd7c6f51SGordon Ross 			goto errout;
1532*bd7c6f51SGordon Ross 		mip++;
1533*bd7c6f51SGordon Ross 	}
1534*bd7c6f51SGordon Ross 	if (selector & (DACL_SECURITY_INFORMATION |
1535*bd7c6f51SGordon Ross 	    SACL_SECURITY_INFORMATION)) {
1536*bd7c6f51SGordon Ross 		int rqtype;
1537*bd7c6f51SGordon Ross 		uid_t uid;
1538*bd7c6f51SGordon Ross 
1539*bd7c6f51SGordon Ross 		zacep = zacevec;
1540*bd7c6f51SGordon Ross 		for (i = 0; i < zacecnt; i++) {
1541*bd7c6f51SGordon Ross 
1542*bd7c6f51SGordon Ross 			switch (zacep->a_type) {
1543*bd7c6f51SGordon Ross 			case ACE_ACCESS_ALLOWED_ACE_TYPE:
1544*bd7c6f51SGordon Ross 			case ACE_ACCESS_DENIED_ACE_TYPE:
1545*bd7c6f51SGordon Ross 				dacl_acecnt++;
1546*bd7c6f51SGordon Ross 				break;
1547*bd7c6f51SGordon Ross 			case ACE_SYSTEM_AUDIT_ACE_TYPE:
1548*bd7c6f51SGordon Ross 			case ACE_SYSTEM_ALARM_ACE_TYPE:
1549*bd7c6f51SGordon Ross 				sacl_acecnt++;
1550*bd7c6f51SGordon Ross 				break;
1551*bd7c6f51SGordon Ross 			/* other types todo */
1552*bd7c6f51SGordon Ross 			}
1553*bd7c6f51SGordon Ross 
1554*bd7c6f51SGordon Ross 			if (zacep->a_flags & ACE_EVERYONE) {
1555*bd7c6f51SGordon Ross 				rqtype = IDM_EVERYONE;
1556*bd7c6f51SGordon Ross 				uid = (uid_t)-1;
1557*bd7c6f51SGordon Ross 			} else if (zacep->a_flags & ACE_GROUP) {
1558*bd7c6f51SGordon Ross 				/* owning group (a_who = -1) */
1559*bd7c6f51SGordon Ross 				rqtype = IDM_TYPE_GROUP;
1560*bd7c6f51SGordon Ross 				uid = (uid_t)own_gid;
1561*bd7c6f51SGordon Ross 			} else if (zacep->a_flags & ACE_OWNER) {
1562*bd7c6f51SGordon Ross 				/* owning user (a_who = -1) */
1563*bd7c6f51SGordon Ross 				rqtype = IDM_TYPE_USER;
1564*bd7c6f51SGordon Ross 				uid = (uid_t)own_uid;
1565*bd7c6f51SGordon Ross 			} else if (zacep->a_flags & ACE_IDENTIFIER_GROUP) {
1566*bd7c6f51SGordon Ross 				/* regular group */
1567*bd7c6f51SGordon Ross 				rqtype = IDM_TYPE_GROUP;
1568*bd7c6f51SGordon Ross 				uid = zacep->a_who;
1569*bd7c6f51SGordon Ross 			} else {
1570*bd7c6f51SGordon Ross 				rqtype = IDM_TYPE_USER;
1571*bd7c6f51SGordon Ross 				uid = zacep->a_who;
1572*bd7c6f51SGordon Ross 			}
1573*bd7c6f51SGordon Ross 
1574*bd7c6f51SGordon Ross 			error = mkrq_idmap_ux2sid(idmap_gh, mip, uid, rqtype);
1575*bd7c6f51SGordon Ross 			if (error)
1576*bd7c6f51SGordon Ross 				goto errout;
1577*bd7c6f51SGordon Ross 			zacep++;
1578*bd7c6f51SGordon Ross 			mip++;
1579*bd7c6f51SGordon Ross 		}
1580*bd7c6f51SGordon Ross 	}
1581*bd7c6f51SGordon Ross 
1582*bd7c6f51SGordon Ross 	idms = I_getmappings(idmap_gh);
1583*bd7c6f51SGordon Ross 	if (idms != IDMAP_SUCCESS) {
1584*bd7c6f51SGordon Ross 		/* creative error choice */
1585*bd7c6f51SGordon Ross 		error = EIDRM;
1586*bd7c6f51SGordon Ross 		goto errout;
1587*bd7c6f51SGordon Ross 	}
1588*bd7c6f51SGordon Ross 
1589*bd7c6f51SGordon Ross 	/*
1590*bd7c6f51SGordon Ross 	 * With any luck, we now have a Windows SID for
1591*bd7c6f51SGordon Ross 	 * every Unix UID or GID in the NFS/ZFS ACL.
1592*bd7c6f51SGordon Ross 	 * The remaining work is just format conversion,
1593*bd7c6f51SGordon Ross 	 * memory allocation, etc.
1594*bd7c6f51SGordon Ross 	 */
1595*bd7c6f51SGordon Ross 	if ((sd = MALLOC(sizeof (*sd))) == NULL) {
1596*bd7c6f51SGordon Ross 		error = ENOMEM;
1597*bd7c6f51SGordon Ross 		goto errout;
1598*bd7c6f51SGordon Ross 	}
1599*bd7c6f51SGordon Ross 	bzero(sd, sizeof (*sd));
1600*bd7c6f51SGordon Ross 	sd->sd_revision = NT_SD_REVISION;
1601*bd7c6f51SGordon Ross 
1602*bd7c6f51SGordon Ross 	mip = mapinfo;
1603*bd7c6f51SGordon Ross 	if (selector & OWNER_SECURITY_INFORMATION) {
1604*bd7c6f51SGordon Ross 		error = smbfs_str2sid(mip->mi_dsid, &mip->mi_rid,
1605*bd7c6f51SGordon Ross 		    &sd->sd_owner);
1606*bd7c6f51SGordon Ross 		mip++;
1607*bd7c6f51SGordon Ross 	}
1608*bd7c6f51SGordon Ross 	if (selector & GROUP_SECURITY_INFORMATION) {
1609*bd7c6f51SGordon Ross 		error = smbfs_str2sid(mip->mi_dsid, &mip->mi_rid,
1610*bd7c6f51SGordon Ross 		    &sd->sd_group);
1611*bd7c6f51SGordon Ross 		mip++;
1612*bd7c6f51SGordon Ross 	}
1613*bd7c6f51SGordon Ross 
1614*bd7c6f51SGordon Ross 	/*
1615*bd7c6f51SGordon Ross 	 * If setting both DACL and SACL, we will
1616*bd7c6f51SGordon Ross 	 * make two passes starting here in mapinfo.
1617*bd7c6f51SGordon Ross 	 */
1618*bd7c6f51SGordon Ross 	mip_acl = mip;
1619*bd7c6f51SGordon Ross 
1620*bd7c6f51SGordon Ross 	if (selector & DACL_SECURITY_INFORMATION) {
1621*bd7c6f51SGordon Ross 		/*
1622*bd7c6f51SGordon Ross 		 * Caller wants to set the DACL.
1623*bd7c6f51SGordon Ross 		 */
1624*bd7c6f51SGordon Ross 		aclsz = I_ACL_SIZE(dacl_acecnt);
1625*bd7c6f51SGordon Ross 		if ((acl = MALLOC(aclsz)) == NULL) {
1626*bd7c6f51SGordon Ross 			error = ENOMEM;
1627*bd7c6f51SGordon Ross 			goto errout;
1628*bd7c6f51SGordon Ross 		}
1629*bd7c6f51SGordon Ross 		bzero(acl, aclsz);
1630*bd7c6f51SGordon Ross 
1631*bd7c6f51SGordon Ross 		acl->acl_revision = NT_ACL_REVISION;
1632*bd7c6f51SGordon Ross 		acl->acl_acecount = (uint16_t)dacl_acecnt;
1633*bd7c6f51SGordon Ross 		acep = &acl->acl_acevec[0];
1634*bd7c6f51SGordon Ross 
1635*bd7c6f51SGordon Ross 		/* 1st pass - scan for DACL ACE types. */
1636*bd7c6f51SGordon Ross 		mip = mip_acl;
1637*bd7c6f51SGordon Ross 		zacep = zacevec;
1638*bd7c6f51SGordon Ross 		for (i = 0; i < zacecnt; i++) {
1639*bd7c6f51SGordon Ross 
1640*bd7c6f51SGordon Ross 			switch (zacep->a_type) {
1641*bd7c6f51SGordon Ross 			case ACE_ACCESS_ALLOWED_ACE_TYPE:
1642*bd7c6f51SGordon Ross 			case ACE_ACCESS_DENIED_ACE_TYPE:
1643*bd7c6f51SGordon Ross 				error = zace2ntace(acep, zacep, mip);
1644*bd7c6f51SGordon Ross 				if (error != 0)
1645*bd7c6f51SGordon Ross 					goto errout;
1646*bd7c6f51SGordon Ross 				acep++;
1647*bd7c6f51SGordon Ross 				break;
1648*bd7c6f51SGordon Ross 
1649*bd7c6f51SGordon Ross 			case ACE_SYSTEM_AUDIT_ACE_TYPE:
1650*bd7c6f51SGordon Ross 			case ACE_SYSTEM_ALARM_ACE_TYPE:
1651*bd7c6f51SGordon Ross 				break;
1652*bd7c6f51SGordon Ross 			/* other types todo */
1653*bd7c6f51SGordon Ross 			}
1654*bd7c6f51SGordon Ross 			zacep++;
1655*bd7c6f51SGordon Ross 			mip++;
1656*bd7c6f51SGordon Ross 		}
1657*bd7c6f51SGordon Ross 		sd->sd_dacl = acl;
1658*bd7c6f51SGordon Ross 		acl = NULL;
1659*bd7c6f51SGordon Ross 		sd->sd_flags |= SD_DACL_PRESENT;
1660*bd7c6f51SGordon Ross 	}
1661*bd7c6f51SGordon Ross 
1662*bd7c6f51SGordon Ross 	if (selector & SACL_SECURITY_INFORMATION) {
1663*bd7c6f51SGordon Ross 		/*
1664*bd7c6f51SGordon Ross 		 * Caller wants to set the SACL.
1665*bd7c6f51SGordon Ross 		 */
1666*bd7c6f51SGordon Ross 		aclsz = I_ACL_SIZE(sacl_acecnt);
1667*bd7c6f51SGordon Ross 		if ((acl = MALLOC(aclsz)) == NULL) {
1668*bd7c6f51SGordon Ross 			error = ENOMEM;
1669*bd7c6f51SGordon Ross 			goto errout;
1670*bd7c6f51SGordon Ross 		}
1671*bd7c6f51SGordon Ross 		bzero(acl, aclsz);
1672*bd7c6f51SGordon Ross 
1673*bd7c6f51SGordon Ross 		acl->acl_revision = NT_ACL_REVISION;
1674*bd7c6f51SGordon Ross 		acl->acl_acecount = (uint16_t)sacl_acecnt;
1675*bd7c6f51SGordon Ross 		acep = &acl->acl_acevec[0];
1676*bd7c6f51SGordon Ross 
1677*bd7c6f51SGordon Ross 		/* 2nd pass - scan for SACL ACE types. */
1678*bd7c6f51SGordon Ross 		mip = mip_acl;
1679*bd7c6f51SGordon Ross 		zacep = zacevec;
1680*bd7c6f51SGordon Ross 		for (i = 0; i < zacecnt; i++) {
1681*bd7c6f51SGordon Ross 
1682*bd7c6f51SGordon Ross 			switch (zacep->a_type) {
1683*bd7c6f51SGordon Ross 			case ACE_ACCESS_ALLOWED_ACE_TYPE:
1684*bd7c6f51SGordon Ross 			case ACE_ACCESS_DENIED_ACE_TYPE:
1685*bd7c6f51SGordon Ross 				break;
1686*bd7c6f51SGordon Ross 
1687*bd7c6f51SGordon Ross 			case ACE_SYSTEM_AUDIT_ACE_TYPE:
1688*bd7c6f51SGordon Ross 			case ACE_SYSTEM_ALARM_ACE_TYPE:
1689*bd7c6f51SGordon Ross 				error = zace2ntace(acep, zacep, mip);
1690*bd7c6f51SGordon Ross 				if (error != 0)
1691*bd7c6f51SGordon Ross 					goto errout;
1692*bd7c6f51SGordon Ross 				acep++;
1693*bd7c6f51SGordon Ross 				break;
1694*bd7c6f51SGordon Ross 			/* other types todo */
1695*bd7c6f51SGordon Ross 			}
1696*bd7c6f51SGordon Ross 			zacep++;
1697*bd7c6f51SGordon Ross 			mip++;
1698*bd7c6f51SGordon Ross 		}
1699*bd7c6f51SGordon Ross 		sd->sd_sacl = acl;
1700*bd7c6f51SGordon Ross 		acl = NULL;
1701*bd7c6f51SGordon Ross 		sd->sd_flags |= SD_SACL_PRESENT;
1702*bd7c6f51SGordon Ross 	}
1703*bd7c6f51SGordon Ross 
1704*bd7c6f51SGordon Ross 	*sdp = sd;
1705*bd7c6f51SGordon Ross 	error = 0;
1706*bd7c6f51SGordon Ross 
1707*bd7c6f51SGordon Ross errout:
1708*bd7c6f51SGordon Ross 	if (error != 0) {
1709*bd7c6f51SGordon Ross 		if (acl != NULL)
1710*bd7c6f51SGordon Ross 			ifree_acl(acl);
1711*bd7c6f51SGordon Ross 		if (sd != NULL)
1712*bd7c6f51SGordon Ross 			smbfs_acl_free_sd(sd);
1713*bd7c6f51SGordon Ross 	}
1714*bd7c6f51SGordon Ross 	if (mapinfo != NULL)
1715*bd7c6f51SGordon Ross 		FREESZ(mapinfo, mapcnt * sizeof (*mapinfo));
1716*bd7c6f51SGordon Ross #ifdef	_KERNEL
1717*bd7c6f51SGordon Ross 	if (idmap_gh != NULL)
1718*bd7c6f51SGordon Ross 		kidmap_get_destroy(idmap_gh);
1719*bd7c6f51SGordon Ross #else /* _KERNEL */
1720*bd7c6f51SGordon Ross 	if (idmap_gh != NULL)
1721*bd7c6f51SGordon Ross 		idmap_get_destroy(idmap_gh);
1722*bd7c6f51SGordon Ross 	if (idmap_h != NULL)
1723*bd7c6f51SGordon Ross 		(void) idmap_fini(idmap_h);
1724*bd7c6f51SGordon Ross #endif /* _KERNEL */
1725*bd7c6f51SGordon Ross 
1726*bd7c6f51SGordon Ross 	return (error);
172702d09e03SGordon Ross }
1728