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