]> CyberLeo.Net >> Repos - FreeBSD/releng/8.0.git/blob - sys/kern/subr_acl_nfs4.c
Adjust to reflect 8.0-RELEASE.
[FreeBSD/releng/8.0.git] / sys / kern / subr_acl_nfs4.c
1 /*-
2  * Copyright (c) 2008 Edward Tomasz NapieraƂa <trasz@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 /*
28  * ACL support routines specific to NFSv4 access control lists.  These are
29  * utility routines for code common across file systems implementing NFSv4
30  * ACLs.
31  */
32
33 #ifdef _KERNEL
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/mount.h>
40 #include <sys/priv.h>
41 #include <sys/vnode.h>
42 #include <sys/errno.h>
43 #include <sys/stat.h>
44 #include <sys/acl.h>
45 #else
46 #include <errno.h>
47 #include <assert.h>
48 #include <sys/acl.h>
49 #include <sys/stat.h>
50 #define KASSERT(a, b) assert(a)
51 #define CTASSERT(a)
52 #endif
53
54 static int
55 _acl_entry_matches(struct acl_entry *entry, acl_tag_t tag, acl_perm_t perm,
56     acl_entry_type_t entry_type)
57 {
58         if (entry->ae_tag != tag)
59                 return (0);
60
61         if (entry->ae_id != ACL_UNDEFINED_ID)
62                 return (0);
63
64         if (entry->ae_perm != perm)
65                 return (0);
66
67         if (entry->ae_entry_type != entry_type)
68                 return (0);
69
70         if (entry->ae_flags != 0)
71                 return (0);
72
73         return (1);
74 }
75
76 static struct acl_entry *
77 _acl_append(struct acl *aclp, acl_tag_t tag, acl_perm_t perm,
78     acl_entry_type_t entry_type)
79 {
80         struct acl_entry *entry;
81
82         KASSERT(aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES,
83             ("aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES"));
84
85         entry = &(aclp->acl_entry[aclp->acl_cnt]);
86         aclp->acl_cnt++;
87
88         entry->ae_tag = tag;
89         entry->ae_id = ACL_UNDEFINED_ID;
90         entry->ae_perm = perm;
91         entry->ae_entry_type = entry_type;
92         entry->ae_flags = 0;
93
94         return (entry);
95 }
96
97 static struct acl_entry *
98 _acl_duplicate_entry(struct acl *aclp, int entry_index)
99 {
100         int i;
101
102         KASSERT(aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES,
103             ("aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES"));
104
105         for (i = aclp->acl_cnt; i > entry_index; i--)
106                 aclp->acl_entry[i] = aclp->acl_entry[i - 1];
107
108         aclp->acl_cnt++;
109
110         return (&(aclp->acl_entry[entry_index + 1]));
111 }
112
113 void
114 acl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode, int file_owner_id)
115 {
116         int i, meets, must_append;
117         struct acl_entry *entry, *copy, *previous,
118             *a1, *a2, *a3, *a4, *a5, *a6;
119         mode_t amode;
120         const int READ = 04;
121         const int WRITE = 02;
122         const int EXEC = 01;
123
124         KASSERT(aclp->acl_cnt >= 0, ("aclp->acl_cnt >= 0"));
125         KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES,
126             ("aclp->acl_cnt <= ACL_MAX_ENTRIES"));
127
128         /*
129          * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt
130          *
131          * 3.16.6.3. Applying a Mode to an Existing ACL
132          */
133
134         /*
135          * 1. For each ACE:
136          */
137         for (i = 0; i < aclp->acl_cnt; i++) {
138                 entry = &(aclp->acl_entry[i]);
139
140                 /*
141                  * 1.1. If the type is neither ALLOW or DENY - skip.
142                  */
143                 if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW &&
144                     entry->ae_entry_type != ACL_ENTRY_TYPE_DENY)
145                         continue;
146
147                 /*
148                  * 1.2. If ACL_ENTRY_INHERIT_ONLY is set - skip.
149                  */
150                 if (entry->ae_flags & ACL_ENTRY_INHERIT_ONLY)
151                         continue;
152
153                 /*
154                  * 1.3. If ACL_ENTRY_FILE_INHERIT or ACL_ENTRY_DIRECTORY_INHERIT
155                  *      are set:
156                  */
157                 if (entry->ae_flags &
158                     (ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT)) {
159                         /*
160                          * 1.3.1. A copy of the current ACE is made, and placed
161                          *        in the ACL immediately following the current
162                          *        ACE.
163                          */
164                         copy = _acl_duplicate_entry(aclp, i);
165
166                         /*
167                          * 1.3.2. In the first ACE, the flag
168                          *        ACL_ENTRY_INHERIT_ONLY is set.
169                          */
170                         entry->ae_flags |= ACL_ENTRY_INHERIT_ONLY;
171
172                         /*
173                          * 1.3.3. In the second ACE, the following flags
174                          *        are cleared:
175                          *        ACL_ENTRY_FILE_INHERIT,
176                          *        ACL_ENTRY_DIRECTORY_INHERIT,
177                          *        ACL_ENTRY_NO_PROPAGATE_INHERIT.
178                          */
179                         copy->ae_flags &= ~(ACL_ENTRY_FILE_INHERIT |
180                             ACL_ENTRY_DIRECTORY_INHERIT |
181                             ACL_ENTRY_NO_PROPAGATE_INHERIT);
182
183                         /*
184                          * The algorithm continues on with the second ACE.
185                          */
186                         i++;
187                         entry = copy;
188                 }
189
190                 /*
191                  * 1.4. If it's owner@, group@ or everyone@ entry, clear
192                  *      ACL_READ_DATA, ACL_WRITE_DATA, ACL_APPEND_DATA
193                  *      and ACL_EXECUTE.  Continue to the next entry.
194                  */
195                 if (entry->ae_tag == ACL_USER_OBJ ||
196                     entry->ae_tag == ACL_GROUP_OBJ ||
197                     entry->ae_tag == ACL_EVERYONE) {
198                         entry->ae_perm &= ~(ACL_READ_DATA | ACL_WRITE_DATA |
199                             ACL_APPEND_DATA | ACL_EXECUTE);
200                         continue;
201                 }
202
203                 /*
204                  * 1.5. Otherwise, if the "who" field did not match one
205                  *      of OWNER@, GROUP@, EVERYONE@:
206                  *
207                  * 1.5.1. If the type is ALLOW, check the preceding ACE.
208                  *        If it does not meet all of the following criteria:
209                  */
210                 if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW)
211                         continue;
212
213                 meets = 0;
214                 if (i > 0) {
215                         meets = 1;
216                         previous = &(aclp->acl_entry[i - 1]);
217
218                         /*
219                          * 1.5.1.1. The type field is DENY,
220                          */
221                         if (previous->ae_entry_type != ACL_ENTRY_TYPE_DENY)
222                                 meets = 0;
223
224                         /*
225                          * 1.5.1.2. The "who" field is the same as the current
226                          *          ACE,
227                          *
228                          * 1.5.1.3. The flag bit ACE4_IDENTIFIER_GROUP
229                          *          is the same as it is in the current ACE,
230                          *          and no other flag bits are set,
231                          */
232                         if (previous->ae_id != entry->ae_id ||
233                             previous->ae_tag != entry->ae_tag)
234                                 meets = 0;
235
236                         if (previous->ae_flags)
237                                 meets = 0;
238
239                         /*
240                          * 1.5.1.4. The mask bits are a subset of the mask bits
241                          *          of the current ACE, and are also subset of
242                          *          the following: ACL_READ_DATA,
243                          *          ACL_WRITE_DATA, ACL_APPEND_DATA, ACL_EXECUTE
244                          */
245                         if (previous->ae_perm & ~(entry->ae_perm))
246                                 meets = 0;
247
248                         if (previous->ae_perm & ~(ACL_READ_DATA |
249                             ACL_WRITE_DATA | ACL_APPEND_DATA | ACL_EXECUTE))
250                                 meets = 0;
251                 }
252
253                 if (!meets) {
254                         /*
255                          * Then the ACE of type DENY, with a who equal
256                          * to the current ACE, flag bits equal to
257                          * (<current ACE flags> & <ACE_IDENTIFIER_GROUP>)
258                          * and no mask bits, is prepended.
259                          */
260                         previous = entry;
261                         entry = _acl_duplicate_entry(aclp, i);
262
263                         /* Adjust counter, as we've just added an entry. */
264                         i++;
265
266                         previous->ae_tag = entry->ae_tag;
267                         previous->ae_id = entry->ae_id;
268                         previous->ae_flags = entry->ae_flags;
269                         previous->ae_perm = 0;
270                         previous->ae_entry_type = ACL_ENTRY_TYPE_DENY;
271                 }
272
273                 /*
274                  * 1.5.2. The following modifications are made to the prepended
275                  *        ACE.  The intent is to mask the following ACE
276                  *        to disallow ACL_READ_DATA, ACL_WRITE_DATA,
277                  *        ACL_APPEND_DATA, or ACL_EXECUTE, based upon the group
278                  *        permissions of the new mode.  As a special case,
279                  *        if the ACE matches the current owner of the file,
280                  *        the owner bits are used, rather than the group bits.
281                  *        This is reflected in the algorithm below.
282                  */
283                 amode = mode >> 3;
284
285                 /*
286                  * If ACE4_IDENTIFIER_GROUP is not set, and the "who" field
287                  * in ACE matches the owner of the file, we shift amode three
288                  * more bits, in order to have the owner permission bits
289                  * placed in the three low order bits of amode.
290                  */
291                 if (entry->ae_tag == ACL_USER && entry->ae_id == file_owner_id)
292                         amode = amode >> 3;
293
294                 if (entry->ae_perm & ACL_READ_DATA) {
295                         if (amode & READ)
296                                 previous->ae_perm &= ~ACL_READ_DATA;
297                         else
298                                 previous->ae_perm |= ACL_READ_DATA;
299                 }
300
301                 if (entry->ae_perm & ACL_WRITE_DATA) {
302                         if (amode & WRITE)
303                                 previous->ae_perm &= ~ACL_WRITE_DATA;
304                         else
305                                 previous->ae_perm |= ACL_WRITE_DATA;
306                 }
307
308                 if (entry->ae_perm & ACL_APPEND_DATA) {
309                         if (amode & WRITE)
310                                 previous->ae_perm &= ~ACL_APPEND_DATA;
311                         else
312                                 previous->ae_perm |= ACL_APPEND_DATA;
313                 }
314
315                 if (entry->ae_perm & ACL_EXECUTE) {
316                         if (amode & EXEC)
317                                 previous->ae_perm &= ~ACL_EXECUTE;
318                         else
319                                 previous->ae_perm |= ACL_EXECUTE;
320                 }
321
322                 /*
323                  * 1.5.3. If ACE4_IDENTIFIER_GROUP is set in the flags
324                  *        of the ALLOW ace:
325                  *
326                  * XXX: This point is not there in the Falkner's draft.
327                  */
328                 if (entry->ae_tag == ACL_GROUP &&
329                     entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) {
330                         mode_t extramode, ownermode;
331                         extramode = (mode >> 3) & 07;
332                         ownermode = mode >> 6;
333                         extramode &= ~ownermode;
334
335                         if (extramode) {
336                                 if (extramode & READ) {
337                                         entry->ae_perm &= ~ACL_READ_DATA;
338                                         previous->ae_perm &= ~ACL_READ_DATA;
339                                 }
340
341                                 if (extramode & WRITE) {
342                                         entry->ae_perm &=
343                                             ~(ACL_WRITE_DATA | ACL_APPEND_DATA);
344                                         previous->ae_perm &=
345                                             ~(ACL_WRITE_DATA | ACL_APPEND_DATA);
346                                 }
347
348                                 if (extramode & EXEC) {
349                                         entry->ae_perm &= ~ACL_EXECUTE;
350                                         previous->ae_perm &= ~ACL_EXECUTE;
351                                 }
352                         }
353                 }
354         }
355
356         /*
357          * 2. If there at least six ACEs, the final six ACEs are examined.
358          *    If they are not equal to what we want, append six ACEs.
359          */
360         must_append = 0;
361         if (aclp->acl_cnt < 6) {
362                 must_append = 1;
363         } else {
364                 a6 = &(aclp->acl_entry[aclp->acl_cnt - 1]);
365                 a5 = &(aclp->acl_entry[aclp->acl_cnt - 2]);
366                 a4 = &(aclp->acl_entry[aclp->acl_cnt - 3]);
367                 a3 = &(aclp->acl_entry[aclp->acl_cnt - 4]);
368                 a2 = &(aclp->acl_entry[aclp->acl_cnt - 5]);
369                 a1 = &(aclp->acl_entry[aclp->acl_cnt - 6]);
370
371                 if (!_acl_entry_matches(a1, ACL_USER_OBJ, 0,
372                     ACL_ENTRY_TYPE_DENY))
373                         must_append = 1;
374                 if (!_acl_entry_matches(a2, ACL_USER_OBJ, ACL_WRITE_ACL |
375                     ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES |
376                     ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_ALLOW))
377                         must_append = 1;
378                 if (!_acl_entry_matches(a3, ACL_GROUP_OBJ, 0,
379                     ACL_ENTRY_TYPE_DENY))
380                         must_append = 1;
381                 if (!_acl_entry_matches(a4, ACL_GROUP_OBJ, 0,
382                     ACL_ENTRY_TYPE_ALLOW))
383                         must_append = 1;
384                 if (!_acl_entry_matches(a5, ACL_EVERYONE, ACL_WRITE_ACL |
385                     ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES |
386                     ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_DENY))
387                         must_append = 1;
388                 if (!_acl_entry_matches(a6, ACL_EVERYONE, ACL_READ_ACL |
389                     ACL_READ_ATTRIBUTES | ACL_READ_NAMED_ATTRS |
390                     ACL_SYNCHRONIZE, ACL_ENTRY_TYPE_ALLOW))
391                         must_append = 1;
392         }
393
394         if (must_append) {
395                 KASSERT(aclp->acl_cnt + 6 <= ACL_MAX_ENTRIES,
396                     ("aclp->acl_cnt <= ACL_MAX_ENTRIES"));
397
398                 a1 = _acl_append(aclp, ACL_USER_OBJ, 0, ACL_ENTRY_TYPE_DENY);
399                 a2 = _acl_append(aclp, ACL_USER_OBJ, ACL_WRITE_ACL |
400                     ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES |
401                     ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_ALLOW);
402                 a3 = _acl_append(aclp, ACL_GROUP_OBJ, 0, ACL_ENTRY_TYPE_DENY);
403                 a4 = _acl_append(aclp, ACL_GROUP_OBJ, 0, ACL_ENTRY_TYPE_ALLOW);
404                 a5 = _acl_append(aclp, ACL_EVERYONE, ACL_WRITE_ACL |
405                     ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES |
406                     ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_DENY);
407                 a6 = _acl_append(aclp, ACL_EVERYONE, ACL_READ_ACL |
408                     ACL_READ_ATTRIBUTES | ACL_READ_NAMED_ATTRS |
409                     ACL_SYNCHRONIZE, ACL_ENTRY_TYPE_ALLOW);
410
411                 KASSERT(a1 != NULL && a2 != NULL && a3 != NULL && a4 != NULL &&
412                     a5 != NULL && a6 != NULL, ("couldn't append to ACL."));
413         }
414
415         /*
416          * 3. The final six ACEs are adjusted according to the incoming mode.
417          */
418         if (mode & S_IRUSR)
419                 a2->ae_perm |= ACL_READ_DATA;
420         else
421                 a1->ae_perm |= ACL_READ_DATA;
422         if (mode & S_IWUSR)
423                 a2->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
424         else
425                 a1->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
426         if (mode & S_IXUSR)
427                 a2->ae_perm |= ACL_EXECUTE;
428         else
429                 a1->ae_perm |= ACL_EXECUTE;
430
431         if (mode & S_IRGRP)
432                 a4->ae_perm |= ACL_READ_DATA;
433         else
434                 a3->ae_perm |= ACL_READ_DATA;
435         if (mode & S_IWGRP)
436                 a4->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
437         else
438                 a3->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
439         if (mode & S_IXGRP)
440                 a4->ae_perm |= ACL_EXECUTE;
441         else
442                 a3->ae_perm |= ACL_EXECUTE;
443
444         if (mode & S_IROTH)
445                 a6->ae_perm |= ACL_READ_DATA;
446         else
447                 a5->ae_perm |= ACL_READ_DATA;
448         if (mode & S_IWOTH)
449                 a6->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
450         else
451                 a5->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
452         if (mode & S_IXOTH)
453                 a6->ae_perm |= ACL_EXECUTE;
454         else
455                 a5->ae_perm |= ACL_EXECUTE;
456 }
457
458 void
459 acl_nfs4_sync_mode_from_acl(mode_t *_mode, const struct acl *aclp)
460 {
461         int i;
462         mode_t old_mode = *_mode, mode = 0, seen = 0;
463         const struct acl_entry *entry;
464
465         KASSERT(aclp->acl_cnt > 0, ("aclp->acl_cnt > 0"));
466         KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES,
467             ("aclp->acl_cnt <= ACL_MAX_ENTRIES"));
468
469         /*
470          * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt
471          *
472          * 3.16.6.1. Recomputing mode upon SETATTR of ACL
473          */
474
475         for (i = 0; i < aclp->acl_cnt; i++) {
476                 entry = &(aclp->acl_entry[i]);
477
478                 if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW &&
479                     entry->ae_entry_type != ACL_ENTRY_TYPE_DENY)
480                         continue;
481
482                 if (entry->ae_flags & ACL_ENTRY_INHERIT_ONLY)
483                         continue;
484
485                 if (entry->ae_tag == ACL_USER_OBJ) {
486                         if ((entry->ae_perm & ACL_READ_DATA) &&
487                             ((seen & S_IRUSR) == 0)) {
488                                 seen |= S_IRUSR;
489                                 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
490                                         mode |= S_IRUSR;
491                         }
492                         if ((entry->ae_perm & ACL_WRITE_DATA) &&
493                              ((seen & S_IWUSR) == 0)) {
494                                 seen |= S_IWUSR;
495                                 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
496                                         mode |= S_IWUSR;
497                         }
498                         if ((entry->ae_perm & ACL_EXECUTE) &&
499                             ((seen & S_IXUSR) == 0)) {
500                                 seen |= S_IXUSR;
501                                 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
502                                         mode |= S_IXUSR;
503                         }
504                 } else if (entry->ae_tag == ACL_GROUP_OBJ) {
505                         if ((entry->ae_perm & ACL_READ_DATA) &&
506                             ((seen & S_IRGRP) == 0)) {
507                                 seen |= S_IRGRP;
508                                 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
509                                         mode |= S_IRGRP;
510                         }
511                         if ((entry->ae_perm & ACL_WRITE_DATA) &&
512                             ((seen & S_IWGRP) == 0)) {
513                                 seen |= S_IWGRP;
514                                 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
515                                         mode |= S_IWGRP;
516                         }
517                         if ((entry->ae_perm & ACL_EXECUTE) &&
518                             ((seen & S_IXGRP) == 0)) {
519                                 seen |= S_IXGRP;
520                                 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
521                                         mode |= S_IXGRP;
522                         }
523                 } else if (entry->ae_tag == ACL_EVERYONE) {
524                         if (entry->ae_perm & ACL_READ_DATA) {
525                                 if ((seen & S_IRUSR) == 0) {
526                                         seen |= S_IRUSR;
527                                         if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
528                                                 mode |= S_IRUSR;
529                                 }
530                                 if ((seen & S_IRGRP) == 0) {
531                                         seen |= S_IRGRP;
532                                         if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
533                                                 mode |= S_IRGRP;
534                                 }
535                                 if ((seen & S_IROTH) == 0) {
536                                         seen |= S_IROTH;
537                                         if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
538                                                 mode |= S_IROTH;
539                                 }
540                         }
541                         if (entry->ae_perm & ACL_WRITE_DATA) {
542                                 if ((seen & S_IWUSR) == 0) {
543                                         seen |= S_IWUSR;
544                                         if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
545                                                 mode |= S_IWUSR;
546                                 }
547                                 if ((seen & S_IWGRP) == 0) {
548                                         seen |= S_IWGRP;
549                                         if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
550                                                 mode |= S_IWGRP;
551                                 }
552                                 if ((seen & S_IWOTH) == 0) {
553                                         seen |= S_IWOTH;
554                                         if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
555                                                 mode |= S_IWOTH;
556                                 }
557                         }
558                         if (entry->ae_perm & ACL_EXECUTE) {
559                                 if ((seen & S_IXUSR) == 0) {
560                                         seen |= S_IXUSR;
561                                         if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
562                                                 mode |= S_IXUSR;
563                                 }
564                                 if ((seen & S_IXGRP) == 0) {
565                                         seen |= S_IXGRP;
566                                         if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
567                                                 mode |= S_IXGRP;
568                                 }
569                                 if ((seen & S_IXOTH) == 0) {
570                                         seen |= S_IXOTH;
571                                         if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
572                                                 mode |= S_IXOTH;
573                                 }
574                         }
575                 }
576         }
577
578         *_mode = mode | (old_mode & ACL_PRESERVE_MASK);
579 }