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