xref: /illumos-gate/usr/src/common/smbclnt/smbfs_ntacl.c (revision d8a7fe16f62711cdc5c4267da8b34ff24a6b668c)
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 2009 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 #ifdef _KERNEL
63 #define	MALLOC(size) kmem_alloc(size, KM_SLEEP)
64 #define	FREESZ(p, sz) kmem_free(p, sz)
65 #else	/* _KERNEL */
66 #define	MALLOC(size) malloc(size)
67 #ifndef lint
68 #define	FREESZ(p, sz) free(p)
69 #else	/* lint */
70 /* ARGSUSED */
71 static void
72 FREESZ(void *p, size_t sz)
73 {
74 	free(p);
75 }
76 #endif	/* lint */
77 #endif	/* _KERNEL */
78 
79 #define	ERRCHK(expr)	if ((error = expr) != 0) goto errout
80 
81 /*
82  * Security IDentifier (SID)
83  */
84 static void
85 ifree_sid(i_ntsid_t *sid)
86 {
87 	size_t sz;
88 
89 	if (sid == NULL)
90 		return;
91 
92 	sz = I_SID_SIZE(sid->sid_subauthcount);
93 	FREESZ(sid, sz);
94 }
95 
96 static int
97 md_get_sid(mdchain_t *mdp, i_ntsid_t **sidp)
98 {
99 	i_ntsid_t *sid = NULL;
100 	uint8_t revision, subauthcount;
101 	uint32_t *subauthp;
102 	size_t sidsz;
103 	int error, i;
104 
105 	if ((error = md_get_uint8(mdp, &revision)) != 0)
106 		return (error);
107 	if ((error = md_get_uint8(mdp, &subauthcount)) != 0)
108 		return (error);
109 
110 	sidsz = I_SID_SIZE(subauthcount);
111 
112 	if ((sid = MALLOC(sidsz)) == NULL)
113 		return (ENOMEM);
114 
115 	bzero(sid, sidsz);
116 	sid->sid_revision = revision;
117 	sid->sid_subauthcount = subauthcount;
118 	ERRCHK(md_get_mem(mdp, sid->sid_authority, 6, MB_MSYSTEM));
119 
120 	subauthp = &sid->sid_subauthvec[0];
121 	for (i = 0; i < subauthcount; i++) {
122 		ERRCHK(md_get_uint32le(mdp, subauthp));
123 		subauthp++;
124 	}
125 
126 	/* Success! */
127 	*sidp = sid;
128 	return (0);
129 
130 errout:
131 	ifree_sid(sid);
132 	return (error);
133 }
134 
135 static int
136 mb_put_sid(mbchain_t *mbp, i_ntsid_t *sid)
137 {
138 	uint32_t *subauthp;
139 	int error, i;
140 
141 	if (sid == NULL)
142 		return (EINVAL);
143 
144 	ERRCHK(mb_put_uint8(mbp, sid->sid_revision));
145 	ERRCHK(mb_put_uint8(mbp, sid->sid_subauthcount));
146 	ERRCHK(mb_put_mem(mbp, sid->sid_authority, 6, MB_MSYSTEM));
147 
148 	subauthp = &sid->sid_subauthvec[0];
149 	for (i = 0; i < sid->sid_subauthcount; i++) {
150 		ERRCHK(mb_put_uint32le(mbp, *subauthp));
151 		subauthp++;
152 	}
153 
154 	/* Success! */
155 	return (0);
156 
157 errout:
158 	return (error);
159 }
160 
161 
162 /*
163  * Access Control Entry (ACE)
164  */
165 static void
166 ifree_ace(i_ntace_t *ace)
167 {
168 
169 	if (ace == NULL)
170 		return;
171 
172 	ifree_sid(ace->ace_sid);
173 	FREESZ(ace, sizeof (*ace));
174 }
175 
176 static int
177 md_get_ace(mdchain_t *mdp, i_ntace_t **acep)
178 {
179 	mdchain_t tmp_md;
180 	i_ntace_t *ace = NULL;
181 	uint16_t ace_len;
182 	int error;
183 
184 	if ((ace = MALLOC(sizeof (*ace))) == NULL)
185 		return (ENOMEM);
186 	bzero(ace, sizeof (*ace));
187 
188 	/*
189 	 * The ACE is realy variable length,
190 	 * with format determined by the type.
191 	 * XXX: This only decodes types 0-7
192 	 *
193 	 * There may also be padding after it, so
194 	 * decode the using a copy of the mdchain,
195 	 * and then consume the specified length.
196 	 */
197 	tmp_md = *mdp;
198 
199 	/* Fixed-size header */
200 	ERRCHK(md_get_uint8(&tmp_md, &ace->ace_type));
201 	ERRCHK(md_get_uint8(&tmp_md, &ace->ace_flags));
202 	ERRCHK(md_get_uint16le(&tmp_md, &ace_len));
203 
204 	/* Variable-size body */
205 	ERRCHK(md_get_uint32le(&tmp_md, &ace->ace_rights));
206 	ERRCHK(md_get_sid(&tmp_md, &ace->ace_sid));
207 
208 	/* Now actually consume ace_len */
209 	ERRCHK(md_get_mem(mdp, NULL, ace_len, MB_MSYSTEM));
210 
211 	/* Success! */
212 	*acep = ace;
213 	return (0);
214 
215 errout:
216 	ifree_ace(ace);
217 	return (error);
218 }
219 
220 static int
221 mb_put_ace(mbchain_t *mbp, i_ntace_t *ace)
222 {
223 	int cnt0, error;
224 	uint16_t ace_len, *ace_len_p;
225 
226 	if (ace == NULL)
227 		return (EINVAL);
228 
229 	cnt0 = mbp->mb_count;
230 
231 	ERRCHK(mb_put_uint8(mbp, ace->ace_type));
232 	ERRCHK(mb_put_uint8(mbp, ace->ace_flags));
233 	ace_len_p = mb_reserve(mbp, sizeof (*ace_len_p));
234 	if (ace_len_p == NULL) {
235 		error = ENOMEM;
236 		goto errout;
237 	}
238 	ERRCHK(mb_put_uint32le(mbp, ace->ace_rights));
239 
240 	ERRCHK(mb_put_sid(mbp, ace->ace_sid));
241 
242 	ace_len = mbp->mb_count - cnt0;
243 	*ace_len_p = htoles(ace_len);
244 
245 	/* Success! */
246 	return (0);
247 
248 errout:
249 	return (error);
250 }
251 
252 
253 /*
254  * Access Control List (ACL)
255  */
256 
257 /* Not an OTW structure, so size can be at our convenience. */
258 #define	I_ACL_SIZE(cnt)	(sizeof (i_ntacl_t) + (cnt) * sizeof (void *))
259 
260 static void
261 ifree_acl(i_ntacl_t *acl)
262 {
263 	i_ntace_t **acep;
264 	size_t sz;
265 	int i;
266 
267 	if (acl == NULL)
268 		return;
269 
270 	acep = &acl->acl_acevec[0];
271 	for (i = 0; i < acl->acl_acecount; i++) {
272 		ifree_ace(*acep);
273 		acep++;
274 	}
275 	sz = I_ACL_SIZE(acl->acl_acecount);
276 	FREESZ(acl, sz);
277 }
278 
279 static int
280 md_get_acl(mdchain_t *mdp, i_ntacl_t **aclp)
281 {
282 	i_ntacl_t *acl = NULL;
283 	i_ntace_t **acep;
284 	uint8_t revision;
285 	uint16_t acl_len, acecount;
286 	size_t aclsz;
287 	int i, error;
288 
289 	if ((error = md_get_uint8(mdp, &revision)) != 0)
290 		return (error);
291 	if ((error = md_get_uint8(mdp, NULL)) != 0)
292 		return (error);
293 	if ((error = md_get_uint16le(mdp, &acl_len)) != 0)
294 		return (error);
295 	if ((error = md_get_uint16le(mdp, &acecount)) != 0)
296 		return (error);
297 	if ((error = md_get_uint16le(mdp, NULL)) != 0)
298 		return (error);
299 
300 	aclsz = I_ACL_SIZE(acecount);
301 	if ((acl = MALLOC(aclsz)) == NULL)
302 		return (ENOMEM);
303 	bzero(acl, aclsz);
304 	acl->acl_revision = revision;
305 	acl->acl_acecount = acecount;
306 
307 	acep = &acl->acl_acevec[0];
308 	for (i = 0; i < acl->acl_acecount; i++) {
309 		ERRCHK(md_get_ace(mdp, acep));
310 		acep++;
311 	}
312 	/*
313 	 * There may be more data here, but
314 	 * the caller takes care of that.
315 	 */
316 
317 	/* Success! */
318 	*aclp = acl;
319 	return (0);
320 
321 errout:
322 	ifree_acl(acl);
323 	return (error);
324 }
325 
326 static int
327 mb_put_acl(mbchain_t *mbp, i_ntacl_t *acl)
328 {
329 	i_ntace_t **acep;
330 	uint16_t acl_len, *acl_len_p;
331 	int i, cnt0, error;
332 
333 	cnt0 = mbp->mb_count;
334 
335 	ERRCHK(mb_put_uint8(mbp, acl->acl_revision));
336 	ERRCHK(mb_put_uint8(mbp, 0)); /* pad1 */
337 	acl_len_p = mb_reserve(mbp, sizeof (*acl_len_p));
338 	if (acl_len_p == NULL) {
339 		error = ENOMEM;
340 		goto errout;
341 	}
342 	ERRCHK(mb_put_uint16le(mbp, acl->acl_acecount));
343 	ERRCHK(mb_put_uint16le(mbp, 0)); /* pad2 */
344 
345 	acep = &acl->acl_acevec[0];
346 	for (i = 0; i < acl->acl_acecount; i++) {
347 		ERRCHK(mb_put_ace(mbp, *acep));
348 		acep++;
349 	}
350 
351 	/* Fill in acl_len_p */
352 	acl_len = mbp->mb_count - cnt0;
353 	*acl_len_p = htoles(acl_len);
354 
355 	/* Success! */
356 	return (0);
357 
358 errout:
359 	return (error);
360 }
361 
362 
363 /*
364  * Security Descriptor
365  */
366 void
367 smbfs_acl_free_sd(i_ntsd_t *sd)
368 {
369 
370 	if (sd == NULL)
371 		return;
372 
373 	ifree_sid(sd->sd_owner);
374 	ifree_sid(sd->sd_group);
375 	ifree_acl(sd->sd_sacl);
376 	ifree_acl(sd->sd_dacl);
377 
378 	FREESZ(sd, sizeof (*sd));
379 }
380 
381 /*
382  * Import a raw SD (mb chain) into "internal" form.
383  * (like "absolute" form per. NT docs)
384  * Returns allocated data in sdp
385  *
386  * Note: does NOT consume all the mdp data, so the
387  * caller has to take care of that if necessary.
388  */
389 int
390 md_get_ntsd(mdchain_t *mdp, i_ntsd_t **sdp)
391 {
392 	i_ntsd_t *sd = NULL;
393 	mdchain_t top_md, tmp_md;
394 	uint32_t owneroff, groupoff, sacloff, dacloff;
395 	int error;
396 
397 	if ((sd = MALLOC(sizeof (*sd))) == NULL)
398 		return (ENOMEM);
399 	bzero(sd, sizeof (*sd));
400 
401 	/*
402 	 * Offsets below are relative to this point,
403 	 * so save the mdp state for use below.
404 	 */
405 	top_md = *mdp;
406 
407 	ERRCHK(md_get_uint8(mdp, &sd->sd_revision));
408 	ERRCHK(md_get_uint8(mdp, &sd->sd_rmctl));
409 	ERRCHK(md_get_uint16le(mdp, &sd->sd_flags));
410 	ERRCHK(md_get_uint32le(mdp, &owneroff));
411 	ERRCHK(md_get_uint32le(mdp, &groupoff));
412 	ERRCHK(md_get_uint32le(mdp, &sacloff));
413 	ERRCHK(md_get_uint32le(mdp, &dacloff));
414 
415 	/*
416 	 * For each section make a temporary copy of the
417 	 * top_md state, advance to the given offset, and
418 	 * pass that to the lower md_get_xxx functions.
419 	 * These could be marshalled in any order, but
420 	 * are normally found in the order shown here.
421 	 */
422 	if (sacloff) {
423 		tmp_md = top_md;
424 		md_get_mem(&tmp_md, NULL, sacloff, MB_MSYSTEM);
425 		ERRCHK(md_get_acl(&tmp_md, &sd->sd_sacl));
426 	}
427 	if (dacloff) {
428 		tmp_md = top_md;
429 		md_get_mem(&tmp_md, NULL, dacloff, MB_MSYSTEM);
430 		ERRCHK(md_get_acl(&tmp_md, &sd->sd_dacl));
431 	}
432 	if (owneroff) {
433 		tmp_md = top_md;
434 		md_get_mem(&tmp_md, NULL, owneroff, MB_MSYSTEM);
435 		ERRCHK(md_get_sid(&tmp_md, &sd->sd_owner));
436 	}
437 	if (groupoff) {
438 		tmp_md = top_md;
439 		md_get_mem(&tmp_md, NULL, groupoff, MB_MSYSTEM);
440 		ERRCHK(md_get_sid(&tmp_md, &sd->sd_group));
441 	}
442 
443 	/* Success! */
444 	*sdp = sd;
445 	return (0);
446 
447 errout:
448 	smbfs_acl_free_sd(sd);
449 	return (error);
450 }
451 
452 /*
453  * Export an "internal" SD into an raw SD (mb chain).
454  * (a.k.a "self-relative" form per. NT docs)
455  * Returns allocated mbchain in mbp.
456  */
457 int
458 mb_put_ntsd(mbchain_t *mbp, i_ntsd_t *sd)
459 {
460 	uint32_t *owneroffp, *groupoffp, *sacloffp, *dacloffp;
461 	uint32_t owneroff, groupoff, sacloff, dacloff;
462 	int cnt0, error;
463 
464 	cnt0 = mbp->mb_count;
465 	owneroff = groupoff = sacloff = dacloff = 0;
466 
467 	ERRCHK(mb_put_uint8(mbp, sd->sd_revision));
468 	ERRCHK(mb_put_uint8(mbp, sd->sd_rmctl));
469 	ERRCHK(mb_put_uint16le(mbp, sd->sd_flags));
470 
471 	owneroffp = mb_reserve(mbp, sizeof (*owneroffp));
472 	groupoffp = mb_reserve(mbp, sizeof (*groupoffp));
473 	sacloffp  = mb_reserve(mbp, sizeof (*sacloffp));
474 	dacloffp  = mb_reserve(mbp, sizeof (*dacloffp));
475 	if (owneroffp == NULL || groupoffp == NULL ||
476 	    sacloffp == NULL || dacloffp == NULL) {
477 		error = ENOMEM;
478 		goto errout;
479 	}
480 
481 	/*
482 	 * These could be marshalled in any order, but
483 	 * are normally found in the order shown here.
484 	 */
485 	if (sd->sd_sacl) {
486 		sacloff = mbp->mb_count - cnt0;
487 		ERRCHK(mb_put_acl(mbp, sd->sd_sacl));
488 	}
489 	if (sd->sd_dacl) {
490 		dacloff = mbp->mb_count - cnt0;
491 		ERRCHK(mb_put_acl(mbp, sd->sd_dacl));
492 	}
493 	if (sd->sd_owner) {
494 		owneroff = mbp->mb_count - cnt0;
495 		ERRCHK(mb_put_sid(mbp, sd->sd_owner));
496 	}
497 	if (sd->sd_group) {
498 		groupoff = mbp->mb_count - cnt0;
499 		ERRCHK(mb_put_sid(mbp, sd->sd_group));
500 	}
501 
502 	/* Fill in the offsets */
503 	*owneroffp = htolel(owneroff);
504 	*groupoffp = htolel(groupoff);
505 	*sacloffp  = htolel(sacloff);
506 	*dacloffp  = htolel(dacloff);
507 
508 	/* Success! */
509 	return (0);
510 
511 errout:
512 	return (error);
513 }
514 
515 
516 /*
517  * Helper functions for conversion between ZFS-style ACLs
518  * and Windows Security Descriptors.
519  */
520 
521 
522 /*
523  * Convert an NT SID to a string. Optionally return the
524  * last sub-authority (or "relative ID" -- RID) in *ridp
525  * and truncate the output string after the domain part.
526  * If ridp==NULL, the output string is the whole SID,
527  * including both the domain and RID.
528  *
529  * Return length written, or -1 on error.
530  */
531 int
532 smbfs_sid2str(i_ntsid_t *sid,
533 	char *obuf, size_t osz, uint32_t *ridp)
534 {
535 	char *s = obuf;
536 	uint64_t auth = 0;
537 	uint_t i, n;
538 	uint32_t subs, *ip;
539 
540 	n = snprintf(s, osz, "S-%u", sid->sid_revision);
541 	if (n > osz)
542 		return (-1);
543 	s += n; osz -= n;
544 
545 	for (i = 0; i < 6; i++)
546 		auth = (auth << 8) | sid->sid_authority[i];
547 	n = snprintf(s, osz, "-%llu", (u_longlong_t)auth);
548 	if (n > osz)
549 		return (-1);
550 	s += n; osz -= n;
551 
552 	subs = sid->sid_subauthcount;
553 	if (subs < 1 || subs > 15)
554 		return (-1);
555 	if (ridp)
556 		subs--;
557 
558 	ip = &sid->sid_subauthvec[0];
559 	for (; subs; subs--, ip++) {
560 		n = snprintf(s, osz, "-%u", *ip);
561 		if (n > osz)
562 			return (-1);
563 		s += n; osz -= n;
564 	}
565 	if (ridp)
566 		*ridp = *ip;
567 
568 	/* LINTED E_PTRDIFF_OVERFLOW */
569 	return (s - obuf);
570 }
571 
572 /*
573  * Our interface to the idmap service.
574  *
575  * The idmap API is _almost_ the same between
576  * kernel and user-level.  But not quite...
577  * Hope this improves readability below.
578  */
579 #ifdef	_KERNEL
580 
581 #define	I_GetPidBySid(GH, SPP, RID, PIDP, ISUP, SP) \
582 	kidmap_batch_getpidbysid(GH, SPP, RID, PIDP, ISUP, SP)
583 #define	I_GetMappings kidmap_get_mappings
584 
585 #else /* _KERNEL */
586 
587 #define	I_GetPidBySid(GH, SPP, RID, PIDP, ISUP, SP) \
588 	idmap_get_pidbysid(GH, SPP, RID, 0, PIDP, ISUP, SP)
589 #define	I_GetMappings idmap_get_mappings
590 
591 #endif /* _KERNEL */
592 
593 struct mapinfo {
594 	uid_t	mi_uid; /* or gid */
595 	int	mi_isuser;
596 	idmap_stat mi_status;
597 };
598 
599 /*
600  * A special value for mi_isuser (above) to indicate
601  * that the SID is the well-known "Everyone" (S-1-1-0).
602  * The idmap library only uses -1, 0, 1, so this value
603  * is arbitrary but must not overlap w/ idmap values.
604  * XXX: Could use a way for idmap to tell us when
605  * it recognizes this well-known SID.
606  */
607 #define	IS_WKSID_EVERYONE 11
608 
609 /*
610  * Build an idmap request.  Cleanup is
611  * handled by the caller (error or not)
612  */
613 static int
614 mkrq_idmap_sid2ux(
615 	idmap_get_handle_t *idmap_gh,
616 	i_ntsid_t *sid,
617 	struct mapinfo *mip)
618 {
619 	char sid_prefix[256];
620 	uint32_t	rid;
621 	idmap_stat	idms;
622 
623 	if (smbfs_sid2str(sid, sid_prefix, sizeof (sid_prefix), &rid) < 0)
624 		return (EINVAL);
625 
626 	/*
627 	 * Give the "Everyone" group special treatment.
628 	 */
629 	if (strcmp(sid_prefix, "S-1-1") == 0 && rid == 0) {
630 		/* This is "Everyone" */
631 		mip->mi_uid = (uid_t)-1;
632 		mip->mi_isuser = IS_WKSID_EVERYONE;
633 		mip->mi_status = 0;
634 		return (0);
635 	}
636 
637 	idms = I_GetPidBySid(idmap_gh, sid_prefix, rid,
638 	    &mip->mi_uid, &mip->mi_isuser, &mip->mi_status);
639 	if (idms != IDMAP_SUCCESS)
640 		return (EINVAL);
641 
642 	return (0);
643 }
644 
645 static void
646 ntace2zace(ace_t *zacep, i_ntace_t *ntace, struct mapinfo *mip)
647 {
648 	uint32_t zamask;
649 	uint16_t zflags, ntflags;
650 	uint8_t zatype = ntace->ace_type;
651 
652 	/*
653 	 * Translate NT ACE flags to ZFS ACE flags.
654 	 * The low four bits are the same, but not
655 	 * others: INHERITED_ACE_FLAG, etc.
656 	 */
657 	ntflags = ntace->ace_flags;
658 	zflags = 0;
659 
660 	if (ntflags & OBJECT_INHERIT_ACE_FLAG)
661 		zflags |= ACE_FILE_INHERIT_ACE;
662 	if (ntflags & CONTAINER_INHERIT_ACE_FLAG)
663 		zflags |= ACE_DIRECTORY_INHERIT_ACE;
664 	if (ntflags & NO_PROPAGATE_INHERIT_ACE_FLAG)
665 		zflags |= ACE_NO_PROPAGATE_INHERIT_ACE;
666 	if (ntflags & INHERIT_ONLY_ACE_FLAG)
667 		zflags |= ACE_INHERIT_ONLY_ACE;
668 	if (ntflags & INHERITED_ACE_FLAG)
669 		zflags |= ACE_INHERITED_ACE;
670 
671 	if (ntflags & SUCCESSFUL_ACCESS_ACE_FLAG)
672 		zflags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
673 	if (ntflags & FAILED_ACCESS_ACE_FLAG)
674 		zflags |= ACE_FAILED_ACCESS_ACE_FLAG;
675 
676 	/*
677 	 * Add the "ID type" flags to the ZFS ace flags.
678 	 * Would be nice if the idmap header defined some
679 	 * manifest constants for these "isuser" values.
680 	 */
681 	switch (mip->mi_isuser) {
682 	case IS_WKSID_EVERYONE:
683 		zflags |= ACE_EVERYONE;
684 		break;
685 	case 0: /* it's a GID */
686 		zflags |= ACE_IDENTIFIER_GROUP;
687 		break;
688 	default:
689 	case 1: /* it's a UID */
690 		break;
691 	}
692 
693 	/*
694 	 * The access mask bits are the same, but
695 	 * mask off any bits we don't expect.
696 	 * Should not see any GENERIC_xxx flags,
697 	 * as those are only valid in requested
698 	 * access masks, not ACLs.  But if we do,
699 	 * get those, silently clear them here.
700 	 */
701 	zamask = ntace->ace_rights & ACE_ALL_PERMS;
702 
703 	/*
704 	 * Verify that it's a known ACE type.
705 	 * Only handle the types that appear in
706 	 * V2, V3, V4 ACLs for now.  Avoid failing
707 	 * the whole conversion if we get unknown
708 	 * ace types, but convert them to something
709 	 * that will have no effect on access.
710 	 */
711 	if (zatype > SYSTEM_ALARM_OBJECT_ACE_TYPE) {
712 		zatype = ACCESS_ALLOWED_ACE_TYPE;
713 		zamask = 0; /* harmless */
714 	}
715 
716 	/*
717 	 * Fill in the ZFS-style ACE
718 	 */
719 	zacep->a_who = mip->mi_uid; /* from ace_sid */
720 	zacep->a_access_mask = zamask;
721 	zacep->a_flags = zflags;
722 	zacep->a_type = zatype;
723 }
724 
725 /*
726  * Convert an internal SD to a ZFS-style ACL.
727  * Note optional args: vsa/acl, uidp, gidp.
728  */
729 int
730 smbfs_acl_sd2zfs(
731 	i_ntsd_t *sd,
732 #ifdef	_KERNEL
733 	vsecattr_t *acl_info,
734 #else /* _KERNEL */
735 	acl_t *acl_info,
736 #endif /* _KERNEL */
737 	uid_t *uidp, gid_t *gidp)
738 {
739 	struct mapinfo *mip, *mapinfo = NULL;
740 	int error, i, mapcnt, zacecnt, zacl_size;
741 	ace_t *zacep;
742 	i_ntacl_t *ntacl;
743 	i_ntace_t **ntacep;
744 #ifndef	_KERNEL
745 	idmap_handle_t *idmap_h = NULL;
746 #endif /* _KERNEL */
747 	idmap_get_handle_t *idmap_gh = NULL;
748 	idmap_stat	idms;
749 
750 	/*
751 	 * sanity checks
752 	 */
753 #ifndef	_KERNEL
754 	if (acl_info) {
755 		if (acl_info->acl_type != ACE_T ||
756 		    acl_info->acl_aclp != NULL ||
757 		    acl_info->acl_entry_size != sizeof (ace_t))
758 			return (EINVAL);
759 	}
760 #endif /* _KERNEL */
761 
762 	/*
763 	 * First, get all the SID mappings.
764 	 * How many?
765 	 */
766 	mapcnt = 0;
767 	if (sd->sd_owner)
768 		mapcnt++;
769 	if (sd->sd_group)
770 		mapcnt++;
771 	if (sd->sd_sacl)
772 		mapcnt += sd->sd_sacl->acl_acecount;
773 	if (sd->sd_dacl)
774 		mapcnt += sd->sd_dacl->acl_acecount;
775 	if (mapcnt == 0)
776 		return (EINVAL);
777 
778 	mapinfo = MALLOC(mapcnt * sizeof (*mapinfo));
779 	if (mapinfo == NULL) {
780 		error = ENOMEM;
781 		goto errout;
782 	}
783 	bzero(mapinfo, mapcnt * sizeof (*mapinfo));
784 
785 
786 	/*
787 	 * Build our request to the idmap deamon.
788 	 */
789 #ifdef	_KERNEL
790 	idmap_gh = kidmap_get_create(curproc->p_zone);
791 #else /* _KERNEL */
792 	idms = idmap_init(&idmap_h);
793 	if (idms != IDMAP_SUCCESS) {
794 		error = ENOTACTIVE;
795 		goto errout;
796 	}
797 	idms = idmap_get_create(idmap_h, &idmap_gh);
798 	if (idms != IDMAP_SUCCESS) {
799 		error = ENOTACTIVE;
800 		goto errout;
801 	}
802 #endif /* _KERNEL */
803 
804 	mip = mapinfo;
805 	if (sd->sd_owner) {
806 		error = mkrq_idmap_sid2ux(
807 		    idmap_gh, sd->sd_owner, mip);
808 		if (error)
809 			goto errout;
810 		mip++;
811 	}
812 	if (sd->sd_group) {
813 		error = mkrq_idmap_sid2ux(
814 		    idmap_gh, sd->sd_group, mip);
815 		if (error)
816 			goto errout;
817 		mip++;
818 	}
819 	if (sd->sd_sacl) {
820 		ntacl = sd->sd_sacl;
821 		ntacep = &ntacl->acl_acevec[0];
822 		for (i = 0; i < ntacl->acl_acecount; i++) {
823 			error = mkrq_idmap_sid2ux(
824 			    idmap_gh, (*ntacep)->ace_sid, mip);
825 			if (error)
826 				goto errout;
827 			ntacep++;
828 			mip++;
829 		}
830 	}
831 	if (sd->sd_dacl) {
832 		ntacl = sd->sd_dacl;
833 		ntacep = &ntacl->acl_acevec[0];
834 		for (i = 0; i < ntacl->acl_acecount; i++) {
835 			error = mkrq_idmap_sid2ux(
836 			    idmap_gh, (*ntacep)->ace_sid, mip);
837 			if (error)
838 				goto errout;
839 			ntacep++;
840 			mip++;
841 		}
842 	}
843 
844 	idms = I_GetMappings(idmap_gh);
845 	if (idms != IDMAP_SUCCESS) {
846 		/* creative error choice */
847 		error = EIDRM;
848 		goto errout;
849 	}
850 
851 	/*
852 	 * With any luck, we now have Unix user/group IDs
853 	 * for every Windows SID in the security descriptor.
854 	 * The remaining work is just format conversion.
855 	 */
856 	mip = mapinfo;
857 	if (sd->sd_owner) {
858 		if (uidp) {
859 			if (mip->mi_isuser == 1)
860 				*uidp = mip->mi_uid;
861 			else
862 				*uidp = (uid_t)-1;
863 		}
864 		mip++;
865 	} else {
866 		if (uidp)
867 			*uidp = (uid_t)-1;
868 	}
869 	if (sd->sd_group) {
870 		if (gidp) {
871 			if (mip->mi_isuser == 0)
872 				*gidp = (gid_t)mip->mi_uid;
873 			else
874 				*gidp = (gid_t)-1;
875 		}
876 		mip++;
877 	} else {
878 		if (gidp)
879 			*gidp = (gid_t)-1;
880 	}
881 
882 	if (acl_info == NULL) {
883 		/* Caller only wanted uid/gid */
884 		goto ok_out;
885 	}
886 
887 	/*
888 	 * Build the ZFS-style ACL
889 	 */
890 	zacecnt = 0;
891 	if (sd->sd_sacl)
892 		zacecnt += sd->sd_sacl->acl_acecount;
893 	if (sd->sd_dacl)
894 		zacecnt += sd->sd_dacl->acl_acecount;
895 	zacl_size = zacecnt * sizeof (ace_t);
896 	zacep = MALLOC(zacl_size);
897 #ifdef _KERNEL
898 	acl_info->vsa_aclentp = zacep;
899 	acl_info->vsa_aclentsz = zacl_size;
900 #else	/* _KERNEL */
901 	if (zacep == NULL) {
902 		error = ENOMEM;
903 		goto errout;
904 	}
905 	acl_info->acl_cnt = zacecnt;
906 	acl_info->acl_aclp = zacep;
907 #endif	/* _KERNEL */
908 
909 	if (sd->sd_sacl) {
910 		ntacl = sd->sd_sacl;
911 		ntacep = &ntacl->acl_acevec[0];
912 		for (i = 0; i < ntacl->acl_acecount; i++) {
913 			ntace2zace(zacep, *ntacep, mip);
914 			zacep++;
915 			ntacep++;
916 			mip++;
917 		}
918 	}
919 	if (sd->sd_dacl) {
920 		ntacl = sd->sd_dacl;
921 		ntacep = &ntacl->acl_acevec[0];
922 		for (i = 0; i < ntacl->acl_acecount; i++) {
923 			ntace2zace(zacep, *ntacep, mip);
924 			zacep++;
925 			ntacep++;
926 			mip++;
927 		}
928 	}
929 
930 ok_out:
931 	error = 0;
932 
933 errout:
934 	if (mapinfo)
935 		FREESZ(mapinfo, mapcnt * sizeof (*mapinfo));
936 
937 	return (error);
938 }
939 
940 
941 /*
942  * Convert an internal SD to a ZFS-style ACL.
943  * Include owner/group too if uid/gid != -1.
944  * Note optional arg: vsa/acl
945  */
946 /*ARGSUSED*/
947 int smbfs_acl_zfs2sd(
948 #ifdef	_KERNEL
949 	vsecattr_t *vsa,
950 #else /* _KERNEL */
951 	acl_t *acl,
952 #endif /* _KERNEL */
953 	uid_t uid, gid_t gid,
954 	i_ntsd_t **sdp)
955 {
956 	/* XXX - todo */
957 	return (ENOSYS);
958 }
959