]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/subr_acl_posix1e.c
Add UPDATING entries and bump version.
[FreeBSD/FreeBSD.git] / sys / kern / subr_acl_posix1e.c
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);