]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/subr_acl_posix1e.c
tcp bbr: improve code consistency
[FreeBSD/FreeBSD.git] / sys / kern / subr_acl_posix1e.c
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);