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