xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_acl.c (revision c8ec8eea9849cac239663c46be8a7f5d2ba7ca00)
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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"@(#)smb_acl.c	1.5	08/07/28 SMI"
27 
28 #include <sys/acl.h>
29 #include <acl/acl_common.h>
30 #include <smbsrv/smb_sid.h>
31 #include <smbsrv/smb_fsops.h>
32 #include <smbsrv/smb_idmap.h>
33 #include <smbsrv/smb_kproto.h>
34 #include <smbsrv/ntstatus.h>
35 #include <smbsrv/ntaccess.h>
36 
37 #define	ACE_FD_INHERIT_ACE (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE)
38 
39 #define	ZACE_IS_OWNER(zace) ((zace->a_flags & ACE_TYPE_FLAGS) == ACE_OWNER)
40 #define	ZACE_IS_OWNGRP(zace) \
41 	((zace->a_flags & ACE_TYPE_FLAGS) == (ACE_IDENTIFIER_GROUP|ACE_GROUP))
42 
43 #define	ZACE_IS_USER(zace) \
44 	(((zace->a_flags & ACE_TYPE_FLAGS) == 0) || (ZACE_IS_OWNER(zace)))
45 #define	ZACE_IS_GROUP(zace) (zace->a_flags & ACE_IDENTIFIER_GROUP)
46 #define	ZACE_IS_EVERYONE(zace) (zace->a_flags & ACE_EVERYONE)
47 
48 #define	ZACE_IS_PROPAGATE(zace) \
49 	((zace->a_flags & ACE_NO_PROPAGATE_INHERIT_ACE) == 0)
50 
51 #define	ZACE_IS_CREATOR_OWNER(zace) \
52 	(ZACE_IS_USER(zace) && (zace->a_who == IDMAP_WK_CREATOR_OWNER_UID))
53 
54 #define	ZACE_IS_CREATOR_GROUP(zace) \
55 	(ZACE_IS_GROUP(zace) && (zace->a_who == IDMAP_WK_CREATOR_GROUP_GID))
56 
57 #define	ZACE_IS_CREATOR(zace) \
58 	(ZACE_IS_CREATOR_OWNER(zace) || ZACE_IS_CREATOR_GROUP(zace))
59 
60 /*
61  * ACE groups within a DACL
62  *
63  * This is from lower to higher ACE order priority
64  */
65 #define	SMB_AG_START		0
66 #define	SMB_AG_ALW_INHRT	0
67 #define	SMB_AG_DNY_INHRT	1
68 #define	SMB_AG_ALW_DRCT		2
69 #define	SMB_AG_DNY_DRCT		3
70 #define	SMB_AG_NUM		4
71 
72 /*
73  * SID for Everyone group: S-1-1-0.
74  */
75 smb_sid_t everyone_sid = {
76 	NT_SID_REVISION,
77 	1,
78 	NT_SECURITY_WORLD_AUTH,
79 	{ 0 }
80 };
81 
82 #define	DEFAULT_DACL_ACENUM	2
83 /*
84  * Default ACL:
85  *    owner: full access
86  *    SYSTEM: full access
87  */
88 static ace_t default_dacl[DEFAULT_DACL_ACENUM] = {
89 	{ (uid_t)-1, ACE_ALL_PERMS, 0, ACE_ACCESS_ALLOWED_ACE_TYPE },
90 	{ IDMAP_WK_LOCAL_SYSTEM_GID, ACE_ALL_PERMS, ACE_IDENTIFIER_GROUP,
91 	    ACE_ACCESS_ALLOWED_ACE_TYPE }
92 };
93 
94 /*
95  * Note:
96  *
97  * smb_acl_xxx functions work with smb_acl_t which represents the CIFS format
98  * smb_fsacl_xxx functions work with acl_t which represents the Solaris native
99  * format
100  */
101 
102 static idmap_stat smb_fsacl_getsids(smb_idmap_batch_t *, acl_t *, uid_t, gid_t);
103 static acl_t *smb_fsacl_null_empty(boolean_t);
104 static int smb_fsacl_inheritable(acl_t *, int);
105 
106 static void smb_ace_inherit(ace_t *, ace_t *, int);
107 static boolean_t smb_ace_isvalid(smb_ace_t *, int);
108 static uint16_t smb_ace_len(smb_ace_t *);
109 static uint32_t smb_ace_mask_g2s(uint32_t);
110 static uint16_t smb_ace_flags_tozfs(uint8_t);
111 static uint8_t smb_ace_flags_fromzfs(uint16_t);
112 
113 smb_acl_t *
114 smb_acl_alloc(uint8_t revision, uint16_t bsize, uint16_t acecnt)
115 {
116 	smb_acl_t *acl;
117 	int size;
118 
119 	size = sizeof (smb_acl_t) + (acecnt * sizeof (smb_ace_t));
120 	acl = kmem_zalloc(size, KM_SLEEP);
121 	acl->sl_revision = revision;
122 	acl->sl_bsize = bsize;
123 	acl->sl_acecnt = acecnt;
124 	acl->sl_aces = (smb_ace_t *)(acl + 1);
125 
126 	list_create(&acl->sl_sorted, sizeof (smb_ace_t),
127 	    offsetof(smb_ace_t, se_sln));
128 	return (acl);
129 }
130 
131 void
132 smb_acl_free(smb_acl_t *acl)
133 {
134 	int i, size;
135 	void *ace;
136 
137 	if (acl == NULL)
138 		return;
139 
140 	for (i = 0; i < acl->sl_acecnt; i++)
141 		smb_sid_free(acl->sl_aces[i].se_sid);
142 
143 	while ((ace = list_head(&acl->sl_sorted)) != NULL)
144 		list_remove(&acl->sl_sorted, ace);
145 	list_destroy(&acl->sl_sorted);
146 
147 	size = sizeof (smb_acl_t) + (acl->sl_acecnt * sizeof (smb_ace_t));
148 	kmem_free(acl, size);
149 }
150 
151 /*
152  * smb_acl_len
153  *
154  * Returns the size of given ACL in bytes. Note that this
155  * is not an in-memory size, it's the ACL's size as it would
156  * appear on the wire
157  */
158 uint16_t
159 smb_acl_len(smb_acl_t *acl)
160 {
161 	return ((acl) ? acl->sl_bsize : 0);
162 }
163 
164 boolean_t
165 smb_acl_isvalid(smb_acl_t *acl, int which_acl)
166 {
167 	int i;
168 
169 	if (acl->sl_bsize < SMB_ACL_HDRSIZE)
170 		return (B_FALSE);
171 
172 	if (acl->sl_revision != ACL_REVISION) {
173 		/*
174 		 * we are rejecting ACLs with object-specific ACEs for now
175 		 */
176 		return (B_FALSE);
177 	}
178 
179 	for (i = 0; i < acl->sl_acecnt; i++) {
180 		if (!smb_ace_isvalid(&acl->sl_aces[i], which_acl))
181 			return (B_FALSE);
182 	}
183 
184 	return (B_TRUE);
185 }
186 
187 /*
188  * smb_acl_sort
189  *
190  * Sorts the given ACL in place if it needs to be sorted.
191  *
192  * The following is an excerpt from MSDN website.
193  *
194  * Order of ACEs in a DACL
195  *
196  * For Windows NT versions 4.0 and earlier, the preferred order of ACEs
197  * is simple: In a DACL, all access-denied ACEs should precede any
198  * access-allowed ACEs.
199  *
200  * For Windows 2000 or later, the proper order of ACEs is more complicated
201  * because of the introduction of object-specific ACEs and automatic
202  * inheritance.
203  *
204  * The following describes the preferred order:
205  *
206  * To ensure that noninherited ACEs have precedence over inherited ACEs,
207  * place all noninherited ACEs in a group before any inherited ACEs. This
208  * ordering ensures, for example, that a noninherited access-denied ACE
209  * is enforced regardless of any inherited ACE that allows access.
210  * Within the groups of noninherited ACEs and inherited ACEs, order ACEs
211  * according to ACE type, as the following shows:
212  * 	. Access-denied ACEs that apply to the object itself
213  * 	. Access-denied ACEs that apply to a subobject of the
214  *	  object, such as a property set or property
215  * 	. Access-allowed ACEs that apply to the object itself
216  * 	. Access-allowed ACEs that apply to a subobject of the object
217  *
218  * So, here is the desired ACE order
219  *
220  * deny-direct, allow-direct, deny-inherited, allow-inherited
221  *
222  * Of course, not all ACE types are required in an ACL.
223  */
224 void
225 smb_acl_sort(smb_acl_t *acl)
226 {
227 	list_t ace_grps[SMB_AG_NUM];
228 	list_t *alist;
229 	smb_ace_t *ace;
230 	uint8_t ace_flags;
231 	int ag, i;
232 
233 	ASSERT(acl);
234 
235 	if (acl->sl_acecnt == 0) {
236 		/*
237 		 * ACL with no entry is a valid ACL and it means
238 		 * no access for anybody.
239 		 */
240 		return;
241 	}
242 
243 	for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
244 		list_create(&ace_grps[i], sizeof (smb_ace_t),
245 		    offsetof(smb_ace_t, se_sln));
246 	}
247 
248 	for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; ++i, ace++) {
249 		ace_flags = ace->se_hdr.se_flags;
250 
251 		switch (ace->se_hdr.se_type) {
252 		case ACCESS_DENIED_ACE_TYPE:
253 			ag = (ace_flags & INHERITED_ACE) ?
254 			    SMB_AG_DNY_INHRT : SMB_AG_DNY_DRCT;
255 			break;
256 
257 		case ACCESS_ALLOWED_ACE_TYPE:
258 			ag = (ace_flags & INHERITED_ACE) ?
259 			    SMB_AG_ALW_INHRT : SMB_AG_ALW_DRCT;
260 			break;
261 
262 		default:
263 			/*
264 			 * This is the lowest priority group so we put
265 			 * evertything unknown here.
266 			 */
267 			ag = SMB_AG_ALW_INHRT;
268 			break;
269 		}
270 
271 		/* Add the ACE to the selected group */
272 		list_insert_tail(&ace_grps[ag], ace);
273 	}
274 
275 	/*
276 	 * start with highest priority ACE group and append
277 	 * the ACEs to the ACL.
278 	 */
279 	for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) {
280 		alist = &ace_grps[i];
281 		while ((ace = list_head(alist)) != NULL) {
282 			list_remove(alist, ace);
283 			list_insert_tail(&acl->sl_sorted, ace);
284 		}
285 		list_destroy(alist);
286 	}
287 }
288 
289 /*
290  * smb_acl_from_zfs
291  *
292  * Converts given ZFS ACL to a Windows ACL.
293  *
294  * A pointer to allocated memory for the Win ACL will be
295  * returned upon successful conversion.
296  */
297 smb_acl_t *
298 smb_acl_from_zfs(acl_t *zacl, uid_t uid, gid_t gid)
299 {
300 	ace_t *zace;
301 	int numaces;
302 	smb_acl_t *acl;
303 	smb_ace_t *ace;
304 	smb_idmap_batch_t sib;
305 	smb_idmap_t *sim;
306 	idmap_stat idm_stat;
307 
308 	idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt,
309 	    SMB_IDMAP_ID2SID);
310 	if (idm_stat != IDMAP_SUCCESS)
311 		return (NULL);
312 
313 	if (smb_fsacl_getsids(&sib, zacl, uid, gid) != IDMAP_SUCCESS) {
314 		smb_idmap_batch_destroy(&sib);
315 		return (NULL);
316 	}
317 
318 	acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt);
319 
320 	sim = sib.sib_maps;
321 	for (numaces = 0, zace = zacl->acl_aclp;
322 	    numaces < zacl->acl_cnt;
323 	    zace++, numaces++, sim++) {
324 		ASSERT(sim->sim_sid);
325 		if (sim->sim_sid == NULL) {
326 			smb_acl_free(acl);
327 			acl = NULL;
328 			break;
329 		}
330 
331 		ace = &acl->sl_aces[numaces];
332 		ace->se_hdr.se_type = zace->a_type;
333 		ace->se_hdr.se_flags = smb_ace_flags_fromzfs(zace->a_flags);
334 		ace->se_mask = zace->a_access_mask;
335 		ace->se_sid = smb_sid_dup(sim->sim_sid);
336 		ace->se_hdr.se_bsize = smb_ace_len(ace);
337 
338 		acl->sl_bsize += ace->se_hdr.se_bsize;
339 	}
340 
341 	smb_idmap_batch_destroy(&sib);
342 	return (acl);
343 }
344 
345 /*
346  * smb_acl_to_zfs
347  *
348  * Converts given Windows ACL to a ZFS ACL.
349  *
350  * fs_acl will contain a pointer to the created ZFS ACL.
351  * The allocated memory should be freed by calling
352  * smb_fsacl_free().
353  *
354  * Since the output parameter, fs_acl, is allocated in this
355  * function, the caller has to make sure *fs_acl is NULL which
356  * means it's not pointing to any memory.
357  */
358 uint32_t
359 smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl)
360 {
361 	smb_ace_t *ace;
362 	acl_t *zacl;
363 	ace_t *zace;
364 	smb_idmap_batch_t sib;
365 	smb_idmap_t *sim;
366 	idmap_stat idm_stat;
367 	int i;
368 
369 	ASSERT(fs_acl);
370 	ASSERT(*fs_acl == NULL);
371 
372 	if (acl && !smb_acl_isvalid(acl, which_acl))
373 		return (NT_STATUS_INVALID_ACL);
374 
375 	if ((acl == NULL) || (acl->sl_acecnt == 0)) {
376 		if (which_acl == SMB_DACL_SECINFO) {
377 			*fs_acl = smb_fsacl_null_empty(acl == NULL);
378 		}
379 
380 		return (NT_STATUS_SUCCESS);
381 	}
382 
383 	idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt,
384 	    SMB_IDMAP_SID2ID);
385 	if (idm_stat != IDMAP_SUCCESS)
386 		return (NT_STATUS_INTERNAL_ERROR);
387 
388 	zacl = smb_fsacl_alloc(acl->sl_acecnt, flags);
389 
390 	zace = zacl->acl_aclp;
391 	ace = acl->sl_aces;
392 	sim = sib.sib_maps;
393 
394 	for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
395 		zace->a_type = ace->se_hdr.se_type & ACE_ALL_TYPES;
396 		zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask);
397 		zace->a_flags = smb_ace_flags_tozfs(ace->se_hdr.se_flags);
398 
399 		if (smb_sid_cmp(ace->se_sid, &everyone_sid))
400 			zace->a_flags |= ACE_EVERYONE;
401 		else {
402 			sim->sim_id = &zace->a_who;
403 			idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim,
404 			    ace->se_sid, -1);
405 
406 			if (idm_stat != IDMAP_SUCCESS) {
407 				smb_fsacl_free(zacl);
408 				smb_idmap_batch_destroy(&sib);
409 				return (NT_STATUS_INTERNAL_ERROR);
410 			}
411 		}
412 	}
413 
414 	idm_stat = smb_idmap_batch_getmappings(&sib);
415 	if (idm_stat != IDMAP_SUCCESS) {
416 		smb_fsacl_free(zacl);
417 		smb_idmap_batch_destroy(&sib);
418 		return (NT_STATUS_NONE_MAPPED);
419 	}
420 
421 	/*
422 	 * Set the ACEs group flag based on the type of ID returned.
423 	 */
424 	zace = zacl->acl_aclp;
425 	ace = acl->sl_aces;
426 	sim = sib.sib_maps;
427 	for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
428 		if (zace->a_flags & ACE_EVERYONE)
429 			continue;
430 
431 		if (sim->sim_idtype == SMB_IDMAP_GROUP)
432 			zace->a_flags |= ACE_IDENTIFIER_GROUP;
433 	}
434 
435 	smb_idmap_batch_destroy(&sib);
436 
437 	*fs_acl = zacl;
438 	return (NT_STATUS_SUCCESS);
439 }
440 
441 /*
442  * smb_fsacl_getsids
443  *
444  * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs.
445  */
446 static idmap_stat
447 smb_fsacl_getsids(smb_idmap_batch_t *sib, acl_t *zacl, uid_t uid, gid_t gid)
448 {
449 	ace_t *zace;
450 	idmap_stat idm_stat;
451 	smb_idmap_t *sim;
452 	uid_t id;
453 	int i, idtype;
454 
455 	sim = sib->sib_maps;
456 
457 	for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt;
458 	    zace++, i++, sim++) {
459 		switch (zace->a_flags & ACE_TYPE_FLAGS) {
460 		case ACE_OWNER:
461 			id = uid;
462 			idtype = SMB_IDMAP_USER;
463 			break;
464 
465 		case (ACE_GROUP | ACE_IDENTIFIER_GROUP):
466 			/* owning group */
467 			id = gid;
468 			idtype = SMB_IDMAP_GROUP;
469 			break;
470 
471 		case ACE_IDENTIFIER_GROUP:
472 			/* regular group */
473 			id = zace->a_who;
474 			idtype = SMB_IDMAP_GROUP;
475 			break;
476 
477 		case ACE_EVERYONE:
478 			idtype = SMB_IDMAP_EVERYONE;
479 			break;
480 
481 		default:
482 			/* user entry */
483 			id = zace->a_who;
484 			idtype = SMB_IDMAP_USER;
485 		}
486 
487 		idm_stat = smb_idmap_batch_getsid(sib->sib_idmaph, sim,
488 		    id, idtype);
489 
490 		if (idm_stat != IDMAP_SUCCESS) {
491 			return (idm_stat);
492 		}
493 	}
494 
495 	idm_stat = smb_idmap_batch_getmappings(sib);
496 	return (idm_stat);
497 }
498 
499 /*
500  * smb_fsacl_null_empty
501  *
502  * NULL DACL means everyone full-access
503  * Empty DACL means everyone full-deny
504  *
505  * ZFS ACL must have at least one entry so smb server has
506  * to simulate the aforementioned expected behavior by adding
507  * an entry in case the requested DACL is null or empty. Adding
508  * a everyone full-deny entry has proved to be problematic in
509  * tests since a deny entry takes precedence over allow entries.
510  * So, instead of adding a everyone full-deny, an owner ACE with
511  * owner implicit permissions will be set.
512  */
513 static acl_t *
514 smb_fsacl_null_empty(boolean_t null)
515 {
516 	acl_t *zacl;
517 	ace_t *zace;
518 
519 	zacl = smb_fsacl_alloc(1, ACL_AUTO_INHERIT);
520 	zace = zacl->acl_aclp;
521 
522 	zace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
523 	if (null) {
524 		zace->a_access_mask = ACE_ALL_PERMS;
525 		zace->a_flags = ACE_EVERYONE;
526 	} else {
527 		zace->a_access_mask = ACE_READ_ACL | ACE_WRITE_ACL |
528 		    ACE_READ_ATTRIBUTES;
529 		zace->a_flags = ACE_OWNER;
530 	}
531 
532 	return (zacl);
533 }
534 
535 /*
536  * FS ACL (acl_t) Functions
537  */
538 acl_t *
539 smb_fsacl_alloc(int acenum, int flags)
540 {
541 	acl_t *acl;
542 
543 	acl = acl_alloc(ACE_T);
544 	acl->acl_cnt = acenum;
545 	acl->acl_aclp = kmem_zalloc(acl->acl_entry_size * acenum, KM_SLEEP);
546 	acl->acl_flags = flags;
547 	return (acl);
548 }
549 
550 void
551 smb_fsacl_free(acl_t *acl)
552 {
553 	if (acl)
554 		acl_free(acl);
555 }
556 
557 /*
558  * smb_fsop_aclmerge
559  *
560  * smb_fsop_aclread/write routines which interact with filesystem
561  * work with single ACL. This routine merges given DACL and SACL
562  * which might have been created during CIFS to FS conversion into
563  * one single ACL.
564  */
565 acl_t *
566 smb_fsacl_merge(acl_t *dacl, acl_t *sacl)
567 {
568 	acl_t *acl;
569 	int dacl_size;
570 
571 	ASSERT(dacl);
572 	ASSERT(sacl);
573 
574 	acl = smb_fsacl_alloc(dacl->acl_cnt + sacl->acl_cnt, dacl->acl_flags);
575 	dacl_size = dacl->acl_cnt * dacl->acl_entry_size;
576 	bcopy(dacl->acl_aclp, acl->acl_aclp, dacl_size);
577 	bcopy(sacl->acl_aclp, (char *)acl->acl_aclp + dacl_size,
578 	    sacl->acl_cnt * sacl->acl_entry_size);
579 
580 	return (acl);
581 }
582 
583 /*
584  * smb_fsacl_split
585  *
586  * splits the given ACE_T ACL (zacl) to one or two ACLs (DACL/SACL) based on
587  * the 'which_acl' parameter. Note that output dacl/sacl parameters could be
588  * NULL even if they're specified in 'which_acl', which means the target
589  * doesn't have any access and/or audit ACEs.
590  */
591 void
592 smb_fsacl_split(acl_t *zacl, acl_t **dacl, acl_t **sacl, int which_acl)
593 {
594 	ace_t *zace;
595 	ace_t *access_ace;
596 	ace_t *audit_ace;
597 	int naccess, naudit;
598 	int get_dacl, get_sacl;
599 	int i;
600 
601 	*dacl = *sacl = NULL;
602 	naccess = naudit = 0;
603 	get_dacl = (which_acl & SMB_DACL_SECINFO);
604 	get_sacl = (which_acl & SMB_SACL_SECINFO);
605 
606 	for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) {
607 		if (get_dacl && smb_ace_is_access(zace->a_type))
608 			naccess++;
609 		else if (get_sacl && smb_ace_is_audit(zace->a_type))
610 			naudit++;
611 	}
612 
613 	if (naccess) {
614 		*dacl = smb_fsacl_alloc(naccess, zacl->acl_flags);
615 		access_ace = (*dacl)->acl_aclp;
616 	}
617 
618 	if (naudit) {
619 		*sacl = smb_fsacl_alloc(naudit, zacl->acl_flags);
620 		audit_ace = (*sacl)->acl_aclp;
621 	}
622 
623 	for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) {
624 		if (get_dacl && smb_ace_is_access(zace->a_type)) {
625 			*access_ace = *zace;
626 			access_ace++;
627 		} else if (get_sacl && smb_ace_is_audit(zace->a_type)) {
628 			*audit_ace = *zace;
629 			audit_ace++;
630 		}
631 	}
632 }
633 
634 /*
635  * ACE Inheritance Rules
636  *
637  * The system propagates inheritable ACEs to child objects according to a
638  * set of inheritance rules. The system places inherited ACEs in the child's
639  * DACL according to the preferred order of ACEs in a DACL. For Windows
640  * 2000 or later, the system sets the INHERITED_ACE flag in all inherited ACEs.
641  *
642  * The following table shows the ACEs inherited by container and noncontainer
643  * child objects for different combinations of inheritance flags. These
644  * inheritance rules work the same for both DACLs and SACLs.
645  *
646  * Parent ACE type 			Effect on Child ACL
647  * -----------------------		-------------------
648  * OBJECT_INHERIT_ACE only 		Noncontainer child objects:
649  *					Inherited as an effective ACE.
650  *					Container child objects:
651  *					Containers inherit an inherit-only ACE
652  *					unless the NO_PROPAGATE_INHERIT_ACE bit
653  *					flag is also set.
654  *
655  * CONTAINER_INHERIT_ACE only 		Noncontainer child objects:
656  *					No effect on the child object.
657  *					Container child objects:
658  *				The child object inherits an effective ACE.
659  *				The inherited ACE is inheritable unless the
660  *				NO_PROPAGATE_INHERIT_ACE bit flag is also set.
661  *
662  * CONTAINER_INHERIT_ACE and
663  * OBJECT_INHERIT_ACE 			Noncontainer child objects:
664  *					Inherited as an effective ACE.
665  *					Container child objects:
666  *				The child object inherits an effective ACE.
667  *				The inherited ACE is inheritable unless the
668  *				NO_PROPAGATE_INHERIT_ACE bit flag is also set
669  *
670  * No inheritance flags set 	No effect on child container or noncontainer
671  *				objects.
672  *
673  * If an inherited ACE is an effective ACE for the child object, the system
674  * maps any generic rights to the specific rights for the child object.
675  * Similarly, the system maps generic SIDs, such as CREATOR_OWNER, to the
676  * appropriate SID. If an inherited ACE is an inherit-only ACE, any generic
677  * rights or generic SIDs are left unchanged so that they can be mapped
678  * appropriately when the ACE is inherited by the next generation of child
679  * objects.
680  *
681  * For a case in which a container object inherits an ACE that is both
682  * effective on the container and inheritable by its descendants, the
683  * container may inherit two ACEs. This occurs if the inheritable ACE
684  * contains generic information. The container inherits an inherit-only
685  * ACE containing the generic information and an effective-only ACE in
686  * which the generic information has been mapped.
687  */
688 
689 /*
690  * smb_fsacl_inherit
691  *
692  * Manufacture the inherited ACL from the given ACL considering
693  * the new object type (file/dir) specified by 'is_dir'. The
694  * returned ACL is used in smb_fsop_create/smb_fsop_mkdir functions.
695  * This function implements Windows inheritance rules explained above.
696  *
697  * Note that the in/out ACLs are ZFS ACLs not Windows ACLs
698  */
699 acl_t *
700 smb_fsacl_inherit(acl_t *dir_zacl, int is_dir, int which_acl, uid_t owner_uid)
701 {
702 	boolean_t use_default = B_FALSE;
703 	int num_inheritable = 0;
704 	int numaces;
705 	ace_t *dir_zace;
706 	acl_t *new_zacl;
707 	ace_t *new_zace;
708 
709 	num_inheritable = smb_fsacl_inheritable(dir_zacl, is_dir);
710 
711 	if (num_inheritable == 0) {
712 		if (which_acl == SMB_DACL_SECINFO) {
713 			/* No inheritable access ACEs -> default DACL */
714 			num_inheritable = DEFAULT_DACL_ACENUM;
715 			use_default = B_TRUE;
716 		} else {
717 			return (NULL);
718 		}
719 	}
720 
721 	new_zacl = smb_fsacl_alloc(num_inheritable, ACL_AUTO_INHERIT);
722 	new_zace = new_zacl->acl_aclp;
723 
724 	if (use_default) {
725 		bcopy(default_dacl, new_zacl->acl_aclp, sizeof (default_dacl));
726 		new_zace->a_who = owner_uid;
727 		return (new_zacl);
728 	}
729 
730 	for (numaces = 0, dir_zace = dir_zacl->acl_aclp;
731 	    numaces < dir_zacl->acl_cnt;
732 	    dir_zace++, numaces++) {
733 		switch (dir_zace->a_flags & ACE_FD_INHERIT_ACE) {
734 		case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE):
735 			/*
736 			 * Files inherit an effective ACE.
737 			 *
738 			 * Dirs inherit an effective ACE.
739 			 * The inherited ACE is inheritable unless the
740 			 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set
741 			 */
742 			smb_ace_inherit(dir_zace, new_zace, is_dir);
743 			new_zace++;
744 
745 			if (is_dir && ZACE_IS_CREATOR(dir_zace) &&
746 			    (ZACE_IS_PROPAGATE(dir_zace))) {
747 				*new_zace = *dir_zace;
748 				new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
749 				    ACE_INHERITED_ACE);
750 				new_zace++;
751 			}
752 			break;
753 
754 		case ACE_FILE_INHERIT_ACE:
755 			/*
756 			 * Files inherit as an effective ACE.
757 			 *
758 			 * Dirs inherit an inherit-only ACE
759 			 * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit
760 			 * flag is also set.
761 			 */
762 			if (is_dir == 0) {
763 				smb_ace_inherit(dir_zace, new_zace, is_dir);
764 				new_zace++;
765 			} else if (ZACE_IS_PROPAGATE(dir_zace)) {
766 				*new_zace = *dir_zace;
767 				new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
768 				    ACE_INHERITED_ACE);
769 				new_zace++;
770 			}
771 			break;
772 
773 		case ACE_DIRECTORY_INHERIT_ACE:
774 			/*
775 			 * No effect on files
776 			 *
777 			 * Dirs inherit an effective ACE.
778 			 * The inherited ACE is inheritable unless the
779 			 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set.
780 			 */
781 			if (is_dir == 0)
782 				break;
783 
784 			smb_ace_inherit(dir_zace, new_zace, is_dir);
785 			new_zace++;
786 
787 			if (ZACE_IS_CREATOR(dir_zace) &&
788 			    (ZACE_IS_PROPAGATE(dir_zace))) {
789 				*new_zace = *dir_zace;
790 				new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
791 				    ACE_INHERITED_ACE);
792 				new_zace++;
793 			}
794 
795 			break;
796 
797 		default:
798 			break;
799 		}
800 	}
801 
802 	return (new_zacl);
803 }
804 
805 /*
806  * smb_fsacl_from_vsa
807  *
808  * Converts given vsecattr_t structure to a acl_t structure.
809  *
810  * The allocated memory for retuned acl_t should be freed by
811  * calling acl_free().
812  */
813 acl_t *
814 smb_fsacl_from_vsa(vsecattr_t *vsecattr, acl_type_t acl_type)
815 {
816 	int		aclbsize = 0;	/* size of acl list in bytes */
817 	int		dfaclbsize = 0;	/* size of default acl list in bytes */
818 	int		numacls;
819 	acl_t		*acl_info;
820 
821 	ASSERT(vsecattr);
822 
823 	acl_info = acl_alloc(acl_type);
824 	if (acl_info == NULL)
825 		return (NULL);
826 
827 	acl_info->acl_flags = 0;
828 
829 	switch (acl_type) {
830 
831 	case ACLENT_T:
832 		numacls = vsecattr->vsa_aclcnt + vsecattr->vsa_dfaclcnt;
833 		aclbsize = vsecattr->vsa_aclcnt * sizeof (aclent_t);
834 		dfaclbsize = vsecattr->vsa_dfaclcnt * sizeof (aclent_t);
835 
836 		acl_info->acl_cnt = numacls;
837 		acl_info->acl_aclp = kmem_alloc(aclbsize + dfaclbsize,
838 		    KM_SLEEP);
839 		(void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp,
840 		    aclbsize);
841 		(void) memcpy((char *)acl_info->acl_aclp + aclbsize,
842 		    vsecattr->vsa_dfaclentp, dfaclbsize);
843 
844 		if (acl_info->acl_cnt <= MIN_ACL_ENTRIES)
845 			acl_info->acl_flags |= ACL_IS_TRIVIAL;
846 
847 		break;
848 
849 	case ACE_T:
850 		aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t);
851 		acl_info->acl_cnt = vsecattr->vsa_aclcnt;
852 		acl_info->acl_flags = vsecattr->vsa_aclflags;
853 		acl_info->acl_aclp = kmem_alloc(aclbsize, KM_SLEEP);
854 		(void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp,
855 		    aclbsize);
856 		if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0)
857 			acl_info->acl_flags |= ACL_IS_TRIVIAL;
858 
859 		break;
860 
861 	default:
862 		acl_free(acl_info);
863 		return (NULL);
864 	}
865 
866 	if (aclbsize && vsecattr->vsa_aclentp)
867 		kmem_free(vsecattr->vsa_aclentp, aclbsize);
868 	if (dfaclbsize && vsecattr->vsa_dfaclentp)
869 		kmem_free(vsecattr->vsa_dfaclentp, dfaclbsize);
870 
871 	return (acl_info);
872 }
873 
874 /*
875  * smb_fsacl_to_vsa
876  *
877  * Converts given acl_t structure to a vsecattr_t structure.
878  *
879  * IMPORTANT:
880  * Upon successful return the memory allocated for vsa_aclentp
881  * should be freed by calling kmem_free(). The size is returned
882  * in aclbsize.
883  */
884 int
885 smb_fsacl_to_vsa(acl_t *acl_info, vsecattr_t *vsecattr, int *aclbsize)
886 {
887 	int		error = 0;
888 	int		numacls;
889 	aclent_t	*aclp;
890 
891 	ASSERT(acl_info);
892 	ASSERT(vsecattr);
893 	ASSERT(aclbsize);
894 
895 	bzero(vsecattr, sizeof (vsecattr_t));
896 	*aclbsize = 0;
897 
898 	switch (acl_info->acl_type) {
899 	case ACLENT_T:
900 		numacls = acl_info->acl_cnt;
901 		/*
902 		 * Minimum ACL size is three entries so might as well
903 		 * bail out here.  Also limit request size to prevent user
904 		 * from allocating too much kernel memory.  Maximum size
905 		 * is MAX_ACL_ENTRIES for the ACL part and MAX_ACL_ENTRIES
906 		 * for the default ACL part.
907 		 */
908 		if (numacls < 3 || numacls > (MAX_ACL_ENTRIES * 2)) {
909 			error = EINVAL;
910 			break;
911 		}
912 
913 		vsecattr->vsa_mask = VSA_ACL;
914 
915 		vsecattr->vsa_aclcnt = numacls;
916 		*aclbsize = numacls * sizeof (aclent_t);
917 		vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP);
918 		(void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp,
919 		    *aclbsize);
920 
921 		/* Sort the acl list */
922 		ksort((caddr_t)vsecattr->vsa_aclentp,
923 		    vsecattr->vsa_aclcnt, sizeof (aclent_t), cmp2acls);
924 
925 		/* Break into acl and default acl lists */
926 		for (numacls = 0, aclp = vsecattr->vsa_aclentp;
927 		    numacls < vsecattr->vsa_aclcnt;
928 		    aclp++, numacls++) {
929 			if (aclp->a_type & ACL_DEFAULT)
930 				break;
931 		}
932 
933 		/* Find where defaults start (if any) */
934 		if (numacls < vsecattr->vsa_aclcnt) {
935 			vsecattr->vsa_mask |= VSA_DFACL;
936 			vsecattr->vsa_dfaclcnt = vsecattr->vsa_aclcnt - numacls;
937 			vsecattr->vsa_dfaclentp = aclp;
938 			vsecattr->vsa_aclcnt = numacls;
939 		}
940 
941 		/* Adjust if they're all defaults */
942 		if (vsecattr->vsa_aclcnt == 0) {
943 			vsecattr->vsa_mask &= ~VSA_ACL;
944 			vsecattr->vsa_aclentp = NULL;
945 		}
946 
947 		/* Only directories can have defaults */
948 		if (vsecattr->vsa_dfaclcnt &&
949 		    (acl_info->acl_flags & ACL_IS_DIR)) {
950 			error = ENOTDIR;
951 		}
952 
953 		break;
954 
955 	case ACE_T:
956 		if (acl_info->acl_cnt < 1 ||
957 		    acl_info->acl_cnt > MAX_ACL_ENTRIES) {
958 			error = EINVAL;
959 			break;
960 		}
961 
962 		vsecattr->vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS;
963 		vsecattr->vsa_aclcnt = acl_info->acl_cnt;
964 		vsecattr->vsa_aclflags = acl_info->acl_flags & ACL_FLAGS_ALL;
965 		*aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t);
966 		vsecattr->vsa_aclentsz = *aclbsize;
967 		vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP);
968 		(void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp,
969 		    *aclbsize);
970 
971 		break;
972 
973 	default:
974 		error = EINVAL;
975 	}
976 
977 	return (error);
978 }
979 
980 /*
981  * smb_fsacl_inheritable
982  *
983  * Checks to see if there are any inheritable ACEs in the
984  * given ZFS ACL. Returns the number of inheritable ACEs.
985  *
986  * The inherited ACL could be different based on the type of
987  * new object (file/dir) specified by 'is_dir'.
988  *
989  * Note that the input ACL is a ZFS ACL not Windows ACL.
990  */
991 static int
992 smb_fsacl_inheritable(acl_t *zacl, int is_dir)
993 {
994 	int numaces;
995 	int num_inheritable = 0;
996 	ace_t *zace;
997 
998 	if (zacl == NULL)
999 		return (0);
1000 
1001 	for (numaces = 0, zace = zacl->acl_aclp;
1002 	    numaces < zacl->acl_cnt;
1003 	    zace++, numaces++) {
1004 		switch (zace->a_flags & ACE_FD_INHERIT_ACE) {
1005 		case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE):
1006 			/*
1007 			 * Files inherit an effective ACE.
1008 			 *
1009 			 * Dirs inherit an effective ACE.
1010 			 * The inherited ACE is inheritable unless the
1011 			 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set
1012 			 */
1013 			num_inheritable++;
1014 
1015 			if (is_dir && ZACE_IS_CREATOR(zace) &&
1016 			    (ZACE_IS_PROPAGATE(zace))) {
1017 				num_inheritable++;
1018 			}
1019 			break;
1020 
1021 		case ACE_FILE_INHERIT_ACE:
1022 			/*
1023 			 * Files inherit as an effective ACE.
1024 			 *
1025 			 * Dirs inherit an inherit-only ACE
1026 			 * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit
1027 			 * flag is also set.
1028 			 */
1029 			if (is_dir == 0)
1030 				num_inheritable++;
1031 			else if (ZACE_IS_PROPAGATE(zace))
1032 				num_inheritable++;
1033 			break;
1034 
1035 		case ACE_DIRECTORY_INHERIT_ACE:
1036 			/*
1037 			 * No effect on files
1038 			 *
1039 			 * Dirs inherit an effective ACE.
1040 			 * The inherited ACE is inheritable unless the
1041 			 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set.
1042 			 */
1043 			if (is_dir == 0)
1044 				break;
1045 
1046 			num_inheritable++;
1047 
1048 			if (ZACE_IS_CREATOR(zace) &&
1049 			    (ZACE_IS_PROPAGATE(zace)))
1050 				num_inheritable++;
1051 			break;
1052 
1053 		default:
1054 			break;
1055 		}
1056 	}
1057 
1058 	return (num_inheritable);
1059 }
1060 
1061 
1062 /*
1063  * ACE Functions
1064  */
1065 
1066 /*
1067  * This is generic (ACL version 2) vs. object-specific
1068  * (ACL version 4) ACE types.
1069  */
1070 boolean_t
1071 smb_ace_is_generic(int type)
1072 {
1073 	switch (type) {
1074 	case ACE_ACCESS_ALLOWED_ACE_TYPE:
1075 	case ACE_ACCESS_DENIED_ACE_TYPE:
1076 	case ACE_SYSTEM_AUDIT_ACE_TYPE:
1077 	case ACE_SYSTEM_ALARM_ACE_TYPE:
1078 	case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
1079 	case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
1080 	case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
1081 	case ACE_SYSTEM_ALARM_CALLBACK_ACE_TYPE:
1082 		return (B_TRUE);
1083 
1084 	default:
1085 		break;
1086 	}
1087 
1088 	return (B_FALSE);
1089 }
1090 
1091 boolean_t
1092 smb_ace_is_access(int type)
1093 {
1094 	switch (type) {
1095 	case ACE_ACCESS_ALLOWED_ACE_TYPE:
1096 	case ACE_ACCESS_DENIED_ACE_TYPE:
1097 	case ACE_ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
1098 	case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
1099 	case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
1100 	case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
1101 	case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
1102 	case ACE_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
1103 	case ACE_ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
1104 		return (B_TRUE);
1105 
1106 	default:
1107 		break;
1108 	}
1109 
1110 	return (B_FALSE);
1111 }
1112 
1113 boolean_t
1114 smb_ace_is_audit(int type)
1115 {
1116 	switch (type) {
1117 	case ACE_SYSTEM_AUDIT_ACE_TYPE:
1118 	case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
1119 	case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
1120 	case ACE_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
1121 		return (B_TRUE);
1122 
1123 	default:
1124 		break;
1125 	}
1126 
1127 	return (B_FALSE);
1128 }
1129 
1130 /*
1131  * smb_ace_len
1132  *
1133  * Returns the length of the given ACE as it appears in an
1134  * ACL on the wire (i.e. a flat buffer which contains the SID)
1135  */
1136 static uint16_t
1137 smb_ace_len(smb_ace_t *ace)
1138 {
1139 	ASSERT(ace);
1140 	ASSERT(ace->se_sid);
1141 
1142 	if (ace == NULL)
1143 		return (0);
1144 
1145 	return (SMB_ACE_HDRSIZE + sizeof (ace->se_mask) +
1146 	    smb_sid_len(ace->se_sid));
1147 }
1148 
1149 static void
1150 smb_ace_inherit(ace_t *dir_zace, ace_t *zace, int is_dir)
1151 {
1152 	*zace = *dir_zace;
1153 
1154 	/* This is an effective ACE so remove the inherit_only flag */
1155 	zace->a_flags &= ~ACE_INHERIT_ONLY_ACE;
1156 	/* Mark this ACE as inherited */
1157 	zace->a_flags |= ACE_INHERITED_ACE;
1158 
1159 	/*
1160 	 * If this is a file or NO_PROPAGATE is set then this inherited
1161 	 * ACE is not inheritable so clear the inheritance flags
1162 	 */
1163 	if (!(is_dir && ZACE_IS_PROPAGATE(dir_zace)))
1164 		zace->a_flags &= ~ACE_INHERIT_FLAGS;
1165 
1166 	/*
1167 	 * Replace creator owner/group ACEs with actual owner/group ACEs.
1168 	 * This would be an effictive ACE which is not inheritable.
1169 	 */
1170 	if (ZACE_IS_CREATOR_OWNER(dir_zace)) {
1171 		zace->a_who = (uid_t)-1;
1172 		zace->a_flags |= ACE_OWNER;
1173 		zace->a_flags &= ~ACE_INHERIT_FLAGS;
1174 	} else if (ZACE_IS_CREATOR_GROUP(dir_zace)) {
1175 		zace->a_who = (uid_t)-1;
1176 		zace->a_flags |= ACE_GROUP;
1177 		zace->a_flags &= ~ACE_INHERIT_FLAGS;
1178 	}
1179 }
1180 
1181 /*
1182  * smb_ace_mask_g2s
1183  *
1184  * Converts generic access bits in the given mask (if any)
1185  * to file specific bits. Generic access masks shouldn't be
1186  * stored in filesystem ACEs.
1187  */
1188 static uint32_t
1189 smb_ace_mask_g2s(uint32_t mask)
1190 {
1191 	if (mask & GENERIC_ALL) {
1192 		mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE
1193 		    | GENERIC_EXECUTE);
1194 
1195 		mask |= FILE_ALL_ACCESS;
1196 		return (mask);
1197 	}
1198 
1199 	if (mask & GENERIC_READ) {
1200 		mask &= ~GENERIC_READ;
1201 		mask |= FILE_GENERIC_READ;
1202 	}
1203 
1204 	if (mask & GENERIC_WRITE) {
1205 		mask &= ~GENERIC_WRITE;
1206 		mask |= FILE_GENERIC_WRITE;
1207 	}
1208 
1209 	if (mask & GENERIC_EXECUTE) {
1210 		mask &= ~GENERIC_EXECUTE;
1211 		mask |= FILE_GENERIC_EXECUTE;
1212 	}
1213 
1214 	return (mask);
1215 }
1216 
1217 /*
1218  * smb_ace_flags_tozfs
1219  *
1220  * This function maps the flags which have different values
1221  * in Windows and Solaris. The ones with the same value are
1222  * transferred untouched.
1223  */
1224 static uint16_t
1225 smb_ace_flags_tozfs(uint8_t c_flags)
1226 {
1227 	uint16_t z_flags = 0;
1228 
1229 	if (c_flags & SUCCESSFUL_ACCESS_ACE_FLAG)
1230 		z_flags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
1231 
1232 	if (c_flags & FAILED_ACCESS_ACE_FLAG)
1233 		z_flags |= ACE_FAILED_ACCESS_ACE_FLAG;
1234 
1235 	if (c_flags & INHERITED_ACE)
1236 		z_flags |= ACE_INHERITED_ACE;
1237 
1238 	z_flags |= (c_flags & ACE_INHERIT_FLAGS);
1239 
1240 	return (z_flags);
1241 }
1242 
1243 static uint8_t
1244 smb_ace_flags_fromzfs(uint16_t z_flags)
1245 {
1246 	uint8_t c_flags;
1247 
1248 	c_flags = z_flags & ACE_INHERIT_FLAGS;
1249 
1250 	if (z_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
1251 		c_flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
1252 
1253 	if (z_flags & ACE_FAILED_ACCESS_ACE_FLAG)
1254 		c_flags |= FAILED_ACCESS_ACE_FLAG;
1255 
1256 	if (z_flags & ACE_INHERITED_ACE)
1257 		c_flags |= INHERITED_ACE;
1258 
1259 	return (c_flags);
1260 }
1261 
1262 static boolean_t
1263 smb_ace_isvalid(smb_ace_t *ace, int which_acl)
1264 {
1265 	uint16_t min_len;
1266 
1267 	min_len = sizeof (smb_acehdr_t);
1268 
1269 	if (ace->se_hdr.se_bsize < min_len)
1270 		return (B_FALSE);
1271 
1272 	if (smb_ace_is_access(ace->se_hdr.se_type) &&
1273 	    (which_acl != SMB_DACL_SECINFO))
1274 		return (B_FALSE);
1275 
1276 	if (smb_ace_is_audit(ace->se_hdr.se_type) &&
1277 	    (which_acl != SMB_SACL_SECINFO))
1278 		return (B_FALSE);
1279 
1280 	if (smb_ace_is_generic(ace->se_hdr.se_type)) {
1281 		if (!smb_sid_isvalid(ace->se_sid))
1282 			return (B_FALSE);
1283 
1284 		min_len += sizeof (ace->se_mask);
1285 		min_len += smb_sid_len(ace->se_sid);
1286 
1287 		if (ace->se_hdr.se_bsize < min_len)
1288 			return (B_FALSE);
1289 	}
1290 
1291 	/*
1292 	 * object-specific ACE validation will be added later.
1293 	 */
1294 	return (B_TRUE);
1295 }
1296