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