xref: /freebsd/sys/kern/subr_acl_posix1e.c (revision ab40f58ccfe6c07ebefddc72f4661a52fe746353)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 1999-2006 Robert N. M. Watson
5  * All rights reserved.
6  *
7  * This software was developed by Robert Watson for the TrustedBSD Project.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 /*
31  * Developed by the TrustedBSD Project.
32  *
33  * ACL support routines specific to POSIX.1e access control lists.  These are
34  * utility routines for code common across file systems implementing POSIX.1e
35  * ACLs.
36  */
37 
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40 
41 #include <sys/param.h>
42 #include <sys/kernel.h>
43 #include <sys/module.h>
44 #include <sys/systm.h>
45 #include <sys/mount.h>
46 #include <sys/priv.h>
47 #include <sys/vnode.h>
48 #include <sys/errno.h>
49 #include <sys/stat.h>
50 #include <sys/acl.h>
51 
52 /*
53  * Implement a version of vaccess() that understands POSIX.1e ACL semantics;
54  * the access ACL has already been prepared for evaluation by the file system
55  * and is passed via 'uid', 'gid', and 'acl'.  Return 0 on success, else an
56  * errno value.
57  */
58 int
59 vaccess_acl_posix1e(enum vtype type, uid_t file_uid, gid_t file_gid,
60     struct acl *acl, accmode_t accmode, struct ucred *cred, int *privused)
61 {
62 	struct acl_entry *acl_other, *acl_mask;
63 	accmode_t dac_granted;
64 	accmode_t priv_granted;
65 	accmode_t acl_mask_granted;
66 	int group_matched, i;
67 
68 	KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND)) == 0,
69 	    ("invalid bit in accmode"));
70 	KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE),
71 	    	("VAPPEND without VWRITE"));
72 
73 	/*
74 	 * Look for a normal, non-privileged way to access the file/directory
75 	 * as requested.  If it exists, go with that.  Otherwise, attempt to
76 	 * use privileges granted via priv_granted.  In some cases, which
77 	 * privileges to use may be ambiguous due to "best match", in which
78 	 * case fall back on first match for the time being.
79 	 */
80 	if (privused != NULL)
81 		*privused = 0;
82 
83 	/*
84 	 * Determine privileges now, but don't apply until we've found a DAC
85 	 * entry that matches but has failed to allow access.
86 	 *
87 	 * XXXRW: Ideally, we'd determine the privileges required before
88 	 * asking for them.
89 	 */
90 	priv_granted = 0;
91 
92 	if (type == VDIR) {
93 		if ((accmode & VEXEC) && !priv_check_cred(cred,
94 		     PRIV_VFS_LOOKUP, 0))
95 			priv_granted |= VEXEC;
96 	} else {
97 		/*
98 		 * Ensure that at least one execute bit is on. Otherwise,
99 		 * a privileged user will always succeed, and we don't want
100 		 * this to happen unless the file really is executable.
101 		 */
102 		if ((accmode & VEXEC) && (acl_posix1e_acl_to_mode(acl) &
103 		    (S_IXUSR | S_IXGRP | S_IXOTH)) != 0 &&
104 		    !priv_check_cred(cred, PRIV_VFS_EXEC, 0))
105 			priv_granted |= VEXEC;
106 	}
107 
108 	if ((accmode & VREAD) && !priv_check_cred(cred, PRIV_VFS_READ, 0))
109 		priv_granted |= VREAD;
110 
111 	if (((accmode & VWRITE) || (accmode & VAPPEND)) &&
112 	    !priv_check_cred(cred, PRIV_VFS_WRITE, 0))
113 		priv_granted |= (VWRITE | VAPPEND);
114 
115 	if ((accmode & VADMIN) && !priv_check_cred(cred, PRIV_VFS_ADMIN, 0))
116 		priv_granted |= VADMIN;
117 
118 	/*
119 	 * The owner matches if the effective uid associated with the
120 	 * credential matches that of the ACL_USER_OBJ entry.  While we're
121 	 * doing the first scan, also cache the location of the ACL_MASK and
122 	 * ACL_OTHER entries, preventing some future iterations.
123 	 */
124 	acl_mask = acl_other = NULL;
125 	for (i = 0; i < acl->acl_cnt; i++) {
126 		switch (acl->acl_entry[i].ae_tag) {
127 		case ACL_USER_OBJ:
128 			if (file_uid != cred->cr_uid)
129 				break;
130 			dac_granted = 0;
131 			dac_granted |= VADMIN;
132 			if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
133 				dac_granted |= VEXEC;
134 			if (acl->acl_entry[i].ae_perm & ACL_READ)
135 				dac_granted |= VREAD;
136 			if (acl->acl_entry[i].ae_perm & ACL_WRITE)
137 				dac_granted |= (VWRITE | VAPPEND);
138 			if ((accmode & dac_granted) == accmode)
139 				return (0);
140 
141 			/*
142 			 * XXXRW: Do privilege lookup here.
143 			 */
144 			if ((accmode & (dac_granted | priv_granted)) ==
145 			    accmode) {
146 				if (privused != NULL)
147 					*privused = 1;
148 				return (0);
149 			}
150 			goto error;
151 
152 		case ACL_MASK:
153 			acl_mask = &acl->acl_entry[i];
154 			break;
155 
156 		case ACL_OTHER:
157 			acl_other = &acl->acl_entry[i];
158 			break;
159 
160 		default:
161 			break;
162 		}
163 	}
164 
165 	/*
166 	 * An ACL_OTHER entry should always exist in a valid access ACL.  If
167 	 * it doesn't, then generate a serious failure.  For now, this means
168 	 * a debugging message and EPERM, but in the future should probably
169 	 * be a panic.
170 	 */
171 	if (acl_other == NULL) {
172 		/*
173 		 * XXX This should never happen
174 		 */
175 		printf("vaccess_acl_posix1e: ACL_OTHER missing\n");
176 		return (EPERM);
177 	}
178 
179 	/*
180 	 * Checks against ACL_USER, ACL_GROUP_OBJ, and ACL_GROUP fields are
181 	 * masked by an ACL_MASK entry, if any.  As such, first identify the
182 	 * ACL_MASK field, then iterate through identifying potential user
183 	 * matches, then group matches.  If there is no ACL_MASK, assume that
184 	 * the mask allows all requests to succeed.
185 	 */
186 	if (acl_mask != NULL) {
187 		acl_mask_granted = 0;
188 		if (acl_mask->ae_perm & ACL_EXECUTE)
189 			acl_mask_granted |= VEXEC;
190 		if (acl_mask->ae_perm & ACL_READ)
191 			acl_mask_granted |= VREAD;
192 		if (acl_mask->ae_perm & ACL_WRITE)
193 			acl_mask_granted |= (VWRITE | VAPPEND);
194 	} else
195 		acl_mask_granted = VEXEC | VREAD | VWRITE | VAPPEND;
196 
197 	/*
198 	 * Check ACL_USER ACL entries.  There will either be one or no
199 	 * matches; if there is one, we accept or rejected based on the
200 	 * match; otherwise, we continue on to groups.
201 	 */
202 	for (i = 0; i < acl->acl_cnt; i++) {
203 		switch (acl->acl_entry[i].ae_tag) {
204 		case ACL_USER:
205 			if (acl->acl_entry[i].ae_id != cred->cr_uid)
206 				break;
207 			dac_granted = 0;
208 			if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
209 				dac_granted |= VEXEC;
210 			if (acl->acl_entry[i].ae_perm & ACL_READ)
211 				dac_granted |= VREAD;
212 			if (acl->acl_entry[i].ae_perm & ACL_WRITE)
213 				dac_granted |= (VWRITE | VAPPEND);
214 			dac_granted &= acl_mask_granted;
215 			if ((accmode & dac_granted) == accmode)
216 				return (0);
217 			/*
218 			 * XXXRW: Do privilege lookup here.
219 			 */
220 			if ((accmode & (dac_granted | priv_granted)) !=
221 			    accmode)
222 				goto error;
223 
224 			if (privused != NULL)
225 				*privused = 1;
226 			return (0);
227 		}
228 	}
229 
230 	/*
231 	 * Group match is best-match, not first-match, so find a "best"
232 	 * match.  Iterate across, testing each potential group match.  Make
233 	 * sure we keep track of whether we found a match or not, so that we
234 	 * know if we should try again with any available privilege, or if we
235 	 * should move on to ACL_OTHER.
236 	 */
237 	group_matched = 0;
238 	for (i = 0; i < acl->acl_cnt; i++) {
239 		switch (acl->acl_entry[i].ae_tag) {
240 		case ACL_GROUP_OBJ:
241 			if (!groupmember(file_gid, cred))
242 				break;
243 			dac_granted = 0;
244 			if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
245 				dac_granted |= VEXEC;
246 			if (acl->acl_entry[i].ae_perm & ACL_READ)
247 				dac_granted |= VREAD;
248 			if (acl->acl_entry[i].ae_perm & ACL_WRITE)
249 				dac_granted |= (VWRITE | VAPPEND);
250 			dac_granted  &= acl_mask_granted;
251 
252 			if ((accmode & dac_granted) == accmode)
253 				return (0);
254 
255 			group_matched = 1;
256 			break;
257 
258 		case ACL_GROUP:
259 			if (!groupmember(acl->acl_entry[i].ae_id, cred))
260 				break;
261 			dac_granted = 0;
262 			if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
263 				dac_granted |= VEXEC;
264 			if (acl->acl_entry[i].ae_perm & ACL_READ)
265 				dac_granted |= VREAD;
266 			if (acl->acl_entry[i].ae_perm & ACL_WRITE)
267 				dac_granted |= (VWRITE | VAPPEND);
268 			dac_granted  &= acl_mask_granted;
269 
270 			if ((accmode & dac_granted) == accmode)
271 				return (0);
272 
273 			group_matched = 1;
274 			break;
275 
276 		default:
277 			break;
278 		}
279 	}
280 
281 	if (group_matched == 1) {
282 		/*
283 		 * There was a match, but it did not grant rights via pure
284 		 * DAC.  Try again, this time with privilege.
285 		 */
286 		for (i = 0; i < acl->acl_cnt; i++) {
287 			switch (acl->acl_entry[i].ae_tag) {
288 			case ACL_GROUP_OBJ:
289 				if (!groupmember(file_gid, cred))
290 					break;
291 				dac_granted = 0;
292 				if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
293 					dac_granted |= VEXEC;
294 				if (acl->acl_entry[i].ae_perm & ACL_READ)
295 					dac_granted |= VREAD;
296 				if (acl->acl_entry[i].ae_perm & ACL_WRITE)
297 					dac_granted |= (VWRITE | VAPPEND);
298 				dac_granted &= acl_mask_granted;
299 
300 				/*
301 				 * XXXRW: Do privilege lookup here.
302 				 */
303 				if ((accmode & (dac_granted | priv_granted))
304 				    != accmode)
305 					break;
306 
307 				if (privused != NULL)
308 					*privused = 1;
309 				return (0);
310 
311 			case ACL_GROUP:
312 				if (!groupmember(acl->acl_entry[i].ae_id,
313 				    cred))
314 					break;
315 				dac_granted = 0;
316 				if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
317 				dac_granted |= VEXEC;
318 				if (acl->acl_entry[i].ae_perm & ACL_READ)
319 					dac_granted |= VREAD;
320 				if (acl->acl_entry[i].ae_perm & ACL_WRITE)
321 					dac_granted |= (VWRITE | VAPPEND);
322 				dac_granted &= acl_mask_granted;
323 
324 				/*
325 				 * XXXRW: Do privilege lookup here.
326 				 */
327 				if ((accmode & (dac_granted | priv_granted))
328 				    != accmode)
329 					break;
330 
331 				if (privused != NULL)
332 					*privused = 1;
333 				return (0);
334 
335 			default:
336 				break;
337 			}
338 		}
339 		/*
340 		 * Even with privilege, group membership was not sufficient.
341 		 * Return failure.
342 		 */
343 		goto error;
344 	}
345 
346 	/*
347 	 * Fall back on ACL_OTHER.  ACL_MASK is not applied to ACL_OTHER.
348 	 */
349 	dac_granted = 0;
350 	if (acl_other->ae_perm & ACL_EXECUTE)
351 		dac_granted |= VEXEC;
352 	if (acl_other->ae_perm & ACL_READ)
353 		dac_granted |= VREAD;
354 	if (acl_other->ae_perm & ACL_WRITE)
355 		dac_granted |= (VWRITE | VAPPEND);
356 
357 	if ((accmode & dac_granted) == accmode)
358 		return (0);
359 	/*
360 	 * XXXRW: Do privilege lookup here.
361 	 */
362 	if ((accmode & (dac_granted | priv_granted)) == accmode) {
363 		if (privused != NULL)
364 			*privused = 1;
365 		return (0);
366 	}
367 
368 error:
369 	return ((accmode & VADMIN) ? EPERM : EACCES);
370 }
371 
372 /*
373  * For the purposes of filesystems maintaining the _OBJ entries in an inode
374  * with a mode_t field, this routine converts a mode_t entry to an
375  * acl_perm_t.
376  */
377 acl_perm_t
378 acl_posix1e_mode_to_perm(acl_tag_t tag, mode_t mode)
379 {
380 	acl_perm_t	perm = 0;
381 
382 	switch(tag) {
383 	case ACL_USER_OBJ:
384 		if (mode & S_IXUSR)
385 			perm |= ACL_EXECUTE;
386 		if (mode & S_IRUSR)
387 			perm |= ACL_READ;
388 		if (mode & S_IWUSR)
389 			perm |= ACL_WRITE;
390 		return (perm);
391 
392 	case ACL_GROUP_OBJ:
393 		if (mode & S_IXGRP)
394 			perm |= ACL_EXECUTE;
395 		if (mode & S_IRGRP)
396 			perm |= ACL_READ;
397 		if (mode & S_IWGRP)
398 			perm |= ACL_WRITE;
399 		return (perm);
400 
401 	case ACL_OTHER:
402 		if (mode & S_IXOTH)
403 			perm |= ACL_EXECUTE;
404 		if (mode & S_IROTH)
405 			perm |= ACL_READ;
406 		if (mode & S_IWOTH)
407 			perm |= ACL_WRITE;
408 		return (perm);
409 
410 	default:
411 		printf("acl_posix1e_mode_to_perm: invalid tag (%d)\n", tag);
412 		return (0);
413 	}
414 }
415 
416 /*
417  * Given inode information (uid, gid, mode), return an acl entry of the
418  * appropriate type.
419  */
420 struct acl_entry
421 acl_posix1e_mode_to_entry(acl_tag_t tag, uid_t uid, gid_t gid, mode_t mode)
422 {
423 	struct acl_entry	acl_entry;
424 
425 	acl_entry.ae_tag = tag;
426 	acl_entry.ae_perm = acl_posix1e_mode_to_perm(tag, mode);
427 	acl_entry.ae_entry_type = 0;
428 	acl_entry.ae_flags = 0;
429 	switch(tag) {
430 	case ACL_USER_OBJ:
431 		acl_entry.ae_id = uid;
432 		break;
433 
434 	case ACL_GROUP_OBJ:
435 		acl_entry.ae_id = gid;
436 		break;
437 
438 	case ACL_OTHER:
439 		acl_entry.ae_id = ACL_UNDEFINED_ID;
440 		break;
441 
442 	default:
443 		acl_entry.ae_id = ACL_UNDEFINED_ID;
444 		printf("acl_posix1e_mode_to_entry: invalid tag (%d)\n", tag);
445 	}
446 
447 	return (acl_entry);
448 }
449 
450 /*
451  * Utility function to generate a file mode given appropriate ACL entries.
452  */
453 mode_t
454 acl_posix1e_perms_to_mode(struct acl_entry *acl_user_obj_entry,
455     struct acl_entry *acl_group_obj_entry, struct acl_entry *acl_other_entry)
456 {
457 	mode_t	mode;
458 
459 	mode = 0;
460 	if (acl_user_obj_entry->ae_perm & ACL_EXECUTE)
461 		mode |= S_IXUSR;
462 	if (acl_user_obj_entry->ae_perm & ACL_READ)
463 		mode |= S_IRUSR;
464 	if (acl_user_obj_entry->ae_perm & ACL_WRITE)
465 		mode |= S_IWUSR;
466 	if (acl_group_obj_entry->ae_perm & ACL_EXECUTE)
467 		mode |= S_IXGRP;
468 	if (acl_group_obj_entry->ae_perm & ACL_READ)
469 		mode |= S_IRGRP;
470 	if (acl_group_obj_entry->ae_perm & ACL_WRITE)
471 		mode |= S_IWGRP;
472 	if (acl_other_entry->ae_perm & ACL_EXECUTE)
473 		mode |= S_IXOTH;
474 	if (acl_other_entry->ae_perm & ACL_READ)
475 		mode |= S_IROTH;
476 	if (acl_other_entry->ae_perm & ACL_WRITE)
477 		mode |= S_IWOTH;
478 
479 	return (mode);
480 }
481 
482 /*
483  * Utility function to generate a file mode given a complete POSIX.1e access
484  * ACL.  Note that if the ACL is improperly formed, this may result in a
485  * panic.
486  */
487 mode_t
488 acl_posix1e_acl_to_mode(struct acl *acl)
489 {
490 	struct acl_entry *acl_mask, *acl_user_obj, *acl_group_obj, *acl_other;
491 	int i;
492 
493 	/*
494 	 * Find the ACL entries relevant to a POSIX permission mode.
495 	 */
496 	acl_user_obj = acl_group_obj = acl_other = acl_mask = NULL;
497 	for (i = 0; i < acl->acl_cnt; i++) {
498 		switch (acl->acl_entry[i].ae_tag) {
499 		case ACL_USER_OBJ:
500 			acl_user_obj = &acl->acl_entry[i];
501 			break;
502 
503 		case ACL_GROUP_OBJ:
504 			acl_group_obj = &acl->acl_entry[i];
505 			break;
506 
507 		case ACL_OTHER:
508 			acl_other = &acl->acl_entry[i];
509 			break;
510 
511 		case ACL_MASK:
512 			acl_mask = &acl->acl_entry[i];
513 			break;
514 
515 		case ACL_USER:
516 		case ACL_GROUP:
517 			break;
518 
519 		default:
520 			panic("acl_posix1e_acl_to_mode: bad ae_tag");
521 		}
522 	}
523 
524 	if (acl_user_obj == NULL || acl_group_obj == NULL || acl_other == NULL)
525 		panic("acl_posix1e_acl_to_mode: missing base ae_tags");
526 
527 	/*
528 	 * POSIX.1e specifies that if there is an ACL_MASK entry, we replace
529 	 * the mode "group" bits with its permissions.  If there isn't, we
530 	 * use the ACL_GROUP_OBJ permissions.
531 	 */
532 	if (acl_mask != NULL)
533 		return (acl_posix1e_perms_to_mode(acl_user_obj, acl_mask,
534 		    acl_other));
535 	else
536 		return (acl_posix1e_perms_to_mode(acl_user_obj, acl_group_obj,
537 		    acl_other));
538 }
539 
540 /*
541  * Perform a syntactic check of the ACL, sufficient to allow an implementing
542  * filesystem to determine if it should accept this and rely on the POSIX.1e
543  * ACL properties.
544  */
545 int
546 acl_posix1e_check(struct acl *acl)
547 {
548 	int num_acl_user_obj, num_acl_user, num_acl_group_obj, num_acl_group;
549 	int num_acl_mask, num_acl_other, i;
550 
551 	/*
552 	 * Verify that the number of entries does not exceed the maximum
553 	 * defined for acl_t.
554 	 *
555 	 * Verify that the correct number of various sorts of ae_tags are
556 	 * present:
557 	 *   Exactly one ACL_USER_OBJ
558 	 *   Exactly one ACL_GROUP_OBJ
559 	 *   Exactly one ACL_OTHER
560 	 *   If any ACL_USER or ACL_GROUP entries appear, then exactly one
561 	 *   ACL_MASK entry must also appear.
562 	 *
563 	 * Verify that all ae_perm entries are in ACL_PERM_BITS.
564 	 *
565 	 * Verify all ae_tag entries are understood by this implementation.
566 	 *
567 	 * Note: Does not check for uniqueness of qualifier (ae_id) field.
568 	 */
569 	num_acl_user_obj = num_acl_user = num_acl_group_obj = num_acl_group =
570 	    num_acl_mask = num_acl_other = 0;
571 	if (acl->acl_cnt > ACL_MAX_ENTRIES)
572 		return (EINVAL);
573 	for (i = 0; i < acl->acl_cnt; i++) {
574 		/*
575 		 * Check for a valid tag.
576 		 */
577 		switch(acl->acl_entry[i].ae_tag) {
578 		case ACL_USER_OBJ:
579 			acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
580 			if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
581 				return (EINVAL);
582 			num_acl_user_obj++;
583 			break;
584 		case ACL_GROUP_OBJ:
585 			acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
586 			if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
587 				return (EINVAL);
588 			num_acl_group_obj++;
589 			break;
590 		case ACL_USER:
591 			if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID)
592 				return (EINVAL);
593 			num_acl_user++;
594 			break;
595 		case ACL_GROUP:
596 			if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID)
597 				return (EINVAL);
598 			num_acl_group++;
599 			break;
600 		case ACL_OTHER:
601 			acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
602 			if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
603 				return (EINVAL);
604 			num_acl_other++;
605 			break;
606 		case ACL_MASK:
607 			acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
608 			if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
609 				return (EINVAL);
610 			num_acl_mask++;
611 			break;
612 		default:
613 			return (EINVAL);
614 		}
615 		/*
616 		 * Check for valid perm entries.
617 		 */
618 		if ((acl->acl_entry[i].ae_perm | ACL_PERM_BITS) !=
619 		    ACL_PERM_BITS)
620 			return (EINVAL);
621 	}
622 	if ((num_acl_user_obj != 1) || (num_acl_group_obj != 1) ||
623 	    (num_acl_other != 1) || (num_acl_mask != 0 && num_acl_mask != 1))
624 		return (EINVAL);
625 	if (((num_acl_group != 0) || (num_acl_user != 0)) &&
626 	    (num_acl_mask != 1))
627 		return (EINVAL);
628 	return (0);
629 }
630 
631 /*
632  * Given a requested mode for a new object, and a default ACL, combine the
633  * two to produce a new mode.  Be careful not to clear any bits that aren't
634  * intended to be affected by the POSIX.1e ACL.  Eventually, this might also
635  * take the cmask as an argument, if we push that down into
636  * per-filesystem-code.
637  */
638 mode_t
639 acl_posix1e_newfilemode(mode_t cmode, struct acl *dacl)
640 {
641 	mode_t mode;
642 
643 	mode = cmode;
644 	/*
645 	 * The current composition policy is that a permission bit must be
646 	 * set in *both* the ACL and the requested creation mode for it to
647 	 * appear in the resulting mode/ACL.  First clear any possibly
648 	 * effected bits, then reconstruct.
649 	 */
650 	mode &= ACL_PRESERVE_MASK;
651 	mode |= (ACL_OVERRIDE_MASK & cmode & acl_posix1e_acl_to_mode(dacl));
652 
653 	return (mode);
654 }
655 
656 
657 static int
658 acl_posix1e_modload(module_t mod, int what, void *arg)
659 {
660 	int ret;
661 
662 	ret = 0;
663 
664 	switch (what) {
665 	case MOD_LOAD:
666 	case MOD_SHUTDOWN:
667 		break;
668 
669 	case MOD_QUIESCE:
670 		/* XXX TODO */
671 		ret = 0;
672 		break;
673 
674 	case MOD_UNLOAD:
675 		/* XXX TODO */
676 		ret = 0;
677 		break;
678 	default:
679 		ret = EINVAL;
680 		break;
681 	}
682 
683 	return (ret);
684 }
685 
686 static moduledata_t acl_posix1e_mod = {
687 	"acl_posix1e",
688 	acl_posix1e_modload,
689 	NULL
690 };
691 
692 DECLARE_MODULE(acl_posix1e, acl_posix1e_mod, SI_SUB_VFS, SI_ORDER_FIRST);
693 MODULE_VERSION(acl_posix1e, 1);
694