xref: /netbsd-src/sys/kern/subr_acl_posix1e.c (revision 9aa2a9c323eb12a08584c70d6ea91d316703d3fe)
1*9aa2a9c3Schristos /*-
2*9aa2a9c3Schristos  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*9aa2a9c3Schristos  *
4*9aa2a9c3Schristos  * Copyright (c) 1999-2006 Robert N. M. Watson
5*9aa2a9c3Schristos  * All rights reserved.
6*9aa2a9c3Schristos  *
7*9aa2a9c3Schristos  * This software was developed by Robert Watson for the TrustedBSD Project.
8*9aa2a9c3Schristos  *
9*9aa2a9c3Schristos  * Redistribution and use in source and binary forms, with or without
10*9aa2a9c3Schristos  * modification, are permitted provided that the following conditions
11*9aa2a9c3Schristos  * are met:
12*9aa2a9c3Schristos  * 1. Redistributions of source code must retain the above copyright
13*9aa2a9c3Schristos  *    notice, this list of conditions and the following disclaimer.
14*9aa2a9c3Schristos  * 2. Redistributions in binary form must reproduce the above copyright
15*9aa2a9c3Schristos  *    notice, this list of conditions and the following disclaimer in the
16*9aa2a9c3Schristos  *    documentation and/or other materials provided with the distribution.
17*9aa2a9c3Schristos  *
18*9aa2a9c3Schristos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19*9aa2a9c3Schristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*9aa2a9c3Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*9aa2a9c3Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22*9aa2a9c3Schristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*9aa2a9c3Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24*9aa2a9c3Schristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*9aa2a9c3Schristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26*9aa2a9c3Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27*9aa2a9c3Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*9aa2a9c3Schristos  * SUCH DAMAGE.
29*9aa2a9c3Schristos  */
30*9aa2a9c3Schristos /*
31*9aa2a9c3Schristos  * Developed by the TrustedBSD Project.
32*9aa2a9c3Schristos  *
33*9aa2a9c3Schristos  * ACL support routines specific to POSIX.1e access control lists.  These are
34*9aa2a9c3Schristos  * utility routines for code common across file systems implementing POSIX.1e
35*9aa2a9c3Schristos  * ACLs.
36*9aa2a9c3Schristos  */
37*9aa2a9c3Schristos 
38*9aa2a9c3Schristos #include <sys/cdefs.h>
39*9aa2a9c3Schristos #if 0
40*9aa2a9c3Schristos __FBSDID("$FreeBSD: head/sys/kern/subr_acl_posix1e.c 341827 2018-12-11 19:32:16Z mjg $");
41*9aa2a9c3Schristos #endif
42*9aa2a9c3Schristos __KERNEL_RCSID(0, "$NetBSD: subr_acl_posix1e.c,v 1.1 2020/05/16 18:31:50 christos Exp $");
43*9aa2a9c3Schristos 
44*9aa2a9c3Schristos #include <sys/param.h>
45*9aa2a9c3Schristos #include <sys/kernel.h>
46*9aa2a9c3Schristos #include <sys/module.h>
47*9aa2a9c3Schristos #include <sys/systm.h>
48*9aa2a9c3Schristos #include <sys/mount.h>
49*9aa2a9c3Schristos #include <sys/vnode.h>
50*9aa2a9c3Schristos #include <sys/kauth.h>
51*9aa2a9c3Schristos #include <sys/errno.h>
52*9aa2a9c3Schristos #include <sys/stat.h>
53*9aa2a9c3Schristos #include <sys/acl.h>
54*9aa2a9c3Schristos 
55*9aa2a9c3Schristos /*
56*9aa2a9c3Schristos  * For the purposes of filesystems maintaining the _OBJ entries in an inode
57*9aa2a9c3Schristos  * with a mode_t field, this routine converts a mode_t entry to an
58*9aa2a9c3Schristos  * acl_perm_t.
59*9aa2a9c3Schristos  */
60*9aa2a9c3Schristos acl_perm_t
acl_posix1e_mode_to_perm(acl_tag_t tag,mode_t mode)61*9aa2a9c3Schristos acl_posix1e_mode_to_perm(acl_tag_t tag, mode_t mode)
62*9aa2a9c3Schristos {
63*9aa2a9c3Schristos 	acl_perm_t	perm = 0;
64*9aa2a9c3Schristos 
65*9aa2a9c3Schristos 	switch(tag) {
66*9aa2a9c3Schristos 	case ACL_USER_OBJ:
67*9aa2a9c3Schristos 		if (mode & S_IXUSR)
68*9aa2a9c3Schristos 			perm |= ACL_EXECUTE;
69*9aa2a9c3Schristos 		if (mode & S_IRUSR)
70*9aa2a9c3Schristos 			perm |= ACL_READ;
71*9aa2a9c3Schristos 		if (mode & S_IWUSR)
72*9aa2a9c3Schristos 			perm |= ACL_WRITE;
73*9aa2a9c3Schristos 		return (perm);
74*9aa2a9c3Schristos 
75*9aa2a9c3Schristos 	case ACL_GROUP_OBJ:
76*9aa2a9c3Schristos 		if (mode & S_IXGRP)
77*9aa2a9c3Schristos 			perm |= ACL_EXECUTE;
78*9aa2a9c3Schristos 		if (mode & S_IRGRP)
79*9aa2a9c3Schristos 			perm |= ACL_READ;
80*9aa2a9c3Schristos 		if (mode & S_IWGRP)
81*9aa2a9c3Schristos 			perm |= ACL_WRITE;
82*9aa2a9c3Schristos 		return (perm);
83*9aa2a9c3Schristos 
84*9aa2a9c3Schristos 	case ACL_OTHER:
85*9aa2a9c3Schristos 		if (mode & S_IXOTH)
86*9aa2a9c3Schristos 			perm |= ACL_EXECUTE;
87*9aa2a9c3Schristos 		if (mode & S_IROTH)
88*9aa2a9c3Schristos 			perm |= ACL_READ;
89*9aa2a9c3Schristos 		if (mode & S_IWOTH)
90*9aa2a9c3Schristos 			perm |= ACL_WRITE;
91*9aa2a9c3Schristos 		return (perm);
92*9aa2a9c3Schristos 
93*9aa2a9c3Schristos 	default:
94*9aa2a9c3Schristos 		printf("%s: invalid tag (%u)\n", __func__, tag);
95*9aa2a9c3Schristos 		return (0);
96*9aa2a9c3Schristos 	}
97*9aa2a9c3Schristos }
98*9aa2a9c3Schristos 
99*9aa2a9c3Schristos /*
100*9aa2a9c3Schristos  * Given inode information (uid, gid, mode), return an acl entry of the
101*9aa2a9c3Schristos  * appropriate type.
102*9aa2a9c3Schristos  */
103*9aa2a9c3Schristos struct acl_entry
acl_posix1e_mode_to_entry(acl_tag_t tag,uid_t uid,gid_t gid,mode_t mode)104*9aa2a9c3Schristos acl_posix1e_mode_to_entry(acl_tag_t tag, uid_t uid, gid_t gid, mode_t mode)
105*9aa2a9c3Schristos {
106*9aa2a9c3Schristos 	struct acl_entry	acl_entry;
107*9aa2a9c3Schristos 
108*9aa2a9c3Schristos 	acl_entry.ae_tag = tag;
109*9aa2a9c3Schristos 	acl_entry.ae_perm = acl_posix1e_mode_to_perm(tag, mode);
110*9aa2a9c3Schristos 	acl_entry.ae_entry_type = 0;
111*9aa2a9c3Schristos 	acl_entry.ae_flags = 0;
112*9aa2a9c3Schristos 	switch(tag) {
113*9aa2a9c3Schristos 	case ACL_USER_OBJ:
114*9aa2a9c3Schristos 		acl_entry.ae_id = uid;
115*9aa2a9c3Schristos 		break;
116*9aa2a9c3Schristos 
117*9aa2a9c3Schristos 	case ACL_GROUP_OBJ:
118*9aa2a9c3Schristos 		acl_entry.ae_id = gid;
119*9aa2a9c3Schristos 		break;
120*9aa2a9c3Schristos 
121*9aa2a9c3Schristos 	case ACL_OTHER:
122*9aa2a9c3Schristos 		acl_entry.ae_id = ACL_UNDEFINED_ID;
123*9aa2a9c3Schristos 		break;
124*9aa2a9c3Schristos 
125*9aa2a9c3Schristos 	default:
126*9aa2a9c3Schristos 		acl_entry.ae_id = ACL_UNDEFINED_ID;
127*9aa2a9c3Schristos 		printf("acl_posix1e_mode_to_entry: invalid tag (%d)\n", tag);
128*9aa2a9c3Schristos 	}
129*9aa2a9c3Schristos 
130*9aa2a9c3Schristos 	return (acl_entry);
131*9aa2a9c3Schristos }
132*9aa2a9c3Schristos 
133*9aa2a9c3Schristos /*
134*9aa2a9c3Schristos  * Utility function to generate a file mode given appropriate ACL entries.
135*9aa2a9c3Schristos  */
136*9aa2a9c3Schristos mode_t
acl_posix1e_perms_to_mode(struct acl_entry * acl_user_obj_entry,struct acl_entry * acl_group_obj_entry,struct acl_entry * acl_other_entry)137*9aa2a9c3Schristos acl_posix1e_perms_to_mode(struct acl_entry *acl_user_obj_entry,
138*9aa2a9c3Schristos     struct acl_entry *acl_group_obj_entry, struct acl_entry *acl_other_entry)
139*9aa2a9c3Schristos {
140*9aa2a9c3Schristos 	mode_t	mode;
141*9aa2a9c3Schristos 
142*9aa2a9c3Schristos 	mode = 0;
143*9aa2a9c3Schristos 	if (acl_user_obj_entry->ae_perm & ACL_EXECUTE)
144*9aa2a9c3Schristos 		mode |= S_IXUSR;
145*9aa2a9c3Schristos 	if (acl_user_obj_entry->ae_perm & ACL_READ)
146*9aa2a9c3Schristos 		mode |= S_IRUSR;
147*9aa2a9c3Schristos 	if (acl_user_obj_entry->ae_perm & ACL_WRITE)
148*9aa2a9c3Schristos 		mode |= S_IWUSR;
149*9aa2a9c3Schristos 	if (acl_group_obj_entry->ae_perm & ACL_EXECUTE)
150*9aa2a9c3Schristos 		mode |= S_IXGRP;
151*9aa2a9c3Schristos 	if (acl_group_obj_entry->ae_perm & ACL_READ)
152*9aa2a9c3Schristos 		mode |= S_IRGRP;
153*9aa2a9c3Schristos 	if (acl_group_obj_entry->ae_perm & ACL_WRITE)
154*9aa2a9c3Schristos 		mode |= S_IWGRP;
155*9aa2a9c3Schristos 	if (acl_other_entry->ae_perm & ACL_EXECUTE)
156*9aa2a9c3Schristos 		mode |= S_IXOTH;
157*9aa2a9c3Schristos 	if (acl_other_entry->ae_perm & ACL_READ)
158*9aa2a9c3Schristos 		mode |= S_IROTH;
159*9aa2a9c3Schristos 	if (acl_other_entry->ae_perm & ACL_WRITE)
160*9aa2a9c3Schristos 		mode |= S_IWOTH;
161*9aa2a9c3Schristos 
162*9aa2a9c3Schristos 	return (mode);
163*9aa2a9c3Schristos }
164*9aa2a9c3Schristos 
165*9aa2a9c3Schristos /*
166*9aa2a9c3Schristos  * Utility function to generate a file mode given a complete POSIX.1e access
167*9aa2a9c3Schristos  * ACL.  Note that if the ACL is improperly formed, this may result in a
168*9aa2a9c3Schristos  * panic.
169*9aa2a9c3Schristos  */
170*9aa2a9c3Schristos mode_t
acl_posix1e_acl_to_mode(struct acl * acl)171*9aa2a9c3Schristos acl_posix1e_acl_to_mode(struct acl *acl)
172*9aa2a9c3Schristos {
173*9aa2a9c3Schristos 	struct acl_entry *acl_mask, *acl_user_obj, *acl_group_obj, *acl_other;
174*9aa2a9c3Schristos 	int i;
175*9aa2a9c3Schristos 
176*9aa2a9c3Schristos 	/*
177*9aa2a9c3Schristos 	 * Find the ACL entries relevant to a POSIX permission mode.
178*9aa2a9c3Schristos 	 */
179*9aa2a9c3Schristos 	acl_user_obj = acl_group_obj = acl_other = acl_mask = NULL;
180*9aa2a9c3Schristos 	for (i = 0; i < acl->acl_cnt; i++) {
181*9aa2a9c3Schristos 		switch (acl->acl_entry[i].ae_tag) {
182*9aa2a9c3Schristos 		case ACL_USER_OBJ:
183*9aa2a9c3Schristos 			acl_user_obj = &acl->acl_entry[i];
184*9aa2a9c3Schristos 			break;
185*9aa2a9c3Schristos 
186*9aa2a9c3Schristos 		case ACL_GROUP_OBJ:
187*9aa2a9c3Schristos 			acl_group_obj = &acl->acl_entry[i];
188*9aa2a9c3Schristos 			break;
189*9aa2a9c3Schristos 
190*9aa2a9c3Schristos 		case ACL_OTHER:
191*9aa2a9c3Schristos 			acl_other = &acl->acl_entry[i];
192*9aa2a9c3Schristos 			break;
193*9aa2a9c3Schristos 
194*9aa2a9c3Schristos 		case ACL_MASK:
195*9aa2a9c3Schristos 			acl_mask = &acl->acl_entry[i];
196*9aa2a9c3Schristos 			break;
197*9aa2a9c3Schristos 
198*9aa2a9c3Schristos 		case ACL_USER:
199*9aa2a9c3Schristos 		case ACL_GROUP:
200*9aa2a9c3Schristos 			break;
201*9aa2a9c3Schristos 
202*9aa2a9c3Schristos 		default:
203*9aa2a9c3Schristos 			panic("acl_posix1e_acl_to_mode: bad ae_tag");
204*9aa2a9c3Schristos 		}
205*9aa2a9c3Schristos 	}
206*9aa2a9c3Schristos 
207*9aa2a9c3Schristos 	if (acl_user_obj == NULL || acl_group_obj == NULL || acl_other == NULL)
208*9aa2a9c3Schristos 		panic("acl_posix1e_acl_to_mode: missing base ae_tags");
209*9aa2a9c3Schristos 
210*9aa2a9c3Schristos 	/*
211*9aa2a9c3Schristos 	 * POSIX.1e specifies that if there is an ACL_MASK entry, we replace
212*9aa2a9c3Schristos 	 * the mode "group" bits with its permissions.  If there isn't, we
213*9aa2a9c3Schristos 	 * use the ACL_GROUP_OBJ permissions.
214*9aa2a9c3Schristos 	 */
215*9aa2a9c3Schristos 	if (acl_mask != NULL)
216*9aa2a9c3Schristos 		return (acl_posix1e_perms_to_mode(acl_user_obj, acl_mask,
217*9aa2a9c3Schristos 		    acl_other));
218*9aa2a9c3Schristos 	else
219*9aa2a9c3Schristos 		return (acl_posix1e_perms_to_mode(acl_user_obj, acl_group_obj,
220*9aa2a9c3Schristos 		    acl_other));
221*9aa2a9c3Schristos }
222*9aa2a9c3Schristos 
223*9aa2a9c3Schristos /*
224*9aa2a9c3Schristos  * Perform a syntactic check of the ACL, sufficient to allow an implementing
225*9aa2a9c3Schristos  * filesystem to determine if it should accept this and rely on the POSIX.1e
226*9aa2a9c3Schristos  * ACL properties.
227*9aa2a9c3Schristos  */
228*9aa2a9c3Schristos int
acl_posix1e_check(struct acl * acl)229*9aa2a9c3Schristos acl_posix1e_check(struct acl *acl)
230*9aa2a9c3Schristos {
231*9aa2a9c3Schristos 	int num_acl_user_obj, num_acl_user, num_acl_group_obj, num_acl_group;
232*9aa2a9c3Schristos 	int num_acl_mask, num_acl_other, i;
233*9aa2a9c3Schristos 
234*9aa2a9c3Schristos 	/*
235*9aa2a9c3Schristos 	 * Verify that the number of entries does not exceed the maximum
236*9aa2a9c3Schristos 	 * defined for acl_t.
237*9aa2a9c3Schristos 	 *
238*9aa2a9c3Schristos 	 * Verify that the correct number of various sorts of ae_tags are
239*9aa2a9c3Schristos 	 * present:
240*9aa2a9c3Schristos 	 *   Exactly one ACL_USER_OBJ
241*9aa2a9c3Schristos 	 *   Exactly one ACL_GROUP_OBJ
242*9aa2a9c3Schristos 	 *   Exactly one ACL_OTHER
243*9aa2a9c3Schristos 	 *   If any ACL_USER or ACL_GROUP entries appear, then exactly one
244*9aa2a9c3Schristos 	 *   ACL_MASK entry must also appear.
245*9aa2a9c3Schristos 	 *
246*9aa2a9c3Schristos 	 * Verify that all ae_perm entries are in ACL_PERM_BITS.
247*9aa2a9c3Schristos 	 *
248*9aa2a9c3Schristos 	 * Verify all ae_tag entries are understood by this implementation.
249*9aa2a9c3Schristos 	 *
250*9aa2a9c3Schristos 	 * Note: Does not check for uniqueness of qualifier (ae_id) field.
251*9aa2a9c3Schristos 	 */
252*9aa2a9c3Schristos 	num_acl_user_obj = num_acl_user = num_acl_group_obj = num_acl_group =
253*9aa2a9c3Schristos 	    num_acl_mask = num_acl_other = 0;
254*9aa2a9c3Schristos 	if (acl->acl_cnt > ACL_MAX_ENTRIES)
255*9aa2a9c3Schristos 		return (EINVAL);
256*9aa2a9c3Schristos 	for (i = 0; i < acl->acl_cnt; i++) {
257*9aa2a9c3Schristos 		struct acl_entry *ae = &acl->acl_entry[i];
258*9aa2a9c3Schristos 		/*
259*9aa2a9c3Schristos 		 * Check for a valid tag.
260*9aa2a9c3Schristos 		 */
261*9aa2a9c3Schristos 		switch(ae->ae_tag) {
262*9aa2a9c3Schristos 		case ACL_USER_OBJ:
263*9aa2a9c3Schristos 			ae->ae_id = ACL_UNDEFINED_ID; /* XXX */
264*9aa2a9c3Schristos 			if (ae->ae_id != ACL_UNDEFINED_ID)
265*9aa2a9c3Schristos 				return (EINVAL);
266*9aa2a9c3Schristos 			num_acl_user_obj++;
267*9aa2a9c3Schristos 			break;
268*9aa2a9c3Schristos 		case ACL_GROUP_OBJ:
269*9aa2a9c3Schristos 			ae->ae_id = ACL_UNDEFINED_ID; /* XXX */
270*9aa2a9c3Schristos 			if (ae->ae_id != ACL_UNDEFINED_ID)
271*9aa2a9c3Schristos 				return (EINVAL);
272*9aa2a9c3Schristos 			num_acl_group_obj++;
273*9aa2a9c3Schristos 			break;
274*9aa2a9c3Schristos 		case ACL_USER:
275*9aa2a9c3Schristos 			if (ae->ae_id == ACL_UNDEFINED_ID)
276*9aa2a9c3Schristos 				return (EINVAL);
277*9aa2a9c3Schristos 			num_acl_user++;
278*9aa2a9c3Schristos 			break;
279*9aa2a9c3Schristos 		case ACL_GROUP:
280*9aa2a9c3Schristos 			if (ae->ae_id == ACL_UNDEFINED_ID)
281*9aa2a9c3Schristos 				return (EINVAL);
282*9aa2a9c3Schristos 			num_acl_group++;
283*9aa2a9c3Schristos 			break;
284*9aa2a9c3Schristos 		case ACL_OTHER:
285*9aa2a9c3Schristos 			ae->ae_id = ACL_UNDEFINED_ID; /* XXX */
286*9aa2a9c3Schristos 			if (ae->ae_id != ACL_UNDEFINED_ID)
287*9aa2a9c3Schristos 				return (EINVAL);
288*9aa2a9c3Schristos 			num_acl_other++;
289*9aa2a9c3Schristos 			break;
290*9aa2a9c3Schristos 		case ACL_MASK:
291*9aa2a9c3Schristos 			ae->ae_id = ACL_UNDEFINED_ID; /* XXX */
292*9aa2a9c3Schristos 			if (ae->ae_id != ACL_UNDEFINED_ID)
293*9aa2a9c3Schristos 				return (EINVAL);
294*9aa2a9c3Schristos 			num_acl_mask++;
295*9aa2a9c3Schristos 			break;
296*9aa2a9c3Schristos 		default:
297*9aa2a9c3Schristos 			return (EINVAL);
298*9aa2a9c3Schristos 		}
299*9aa2a9c3Schristos 		/*
300*9aa2a9c3Schristos 		 * Check for valid perm entries.
301*9aa2a9c3Schristos 		 */
302*9aa2a9c3Schristos 		if ((acl->acl_entry[i].ae_perm | ACL_PERM_BITS) !=
303*9aa2a9c3Schristos 		    ACL_PERM_BITS)
304*9aa2a9c3Schristos 			return (EINVAL);
305*9aa2a9c3Schristos 	}
306*9aa2a9c3Schristos 	if ((num_acl_user_obj != 1) || (num_acl_group_obj != 1) ||
307*9aa2a9c3Schristos 	    (num_acl_other != 1) || (num_acl_mask != 0 && num_acl_mask != 1))
308*9aa2a9c3Schristos 		return (EINVAL);
309*9aa2a9c3Schristos 	if (((num_acl_group != 0) || (num_acl_user != 0)) &&
310*9aa2a9c3Schristos 	    (num_acl_mask != 1))
311*9aa2a9c3Schristos 		return (EINVAL);
312*9aa2a9c3Schristos 	return (0);
313*9aa2a9c3Schristos }
314*9aa2a9c3Schristos 
315*9aa2a9c3Schristos /*
316*9aa2a9c3Schristos  * Given a requested mode for a new object, and a default ACL, combine the
317*9aa2a9c3Schristos  * two to produce a new mode.  Be careful not to clear any bits that aren't
318*9aa2a9c3Schristos  * intended to be affected by the POSIX.1e ACL.  Eventually, this might also
319*9aa2a9c3Schristos  * take the cmask as an argument, if we push that down into
320*9aa2a9c3Schristos  * per-filesystem-code.
321*9aa2a9c3Schristos  */
322*9aa2a9c3Schristos mode_t
acl_posix1e_newfilemode(mode_t cmode,struct acl * dacl)323*9aa2a9c3Schristos acl_posix1e_newfilemode(mode_t cmode, struct acl *dacl)
324*9aa2a9c3Schristos {
325*9aa2a9c3Schristos 	mode_t mode;
326*9aa2a9c3Schristos 
327*9aa2a9c3Schristos 	mode = cmode;
328*9aa2a9c3Schristos 	/*
329*9aa2a9c3Schristos 	 * The current composition policy is that a permission bit must be
330*9aa2a9c3Schristos 	 * set in *both* the ACL and the requested creation mode for it to
331*9aa2a9c3Schristos 	 * appear in the resulting mode/ACL.  First clear any possibly
332*9aa2a9c3Schristos 	 * effected bits, then reconstruct.
333*9aa2a9c3Schristos 	 */
334*9aa2a9c3Schristos 	mode &= ACL_PRESERVE_MASK;
335*9aa2a9c3Schristos 	mode |= (ACL_OVERRIDE_MASK & cmode & acl_posix1e_acl_to_mode(dacl));
336*9aa2a9c3Schristos 
337*9aa2a9c3Schristos 	return (mode);
338*9aa2a9c3Schristos }
339