1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2008-2010 Edward Tomasz Napiera��a <trasz@FreeBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29/*
30 * ACL support routines specific to NFSv4 access control lists.  These are
31 * utility routines for code common across file systems implementing NFSv4
32 * ACLs.
33 */
34
35#ifdef _KERNEL
36#include <sys/cdefs.h>
37#if 0
38__FBSDID("$FreeBSD: head/sys/kern/subr_acl_nfs4.c 341827 2018-12-11 19:32:16Z mjg $");
39#endif
40__KERNEL_RCSID(0, "$NetBSD: subr_acl_nfs4.c,v 1.2 2024/01/19 19:07:38 christos Exp $");
41
42#include <sys/param.h>
43#include <sys/kernel.h>
44#include <sys/module.h>
45#include <sys/systm.h>
46#include <sys/mount.h>
47#include <sys/vnode.h>
48#include <sys/errno.h>
49#include <sys/stat.h>
50#include <sys/sysctl.h>
51#include <sys/acl.h>
52#include <sys/kauth.h>
53
54static void	acl_nfs4_trivial_from_mode(struct acl *aclp, mode_t mode);
55
56
57#else
58
59#include <errno.h>
60#include <assert.h>
61#include <sys/acl.h>
62#include <sys/stat.h>
63#define KASSERT(a) assert(a)
64
65#endif /* !_KERNEL */
66
67#if 0
68static int
69_acl_entry_matches(struct acl_entry *ae, acl_tag_t tag, acl_perm_t perm,
70    acl_entry_type_t entry_type)
71{
72	if (ae->ae_tag != tag)
73		return (0);
74
75	if (ae->ae_id != ACL_UNDEFINED_ID)
76		return (0);
77
78	if (ae->ae_perm != perm)
79		return (0);
80
81	if (ae->ae_entry_type != entry_type)
82		return (0);
83
84	if (ae->ae_flags != 0)
85		return (0);
86
87	return (1);
88}
89#endif
90
91static struct acl_entry *
92_acl_append(struct acl *aclp, acl_tag_t tag, acl_perm_t perm,
93    acl_entry_type_t entry_type)
94{
95	struct acl_entry *ae;
96
97	KASSERT(aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES);
98
99	ae = &(aclp->acl_entry[aclp->acl_cnt]);
100	aclp->acl_cnt++;
101
102	ae->ae_tag = tag;
103	ae->ae_id = ACL_UNDEFINED_ID;
104	ae->ae_perm = perm;
105	ae->ae_entry_type = entry_type;
106	ae->ae_flags = 0;
107
108	return (ae);
109}
110
111#if 0
112static struct acl_entry *
113_acl_duplicate_entry(struct acl *aclp, unsigned int entry_index)
114{
115	size_t i;
116
117	KASSERT(aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES);
118
119	for (i = aclp->acl_cnt; i > entry_index; i--)
120		aclp->acl_entry[i] = aclp->acl_entry[i - 1];
121
122	aclp->acl_cnt++;
123
124	return (&(aclp->acl_entry[entry_index + 1]));
125}
126#endif
127
128
129#ifdef _KERNEL
130void
131acl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode,
132    int file_owner_id)
133{
134
135	acl_nfs4_trivial_from_mode(aclp, mode);
136}
137#endif /* _KERNEL */
138
139void
140__acl_nfs4_sync_mode_from_acl(mode_t *_mode, const struct acl *aclp)
141{
142	size_t i;
143	mode_t old_mode = *_mode, mode = 0, seen = 0;
144	const struct acl_entry *ae;
145
146	KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES);
147
148	/*
149	 * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt
150	 *
151	 * 3.16.6.1. Recomputing mode upon SETATTR of ACL
152	 */
153
154	for (i = 0; i < aclp->acl_cnt; i++) {
155		ae = &(aclp->acl_entry[i]);
156
157		if (ae->ae_entry_type != ACL_ENTRY_TYPE_ALLOW &&
158		    ae->ae_entry_type != ACL_ENTRY_TYPE_DENY)
159			continue;
160
161		if (ae->ae_flags & ACL_ENTRY_INHERIT_ONLY)
162			continue;
163
164		if (ae->ae_tag == ACL_USER_OBJ) {
165			if ((ae->ae_perm & ACL_READ_DATA) &&
166			    ((seen & S_IRUSR) == 0)) {
167				seen |= S_IRUSR;
168				if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
169					mode |= S_IRUSR;
170			}
171			if ((ae->ae_perm & ACL_WRITE_DATA) &&
172			     ((seen & S_IWUSR) == 0)) {
173				seen |= S_IWUSR;
174				if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
175					mode |= S_IWUSR;
176			}
177			if ((ae->ae_perm & ACL_EXECUTE) &&
178			    ((seen & S_IXUSR) == 0)) {
179				seen |= S_IXUSR;
180				if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
181					mode |= S_IXUSR;
182			}
183		} else if (ae->ae_tag == ACL_GROUP_OBJ) {
184			if ((ae->ae_perm & ACL_READ_DATA) &&
185			    ((seen & S_IRGRP) == 0)) {
186				seen |= S_IRGRP;
187				if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
188					mode |= S_IRGRP;
189			}
190			if ((ae->ae_perm & ACL_WRITE_DATA) &&
191			    ((seen & S_IWGRP) == 0)) {
192				seen |= S_IWGRP;
193				if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
194					mode |= S_IWGRP;
195			}
196			if ((ae->ae_perm & ACL_EXECUTE) &&
197			    ((seen & S_IXGRP) == 0)) {
198				seen |= S_IXGRP;
199				if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
200					mode |= S_IXGRP;
201			}
202		} else if (ae->ae_tag == ACL_EVERYONE) {
203			if (ae->ae_perm & ACL_READ_DATA) {
204				if ((seen & S_IRUSR) == 0) {
205					seen |= S_IRUSR;
206					if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
207						mode |= S_IRUSR;
208				}
209				if ((seen & S_IRGRP) == 0) {
210					seen |= S_IRGRP;
211					if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
212						mode |= S_IRGRP;
213				}
214				if ((seen & S_IROTH) == 0) {
215					seen |= S_IROTH;
216					if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
217						mode |= S_IROTH;
218				}
219			}
220			if (ae->ae_perm & ACL_WRITE_DATA) {
221				if ((seen & S_IWUSR) == 0) {
222					seen |= S_IWUSR;
223					if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
224						mode |= S_IWUSR;
225				}
226				if ((seen & S_IWGRP) == 0) {
227					seen |= S_IWGRP;
228					if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
229						mode |= S_IWGRP;
230				}
231				if ((seen & S_IWOTH) == 0) {
232					seen |= S_IWOTH;
233					if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
234						mode |= S_IWOTH;
235				}
236			}
237			if (ae->ae_perm & ACL_EXECUTE) {
238				if ((seen & S_IXUSR) == 0) {
239					seen |= S_IXUSR;
240					if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
241						mode |= S_IXUSR;
242				}
243				if ((seen & S_IXGRP) == 0) {
244					seen |= S_IXGRP;
245					if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
246						mode |= S_IXGRP;
247				}
248				if ((seen & S_IXOTH) == 0) {
249					seen |= S_IXOTH;
250					if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
251						mode |= S_IXOTH;
252				}
253			}
254		}
255	}
256
257	*_mode = mode | (old_mode & ACL_PRESERVE_MASK);
258}
259
260/*
261 * Populate the ACL with entries inherited from parent_aclp.
262 */
263static void
264/*ARGSUSED*/
265acl_nfs4_inherit_entries(const struct acl *parent_aclp,
266    struct acl *child_aclp, mode_t mode, int file_owner_id,
267    int is_directory)
268{
269	int flags, tag;
270	size_t i;
271	const struct acl_entry *parent_entry;
272	struct acl_entry *ae;
273
274	KASSERT(parent_aclp->acl_cnt <= ACL_MAX_ENTRIES);
275
276	for (i = 0; i < parent_aclp->acl_cnt; i++) {
277		parent_entry = &(parent_aclp->acl_entry[i]);
278		flags = parent_entry->ae_flags;
279		tag = parent_entry->ae_tag;
280
281		/*
282		 * Don't inherit owner@, group@, or everyone@ entries.
283		 */
284		if (tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ ||
285		    tag == ACL_EVERYONE)
286			continue;
287
288		/*
289		 * Entry is not inheritable at all.
290		 */
291		if ((flags & (ACL_ENTRY_DIRECTORY_INHERIT |
292		    ACL_ENTRY_FILE_INHERIT)) == 0)
293			continue;
294
295		/*
296		 * We're creating a file, but ae is not inheritable
297		 * by files.
298		 */
299		if (!is_directory && (flags & ACL_ENTRY_FILE_INHERIT) == 0)
300			continue;
301
302		/*
303		 * Entry is inheritable only by files, but has NO_PROPAGATE
304		 * flag set, and we're creating a directory, so it wouldn't
305		 * propagate to any file in that directory anyway.
306		 */
307		if (is_directory &&
308		    (flags & ACL_ENTRY_DIRECTORY_INHERIT) == 0 &&
309		    (flags & ACL_ENTRY_NO_PROPAGATE_INHERIT))
310			continue;
311
312		/*
313		 * Entry qualifies for being inherited.
314		 */
315		KASSERT(child_aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES);
316		ae = &(child_aclp->acl_entry[child_aclp->acl_cnt]);
317		*ae = *parent_entry;
318		child_aclp->acl_cnt++;
319
320		ae->ae_flags &= ~ACL_ENTRY_INHERIT_ONLY;
321		ae->ae_flags |= ACL_ENTRY_INHERITED;
322
323		/*
324		 * If the type of the ACE is neither ALLOW nor DENY,
325		 * then leave it as it is and proceed to the next one.
326		 */
327		if (ae->ae_entry_type != ACL_ENTRY_TYPE_ALLOW &&
328		    ae->ae_entry_type != ACL_ENTRY_TYPE_DENY)
329			continue;
330
331		/*
332		 * If the ACL_ENTRY_NO_PROPAGATE_INHERIT is set, or if
333		 * the object being created is not a directory, then clear
334		 * the following flags: ACL_ENTRY_NO_PROPAGATE_INHERIT,
335		 * ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT,
336		 * ACL_ENTRY_INHERIT_ONLY.
337		 */
338		if (ae->ae_flags & ACL_ENTRY_NO_PROPAGATE_INHERIT ||
339		    !is_directory) {
340			ae->ae_flags &= ~(ACL_ENTRY_NO_PROPAGATE_INHERIT |
341			ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT |
342			ACL_ENTRY_INHERIT_ONLY);
343		}
344
345		/*
346		 * If the object is a directory and ACL_ENTRY_FILE_INHERIT
347		 * is set, but ACL_ENTRY_DIRECTORY_INHERIT is not set, ensure
348		 * that ACL_ENTRY_INHERIT_ONLY is set.
349		 */
350		if (is_directory &&
351		    (ae->ae_flags & ACL_ENTRY_FILE_INHERIT) &&
352		    ((ae->ae_flags & ACL_ENTRY_DIRECTORY_INHERIT) == 0)) {
353			ae->ae_flags |= ACL_ENTRY_INHERIT_ONLY;
354		}
355
356		if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW &&
357		    (ae->ae_flags & ACL_ENTRY_INHERIT_ONLY) == 0) {
358			/*
359			 * Some permissions must never be inherited.
360			 */
361			ae->ae_perm &= ~(ACL_WRITE_ACL | ACL_WRITE_OWNER |
362			    ACL_WRITE_NAMED_ATTRS | ACL_WRITE_ATTRIBUTES);
363
364			/*
365			 * Others must be masked according to the file mode.
366			 */
367			if ((mode & S_IRGRP) == 0)
368				ae->ae_perm &= ~ACL_READ_DATA;
369			if ((mode & S_IWGRP) == 0)
370				ae->ae_perm &=
371				    ~(ACL_WRITE_DATA | ACL_APPEND_DATA);
372			if ((mode & S_IXGRP) == 0)
373				ae->ae_perm &= ~ACL_EXECUTE;
374		}
375	}
376}
377
378/*
379 * Calculate inherited ACL in a manner compatible with PSARC/2010/029.
380 * It's also being used to calculate a trivial ACL, by inheriting from
381 * a NULL ACL.
382 */
383static void
384acl_nfs4_compute_inherited_acl_psarc(const struct acl *parent_aclp,
385    struct acl *aclp, mode_t mode, int file_owner_id, int is_directory)
386{
387	acl_perm_t user_allow_first = 0, user_deny = 0, group_deny = 0;
388	acl_perm_t user_allow, group_allow, everyone_allow;
389
390	KASSERT(aclp->acl_cnt == 0);
391
392	user_allow = group_allow = everyone_allow = ACL_READ_ACL |
393	    ACL_READ_ATTRIBUTES | ACL_READ_NAMED_ATTRS | ACL_SYNCHRONIZE;
394	user_allow |= ACL_WRITE_ACL | ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES |
395	    ACL_WRITE_NAMED_ATTRS;
396
397	if (mode & S_IRUSR)
398		user_allow |= ACL_READ_DATA;
399	if (mode & S_IWUSR)
400		user_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
401	if (mode & S_IXUSR)
402		user_allow |= ACL_EXECUTE;
403
404	if (mode & S_IRGRP)
405		group_allow |= ACL_READ_DATA;
406	if (mode & S_IWGRP)
407		group_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
408	if (mode & S_IXGRP)
409		group_allow |= ACL_EXECUTE;
410
411	if (mode & S_IROTH)
412		everyone_allow |= ACL_READ_DATA;
413	if (mode & S_IWOTH)
414		everyone_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
415	if (mode & S_IXOTH)
416		everyone_allow |= ACL_EXECUTE;
417
418	user_deny = ((group_allow | everyone_allow) & ~user_allow);
419	group_deny = everyone_allow & ~group_allow;
420	user_allow_first = group_deny & ~user_deny;
421
422	if (user_allow_first != 0)
423		_acl_append(aclp, ACL_USER_OBJ, user_allow_first,
424		    ACL_ENTRY_TYPE_ALLOW);
425	if (user_deny != 0)
426		_acl_append(aclp, ACL_USER_OBJ, user_deny,
427		    ACL_ENTRY_TYPE_DENY);
428	if (group_deny != 0)
429		_acl_append(aclp, ACL_GROUP_OBJ, group_deny,
430		    ACL_ENTRY_TYPE_DENY);
431
432	if (parent_aclp != NULL)
433		acl_nfs4_inherit_entries(parent_aclp, aclp, mode,
434		    file_owner_id, is_directory);
435
436	_acl_append(aclp, ACL_USER_OBJ, user_allow, ACL_ENTRY_TYPE_ALLOW);
437	_acl_append(aclp, ACL_GROUP_OBJ, group_allow, ACL_ENTRY_TYPE_ALLOW);
438	_acl_append(aclp, ACL_EVERYONE, everyone_allow, ACL_ENTRY_TYPE_ALLOW);
439}
440
441#ifdef _KERNEL
442void
443acl_nfs4_compute_inherited_acl(const struct acl *parent_aclp,
444    struct acl *child_aclp, mode_t mode, int file_owner_id,
445    int is_directory)
446{
447
448	acl_nfs4_compute_inherited_acl_psarc(parent_aclp, child_aclp,
449	    mode, file_owner_id, is_directory);
450}
451#endif /* _KERNEL */
452
453/*
454 * Calculate trivial ACL in a manner compatible with PSARC/2010/029.
455 * Note that this results in an ACL different from (but semantically
456 * equal to) the "canonical six" trivial ACL computed using algorithm
457 * described in draft-ietf-nfsv4-minorversion1-03.txt, 3.16.6.2.
458 */
459static void
460acl_nfs4_trivial_from_mode(struct acl *aclp, mode_t mode)
461{
462
463	aclp->acl_cnt = 0;
464	acl_nfs4_compute_inherited_acl_psarc(NULL, aclp, mode, -1, -1);
465}
466
467#ifndef _KERNEL
468/*
469 * This routine is used by libc to implement acl_strip_np(3)
470 * and acl_is_trivial_np(3).
471 */
472void
473/*ARGSUSED*/
474__acl_nfs4_trivial_from_mode_libc(struct acl *aclp, int mode, int canonical_six)
475{
476
477	aclp->acl_cnt = 0;
478	acl_nfs4_trivial_from_mode(aclp, mode);
479}
480#endif /* !_KERNEL */
481
482#ifdef _KERNEL
483static int
484_acls_are_equal(const struct acl *a, const struct acl *b)
485{
486	int i;
487	const struct acl_entry *entrya, *entryb;
488
489	if (a->acl_cnt != b->acl_cnt)
490		return (0);
491
492	for (i = 0; i < b->acl_cnt; i++) {
493		entrya = &(a->acl_entry[i]);
494		entryb = &(b->acl_entry[i]);
495
496		if (entrya->ae_tag != entryb->ae_tag ||
497		    entrya->ae_id != entryb->ae_id ||
498		    entrya->ae_perm != entryb->ae_perm ||
499		    entrya->ae_entry_type != entryb->ae_entry_type ||
500		    entrya->ae_flags != entryb->ae_flags)
501			return (0);
502	}
503
504	return (1);
505}
506
507/*
508 * This routine is used to determine whether to remove extended attribute
509 * that stores ACL contents.
510 */
511int
512acl_nfs4_is_trivial(const struct acl *aclp, int file_owner_id)
513{
514	int trivial;
515	mode_t tmpmode = 0;
516	struct acl *tmpaclp;
517
518	if (aclp->acl_cnt > 6)
519		return (0);
520
521	/*
522	 * Compute the mode from the ACL, then compute new ACL from that mode.
523	 * If the ACLs are identical, then the ACL is trivial.
524	 *
525	 * XXX: I guess there is a faster way to do this.  However, even
526	 *      this slow implementation significantly speeds things up
527	 *      for files that don't have non-trivial ACLs - it's critical
528	 *      for performance to not use EA when they are not needed.
529	 *
530	 * First try the PSARC/2010/029 semantics.
531	 */
532	tmpaclp = acl_alloc(KM_SLEEP);
533	__acl_nfs4_sync_mode_from_acl(&tmpmode, aclp);
534	acl_nfs4_trivial_from_mode(tmpaclp, tmpmode);
535	trivial = _acls_are_equal(aclp, tmpaclp);
536	if (trivial) {
537		acl_free(tmpaclp);
538		return (trivial);
539	}
540
541	/*
542	 * Check if it's a draft-ietf-nfsv4-minorversion1-03.txt trivial ACL.
543	 */
544	acl_free(tmpaclp);
545
546	return (trivial);
547}
548
549int
550acl_nfs4_check(const struct acl *aclp, int is_directory)
551{
552	size_t i;
553	const struct acl_entry *ae;
554
555	/*
556	 * The spec doesn't seem to say anything about ACL validity.
557	 * It seems there is not much to do here.  There is even no need
558	 * to count "owner@" or "everyone@" (ACL_USER_OBJ and ACL_EVERYONE)
559	 * entries, as there can be several of them and that's perfectly
560	 * valid.  There can be none of them too.  Really.
561	 */
562
563	if (aclp->acl_cnt > ACL_MAX_ENTRIES || aclp->acl_cnt <= 0)
564		return (EINVAL);
565
566	for (i = 0; i < aclp->acl_cnt; i++) {
567		ae = &(aclp->acl_entry[i]);
568
569		switch (ae->ae_tag) {
570		case ACL_USER_OBJ:
571		case ACL_GROUP_OBJ:
572		case ACL_EVERYONE:
573			if (ae->ae_id != ACL_UNDEFINED_ID)
574				return (EINVAL);
575			break;
576
577		case ACL_USER:
578		case ACL_GROUP:
579			if (ae->ae_id == ACL_UNDEFINED_ID)
580				return (EINVAL);
581			break;
582
583		default:
584			return (EINVAL);
585		}
586
587		if ((ae->ae_perm | ACL_NFS4_PERM_BITS) != ACL_NFS4_PERM_BITS)
588			return (EINVAL);
589
590		/*
591		 * Disallow ACL_ENTRY_TYPE_AUDIT and ACL_ENTRY_TYPE_ALARM for now.
592		 */
593		if (ae->ae_entry_type != ACL_ENTRY_TYPE_ALLOW &&
594		    ae->ae_entry_type != ACL_ENTRY_TYPE_DENY)
595			return (EINVAL);
596
597		if ((ae->ae_flags | ACL_FLAGS_BITS) != ACL_FLAGS_BITS)
598			return (EINVAL);
599
600		/* Disallow unimplemented flags. */
601		if (ae->ae_flags & (ACL_ENTRY_SUCCESSFUL_ACCESS |
602		    ACL_ENTRY_FAILED_ACCESS))
603			return (EINVAL);
604
605		/* Disallow flags not allowed for ordinary files. */
606		if (!is_directory) {
607			if (ae->ae_flags & (ACL_ENTRY_FILE_INHERIT |
608			    ACL_ENTRY_DIRECTORY_INHERIT |
609			    ACL_ENTRY_NO_PROPAGATE_INHERIT | ACL_ENTRY_INHERIT_ONLY))
610				return (EINVAL);
611		}
612	}
613
614	return (0);
615}
616#endif
617