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