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