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