xref: /onnv-gate/usr/src/common/smbclnt/smbfs_ntacl.c (revision 12914:e95332bf1454)
111332SGordon.Ross@Sun.COM /*
211332SGordon.Ross@Sun.COM  * CDDL HEADER START
311332SGordon.Ross@Sun.COM  *
411332SGordon.Ross@Sun.COM  * The contents of this file are subject to the terms of the
511332SGordon.Ross@Sun.COM  * Common Development and Distribution License (the "License").
611332SGordon.Ross@Sun.COM  * You may not use this file except in compliance with the License.
711332SGordon.Ross@Sun.COM  *
811332SGordon.Ross@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911332SGordon.Ross@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1011332SGordon.Ross@Sun.COM  * See the License for the specific language governing permissions
1111332SGordon.Ross@Sun.COM  * and limitations under the License.
1211332SGordon.Ross@Sun.COM  *
1311332SGordon.Ross@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1411332SGordon.Ross@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511332SGordon.Ross@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1611332SGordon.Ross@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1711332SGordon.Ross@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1811332SGordon.Ross@Sun.COM  *
1911332SGordon.Ross@Sun.COM  * CDDL HEADER END
2011332SGordon.Ross@Sun.COM  */
2111332SGordon.Ross@Sun.COM 
2211332SGordon.Ross@Sun.COM /*
23*12914SJoyce.McIntosh@Sun.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
2411332SGordon.Ross@Sun.COM  */
2511332SGordon.Ross@Sun.COM 
2611332SGordon.Ross@Sun.COM /*
2711332SGordon.Ross@Sun.COM  * ACL conversion support for smbfs
2811332SGordon.Ross@Sun.COM  * (To/from NT/ZFS-style ACLs.)
2911332SGordon.Ross@Sun.COM  */
3011332SGordon.Ross@Sun.COM 
3111332SGordon.Ross@Sun.COM #include <sys/types.h>
3211332SGordon.Ross@Sun.COM #include <sys/errno.h>
3311332SGordon.Ross@Sun.COM #include <sys/acl.h>
3411332SGordon.Ross@Sun.COM #include <sys/byteorder.h>
3511332SGordon.Ross@Sun.COM 
3611332SGordon.Ross@Sun.COM #ifdef _KERNEL
3711332SGordon.Ross@Sun.COM 
3811332SGordon.Ross@Sun.COM #include <sys/cred.h>
3911332SGordon.Ross@Sun.COM #include <sys/cmn_err.h>
4011332SGordon.Ross@Sun.COM #include <sys/kmem.h>
4111332SGordon.Ross@Sun.COM #include <sys/sunddi.h>
4211332SGordon.Ross@Sun.COM #include <sys/vnode.h>
4311332SGordon.Ross@Sun.COM #include <sys/vfs.h>
4411332SGordon.Ross@Sun.COM 
4511332SGordon.Ross@Sun.COM #include <sys/kidmap.h>
4611332SGordon.Ross@Sun.COM 
4711332SGordon.Ross@Sun.COM #else	/* _KERNEL */
4811332SGordon.Ross@Sun.COM 
4911332SGordon.Ross@Sun.COM #include <stdio.h>
5011332SGordon.Ross@Sun.COM #include <stdlib.h>
5111332SGordon.Ross@Sun.COM #include <strings.h>
5211332SGordon.Ross@Sun.COM 
5311332SGordon.Ross@Sun.COM #include <idmap.h>
5411332SGordon.Ross@Sun.COM 
5511332SGordon.Ross@Sun.COM #endif	/* _KERNEL */
5611332SGordon.Ross@Sun.COM 
5711332SGordon.Ross@Sun.COM #include <netsmb/mchain.h>
5811332SGordon.Ross@Sun.COM #include <netsmb/smb.h>
5911332SGordon.Ross@Sun.COM #include "smbfs_ntacl.h"
6011332SGordon.Ross@Sun.COM 
6111564SGordon.Ross@Sun.COM #define	NT_SD_REVISION	1
6211564SGordon.Ross@Sun.COM #define	NT_ACL_REVISION	2
6311564SGordon.Ross@Sun.COM 
6411332SGordon.Ross@Sun.COM #ifdef _KERNEL
6511332SGordon.Ross@Sun.COM #define	MALLOC(size) kmem_alloc(size, KM_SLEEP)
6611332SGordon.Ross@Sun.COM #define	FREESZ(p, sz) kmem_free(p, sz)
6711332SGordon.Ross@Sun.COM #else	/* _KERNEL */
6811332SGordon.Ross@Sun.COM #define	MALLOC(size) malloc(size)
6911332SGordon.Ross@Sun.COM #ifndef lint
7011332SGordon.Ross@Sun.COM #define	FREESZ(p, sz) free(p)
7111332SGordon.Ross@Sun.COM #else	/* lint */
7211332SGordon.Ross@Sun.COM /* ARGSUSED */
7311332SGordon.Ross@Sun.COM static void
FREESZ(void * p,size_t sz)7411332SGordon.Ross@Sun.COM FREESZ(void *p, size_t sz)
7511332SGordon.Ross@Sun.COM {
7611332SGordon.Ross@Sun.COM 	free(p);
7711332SGordon.Ross@Sun.COM }
7811332SGordon.Ross@Sun.COM #endif	/* lint */
7911332SGordon.Ross@Sun.COM #endif	/* _KERNEL */
8011332SGordon.Ross@Sun.COM 
8111332SGordon.Ross@Sun.COM #define	ERRCHK(expr)	if ((error = expr) != 0) goto errout
8211332SGordon.Ross@Sun.COM 
8311332SGordon.Ross@Sun.COM /*
8411332SGordon.Ross@Sun.COM  * Security IDentifier (SID)
8511332SGordon.Ross@Sun.COM  */
8611332SGordon.Ross@Sun.COM static void
ifree_sid(i_ntsid_t * sid)8711332SGordon.Ross@Sun.COM ifree_sid(i_ntsid_t *sid)
8811332SGordon.Ross@Sun.COM {
8911332SGordon.Ross@Sun.COM 	size_t sz;
9011332SGordon.Ross@Sun.COM 
9111332SGordon.Ross@Sun.COM 	if (sid == NULL)
9211332SGordon.Ross@Sun.COM 		return;
9311332SGordon.Ross@Sun.COM 
9411332SGordon.Ross@Sun.COM 	sz = I_SID_SIZE(sid->sid_subauthcount);
9511332SGordon.Ross@Sun.COM 	FREESZ(sid, sz);
9611332SGordon.Ross@Sun.COM }
9711332SGordon.Ross@Sun.COM 
9811332SGordon.Ross@Sun.COM static int
md_get_sid(mdchain_t * mdp,i_ntsid_t ** sidp)9911332SGordon.Ross@Sun.COM md_get_sid(mdchain_t *mdp, i_ntsid_t **sidp)
10011332SGordon.Ross@Sun.COM {
10111332SGordon.Ross@Sun.COM 	i_ntsid_t *sid = NULL;
10211332SGordon.Ross@Sun.COM 	uint8_t revision, subauthcount;
10311332SGordon.Ross@Sun.COM 	uint32_t *subauthp;
10411332SGordon.Ross@Sun.COM 	size_t sidsz;
10511332SGordon.Ross@Sun.COM 	int error, i;
10611332SGordon.Ross@Sun.COM 
10711332SGordon.Ross@Sun.COM 	if ((error = md_get_uint8(mdp, &revision)) != 0)
10811332SGordon.Ross@Sun.COM 		return (error);
10911332SGordon.Ross@Sun.COM 	if ((error = md_get_uint8(mdp, &subauthcount)) != 0)
11011332SGordon.Ross@Sun.COM 		return (error);
11111332SGordon.Ross@Sun.COM 
11211332SGordon.Ross@Sun.COM 	sidsz = I_SID_SIZE(subauthcount);
11311332SGordon.Ross@Sun.COM 
11411332SGordon.Ross@Sun.COM 	if ((sid = MALLOC(sidsz)) == NULL)
11511332SGordon.Ross@Sun.COM 		return (ENOMEM);
11611332SGordon.Ross@Sun.COM 
11711332SGordon.Ross@Sun.COM 	bzero(sid, sidsz);
11811332SGordon.Ross@Sun.COM 	sid->sid_revision = revision;
11911332SGordon.Ross@Sun.COM 	sid->sid_subauthcount = subauthcount;
12011332SGordon.Ross@Sun.COM 	ERRCHK(md_get_mem(mdp, sid->sid_authority, 6, MB_MSYSTEM));
12111332SGordon.Ross@Sun.COM 
12211332SGordon.Ross@Sun.COM 	subauthp = &sid->sid_subauthvec[0];
12311332SGordon.Ross@Sun.COM 	for (i = 0; i < subauthcount; i++) {
12411332SGordon.Ross@Sun.COM 		ERRCHK(md_get_uint32le(mdp, subauthp));
12511332SGordon.Ross@Sun.COM 		subauthp++;
12611332SGordon.Ross@Sun.COM 	}
12711332SGordon.Ross@Sun.COM 
12811332SGordon.Ross@Sun.COM 	/* Success! */
12911332SGordon.Ross@Sun.COM 	*sidp = sid;
13011332SGordon.Ross@Sun.COM 	return (0);
13111332SGordon.Ross@Sun.COM 
13211332SGordon.Ross@Sun.COM errout:
13311332SGordon.Ross@Sun.COM 	ifree_sid(sid);
13411332SGordon.Ross@Sun.COM 	return (error);
13511332SGordon.Ross@Sun.COM }
13611332SGordon.Ross@Sun.COM 
13711332SGordon.Ross@Sun.COM static int
mb_put_sid(mbchain_t * mbp,i_ntsid_t * sid)13811332SGordon.Ross@Sun.COM mb_put_sid(mbchain_t *mbp, i_ntsid_t *sid)
13911332SGordon.Ross@Sun.COM {
14011332SGordon.Ross@Sun.COM 	uint32_t *subauthp;
14111332SGordon.Ross@Sun.COM 	int error, i;
14211332SGordon.Ross@Sun.COM 
14311332SGordon.Ross@Sun.COM 	if (sid == NULL)
14411332SGordon.Ross@Sun.COM 		return (EINVAL);
14511332SGordon.Ross@Sun.COM 
14611332SGordon.Ross@Sun.COM 	ERRCHK(mb_put_uint8(mbp, sid->sid_revision));
14711332SGordon.Ross@Sun.COM 	ERRCHK(mb_put_uint8(mbp, sid->sid_subauthcount));
14811332SGordon.Ross@Sun.COM 	ERRCHK(mb_put_mem(mbp, sid->sid_authority, 6, MB_MSYSTEM));
14911332SGordon.Ross@Sun.COM 
15011332SGordon.Ross@Sun.COM 	subauthp = &sid->sid_subauthvec[0];
15111332SGordon.Ross@Sun.COM 	for (i = 0; i < sid->sid_subauthcount; i++) {
15211332SGordon.Ross@Sun.COM 		ERRCHK(mb_put_uint32le(mbp, *subauthp));
15311332SGordon.Ross@Sun.COM 		subauthp++;
15411332SGordon.Ross@Sun.COM 	}
15511332SGordon.Ross@Sun.COM 
15611332SGordon.Ross@Sun.COM 	/* Success! */
15711332SGordon.Ross@Sun.COM 	return (0);
15811332SGordon.Ross@Sun.COM 
15911332SGordon.Ross@Sun.COM errout:
16011332SGordon.Ross@Sun.COM 	return (error);
16111332SGordon.Ross@Sun.COM }
16211332SGordon.Ross@Sun.COM 
16311332SGordon.Ross@Sun.COM 
16411332SGordon.Ross@Sun.COM /*
16511332SGordon.Ross@Sun.COM  * Access Control Entry (ACE)
16611332SGordon.Ross@Sun.COM  */
16711332SGordon.Ross@Sun.COM static void
ifree_ace(i_ntace_t * ace)16811332SGordon.Ross@Sun.COM ifree_ace(i_ntace_t *ace)
16911332SGordon.Ross@Sun.COM {
17011332SGordon.Ross@Sun.COM 
17111332SGordon.Ross@Sun.COM 	if (ace == NULL)
17211332SGordon.Ross@Sun.COM 		return;
17311332SGordon.Ross@Sun.COM 
17411564SGordon.Ross@Sun.COM 	switch (ace->ace_hdr.ace_type) {
17511564SGordon.Ross@Sun.COM 	case ACCESS_ALLOWED_ACE_TYPE:
17611564SGordon.Ross@Sun.COM 	case ACCESS_DENIED_ACE_TYPE:
17711564SGordon.Ross@Sun.COM 	case SYSTEM_AUDIT_ACE_TYPE:
17811564SGordon.Ross@Sun.COM 	case SYSTEM_ALARM_ACE_TYPE:
17911564SGordon.Ross@Sun.COM 		ifree_sid(ace->ace_v2.ace_sid);
18011564SGordon.Ross@Sun.COM 		FREESZ(ace, sizeof (i_ntace_v2_t));
18111564SGordon.Ross@Sun.COM 		break;
18211564SGordon.Ross@Sun.COM 	/* other types todo */
18311564SGordon.Ross@Sun.COM 	default:
18411564SGordon.Ross@Sun.COM 		break;
18511564SGordon.Ross@Sun.COM 	}
18611332SGordon.Ross@Sun.COM }
18711332SGordon.Ross@Sun.COM 
18811332SGordon.Ross@Sun.COM static int
md_get_ace(mdchain_t * mdp,i_ntace_t ** acep)18911332SGordon.Ross@Sun.COM md_get_ace(mdchain_t *mdp, i_ntace_t **acep)
19011332SGordon.Ross@Sun.COM {
19111332SGordon.Ross@Sun.COM 	mdchain_t tmp_md;
19211564SGordon.Ross@Sun.COM 	i_ntace_hdr_t ace_hdr;
19311332SGordon.Ross@Sun.COM 	i_ntace_t *ace = NULL;
19411564SGordon.Ross@Sun.COM 	uint16_t alloc_size;
19511332SGordon.Ross@Sun.COM 	int error;
19611332SGordon.Ross@Sun.COM 
19711332SGordon.Ross@Sun.COM 	/*
19811332SGordon.Ross@Sun.COM 	 * The ACE is realy variable length,
19911332SGordon.Ross@Sun.COM 	 * with format determined by the type.
20011332SGordon.Ross@Sun.COM 	 *
20111332SGordon.Ross@Sun.COM 	 * There may also be padding after it, so
20211564SGordon.Ross@Sun.COM 	 * decode it using a copy of the mdchain,
20311332SGordon.Ross@Sun.COM 	 * and then consume the specified length.
20411332SGordon.Ross@Sun.COM 	 */
20511332SGordon.Ross@Sun.COM 	tmp_md = *mdp;
20611332SGordon.Ross@Sun.COM 
20711564SGordon.Ross@Sun.COM 	/* Fixed-size ACE header */
20811564SGordon.Ross@Sun.COM 	ERRCHK(md_get_uint8(&tmp_md, &ace_hdr.ace_type));
20911564SGordon.Ross@Sun.COM 	ERRCHK(md_get_uint8(&tmp_md, &ace_hdr.ace_flags));
21011564SGordon.Ross@Sun.COM 	ERRCHK(md_get_uint16le(&tmp_md, &ace_hdr.ace_size));
21111332SGordon.Ross@Sun.COM 
21211564SGordon.Ross@Sun.COM 	switch (ace_hdr.ace_type) {
21311564SGordon.Ross@Sun.COM 	case ACCESS_ALLOWED_ACE_TYPE:
21411564SGordon.Ross@Sun.COM 	case ACCESS_DENIED_ACE_TYPE:
21511564SGordon.Ross@Sun.COM 	case SYSTEM_AUDIT_ACE_TYPE:
21611564SGordon.Ross@Sun.COM 	case SYSTEM_ALARM_ACE_TYPE:
21711564SGordon.Ross@Sun.COM 		alloc_size = sizeof (i_ntace_v2_t);
21811564SGordon.Ross@Sun.COM 		if ((ace = MALLOC(alloc_size)) == NULL)
21911564SGordon.Ross@Sun.COM 			return (ENOMEM);
22011564SGordon.Ross@Sun.COM 		bzero(ace, alloc_size);
22111564SGordon.Ross@Sun.COM 		/* ACE header */
22211564SGordon.Ross@Sun.COM 		ace->ace_hdr.ace_type = ace_hdr.ace_type;
22311564SGordon.Ross@Sun.COM 		ace->ace_hdr.ace_flags = ace_hdr.ace_flags;
22411564SGordon.Ross@Sun.COM 		ace->ace_hdr.ace_size = alloc_size;
22511564SGordon.Ross@Sun.COM 		/* Type-specific data. */
22611564SGordon.Ross@Sun.COM 		ERRCHK(md_get_uint32le(&tmp_md, &ace->ace_v2.ace_rights));
22711564SGordon.Ross@Sun.COM 		ERRCHK(md_get_sid(&tmp_md, &ace->ace_v2.ace_sid));
22811564SGordon.Ross@Sun.COM 		break;
22911332SGordon.Ross@Sun.COM 
23011564SGordon.Ross@Sun.COM 	/* other types todo */
23111564SGordon.Ross@Sun.COM 	default:
23211564SGordon.Ross@Sun.COM 		error = EIO;
23311564SGordon.Ross@Sun.COM 		goto errout;
23411564SGordon.Ross@Sun.COM 	}
23511564SGordon.Ross@Sun.COM 
23611564SGordon.Ross@Sun.COM 	/* Now actually consume ace_hdr.ace_size */
23711564SGordon.Ross@Sun.COM 	ERRCHK(md_get_mem(mdp, NULL, ace_hdr.ace_size, MB_MSYSTEM));
23811332SGordon.Ross@Sun.COM 
23911332SGordon.Ross@Sun.COM 	/* Success! */
24011332SGordon.Ross@Sun.COM 	*acep = ace;
24111332SGordon.Ross@Sun.COM 	return (0);
24211332SGordon.Ross@Sun.COM 
24311332SGordon.Ross@Sun.COM errout:
24411332SGordon.Ross@Sun.COM 	ifree_ace(ace);
24511332SGordon.Ross@Sun.COM 	return (error);
24611332SGordon.Ross@Sun.COM }
24711332SGordon.Ross@Sun.COM 
24811332SGordon.Ross@Sun.COM static int
mb_put_ace(mbchain_t * mbp,i_ntace_t * ace)24911332SGordon.Ross@Sun.COM mb_put_ace(mbchain_t *mbp, i_ntace_t *ace)
25011332SGordon.Ross@Sun.COM {
25111332SGordon.Ross@Sun.COM 	int cnt0, error;
25211332SGordon.Ross@Sun.COM 	uint16_t ace_len, *ace_len_p;
25311332SGordon.Ross@Sun.COM 
25411332SGordon.Ross@Sun.COM 	if (ace == NULL)
25511332SGordon.Ross@Sun.COM 		return (EINVAL);
25611332SGordon.Ross@Sun.COM 
25711332SGordon.Ross@Sun.COM 	cnt0 = mbp->mb_count;
25811332SGordon.Ross@Sun.COM 
25911564SGordon.Ross@Sun.COM 	/*
26011564SGordon.Ross@Sun.COM 	 * Put the (fixed-size) ACE header
26111564SGordon.Ross@Sun.COM 	 * Will fill in the length later.
26211564SGordon.Ross@Sun.COM 	 */
26311564SGordon.Ross@Sun.COM 	ERRCHK(mb_put_uint8(mbp, ace->ace_hdr.ace_type));
26411564SGordon.Ross@Sun.COM 	ERRCHK(mb_put_uint8(mbp, ace->ace_hdr.ace_flags));
26511332SGordon.Ross@Sun.COM 	ace_len_p = mb_reserve(mbp, sizeof (*ace_len_p));
26611332SGordon.Ross@Sun.COM 	if (ace_len_p == NULL) {
26711332SGordon.Ross@Sun.COM 		error = ENOMEM;
26811332SGordon.Ross@Sun.COM 		goto errout;
26911332SGordon.Ross@Sun.COM 	}
27011332SGordon.Ross@Sun.COM 
27111564SGordon.Ross@Sun.COM 	switch (ace->ace_hdr.ace_type) {
27211564SGordon.Ross@Sun.COM 	case ACCESS_ALLOWED_ACE_TYPE:
27311564SGordon.Ross@Sun.COM 	case ACCESS_DENIED_ACE_TYPE:
27411564SGordon.Ross@Sun.COM 	case SYSTEM_AUDIT_ACE_TYPE:
27511564SGordon.Ross@Sun.COM 	case SYSTEM_ALARM_ACE_TYPE:
27611564SGordon.Ross@Sun.COM 		/* Put type-specific data. */
27711564SGordon.Ross@Sun.COM 		ERRCHK(mb_put_uint32le(mbp, ace->ace_v2.ace_rights));
27811564SGordon.Ross@Sun.COM 		ERRCHK(mb_put_sid(mbp, ace->ace_v2.ace_sid));
27911564SGordon.Ross@Sun.COM 		break;
28011332SGordon.Ross@Sun.COM 
28111564SGordon.Ross@Sun.COM 	/* other types todo */
28211564SGordon.Ross@Sun.COM 	default:
28311564SGordon.Ross@Sun.COM 		error = EIO;
28411564SGordon.Ross@Sun.COM 		goto errout;
28511564SGordon.Ross@Sun.COM 	}
28611564SGordon.Ross@Sun.COM 
28711564SGordon.Ross@Sun.COM 	/* Fill in the (OtW) ACE length. */
28811332SGordon.Ross@Sun.COM 	ace_len = mbp->mb_count - cnt0;
28911332SGordon.Ross@Sun.COM 	*ace_len_p = htoles(ace_len);
29011332SGordon.Ross@Sun.COM 
29111332SGordon.Ross@Sun.COM 	/* Success! */
29211332SGordon.Ross@Sun.COM 	return (0);
29311332SGordon.Ross@Sun.COM 
29411332SGordon.Ross@Sun.COM errout:
29511332SGordon.Ross@Sun.COM 	return (error);
29611332SGordon.Ross@Sun.COM }
29711332SGordon.Ross@Sun.COM 
29811332SGordon.Ross@Sun.COM 
29911332SGordon.Ross@Sun.COM /*
30011332SGordon.Ross@Sun.COM  * Access Control List (ACL)
30111332SGordon.Ross@Sun.COM  */
30211332SGordon.Ross@Sun.COM 
30311332SGordon.Ross@Sun.COM /* Not an OTW structure, so size can be at our convenience. */
30411332SGordon.Ross@Sun.COM #define	I_ACL_SIZE(cnt)	(sizeof (i_ntacl_t) + (cnt) * sizeof (void *))
30511332SGordon.Ross@Sun.COM 
30611332SGordon.Ross@Sun.COM static void
ifree_acl(i_ntacl_t * acl)30711332SGordon.Ross@Sun.COM ifree_acl(i_ntacl_t *acl)
30811332SGordon.Ross@Sun.COM {
30911332SGordon.Ross@Sun.COM 	i_ntace_t **acep;
31011332SGordon.Ross@Sun.COM 	size_t sz;
31111332SGordon.Ross@Sun.COM 	int i;
31211332SGordon.Ross@Sun.COM 
31311332SGordon.Ross@Sun.COM 	if (acl == NULL)
31411332SGordon.Ross@Sun.COM 		return;
31511332SGordon.Ross@Sun.COM 
31611332SGordon.Ross@Sun.COM 	acep = &acl->acl_acevec[0];
31711332SGordon.Ross@Sun.COM 	for (i = 0; i < acl->acl_acecount; i++) {
31811332SGordon.Ross@Sun.COM 		ifree_ace(*acep);
31911332SGordon.Ross@Sun.COM 		acep++;
32011332SGordon.Ross@Sun.COM 	}
32111332SGordon.Ross@Sun.COM 	sz = I_ACL_SIZE(acl->acl_acecount);
32211332SGordon.Ross@Sun.COM 	FREESZ(acl, sz);
32311332SGordon.Ross@Sun.COM }
32411332SGordon.Ross@Sun.COM 
32511332SGordon.Ross@Sun.COM static int
md_get_acl(mdchain_t * mdp,i_ntacl_t ** aclp)32611332SGordon.Ross@Sun.COM md_get_acl(mdchain_t *mdp, i_ntacl_t **aclp)
32711332SGordon.Ross@Sun.COM {
32811332SGordon.Ross@Sun.COM 	i_ntacl_t *acl = NULL;
32911332SGordon.Ross@Sun.COM 	i_ntace_t **acep;
33011332SGordon.Ross@Sun.COM 	uint8_t revision;
33111332SGordon.Ross@Sun.COM 	uint16_t acl_len, acecount;
33211332SGordon.Ross@Sun.COM 	size_t aclsz;
33311332SGordon.Ross@Sun.COM 	int i, error;
33411332SGordon.Ross@Sun.COM 
33511332SGordon.Ross@Sun.COM 	if ((error = md_get_uint8(mdp, &revision)) != 0)
33611332SGordon.Ross@Sun.COM 		return (error);
33711564SGordon.Ross@Sun.COM 	if ((error = md_get_uint8(mdp, NULL)) != 0) /* pad1 */
33811332SGordon.Ross@Sun.COM 		return (error);
33911332SGordon.Ross@Sun.COM 	if ((error = md_get_uint16le(mdp, &acl_len)) != 0)
34011332SGordon.Ross@Sun.COM 		return (error);
34111332SGordon.Ross@Sun.COM 	if ((error = md_get_uint16le(mdp, &acecount)) != 0)
34211332SGordon.Ross@Sun.COM 		return (error);
34311564SGordon.Ross@Sun.COM 	if ((error = md_get_uint16le(mdp, NULL)) != 0) /* pad2 */
34411332SGordon.Ross@Sun.COM 		return (error);
34511332SGordon.Ross@Sun.COM 
34611332SGordon.Ross@Sun.COM 	aclsz = I_ACL_SIZE(acecount);
34711332SGordon.Ross@Sun.COM 	if ((acl = MALLOC(aclsz)) == NULL)
34811332SGordon.Ross@Sun.COM 		return (ENOMEM);
34911332SGordon.Ross@Sun.COM 	bzero(acl, aclsz);
35011332SGordon.Ross@Sun.COM 	acl->acl_revision = revision;
35111332SGordon.Ross@Sun.COM 	acl->acl_acecount = acecount;
35211332SGordon.Ross@Sun.COM 
35311332SGordon.Ross@Sun.COM 	acep = &acl->acl_acevec[0];
35411332SGordon.Ross@Sun.COM 	for (i = 0; i < acl->acl_acecount; i++) {
35511332SGordon.Ross@Sun.COM 		ERRCHK(md_get_ace(mdp, acep));
35611332SGordon.Ross@Sun.COM 		acep++;
35711332SGordon.Ross@Sun.COM 	}
35811332SGordon.Ross@Sun.COM 	/*
35911332SGordon.Ross@Sun.COM 	 * There may be more data here, but
36011332SGordon.Ross@Sun.COM 	 * the caller takes care of that.
36111332SGordon.Ross@Sun.COM 	 */
36211332SGordon.Ross@Sun.COM 
36311332SGordon.Ross@Sun.COM 	/* Success! */
36411332SGordon.Ross@Sun.COM 	*aclp = acl;
36511332SGordon.Ross@Sun.COM 	return (0);
36611332SGordon.Ross@Sun.COM 
36711332SGordon.Ross@Sun.COM errout:
36811332SGordon.Ross@Sun.COM 	ifree_acl(acl);
36911332SGordon.Ross@Sun.COM 	return (error);
37011332SGordon.Ross@Sun.COM }
37111332SGordon.Ross@Sun.COM 
37211332SGordon.Ross@Sun.COM static int
mb_put_acl(mbchain_t * mbp,i_ntacl_t * acl)37311332SGordon.Ross@Sun.COM mb_put_acl(mbchain_t *mbp, i_ntacl_t *acl)
37411332SGordon.Ross@Sun.COM {
37511332SGordon.Ross@Sun.COM 	i_ntace_t **acep;
37611332SGordon.Ross@Sun.COM 	uint16_t acl_len, *acl_len_p;
37711332SGordon.Ross@Sun.COM 	int i, cnt0, error;
37811332SGordon.Ross@Sun.COM 
37911332SGordon.Ross@Sun.COM 	cnt0 = mbp->mb_count;
38011332SGordon.Ross@Sun.COM 
38111332SGordon.Ross@Sun.COM 	ERRCHK(mb_put_uint8(mbp, acl->acl_revision));
38211332SGordon.Ross@Sun.COM 	ERRCHK(mb_put_uint8(mbp, 0)); /* pad1 */
38311332SGordon.Ross@Sun.COM 	acl_len_p = mb_reserve(mbp, sizeof (*acl_len_p));
38411332SGordon.Ross@Sun.COM 	if (acl_len_p == NULL) {
38511332SGordon.Ross@Sun.COM 		error = ENOMEM;
38611332SGordon.Ross@Sun.COM 		goto errout;
38711332SGordon.Ross@Sun.COM 	}
38811332SGordon.Ross@Sun.COM 	ERRCHK(mb_put_uint16le(mbp, acl->acl_acecount));
38911332SGordon.Ross@Sun.COM 	ERRCHK(mb_put_uint16le(mbp, 0)); /* pad2 */
39011332SGordon.Ross@Sun.COM 
39111332SGordon.Ross@Sun.COM 	acep = &acl->acl_acevec[0];
39211332SGordon.Ross@Sun.COM 	for (i = 0; i < acl->acl_acecount; i++) {
39311332SGordon.Ross@Sun.COM 		ERRCHK(mb_put_ace(mbp, *acep));
39411332SGordon.Ross@Sun.COM 		acep++;
39511332SGordon.Ross@Sun.COM 	}
39611332SGordon.Ross@Sun.COM 
39711332SGordon.Ross@Sun.COM 	/* Fill in acl_len_p */
39811332SGordon.Ross@Sun.COM 	acl_len = mbp->mb_count - cnt0;
39911332SGordon.Ross@Sun.COM 	*acl_len_p = htoles(acl_len);
40011332SGordon.Ross@Sun.COM 
40111332SGordon.Ross@Sun.COM 	/* Success! */
40211332SGordon.Ross@Sun.COM 	return (0);
40311332SGordon.Ross@Sun.COM 
40411332SGordon.Ross@Sun.COM errout:
40511332SGordon.Ross@Sun.COM 	return (error);
40611332SGordon.Ross@Sun.COM }
40711332SGordon.Ross@Sun.COM 
40811332SGordon.Ross@Sun.COM 
40911332SGordon.Ross@Sun.COM /*
41011332SGordon.Ross@Sun.COM  * Security Descriptor
41111332SGordon.Ross@Sun.COM  */
41211332SGordon.Ross@Sun.COM void
smbfs_acl_free_sd(i_ntsd_t * sd)41311332SGordon.Ross@Sun.COM smbfs_acl_free_sd(i_ntsd_t *sd)
41411332SGordon.Ross@Sun.COM {
41511332SGordon.Ross@Sun.COM 
41611332SGordon.Ross@Sun.COM 	if (sd == NULL)
41711332SGordon.Ross@Sun.COM 		return;
41811332SGordon.Ross@Sun.COM 
41911332SGordon.Ross@Sun.COM 	ifree_sid(sd->sd_owner);
42011332SGordon.Ross@Sun.COM 	ifree_sid(sd->sd_group);
42111332SGordon.Ross@Sun.COM 	ifree_acl(sd->sd_sacl);
42211332SGordon.Ross@Sun.COM 	ifree_acl(sd->sd_dacl);
42311332SGordon.Ross@Sun.COM 
42411332SGordon.Ross@Sun.COM 	FREESZ(sd, sizeof (*sd));
42511332SGordon.Ross@Sun.COM }
42611332SGordon.Ross@Sun.COM 
42711332SGordon.Ross@Sun.COM /*
42811332SGordon.Ross@Sun.COM  * Import a raw SD (mb chain) into "internal" form.
42911332SGordon.Ross@Sun.COM  * (like "absolute" form per. NT docs)
43011332SGordon.Ross@Sun.COM  * Returns allocated data in sdp
43111332SGordon.Ross@Sun.COM  *
43211332SGordon.Ross@Sun.COM  * Note: does NOT consume all the mdp data, so the
43311332SGordon.Ross@Sun.COM  * caller has to take care of that if necessary.
43411332SGordon.Ross@Sun.COM  */
43511332SGordon.Ross@Sun.COM int
md_get_ntsd(mdchain_t * mdp,i_ntsd_t ** sdp)43611332SGordon.Ross@Sun.COM md_get_ntsd(mdchain_t *mdp, i_ntsd_t **sdp)
43711332SGordon.Ross@Sun.COM {
43811332SGordon.Ross@Sun.COM 	i_ntsd_t *sd = NULL;
43911332SGordon.Ross@Sun.COM 	mdchain_t top_md, tmp_md;
44011332SGordon.Ross@Sun.COM 	uint32_t owneroff, groupoff, sacloff, dacloff;
44111332SGordon.Ross@Sun.COM 	int error;
44211332SGordon.Ross@Sun.COM 
44311332SGordon.Ross@Sun.COM 	if ((sd = MALLOC(sizeof (*sd))) == NULL)
44411332SGordon.Ross@Sun.COM 		return (ENOMEM);
44511332SGordon.Ross@Sun.COM 	bzero(sd, sizeof (*sd));
44611332SGordon.Ross@Sun.COM 
44711332SGordon.Ross@Sun.COM 	/*
44811332SGordon.Ross@Sun.COM 	 * Offsets below are relative to this point,
44911332SGordon.Ross@Sun.COM 	 * so save the mdp state for use below.
45011332SGordon.Ross@Sun.COM 	 */
45111332SGordon.Ross@Sun.COM 	top_md = *mdp;
45211332SGordon.Ross@Sun.COM 
45311332SGordon.Ross@Sun.COM 	ERRCHK(md_get_uint8(mdp, &sd->sd_revision));
45411332SGordon.Ross@Sun.COM 	ERRCHK(md_get_uint8(mdp, &sd->sd_rmctl));
45511332SGordon.Ross@Sun.COM 	ERRCHK(md_get_uint16le(mdp, &sd->sd_flags));
45611332SGordon.Ross@Sun.COM 	ERRCHK(md_get_uint32le(mdp, &owneroff));
45711332SGordon.Ross@Sun.COM 	ERRCHK(md_get_uint32le(mdp, &groupoff));
45811332SGordon.Ross@Sun.COM 	ERRCHK(md_get_uint32le(mdp, &sacloff));
45911332SGordon.Ross@Sun.COM 	ERRCHK(md_get_uint32le(mdp, &dacloff));
46011332SGordon.Ross@Sun.COM 
46111332SGordon.Ross@Sun.COM 	/*
46211564SGordon.Ross@Sun.COM 	 * The SD is "self-relative" on the wire,
46311564SGordon.Ross@Sun.COM 	 * but not after this decodes it.
46411564SGordon.Ross@Sun.COM 	 */
46511564SGordon.Ross@Sun.COM 	sd->sd_flags &= ~SD_SELF_RELATIVE;
46611564SGordon.Ross@Sun.COM 
46711564SGordon.Ross@Sun.COM 	/*
46811332SGordon.Ross@Sun.COM 	 * For each section make a temporary copy of the
46911332SGordon.Ross@Sun.COM 	 * top_md state, advance to the given offset, and
47011332SGordon.Ross@Sun.COM 	 * pass that to the lower md_get_xxx functions.
47111332SGordon.Ross@Sun.COM 	 * These could be marshalled in any order, but
47211332SGordon.Ross@Sun.COM 	 * are normally found in the order shown here.
47311332SGordon.Ross@Sun.COM 	 */
47411332SGordon.Ross@Sun.COM 	if (sacloff) {
47511332SGordon.Ross@Sun.COM 		tmp_md = top_md;
47611332SGordon.Ross@Sun.COM 		md_get_mem(&tmp_md, NULL, sacloff, MB_MSYSTEM);
47711332SGordon.Ross@Sun.COM 		ERRCHK(md_get_acl(&tmp_md, &sd->sd_sacl));
47811332SGordon.Ross@Sun.COM 	}
47911332SGordon.Ross@Sun.COM 	if (dacloff) {
48011332SGordon.Ross@Sun.COM 		tmp_md = top_md;
48111332SGordon.Ross@Sun.COM 		md_get_mem(&tmp_md, NULL, dacloff, MB_MSYSTEM);
48211332SGordon.Ross@Sun.COM 		ERRCHK(md_get_acl(&tmp_md, &sd->sd_dacl));
48311332SGordon.Ross@Sun.COM 	}
48411332SGordon.Ross@Sun.COM 	if (owneroff) {
48511332SGordon.Ross@Sun.COM 		tmp_md = top_md;
48611332SGordon.Ross@Sun.COM 		md_get_mem(&tmp_md, NULL, owneroff, MB_MSYSTEM);
48711332SGordon.Ross@Sun.COM 		ERRCHK(md_get_sid(&tmp_md, &sd->sd_owner));
48811332SGordon.Ross@Sun.COM 	}
48911332SGordon.Ross@Sun.COM 	if (groupoff) {
49011332SGordon.Ross@Sun.COM 		tmp_md = top_md;
49111332SGordon.Ross@Sun.COM 		md_get_mem(&tmp_md, NULL, groupoff, MB_MSYSTEM);
49211332SGordon.Ross@Sun.COM 		ERRCHK(md_get_sid(&tmp_md, &sd->sd_group));
49311332SGordon.Ross@Sun.COM 	}
49411332SGordon.Ross@Sun.COM 
49511332SGordon.Ross@Sun.COM 	/* Success! */
49611332SGordon.Ross@Sun.COM 	*sdp = sd;
49711332SGordon.Ross@Sun.COM 	return (0);
49811332SGordon.Ross@Sun.COM 
49911332SGordon.Ross@Sun.COM errout:
50011332SGordon.Ross@Sun.COM 	smbfs_acl_free_sd(sd);
50111332SGordon.Ross@Sun.COM 	return (error);
50211332SGordon.Ross@Sun.COM }
50311332SGordon.Ross@Sun.COM 
50411332SGordon.Ross@Sun.COM /*
50511332SGordon.Ross@Sun.COM  * Export an "internal" SD into an raw SD (mb chain).
50611332SGordon.Ross@Sun.COM  * (a.k.a "self-relative" form per. NT docs)
50711332SGordon.Ross@Sun.COM  * Returns allocated mbchain in mbp.
50811332SGordon.Ross@Sun.COM  */
50911332SGordon.Ross@Sun.COM int
mb_put_ntsd(mbchain_t * mbp,i_ntsd_t * sd)51011332SGordon.Ross@Sun.COM mb_put_ntsd(mbchain_t *mbp, i_ntsd_t *sd)
51111332SGordon.Ross@Sun.COM {
51211332SGordon.Ross@Sun.COM 	uint32_t *owneroffp, *groupoffp, *sacloffp, *dacloffp;
51311332SGordon.Ross@Sun.COM 	uint32_t owneroff, groupoff, sacloff, dacloff;
51411564SGordon.Ross@Sun.COM 	uint16_t flags;
51511332SGordon.Ross@Sun.COM 	int cnt0, error;
51611332SGordon.Ross@Sun.COM 
51711332SGordon.Ross@Sun.COM 	cnt0 = mbp->mb_count;
51811332SGordon.Ross@Sun.COM 	owneroff = groupoff = sacloff = dacloff = 0;
51911332SGordon.Ross@Sun.COM 
52011564SGordon.Ross@Sun.COM 	/* The SD is "self-relative" on the wire. */
52111564SGordon.Ross@Sun.COM 	flags = sd->sd_flags | SD_SELF_RELATIVE;
52211564SGordon.Ross@Sun.COM 
52311332SGordon.Ross@Sun.COM 	ERRCHK(mb_put_uint8(mbp, sd->sd_revision));
52411332SGordon.Ross@Sun.COM 	ERRCHK(mb_put_uint8(mbp, sd->sd_rmctl));
52511564SGordon.Ross@Sun.COM 	ERRCHK(mb_put_uint16le(mbp, flags));
52611332SGordon.Ross@Sun.COM 
52711332SGordon.Ross@Sun.COM 	owneroffp = mb_reserve(mbp, sizeof (*owneroffp));
52811332SGordon.Ross@Sun.COM 	groupoffp = mb_reserve(mbp, sizeof (*groupoffp));
52911332SGordon.Ross@Sun.COM 	sacloffp  = mb_reserve(mbp, sizeof (*sacloffp));
53011332SGordon.Ross@Sun.COM 	dacloffp  = mb_reserve(mbp, sizeof (*dacloffp));
53111332SGordon.Ross@Sun.COM 	if (owneroffp == NULL || groupoffp == NULL ||
53211332SGordon.Ross@Sun.COM 	    sacloffp == NULL || dacloffp == NULL) {
53311332SGordon.Ross@Sun.COM 		error = ENOMEM;
53411332SGordon.Ross@Sun.COM 		goto errout;
53511332SGordon.Ross@Sun.COM 	}
53611332SGordon.Ross@Sun.COM 
53711332SGordon.Ross@Sun.COM 	/*
53811332SGordon.Ross@Sun.COM 	 * These could be marshalled in any order, but
53911332SGordon.Ross@Sun.COM 	 * are normally found in the order shown here.
54011332SGordon.Ross@Sun.COM 	 */
54111332SGordon.Ross@Sun.COM 	if (sd->sd_sacl) {
54211332SGordon.Ross@Sun.COM 		sacloff = mbp->mb_count - cnt0;
54311332SGordon.Ross@Sun.COM 		ERRCHK(mb_put_acl(mbp, sd->sd_sacl));
54411332SGordon.Ross@Sun.COM 	}
54511332SGordon.Ross@Sun.COM 	if (sd->sd_dacl) {
54611332SGordon.Ross@Sun.COM 		dacloff = mbp->mb_count - cnt0;
54711332SGordon.Ross@Sun.COM 		ERRCHK(mb_put_acl(mbp, sd->sd_dacl));
54811332SGordon.Ross@Sun.COM 	}
54911332SGordon.Ross@Sun.COM 	if (sd->sd_owner) {
55011332SGordon.Ross@Sun.COM 		owneroff = mbp->mb_count - cnt0;
55111332SGordon.Ross@Sun.COM 		ERRCHK(mb_put_sid(mbp, sd->sd_owner));
55211332SGordon.Ross@Sun.COM 	}
55311332SGordon.Ross@Sun.COM 	if (sd->sd_group) {
55411332SGordon.Ross@Sun.COM 		groupoff = mbp->mb_count - cnt0;
55511332SGordon.Ross@Sun.COM 		ERRCHK(mb_put_sid(mbp, sd->sd_group));
55611332SGordon.Ross@Sun.COM 	}
55711332SGordon.Ross@Sun.COM 
55811332SGordon.Ross@Sun.COM 	/* Fill in the offsets */
55911332SGordon.Ross@Sun.COM 	*owneroffp = htolel(owneroff);
56011332SGordon.Ross@Sun.COM 	*groupoffp = htolel(groupoff);
56111332SGordon.Ross@Sun.COM 	*sacloffp  = htolel(sacloff);
56211332SGordon.Ross@Sun.COM 	*dacloffp  = htolel(dacloff);
56311332SGordon.Ross@Sun.COM 
56411332SGordon.Ross@Sun.COM 	/* Success! */
56511332SGordon.Ross@Sun.COM 	return (0);
56611332SGordon.Ross@Sun.COM 
56711332SGordon.Ross@Sun.COM errout:
56811332SGordon.Ross@Sun.COM 	return (error);
56911332SGordon.Ross@Sun.COM }
57011332SGordon.Ross@Sun.COM 
57111564SGordon.Ross@Sun.COM /*
57211564SGordon.Ross@Sun.COM  * ================================================================
57311564SGordon.Ross@Sun.COM  * Support for ACL fetch, including conversions
57411564SGordon.Ross@Sun.COM  * from Windows ACLs to NFSv4-style ACLs.
57511564SGordon.Ross@Sun.COM  * ================================================================
57611564SGordon.Ross@Sun.COM  */
57711564SGordon.Ross@Sun.COM 
57811564SGordon.Ross@Sun.COM #define	GENERIC_RIGHTS_MASK \
57911564SGordon.Ross@Sun.COM 	(GENERIC_RIGHT_READ_ACCESS | GENERIC_RIGHT_WRITE_ACCESS |\
58011564SGordon.Ross@Sun.COM 	GENERIC_RIGHT_EXECUTE_ACCESS | GENERIC_RIGHT_ALL_ACCESS)
58111332SGordon.Ross@Sun.COM 
58211332SGordon.Ross@Sun.COM /*
58311564SGordon.Ross@Sun.COM  * Table for converting NT GENERIC_RIGHT_... to specific rights
58411564SGordon.Ross@Sun.COM  * appropriate for objects of type file.
58511332SGordon.Ross@Sun.COM  */
58611564SGordon.Ross@Sun.COM struct gen2fsr {
58711564SGordon.Ross@Sun.COM 	uint32_t	gf_generic;
58811564SGordon.Ross@Sun.COM 	uint32_t	gf_specific;
58911564SGordon.Ross@Sun.COM };
59011564SGordon.Ross@Sun.COM static const struct gen2fsr
59111564SGordon.Ross@Sun.COM smbfs_gen2fsr[] = {
59211564SGordon.Ross@Sun.COM 	{
59311564SGordon.Ross@Sun.COM 		GENERIC_RIGHT_READ_ACCESS,
59411564SGordon.Ross@Sun.COM 		STD_RIGHT_SYNCHRONIZE_ACCESS |
59511564SGordon.Ross@Sun.COM 		STD_RIGHT_READ_CONTROL_ACCESS |
59611564SGordon.Ross@Sun.COM 		SA_RIGHT_FILE_READ_ATTRIBUTES |
59711564SGordon.Ross@Sun.COM 		SA_RIGHT_FILE_READ_EA |
59811564SGordon.Ross@Sun.COM 		SA_RIGHT_FILE_READ_DATA },
59911564SGordon.Ross@Sun.COM 	{
60011564SGordon.Ross@Sun.COM 		GENERIC_RIGHT_WRITE_ACCESS,
60111564SGordon.Ross@Sun.COM 		STD_RIGHT_SYNCHRONIZE_ACCESS |
60211564SGordon.Ross@Sun.COM 		STD_RIGHT_READ_CONTROL_ACCESS |
60311564SGordon.Ross@Sun.COM 		SA_RIGHT_FILE_WRITE_ATTRIBUTES |
60411564SGordon.Ross@Sun.COM 		SA_RIGHT_FILE_WRITE_EA |
60511564SGordon.Ross@Sun.COM 		SA_RIGHT_FILE_APPEND_DATA |
60611564SGordon.Ross@Sun.COM 		SA_RIGHT_FILE_WRITE_DATA },
60711564SGordon.Ross@Sun.COM 	{
60811564SGordon.Ross@Sun.COM 		GENERIC_RIGHT_EXECUTE_ACCESS,
60911564SGordon.Ross@Sun.COM 		STD_RIGHT_SYNCHRONIZE_ACCESS |
61011564SGordon.Ross@Sun.COM 		STD_RIGHT_READ_CONTROL_ACCESS |
61111564SGordon.Ross@Sun.COM 		SA_RIGHT_FILE_READ_ATTRIBUTES |
61211564SGordon.Ross@Sun.COM 		SA_RIGHT_FILE_EXECUTE },
61311564SGordon.Ross@Sun.COM 	{
61411564SGordon.Ross@Sun.COM 		GENERIC_RIGHT_ALL_ACCESS,
61511564SGordon.Ross@Sun.COM 		STD_RIGHT_SYNCHRONIZE_ACCESS |
61611564SGordon.Ross@Sun.COM 		STD_RIGHT_WRITE_OWNER_ACCESS |
61711564SGordon.Ross@Sun.COM 		STD_RIGHT_WRITE_DAC_ACCESS |
61811564SGordon.Ross@Sun.COM 		STD_RIGHT_READ_CONTROL_ACCESS |
61911564SGordon.Ross@Sun.COM 		STD_RIGHT_DELETE_ACCESS |
62011564SGordon.Ross@Sun.COM 		SA_RIGHT_FILE_ALL_ACCESS },
62111564SGordon.Ross@Sun.COM 	{ 0, 0 }
62211564SGordon.Ross@Sun.COM };
62311332SGordon.Ross@Sun.COM 
62411564SGordon.Ross@Sun.COM /*
62511564SGordon.Ross@Sun.COM  * Table for translating ZFS ACE flags to NT ACE flags.
62611564SGordon.Ross@Sun.COM  * The low four bits are the same, but not others.
62711564SGordon.Ross@Sun.COM  */
62811564SGordon.Ross@Sun.COM struct zaf2naf {
62911564SGordon.Ross@Sun.COM 	uint16_t	za_flag;
63011564SGordon.Ross@Sun.COM 	uint8_t		na_flag;
63111564SGordon.Ross@Sun.COM };
63211564SGordon.Ross@Sun.COM static const struct zaf2naf
63311564SGordon.Ross@Sun.COM smbfs_zaf2naf[] = {
63411564SGordon.Ross@Sun.COM 	{ ACE_FILE_INHERIT_ACE,		OBJECT_INHERIT_ACE_FLAG },
63511564SGordon.Ross@Sun.COM 	{ ACE_DIRECTORY_INHERIT_ACE,	CONTAINER_INHERIT_ACE_FLAG },
63611564SGordon.Ross@Sun.COM 	{ ACE_NO_PROPAGATE_INHERIT_ACE,	NO_PROPAGATE_INHERIT_ACE_FLAG },
63711564SGordon.Ross@Sun.COM 	{ ACE_INHERIT_ONLY_ACE,		INHERIT_ONLY_ACE_FLAG },
63811564SGordon.Ross@Sun.COM 	{ ACE_INHERITED_ACE,		INHERITED_ACE_FLAG },
63911564SGordon.Ross@Sun.COM 	{ ACE_SUCCESSFUL_ACCESS_ACE_FLAG, SUCCESSFUL_ACCESS_ACE_FLAG },
64011564SGordon.Ross@Sun.COM 	{ ACE_FAILED_ACCESS_ACE_FLAG,	FAILED_ACCESS_ACE_FLAG },
64111564SGordon.Ross@Sun.COM 	{ 0, 0 }
64211564SGordon.Ross@Sun.COM };
64311332SGordon.Ross@Sun.COM 
64411332SGordon.Ross@Sun.COM /*
64511332SGordon.Ross@Sun.COM  * Convert an NT SID to a string. Optionally return the
64611332SGordon.Ross@Sun.COM  * last sub-authority (or "relative ID" -- RID) in *ridp
64711332SGordon.Ross@Sun.COM  * and truncate the output string after the domain part.
64811332SGordon.Ross@Sun.COM  * If ridp==NULL, the output string is the whole SID,
64911332SGordon.Ross@Sun.COM  * including both the domain and RID.
65011332SGordon.Ross@Sun.COM  *
65111332SGordon.Ross@Sun.COM  * Return length written, or -1 on error.
65211332SGordon.Ross@Sun.COM  */
65311332SGordon.Ross@Sun.COM int
smbfs_sid2str(i_ntsid_t * sid,char * obuf,size_t osz,uint32_t * ridp)65411332SGordon.Ross@Sun.COM smbfs_sid2str(i_ntsid_t *sid,
65511332SGordon.Ross@Sun.COM 	char *obuf, size_t osz, uint32_t *ridp)
65611332SGordon.Ross@Sun.COM {
65711332SGordon.Ross@Sun.COM 	char *s = obuf;
65811332SGordon.Ross@Sun.COM 	uint64_t auth = 0;
65911332SGordon.Ross@Sun.COM 	uint_t i, n;
66011332SGordon.Ross@Sun.COM 	uint32_t subs, *ip;
66111332SGordon.Ross@Sun.COM 
66211332SGordon.Ross@Sun.COM 	n = snprintf(s, osz, "S-%u", sid->sid_revision);
66311332SGordon.Ross@Sun.COM 	if (n > osz)
66411332SGordon.Ross@Sun.COM 		return (-1);
66511332SGordon.Ross@Sun.COM 	s += n; osz -= n;
66611332SGordon.Ross@Sun.COM 
66711332SGordon.Ross@Sun.COM 	for (i = 0; i < 6; i++)
66811332SGordon.Ross@Sun.COM 		auth = (auth << 8) | sid->sid_authority[i];
66911332SGordon.Ross@Sun.COM 	n = snprintf(s, osz, "-%llu", (u_longlong_t)auth);
67011332SGordon.Ross@Sun.COM 	if (n > osz)
67111332SGordon.Ross@Sun.COM 		return (-1);
67211332SGordon.Ross@Sun.COM 	s += n; osz -= n;
67311332SGordon.Ross@Sun.COM 
67411332SGordon.Ross@Sun.COM 	subs = sid->sid_subauthcount;
67511332SGordon.Ross@Sun.COM 	if (subs < 1 || subs > 15)
67611332SGordon.Ross@Sun.COM 		return (-1);
67711332SGordon.Ross@Sun.COM 	if (ridp)
67811332SGordon.Ross@Sun.COM 		subs--;
67911332SGordon.Ross@Sun.COM 
68011332SGordon.Ross@Sun.COM 	ip = &sid->sid_subauthvec[0];
68111332SGordon.Ross@Sun.COM 	for (; subs; subs--, ip++) {
68211332SGordon.Ross@Sun.COM 		n = snprintf(s, osz, "-%u", *ip);
68311332SGordon.Ross@Sun.COM 		if (n > osz)
68411332SGordon.Ross@Sun.COM 			return (-1);
68511332SGordon.Ross@Sun.COM 		s += n; osz -= n;
68611332SGordon.Ross@Sun.COM 	}
68711332SGordon.Ross@Sun.COM 	if (ridp)
68811332SGordon.Ross@Sun.COM 		*ridp = *ip;
68911332SGordon.Ross@Sun.COM 
69011332SGordon.Ross@Sun.COM 	/* LINTED E_PTRDIFF_OVERFLOW */
69111332SGordon.Ross@Sun.COM 	return (s - obuf);
69211332SGordon.Ross@Sun.COM }
69311332SGordon.Ross@Sun.COM 
69411332SGordon.Ross@Sun.COM /*
69511332SGordon.Ross@Sun.COM  * Our interface to the idmap service.
69611332SGordon.Ross@Sun.COM  *
69711332SGordon.Ross@Sun.COM  * The idmap API is _almost_ the same between
69811332SGordon.Ross@Sun.COM  * kernel and user-level.  But not quite...
69911332SGordon.Ross@Sun.COM  * Hope this improves readability below.
70011332SGordon.Ross@Sun.COM  */
70111332SGordon.Ross@Sun.COM #ifdef	_KERNEL
70211332SGordon.Ross@Sun.COM 
70311564SGordon.Ross@Sun.COM #define	I_getuidbysid(GH, SPP, RID, UIDP, SP) \
70411564SGordon.Ross@Sun.COM 	kidmap_batch_getuidbysid(GH, SPP, RID, UIDP, SP)
70511564SGordon.Ross@Sun.COM 
70611564SGordon.Ross@Sun.COM #define	I_getgidbysid(GH, SPP, RID, GIDP, SP) \
70711564SGordon.Ross@Sun.COM 	kidmap_batch_getgidbysid(GH, SPP, RID, GIDP, SP)
70811564SGordon.Ross@Sun.COM 
70911564SGordon.Ross@Sun.COM #define	I_getpidbysid(GH, SPP, RID, PIDP, ISUP, SP) \
71011332SGordon.Ross@Sun.COM 	kidmap_batch_getpidbysid(GH, SPP, RID, PIDP, ISUP, SP)
71111564SGordon.Ross@Sun.COM 
71211564SGordon.Ross@Sun.COM #define	I_getmappings kidmap_get_mappings
71311332SGordon.Ross@Sun.COM 
71411332SGordon.Ross@Sun.COM #else /* _KERNEL */
71511332SGordon.Ross@Sun.COM 
71611564SGordon.Ross@Sun.COM #define	I_getuidbysid(GH, SPP, RID, UIDP, SP) \
71711564SGordon.Ross@Sun.COM 	idmap_get_uidbysid(GH, SPP, RID, 0, UIDP, SP)
71811564SGordon.Ross@Sun.COM 
71911564SGordon.Ross@Sun.COM #define	I_getgidbysid(GH, SPP, RID, GIDP, SP) \
72011564SGordon.Ross@Sun.COM 	idmap_get_gidbysid(GH, SPP, RID, 0, GIDP, SP)
72111564SGordon.Ross@Sun.COM 
72211564SGordon.Ross@Sun.COM #define	I_getpidbysid(GH, SPP, RID, PIDP, ISUP, SP) \
72311332SGordon.Ross@Sun.COM 	idmap_get_pidbysid(GH, SPP, RID, 0, PIDP, ISUP, SP)
72411564SGordon.Ross@Sun.COM 
72511564SGordon.Ross@Sun.COM #define	I_getmappings idmap_get_mappings
72611332SGordon.Ross@Sun.COM 
72711332SGordon.Ross@Sun.COM #endif /* _KERNEL */
72811332SGordon.Ross@Sun.COM 
72911332SGordon.Ross@Sun.COM 
73011332SGordon.Ross@Sun.COM /*
73111564SGordon.Ross@Sun.COM  * The idmap request types, chosen so they also
73211564SGordon.Ross@Sun.COM  * match the values returned in mi_isuser.
73311564SGordon.Ross@Sun.COM  */
73411564SGordon.Ross@Sun.COM #define	IDM_TYPE_ANY	-1
73511564SGordon.Ross@Sun.COM #define	IDM_TYPE_GROUP	0
73611564SGordon.Ross@Sun.COM #define	IDM_TYPE_USER	1
73711564SGordon.Ross@Sun.COM 
73811564SGordon.Ross@Sun.COM /*
73911564SGordon.Ross@Sun.COM  * A sentinel value for mi_isuser (below) to indicate
74011332SGordon.Ross@Sun.COM  * that the SID is the well-known "Everyone" (S-1-1-0).
74111332SGordon.Ross@Sun.COM  * The idmap library only uses -1, 0, 1, so this value
74211332SGordon.Ross@Sun.COM  * is arbitrary but must not overlap w/ idmap values.
74311332SGordon.Ross@Sun.COM  * XXX: Could use a way for idmap to tell us when
74411332SGordon.Ross@Sun.COM  * it recognizes this well-known SID.
74511332SGordon.Ross@Sun.COM  */
74611564SGordon.Ross@Sun.COM #define	IDM_EVERYONE	11
74711564SGordon.Ross@Sun.COM 
74811564SGordon.Ross@Sun.COM struct mapinfo2uid {
74911564SGordon.Ross@Sun.COM 	uid_t	mi_uid; /* or gid, or pid */
75011564SGordon.Ross@Sun.COM 	int	mi_isuser; /* IDM_TYPE */
75111564SGordon.Ross@Sun.COM 	idmap_stat mi_status;
75211564SGordon.Ross@Sun.COM };
75311332SGordon.Ross@Sun.COM 
75411332SGordon.Ross@Sun.COM /*
75511332SGordon.Ross@Sun.COM  * Build an idmap request.  Cleanup is
75611332SGordon.Ross@Sun.COM  * handled by the caller (error or not)
75711332SGordon.Ross@Sun.COM  */
75811332SGordon.Ross@Sun.COM static int
mkrq_idmap_sid2ux(idmap_get_handle_t * idmap_gh,struct mapinfo2uid * mip,i_ntsid_t * sid,int req_type)75911332SGordon.Ross@Sun.COM mkrq_idmap_sid2ux(
76011332SGordon.Ross@Sun.COM 	idmap_get_handle_t *idmap_gh,
76111564SGordon.Ross@Sun.COM 	struct mapinfo2uid *mip,
76211332SGordon.Ross@Sun.COM 	i_ntsid_t *sid,
76311564SGordon.Ross@Sun.COM 	int req_type)
76411332SGordon.Ross@Sun.COM {
76511564SGordon.Ross@Sun.COM 	char strbuf[256];
76611564SGordon.Ross@Sun.COM 	char *sid_prefix;
76711332SGordon.Ross@Sun.COM 	uint32_t	rid;
76811332SGordon.Ross@Sun.COM 	idmap_stat	idms;
76911332SGordon.Ross@Sun.COM 
77011564SGordon.Ross@Sun.COM 	if (smbfs_sid2str(sid, strbuf, sizeof (strbuf), &rid) < 0)
77111332SGordon.Ross@Sun.COM 		return (EINVAL);
77211564SGordon.Ross@Sun.COM 	sid_prefix = strbuf;
77311332SGordon.Ross@Sun.COM 
77411332SGordon.Ross@Sun.COM 	/*
77511332SGordon.Ross@Sun.COM 	 * Give the "Everyone" group special treatment.
77611332SGordon.Ross@Sun.COM 	 */
77711332SGordon.Ross@Sun.COM 	if (strcmp(sid_prefix, "S-1-1") == 0 && rid == 0) {
77811332SGordon.Ross@Sun.COM 		/* This is "Everyone" */
77911332SGordon.Ross@Sun.COM 		mip->mi_uid = (uid_t)-1;
78011564SGordon.Ross@Sun.COM 		mip->mi_isuser = IDM_EVERYONE;
78111332SGordon.Ross@Sun.COM 		mip->mi_status = 0;
78211332SGordon.Ross@Sun.COM 		return (0);
78311332SGordon.Ross@Sun.COM 	}
78411332SGordon.Ross@Sun.COM 
78511564SGordon.Ross@Sun.COM 	switch (req_type) {
78611564SGordon.Ross@Sun.COM 
78711564SGordon.Ross@Sun.COM 	case IDM_TYPE_USER:
78811564SGordon.Ross@Sun.COM 		mip->mi_isuser = req_type;
78911564SGordon.Ross@Sun.COM 		idms = I_getuidbysid(idmap_gh, sid_prefix, rid,
79011564SGordon.Ross@Sun.COM 		    &mip->mi_uid, &mip->mi_status);
79111564SGordon.Ross@Sun.COM 		break;
79211564SGordon.Ross@Sun.COM 
79311564SGordon.Ross@Sun.COM 	case IDM_TYPE_GROUP:
79411564SGordon.Ross@Sun.COM 		mip->mi_isuser = req_type;
79511564SGordon.Ross@Sun.COM 		idms = I_getgidbysid(idmap_gh, sid_prefix, rid,
79611564SGordon.Ross@Sun.COM 		    &mip->mi_uid, &mip->mi_status);
79711564SGordon.Ross@Sun.COM 		break;
79811564SGordon.Ross@Sun.COM 
79911564SGordon.Ross@Sun.COM 	case IDM_TYPE_ANY:
80011564SGordon.Ross@Sun.COM 		idms = I_getpidbysid(idmap_gh, sid_prefix, rid,
80111564SGordon.Ross@Sun.COM 		    &mip->mi_uid, &mip->mi_isuser, &mip->mi_status);
80211564SGordon.Ross@Sun.COM 		break;
80311564SGordon.Ross@Sun.COM 
80411564SGordon.Ross@Sun.COM 	default:
80511564SGordon.Ross@Sun.COM 		idms = IDMAP_ERR_OTHER;
80611564SGordon.Ross@Sun.COM 		break;
80711564SGordon.Ross@Sun.COM 	}
80811564SGordon.Ross@Sun.COM 
80911332SGordon.Ross@Sun.COM 	if (idms != IDMAP_SUCCESS)
81011332SGordon.Ross@Sun.COM 		return (EINVAL);
81111332SGordon.Ross@Sun.COM 
81211332SGordon.Ross@Sun.COM 	return (0);
81311332SGordon.Ross@Sun.COM }
81411332SGordon.Ross@Sun.COM 
81511564SGordon.Ross@Sun.COM /*
81611564SGordon.Ross@Sun.COM  * Convert an NT ACE to a ZFS ACE.
81711564SGordon.Ross@Sun.COM  * ACE type was already validated.
81811564SGordon.Ross@Sun.COM  */
81911332SGordon.Ross@Sun.COM static void
ntace2zace(ace_t * zacep,i_ntace_t * ntace,struct mapinfo2uid * mip)82011564SGordon.Ross@Sun.COM ntace2zace(ace_t *zacep, i_ntace_t *ntace, struct mapinfo2uid *mip)
82111332SGordon.Ross@Sun.COM {
82211564SGordon.Ross@Sun.COM 	const struct zaf2naf *znaf;
82311564SGordon.Ross@Sun.COM 	uid_t zwho;
82411332SGordon.Ross@Sun.COM 	uint32_t zamask;
82511564SGordon.Ross@Sun.COM 	uint16_t zflags;
82611332SGordon.Ross@Sun.COM 
82711332SGordon.Ross@Sun.COM 	/*
82811564SGordon.Ross@Sun.COM 	 * Set the "ID type" flags in the ZFS ace flags.
82911332SGordon.Ross@Sun.COM 	 */
83011332SGordon.Ross@Sun.COM 	zflags = 0;
83111564SGordon.Ross@Sun.COM 	switch (mip->mi_isuser) {
83211564SGordon.Ross@Sun.COM 	case IDM_EVERYONE:
83311564SGordon.Ross@Sun.COM 		zflags = ACE_EVERYONE;
83411564SGordon.Ross@Sun.COM 		zwho = (uid_t)-1;
83511564SGordon.Ross@Sun.COM 		break;
83611332SGordon.Ross@Sun.COM 
83711564SGordon.Ross@Sun.COM 	case IDM_TYPE_GROUP: /* it's a GID */
83811564SGordon.Ross@Sun.COM 		zflags = ACE_IDENTIFIER_GROUP;
83911564SGordon.Ross@Sun.COM 		zwho = mip->mi_uid;
84011564SGordon.Ross@Sun.COM 		break;
84111332SGordon.Ross@Sun.COM 
84211332SGordon.Ross@Sun.COM 	default:
84311564SGordon.Ross@Sun.COM 	case IDM_TYPE_USER: /* it's a UID */
84411564SGordon.Ross@Sun.COM 		zflags = 0;
84511564SGordon.Ross@Sun.COM 		zwho = mip->mi_uid;
84611332SGordon.Ross@Sun.COM 		break;
84711332SGordon.Ross@Sun.COM 	}
84811332SGordon.Ross@Sun.COM 
84911332SGordon.Ross@Sun.COM 	/*
85011564SGordon.Ross@Sun.COM 	 * Translate NT ACE flags to ZFS ACE flags.
85111332SGordon.Ross@Sun.COM 	 */
85211564SGordon.Ross@Sun.COM 	for (znaf = smbfs_zaf2naf; znaf->za_flag; znaf++)
85311564SGordon.Ross@Sun.COM 		if (ntace->ace_hdr.ace_flags & znaf->na_flag)
85411564SGordon.Ross@Sun.COM 			zflags |= znaf->za_flag;
85511332SGordon.Ross@Sun.COM 
85611332SGordon.Ross@Sun.COM 	/*
85711564SGordon.Ross@Sun.COM 	 * The "normal" access mask bits are the same, but
85811564SGordon.Ross@Sun.COM 	 * if the ACE has any GENERIC_RIGHT_... convert those
85911564SGordon.Ross@Sun.COM 	 * to specific rights.  GENERIC bits are rarely seen,
86011564SGordon.Ross@Sun.COM 	 * but reportedly can happen with inherit-only ACEs.
86111332SGordon.Ross@Sun.COM 	 */
86211564SGordon.Ross@Sun.COM 	zamask = ntace->ace_v2.ace_rights & ACE_ALL_PERMS;
86311564SGordon.Ross@Sun.COM 	if (ntace->ace_v2.ace_rights & GENERIC_RIGHTS_MASK) {
86411564SGordon.Ross@Sun.COM 		const struct gen2fsr *gf;
86511564SGordon.Ross@Sun.COM 		for (gf = smbfs_gen2fsr; gf->gf_generic; gf++)
86611564SGordon.Ross@Sun.COM 			if (ntace->ace_v2.ace_rights & gf->gf_generic)
86711564SGordon.Ross@Sun.COM 				zamask |= gf->gf_specific;
86811332SGordon.Ross@Sun.COM 	}
86911332SGordon.Ross@Sun.COM 
87011332SGordon.Ross@Sun.COM 	/*
87111332SGordon.Ross@Sun.COM 	 * Fill in the ZFS-style ACE
87211332SGordon.Ross@Sun.COM 	 */
87311564SGordon.Ross@Sun.COM 	zacep->a_who = zwho;
87411332SGordon.Ross@Sun.COM 	zacep->a_access_mask = zamask;
87511332SGordon.Ross@Sun.COM 	zacep->a_flags = zflags;
87611564SGordon.Ross@Sun.COM 	zacep->a_type = ntace->ace_hdr.ace_type;
87711332SGordon.Ross@Sun.COM }
87811332SGordon.Ross@Sun.COM 
87911332SGordon.Ross@Sun.COM /*
88011332SGordon.Ross@Sun.COM  * Convert an internal SD to a ZFS-style ACL.
88111332SGordon.Ross@Sun.COM  * Note optional args: vsa/acl, uidp, gidp.
88211564SGordon.Ross@Sun.COM  *
88311564SGordon.Ross@Sun.COM  * This makes two passes over the SD, the first building a
88411564SGordon.Ross@Sun.COM  * "batch" request for idmap with results in mapinfo, the
88511564SGordon.Ross@Sun.COM  * second building a ZFS-style ACL using the idmap results.
88611332SGordon.Ross@Sun.COM  */
88711332SGordon.Ross@Sun.COM int
smbfs_acl_sd2zfs(i_ntsd_t * sd,vsecattr_t * acl_info,uid_t * uidp,gid_t * gidp)88811332SGordon.Ross@Sun.COM smbfs_acl_sd2zfs(
88911332SGordon.Ross@Sun.COM 	i_ntsd_t *sd,
89011332SGordon.Ross@Sun.COM #ifdef	_KERNEL
89111332SGordon.Ross@Sun.COM 	vsecattr_t *acl_info,
89211332SGordon.Ross@Sun.COM #else /* _KERNEL */
89311332SGordon.Ross@Sun.COM 	acl_t *acl_info,
89411332SGordon.Ross@Sun.COM #endif /* _KERNEL */
89511332SGordon.Ross@Sun.COM 	uid_t *uidp, gid_t *gidp)
89611332SGordon.Ross@Sun.COM {
89711564SGordon.Ross@Sun.COM 	struct mapinfo2uid *mip, *mapinfo = NULL;
89811332SGordon.Ross@Sun.COM 	int error, i, mapcnt, zacecnt, zacl_size;
89911564SGordon.Ross@Sun.COM 	ace_t *zacep0, *zacep;
90011564SGordon.Ross@Sun.COM 	uid_t own_uid = (uid_t)-1;
90111564SGordon.Ross@Sun.COM 	gid_t own_gid = (gid_t)-1;
90211332SGordon.Ross@Sun.COM 	i_ntacl_t *ntacl;
90311332SGordon.Ross@Sun.COM 	i_ntace_t **ntacep;
90411332SGordon.Ross@Sun.COM 	idmap_get_handle_t *idmap_gh = NULL;
90511332SGordon.Ross@Sun.COM 	idmap_stat	idms;
90611332SGordon.Ross@Sun.COM 
90711332SGordon.Ross@Sun.COM 	/*
90811332SGordon.Ross@Sun.COM 	 * sanity checks
90911332SGordon.Ross@Sun.COM 	 */
91011564SGordon.Ross@Sun.COM 	if (acl_info) {
91111332SGordon.Ross@Sun.COM #ifndef	_KERNEL
91211332SGordon.Ross@Sun.COM 		if (acl_info->acl_type != ACE_T ||
91311332SGordon.Ross@Sun.COM 		    acl_info->acl_aclp != NULL ||
91411332SGordon.Ross@Sun.COM 		    acl_info->acl_entry_size != sizeof (ace_t))
91511332SGordon.Ross@Sun.COM 			return (EINVAL);
91611564SGordon.Ross@Sun.COM #endif /* _KERNEL */
91711564SGordon.Ross@Sun.COM 		if ((sd->sd_flags & SD_DACL_PRESENT) == 0)
91811564SGordon.Ross@Sun.COM 			return (EINVAL);
91911332SGordon.Ross@Sun.COM 	}
92011332SGordon.Ross@Sun.COM 
92111332SGordon.Ross@Sun.COM 	/*
92211564SGordon.Ross@Sun.COM 	 * How many SID mappings will we need?
92311332SGordon.Ross@Sun.COM 	 */
92411332SGordon.Ross@Sun.COM 	mapcnt = 0;
92511332SGordon.Ross@Sun.COM 	if (sd->sd_owner)
92611332SGordon.Ross@Sun.COM 		mapcnt++;
92711332SGordon.Ross@Sun.COM 	if (sd->sd_group)
92811332SGordon.Ross@Sun.COM 		mapcnt++;
92911564SGordon.Ross@Sun.COM 	if ((sd->sd_flags & SD_SACL_PRESENT) &&
93011564SGordon.Ross@Sun.COM 	    (sd->sd_sacl != NULL))
93111332SGordon.Ross@Sun.COM 		mapcnt += sd->sd_sacl->acl_acecount;
93211564SGordon.Ross@Sun.COM 	if ((sd->sd_flags & SD_DACL_PRESENT) &&
93311564SGordon.Ross@Sun.COM 	    (sd->sd_dacl != NULL))
93411332SGordon.Ross@Sun.COM 		mapcnt += sd->sd_dacl->acl_acecount;
93511564SGordon.Ross@Sun.COM 	if (mapcnt == 0) {
93611564SGordon.Ross@Sun.COM 		/*
93711564SGordon.Ross@Sun.COM 		 * We have a NULL DACL, SACL, and don't
93811564SGordon.Ross@Sun.COM 		 * have an owner or group, so there's no
93911564SGordon.Ross@Sun.COM 		 * idmap work to do.  This is very rare,
94011564SGordon.Ross@Sun.COM 		 * so rather than complicate things below,
94111564SGordon.Ross@Sun.COM 		 * pretend we need one mapping slot.
94211564SGordon.Ross@Sun.COM 		 */
94311564SGordon.Ross@Sun.COM 		mapcnt = 1;
94411564SGordon.Ross@Sun.COM 	}
94511332SGordon.Ross@Sun.COM 
94611332SGordon.Ross@Sun.COM 	mapinfo = MALLOC(mapcnt * sizeof (*mapinfo));
94711332SGordon.Ross@Sun.COM 	if (mapinfo == NULL) {
94811332SGordon.Ross@Sun.COM 		error = ENOMEM;
94911332SGordon.Ross@Sun.COM 		goto errout;
95011332SGordon.Ross@Sun.COM 	}
95111332SGordon.Ross@Sun.COM 	bzero(mapinfo, mapcnt * sizeof (*mapinfo));
95211332SGordon.Ross@Sun.COM 
95311332SGordon.Ross@Sun.COM 
95411332SGordon.Ross@Sun.COM 	/*
95511564SGordon.Ross@Sun.COM 	 * Get an imap "batch" request handle.
95611332SGordon.Ross@Sun.COM 	 */
95711332SGordon.Ross@Sun.COM #ifdef	_KERNEL
95811332SGordon.Ross@Sun.COM 	idmap_gh = kidmap_get_create(curproc->p_zone);
95911332SGordon.Ross@Sun.COM #else /* _KERNEL */
960*12914SJoyce.McIntosh@Sun.COM 	idms = idmap_get_create(&idmap_gh);
96111332SGordon.Ross@Sun.COM 	if (idms != IDMAP_SUCCESS) {
96211332SGordon.Ross@Sun.COM 		error = ENOTACTIVE;
96311332SGordon.Ross@Sun.COM 		goto errout;
96411332SGordon.Ross@Sun.COM 	}
96511332SGordon.Ross@Sun.COM #endif /* _KERNEL */
96611332SGordon.Ross@Sun.COM 
96711564SGordon.Ross@Sun.COM 	/*
96811564SGordon.Ross@Sun.COM 	 * Build our request to the idmap deamon,
96911564SGordon.Ross@Sun.COM 	 * getting Unix IDs for every SID.
97011564SGordon.Ross@Sun.COM 	 */
97111332SGordon.Ross@Sun.COM 	mip = mapinfo;
97211332SGordon.Ross@Sun.COM 	if (sd->sd_owner) {
97311564SGordon.Ross@Sun.COM 		error = mkrq_idmap_sid2ux(idmap_gh, mip,
97411564SGordon.Ross@Sun.COM 		    sd->sd_owner, IDM_TYPE_USER);
97511332SGordon.Ross@Sun.COM 		if (error)
97611332SGordon.Ross@Sun.COM 			goto errout;
97711332SGordon.Ross@Sun.COM 		mip++;
97811332SGordon.Ross@Sun.COM 	}
97911332SGordon.Ross@Sun.COM 	if (sd->sd_group) {
98011564SGordon.Ross@Sun.COM 		error = mkrq_idmap_sid2ux(idmap_gh, mip,
98111564SGordon.Ross@Sun.COM 		    sd->sd_group, IDM_TYPE_GROUP);
98211332SGordon.Ross@Sun.COM 		if (error)
98311332SGordon.Ross@Sun.COM 			goto errout;
98411332SGordon.Ross@Sun.COM 		mip++;
98511332SGordon.Ross@Sun.COM 	}
98611564SGordon.Ross@Sun.COM 	if ((sd->sd_flags & SD_SACL_PRESENT) &&
98711564SGordon.Ross@Sun.COM 	    (sd->sd_sacl != NULL)) {
98811332SGordon.Ross@Sun.COM 		ntacl = sd->sd_sacl;
98911332SGordon.Ross@Sun.COM 		ntacep = &ntacl->acl_acevec[0];
99011332SGordon.Ross@Sun.COM 		for (i = 0; i < ntacl->acl_acecount; i++) {
99111564SGordon.Ross@Sun.COM 			error = mkrq_idmap_sid2ux(idmap_gh, mip,
99211564SGordon.Ross@Sun.COM 			    (*ntacep)->ace_v2.ace_sid, IDM_TYPE_ANY);
99311332SGordon.Ross@Sun.COM 			if (error)
99411332SGordon.Ross@Sun.COM 				goto errout;
99511332SGordon.Ross@Sun.COM 			ntacep++;
99611332SGordon.Ross@Sun.COM 			mip++;
99711332SGordon.Ross@Sun.COM 		}
99811332SGordon.Ross@Sun.COM 	}
99911564SGordon.Ross@Sun.COM 	if ((sd->sd_flags & SD_DACL_PRESENT) &&
100011564SGordon.Ross@Sun.COM 	    (sd->sd_dacl != NULL)) {
100111332SGordon.Ross@Sun.COM 		ntacl = sd->sd_dacl;
100211332SGordon.Ross@Sun.COM 		ntacep = &ntacl->acl_acevec[0];
100311332SGordon.Ross@Sun.COM 		for (i = 0; i < ntacl->acl_acecount; i++) {
100411564SGordon.Ross@Sun.COM 			error = mkrq_idmap_sid2ux(idmap_gh, mip,
100511564SGordon.Ross@Sun.COM 			    (*ntacep)->ace_v2.ace_sid, IDM_TYPE_ANY);
100611332SGordon.Ross@Sun.COM 			if (error)
100711332SGordon.Ross@Sun.COM 				goto errout;
100811332SGordon.Ross@Sun.COM 			ntacep++;
100911332SGordon.Ross@Sun.COM 			mip++;
101011332SGordon.Ross@Sun.COM 		}
101111332SGordon.Ross@Sun.COM 	}
101211332SGordon.Ross@Sun.COM 
101311564SGordon.Ross@Sun.COM 	if (mip != mapinfo) {
101411564SGordon.Ross@Sun.COM 		idms = I_getmappings(idmap_gh);
101511564SGordon.Ross@Sun.COM 		if (idms != IDMAP_SUCCESS) {
101611564SGordon.Ross@Sun.COM 			/* creative error choice */
101711564SGordon.Ross@Sun.COM 			error = EIDRM;
101811564SGordon.Ross@Sun.COM 			goto errout;
101911564SGordon.Ross@Sun.COM 		}
102011332SGordon.Ross@Sun.COM 	}
102111332SGordon.Ross@Sun.COM 
102211332SGordon.Ross@Sun.COM 	/*
102311332SGordon.Ross@Sun.COM 	 * With any luck, we now have Unix user/group IDs
102411332SGordon.Ross@Sun.COM 	 * for every Windows SID in the security descriptor.
102511332SGordon.Ross@Sun.COM 	 * The remaining work is just format conversion.
102611332SGordon.Ross@Sun.COM 	 */
102711332SGordon.Ross@Sun.COM 	mip = mapinfo;
102811332SGordon.Ross@Sun.COM 	if (sd->sd_owner) {
102911564SGordon.Ross@Sun.COM 		own_uid = mip->mi_uid;
103011332SGordon.Ross@Sun.COM 		mip++;
103111332SGordon.Ross@Sun.COM 	}
103211332SGordon.Ross@Sun.COM 	if (sd->sd_group) {
103311564SGordon.Ross@Sun.COM 		own_gid = mip->mi_uid;
103411332SGordon.Ross@Sun.COM 		mip++;
103511332SGordon.Ross@Sun.COM 	}
103611332SGordon.Ross@Sun.COM 
103711564SGordon.Ross@Sun.COM 	if (uidp)
103811564SGordon.Ross@Sun.COM 		*uidp = own_uid;
103911564SGordon.Ross@Sun.COM 	if (gidp)
104011564SGordon.Ross@Sun.COM 		*gidp = own_gid;
104111564SGordon.Ross@Sun.COM 
104211332SGordon.Ross@Sun.COM 	if (acl_info == NULL) {
104311332SGordon.Ross@Sun.COM 		/* Caller only wanted uid/gid */
104411564SGordon.Ross@Sun.COM 		goto done;
104511332SGordon.Ross@Sun.COM 	}
104611332SGordon.Ross@Sun.COM 
104711332SGordon.Ross@Sun.COM 	/*
104811332SGordon.Ross@Sun.COM 	 * Build the ZFS-style ACL
104911564SGordon.Ross@Sun.COM 	 * First, allocate the most ZFS ACEs we'll need.
105011332SGordon.Ross@Sun.COM 	 */
105111332SGordon.Ross@Sun.COM 	zacecnt = 0;
105211564SGordon.Ross@Sun.COM 	if ((sd->sd_flags & SD_SACL_PRESENT) &&
105311564SGordon.Ross@Sun.COM 	    (sd->sd_sacl != NULL))
105411332SGordon.Ross@Sun.COM 		zacecnt += sd->sd_sacl->acl_acecount;
105511564SGordon.Ross@Sun.COM 
105611564SGordon.Ross@Sun.COM 	/* NB, have: (sd->sd_flags & SD_DACL_PRESENT) */
105711564SGordon.Ross@Sun.COM 	if ((sd->sd_dacl != NULL) &&
105811564SGordon.Ross@Sun.COM 	    (sd->sd_dacl->acl_acecount > 0)) {
105911332SGordon.Ross@Sun.COM 		zacecnt += sd->sd_dacl->acl_acecount;
106011564SGordon.Ross@Sun.COM 	} else {
106111564SGordon.Ross@Sun.COM 		/*
106211564SGordon.Ross@Sun.COM 		 * DACL is NULL or empty. Either way,
106311564SGordon.Ross@Sun.COM 		 * we'll need to add a ZFS ACE below.
106411564SGordon.Ross@Sun.COM 		 */
106511564SGordon.Ross@Sun.COM 		zacecnt++;
106611564SGordon.Ross@Sun.COM 	}
106711332SGordon.Ross@Sun.COM 	zacl_size = zacecnt * sizeof (ace_t);
106811564SGordon.Ross@Sun.COM 	zacep0 = MALLOC(zacl_size);
106911564SGordon.Ross@Sun.COM 	if (zacep0 == NULL) {
107011332SGordon.Ross@Sun.COM 		error = ENOMEM;
107111332SGordon.Ross@Sun.COM 		goto errout;
107211332SGordon.Ross@Sun.COM 	}
107311564SGordon.Ross@Sun.COM 	zacep = zacep0;
107411332SGordon.Ross@Sun.COM 
107511564SGordon.Ross@Sun.COM 	if ((sd->sd_flags & SD_SACL_PRESENT) &&
107611564SGordon.Ross@Sun.COM 	    (sd->sd_sacl != NULL)) {
107711332SGordon.Ross@Sun.COM 		ntacl = sd->sd_sacl;
107811332SGordon.Ross@Sun.COM 		ntacep = &ntacl->acl_acevec[0];
107911332SGordon.Ross@Sun.COM 		for (i = 0; i < ntacl->acl_acecount; i++) {
108011332SGordon.Ross@Sun.COM 			ntace2zace(zacep, *ntacep, mip);
108111332SGordon.Ross@Sun.COM 			zacep++;
108211332SGordon.Ross@Sun.COM 			ntacep++;
108311332SGordon.Ross@Sun.COM 			mip++;
108411332SGordon.Ross@Sun.COM 		}
108511332SGordon.Ross@Sun.COM 	}
108611564SGordon.Ross@Sun.COM 
108711564SGordon.Ross@Sun.COM 	/* NB, have: (sd->sd_flags & SD_DACL_PRESENT) */
108811564SGordon.Ross@Sun.COM 	if (sd->sd_dacl != NULL) {
108911332SGordon.Ross@Sun.COM 		ntacl = sd->sd_dacl;
109011332SGordon.Ross@Sun.COM 		ntacep = &ntacl->acl_acevec[0];
109111332SGordon.Ross@Sun.COM 		for (i = 0; i < ntacl->acl_acecount; i++) {
109211332SGordon.Ross@Sun.COM 			ntace2zace(zacep, *ntacep, mip);
109311332SGordon.Ross@Sun.COM 			zacep++;
109411332SGordon.Ross@Sun.COM 			ntacep++;
109511332SGordon.Ross@Sun.COM 			mip++;
109611332SGordon.Ross@Sun.COM 		}
109711332SGordon.Ross@Sun.COM 	}
109811564SGordon.Ross@Sun.COM 	if (sd->sd_dacl == NULL) {
109911564SGordon.Ross@Sun.COM 		/*
110011564SGordon.Ross@Sun.COM 		 * The SD has a NULL DACL.  That means
110111564SGordon.Ross@Sun.COM 		 * everyone@, full-control
110211564SGordon.Ross@Sun.COM 		 */
110311564SGordon.Ross@Sun.COM 		zacep->a_who = (uid_t)-1;
110411564SGordon.Ross@Sun.COM 		zacep->a_access_mask = ACE_ALL_PERMS;
110511564SGordon.Ross@Sun.COM 		zacep->a_flags = ACE_EVERYONE;
110611564SGordon.Ross@Sun.COM 		zacep->a_type = ACCESS_ALLOWED_ACE_TYPE;
110711564SGordon.Ross@Sun.COM 	} else if (sd->sd_dacl->acl_acecount == 0) {
110811564SGordon.Ross@Sun.COM 		/*
110911564SGordon.Ross@Sun.COM 		 * The SD has an Empty DACL.  We need
111011564SGordon.Ross@Sun.COM 		 * at least one ACE, so add one giving
111111564SGordon.Ross@Sun.COM 		 * the owner the usual implied access.
111211564SGordon.Ross@Sun.COM 		 */
111311564SGordon.Ross@Sun.COM 		zacep->a_who = (uid_t)-1;
111411564SGordon.Ross@Sun.COM 		zacep->a_access_mask = ACE_READ_ATTRIBUTES | \
111511564SGordon.Ross@Sun.COM 		    ACE_READ_ACL | ACE_WRITE_ACL;
111611564SGordon.Ross@Sun.COM 		zacep->a_flags = ACE_OWNER;
111711564SGordon.Ross@Sun.COM 		zacep->a_type = ACCESS_ALLOWED_ACE_TYPE;
111811564SGordon.Ross@Sun.COM 	}
111911332SGordon.Ross@Sun.COM 
112011564SGordon.Ross@Sun.COM #ifdef _KERNEL
112111564SGordon.Ross@Sun.COM 	acl_info->vsa_aclcnt = zacecnt;
112211564SGordon.Ross@Sun.COM 	acl_info->vsa_aclentp = zacep0;
112311564SGordon.Ross@Sun.COM 	acl_info->vsa_aclentsz = zacl_size;
112411564SGordon.Ross@Sun.COM #else	/* _KERNEL */
112511564SGordon.Ross@Sun.COM 	acl_info->acl_cnt = zacecnt;
112611564SGordon.Ross@Sun.COM 	acl_info->acl_aclp = zacep0;
112711564SGordon.Ross@Sun.COM #endif	/* _KERNEL */
112811564SGordon.Ross@Sun.COM 
112911564SGordon.Ross@Sun.COM done:
113011332SGordon.Ross@Sun.COM 	error = 0;
113111332SGordon.Ross@Sun.COM 
113211332SGordon.Ross@Sun.COM errout:
113311564SGordon.Ross@Sun.COM 	if (mapinfo != NULL)
113411332SGordon.Ross@Sun.COM 		FREESZ(mapinfo, mapcnt * sizeof (*mapinfo));
113511564SGordon.Ross@Sun.COM #ifdef	_KERNEL
113611564SGordon.Ross@Sun.COM 	if (idmap_gh != NULL)
113711564SGordon.Ross@Sun.COM 		kidmap_get_destroy(idmap_gh);
113811564SGordon.Ross@Sun.COM #else /* _KERNEL */
113911564SGordon.Ross@Sun.COM 	if (idmap_gh != NULL)
114011564SGordon.Ross@Sun.COM 		idmap_get_destroy(idmap_gh);
114111564SGordon.Ross@Sun.COM #endif /* _KERNEL */
114211332SGordon.Ross@Sun.COM 
114311332SGordon.Ross@Sun.COM 	return (error);
114411332SGordon.Ross@Sun.COM }
114511332SGordon.Ross@Sun.COM 
114611332SGordon.Ross@Sun.COM 
114711332SGordon.Ross@Sun.COM /*
114811564SGordon.Ross@Sun.COM  * ================================================================
114911564SGordon.Ross@Sun.COM  * Support for ACL store, including conversions
115011564SGordon.Ross@Sun.COM  * from NFSv4-style ACLs to Windows ACLs.
115111564SGordon.Ross@Sun.COM  * ================================================================
115211564SGordon.Ross@Sun.COM  */
115311564SGordon.Ross@Sun.COM 
115411564SGordon.Ross@Sun.COM /*
115511564SGordon.Ross@Sun.COM  * Convert a "sid-prefix" string plus RID into an NT SID.
115611564SGordon.Ross@Sun.COM  *
115711564SGordon.Ross@Sun.COM  * If successful, sets *osid and returns zero,
115811564SGordon.Ross@Sun.COM  * otherwise returns an errno value.
115911564SGordon.Ross@Sun.COM  */
116011564SGordon.Ross@Sun.COM int
smbfs_str2sid(const char * sid_prefix,uint32_t * ridp,i_ntsid_t ** osidp)116111564SGordon.Ross@Sun.COM smbfs_str2sid(const char *sid_prefix, uint32_t *ridp, i_ntsid_t **osidp)
116211564SGordon.Ross@Sun.COM {
116311564SGordon.Ross@Sun.COM 	i_ntsid_t *sid = NULL;
116411564SGordon.Ross@Sun.COM 	u_longlong_t auth = 0;
116511564SGordon.Ross@Sun.COM 	ulong_t sa;
116611564SGordon.Ross@Sun.COM 	uint8_t sacnt;
116711564SGordon.Ross@Sun.COM 	const char *p;
116811564SGordon.Ross@Sun.COM 	char *np;
116911564SGordon.Ross@Sun.COM 	size_t size;
117011564SGordon.Ross@Sun.COM 	int i;
117111564SGordon.Ross@Sun.COM 	int err;
117211564SGordon.Ross@Sun.COM 
117311564SGordon.Ross@Sun.COM 	if (sid_prefix == NULL)
117411564SGordon.Ross@Sun.COM 		return (EINVAL);
117511564SGordon.Ross@Sun.COM 
117611564SGordon.Ross@Sun.COM 	p = sid_prefix;
117711564SGordon.Ross@Sun.COM 	if (strncmp(p, "S-1-", 4) != 0)
117811564SGordon.Ross@Sun.COM 		return (EINVAL);
117911564SGordon.Ross@Sun.COM 	p += 4;
118011564SGordon.Ross@Sun.COM 
118111564SGordon.Ross@Sun.COM 	/* Parse the "authority" */
118211564SGordon.Ross@Sun.COM #ifdef	_KERNEL
118311564SGordon.Ross@Sun.COM 	err = ddi_strtoull(p, &np, 10, &auth);
118411564SGordon.Ross@Sun.COM 	if (err != 0)
118511564SGordon.Ross@Sun.COM 		return (err);
118611564SGordon.Ross@Sun.COM #else	/* _KERNEL */
118711564SGordon.Ross@Sun.COM 	auth = strtoull(p, &np, 10);
118811564SGordon.Ross@Sun.COM 	if (p == np)
118911564SGordon.Ross@Sun.COM 		return (EINVAL);
119011564SGordon.Ross@Sun.COM #endif	/* _KERNEL */
119111564SGordon.Ross@Sun.COM 
119211564SGordon.Ross@Sun.COM 	/*
119311564SGordon.Ross@Sun.COM 	 * Count the sub-authorities.  Here, np points to
119411564SGordon.Ross@Sun.COM 	 * the "-" before the first sub-authority.
119511564SGordon.Ross@Sun.COM 	 */
119611564SGordon.Ross@Sun.COM 	sacnt = 0;
119711564SGordon.Ross@Sun.COM 	for (p = np; *p; p++) {
119811564SGordon.Ross@Sun.COM 		if (*p == '-')
119911564SGordon.Ross@Sun.COM 			sacnt++;
120011564SGordon.Ross@Sun.COM 	}
120111564SGordon.Ross@Sun.COM 	if (ridp != NULL)
120211564SGordon.Ross@Sun.COM 		sacnt++;
120311564SGordon.Ross@Sun.COM 
120411564SGordon.Ross@Sun.COM 	/* Allocate the internal SID. */
120511564SGordon.Ross@Sun.COM 	size = I_SID_SIZE(sacnt);
120611564SGordon.Ross@Sun.COM 	sid = MALLOC(size);
120711564SGordon.Ross@Sun.COM 	if (sid == NULL)
120811564SGordon.Ross@Sun.COM 		return (ENOMEM);
120911564SGordon.Ross@Sun.COM 	bzero(sid, size);
121011564SGordon.Ross@Sun.COM 
121111564SGordon.Ross@Sun.COM 	/* Fill it in. */
121211564SGordon.Ross@Sun.COM 	sid->sid_revision = 1;
121311564SGordon.Ross@Sun.COM 	sid->sid_subauthcount = sacnt;
121411564SGordon.Ross@Sun.COM 	for (i = 5; i >= 0; i--) {
121511564SGordon.Ross@Sun.COM 		sid->sid_authority[i] = auth & 0xFF;
121611564SGordon.Ross@Sun.COM 		auth = auth >> 8;
121711564SGordon.Ross@Sun.COM 	}
121811564SGordon.Ross@Sun.COM 
121911564SGordon.Ross@Sun.COM 	err = EINVAL;
122011564SGordon.Ross@Sun.COM 	if (ridp != NULL)
122111564SGordon.Ross@Sun.COM 		sacnt--; /* Last SA not from string */
122211564SGordon.Ross@Sun.COM 	p = np;
122311564SGordon.Ross@Sun.COM 	for (i = 0; i < sacnt; i++) {
122411564SGordon.Ross@Sun.COM 		if (*p != '-') {
122511564SGordon.Ross@Sun.COM 			err = EINVAL;
122611564SGordon.Ross@Sun.COM 			goto out;
122711564SGordon.Ross@Sun.COM 		}
122811564SGordon.Ross@Sun.COM 		p++;
122911564SGordon.Ross@Sun.COM #ifdef	_KERNEL
123011564SGordon.Ross@Sun.COM 		err = ddi_strtoul(p, &np, 10, &sa);
123111564SGordon.Ross@Sun.COM 		if (err != 0)
123211564SGordon.Ross@Sun.COM 			goto out;
123311564SGordon.Ross@Sun.COM #else	/* _KERNEL */
123411564SGordon.Ross@Sun.COM 		sa = strtoul(p, &np, 10);
123511564SGordon.Ross@Sun.COM 		if (p == np) {
123611564SGordon.Ross@Sun.COM 			err = EINVAL;
123711564SGordon.Ross@Sun.COM 			goto out;
123811564SGordon.Ross@Sun.COM 		}
123911564SGordon.Ross@Sun.COM #endif	/* _KERNEL */
124011564SGordon.Ross@Sun.COM 		sid->sid_subauthvec[i] = (uint32_t)sa;
124111564SGordon.Ross@Sun.COM 		p = np;
124211564SGordon.Ross@Sun.COM 	}
124311564SGordon.Ross@Sun.COM 	if (*p != '\0')
124411564SGordon.Ross@Sun.COM 		goto out;
124511564SGordon.Ross@Sun.COM 	if (ridp != NULL)
124611564SGordon.Ross@Sun.COM 		sid->sid_subauthvec[i] = *ridp;
124711564SGordon.Ross@Sun.COM 	err = 0;
124811564SGordon.Ross@Sun.COM 
124911564SGordon.Ross@Sun.COM out:
125011564SGordon.Ross@Sun.COM 	if (err)
125111564SGordon.Ross@Sun.COM 		FREESZ(sid, size);
125211564SGordon.Ross@Sun.COM 	else
125311564SGordon.Ross@Sun.COM 		*osidp = sid;
125411564SGordon.Ross@Sun.COM 
125511564SGordon.Ross@Sun.COM 	return (err);
125611564SGordon.Ross@Sun.COM }
125711564SGordon.Ross@Sun.COM 
125811564SGordon.Ross@Sun.COM /*
125911564SGordon.Ross@Sun.COM  * The idmap API is _almost_ the same between
126011564SGordon.Ross@Sun.COM  * kernel and user-level.  But not quite...
126111564SGordon.Ross@Sun.COM  * Hope this improves readability below.
126211332SGordon.Ross@Sun.COM  */
126311564SGordon.Ross@Sun.COM #ifdef	_KERNEL
126411564SGordon.Ross@Sun.COM 
126511564SGordon.Ross@Sun.COM #define	I_getsidbyuid(GH, UID, SPP, RP, ST) \
126611564SGordon.Ross@Sun.COM 	kidmap_batch_getsidbyuid(GH, UID, SPP, RP, ST)
126711564SGordon.Ross@Sun.COM 
126811564SGordon.Ross@Sun.COM #define	I_getsidbygid(GH, GID, SPP, RP, ST) \
126911564SGordon.Ross@Sun.COM 	kidmap_batch_getsidbygid(GH, GID, SPP, RP, ST)
127011564SGordon.Ross@Sun.COM 
127111564SGordon.Ross@Sun.COM #else /* _KERNEL */
127211564SGordon.Ross@Sun.COM 
127311564SGordon.Ross@Sun.COM #define	I_getsidbyuid(GH, UID, SPP, RP, ST) \
127411564SGordon.Ross@Sun.COM 	idmap_get_sidbyuid(GH, UID, 0, SPP, RP, ST)
127511564SGordon.Ross@Sun.COM 
127611564SGordon.Ross@Sun.COM #define	I_getsidbygid(GH, GID, SPP, RP, ST) \
127711564SGordon.Ross@Sun.COM 	idmap_get_sidbygid(GH, GID, 0, SPP, RP, ST)
127811564SGordon.Ross@Sun.COM 
127911564SGordon.Ross@Sun.COM #endif /* _KERNEL */
128011564SGordon.Ross@Sun.COM 
128111564SGordon.Ross@Sun.COM struct mapinfo2sid {
128211564SGordon.Ross@Sun.COM 	/* Yet another kernel vs. user difference. */
128311332SGordon.Ross@Sun.COM #ifdef	_KERNEL
128411564SGordon.Ross@Sun.COM 	const char *mi_dsid;	/* domain SID */
128511332SGordon.Ross@Sun.COM #else /* _KERNEL */
128611564SGordon.Ross@Sun.COM 	char *mi_dsid;
128711332SGordon.Ross@Sun.COM #endif /* _KERNEL */
128811564SGordon.Ross@Sun.COM 	uint32_t mi_rid;	/* relative ID */
128911564SGordon.Ross@Sun.COM 	idmap_stat mi_status;
129011564SGordon.Ross@Sun.COM };
129111564SGordon.Ross@Sun.COM 
129211564SGordon.Ross@Sun.COM /*
129311564SGordon.Ross@Sun.COM  * Build an idmap request.  Cleanup is
129411564SGordon.Ross@Sun.COM  * handled by the caller (error or not)
129511564SGordon.Ross@Sun.COM  */
129611564SGordon.Ross@Sun.COM static int
mkrq_idmap_ux2sid(idmap_get_handle_t * idmap_gh,struct mapinfo2sid * mip,uid_t uid,int req_type)129711564SGordon.Ross@Sun.COM mkrq_idmap_ux2sid(
129811564SGordon.Ross@Sun.COM 	idmap_get_handle_t *idmap_gh,
129911564SGordon.Ross@Sun.COM 	struct mapinfo2sid *mip,
130011564SGordon.Ross@Sun.COM 	uid_t	uid, /* or gid */
130111564SGordon.Ross@Sun.COM 	int req_type)
130211564SGordon.Ross@Sun.COM {
130311564SGordon.Ross@Sun.COM 	idmap_stat	idms;
130411564SGordon.Ross@Sun.COM 
130511564SGordon.Ross@Sun.COM 	switch (req_type) {
130611564SGordon.Ross@Sun.COM 
130711564SGordon.Ross@Sun.COM 	case IDM_TYPE_USER:
130811564SGordon.Ross@Sun.COM 		if (uid == (uid_t)-1)
130911564SGordon.Ross@Sun.COM 			return (EINVAL);
131011564SGordon.Ross@Sun.COM 		idms = I_getsidbyuid(idmap_gh, uid,
131111564SGordon.Ross@Sun.COM 		    &mip->mi_dsid, &mip->mi_rid, &mip->mi_status);
131211564SGordon.Ross@Sun.COM 		break;
131311564SGordon.Ross@Sun.COM 
131411564SGordon.Ross@Sun.COM 	case IDM_TYPE_GROUP:
131511564SGordon.Ross@Sun.COM 		if (uid == (uid_t)-1)
131611564SGordon.Ross@Sun.COM 			return (EINVAL);
131711564SGordon.Ross@Sun.COM 		idms = I_getsidbygid(idmap_gh, uid,
131811564SGordon.Ross@Sun.COM 		    &mip->mi_dsid, &mip->mi_rid, &mip->mi_status);
131911564SGordon.Ross@Sun.COM 		break;
132011564SGordon.Ross@Sun.COM 
132111564SGordon.Ross@Sun.COM 	case IDM_EVERYONE:
132211564SGordon.Ross@Sun.COM 		mip->mi_dsid = "S-1-1";
132311564SGordon.Ross@Sun.COM 		mip->mi_rid = 0;
132411564SGordon.Ross@Sun.COM 		mip->mi_status = 0;
132511564SGordon.Ross@Sun.COM 		idms = IDMAP_SUCCESS;
132611564SGordon.Ross@Sun.COM 		break;
132711564SGordon.Ross@Sun.COM 
132811564SGordon.Ross@Sun.COM 	default:
132911564SGordon.Ross@Sun.COM 		idms = IDMAP_ERR_OTHER;
133011564SGordon.Ross@Sun.COM 		break;
133111564SGordon.Ross@Sun.COM 	}
133211564SGordon.Ross@Sun.COM 
133311564SGordon.Ross@Sun.COM 	if (idms != IDMAP_SUCCESS)
133411564SGordon.Ross@Sun.COM 		return (EINVAL);
133511564SGordon.Ross@Sun.COM 
133611564SGordon.Ross@Sun.COM 	return (0);
133711564SGordon.Ross@Sun.COM }
133811564SGordon.Ross@Sun.COM 
133911564SGordon.Ross@Sun.COM /*
134011564SGordon.Ross@Sun.COM  * Convert a ZFS ACE to an NT ACE.
134111564SGordon.Ross@Sun.COM  * ACE type was already validated.
134211564SGordon.Ross@Sun.COM  */
134311564SGordon.Ross@Sun.COM static int
zace2ntace(i_ntace_t ** ntacep,ace_t * zacep,struct mapinfo2sid * mip)134411564SGordon.Ross@Sun.COM zace2ntace(i_ntace_t **ntacep, ace_t *zacep, struct mapinfo2sid *mip)
134511564SGordon.Ross@Sun.COM {
134611564SGordon.Ross@Sun.COM 	const struct zaf2naf *znaf;
134711564SGordon.Ross@Sun.COM 	uint8_t aflags;
134811564SGordon.Ross@Sun.COM 	uint16_t alloc_size;
134911564SGordon.Ross@Sun.COM 	uint32_t rights;
135011564SGordon.Ross@Sun.COM 	i_ntace_t *ntace = NULL;
135111564SGordon.Ross@Sun.COM 	i_ntsid_t *sid = NULL;
135211564SGordon.Ross@Sun.COM 	int error;
135311564SGordon.Ross@Sun.COM 
135411564SGordon.Ross@Sun.COM 	if (mip->mi_dsid == NULL || mip->mi_status != 0) {
135511564SGordon.Ross@Sun.COM 		return (EINVAL);
135611564SGordon.Ross@Sun.COM 	}
135711564SGordon.Ross@Sun.COM 
135811564SGordon.Ross@Sun.COM 	/*
135911564SGordon.Ross@Sun.COM 	 * Translate ZFS ACE flags to NT ACE flags.
136011564SGordon.Ross@Sun.COM 	 */
136111564SGordon.Ross@Sun.COM 	aflags = 0;
136211564SGordon.Ross@Sun.COM 	for (znaf = smbfs_zaf2naf; znaf->za_flag; znaf++)
136311564SGordon.Ross@Sun.COM 		if (zacep->a_flags & znaf->za_flag)
136411564SGordon.Ross@Sun.COM 			aflags |= znaf->na_flag;
136511564SGordon.Ross@Sun.COM 
136611564SGordon.Ross@Sun.COM 	/*
136711564SGordon.Ross@Sun.COM 	 * The access rights bits are OK as-is.
136811564SGordon.Ross@Sun.COM 	 */
136911564SGordon.Ross@Sun.COM 	rights = zacep->a_access_mask;
137011564SGordon.Ross@Sun.COM 
137111564SGordon.Ross@Sun.COM 	/*
137211564SGordon.Ross@Sun.COM 	 * Make sure we can get the SID.
137311564SGordon.Ross@Sun.COM 	 * Note: allocates sid.
137411564SGordon.Ross@Sun.COM 	 */
137511564SGordon.Ross@Sun.COM 	error = smbfs_str2sid(mip->mi_dsid, &mip->mi_rid, &sid);
137611564SGordon.Ross@Sun.COM 	if (error)
137711564SGordon.Ross@Sun.COM 		return (error);
137811564SGordon.Ross@Sun.COM 
137911564SGordon.Ross@Sun.COM 	/*
138011564SGordon.Ross@Sun.COM 	 * Allocate the NT ACE and fill it in.
138111564SGordon.Ross@Sun.COM 	 */
138211564SGordon.Ross@Sun.COM 	alloc_size = sizeof (i_ntace_v2_t);
138311564SGordon.Ross@Sun.COM 	if ((ntace = MALLOC(alloc_size)) == NULL) {
138411564SGordon.Ross@Sun.COM 		ifree_sid(sid);
138511564SGordon.Ross@Sun.COM 		return (ENOMEM);
138611564SGordon.Ross@Sun.COM 	}
138711564SGordon.Ross@Sun.COM 	bzero(ntace, alloc_size);
138811564SGordon.Ross@Sun.COM 
138911564SGordon.Ross@Sun.COM 	ntace->ace_hdr.ace_type = zacep->a_type;
139011564SGordon.Ross@Sun.COM 	ntace->ace_hdr.ace_flags = aflags;
139111564SGordon.Ross@Sun.COM 	ntace->ace_hdr.ace_size = alloc_size;
139211564SGordon.Ross@Sun.COM 	ntace->ace_v2.ace_rights = rights;
139311564SGordon.Ross@Sun.COM 	ntace->ace_v2.ace_sid = sid;
139411564SGordon.Ross@Sun.COM 
139511564SGordon.Ross@Sun.COM 	*ntacep = ntace;
139611564SGordon.Ross@Sun.COM 	return (0);
139711564SGordon.Ross@Sun.COM }
139811564SGordon.Ross@Sun.COM 
139911564SGordon.Ross@Sun.COM /*
140011564SGordon.Ross@Sun.COM  * Convert a ZFS-style ACL to an internal SD.
140111564SGordon.Ross@Sun.COM  * Set owner/group too if selector indicates.
140211564SGordon.Ross@Sun.COM  * Always need to pass uid+gid, either the new
140311564SGordon.Ross@Sun.COM  * (when setting them) or existing, so that any
140411564SGordon.Ross@Sun.COM  * owner@ or group@ ACEs can be translated.
140511564SGordon.Ross@Sun.COM  *
140611564SGordon.Ross@Sun.COM  * This makes two passes over the ZFS ACL.  The first builds a
140711564SGordon.Ross@Sun.COM  * "batch" request for idmap with results in mapinfo, and the
140811564SGordon.Ross@Sun.COM  * second builds the NT SD using the idmap SID results.
140911564SGordon.Ross@Sun.COM  */
141011564SGordon.Ross@Sun.COM int
smbfs_acl_zfs2sd(vsecattr_t * acl_info,uid_t own_uid,gid_t own_gid,uint32_t selector,i_ntsd_t ** sdp)141111564SGordon.Ross@Sun.COM smbfs_acl_zfs2sd(
141211564SGordon.Ross@Sun.COM #ifdef	_KERNEL
141311564SGordon.Ross@Sun.COM 	vsecattr_t *acl_info,
141411564SGordon.Ross@Sun.COM #else /* _KERNEL */
141511564SGordon.Ross@Sun.COM 	acl_t *acl_info,
141611564SGordon.Ross@Sun.COM #endif /* _KERNEL */
141711564SGordon.Ross@Sun.COM 	uid_t own_uid,
141811564SGordon.Ross@Sun.COM 	gid_t own_gid,
141911564SGordon.Ross@Sun.COM 	uint32_t selector,
142011332SGordon.Ross@Sun.COM 	i_ntsd_t **sdp)
142111332SGordon.Ross@Sun.COM {
142211564SGordon.Ross@Sun.COM 	struct mapinfo2sid *mip, *mip_acl, *mapinfo = NULL;
142311564SGordon.Ross@Sun.COM 	int aclsz, error, i, mapcnt;
142411564SGordon.Ross@Sun.COM 	int dacl_acecnt = 0;
142511564SGordon.Ross@Sun.COM 	int sacl_acecnt = 0;
142611564SGordon.Ross@Sun.COM 	int zacecnt = 0;
142711564SGordon.Ross@Sun.COM 	ace_t *zacevec = NULL;
142811564SGordon.Ross@Sun.COM 	ace_t *zacep;
142911564SGordon.Ross@Sun.COM 	i_ntsd_t *sd = NULL;
143011564SGordon.Ross@Sun.COM 	i_ntacl_t *acl = NULL;
143111564SGordon.Ross@Sun.COM 	i_ntace_t **acep = NULL;
143211564SGordon.Ross@Sun.COM 	idmap_get_handle_t *idmap_gh = NULL;
143311564SGordon.Ross@Sun.COM 	idmap_stat	idms;
143411564SGordon.Ross@Sun.COM 
143511564SGordon.Ross@Sun.COM 	/*
143611564SGordon.Ross@Sun.COM 	 * First, get all the UID+GID to SID mappings.
143711564SGordon.Ross@Sun.COM 	 * How many?  Also sanity checks.
143811564SGordon.Ross@Sun.COM 	 */
143911564SGordon.Ross@Sun.COM 	mapcnt = 0;
144011564SGordon.Ross@Sun.COM 	if (selector & OWNER_SECURITY_INFORMATION) {
144111564SGordon.Ross@Sun.COM 		if (own_uid == (uid_t)-1)
144211564SGordon.Ross@Sun.COM 			return (EINVAL);
144311564SGordon.Ross@Sun.COM 		mapcnt++;
144411564SGordon.Ross@Sun.COM 	}
144511564SGordon.Ross@Sun.COM 	if (selector & GROUP_SECURITY_INFORMATION) {
144611564SGordon.Ross@Sun.COM 		if (own_gid == (gid_t)-1)
144711564SGordon.Ross@Sun.COM 			return (EINVAL);
144811564SGordon.Ross@Sun.COM 		mapcnt++;
144911564SGordon.Ross@Sun.COM 	}
145011564SGordon.Ross@Sun.COM 	if (selector & (DACL_SECURITY_INFORMATION |
145111564SGordon.Ross@Sun.COM 	    SACL_SECURITY_INFORMATION)) {
145211564SGordon.Ross@Sun.COM 		if (acl_info == NULL)
145311564SGordon.Ross@Sun.COM 			return (EINVAL);
145411564SGordon.Ross@Sun.COM 		if (own_uid == (uid_t)-1)
145511564SGordon.Ross@Sun.COM 			return (EINVAL);
145611564SGordon.Ross@Sun.COM 		if (own_gid == (gid_t)-1)
145711564SGordon.Ross@Sun.COM 			return (EINVAL);
145811564SGordon.Ross@Sun.COM #ifdef	_KERNEL
145911564SGordon.Ross@Sun.COM 		if ((acl_info->vsa_mask & VSA_ACE) == 0)
146011564SGordon.Ross@Sun.COM 			return (EINVAL);
146111564SGordon.Ross@Sun.COM 		zacecnt = acl_info->vsa_aclcnt;
146211564SGordon.Ross@Sun.COM 		zacevec = acl_info->vsa_aclentp;
146311564SGordon.Ross@Sun.COM #else	/* _KERNEL */
146411564SGordon.Ross@Sun.COM 		if (acl_info->acl_type != ACE_T ||
146511564SGordon.Ross@Sun.COM 		    acl_info->acl_entry_size != sizeof (ace_t))
146611564SGordon.Ross@Sun.COM 			return (EINVAL);
146711564SGordon.Ross@Sun.COM 		zacecnt = acl_info->acl_cnt;
146811564SGordon.Ross@Sun.COM 		zacevec = acl_info->acl_aclp;
146911564SGordon.Ross@Sun.COM #endif	/* _KERNEL */
147011564SGordon.Ross@Sun.COM 		if (zacecnt == 0 || zacevec == NULL)
147111564SGordon.Ross@Sun.COM 			return (EINVAL);
147211564SGordon.Ross@Sun.COM 		mapcnt += zacecnt;
147311564SGordon.Ross@Sun.COM 	}
147411564SGordon.Ross@Sun.COM 	if (mapcnt == 0)
147511564SGordon.Ross@Sun.COM 		return (EINVAL);
147611564SGordon.Ross@Sun.COM 	mapinfo = MALLOC(mapcnt * sizeof (*mapinfo));
147711564SGordon.Ross@Sun.COM 	if (mapinfo == NULL)
147811564SGordon.Ross@Sun.COM 		return (ENOMEM);
147911564SGordon.Ross@Sun.COM 	bzero(mapinfo, mapcnt * sizeof (*mapinfo));
148011564SGordon.Ross@Sun.COM 	/* no more returns until errout */
148111564SGordon.Ross@Sun.COM 
148211564SGordon.Ross@Sun.COM 	/*
148311564SGordon.Ross@Sun.COM 	 * Get an imap "batch" request handle.
148411564SGordon.Ross@Sun.COM 	 */
148511564SGordon.Ross@Sun.COM #ifdef	_KERNEL
148611564SGordon.Ross@Sun.COM 	idmap_gh = kidmap_get_create(curproc->p_zone);
148711564SGordon.Ross@Sun.COM #else /* _KERNEL */
1488*12914SJoyce.McIntosh@Sun.COM 	idms = idmap_get_create(&idmap_gh);
148911564SGordon.Ross@Sun.COM 	if (idms != IDMAP_SUCCESS) {
149011564SGordon.Ross@Sun.COM 		error = ENOTACTIVE;
149111564SGordon.Ross@Sun.COM 		goto errout;
149211564SGordon.Ross@Sun.COM 	}
149311564SGordon.Ross@Sun.COM #endif /* _KERNEL */
149411564SGordon.Ross@Sun.COM 
149511564SGordon.Ross@Sun.COM 	/*
149611564SGordon.Ross@Sun.COM 	 * Build our request to the idmap deamon,
149711564SGordon.Ross@Sun.COM 	 * getting SIDs for every Unix UID/GID.
149811564SGordon.Ross@Sun.COM 	 * Also count DACL and SACL ACEs here.
149911564SGordon.Ross@Sun.COM 	 */
150011564SGordon.Ross@Sun.COM 	mip = mapinfo;
150111564SGordon.Ross@Sun.COM 	if (selector & OWNER_SECURITY_INFORMATION) {
150211564SGordon.Ross@Sun.COM 		error = mkrq_idmap_ux2sid(idmap_gh, mip,
150311564SGordon.Ross@Sun.COM 		    own_uid, IDM_TYPE_USER);
150411564SGordon.Ross@Sun.COM 		if (error)
150511564SGordon.Ross@Sun.COM 			goto errout;
150611564SGordon.Ross@Sun.COM 		mip++;
150711564SGordon.Ross@Sun.COM 	}
150811564SGordon.Ross@Sun.COM 	if (selector & GROUP_SECURITY_INFORMATION) {
150911564SGordon.Ross@Sun.COM 		error = mkrq_idmap_ux2sid(idmap_gh, mip,
151011564SGordon.Ross@Sun.COM 		    own_gid, IDM_TYPE_GROUP);
151111564SGordon.Ross@Sun.COM 		if (error)
151211564SGordon.Ross@Sun.COM 			goto errout;
151311564SGordon.Ross@Sun.COM 		mip++;
151411564SGordon.Ross@Sun.COM 	}
151511564SGordon.Ross@Sun.COM 	if (selector & (DACL_SECURITY_INFORMATION |
151611564SGordon.Ross@Sun.COM 	    SACL_SECURITY_INFORMATION)) {
151711564SGordon.Ross@Sun.COM 		int rqtype;
151811564SGordon.Ross@Sun.COM 		uid_t uid;
151911564SGordon.Ross@Sun.COM 
152011564SGordon.Ross@Sun.COM 		zacep = zacevec;
152111564SGordon.Ross@Sun.COM 		for (i = 0; i < zacecnt; i++) {
152211564SGordon.Ross@Sun.COM 
152311564SGordon.Ross@Sun.COM 			switch (zacep->a_type) {
152411564SGordon.Ross@Sun.COM 			case ACE_ACCESS_ALLOWED_ACE_TYPE:
152511564SGordon.Ross@Sun.COM 			case ACE_ACCESS_DENIED_ACE_TYPE:
152611564SGordon.Ross@Sun.COM 				dacl_acecnt++;
152711564SGordon.Ross@Sun.COM 				break;
152811564SGordon.Ross@Sun.COM 			case ACE_SYSTEM_AUDIT_ACE_TYPE:
152911564SGordon.Ross@Sun.COM 			case ACE_SYSTEM_ALARM_ACE_TYPE:
153011564SGordon.Ross@Sun.COM 				sacl_acecnt++;
153111564SGordon.Ross@Sun.COM 				break;
153211564SGordon.Ross@Sun.COM 			/* other types todo */
153311564SGordon.Ross@Sun.COM 			}
153411564SGordon.Ross@Sun.COM 
153511564SGordon.Ross@Sun.COM 			if (zacep->a_flags & ACE_EVERYONE) {
153611564SGordon.Ross@Sun.COM 				rqtype = IDM_EVERYONE;
153711564SGordon.Ross@Sun.COM 				uid = (uid_t)-1;
153811564SGordon.Ross@Sun.COM 			} else if (zacep->a_flags & ACE_GROUP) {
153911564SGordon.Ross@Sun.COM 				/* owning group (a_who = -1) */
154011564SGordon.Ross@Sun.COM 				rqtype = IDM_TYPE_GROUP;
154111564SGordon.Ross@Sun.COM 				uid = (uid_t)own_gid;
154211564SGordon.Ross@Sun.COM 			} else if (zacep->a_flags & ACE_OWNER) {
154311564SGordon.Ross@Sun.COM 				/* owning user (a_who = -1) */
154411564SGordon.Ross@Sun.COM 				rqtype = IDM_TYPE_USER;
154511564SGordon.Ross@Sun.COM 				uid = (uid_t)own_uid;
154611564SGordon.Ross@Sun.COM 			} else if (zacep->a_flags & ACE_IDENTIFIER_GROUP) {
154711564SGordon.Ross@Sun.COM 				/* regular group */
154811564SGordon.Ross@Sun.COM 				rqtype = IDM_TYPE_GROUP;
154911564SGordon.Ross@Sun.COM 				uid = zacep->a_who;
155011564SGordon.Ross@Sun.COM 			} else {
155111564SGordon.Ross@Sun.COM 				rqtype = IDM_TYPE_USER;
155211564SGordon.Ross@Sun.COM 				uid = zacep->a_who;
155311564SGordon.Ross@Sun.COM 			}
155411564SGordon.Ross@Sun.COM 
155511564SGordon.Ross@Sun.COM 			error = mkrq_idmap_ux2sid(idmap_gh, mip, uid, rqtype);
155611564SGordon.Ross@Sun.COM 			if (error)
155711564SGordon.Ross@Sun.COM 				goto errout;
155811564SGordon.Ross@Sun.COM 			zacep++;
155911564SGordon.Ross@Sun.COM 			mip++;
156011564SGordon.Ross@Sun.COM 		}
156111564SGordon.Ross@Sun.COM 	}
156211564SGordon.Ross@Sun.COM 
156311564SGordon.Ross@Sun.COM 	idms = I_getmappings(idmap_gh);
156411564SGordon.Ross@Sun.COM 	if (idms != IDMAP_SUCCESS) {
156511564SGordon.Ross@Sun.COM 		/* creative error choice */
156611564SGordon.Ross@Sun.COM 		error = EIDRM;
156711564SGordon.Ross@Sun.COM 		goto errout;
156811564SGordon.Ross@Sun.COM 	}
156911564SGordon.Ross@Sun.COM 
157011564SGordon.Ross@Sun.COM 	/*
157111564SGordon.Ross@Sun.COM 	 * With any luck, we now have a Windows SID for
157211564SGordon.Ross@Sun.COM 	 * every Unix UID or GID in the NFS/ZFS ACL.
157311564SGordon.Ross@Sun.COM 	 * The remaining work is just format conversion,
157411564SGordon.Ross@Sun.COM 	 * memory allocation, etc.
157511564SGordon.Ross@Sun.COM 	 */
157611564SGordon.Ross@Sun.COM 	if ((sd = MALLOC(sizeof (*sd))) == NULL) {
157711564SGordon.Ross@Sun.COM 		error = ENOMEM;
157811564SGordon.Ross@Sun.COM 		goto errout;
157911564SGordon.Ross@Sun.COM 	}
158011564SGordon.Ross@Sun.COM 	bzero(sd, sizeof (*sd));
158111564SGordon.Ross@Sun.COM 	sd->sd_revision = NT_SD_REVISION;
158211564SGordon.Ross@Sun.COM 
158311564SGordon.Ross@Sun.COM 	mip = mapinfo;
158411564SGordon.Ross@Sun.COM 	if (selector & OWNER_SECURITY_INFORMATION) {
158511564SGordon.Ross@Sun.COM 		error = smbfs_str2sid(mip->mi_dsid, &mip->mi_rid,
158611564SGordon.Ross@Sun.COM 		    &sd->sd_owner);
158711564SGordon.Ross@Sun.COM 		mip++;
158811564SGordon.Ross@Sun.COM 	}
158911564SGordon.Ross@Sun.COM 	if (selector & GROUP_SECURITY_INFORMATION) {
159011564SGordon.Ross@Sun.COM 		error = smbfs_str2sid(mip->mi_dsid, &mip->mi_rid,
159111564SGordon.Ross@Sun.COM 		    &sd->sd_group);
159211564SGordon.Ross@Sun.COM 		mip++;
159311564SGordon.Ross@Sun.COM 	}
159411564SGordon.Ross@Sun.COM 
159511564SGordon.Ross@Sun.COM 	/*
159611564SGordon.Ross@Sun.COM 	 * If setting both DACL and SACL, we will
159711564SGordon.Ross@Sun.COM 	 * make two passes starting here in mapinfo.
159811564SGordon.Ross@Sun.COM 	 */
159911564SGordon.Ross@Sun.COM 	mip_acl = mip;
160011564SGordon.Ross@Sun.COM 
160111564SGordon.Ross@Sun.COM 	if (selector & DACL_SECURITY_INFORMATION) {
160211564SGordon.Ross@Sun.COM 		/*
160311564SGordon.Ross@Sun.COM 		 * Caller wants to set the DACL.
160411564SGordon.Ross@Sun.COM 		 */
160511564SGordon.Ross@Sun.COM 		aclsz = I_ACL_SIZE(dacl_acecnt);
160611564SGordon.Ross@Sun.COM 		if ((acl = MALLOC(aclsz)) == NULL) {
160711564SGordon.Ross@Sun.COM 			error = ENOMEM;
160811564SGordon.Ross@Sun.COM 			goto errout;
160911564SGordon.Ross@Sun.COM 		}
161011564SGordon.Ross@Sun.COM 		bzero(acl, aclsz);
161111564SGordon.Ross@Sun.COM 
161211564SGordon.Ross@Sun.COM 		acl->acl_revision = NT_ACL_REVISION;
161311564SGordon.Ross@Sun.COM 		acl->acl_acecount = (uint16_t)dacl_acecnt;
161411564SGordon.Ross@Sun.COM 		acep = &acl->acl_acevec[0];
161511564SGordon.Ross@Sun.COM 
161611564SGordon.Ross@Sun.COM 		/* 1st pass - scan for DACL ACE types. */
161711564SGordon.Ross@Sun.COM 		mip = mip_acl;
161811564SGordon.Ross@Sun.COM 		zacep = zacevec;
161911564SGordon.Ross@Sun.COM 		for (i = 0; i < zacecnt; i++) {
162011564SGordon.Ross@Sun.COM 
162111564SGordon.Ross@Sun.COM 			switch (zacep->a_type) {
162211564SGordon.Ross@Sun.COM 			case ACE_ACCESS_ALLOWED_ACE_TYPE:
162311564SGordon.Ross@Sun.COM 			case ACE_ACCESS_DENIED_ACE_TYPE:
162411564SGordon.Ross@Sun.COM 				error = zace2ntace(acep, zacep, mip);
162511564SGordon.Ross@Sun.COM 				if (error != 0)
162611564SGordon.Ross@Sun.COM 					goto errout;
162711564SGordon.Ross@Sun.COM 				acep++;
162811564SGordon.Ross@Sun.COM 				break;
162911564SGordon.Ross@Sun.COM 
163011564SGordon.Ross@Sun.COM 			case ACE_SYSTEM_AUDIT_ACE_TYPE:
163111564SGordon.Ross@Sun.COM 			case ACE_SYSTEM_ALARM_ACE_TYPE:
163211564SGordon.Ross@Sun.COM 				break;
163311564SGordon.Ross@Sun.COM 			/* other types todo */
163411564SGordon.Ross@Sun.COM 			}
163511564SGordon.Ross@Sun.COM 			zacep++;
163611564SGordon.Ross@Sun.COM 			mip++;
163711564SGordon.Ross@Sun.COM 		}
163811564SGordon.Ross@Sun.COM 		sd->sd_dacl = acl;
163911564SGordon.Ross@Sun.COM 		acl = NULL;
164011564SGordon.Ross@Sun.COM 		sd->sd_flags |= SD_DACL_PRESENT;
164111564SGordon.Ross@Sun.COM 	}
164211564SGordon.Ross@Sun.COM 
164311564SGordon.Ross@Sun.COM 	if (selector & SACL_SECURITY_INFORMATION) {
164411564SGordon.Ross@Sun.COM 		/*
164511564SGordon.Ross@Sun.COM 		 * Caller wants to set the SACL.
164611564SGordon.Ross@Sun.COM 		 */
164711564SGordon.Ross@Sun.COM 		aclsz = I_ACL_SIZE(sacl_acecnt);
164811564SGordon.Ross@Sun.COM 		if ((acl = MALLOC(aclsz)) == NULL) {
164911564SGordon.Ross@Sun.COM 			error = ENOMEM;
165011564SGordon.Ross@Sun.COM 			goto errout;
165111564SGordon.Ross@Sun.COM 		}
165211564SGordon.Ross@Sun.COM 		bzero(acl, aclsz);
165311564SGordon.Ross@Sun.COM 
165411564SGordon.Ross@Sun.COM 		acl->acl_revision = NT_ACL_REVISION;
165511564SGordon.Ross@Sun.COM 		acl->acl_acecount = (uint16_t)sacl_acecnt;
165611564SGordon.Ross@Sun.COM 		acep = &acl->acl_acevec[0];
165711564SGordon.Ross@Sun.COM 
165811564SGordon.Ross@Sun.COM 		/* 2nd pass - scan for SACL ACE types. */
165911564SGordon.Ross@Sun.COM 		mip = mip_acl;
166011564SGordon.Ross@Sun.COM 		zacep = zacevec;
166111564SGordon.Ross@Sun.COM 		for (i = 0; i < zacecnt; i++) {
166211564SGordon.Ross@Sun.COM 
166311564SGordon.Ross@Sun.COM 			switch (zacep->a_type) {
166411564SGordon.Ross@Sun.COM 			case ACE_ACCESS_ALLOWED_ACE_TYPE:
166511564SGordon.Ross@Sun.COM 			case ACE_ACCESS_DENIED_ACE_TYPE:
166611564SGordon.Ross@Sun.COM 				break;
166711564SGordon.Ross@Sun.COM 
166811564SGordon.Ross@Sun.COM 			case ACE_SYSTEM_AUDIT_ACE_TYPE:
166911564SGordon.Ross@Sun.COM 			case ACE_SYSTEM_ALARM_ACE_TYPE:
167011564SGordon.Ross@Sun.COM 				error = zace2ntace(acep, zacep, mip);
167111564SGordon.Ross@Sun.COM 				if (error != 0)
167211564SGordon.Ross@Sun.COM 					goto errout;
167311564SGordon.Ross@Sun.COM 				acep++;
167411564SGordon.Ross@Sun.COM 				break;
167511564SGordon.Ross@Sun.COM 			/* other types todo */
167611564SGordon.Ross@Sun.COM 			}
167711564SGordon.Ross@Sun.COM 			zacep++;
167811564SGordon.Ross@Sun.COM 			mip++;
167911564SGordon.Ross@Sun.COM 		}
168011564SGordon.Ross@Sun.COM 		sd->sd_sacl = acl;
168111564SGordon.Ross@Sun.COM 		acl = NULL;
168211564SGordon.Ross@Sun.COM 		sd->sd_flags |= SD_SACL_PRESENT;
168311564SGordon.Ross@Sun.COM 	}
168411564SGordon.Ross@Sun.COM 
168511564SGordon.Ross@Sun.COM 	*sdp = sd;
168611564SGordon.Ross@Sun.COM 	error = 0;
168711564SGordon.Ross@Sun.COM 
168811564SGordon.Ross@Sun.COM errout:
168911564SGordon.Ross@Sun.COM 	if (error != 0) {
169011564SGordon.Ross@Sun.COM 		if (acl != NULL)
169111564SGordon.Ross@Sun.COM 			ifree_acl(acl);
169211564SGordon.Ross@Sun.COM 		if (sd != NULL)
169311564SGordon.Ross@Sun.COM 			smbfs_acl_free_sd(sd);
169411564SGordon.Ross@Sun.COM 	}
169511564SGordon.Ross@Sun.COM 	if (mapinfo != NULL)
169611564SGordon.Ross@Sun.COM 		FREESZ(mapinfo, mapcnt * sizeof (*mapinfo));
169711564SGordon.Ross@Sun.COM #ifdef	_KERNEL
169811564SGordon.Ross@Sun.COM 	if (idmap_gh != NULL)
169911564SGordon.Ross@Sun.COM 		kidmap_get_destroy(idmap_gh);
170011564SGordon.Ross@Sun.COM #else /* _KERNEL */
170111564SGordon.Ross@Sun.COM 	if (idmap_gh != NULL)
170211564SGordon.Ross@Sun.COM 		idmap_get_destroy(idmap_gh);
170311564SGordon.Ross@Sun.COM #endif /* _KERNEL */
170411564SGordon.Ross@Sun.COM 
170511564SGordon.Ross@Sun.COM 	return (error);
170611332SGordon.Ross@Sun.COM }
1707