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