xref: /illumos-gate/usr/src/common/smbclnt/smbfs_ntacl.c (revision 78801af7286cd73dbc996d470f789e75993cf15d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
25  */
26 
27 /*
28  * ACL conversion support for smbfs
29  * (To/from NT/ZFS-style ACLs.)
30  */
31 
32 #include <sys/types.h>
33 #include <sys/errno.h>
34 #include <sys/acl.h>
35 #include <sys/byteorder.h>
36 
37 #if defined(_KERNEL) || defined(_FAKE_KERNEL)
38 
39 #include <sys/cred.h>
40 #include <sys/cmn_err.h>
41 #include <sys/kmem.h>
42 #include <sys/sunddi.h>
43 #include <sys/vnode.h>
44 #include <sys/vfs.h>
45 
46 #else	/* _KERNEL || _FAKE_KERNEL */
47 
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <strings.h>
51 
52 #endif	/* _KERNEL || _FAKE_KERNEL */
53 
54 #ifdef _KERNEL
55 #include <sys/kidmap.h>
56 #else	/* _KERNEL */
57 #include <idmap.h>
58 #endif	/* _KERNEL */
59 
60 #include <netsmb/mchain.h>
61 #include <netsmb/smb.h>
62 #include "smbfs_ntacl.h"
63 
64 #define	NT_SD_REVISION	1
65 #define	NT_ACL_REVISION	2
66 
67 #if defined(_KERNEL) || defined(_FAKE_KERNEL)
68 #define	MALLOC(size) kmem_alloc(size, KM_SLEEP)
69 #define	FREESZ(p, sz) kmem_free(p, sz)
70 #else	/* _KERNEL */
71 #define	MALLOC(size) malloc(size)
72 /*
73  * Define FREESZ() as inline function so the compiler will not
74  * trigger variable set but not used warning for sz in calling function.
75  */
76 /* ARGSUSED */
77 static inline void
78 FREESZ(void *p, size_t sz __unused)
79 {
80 	free(p);
81 }
82 #endif	/* _KERNEL */
83 
84 #define	ERRCHK(expr)	if ((error = expr) != 0) goto errout
85 
86 /*
87  * Security IDentifier (SID)
88  */
89 static void
90 ifree_sid(i_ntsid_t *sid)
91 {
92 	size_t sz;
93 
94 	if (sid == NULL)
95 		return;
96 
97 	sz = I_SID_SIZE(sid->sid_subauthcount);
98 	FREESZ(sid, sz);
99 }
100 
101 static int
102 md_get_sid(mdchain_t *mdp, i_ntsid_t **sidp)
103 {
104 	i_ntsid_t *sid = NULL;
105 	uint8_t revision, subauthcount;
106 	uint32_t *subauthp;
107 	size_t sidsz;
108 	int error, i;
109 
110 	if ((error = md_get_uint8(mdp, &revision)) != 0)
111 		return (error);
112 	if ((error = md_get_uint8(mdp, &subauthcount)) != 0)
113 		return (error);
114 
115 	sidsz = I_SID_SIZE(subauthcount);
116 
117 	if ((sid = MALLOC(sidsz)) == NULL)
118 		return (ENOMEM);
119 
120 	bzero(sid, sidsz);
121 	sid->sid_revision = revision;
122 	sid->sid_subauthcount = subauthcount;
123 	ERRCHK(md_get_mem(mdp, sid->sid_authority, 6, MB_MSYSTEM));
124 
125 	subauthp = &sid->sid_subauthvec[0];
126 	for (i = 0; i < subauthcount; i++) {
127 		ERRCHK(md_get_uint32le(mdp, subauthp));
128 		subauthp++;
129 	}
130 
131 	/* Success! */
132 	*sidp = sid;
133 	return (0);
134 
135 errout:
136 	ifree_sid(sid);
137 	return (error);
138 }
139 
140 static int
141 mb_put_sid(mbchain_t *mbp, i_ntsid_t *sid)
142 {
143 	uint32_t *subauthp;
144 	int error, i;
145 
146 	if (sid == NULL)
147 		return (EINVAL);
148 
149 	ERRCHK(mb_put_uint8(mbp, sid->sid_revision));
150 	ERRCHK(mb_put_uint8(mbp, sid->sid_subauthcount));
151 	ERRCHK(mb_put_mem(mbp, sid->sid_authority, 6, MB_MSYSTEM));
152 
153 	subauthp = &sid->sid_subauthvec[0];
154 	for (i = 0; i < sid->sid_subauthcount; i++) {
155 		ERRCHK(mb_put_uint32le(mbp, *subauthp));
156 		subauthp++;
157 	}
158 
159 	/* Success! */
160 	return (0);
161 
162 errout:
163 	return (error);
164 }
165 
166 
167 /*
168  * Access Control Entry (ACE)
169  */
170 static void
171 ifree_ace(i_ntace_t *ace)
172 {
173 
174 	if (ace == NULL)
175 		return;
176 
177 	switch (ace->ace_hdr.ace_type) {
178 	case ACCESS_ALLOWED_ACE_TYPE:
179 	case ACCESS_DENIED_ACE_TYPE:
180 	case SYSTEM_AUDIT_ACE_TYPE:
181 	case SYSTEM_ALARM_ACE_TYPE:
182 		ifree_sid(ace->ace_v2.ace_sid);
183 		FREESZ(ace, sizeof (i_ntace_v2_t));
184 		break;
185 	/* other types todo */
186 	default:
187 		break;
188 	}
189 }
190 
191 static int
192 md_get_ace(mdchain_t *mdp, i_ntace_t **acep)
193 {
194 	mdchain_t tmp_md;
195 	i_ntace_hdr_t ace_hdr;
196 	i_ntace_t *ace = NULL;
197 	uint16_t alloc_size;
198 	int error;
199 
200 	/*
201 	 * The ACE is realy variable length,
202 	 * with format determined by the type.
203 	 *
204 	 * There may also be padding after it, so
205 	 * decode it using a copy of the mdchain,
206 	 * and then consume the specified length.
207 	 */
208 	tmp_md = *mdp;
209 
210 	/* Fixed-size ACE header */
211 	ERRCHK(md_get_uint8(&tmp_md, &ace_hdr.ace_type));
212 	ERRCHK(md_get_uint8(&tmp_md, &ace_hdr.ace_flags));
213 	ERRCHK(md_get_uint16le(&tmp_md, &ace_hdr.ace_size));
214 
215 	switch (ace_hdr.ace_type) {
216 	case ACCESS_ALLOWED_ACE_TYPE:
217 	case ACCESS_DENIED_ACE_TYPE:
218 	case SYSTEM_AUDIT_ACE_TYPE:
219 	case SYSTEM_ALARM_ACE_TYPE:
220 		alloc_size = sizeof (i_ntace_v2_t);
221 		if ((ace = MALLOC(alloc_size)) == NULL)
222 			return (ENOMEM);
223 		bzero(ace, alloc_size);
224 		/* ACE header */
225 		ace->ace_hdr.ace_type = ace_hdr.ace_type;
226 		ace->ace_hdr.ace_flags = ace_hdr.ace_flags;
227 		ace->ace_hdr.ace_size = alloc_size;
228 		/* Type-specific data. */
229 		ERRCHK(md_get_uint32le(&tmp_md, &ace->ace_v2.ace_rights));
230 		ERRCHK(md_get_sid(&tmp_md, &ace->ace_v2.ace_sid));
231 		break;
232 
233 	/* other types todo */
234 	default:
235 		error = EIO;
236 		goto errout;
237 	}
238 
239 	/* Now actually consume ace_hdr.ace_size */
240 	ERRCHK(md_get_mem(mdp, NULL, ace_hdr.ace_size, MB_MSYSTEM));
241 
242 	/* Success! */
243 	*acep = ace;
244 	return (0);
245 
246 errout:
247 	ifree_ace(ace);
248 	return (error);
249 }
250 
251 static int
252 mb_put_ace(mbchain_t *mbp, i_ntace_t *ace)
253 {
254 	int cnt0, error;
255 	uint16_t ace_len, *ace_len_p;
256 
257 	if (ace == NULL)
258 		return (EINVAL);
259 
260 	cnt0 = mbp->mb_count;
261 
262 	/*
263 	 * Put the (fixed-size) ACE header
264 	 * Will fill in the length later.
265 	 */
266 	ERRCHK(mb_put_uint8(mbp, ace->ace_hdr.ace_type));
267 	ERRCHK(mb_put_uint8(mbp, ace->ace_hdr.ace_flags));
268 	ace_len_p = mb_reserve(mbp, sizeof (*ace_len_p));
269 	if (ace_len_p == NULL) {
270 		error = ENOMEM;
271 		goto errout;
272 	}
273 
274 	switch (ace->ace_hdr.ace_type) {
275 	case ACCESS_ALLOWED_ACE_TYPE:
276 	case ACCESS_DENIED_ACE_TYPE:
277 	case SYSTEM_AUDIT_ACE_TYPE:
278 	case SYSTEM_ALARM_ACE_TYPE:
279 		/* Put type-specific data. */
280 		ERRCHK(mb_put_uint32le(mbp, ace->ace_v2.ace_rights));
281 		ERRCHK(mb_put_sid(mbp, ace->ace_v2.ace_sid));
282 		break;
283 
284 	/* other types todo */
285 	default:
286 		error = EIO;
287 		goto errout;
288 	}
289 
290 	/* Fill in the (OtW) ACE length. */
291 	ace_len = mbp->mb_count - cnt0;
292 	*ace_len_p = htoles(ace_len);
293 
294 	/* Success! */
295 	return (0);
296 
297 errout:
298 	return (error);
299 }
300 
301 
302 /*
303  * Access Control List (ACL)
304  */
305 
306 /* Not an OTW structure, so size can be at our convenience. */
307 #define	I_ACL_SIZE(cnt)	(sizeof (i_ntacl_t) + (cnt) * sizeof (void *))
308 
309 static void
310 ifree_acl(i_ntacl_t *acl)
311 {
312 	i_ntace_t **acep;
313 	size_t sz;
314 	int i;
315 
316 	if (acl == NULL)
317 		return;
318 
319 	acep = &acl->acl_acevec[0];
320 	for (i = 0; i < acl->acl_acecount; i++) {
321 		ifree_ace(*acep);
322 		acep++;
323 	}
324 	sz = I_ACL_SIZE(acl->acl_acecount);
325 	FREESZ(acl, sz);
326 }
327 
328 static int
329 md_get_acl(mdchain_t *mdp, i_ntacl_t **aclp)
330 {
331 	i_ntacl_t *acl = NULL;
332 	i_ntace_t **acep;
333 	uint8_t revision;
334 	uint16_t acl_len, acecount;
335 	size_t aclsz;
336 	int i, error;
337 
338 	if ((error = md_get_uint8(mdp, &revision)) != 0)
339 		return (error);
340 	if ((error = md_get_uint8(mdp, NULL)) != 0) /* pad1 */
341 		return (error);
342 	if ((error = md_get_uint16le(mdp, &acl_len)) != 0)
343 		return (error);
344 	if ((error = md_get_uint16le(mdp, &acecount)) != 0)
345 		return (error);
346 	if ((error = md_get_uint16le(mdp, NULL)) != 0) /* pad2 */
347 		return (error);
348 
349 	aclsz = I_ACL_SIZE(acecount);
350 	if ((acl = MALLOC(aclsz)) == NULL)
351 		return (ENOMEM);
352 	bzero(acl, aclsz);
353 	acl->acl_revision = revision;
354 	acl->acl_acecount = acecount;
355 
356 	acep = &acl->acl_acevec[0];
357 	for (i = 0; i < acl->acl_acecount; i++) {
358 		ERRCHK(md_get_ace(mdp, acep));
359 		acep++;
360 	}
361 	/*
362 	 * There may be more data here, but
363 	 * the caller takes care of that.
364 	 */
365 
366 	/* Success! */
367 	*aclp = acl;
368 	return (0);
369 
370 errout:
371 	ifree_acl(acl);
372 	return (error);
373 }
374 
375 static int
376 mb_put_acl(mbchain_t *mbp, i_ntacl_t *acl)
377 {
378 	i_ntace_t **acep;
379 	uint16_t acl_len, *acl_len_p;
380 	int i, cnt0, error;
381 
382 	cnt0 = mbp->mb_count;
383 
384 	ERRCHK(mb_put_uint8(mbp, acl->acl_revision));
385 	ERRCHK(mb_put_uint8(mbp, 0)); /* pad1 */
386 	acl_len_p = mb_reserve(mbp, sizeof (*acl_len_p));
387 	if (acl_len_p == NULL) {
388 		error = ENOMEM;
389 		goto errout;
390 	}
391 	ERRCHK(mb_put_uint16le(mbp, acl->acl_acecount));
392 	ERRCHK(mb_put_uint16le(mbp, 0)); /* pad2 */
393 
394 	acep = &acl->acl_acevec[0];
395 	for (i = 0; i < acl->acl_acecount; i++) {
396 		ERRCHK(mb_put_ace(mbp, *acep));
397 		acep++;
398 	}
399 
400 	/* Fill in acl_len_p */
401 	acl_len = mbp->mb_count - cnt0;
402 	*acl_len_p = htoles(acl_len);
403 
404 	/* Success! */
405 	return (0);
406 
407 errout:
408 	return (error);
409 }
410 
411 
412 /*
413  * Security Descriptor
414  */
415 void
416 smbfs_acl_free_sd(i_ntsd_t *sd)
417 {
418 
419 	if (sd == NULL)
420 		return;
421 
422 	ifree_sid(sd->sd_owner);
423 	ifree_sid(sd->sd_group);
424 	ifree_acl(sd->sd_sacl);
425 	ifree_acl(sd->sd_dacl);
426 
427 	FREESZ(sd, sizeof (*sd));
428 }
429 
430 /*
431  * Import a raw SD (mb chain) into "internal" form.
432  * (like "absolute" form per. NT docs)
433  * Returns allocated data in sdp
434  *
435  * Note: does NOT consume all the mdp data, so the
436  * caller has to take care of that if necessary.
437  */
438 int
439 md_get_ntsd(mdchain_t *mdp, i_ntsd_t **sdp)
440 {
441 	i_ntsd_t *sd = NULL;
442 	mdchain_t top_md, tmp_md;
443 	uint32_t owneroff, groupoff, sacloff, dacloff;
444 	int error;
445 
446 	if ((sd = MALLOC(sizeof (*sd))) == NULL)
447 		return (ENOMEM);
448 	bzero(sd, sizeof (*sd));
449 
450 	/*
451 	 * Offsets below are relative to this point,
452 	 * so save the mdp state for use below.
453 	 */
454 	top_md = *mdp;
455 
456 	ERRCHK(md_get_uint8(mdp, &sd->sd_revision));
457 	ERRCHK(md_get_uint8(mdp, &sd->sd_rmctl));
458 	ERRCHK(md_get_uint16le(mdp, &sd->sd_flags));
459 	ERRCHK(md_get_uint32le(mdp, &owneroff));
460 	ERRCHK(md_get_uint32le(mdp, &groupoff));
461 	ERRCHK(md_get_uint32le(mdp, &sacloff));
462 	ERRCHK(md_get_uint32le(mdp, &dacloff));
463 
464 	/*
465 	 * The SD is "self-relative" on the wire,
466 	 * but not after this decodes it.
467 	 */
468 	sd->sd_flags &= ~SD_SELF_RELATIVE;
469 
470 	/*
471 	 * For each section make a temporary copy of the
472 	 * top_md state, advance to the given offset, and
473 	 * pass that to the lower md_get_xxx functions.
474 	 * These could be marshalled in any order, but
475 	 * are normally found in the order shown here.
476 	 */
477 	if (sacloff) {
478 		tmp_md = top_md;
479 		md_get_mem(&tmp_md, NULL, sacloff, MB_MSYSTEM);
480 		ERRCHK(md_get_acl(&tmp_md, &sd->sd_sacl));
481 	}
482 	if (dacloff) {
483 		tmp_md = top_md;
484 		md_get_mem(&tmp_md, NULL, dacloff, MB_MSYSTEM);
485 		ERRCHK(md_get_acl(&tmp_md, &sd->sd_dacl));
486 	}
487 	if (owneroff) {
488 		tmp_md = top_md;
489 		md_get_mem(&tmp_md, NULL, owneroff, MB_MSYSTEM);
490 		ERRCHK(md_get_sid(&tmp_md, &sd->sd_owner));
491 	}
492 	if (groupoff) {
493 		tmp_md = top_md;
494 		md_get_mem(&tmp_md, NULL, groupoff, MB_MSYSTEM);
495 		ERRCHK(md_get_sid(&tmp_md, &sd->sd_group));
496 	}
497 
498 	/* Success! */
499 	*sdp = sd;
500 	return (0);
501 
502 errout:
503 	smbfs_acl_free_sd(sd);
504 	return (error);
505 }
506 
507 /*
508  * Export an "internal" SD into an raw SD (mb chain).
509  * (a.k.a "self-relative" form per. NT docs)
510  * Returns allocated mbchain in mbp.
511  */
512 int
513 mb_put_ntsd(mbchain_t *mbp, i_ntsd_t *sd)
514 {
515 	uint32_t *owneroffp, *groupoffp, *sacloffp, *dacloffp;
516 	uint32_t owneroff, groupoff, sacloff, dacloff;
517 	uint16_t flags;
518 	int cnt0, error;
519 
520 	cnt0 = mbp->mb_count;
521 	owneroff = groupoff = sacloff = dacloff = 0;
522 
523 	/* The SD is "self-relative" on the wire. */
524 	flags = sd->sd_flags | SD_SELF_RELATIVE;
525 
526 	ERRCHK(mb_put_uint8(mbp, sd->sd_revision));
527 	ERRCHK(mb_put_uint8(mbp, sd->sd_rmctl));
528 	ERRCHK(mb_put_uint16le(mbp, flags));
529 
530 	owneroffp = mb_reserve(mbp, sizeof (*owneroffp));
531 	groupoffp = mb_reserve(mbp, sizeof (*groupoffp));
532 	sacloffp  = mb_reserve(mbp, sizeof (*sacloffp));
533 	dacloffp  = mb_reserve(mbp, sizeof (*dacloffp));
534 	if (owneroffp == NULL || groupoffp == NULL ||
535 	    sacloffp == NULL || dacloffp == NULL) {
536 		error = ENOMEM;
537 		goto errout;
538 	}
539 
540 	/*
541 	 * These could be marshalled in any order, but
542 	 * are normally found in the order shown here.
543 	 */
544 	if (sd->sd_sacl) {
545 		sacloff = mbp->mb_count - cnt0;
546 		ERRCHK(mb_put_acl(mbp, sd->sd_sacl));
547 	}
548 	if (sd->sd_dacl) {
549 		dacloff = mbp->mb_count - cnt0;
550 		ERRCHK(mb_put_acl(mbp, sd->sd_dacl));
551 	}
552 	if (sd->sd_owner) {
553 		owneroff = mbp->mb_count - cnt0;
554 		ERRCHK(mb_put_sid(mbp, sd->sd_owner));
555 	}
556 	if (sd->sd_group) {
557 		groupoff = mbp->mb_count - cnt0;
558 		ERRCHK(mb_put_sid(mbp, sd->sd_group));
559 	}
560 
561 	/* Fill in the offsets */
562 	*owneroffp = htolel(owneroff);
563 	*groupoffp = htolel(groupoff);
564 	*sacloffp  = htolel(sacloff);
565 	*dacloffp  = htolel(dacloff);
566 
567 	/* Success! */
568 	return (0);
569 
570 errout:
571 	return (error);
572 }
573 
574 /*
575  * ================================================================
576  * Support for ACL fetch, including conversions
577  * from Windows ACLs to NFSv4-style ACLs.
578  * ================================================================
579  */
580 
581 #define	GENERIC_RIGHTS_MASK \
582 	(GENERIC_RIGHT_READ_ACCESS | GENERIC_RIGHT_WRITE_ACCESS |\
583 	GENERIC_RIGHT_EXECUTE_ACCESS | GENERIC_RIGHT_ALL_ACCESS)
584 
585 /*
586  * Table for converting NT GENERIC_RIGHT_... to specific rights
587  * appropriate for objects of type file.
588  */
589 struct gen2fsr {
590 	uint32_t	gf_generic;
591 	uint32_t	gf_specific;
592 };
593 static const struct gen2fsr
594 smbfs_gen2fsr[] = {
595 	{
596 		GENERIC_RIGHT_READ_ACCESS,
597 		STD_RIGHT_SYNCHRONIZE_ACCESS |
598 		STD_RIGHT_READ_CONTROL_ACCESS |
599 		SA_RIGHT_FILE_READ_ATTRIBUTES |
600 		SA_RIGHT_FILE_READ_EA |
601 		SA_RIGHT_FILE_READ_DATA },
602 	{
603 		GENERIC_RIGHT_WRITE_ACCESS,
604 		STD_RIGHT_SYNCHRONIZE_ACCESS |
605 		STD_RIGHT_READ_CONTROL_ACCESS |
606 		SA_RIGHT_FILE_WRITE_ATTRIBUTES |
607 		SA_RIGHT_FILE_WRITE_EA |
608 		SA_RIGHT_FILE_APPEND_DATA |
609 		SA_RIGHT_FILE_WRITE_DATA },
610 	{
611 		GENERIC_RIGHT_EXECUTE_ACCESS,
612 		STD_RIGHT_SYNCHRONIZE_ACCESS |
613 		STD_RIGHT_READ_CONTROL_ACCESS |
614 		SA_RIGHT_FILE_READ_ATTRIBUTES |
615 		SA_RIGHT_FILE_EXECUTE },
616 	{
617 		GENERIC_RIGHT_ALL_ACCESS,
618 		STD_RIGHT_SYNCHRONIZE_ACCESS |
619 		STD_RIGHT_WRITE_OWNER_ACCESS |
620 		STD_RIGHT_WRITE_DAC_ACCESS |
621 		STD_RIGHT_READ_CONTROL_ACCESS |
622 		STD_RIGHT_DELETE_ACCESS |
623 		SA_RIGHT_FILE_ALL_ACCESS },
624 	{ 0, 0 }
625 };
626 
627 /*
628  * Table for translating ZFS ACE flags to NT ACE flags.
629  * The low four bits are the same, but not others.
630  */
631 struct zaf2naf {
632 	uint16_t	za_flag;
633 	uint8_t		na_flag;
634 };
635 static const struct zaf2naf
636 smbfs_zaf2naf[] = {
637 	{ ACE_FILE_INHERIT_ACE,		OBJECT_INHERIT_ACE_FLAG },
638 	{ ACE_DIRECTORY_INHERIT_ACE,	CONTAINER_INHERIT_ACE_FLAG },
639 	{ ACE_NO_PROPAGATE_INHERIT_ACE,	NO_PROPAGATE_INHERIT_ACE_FLAG },
640 	{ ACE_INHERIT_ONLY_ACE,		INHERIT_ONLY_ACE_FLAG },
641 	{ ACE_INHERITED_ACE,		INHERITED_ACE_FLAG },
642 	{ ACE_SUCCESSFUL_ACCESS_ACE_FLAG, SUCCESSFUL_ACCESS_ACE_FLAG },
643 	{ ACE_FAILED_ACCESS_ACE_FLAG,	FAILED_ACCESS_ACE_FLAG },
644 	{ 0, 0 }
645 };
646 
647 /*
648  * Convert an NT SID to a string. Optionally return the
649  * last sub-authority (or "relative ID" -- RID) in *ridp
650  * and truncate the output string after the domain part.
651  * If ridp==NULL, the output string is the whole SID,
652  * including both the domain and RID.
653  *
654  * Return length written, or -1 on error.
655  */
656 int
657 smbfs_sid2str(i_ntsid_t *sid,
658 	char *obuf, size_t osz, uint32_t *ridp)
659 {
660 	char *s = obuf;
661 	uint64_t auth = 0;
662 	uint_t i, n;
663 	uint32_t subs, *ip;
664 
665 	n = snprintf(s, osz, "S-%u", sid->sid_revision);
666 	if (n > osz)
667 		return (-1);
668 	s += n; osz -= n;
669 
670 	for (i = 0; i < 6; i++)
671 		auth = (auth << 8) | sid->sid_authority[i];
672 	n = snprintf(s, osz, "-%llu", (u_longlong_t)auth);
673 	if (n > osz)
674 		return (-1);
675 	s += n; osz -= n;
676 
677 	subs = sid->sid_subauthcount;
678 	if (subs < 1 || subs > 15)
679 		return (-1);
680 	if (ridp)
681 		subs--;
682 
683 	ip = &sid->sid_subauthvec[0];
684 	for (; subs; subs--, ip++) {
685 		n = snprintf(s, osz, "-%u", *ip);
686 		if (n > osz)
687 			return (-1);
688 		s += n; osz -= n;
689 	}
690 	if (ridp)
691 		*ridp = *ip;
692 
693 	/* LINTED E_PTRDIFF_OVERFLOW */
694 	return (s - obuf);
695 }
696 
697 /*
698  * Our interface to the idmap service.
699  *
700  * The idmap API is _almost_ the same between
701  * kernel and user-level.  But not quite...
702  * Hope this improves readability below.
703  */
704 #ifdef	_KERNEL
705 
706 #define	I_getuidbysid(GH, SPP, RID, UIDP, SP) \
707 	kidmap_batch_getuidbysid(GH, SPP, RID, UIDP, SP)
708 
709 #define	I_getgidbysid(GH, SPP, RID, GIDP, SP) \
710 	kidmap_batch_getgidbysid(GH, SPP, RID, GIDP, SP)
711 
712 #define	I_getpidbysid(GH, SPP, RID, PIDP, ISUP, SP) \
713 	kidmap_batch_getpidbysid(GH, SPP, RID, PIDP, ISUP, SP)
714 
715 #define	I_getmappings kidmap_get_mappings
716 
717 #else /* _KERNEL */
718 
719 #define	I_getuidbysid(GH, SPP, RID, UIDP, SP) \
720 	idmap_get_uidbysid(GH, SPP, RID, 0, UIDP, SP)
721 
722 #define	I_getgidbysid(GH, SPP, RID, GIDP, SP) \
723 	idmap_get_gidbysid(GH, SPP, RID, 0, GIDP, SP)
724 
725 #define	I_getpidbysid(GH, SPP, RID, PIDP, ISUP, SP) \
726 	idmap_get_pidbysid(GH, SPP, RID, 0, PIDP, ISUP, SP)
727 
728 #define	I_getmappings idmap_get_mappings
729 
730 #endif /* _KERNEL */
731 
732 
733 /*
734  * The idmap request types, chosen so they also
735  * match the values returned in mi_isuser.
736  */
737 #define	IDM_TYPE_ANY	-1
738 #define	IDM_TYPE_GROUP	0
739 #define	IDM_TYPE_USER	1
740 
741 /*
742  * A sentinel value for mi_isuser (below) to indicate
743  * that the SID is the well-known "Everyone" (S-1-1-0).
744  * The idmap library only uses -1, 0, 1, so this value
745  * is arbitrary but must not overlap w/ idmap values.
746  * XXX: Could use a way for idmap to tell us when
747  * it recognizes this well-known SID.
748  */
749 #define	IDM_EVERYONE	11
750 
751 struct mapinfo2uid {
752 	uid_t	mi_uid; /* or gid, or pid */
753 	int	mi_isuser; /* IDM_TYPE */
754 	idmap_stat mi_status;
755 };
756 
757 /*
758  * Build an idmap request.  Cleanup is
759  * handled by the caller (error or not)
760  */
761 static int
762 mkrq_idmap_sid2ux(
763 	idmap_get_handle_t *idmap_gh,
764 	struct mapinfo2uid *mip,
765 	i_ntsid_t *sid,
766 	int req_type)
767 {
768 	char strbuf[256];
769 	char *sid_prefix;
770 	uint32_t	rid;
771 	idmap_stat	idms;
772 
773 	if (smbfs_sid2str(sid, strbuf, sizeof (strbuf), &rid) < 0)
774 		return (EINVAL);
775 	sid_prefix = strbuf;
776 
777 	/*
778 	 * Give the "Everyone" group special treatment.
779 	 */
780 	if (strcmp(sid_prefix, "S-1-1") == 0 && rid == 0) {
781 		/* This is "Everyone" */
782 		mip->mi_uid = (uid_t)-1;
783 		mip->mi_isuser = IDM_EVERYONE;
784 		mip->mi_status = 0;
785 		return (0);
786 	}
787 
788 	switch (req_type) {
789 
790 	case IDM_TYPE_USER:
791 		mip->mi_isuser = req_type;
792 		idms = I_getuidbysid(idmap_gh, sid_prefix, rid,
793 		    &mip->mi_uid, &mip->mi_status);
794 		break;
795 
796 	case IDM_TYPE_GROUP:
797 		mip->mi_isuser = req_type;
798 		idms = I_getgidbysid(idmap_gh, sid_prefix, rid,
799 		    &mip->mi_uid, &mip->mi_status);
800 		break;
801 
802 	case IDM_TYPE_ANY:
803 		idms = I_getpidbysid(idmap_gh, sid_prefix, rid,
804 		    &mip->mi_uid, &mip->mi_isuser, &mip->mi_status);
805 		break;
806 
807 	default:
808 		idms = IDMAP_ERR_OTHER;
809 		break;
810 	}
811 
812 	if (idms != IDMAP_SUCCESS)
813 		return (EINVAL);
814 
815 	return (0);
816 }
817 
818 /*
819  * Convert an NT ACE to a ZFS ACE.
820  * ACE type was already validated.
821  */
822 static void
823 ntace2zace(ace_t *zacep, i_ntace_t *ntace, struct mapinfo2uid *mip)
824 {
825 	const struct zaf2naf *znaf;
826 	uid_t zwho;
827 	uint32_t zamask;
828 	uint16_t zflags;
829 
830 	/*
831 	 * Set the "ID type" flags in the ZFS ace flags.
832 	 */
833 	zflags = 0;
834 	switch (mip->mi_isuser) {
835 	case IDM_EVERYONE:
836 		zflags = ACE_EVERYONE;
837 		zwho = (uid_t)-1;
838 		break;
839 
840 	case IDM_TYPE_GROUP: /* it's a GID */
841 		zflags = ACE_IDENTIFIER_GROUP;
842 		zwho = mip->mi_uid;
843 		break;
844 
845 	default:
846 	case IDM_TYPE_USER: /* it's a UID */
847 		zflags = 0;
848 		zwho = mip->mi_uid;
849 		break;
850 	}
851 
852 	/*
853 	 * Translate NT ACE flags to ZFS ACE flags.
854 	 */
855 	for (znaf = smbfs_zaf2naf; znaf->za_flag; znaf++)
856 		if (ntace->ace_hdr.ace_flags & znaf->na_flag)
857 			zflags |= znaf->za_flag;
858 
859 	/*
860 	 * The "normal" access mask bits are the same, but
861 	 * if the ACE has any GENERIC_RIGHT_... convert those
862 	 * to specific rights.  GENERIC bits are rarely seen,
863 	 * but reportedly can happen with inherit-only ACEs.
864 	 */
865 	zamask = ntace->ace_v2.ace_rights & ACE_ALL_PERMS;
866 	if (ntace->ace_v2.ace_rights & GENERIC_RIGHTS_MASK) {
867 		const struct gen2fsr *gf;
868 		for (gf = smbfs_gen2fsr; gf->gf_generic; gf++)
869 			if (ntace->ace_v2.ace_rights & gf->gf_generic)
870 				zamask |= gf->gf_specific;
871 	}
872 
873 	/*
874 	 * Fill in the ZFS-style ACE
875 	 */
876 	zacep->a_who = zwho;
877 	zacep->a_access_mask = zamask;
878 	zacep->a_flags = zflags;
879 	zacep->a_type = ntace->ace_hdr.ace_type;
880 }
881 
882 /*
883  * Convert an internal SD to a ZFS-style ACL.
884  * Note optional args: vsa/acl, uidp, gidp.
885  *
886  * This makes two passes over the SD, the first building a
887  * "batch" request for idmap with results in mapinfo, the
888  * second building a ZFS-style ACL using the idmap results.
889  */
890 int
891 smbfs_acl_sd2zfs(
892 	i_ntsd_t *sd,
893 #if defined(_KERNEL) || defined(_FAKE_KERNEL)
894 	vsecattr_t *acl_info,
895 #else /* _KERNEL */
896 	acl_t *acl_info,
897 #endif /* _KERNEL */
898 	uid_t *uidp, gid_t *gidp)
899 {
900 	struct mapinfo2uid *mip, *mapinfo = NULL;
901 	int error, i, mapcnt, zacecnt, zacl_size;
902 	ace_t *zacep0, *zacep;
903 	uid_t own_uid = (uid_t)-1;
904 	gid_t own_gid = (gid_t)-1;
905 	i_ntacl_t *ntacl;
906 	i_ntace_t **ntacep;
907 	idmap_get_handle_t *idmap_gh = NULL;
908 	idmap_stat	idms;
909 
910 	/*
911 	 * sanity checks
912 	 */
913 	if (acl_info) {
914 #if !defined(_KERNEL) && !defined(_FAKE_KERNEL)
915 		if (acl_info->acl_type != ACE_T ||
916 		    acl_info->acl_aclp != NULL ||
917 		    acl_info->acl_entry_size != sizeof (ace_t))
918 			return (EINVAL);
919 #endif /* !_KERNEL */
920 		if ((sd->sd_flags & SD_DACL_PRESENT) == 0)
921 			return (EINVAL);
922 	}
923 
924 	/*
925 	 * How many SID mappings will we need?
926 	 */
927 	mapcnt = 0;
928 	if (sd->sd_owner)
929 		mapcnt++;
930 	if (sd->sd_group)
931 		mapcnt++;
932 	if ((sd->sd_flags & SD_SACL_PRESENT) &&
933 	    (sd->sd_sacl != NULL))
934 		mapcnt += sd->sd_sacl->acl_acecount;
935 	if ((sd->sd_flags & SD_DACL_PRESENT) &&
936 	    (sd->sd_dacl != NULL))
937 		mapcnt += sd->sd_dacl->acl_acecount;
938 	if (mapcnt == 0) {
939 		/*
940 		 * We have a NULL DACL, SACL, and don't
941 		 * have an owner or group, so there's no
942 		 * idmap work to do.  This is very rare,
943 		 * so rather than complicate things below,
944 		 * pretend we need one mapping slot.
945 		 */
946 		mapcnt = 1;
947 	}
948 
949 	mapinfo = MALLOC(mapcnt * sizeof (*mapinfo));
950 	if (mapinfo == NULL) {
951 		error = ENOMEM;
952 		goto errout;
953 	}
954 	bzero(mapinfo, mapcnt * sizeof (*mapinfo));
955 
956 
957 	/*
958 	 * Get an imap "batch" request handle.
959 	 */
960 #ifdef	_KERNEL
961 	idmap_gh = kidmap_get_create(curproc->p_zone);
962 #else /* _KERNEL */
963 	idms = idmap_get_create(&idmap_gh);
964 	if (idms != IDMAP_SUCCESS) {
965 		error = ENOTACTIVE;
966 		goto errout;
967 	}
968 #endif /* _KERNEL */
969 
970 	/*
971 	 * Build our request to the idmap deamon,
972 	 * getting Unix IDs for every SID.
973 	 */
974 	mip = mapinfo;
975 	if (sd->sd_owner) {
976 		error = mkrq_idmap_sid2ux(idmap_gh, mip,
977 		    sd->sd_owner, IDM_TYPE_USER);
978 		if (error)
979 			goto errout;
980 		mip++;
981 	}
982 	if (sd->sd_group) {
983 		error = mkrq_idmap_sid2ux(idmap_gh, mip,
984 		    sd->sd_group, IDM_TYPE_GROUP);
985 		if (error)
986 			goto errout;
987 		mip++;
988 	}
989 	if ((sd->sd_flags & SD_SACL_PRESENT) &&
990 	    (sd->sd_sacl != NULL)) {
991 		ntacl = sd->sd_sacl;
992 		ntacep = &ntacl->acl_acevec[0];
993 		for (i = 0; i < ntacl->acl_acecount; i++) {
994 			error = mkrq_idmap_sid2ux(idmap_gh, mip,
995 			    (*ntacep)->ace_v2.ace_sid, IDM_TYPE_ANY);
996 			if (error)
997 				goto errout;
998 			ntacep++;
999 			mip++;
1000 		}
1001 	}
1002 	if ((sd->sd_flags & SD_DACL_PRESENT) &&
1003 	    (sd->sd_dacl != NULL)) {
1004 		ntacl = sd->sd_dacl;
1005 		ntacep = &ntacl->acl_acevec[0];
1006 		for (i = 0; i < ntacl->acl_acecount; i++) {
1007 			error = mkrq_idmap_sid2ux(idmap_gh, mip,
1008 			    (*ntacep)->ace_v2.ace_sid, IDM_TYPE_ANY);
1009 			if (error)
1010 				goto errout;
1011 			ntacep++;
1012 			mip++;
1013 		}
1014 	}
1015 
1016 	if (mip != mapinfo) {
1017 		idms = I_getmappings(idmap_gh);
1018 		if (idms != IDMAP_SUCCESS) {
1019 			/* creative error choice */
1020 			error = EIDRM;
1021 			goto errout;
1022 		}
1023 	}
1024 
1025 	/*
1026 	 * With any luck, we now have Unix user/group IDs
1027 	 * for every Windows SID in the security descriptor.
1028 	 * The remaining work is just format conversion.
1029 	 */
1030 	mip = mapinfo;
1031 	if (sd->sd_owner) {
1032 		own_uid = mip->mi_uid;
1033 		mip++;
1034 	}
1035 	if (sd->sd_group) {
1036 		own_gid = mip->mi_uid;
1037 		mip++;
1038 	}
1039 
1040 	if (uidp)
1041 		*uidp = own_uid;
1042 	if (gidp)
1043 		*gidp = own_gid;
1044 
1045 	if (acl_info == NULL) {
1046 		/* Caller only wanted uid/gid */
1047 		goto done;
1048 	}
1049 
1050 	/*
1051 	 * Build the ZFS-style ACL
1052 	 * First, allocate the most ZFS ACEs we'll need.
1053 	 */
1054 	zacecnt = 0;
1055 	if ((sd->sd_flags & SD_SACL_PRESENT) &&
1056 	    (sd->sd_sacl != NULL))
1057 		zacecnt += sd->sd_sacl->acl_acecount;
1058 
1059 	/* NB, have: (sd->sd_flags & SD_DACL_PRESENT) */
1060 	if ((sd->sd_dacl != NULL) &&
1061 	    (sd->sd_dacl->acl_acecount > 0)) {
1062 		zacecnt += sd->sd_dacl->acl_acecount;
1063 	} else {
1064 		/*
1065 		 * DACL is NULL or empty. Either way,
1066 		 * we'll need to add a ZFS ACE below.
1067 		 */
1068 		zacecnt++;
1069 	}
1070 	zacl_size = zacecnt * sizeof (ace_t);
1071 	zacep0 = MALLOC(zacl_size);
1072 	if (zacep0 == NULL) {
1073 		error = ENOMEM;
1074 		goto errout;
1075 	}
1076 	zacep = zacep0;
1077 
1078 	if ((sd->sd_flags & SD_SACL_PRESENT) &&
1079 	    (sd->sd_sacl != NULL)) {
1080 		ntacl = sd->sd_sacl;
1081 		ntacep = &ntacl->acl_acevec[0];
1082 		for (i = 0; i < ntacl->acl_acecount; i++) {
1083 			ntace2zace(zacep, *ntacep, mip);
1084 			zacep++;
1085 			ntacep++;
1086 			mip++;
1087 		}
1088 	}
1089 
1090 	/* NB, have: (sd->sd_flags & SD_DACL_PRESENT) */
1091 	if (sd->sd_dacl != NULL) {
1092 		ntacl = sd->sd_dacl;
1093 		ntacep = &ntacl->acl_acevec[0];
1094 		for (i = 0; i < ntacl->acl_acecount; i++) {
1095 			ntace2zace(zacep, *ntacep, mip);
1096 			zacep++;
1097 			ntacep++;
1098 			mip++;
1099 		}
1100 	}
1101 	if (sd->sd_dacl == NULL) {
1102 		/*
1103 		 * The SD has a NULL DACL.  That means
1104 		 * everyone@, full-control
1105 		 */
1106 		zacep->a_who = (uid_t)-1;
1107 		zacep->a_access_mask = ACE_ALL_PERMS;
1108 		zacep->a_flags = ACE_EVERYONE;
1109 		zacep->a_type = ACCESS_ALLOWED_ACE_TYPE;
1110 	} else if (sd->sd_dacl->acl_acecount == 0) {
1111 		/*
1112 		 * The SD has an Empty DACL.  We need
1113 		 * at least one ACE, so add one giving
1114 		 * the owner the usual implied access.
1115 		 */
1116 		zacep->a_who = (uid_t)-1;
1117 		zacep->a_access_mask = ACE_READ_ATTRIBUTES | \
1118 		    ACE_READ_ACL | ACE_WRITE_ACL;
1119 		zacep->a_flags = ACE_OWNER;
1120 		zacep->a_type = ACCESS_ALLOWED_ACE_TYPE;
1121 	}
1122 
1123 #if defined(_KERNEL) || defined(_FAKE_KERNEL)
1124 	acl_info->vsa_aclcnt = zacecnt;
1125 	acl_info->vsa_aclentp = zacep0;
1126 	acl_info->vsa_aclentsz = zacl_size;
1127 #else	/* _KERNEL */
1128 	acl_info->acl_cnt = zacecnt;
1129 	acl_info->acl_aclp = zacep0;
1130 #endif	/* _KERNEL */
1131 
1132 done:
1133 	error = 0;
1134 
1135 errout:
1136 	if (mapinfo != NULL)
1137 		FREESZ(mapinfo, mapcnt * sizeof (*mapinfo));
1138 #ifdef	_KERNEL
1139 	if (idmap_gh != NULL)
1140 		kidmap_get_destroy(idmap_gh);
1141 #else /* _KERNEL */
1142 	if (idmap_gh != NULL)
1143 		idmap_get_destroy(idmap_gh);
1144 #endif /* _KERNEL */
1145 
1146 	return (error);
1147 }
1148 
1149 
1150 /*
1151  * ================================================================
1152  * Support for ACL store, including conversions
1153  * from NFSv4-style ACLs to Windows ACLs.
1154  * ================================================================
1155  */
1156 
1157 /*
1158  * Convert a "sid-prefix" string plus RID into an NT SID.
1159  *
1160  * If successful, sets *osid and returns zero,
1161  * otherwise returns an errno value.
1162  */
1163 int
1164 smbfs_str2sid(const char *sid_prefix, uint32_t *ridp, i_ntsid_t **osidp)
1165 {
1166 	i_ntsid_t *sid = NULL;
1167 	u_longlong_t auth = 0;
1168 	ulong_t sa;
1169 	uint8_t sacnt;
1170 	const char *p;
1171 	char *np;
1172 	size_t size;
1173 	int i;
1174 	int err;
1175 
1176 	if (sid_prefix == NULL)
1177 		return (EINVAL);
1178 
1179 	p = sid_prefix;
1180 	if (strncmp(p, "S-1-", 4) != 0)
1181 		return (EINVAL);
1182 	p += 4;
1183 
1184 	/* Parse the "authority" */
1185 #ifdef	_KERNEL
1186 	err = ddi_strtoull(p, &np, 10, &auth);
1187 	if (err != 0)
1188 		return (err);
1189 #else	/* _KERNEL */
1190 	auth = strtoull(p, &np, 10);
1191 	if (p == np)
1192 		return (EINVAL);
1193 #endif	/* _KERNEL */
1194 
1195 	/*
1196 	 * Count the sub-authorities.  Here, np points to
1197 	 * the "-" before the first sub-authority.
1198 	 */
1199 	sacnt = 0;
1200 	for (p = np; *p; p++) {
1201 		if (*p == '-')
1202 			sacnt++;
1203 	}
1204 	if (ridp != NULL)
1205 		sacnt++;
1206 
1207 	/* Allocate the internal SID. */
1208 	size = I_SID_SIZE(sacnt);
1209 	sid = MALLOC(size);
1210 	if (sid == NULL)
1211 		return (ENOMEM);
1212 	bzero(sid, size);
1213 
1214 	/* Fill it in. */
1215 	sid->sid_revision = 1;
1216 	sid->sid_subauthcount = sacnt;
1217 	for (i = 5; i >= 0; i--) {
1218 		sid->sid_authority[i] = auth & 0xFF;
1219 		auth = auth >> 8;
1220 	}
1221 
1222 	err = EINVAL;
1223 	if (ridp != NULL)
1224 		sacnt--; /* Last SA not from string */
1225 	p = np;
1226 	for (i = 0; i < sacnt; i++) {
1227 		if (*p != '-') {
1228 			err = EINVAL;
1229 			goto out;
1230 		}
1231 		p++;
1232 #if defined(_KERNEL) || defined(_FAKE_KERNEL)
1233 		err = ddi_strtoul(p, &np, 10, &sa);
1234 		if (err != 0)
1235 			goto out;
1236 #else	/* _KERNEL */
1237 		sa = strtoul(p, &np, 10);
1238 		if (p == np) {
1239 			err = EINVAL;
1240 			goto out;
1241 		}
1242 #endif	/* _KERNEL */
1243 		sid->sid_subauthvec[i] = (uint32_t)sa;
1244 		p = np;
1245 	}
1246 	if (*p != '\0')
1247 		goto out;
1248 	if (ridp != NULL)
1249 		sid->sid_subauthvec[i] = *ridp;
1250 	err = 0;
1251 
1252 out:
1253 	if (err)
1254 		FREESZ(sid, size);
1255 	else
1256 		*osidp = sid;
1257 
1258 	return (err);
1259 }
1260 
1261 /*
1262  * The idmap API is _almost_ the same between
1263  * kernel and user-level.  But not quite...
1264  * Hope this improves readability below.
1265  */
1266 #ifdef	_KERNEL
1267 
1268 #define	I_getsidbyuid(GH, UID, SPP, RP, ST) \
1269 	kidmap_batch_getsidbyuid(GH, UID, SPP, RP, ST)
1270 
1271 #define	I_getsidbygid(GH, GID, SPP, RP, ST) \
1272 	kidmap_batch_getsidbygid(GH, GID, SPP, RP, ST)
1273 
1274 #else /* _KERNEL */
1275 
1276 #define	I_getsidbyuid(GH, UID, SPP, RP, ST) \
1277 	idmap_get_sidbyuid(GH, UID, 0, SPP, RP, ST)
1278 
1279 #define	I_getsidbygid(GH, GID, SPP, RP, ST) \
1280 	idmap_get_sidbygid(GH, GID, 0, SPP, RP, ST)
1281 
1282 #endif /* _KERNEL */
1283 
1284 struct mapinfo2sid {
1285 	/* Yet another kernel vs. user difference. */
1286 #ifdef	_KERNEL
1287 	const char *mi_dsid;	/* domain SID */
1288 #else /* _KERNEL */
1289 	char *mi_dsid;
1290 #endif /* _KERNEL */
1291 	uint32_t mi_rid;	/* relative ID */
1292 	idmap_stat mi_status;
1293 };
1294 
1295 /*
1296  * Build an idmap request.  Cleanup is
1297  * handled by the caller (error or not)
1298  */
1299 static int
1300 mkrq_idmap_ux2sid(
1301 	idmap_get_handle_t *idmap_gh,
1302 	struct mapinfo2sid *mip,
1303 	uid_t	uid, /* or gid */
1304 	int req_type)
1305 {
1306 	idmap_stat	idms;
1307 
1308 	switch (req_type) {
1309 
1310 	case IDM_TYPE_USER:
1311 		if (uid == (uid_t)-1)
1312 			return (EINVAL);
1313 		idms = I_getsidbyuid(idmap_gh, uid,
1314 		    &mip->mi_dsid, &mip->mi_rid, &mip->mi_status);
1315 		break;
1316 
1317 	case IDM_TYPE_GROUP:
1318 		if (uid == (uid_t)-1)
1319 			return (EINVAL);
1320 		idms = I_getsidbygid(idmap_gh, uid,
1321 		    &mip->mi_dsid, &mip->mi_rid, &mip->mi_status);
1322 		break;
1323 
1324 	case IDM_EVERYONE:
1325 		mip->mi_dsid = "S-1-1";
1326 		mip->mi_rid = 0;
1327 		mip->mi_status = 0;
1328 		idms = IDMAP_SUCCESS;
1329 		break;
1330 
1331 	default:
1332 		idms = IDMAP_ERR_OTHER;
1333 		break;
1334 	}
1335 
1336 	if (idms != IDMAP_SUCCESS)
1337 		return (EINVAL);
1338 
1339 	return (0);
1340 }
1341 
1342 /*
1343  * Convert a ZFS ACE to an NT ACE.
1344  * ACE type was already validated.
1345  */
1346 static int
1347 zace2ntace(i_ntace_t **ntacep, ace_t *zacep, struct mapinfo2sid *mip)
1348 {
1349 	const struct zaf2naf *znaf;
1350 	uint8_t aflags;
1351 	uint16_t alloc_size;
1352 	uint32_t rights;
1353 	i_ntace_t *ntace = NULL;
1354 	i_ntsid_t *sid = NULL;
1355 	int error;
1356 
1357 	if (mip->mi_dsid == NULL || mip->mi_status != 0) {
1358 		return (EINVAL);
1359 	}
1360 
1361 	/*
1362 	 * Translate ZFS ACE flags to NT ACE flags.
1363 	 */
1364 	aflags = 0;
1365 	for (znaf = smbfs_zaf2naf; znaf->za_flag; znaf++)
1366 		if (zacep->a_flags & znaf->za_flag)
1367 			aflags |= znaf->na_flag;
1368 
1369 	/*
1370 	 * The access rights bits are OK as-is.
1371 	 */
1372 	rights = zacep->a_access_mask;
1373 
1374 	/*
1375 	 * Make sure we can get the SID.
1376 	 * Note: allocates sid.
1377 	 */
1378 	error = smbfs_str2sid(mip->mi_dsid, &mip->mi_rid, &sid);
1379 	if (error)
1380 		return (error);
1381 
1382 	/*
1383 	 * Allocate the NT ACE and fill it in.
1384 	 */
1385 	alloc_size = sizeof (i_ntace_v2_t);
1386 	if ((ntace = MALLOC(alloc_size)) == NULL) {
1387 		ifree_sid(sid);
1388 		return (ENOMEM);
1389 	}
1390 	bzero(ntace, alloc_size);
1391 
1392 	ntace->ace_hdr.ace_type = zacep->a_type;
1393 	ntace->ace_hdr.ace_flags = aflags;
1394 	ntace->ace_hdr.ace_size = alloc_size;
1395 	ntace->ace_v2.ace_rights = rights;
1396 	ntace->ace_v2.ace_sid = sid;
1397 
1398 	*ntacep = ntace;
1399 	return (0);
1400 }
1401 
1402 /*
1403  * Convert a ZFS-style ACL to an internal SD.
1404  * Set owner/group too if selector indicates.
1405  * Always need to pass uid+gid, either the new
1406  * (when setting them) or existing, so that any
1407  * owner@ or group@ ACEs can be translated.
1408  *
1409  * This makes two passes over the ZFS ACL.  The first builds a
1410  * "batch" request for idmap with results in mapinfo, and the
1411  * second builds the NT SD using the idmap SID results.
1412  */
1413 int
1414 smbfs_acl_zfs2sd(
1415 #if defined(_KERNEL) || defined(_FAKE_KERNEL)
1416 	vsecattr_t *acl_info,
1417 #else /* _KERNEL */
1418 	acl_t *acl_info,
1419 #endif /* _KERNEL */
1420 	uid_t own_uid,
1421 	gid_t own_gid,
1422 	uint32_t selector,
1423 	i_ntsd_t **sdp)
1424 {
1425 	struct mapinfo2sid *mip, *mip_acl, *mapinfo = NULL;
1426 	int aclsz, error, i, mapcnt;
1427 	int dacl_acecnt = 0;
1428 	int sacl_acecnt = 0;
1429 	int zacecnt = 0;
1430 	ace_t *zacevec = NULL;
1431 	ace_t *zacep;
1432 	i_ntsd_t *sd = NULL;
1433 	i_ntacl_t *acl = NULL;
1434 	i_ntace_t **acep = NULL;
1435 	idmap_get_handle_t *idmap_gh = NULL;
1436 	idmap_stat	idms;
1437 
1438 	/*
1439 	 * First, get all the UID+GID to SID mappings.
1440 	 * How many?  Also sanity checks.
1441 	 */
1442 	mapcnt = 0;
1443 	if (selector & OWNER_SECURITY_INFORMATION) {
1444 		if (own_uid == (uid_t)-1)
1445 			return (EINVAL);
1446 		mapcnt++;
1447 	}
1448 	if (selector & GROUP_SECURITY_INFORMATION) {
1449 		if (own_gid == (gid_t)-1)
1450 			return (EINVAL);
1451 		mapcnt++;
1452 	}
1453 	if (selector & (DACL_SECURITY_INFORMATION |
1454 	    SACL_SECURITY_INFORMATION)) {
1455 		if (acl_info == NULL)
1456 			return (EINVAL);
1457 		if (own_uid == (uid_t)-1)
1458 			return (EINVAL);
1459 		if (own_gid == (gid_t)-1)
1460 			return (EINVAL);
1461 #if defined(_KERNEL) || defined(_FAKE_KERNEL)
1462 		if ((acl_info->vsa_mask & VSA_ACE) == 0)
1463 			return (EINVAL);
1464 		zacecnt = acl_info->vsa_aclcnt;
1465 		zacevec = acl_info->vsa_aclentp;
1466 #else	/* _KERNEL */
1467 		if (acl_info->acl_type != ACE_T ||
1468 		    acl_info->acl_entry_size != sizeof (ace_t))
1469 			return (EINVAL);
1470 		zacecnt = acl_info->acl_cnt;
1471 		zacevec = acl_info->acl_aclp;
1472 #endif	/* _KERNEL */
1473 		if (zacecnt == 0 || zacevec == NULL)
1474 			return (EINVAL);
1475 		mapcnt += zacecnt;
1476 	}
1477 	if (mapcnt == 0)
1478 		return (EINVAL);
1479 	mapinfo = MALLOC(mapcnt * sizeof (*mapinfo));
1480 	if (mapinfo == NULL)
1481 		return (ENOMEM);
1482 	bzero(mapinfo, mapcnt * sizeof (*mapinfo));
1483 	/* no more returns until errout */
1484 
1485 	/*
1486 	 * Get an imap "batch" request handle.
1487 	 */
1488 #ifdef	_KERNEL
1489 	idmap_gh = kidmap_get_create(curproc->p_zone);
1490 #else /* _KERNEL */
1491 	idms = idmap_get_create(&idmap_gh);
1492 	if (idms != IDMAP_SUCCESS) {
1493 		error = ENOTACTIVE;
1494 		goto errout;
1495 	}
1496 #endif /* _KERNEL */
1497 
1498 	/*
1499 	 * Build our request to the idmap deamon,
1500 	 * getting SIDs for every Unix UID/GID.
1501 	 * Also count DACL and SACL ACEs here.
1502 	 */
1503 	mip = mapinfo;
1504 	if (selector & OWNER_SECURITY_INFORMATION) {
1505 		error = mkrq_idmap_ux2sid(idmap_gh, mip,
1506 		    own_uid, IDM_TYPE_USER);
1507 		if (error)
1508 			goto errout;
1509 		mip++;
1510 	}
1511 	if (selector & GROUP_SECURITY_INFORMATION) {
1512 		error = mkrq_idmap_ux2sid(idmap_gh, mip,
1513 		    own_gid, IDM_TYPE_GROUP);
1514 		if (error)
1515 			goto errout;
1516 		mip++;
1517 	}
1518 	if (selector & (DACL_SECURITY_INFORMATION |
1519 	    SACL_SECURITY_INFORMATION)) {
1520 		int rqtype;
1521 		uid_t uid;
1522 
1523 		zacep = zacevec;
1524 		for (i = 0; i < zacecnt; i++) {
1525 
1526 			switch (zacep->a_type) {
1527 			case ACE_ACCESS_ALLOWED_ACE_TYPE:
1528 			case ACE_ACCESS_DENIED_ACE_TYPE:
1529 				dacl_acecnt++;
1530 				break;
1531 			case ACE_SYSTEM_AUDIT_ACE_TYPE:
1532 			case ACE_SYSTEM_ALARM_ACE_TYPE:
1533 				sacl_acecnt++;
1534 				break;
1535 			/* other types todo */
1536 			}
1537 
1538 			if (zacep->a_flags & ACE_EVERYONE) {
1539 				rqtype = IDM_EVERYONE;
1540 				uid = (uid_t)-1;
1541 			} else if (zacep->a_flags & ACE_GROUP) {
1542 				/* owning group (a_who = -1) */
1543 				rqtype = IDM_TYPE_GROUP;
1544 				uid = (uid_t)own_gid;
1545 			} else if (zacep->a_flags & ACE_OWNER) {
1546 				/* owning user (a_who = -1) */
1547 				rqtype = IDM_TYPE_USER;
1548 				uid = (uid_t)own_uid;
1549 			} else if (zacep->a_flags & ACE_IDENTIFIER_GROUP) {
1550 				/* regular group */
1551 				rqtype = IDM_TYPE_GROUP;
1552 				uid = zacep->a_who;
1553 			} else {
1554 				rqtype = IDM_TYPE_USER;
1555 				uid = zacep->a_who;
1556 			}
1557 
1558 			error = mkrq_idmap_ux2sid(idmap_gh, mip, uid, rqtype);
1559 			if (error)
1560 				goto errout;
1561 			zacep++;
1562 			mip++;
1563 		}
1564 	}
1565 
1566 	idms = I_getmappings(idmap_gh);
1567 	if (idms != IDMAP_SUCCESS) {
1568 		/* creative error choice */
1569 		error = EIDRM;
1570 		goto errout;
1571 	}
1572 
1573 	/*
1574 	 * With any luck, we now have a Windows SID for
1575 	 * every Unix UID or GID in the NFS/ZFS ACL.
1576 	 * The remaining work is just format conversion,
1577 	 * memory allocation, etc.
1578 	 */
1579 	if ((sd = MALLOC(sizeof (*sd))) == NULL) {
1580 		error = ENOMEM;
1581 		goto errout;
1582 	}
1583 	bzero(sd, sizeof (*sd));
1584 	sd->sd_revision = NT_SD_REVISION;
1585 
1586 	mip = mapinfo;
1587 	if (selector & OWNER_SECURITY_INFORMATION) {
1588 		error = smbfs_str2sid(mip->mi_dsid, &mip->mi_rid,
1589 		    &sd->sd_owner);
1590 		mip++;
1591 	}
1592 	if (selector & GROUP_SECURITY_INFORMATION) {
1593 		error = smbfs_str2sid(mip->mi_dsid, &mip->mi_rid,
1594 		    &sd->sd_group);
1595 		mip++;
1596 	}
1597 
1598 	/*
1599 	 * If setting both DACL and SACL, we will
1600 	 * make two passes starting here in mapinfo.
1601 	 */
1602 	mip_acl = mip;
1603 
1604 	if (selector & DACL_SECURITY_INFORMATION) {
1605 		/*
1606 		 * Caller wants to set the DACL.
1607 		 */
1608 		aclsz = I_ACL_SIZE(dacl_acecnt);
1609 		if ((acl = MALLOC(aclsz)) == NULL) {
1610 			error = ENOMEM;
1611 			goto errout;
1612 		}
1613 		bzero(acl, aclsz);
1614 
1615 		acl->acl_revision = NT_ACL_REVISION;
1616 		acl->acl_acecount = (uint16_t)dacl_acecnt;
1617 		acep = &acl->acl_acevec[0];
1618 
1619 		/* 1st pass - scan for DACL ACE types. */
1620 		mip = mip_acl;
1621 		zacep = zacevec;
1622 		for (i = 0; i < zacecnt; i++) {
1623 
1624 			switch (zacep->a_type) {
1625 			case ACE_ACCESS_ALLOWED_ACE_TYPE:
1626 			case ACE_ACCESS_DENIED_ACE_TYPE:
1627 				error = zace2ntace(acep, zacep, mip);
1628 				if (error != 0)
1629 					goto errout;
1630 				acep++;
1631 				break;
1632 
1633 			case ACE_SYSTEM_AUDIT_ACE_TYPE:
1634 			case ACE_SYSTEM_ALARM_ACE_TYPE:
1635 				break;
1636 			/* other types todo */
1637 			}
1638 			zacep++;
1639 			mip++;
1640 		}
1641 		sd->sd_dacl = acl;
1642 		acl = NULL;
1643 		sd->sd_flags |= SD_DACL_PRESENT;
1644 	}
1645 
1646 	if (selector & SACL_SECURITY_INFORMATION) {
1647 		/*
1648 		 * Caller wants to set the SACL.
1649 		 */
1650 		aclsz = I_ACL_SIZE(sacl_acecnt);
1651 		if ((acl = MALLOC(aclsz)) == NULL) {
1652 			error = ENOMEM;
1653 			goto errout;
1654 		}
1655 		bzero(acl, aclsz);
1656 
1657 		acl->acl_revision = NT_ACL_REVISION;
1658 		acl->acl_acecount = (uint16_t)sacl_acecnt;
1659 		acep = &acl->acl_acevec[0];
1660 
1661 		/* 2nd pass - scan for SACL ACE types. */
1662 		mip = mip_acl;
1663 		zacep = zacevec;
1664 		for (i = 0; i < zacecnt; i++) {
1665 
1666 			switch (zacep->a_type) {
1667 			case ACE_ACCESS_ALLOWED_ACE_TYPE:
1668 			case ACE_ACCESS_DENIED_ACE_TYPE:
1669 				break;
1670 
1671 			case ACE_SYSTEM_AUDIT_ACE_TYPE:
1672 			case ACE_SYSTEM_ALARM_ACE_TYPE:
1673 				error = zace2ntace(acep, zacep, mip);
1674 				if (error != 0)
1675 					goto errout;
1676 				acep++;
1677 				break;
1678 			/* other types todo */
1679 			}
1680 			zacep++;
1681 			mip++;
1682 		}
1683 		sd->sd_sacl = acl;
1684 		acl = NULL;
1685 		sd->sd_flags |= SD_SACL_PRESENT;
1686 	}
1687 
1688 	*sdp = sd;
1689 	error = 0;
1690 
1691 errout:
1692 	if (error != 0) {
1693 		if (acl != NULL)
1694 			ifree_acl(acl);
1695 		if (sd != NULL)
1696 			smbfs_acl_free_sd(sd);
1697 	}
1698 	if (mapinfo != NULL)
1699 		FREESZ(mapinfo, mapcnt * sizeof (*mapinfo));
1700 #ifdef	_KERNEL
1701 	if (idmap_gh != NULL)
1702 		kidmap_get_destroy(idmap_gh);
1703 #else /* _KERNEL */
1704 	if (idmap_gh != NULL)
1705 		idmap_get_destroy(idmap_gh);
1706 #endif /* _KERNEL */
1707 
1708 	return (error);
1709 }
1710