1fa9e4066Sahrens /*
2fa9e4066Sahrens * CDDL HEADER START
3fa9e4066Sahrens *
4fa9e4066Sahrens * The contents of this file are subject to the terms of the
5ea8dc4b6Seschrock * Common Development and Distribution License (the "License").
6ea8dc4b6Seschrock * You may not use this file except in compliance with the License.
7fa9e4066Sahrens *
8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens * See the License for the specific language governing permissions
11fa9e4066Sahrens * and limitations under the License.
12fa9e4066Sahrens *
13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens *
19fa9e4066Sahrens * CDDL HEADER END
20fa9e4066Sahrens */
21fa9e4066Sahrens /*
2227dd1e87SMark Shellenbaum * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23be6fd75aSMatthew Ahrens * Copyright (c) 2013 by Delphix. All rights reserved.
24f37b3cbbSMatt Barden * Copyright 2020 Tintri by DDN, Inc. All rights reserved.
2570561057SGordon Ross * Copyright 2019-2023 RackTop Systems, Inc.
26fa9e4066Sahrens */
27fa9e4066Sahrens
28fa9e4066Sahrens #include <sys/types.h>
29fa9e4066Sahrens #include <sys/param.h>
30fa9e4066Sahrens #include <sys/time.h>
31fa9e4066Sahrens #include <sys/systm.h>
32fa9e4066Sahrens #include <sys/sysmacros.h>
33fa9e4066Sahrens #include <sys/resource.h>
34fa9e4066Sahrens #include <sys/vfs.h>
35fa9e4066Sahrens #include <sys/vnode.h>
36da6c28aaSamw #include <sys/sid.h>
37fa9e4066Sahrens #include <sys/file.h>
38fa9e4066Sahrens #include <sys/stat.h>
39fa9e4066Sahrens #include <sys/kmem.h>
40fa9e4066Sahrens #include <sys/cmn_err.h>
41fa9e4066Sahrens #include <sys/errno.h>
42fa9e4066Sahrens #include <sys/unistd.h>
43169cdae2Smarks #include <sys/sdt.h>
44fa9e4066Sahrens #include <sys/fs/zfs.h>
45fa9e4066Sahrens #include <sys/mode.h>
46fa9e4066Sahrens #include <sys/policy.h>
47fa9e4066Sahrens #include <sys/zfs_znode.h>
48da6c28aaSamw #include <sys/zfs_fuid.h>
49fa9e4066Sahrens #include <sys/zfs_acl.h>
50fa9e4066Sahrens #include <sys/zfs_dir.h>
51fa9e4066Sahrens #include <sys/zfs_vfsops.h>
52fa9e4066Sahrens #include <sys/dmu.h>
53da6c28aaSamw #include <sys/dnode.h>
54fa9e4066Sahrens #include <sys/zap.h>
550a586ceaSMark Shellenbaum #include <sys/sa.h>
56fa9e4066Sahrens #include "fs/fs_subr.h"
57fa9e4066Sahrens #include <acl/acl_common.h>
58fa9e4066Sahrens
59fa9e4066Sahrens #define ALLOW ACE_ACCESS_ALLOWED_ACE_TYPE
60fa9e4066Sahrens #define DENY ACE_ACCESS_DENIED_ACE_TYPE
61da6c28aaSamw #define MAX_ACE_TYPE ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE
62003c2582SMark Shellenbaum #define MIN_ACE_TYPE ALLOW
63fa9e4066Sahrens
64fa9e4066Sahrens #define OWNING_GROUP (ACE_GROUP|ACE_IDENTIFIER_GROUP)
65fa9e4066Sahrens #define EVERYONE_ALLOW_MASK (ACE_READ_ACL|ACE_READ_ATTRIBUTES | \
66fa9e4066Sahrens ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE)
67fa9e4066Sahrens #define EVERYONE_DENY_MASK (ACE_WRITE_ACL|ACE_WRITE_OWNER | \
68fa9e4066Sahrens ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS)
69fa9e4066Sahrens #define OWNER_ALLOW_MASK (ACE_WRITE_ACL | ACE_WRITE_OWNER | \
70fa9e4066Sahrens ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS)
71da6c28aaSamw
72da6c28aaSamw #define ZFS_CHECKED_MASKS (ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_DATA| \
73da6c28aaSamw ACE_READ_NAMED_ATTRS|ACE_WRITE_DATA|ACE_WRITE_ATTRIBUTES| \
74da6c28aaSamw ACE_WRITE_NAMED_ATTRS|ACE_APPEND_DATA|ACE_EXECUTE|ACE_WRITE_OWNER| \
75da6c28aaSamw ACE_WRITE_ACL|ACE_DELETE|ACE_DELETE_CHILD|ACE_SYNCHRONIZE)
76da6c28aaSamw
77f52e0e2bSMark Shellenbaum #define WRITE_MASK_DATA (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_WRITE_NAMED_ATTRS)
78f52e0e2bSMark Shellenbaum #define WRITE_MASK_ATTRS (ACE_WRITE_ACL|ACE_WRITE_OWNER|ACE_WRITE_ATTRIBUTES| \
79f52e0e2bSMark Shellenbaum ACE_DELETE|ACE_DELETE_CHILD)
80f52e0e2bSMark Shellenbaum #define WRITE_MASK (WRITE_MASK_DATA|WRITE_MASK_ATTRS)
81fa9e4066Sahrens
82fa9e4066Sahrens #define OGE_CLEAR (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
83fa9e4066Sahrens ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
84fa9e4066Sahrens
85fa9e4066Sahrens #define OKAY_MASK_BITS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
86fa9e4066Sahrens ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
87fa9e4066Sahrens
88fa9e4066Sahrens #define ALL_INHERIT (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE | \
89da6c28aaSamw ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE|ACE_INHERITED_ACE)
90fa9e4066Sahrens
91b3d141f8Smarks #define RESTRICTED_CLEAR (ACE_WRITE_ACL|ACE_WRITE_OWNER)
92fa9e4066Sahrens
93da6c28aaSamw #define V4_ACL_WIDE_FLAGS (ZFS_ACL_AUTO_INHERIT|ZFS_ACL_DEFAULTED|\
94da6c28aaSamw ZFS_ACL_PROTECTED)
95da6c28aaSamw
96da6c28aaSamw #define ZFS_ACL_WIDE_FLAGS (V4_ACL_WIDE_FLAGS|ZFS_ACL_TRIVIAL|ZFS_INHERIT_ACE|\
97da6c28aaSamw ZFS_ACL_OBJ_ACE)
98da6c28aaSamw
994929fd5eSTim Haley #define ALL_MODE_EXECS (S_IXUSR | S_IXGRP | S_IXOTH)
1004929fd5eSTim Haley
101*06799660SGordon Ross typedef struct zfs_acl_iter {
102*06799660SGordon Ross zfs_acl_t *zai_aclp; /* The ACL we're iterating */
103*06799660SGordon Ross zfs_acl_node_t *zai_curr_node; /* current node iterator is in */
104*06799660SGordon Ross void *zai_next_ace; /* pointer to next ACE */
105*06799660SGordon Ross int zai_ace_idx; /* ace iterator positioned on */
106*06799660SGordon Ross } zfs_acl_iter_t;
107*06799660SGordon Ross
108da6c28aaSamw static uint16_t
zfs_ace_v0_get_type(void * acep)109da6c28aaSamw zfs_ace_v0_get_type(void *acep)
110da6c28aaSamw {
111da6c28aaSamw return (((zfs_oldace_t *)acep)->z_type);
112da6c28aaSamw }
113da6c28aaSamw
114da6c28aaSamw static uint16_t
zfs_ace_v0_get_flags(void * acep)115da6c28aaSamw zfs_ace_v0_get_flags(void *acep)
116da6c28aaSamw {
117da6c28aaSamw return (((zfs_oldace_t *)acep)->z_flags);
118da6c28aaSamw }
119fa9e4066Sahrens
120da6c28aaSamw static uint32_t
zfs_ace_v0_get_mask(void * acep)121da6c28aaSamw zfs_ace_v0_get_mask(void *acep)
122da6c28aaSamw {
123da6c28aaSamw return (((zfs_oldace_t *)acep)->z_access_mask);
124da6c28aaSamw }
125da6c28aaSamw
126da6c28aaSamw static uint64_t
zfs_ace_v0_get_who(void * acep)127da6c28aaSamw zfs_ace_v0_get_who(void *acep)
128da6c28aaSamw {
129da6c28aaSamw return (((zfs_oldace_t *)acep)->z_fuid);
130da6c28aaSamw }
131da6c28aaSamw
132da6c28aaSamw static void
zfs_ace_v0_set_type(void * acep,uint16_t type)133da6c28aaSamw zfs_ace_v0_set_type(void *acep, uint16_t type)
134da6c28aaSamw {
135da6c28aaSamw ((zfs_oldace_t *)acep)->z_type = type;
136da6c28aaSamw }
137da6c28aaSamw
138da6c28aaSamw static void
zfs_ace_v0_set_flags(void * acep,uint16_t flags)139da6c28aaSamw zfs_ace_v0_set_flags(void *acep, uint16_t flags)
140da6c28aaSamw {
141da6c28aaSamw ((zfs_oldace_t *)acep)->z_flags = flags;
142da6c28aaSamw }
143da6c28aaSamw
144da6c28aaSamw static void
zfs_ace_v0_set_mask(void * acep,uint32_t mask)145da6c28aaSamw zfs_ace_v0_set_mask(void *acep, uint32_t mask)
146da6c28aaSamw {
147da6c28aaSamw ((zfs_oldace_t *)acep)->z_access_mask = mask;
148da6c28aaSamw }
149da6c28aaSamw
150da6c28aaSamw static void
zfs_ace_v0_set_who(void * acep,uint64_t who)151da6c28aaSamw zfs_ace_v0_set_who(void *acep, uint64_t who)
152da6c28aaSamw {
153da6c28aaSamw ((zfs_oldace_t *)acep)->z_fuid = who;
154da6c28aaSamw }
155da6c28aaSamw
156da6c28aaSamw /*ARGSUSED*/
157da6c28aaSamw static size_t
zfs_ace_v0_size(void * acep)158da6c28aaSamw zfs_ace_v0_size(void *acep)
159da6c28aaSamw {
160da6c28aaSamw return (sizeof (zfs_oldace_t));
161da6c28aaSamw }
162da6c28aaSamw
163da6c28aaSamw static size_t
zfs_ace_v0_abstract_size(void)164da6c28aaSamw zfs_ace_v0_abstract_size(void)
165da6c28aaSamw {
166da6c28aaSamw return (sizeof (zfs_oldace_t));
167da6c28aaSamw }
168da6c28aaSamw
169da6c28aaSamw static int
zfs_ace_v0_mask_off(void)170da6c28aaSamw zfs_ace_v0_mask_off(void)
171da6c28aaSamw {
172da6c28aaSamw return (offsetof(zfs_oldace_t, z_access_mask));
173da6c28aaSamw }
174da6c28aaSamw
175da6c28aaSamw /*ARGSUSED*/
176da6c28aaSamw static int
zfs_ace_v0_data(void * acep,void ** datap)177da6c28aaSamw zfs_ace_v0_data(void *acep, void **datap)
178da6c28aaSamw {
179da6c28aaSamw *datap = NULL;
180da6c28aaSamw return (0);
181da6c28aaSamw }
182da6c28aaSamw
183da6c28aaSamw static acl_ops_t zfs_acl_v0_ops = {
184da6c28aaSamw zfs_ace_v0_get_mask,
185da6c28aaSamw zfs_ace_v0_set_mask,
186da6c28aaSamw zfs_ace_v0_get_flags,
187da6c28aaSamw zfs_ace_v0_set_flags,
188da6c28aaSamw zfs_ace_v0_get_type,
189da6c28aaSamw zfs_ace_v0_set_type,
190da6c28aaSamw zfs_ace_v0_get_who,
191da6c28aaSamw zfs_ace_v0_set_who,
192da6c28aaSamw zfs_ace_v0_size,
193da6c28aaSamw zfs_ace_v0_abstract_size,
194da6c28aaSamw zfs_ace_v0_mask_off,
195da6c28aaSamw zfs_ace_v0_data
196da6c28aaSamw };
197da6c28aaSamw
198da6c28aaSamw static uint16_t
zfs_ace_fuid_get_type(void * acep)199da6c28aaSamw zfs_ace_fuid_get_type(void *acep)
200da6c28aaSamw {
201da6c28aaSamw return (((zfs_ace_hdr_t *)acep)->z_type);
202da6c28aaSamw }
203da6c28aaSamw
204da6c28aaSamw static uint16_t
zfs_ace_fuid_get_flags(void * acep)205da6c28aaSamw zfs_ace_fuid_get_flags(void *acep)
206da6c28aaSamw {
207da6c28aaSamw return (((zfs_ace_hdr_t *)acep)->z_flags);
208da6c28aaSamw }
209da6c28aaSamw
210da6c28aaSamw static uint32_t
zfs_ace_fuid_get_mask(void * acep)211da6c28aaSamw zfs_ace_fuid_get_mask(void *acep)
212da6c28aaSamw {
213da6c28aaSamw return (((zfs_ace_hdr_t *)acep)->z_access_mask);
214da6c28aaSamw }
215da6c28aaSamw
216da6c28aaSamw static uint64_t
zfs_ace_fuid_get_who(void * args)217da6c28aaSamw zfs_ace_fuid_get_who(void *args)
218da6c28aaSamw {
219da6c28aaSamw uint16_t entry_type;
220da6c28aaSamw zfs_ace_t *acep = args;
221da6c28aaSamw
222da6c28aaSamw entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS;
223da6c28aaSamw
224da6c28aaSamw if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP ||
225da6c28aaSamw entry_type == ACE_EVERYONE)
226da6c28aaSamw return (-1);
227da6c28aaSamw return (((zfs_ace_t *)acep)->z_fuid);
228da6c28aaSamw }
229da6c28aaSamw
230da6c28aaSamw static void
zfs_ace_fuid_set_type(void * acep,uint16_t type)231da6c28aaSamw zfs_ace_fuid_set_type(void *acep, uint16_t type)
232da6c28aaSamw {
233da6c28aaSamw ((zfs_ace_hdr_t *)acep)->z_type = type;
234da6c28aaSamw }
235da6c28aaSamw
236da6c28aaSamw static void
zfs_ace_fuid_set_flags(void * acep,uint16_t flags)237da6c28aaSamw zfs_ace_fuid_set_flags(void *acep, uint16_t flags)
238da6c28aaSamw {
239da6c28aaSamw ((zfs_ace_hdr_t *)acep)->z_flags = flags;
240da6c28aaSamw }
241da6c28aaSamw
242da6c28aaSamw static void
zfs_ace_fuid_set_mask(void * acep,uint32_t mask)243da6c28aaSamw zfs_ace_fuid_set_mask(void *acep, uint32_t mask)
244da6c28aaSamw {
245da6c28aaSamw ((zfs_ace_hdr_t *)acep)->z_access_mask = mask;
246da6c28aaSamw }
247da6c28aaSamw
248da6c28aaSamw static void
zfs_ace_fuid_set_who(void * arg,uint64_t who)249da6c28aaSamw zfs_ace_fuid_set_who(void *arg, uint64_t who)
250da6c28aaSamw {
251da6c28aaSamw zfs_ace_t *acep = arg;
252da6c28aaSamw
253da6c28aaSamw uint16_t entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS;
254da6c28aaSamw
255da6c28aaSamw if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP ||
256da6c28aaSamw entry_type == ACE_EVERYONE)
257da6c28aaSamw return;
258da6c28aaSamw acep->z_fuid = who;
259da6c28aaSamw }
260da6c28aaSamw
261da6c28aaSamw static size_t
zfs_ace_fuid_size(void * acep)262da6c28aaSamw zfs_ace_fuid_size(void *acep)
263da6c28aaSamw {
264da6c28aaSamw zfs_ace_hdr_t *zacep = acep;
265da6c28aaSamw uint16_t entry_type;
266da6c28aaSamw
267da6c28aaSamw switch (zacep->z_type) {
268da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
269da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
270da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
271da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
272da6c28aaSamw return (sizeof (zfs_object_ace_t));
273da6c28aaSamw case ALLOW:
274da6c28aaSamw case DENY:
275da6c28aaSamw entry_type =
276da6c28aaSamw (((zfs_ace_hdr_t *)acep)->z_flags & ACE_TYPE_FLAGS);
277da6c28aaSamw if (entry_type == ACE_OWNER ||
2781ab99678SMark Shellenbaum entry_type == OWNING_GROUP ||
279da6c28aaSamw entry_type == ACE_EVERYONE)
280da6c28aaSamw return (sizeof (zfs_ace_hdr_t));
281da6c28aaSamw /*FALLTHROUGH*/
282da6c28aaSamw default:
283da6c28aaSamw return (sizeof (zfs_ace_t));
284da6c28aaSamw }
285da6c28aaSamw }
286da6c28aaSamw
287da6c28aaSamw static size_t
zfs_ace_fuid_abstract_size(void)288da6c28aaSamw zfs_ace_fuid_abstract_size(void)
289da6c28aaSamw {
290da6c28aaSamw return (sizeof (zfs_ace_hdr_t));
291da6c28aaSamw }
292da6c28aaSamw
293da6c28aaSamw static int
zfs_ace_fuid_mask_off(void)294da6c28aaSamw zfs_ace_fuid_mask_off(void)
295da6c28aaSamw {
296da6c28aaSamw return (offsetof(zfs_ace_hdr_t, z_access_mask));
297da6c28aaSamw }
298da6c28aaSamw
299da6c28aaSamw static int
zfs_ace_fuid_data(void * acep,void ** datap)300da6c28aaSamw zfs_ace_fuid_data(void *acep, void **datap)
301da6c28aaSamw {
302da6c28aaSamw zfs_ace_t *zacep = acep;
303da6c28aaSamw zfs_object_ace_t *zobjp;
304da6c28aaSamw
305da6c28aaSamw switch (zacep->z_hdr.z_type) {
306da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
307da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
308da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
309da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
310da6c28aaSamw zobjp = acep;
311da6c28aaSamw *datap = (caddr_t)zobjp + sizeof (zfs_ace_t);
312da6c28aaSamw return (sizeof (zfs_object_ace_t) - sizeof (zfs_ace_t));
313da6c28aaSamw default:
314da6c28aaSamw *datap = NULL;
315da6c28aaSamw return (0);
316da6c28aaSamw }
317da6c28aaSamw }
318da6c28aaSamw
319da6c28aaSamw static acl_ops_t zfs_acl_fuid_ops = {
320da6c28aaSamw zfs_ace_fuid_get_mask,
321da6c28aaSamw zfs_ace_fuid_set_mask,
322da6c28aaSamw zfs_ace_fuid_get_flags,
323da6c28aaSamw zfs_ace_fuid_set_flags,
324da6c28aaSamw zfs_ace_fuid_get_type,
325da6c28aaSamw zfs_ace_fuid_set_type,
326da6c28aaSamw zfs_ace_fuid_get_who,
327da6c28aaSamw zfs_ace_fuid_set_who,
328da6c28aaSamw zfs_ace_fuid_size,
329da6c28aaSamw zfs_ace_fuid_abstract_size,
330da6c28aaSamw zfs_ace_fuid_mask_off,
331da6c28aaSamw zfs_ace_fuid_data
332da6c28aaSamw };
333da6c28aaSamw
3340a586ceaSMark Shellenbaum /*
3350a586ceaSMark Shellenbaum * The following three functions are provided for compatibility with
3360a586ceaSMark Shellenbaum * older ZPL version in order to determine if the file use to have
3370a586ceaSMark Shellenbaum * an external ACL and what version of ACL previously existed on the
3380a586ceaSMark Shellenbaum * file. Would really be nice to not need this, sigh.
3390a586ceaSMark Shellenbaum */
3400a586ceaSMark Shellenbaum uint64_t
zfs_external_acl(znode_t * zp)3410a586ceaSMark Shellenbaum zfs_external_acl(znode_t *zp)
3420a586ceaSMark Shellenbaum {
3430a586ceaSMark Shellenbaum zfs_acl_phys_t acl_phys;
3441412a1a2SMark Shellenbaum int error;
3450a586ceaSMark Shellenbaum
3460a586ceaSMark Shellenbaum if (zp->z_is_sa)
3470a586ceaSMark Shellenbaum return (0);
3480a586ceaSMark Shellenbaum
3491412a1a2SMark Shellenbaum /*
3501412a1a2SMark Shellenbaum * Need to deal with a potential
3511412a1a2SMark Shellenbaum * race where zfs_sa_upgrade could cause
3521412a1a2SMark Shellenbaum * z_isa_sa to change.
3531412a1a2SMark Shellenbaum *
3541412a1a2SMark Shellenbaum * If the lookup fails then the state of z_is_sa should have
3551412a1a2SMark Shellenbaum * changed.
3561412a1a2SMark Shellenbaum */
3570a586ceaSMark Shellenbaum
3581412a1a2SMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zp->z_zfsvfs),
3591412a1a2SMark Shellenbaum &acl_phys, sizeof (acl_phys))) == 0)
3601412a1a2SMark Shellenbaum return (acl_phys.z_acl_extern_obj);
3611412a1a2SMark Shellenbaum else {
3621412a1a2SMark Shellenbaum /*
3631412a1a2SMark Shellenbaum * after upgrade the SA_ZPL_ZNODE_ACL should have been
3641412a1a2SMark Shellenbaum * removed
3651412a1a2SMark Shellenbaum */
3661412a1a2SMark Shellenbaum VERIFY(zp->z_is_sa && error == ENOENT);
3671412a1a2SMark Shellenbaum return (0);
3681412a1a2SMark Shellenbaum }
3690a586ceaSMark Shellenbaum }
3700a586ceaSMark Shellenbaum
3710a586ceaSMark Shellenbaum /*
3720a586ceaSMark Shellenbaum * Determine size of ACL in bytes
3730a586ceaSMark Shellenbaum *
3740a586ceaSMark Shellenbaum * This is more complicated than it should be since we have to deal
3750a586ceaSMark Shellenbaum * with old external ACLs.
3760a586ceaSMark Shellenbaum */
3770a586ceaSMark Shellenbaum static int
zfs_acl_znode_info(znode_t * zp,int * aclsize,int * aclcount,zfs_acl_phys_t * aclphys)3780a586ceaSMark Shellenbaum zfs_acl_znode_info(znode_t *zp, int *aclsize, int *aclcount,
3790a586ceaSMark Shellenbaum zfs_acl_phys_t *aclphys)
3800a586ceaSMark Shellenbaum {
3810a586ceaSMark Shellenbaum zfsvfs_t *zfsvfs = zp->z_zfsvfs;
3820a586ceaSMark Shellenbaum uint64_t acl_count;
3830a586ceaSMark Shellenbaum int size;
3840a586ceaSMark Shellenbaum int error;
3850a586ceaSMark Shellenbaum
386*06799660SGordon Ross ASSERT(RW_ISWRITER(&zp->z_acl_lock));
3870a586ceaSMark Shellenbaum if (zp->z_is_sa) {
3880a586ceaSMark Shellenbaum if ((error = sa_size(zp->z_sa_hdl, SA_ZPL_DACL_ACES(zfsvfs),
3890a586ceaSMark Shellenbaum &size)) != 0)
3900a586ceaSMark Shellenbaum return (error);
3910a586ceaSMark Shellenbaum *aclsize = size;
3920a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DACL_COUNT(zfsvfs),
3930a586ceaSMark Shellenbaum &acl_count, sizeof (acl_count))) != 0)
3940a586ceaSMark Shellenbaum return (error);
3950a586ceaSMark Shellenbaum *aclcount = acl_count;
3960a586ceaSMark Shellenbaum } else {
3970a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs),
3980a586ceaSMark Shellenbaum aclphys, sizeof (*aclphys))) != 0)
3990a586ceaSMark Shellenbaum return (error);
4000a586ceaSMark Shellenbaum
4010a586ceaSMark Shellenbaum if (aclphys->z_acl_version == ZFS_ACL_VERSION_INITIAL) {
4020a586ceaSMark Shellenbaum *aclsize = ZFS_ACL_SIZE(aclphys->z_acl_size);
4030a586ceaSMark Shellenbaum *aclcount = aclphys->z_acl_size;
4040a586ceaSMark Shellenbaum } else {
4050a586ceaSMark Shellenbaum *aclsize = aclphys->z_acl_size;
4060a586ceaSMark Shellenbaum *aclcount = aclphys->z_acl_count;
4070a586ceaSMark Shellenbaum }
4080a586ceaSMark Shellenbaum }
4090a586ceaSMark Shellenbaum return (0);
4100a586ceaSMark Shellenbaum }
4110a586ceaSMark Shellenbaum
4120a586ceaSMark Shellenbaum int
zfs_znode_acl_version(znode_t * zp)4130a586ceaSMark Shellenbaum zfs_znode_acl_version(znode_t *zp)
4140a586ceaSMark Shellenbaum {
4150a586ceaSMark Shellenbaum zfs_acl_phys_t acl_phys;
4160a586ceaSMark Shellenbaum
4171412a1a2SMark Shellenbaum if (zp->z_is_sa)
4180a586ceaSMark Shellenbaum return (ZFS_ACL_VERSION_FUID);
4191412a1a2SMark Shellenbaum else {
4201412a1a2SMark Shellenbaum int error;
4211412a1a2SMark Shellenbaum
4221412a1a2SMark Shellenbaum /*
4231412a1a2SMark Shellenbaum * Need to deal with a potential
4241412a1a2SMark Shellenbaum * race where zfs_sa_upgrade could cause
4251412a1a2SMark Shellenbaum * z_isa_sa to change.
4261412a1a2SMark Shellenbaum *
4271412a1a2SMark Shellenbaum * If the lookup fails then the state of z_is_sa should have
4281412a1a2SMark Shellenbaum * changed.
4291412a1a2SMark Shellenbaum */
4301412a1a2SMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl,
4310a586ceaSMark Shellenbaum SA_ZPL_ZNODE_ACL(zp->z_zfsvfs),
4321412a1a2SMark Shellenbaum &acl_phys, sizeof (acl_phys))) == 0)
4331412a1a2SMark Shellenbaum return (acl_phys.z_acl_version);
4341412a1a2SMark Shellenbaum else {
4351412a1a2SMark Shellenbaum /*
4361412a1a2SMark Shellenbaum * After upgrade SA_ZPL_ZNODE_ACL should have
4371412a1a2SMark Shellenbaum * been removed.
4381412a1a2SMark Shellenbaum */
4391412a1a2SMark Shellenbaum VERIFY(zp->z_is_sa && error == ENOENT);
4401412a1a2SMark Shellenbaum return (ZFS_ACL_VERSION_FUID);
4411412a1a2SMark Shellenbaum }
4420a586ceaSMark Shellenbaum }
4430a586ceaSMark Shellenbaum }
4440a586ceaSMark Shellenbaum
445da6c28aaSamw static int
zfs_acl_version(int version)446da6c28aaSamw zfs_acl_version(int version)
447da6c28aaSamw {
448da6c28aaSamw if (version < ZPL_VERSION_FUID)
449da6c28aaSamw return (ZFS_ACL_VERSION_INITIAL);
450da6c28aaSamw else
451da6c28aaSamw return (ZFS_ACL_VERSION_FUID);
452da6c28aaSamw }
453da6c28aaSamw
454da6c28aaSamw static int
zfs_acl_version_zp(znode_t * zp)455da6c28aaSamw zfs_acl_version_zp(znode_t *zp)
456da6c28aaSamw {
457da6c28aaSamw return (zfs_acl_version(zp->z_zfsvfs->z_version));
458da6c28aaSamw }
459fa9e4066Sahrens
4600a586ceaSMark Shellenbaum zfs_acl_t *
zfs_acl_alloc(int vers)461da6c28aaSamw zfs_acl_alloc(int vers)
462fa9e4066Sahrens {
463fa9e4066Sahrens zfs_acl_t *aclp;
464fa9e4066Sahrens
465fa9e4066Sahrens aclp = kmem_zalloc(sizeof (zfs_acl_t), KM_SLEEP);
466da6c28aaSamw list_create(&aclp->z_acl, sizeof (zfs_acl_node_t),
467da6c28aaSamw offsetof(zfs_acl_node_t, z_next));
468da6c28aaSamw aclp->z_version = vers;
469da6c28aaSamw if (vers == ZFS_ACL_VERSION_FUID)
470da6c28aaSamw aclp->z_ops = zfs_acl_fuid_ops;
471da6c28aaSamw else
472da6c28aaSamw aclp->z_ops = zfs_acl_v0_ops;
473fa9e4066Sahrens return (aclp);
474fa9e4066Sahrens }
475fa9e4066Sahrens
4760a586ceaSMark Shellenbaum zfs_acl_node_t *
zfs_acl_node_alloc(size_t bytes)477da6c28aaSamw zfs_acl_node_alloc(size_t bytes)
478da6c28aaSamw {
479da6c28aaSamw zfs_acl_node_t *aclnode;
480da6c28aaSamw
481da6c28aaSamw aclnode = kmem_zalloc(sizeof (zfs_acl_node_t), KM_SLEEP);
482da6c28aaSamw if (bytes) {
483da6c28aaSamw aclnode->z_acldata = kmem_alloc(bytes, KM_SLEEP);
484da6c28aaSamw aclnode->z_allocdata = aclnode->z_acldata;
485da6c28aaSamw aclnode->z_allocsize = bytes;
486da6c28aaSamw aclnode->z_size = bytes;
487da6c28aaSamw }
488da6c28aaSamw
489da6c28aaSamw return (aclnode);
490da6c28aaSamw }
491da6c28aaSamw
492da6c28aaSamw static void
zfs_acl_node_free(zfs_acl_node_t * aclnode)493da6c28aaSamw zfs_acl_node_free(zfs_acl_node_t *aclnode)
494da6c28aaSamw {
495da6c28aaSamw if (aclnode->z_allocsize)
496da6c28aaSamw kmem_free(aclnode->z_allocdata, aclnode->z_allocsize);
497da6c28aaSamw kmem_free(aclnode, sizeof (zfs_acl_node_t));
498da6c28aaSamw }
499da6c28aaSamw
5002459a9eaSmarks static void
zfs_acl_release_nodes(zfs_acl_t * aclp)5012459a9eaSmarks zfs_acl_release_nodes(zfs_acl_t *aclp)
502fa9e4066Sahrens {
503da6c28aaSamw zfs_acl_node_t *aclnode;
504da6c28aaSamw
505da6c28aaSamw while (aclnode = list_head(&aclp->z_acl)) {
506da6c28aaSamw list_remove(&aclp->z_acl, aclnode);
507da6c28aaSamw zfs_acl_node_free(aclnode);
508fa9e4066Sahrens }
5092459a9eaSmarks aclp->z_acl_count = 0;
5102459a9eaSmarks aclp->z_acl_bytes = 0;
5112459a9eaSmarks }
512da6c28aaSamw
5132459a9eaSmarks void
zfs_acl_free(zfs_acl_t * aclp)5142459a9eaSmarks zfs_acl_free(zfs_acl_t *aclp)
5152459a9eaSmarks {
5162459a9eaSmarks zfs_acl_release_nodes(aclp);
517da6c28aaSamw list_destroy(&aclp->z_acl);
518fa9e4066Sahrens kmem_free(aclp, sizeof (zfs_acl_t));
519fa9e4066Sahrens }
520fa9e4066Sahrens
521da6c28aaSamw static boolean_t
zfs_acl_valid_ace_type(uint_t type,uint_t flags)522003c2582SMark Shellenbaum zfs_acl_valid_ace_type(uint_t type, uint_t flags)
523fa9e4066Sahrens {
524003c2582SMark Shellenbaum uint16_t entry_type;
525da6c28aaSamw
526003c2582SMark Shellenbaum switch (type) {
527003c2582SMark Shellenbaum case ALLOW:
528003c2582SMark Shellenbaum case DENY:
529003c2582SMark Shellenbaum case ACE_SYSTEM_AUDIT_ACE_TYPE:
530003c2582SMark Shellenbaum case ACE_SYSTEM_ALARM_ACE_TYPE:
531003c2582SMark Shellenbaum entry_type = flags & ACE_TYPE_FLAGS;
532003c2582SMark Shellenbaum return (entry_type == ACE_OWNER ||
533003c2582SMark Shellenbaum entry_type == OWNING_GROUP ||
534003c2582SMark Shellenbaum entry_type == ACE_EVERYONE || entry_type == 0 ||
535003c2582SMark Shellenbaum entry_type == ACE_IDENTIFIER_GROUP);
536da6c28aaSamw default:
537003c2582SMark Shellenbaum if (type >= MIN_ACE_TYPE && type <= MAX_ACE_TYPE)
538003c2582SMark Shellenbaum return (B_TRUE);
539da6c28aaSamw }
540003c2582SMark Shellenbaum return (B_FALSE);
541003c2582SMark Shellenbaum }
542fa9e4066Sahrens
543003c2582SMark Shellenbaum static boolean_t
zfs_ace_valid(vtype_t obj_type,zfs_acl_t * aclp,uint16_t type,uint16_t iflags)544003c2582SMark Shellenbaum zfs_ace_valid(vtype_t obj_type, zfs_acl_t *aclp, uint16_t type, uint16_t iflags)
545003c2582SMark Shellenbaum {
546169cdae2Smarks /*
547003c2582SMark Shellenbaum * first check type of entry
548169cdae2Smarks */
549fa9e4066Sahrens
550003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags))
551da6c28aaSamw return (B_FALSE);
552da6c28aaSamw
553da6c28aaSamw switch (type) {
554da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
555da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
556da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
557da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
558da6c28aaSamw if (aclp->z_version < ZFS_ACL_VERSION_FUID)
559da6c28aaSamw return (B_FALSE);
560da6c28aaSamw aclp->z_hints |= ZFS_ACL_OBJ_ACE;
561da6c28aaSamw }
562da6c28aaSamw
563003c2582SMark Shellenbaum /*
564003c2582SMark Shellenbaum * next check inheritance level flags
565003c2582SMark Shellenbaum */
566003c2582SMark Shellenbaum
567b249c65cSmarks if (obj_type == VDIR &&
568b249c65cSmarks (iflags & (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE)))
569da6c28aaSamw aclp->z_hints |= ZFS_INHERIT_ACE;
570da6c28aaSamw
571da6c28aaSamw if (iflags & (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) {
572da6c28aaSamw if ((iflags & (ACE_FILE_INHERIT_ACE|
573da6c28aaSamw ACE_DIRECTORY_INHERIT_ACE)) == 0) {
574da6c28aaSamw return (B_FALSE);
575da6c28aaSamw }
576da6c28aaSamw }
577da6c28aaSamw
578da6c28aaSamw return (B_TRUE);
579da6c28aaSamw }
580da6c28aaSamw
581*06799660SGordon Ross /*
582*06799660SGordon Ross * We want this iterator to be usable by multiple threads in parallel.
583*06799660SGordon Ross * Caller now passes iterator state as 1st arg.
584*06799660SGordon Ross */
585da6c28aaSamw static void *
zfs_acl_next_ace(zfs_acl_iter_t * zaip,void * start,uint64_t * who,uint32_t * access_mask,uint16_t * iflags,uint16_t * type)586*06799660SGordon Ross zfs_acl_next_ace(zfs_acl_iter_t *zaip, void *start, uint64_t *who,
587da6c28aaSamw uint32_t *access_mask, uint16_t *iflags, uint16_t *type)
588da6c28aaSamw {
589*06799660SGordon Ross zfs_acl_t *aclp = zaip->zai_aclp;
590da6c28aaSamw zfs_acl_node_t *aclnode;
591da6c28aaSamw
5920a586ceaSMark Shellenbaum ASSERT(aclp);
5930a586ceaSMark Shellenbaum
594da6c28aaSamw if (start == NULL) {
595da6c28aaSamw aclnode = list_head(&aclp->z_acl);
596da6c28aaSamw if (aclnode == NULL)
597da6c28aaSamw return (NULL);
598da6c28aaSamw
599*06799660SGordon Ross zaip->zai_curr_node = aclnode;
600*06799660SGordon Ross zaip->zai_next_ace = aclnode->z_acldata;
601*06799660SGordon Ross zaip->zai_ace_idx = 0;
602da6c28aaSamw }
603da6c28aaSamw
604*06799660SGordon Ross aclnode = zaip->zai_curr_node;
605da6c28aaSamw
606da6c28aaSamw if (aclnode == NULL)
607da6c28aaSamw return (NULL);
608da6c28aaSamw
609*06799660SGordon Ross if (zaip->zai_ace_idx >= aclnode->z_ace_count) {
610*06799660SGordon Ross next_node:
611da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode);
612da6c28aaSamw if (aclnode == NULL)
613da6c28aaSamw return (NULL);
614*06799660SGordon Ross zaip->zai_curr_node = aclnode;
615*06799660SGordon Ross zaip->zai_ace_idx = 0;
616*06799660SGordon Ross zaip->zai_next_ace = aclnode->z_acldata;
617da6c28aaSamw }
618da6c28aaSamw
619*06799660SGordon Ross if (zaip->zai_ace_idx < aclnode->z_ace_count) {
620*06799660SGordon Ross void *acep = zaip->zai_next_ace;
621003c2582SMark Shellenbaum size_t ace_size;
622003c2582SMark Shellenbaum
623003c2582SMark Shellenbaum /*
624003c2582SMark Shellenbaum * Make sure we don't overstep our bounds
625003c2582SMark Shellenbaum */
626003c2582SMark Shellenbaum ace_size = aclp->z_ops.ace_size(acep);
627003c2582SMark Shellenbaum
628003c2582SMark Shellenbaum if (((caddr_t)acep + ace_size) >
629003c2582SMark Shellenbaum ((caddr_t)aclnode->z_acldata + aclnode->z_size)) {
630*06799660SGordon Ross DTRACE_PROBE3(acl__size__error, zfs_acl_t *, aclp,
631*06799660SGordon Ross zfs_acl_node_t *, aclnode, zfs_ace_hdr_t *, acep);
632*06799660SGordon Ross goto next_node;
633003c2582SMark Shellenbaum }
634003c2582SMark Shellenbaum
635da6c28aaSamw *iflags = aclp->z_ops.ace_flags_get(acep);
636da6c28aaSamw *type = aclp->z_ops.ace_type_get(acep);
637da6c28aaSamw *access_mask = aclp->z_ops.ace_mask_get(acep);
638da6c28aaSamw *who = aclp->z_ops.ace_who_get(acep);
639*06799660SGordon Ross
640*06799660SGordon Ross zaip->zai_next_ace = (caddr_t)acep + ace_size;
641*06799660SGordon Ross zaip->zai_ace_idx++;
6420a586ceaSMark Shellenbaum
643da6c28aaSamw return ((void *)acep);
644da6c28aaSamw }
645da6c28aaSamw return (NULL);
646da6c28aaSamw }
647da6c28aaSamw
648da6c28aaSamw /*ARGSUSED*/
649da6c28aaSamw static uint64_t
zfs_ace_walk(void * datap,uint64_t cookie,int aclcnt,uint16_t * flags,uint16_t * type,uint32_t * mask)650da6c28aaSamw zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt,
651da6c28aaSamw uint16_t *flags, uint16_t *type, uint32_t *mask)
652da6c28aaSamw {
653*06799660SGordon Ross zfs_acl_iter_t *zaip = datap;
654da6c28aaSamw zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie;
655da6c28aaSamw uint64_t who;
656da6c28aaSamw
657*06799660SGordon Ross acep = zfs_acl_next_ace(zaip, acep, &who, mask,
658da6c28aaSamw flags, type);
659da6c28aaSamw return ((uint64_t)(uintptr_t)acep);
660da6c28aaSamw }
661da6c28aaSamw
662da6c28aaSamw /*
663da6c28aaSamw * Copy ACE to internal ZFS format.
664da6c28aaSamw * While processing the ACL each ACE will be validated for correctness.
665da6c28aaSamw * ACE FUIDs will be created later.
666da6c28aaSamw */
667da6c28aaSamw int
zfs_copy_ace_2_fuid(zfsvfs_t * zfsvfs,vtype_t obj_type,zfs_acl_t * aclp,void * datap,zfs_ace_t * z_acl,uint64_t aclcnt,size_t * size,zfs_fuid_info_t ** fuidp,cred_t * cr)66889459e17SMark Shellenbaum zfs_copy_ace_2_fuid(zfsvfs_t *zfsvfs, vtype_t obj_type, zfs_acl_t *aclp,
6690a586ceaSMark Shellenbaum void *datap, zfs_ace_t *z_acl, uint64_t aclcnt, size_t *size,
67089459e17SMark Shellenbaum zfs_fuid_info_t **fuidp, cred_t *cr)
671da6c28aaSamw {
672da6c28aaSamw int i;
673da6c28aaSamw uint16_t entry_type;
674da6c28aaSamw zfs_ace_t *aceptr = z_acl;
675da6c28aaSamw ace_t *acep = datap;
676da6c28aaSamw zfs_object_ace_t *zobjacep;
677da6c28aaSamw ace_object_t *aceobjp;
678da6c28aaSamw
679da6c28aaSamw for (i = 0; i != aclcnt; i++) {
680da6c28aaSamw aceptr->z_hdr.z_access_mask = acep->a_access_mask;
681da6c28aaSamw aceptr->z_hdr.z_flags = acep->a_flags;
682da6c28aaSamw aceptr->z_hdr.z_type = acep->a_type;
683da6c28aaSamw entry_type = aceptr->z_hdr.z_flags & ACE_TYPE_FLAGS;
684da6c28aaSamw if (entry_type != ACE_OWNER && entry_type != OWNING_GROUP &&
6854c841f60Smarks entry_type != ACE_EVERYONE) {
68689459e17SMark Shellenbaum aceptr->z_fuid = zfs_fuid_create(zfsvfs, acep->a_who,
68789459e17SMark Shellenbaum cr, (entry_type == 0) ?
68889459e17SMark Shellenbaum ZFS_ACE_USER : ZFS_ACE_GROUP, fuidp);
6894c841f60Smarks }
6904c841f60Smarks
691da6c28aaSamw /*
692da6c28aaSamw * Make sure ACE is valid
693da6c28aaSamw */
694da6c28aaSamw if (zfs_ace_valid(obj_type, aclp, aceptr->z_hdr.z_type,
695da6c28aaSamw aceptr->z_hdr.z_flags) != B_TRUE)
696be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL));
697da6c28aaSamw
698da6c28aaSamw switch (acep->a_type) {
699da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
700da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
701da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
702da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
703da6c28aaSamw zobjacep = (zfs_object_ace_t *)aceptr;
704da6c28aaSamw aceobjp = (ace_object_t *)acep;
705da6c28aaSamw
706da6c28aaSamw bcopy(aceobjp->a_obj_type, zobjacep->z_object_type,
707da6c28aaSamw sizeof (aceobjp->a_obj_type));
708da6c28aaSamw bcopy(aceobjp->a_inherit_obj_type,
709da6c28aaSamw zobjacep->z_inherit_type,
710da6c28aaSamw sizeof (aceobjp->a_inherit_obj_type));
711da6c28aaSamw acep = (ace_t *)((caddr_t)acep + sizeof (ace_object_t));
712da6c28aaSamw break;
713da6c28aaSamw default:
714da6c28aaSamw acep = (ace_t *)((caddr_t)acep + sizeof (ace_t));
715da6c28aaSamw }
716da6c28aaSamw
717da6c28aaSamw aceptr = (zfs_ace_t *)((caddr_t)aceptr +
718da6c28aaSamw aclp->z_ops.ace_size(aceptr));
719da6c28aaSamw }
720da6c28aaSamw
721da6c28aaSamw *size = (caddr_t)aceptr - (caddr_t)z_acl;
722da6c28aaSamw
723da6c28aaSamw return (0);
724da6c28aaSamw }
725da6c28aaSamw
726da6c28aaSamw /*
727da6c28aaSamw * Copy ZFS ACEs to fixed size ace_t layout
728da6c28aaSamw */
729da6c28aaSamw static void
zfs_copy_fuid_2_ace(zfsvfs_t * zfsvfs,zfs_acl_t * aclp,cred_t * cr,void * datap,int filter)730bda89588Sjp zfs_copy_fuid_2_ace(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, cred_t *cr,
731bda89588Sjp void *datap, int filter)
732da6c28aaSamw {
733da6c28aaSamw uint64_t who;
734da6c28aaSamw uint32_t access_mask;
735da6c28aaSamw uint16_t iflags, type;
736da6c28aaSamw zfs_ace_hdr_t *zacep = NULL;
737da6c28aaSamw ace_t *acep = datap;
738da6c28aaSamw ace_object_t *objacep;
739da6c28aaSamw zfs_object_ace_t *zobjacep;
740da6c28aaSamw size_t ace_size;
741da6c28aaSamw uint16_t entry_type;
742*06799660SGordon Ross zfs_acl_iter_t zai = {0};
743da6c28aaSamw
744*06799660SGordon Ross zai.zai_aclp = aclp;
745*06799660SGordon Ross while (zacep = zfs_acl_next_ace(&zai, zacep,
746da6c28aaSamw &who, &access_mask, &iflags, &type)) {
747da6c28aaSamw
748da6c28aaSamw switch (type) {
749da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
750da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
751da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
752da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
753da6c28aaSamw if (filter) {
754da6c28aaSamw continue;
755da6c28aaSamw }
756da6c28aaSamw zobjacep = (zfs_object_ace_t *)zacep;
757da6c28aaSamw objacep = (ace_object_t *)acep;
758da6c28aaSamw bcopy(zobjacep->z_object_type,
759da6c28aaSamw objacep->a_obj_type,
760da6c28aaSamw sizeof (zobjacep->z_object_type));
761da6c28aaSamw bcopy(zobjacep->z_inherit_type,
762da6c28aaSamw objacep->a_inherit_obj_type,
763da6c28aaSamw sizeof (zobjacep->z_inherit_type));
764da6c28aaSamw ace_size = sizeof (ace_object_t);
765da6c28aaSamw break;
766da6c28aaSamw default:
767da6c28aaSamw ace_size = sizeof (ace_t);
768da6c28aaSamw break;
769da6c28aaSamw }
770da6c28aaSamw
771da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS);
772da6c28aaSamw if ((entry_type != ACE_OWNER &&
7731ab99678SMark Shellenbaum entry_type != OWNING_GROUP &&
774e0d35c44Smarks entry_type != ACE_EVERYONE)) {
775e0d35c44Smarks acep->a_who = zfs_fuid_map_id(zfsvfs, who,
776e0d35c44Smarks cr, (entry_type & ACE_IDENTIFIER_GROUP) ?
777e0d35c44Smarks ZFS_ACE_GROUP : ZFS_ACE_USER);
778e0d35c44Smarks } else {
779da6c28aaSamw acep->a_who = (uid_t)(int64_t)who;
780e0d35c44Smarks }
781da6c28aaSamw acep->a_access_mask = access_mask;
782da6c28aaSamw acep->a_flags = iflags;
783da6c28aaSamw acep->a_type = type;
784da6c28aaSamw acep = (ace_t *)((caddr_t)acep + ace_size);
785da6c28aaSamw }
786da6c28aaSamw }
787da6c28aaSamw
788da6c28aaSamw static int
zfs_copy_ace_2_oldace(vtype_t obj_type,zfs_acl_t * aclp,ace_t * acep,zfs_oldace_t * z_acl,int aclcnt,size_t * size)789da6c28aaSamw zfs_copy_ace_2_oldace(vtype_t obj_type, zfs_acl_t *aclp, ace_t *acep,
790da6c28aaSamw zfs_oldace_t *z_acl, int aclcnt, size_t *size)
791da6c28aaSamw {
792da6c28aaSamw int i;
793da6c28aaSamw zfs_oldace_t *aceptr = z_acl;
794da6c28aaSamw
795da6c28aaSamw for (i = 0; i != aclcnt; i++, aceptr++) {
796da6c28aaSamw aceptr->z_access_mask = acep[i].a_access_mask;
797da6c28aaSamw aceptr->z_type = acep[i].a_type;
798da6c28aaSamw aceptr->z_flags = acep[i].a_flags;
799da6c28aaSamw aceptr->z_fuid = acep[i].a_who;
800da6c28aaSamw /*
801da6c28aaSamw * Make sure ACE is valid
802da6c28aaSamw */
803da6c28aaSamw if (zfs_ace_valid(obj_type, aclp, aceptr->z_type,
804da6c28aaSamw aceptr->z_flags) != B_TRUE)
805be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL));
806da6c28aaSamw }
807da6c28aaSamw *size = (caddr_t)aceptr - (caddr_t)z_acl;
808da6c28aaSamw return (0);
809da6c28aaSamw }
810da6c28aaSamw
811da6c28aaSamw /*
812da6c28aaSamw * convert old ACL format to new
813da6c28aaSamw */
814da6c28aaSamw void
zfs_acl_xform(znode_t * zp,zfs_acl_t * aclp,cred_t * cr)81589459e17SMark Shellenbaum zfs_acl_xform(znode_t *zp, zfs_acl_t *aclp, cred_t *cr)
816da6c28aaSamw {
817da6c28aaSamw zfs_oldace_t *oldaclp;
818da6c28aaSamw int i;
819da6c28aaSamw uint16_t type, iflags;
820da6c28aaSamw uint32_t access_mask;
821da6c28aaSamw uint64_t who;
822da6c28aaSamw void *cookie = NULL;
8232459a9eaSmarks zfs_acl_node_t *newaclnode;
824*06799660SGordon Ross zfs_acl_iter_t zai = {0};
825da6c28aaSamw
826da6c28aaSamw ASSERT(aclp->z_version == ZFS_ACL_VERSION_INITIAL);
827da6c28aaSamw /*
828da6c28aaSamw * First create the ACE in a contiguous piece of memory
829da6c28aaSamw * for zfs_copy_ace_2_fuid().
830da6c28aaSamw *
831da6c28aaSamw * We only convert an ACL once, so this won't happen
832da6c28aaSamw * everytime.
833da6c28aaSamw */
834da6c28aaSamw oldaclp = kmem_alloc(sizeof (zfs_oldace_t) * aclp->z_acl_count,
835da6c28aaSamw KM_SLEEP);
836da6c28aaSamw i = 0;
837*06799660SGordon Ross
838*06799660SGordon Ross zai.zai_aclp = aclp;
839*06799660SGordon Ross while (cookie = zfs_acl_next_ace(&zai, cookie, &who,
840da6c28aaSamw &access_mask, &iflags, &type)) {
841da6c28aaSamw oldaclp[i].z_flags = iflags;
842da6c28aaSamw oldaclp[i].z_type = type;
843da6c28aaSamw oldaclp[i].z_fuid = who;
844da6c28aaSamw oldaclp[i++].z_access_mask = access_mask;
845da6c28aaSamw }
846da6c28aaSamw
847da6c28aaSamw newaclnode = zfs_acl_node_alloc(aclp->z_acl_count *
848da6c28aaSamw sizeof (zfs_object_ace_t));
849da6c28aaSamw aclp->z_ops = zfs_acl_fuid_ops;
85089459e17SMark Shellenbaum VERIFY(zfs_copy_ace_2_fuid(zp->z_zfsvfs, ZTOV(zp)->v_type, aclp,
85189459e17SMark Shellenbaum oldaclp, newaclnode->z_acldata, aclp->z_acl_count,
85289459e17SMark Shellenbaum &newaclnode->z_size, NULL, cr) == 0);
853da6c28aaSamw newaclnode->z_ace_count = aclp->z_acl_count;
854da6c28aaSamw aclp->z_version = ZFS_ACL_VERSION;
855da6c28aaSamw kmem_free(oldaclp, aclp->z_acl_count * sizeof (zfs_oldace_t));
856da6c28aaSamw
857da6c28aaSamw /*
858da6c28aaSamw * Release all previous ACL nodes
859da6c28aaSamw */
860da6c28aaSamw
8612459a9eaSmarks zfs_acl_release_nodes(aclp);
8622459a9eaSmarks
863da6c28aaSamw list_insert_head(&aclp->z_acl, newaclnode);
8642459a9eaSmarks
8652459a9eaSmarks aclp->z_acl_bytes = newaclnode->z_size;
8662459a9eaSmarks aclp->z_acl_count = newaclnode->z_ace_count;
8672459a9eaSmarks
868fa9e4066Sahrens }
869fa9e4066Sahrens
870fa9e4066Sahrens /*
871fa9e4066Sahrens * Convert unix access mask to v4 access mask
872fa9e4066Sahrens */
873fa9e4066Sahrens static uint32_t
zfs_unix_to_v4(uint32_t access_mask)874fa9e4066Sahrens zfs_unix_to_v4(uint32_t access_mask)
875fa9e4066Sahrens {
876fa9e4066Sahrens uint32_t new_mask = 0;
877fa9e4066Sahrens
878da6c28aaSamw if (access_mask & S_IXOTH)
879da6c28aaSamw new_mask |= ACE_EXECUTE;
880da6c28aaSamw if (access_mask & S_IWOTH)
881da6c28aaSamw new_mask |= ACE_WRITE_DATA;
882da6c28aaSamw if (access_mask & S_IROTH)
883fa9e4066Sahrens new_mask |= ACE_READ_DATA;
884fa9e4066Sahrens return (new_mask);
885fa9e4066Sahrens }
886fa9e4066Sahrens
887fa9e4066Sahrens static void
zfs_set_ace(zfs_acl_t * aclp,void * acep,uint32_t access_mask,uint16_t access_type,uint64_t fuid,uint16_t entry_type)888da6c28aaSamw zfs_set_ace(zfs_acl_t *aclp, void *acep, uint32_t access_mask,
889da6c28aaSamw uint16_t access_type, uint64_t fuid, uint16_t entry_type)
890fa9e4066Sahrens {
891da6c28aaSamw uint16_t type = entry_type & ACE_TYPE_FLAGS;
892da6c28aaSamw
893da6c28aaSamw aclp->z_ops.ace_mask_set(acep, access_mask);
894da6c28aaSamw aclp->z_ops.ace_type_set(acep, access_type);
895da6c28aaSamw aclp->z_ops.ace_flags_set(acep, entry_type);
8961ab99678SMark Shellenbaum if ((type != ACE_OWNER && type != OWNING_GROUP &&
897da6c28aaSamw type != ACE_EVERYONE))
898da6c28aaSamw aclp->z_ops.ace_who_set(acep, fuid);
899fa9e4066Sahrens }
900fa9e4066Sahrens
901da6c28aaSamw /*
902da6c28aaSamw * Determine mode of file based on ACL.
903da6c28aaSamw */
9040a586ceaSMark Shellenbaum uint64_t
zfs_mode_compute(uint64_t fmode,zfs_acl_t * aclp,uint64_t * pflags,uint64_t fuid,uint64_t fgid)90527dd1e87SMark Shellenbaum zfs_mode_compute(uint64_t fmode, zfs_acl_t *aclp,
90627dd1e87SMark Shellenbaum uint64_t *pflags, uint64_t fuid, uint64_t fgid)
907fa9e4066Sahrens {
908da6c28aaSamw int entry_type;
909da6c28aaSamw mode_t mode;
910da6c28aaSamw mode_t seen = 0;
91154811da5SToomas Soome zfs_ace_hdr_t *acep = NULL;
912da6c28aaSamw uint64_t who;
913da6c28aaSamw uint16_t iflags, type;
914da6c28aaSamw uint32_t access_mask;
915d47621a4STim Haley boolean_t an_exec_denied = B_FALSE;
916*06799660SGordon Ross zfs_acl_iter_t zai = {0};
917da6c28aaSamw
9180a586ceaSMark Shellenbaum mode = (fmode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX));
919fa9e4066Sahrens
920*06799660SGordon Ross zai.zai_aclp = aclp;
921*06799660SGordon Ross while (acep = zfs_acl_next_ace(&zai, acep, &who,
922da6c28aaSamw &access_mask, &iflags, &type)) {
92329a0b737Smarks
924003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags))
925003c2582SMark Shellenbaum continue;
926003c2582SMark Shellenbaum
9271ab99678SMark Shellenbaum entry_type = (iflags & ACE_TYPE_FLAGS);
9281ab99678SMark Shellenbaum
92929a0b737Smarks /*
930de0f1ddbSAlbert Lee * Skip over any inherit_only ACEs
93129a0b737Smarks */
932de0f1ddbSAlbert Lee if (iflags & ACE_INHERIT_ONLY_ACE)
93329a0b737Smarks continue;
93429a0b737Smarks
93527dd1e87SMark Shellenbaum if (entry_type == ACE_OWNER || (entry_type == 0 &&
93627dd1e87SMark Shellenbaum who == fuid)) {
937da6c28aaSamw if ((access_mask & ACE_READ_DATA) &&
938fa9e4066Sahrens (!(seen & S_IRUSR))) {
939fa9e4066Sahrens seen |= S_IRUSR;
940da6c28aaSamw if (type == ALLOW) {
941fa9e4066Sahrens mode |= S_IRUSR;
942fa9e4066Sahrens }
943fa9e4066Sahrens }
944da6c28aaSamw if ((access_mask & ACE_WRITE_DATA) &&
945fa9e4066Sahrens (!(seen & S_IWUSR))) {
946fa9e4066Sahrens seen |= S_IWUSR;
947da6c28aaSamw if (type == ALLOW) {
948fa9e4066Sahrens mode |= S_IWUSR;
949fa9e4066Sahrens }
950fa9e4066Sahrens }
951da6c28aaSamw if ((access_mask & ACE_EXECUTE) &&
952fa9e4066Sahrens (!(seen & S_IXUSR))) {
953fa9e4066Sahrens seen |= S_IXUSR;
954da6c28aaSamw if (type == ALLOW) {
955fa9e4066Sahrens mode |= S_IXUSR;
956fa9e4066Sahrens }
957fa9e4066Sahrens }
95827dd1e87SMark Shellenbaum } else if (entry_type == OWNING_GROUP ||
95927dd1e87SMark Shellenbaum (entry_type == ACE_IDENTIFIER_GROUP && who == fgid)) {
960da6c28aaSamw if ((access_mask & ACE_READ_DATA) &&
961fa9e4066Sahrens (!(seen & S_IRGRP))) {
962fa9e4066Sahrens seen |= S_IRGRP;
963da6c28aaSamw if (type == ALLOW) {
964fa9e4066Sahrens mode |= S_IRGRP;
965fa9e4066Sahrens }
966fa9e4066Sahrens }
967da6c28aaSamw if ((access_mask & ACE_WRITE_DATA) &&
968fa9e4066Sahrens (!(seen & S_IWGRP))) {
969fa9e4066Sahrens seen |= S_IWGRP;
970da6c28aaSamw if (type == ALLOW) {
971fa9e4066Sahrens mode |= S_IWGRP;
972fa9e4066Sahrens }
973fa9e4066Sahrens }
974da6c28aaSamw if ((access_mask & ACE_EXECUTE) &&
975fa9e4066Sahrens (!(seen & S_IXGRP))) {
976fa9e4066Sahrens seen |= S_IXGRP;
977da6c28aaSamw if (type == ALLOW) {
978fa9e4066Sahrens mode |= S_IXGRP;
979fa9e4066Sahrens }
980fa9e4066Sahrens }
981fa9e4066Sahrens } else if (entry_type == ACE_EVERYONE) {
982da6c28aaSamw if ((access_mask & ACE_READ_DATA)) {
983fa9e4066Sahrens if (!(seen & S_IRUSR)) {
984fa9e4066Sahrens seen |= S_IRUSR;
985da6c28aaSamw if (type == ALLOW) {
986fa9e4066Sahrens mode |= S_IRUSR;
987fa9e4066Sahrens }
988fa9e4066Sahrens }
989fa9e4066Sahrens if (!(seen & S_IRGRP)) {
990fa9e4066Sahrens seen |= S_IRGRP;
991da6c28aaSamw if (type == ALLOW) {
992fa9e4066Sahrens mode |= S_IRGRP;
993fa9e4066Sahrens }
994fa9e4066Sahrens }
995fa9e4066Sahrens if (!(seen & S_IROTH)) {
996fa9e4066Sahrens seen |= S_IROTH;
997da6c28aaSamw if (type == ALLOW) {
998fa9e4066Sahrens mode |= S_IROTH;
999fa9e4066Sahrens }
1000fa9e4066Sahrens }
1001fa9e4066Sahrens }
1002da6c28aaSamw if ((access_mask & ACE_WRITE_DATA)) {
1003fa9e4066Sahrens if (!(seen & S_IWUSR)) {
1004fa9e4066Sahrens seen |= S_IWUSR;
1005da6c28aaSamw if (type == ALLOW) {
1006fa9e4066Sahrens mode |= S_IWUSR;
1007fa9e4066Sahrens }
1008fa9e4066Sahrens }
1009fa9e4066Sahrens if (!(seen & S_IWGRP)) {
1010fa9e4066Sahrens seen |= S_IWGRP;
1011da6c28aaSamw if (type == ALLOW) {
1012fa9e4066Sahrens mode |= S_IWGRP;
1013fa9e4066Sahrens }
1014fa9e4066Sahrens }
1015fa9e4066Sahrens if (!(seen & S_IWOTH)) {
1016fa9e4066Sahrens seen |= S_IWOTH;
1017da6c28aaSamw if (type == ALLOW) {
1018fa9e4066Sahrens mode |= S_IWOTH;
1019fa9e4066Sahrens }
1020fa9e4066Sahrens }
1021fa9e4066Sahrens }
1022da6c28aaSamw if ((access_mask & ACE_EXECUTE)) {
1023fa9e4066Sahrens if (!(seen & S_IXUSR)) {
1024fa9e4066Sahrens seen |= S_IXUSR;
1025da6c28aaSamw if (type == ALLOW) {
1026fa9e4066Sahrens mode |= S_IXUSR;
1027fa9e4066Sahrens }
1028fa9e4066Sahrens }
1029fa9e4066Sahrens if (!(seen & S_IXGRP)) {
1030fa9e4066Sahrens seen |= S_IXGRP;
1031da6c28aaSamw if (type == ALLOW) {
1032fa9e4066Sahrens mode |= S_IXGRP;
1033fa9e4066Sahrens }
1034fa9e4066Sahrens }
1035fa9e4066Sahrens if (!(seen & S_IXOTH)) {
1036fa9e4066Sahrens seen |= S_IXOTH;
1037da6c28aaSamw if (type == ALLOW) {
1038fa9e4066Sahrens mode |= S_IXOTH;
1039fa9e4066Sahrens }
1040fa9e4066Sahrens }
1041fa9e4066Sahrens }
1042d47621a4STim Haley } else {
1043d47621a4STim Haley /*
1044d47621a4STim Haley * Only care if this IDENTIFIER_GROUP or
1045d47621a4STim Haley * USER ACE denies execute access to someone,
1046d47621a4STim Haley * mode is not affected
1047d47621a4STim Haley */
1048d47621a4STim Haley if ((access_mask & ACE_EXECUTE) && type == DENY)
1049d47621a4STim Haley an_exec_denied = B_TRUE;
1050fa9e4066Sahrens }
1051fa9e4066Sahrens }
1052d47621a4STim Haley
10534929fd5eSTim Haley /*
10544929fd5eSTim Haley * Failure to allow is effectively a deny, so execute permission
10554929fd5eSTim Haley * is denied if it was never mentioned or if we explicitly
10564929fd5eSTim Haley * weren't allowed it.
10574929fd5eSTim Haley */
10584929fd5eSTim Haley if (!an_exec_denied &&
10594929fd5eSTim Haley ((seen & ALL_MODE_EXECS) != ALL_MODE_EXECS ||
10604929fd5eSTim Haley (mode & ALL_MODE_EXECS) != ALL_MODE_EXECS))
1061d47621a4STim Haley an_exec_denied = B_TRUE;
1062d47621a4STim Haley
1063d47621a4STim Haley if (an_exec_denied)
10640a586ceaSMark Shellenbaum *pflags &= ~ZFS_NO_EXECS_DENIED;
1065d47621a4STim Haley else
10660a586ceaSMark Shellenbaum *pflags |= ZFS_NO_EXECS_DENIED;
1067d47621a4STim Haley
1068fa9e4066Sahrens return (mode);
1069fa9e4066Sahrens }
1070fa9e4066Sahrens
1071fa9e4066Sahrens /*
10724929fd5eSTim Haley * Read an external acl object. If the intent is to modify, always
10734929fd5eSTim Haley * create a new acl and leave any cached acl in place.
1074fa9e4066Sahrens */
1075f67950b2SNasf-Fan int
zfs_acl_node_read(struct znode * zp,boolean_t have_lock,zfs_acl_t ** aclpp,boolean_t will_modify)1076f67950b2SNasf-Fan zfs_acl_node_read(struct znode *zp, boolean_t have_lock, zfs_acl_t **aclpp,
10771412a1a2SMark Shellenbaum boolean_t will_modify)
1078fa9e4066Sahrens {
1079fa9e4066Sahrens zfs_acl_t *aclp;
10800a586ceaSMark Shellenbaum int aclsize;
10810a586ceaSMark Shellenbaum int acl_count;
1082da6c28aaSamw zfs_acl_node_t *aclnode;
10830a586ceaSMark Shellenbaum zfs_acl_phys_t znode_acl;
10840a586ceaSMark Shellenbaum int version;
10850a586ceaSMark Shellenbaum int error;
10861412a1a2SMark Shellenbaum boolean_t drop_lock = B_FALSE;
1087fa9e4066Sahrens
1088*06799660SGordon Ross ASSERT(RW_ISWRITER(&zp->z_acl_lock));
1089fa9e4066Sahrens
10904929fd5eSTim Haley if (zp->z_acl_cached && !will_modify) {
1091d47621a4STim Haley *aclpp = zp->z_acl_cached;
1092d47621a4STim Haley return (0);
1093d47621a4STim Haley }
1094d47621a4STim Haley
10951412a1a2SMark Shellenbaum /*
10961412a1a2SMark Shellenbaum * close race where znode could be upgrade while trying to
10971412a1a2SMark Shellenbaum * read the znode attributes.
10981412a1a2SMark Shellenbaum *
10991412a1a2SMark Shellenbaum * But this could only happen if the file isn't already an SA
11001412a1a2SMark Shellenbaum * znode
11011412a1a2SMark Shellenbaum */
11021412a1a2SMark Shellenbaum if (!zp->z_is_sa && !have_lock) {
11031412a1a2SMark Shellenbaum mutex_enter(&zp->z_lock);
11041412a1a2SMark Shellenbaum drop_lock = B_TRUE;
11051412a1a2SMark Shellenbaum }
11061412a1a2SMark Shellenbaum version = zfs_znode_acl_version(zp);
1107fa9e4066Sahrens
11080a586ceaSMark Shellenbaum if ((error = zfs_acl_znode_info(zp, &aclsize,
11091412a1a2SMark Shellenbaum &acl_count, &znode_acl)) != 0) {
11101412a1a2SMark Shellenbaum goto done;
11111412a1a2SMark Shellenbaum }
11120a586ceaSMark Shellenbaum
11130a586ceaSMark Shellenbaum aclp = zfs_acl_alloc(version);
1114fa9e4066Sahrens
1115da6c28aaSamw aclp->z_acl_count = acl_count;
1116da6c28aaSamw aclp->z_acl_bytes = aclsize;
1117da6c28aaSamw
11180a586ceaSMark Shellenbaum aclnode = zfs_acl_node_alloc(aclsize);
11190a586ceaSMark Shellenbaum aclnode->z_ace_count = aclp->z_acl_count;
11200a586ceaSMark Shellenbaum aclnode->z_size = aclsize;
11210a586ceaSMark Shellenbaum
11220a586ceaSMark Shellenbaum if (!zp->z_is_sa) {
11230a586ceaSMark Shellenbaum if (znode_acl.z_acl_extern_obj) {
11240a586ceaSMark Shellenbaum error = dmu_read(zp->z_zfsvfs->z_os,
11250a586ceaSMark Shellenbaum znode_acl.z_acl_extern_obj, 0, aclnode->z_size,
11260a586ceaSMark Shellenbaum aclnode->z_acldata, DMU_READ_PREFETCH);
11270a586ceaSMark Shellenbaum } else {
11280a586ceaSMark Shellenbaum bcopy(znode_acl.z_ace_data, aclnode->z_acldata,
11290a586ceaSMark Shellenbaum aclnode->z_size);
11300a586ceaSMark Shellenbaum }
11310a586ceaSMark Shellenbaum } else {
11320a586ceaSMark Shellenbaum error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DACL_ACES(zp->z_zfsvfs),
11330a586ceaSMark Shellenbaum aclnode->z_acldata, aclnode->z_size);
11340a586ceaSMark Shellenbaum }
11350a586ceaSMark Shellenbaum
1136ea8dc4b6Seschrock if (error != 0) {
1137ea8dc4b6Seschrock zfs_acl_free(aclp);
11380a586ceaSMark Shellenbaum zfs_acl_node_free(aclnode);
1139b87f3af3Sperrin /* convert checksum errors into IO errors */
1140b87f3af3Sperrin if (error == ECKSUM)
1141be6fd75aSMatthew Ahrens error = SET_ERROR(EIO);
11421412a1a2SMark Shellenbaum goto done;
1143ea8dc4b6Seschrock }
1144fa9e4066Sahrens
11450a586ceaSMark Shellenbaum list_insert_head(&aclp->z_acl, aclnode);
11460a586ceaSMark Shellenbaum
11474929fd5eSTim Haley *aclpp = aclp;
11484929fd5eSTim Haley if (!will_modify)
11494929fd5eSTim Haley zp->z_acl_cached = aclp;
11501412a1a2SMark Shellenbaum done:
11511412a1a2SMark Shellenbaum if (drop_lock)
11521412a1a2SMark Shellenbaum mutex_exit(&zp->z_lock);
11531412a1a2SMark Shellenbaum return (error);
1154fa9e4066Sahrens }
1155fa9e4066Sahrens
11560a586ceaSMark Shellenbaum /*ARGSUSED*/
11570a586ceaSMark Shellenbaum void
zfs_acl_data_locator(void ** dataptr,uint32_t * length,uint32_t buflen,boolean_t start,void * userdata)11580a586ceaSMark Shellenbaum zfs_acl_data_locator(void **dataptr, uint32_t *length, uint32_t buflen,
11590a586ceaSMark Shellenbaum boolean_t start, void *userdata)
11600a586ceaSMark Shellenbaum {
11610a586ceaSMark Shellenbaum zfs_acl_locator_cb_t *cb = (zfs_acl_locator_cb_t *)userdata;
11620a586ceaSMark Shellenbaum
11630a586ceaSMark Shellenbaum if (start) {
11640a586ceaSMark Shellenbaum cb->cb_acl_node = list_head(&cb->cb_aclp->z_acl);
11650a586ceaSMark Shellenbaum } else {
11660a586ceaSMark Shellenbaum cb->cb_acl_node = list_next(&cb->cb_aclp->z_acl,
11670a586ceaSMark Shellenbaum cb->cb_acl_node);
11680a586ceaSMark Shellenbaum }
11690a586ceaSMark Shellenbaum *dataptr = cb->cb_acl_node->z_acldata;
11700a586ceaSMark Shellenbaum *length = cb->cb_acl_node->z_size;
11710a586ceaSMark Shellenbaum }
11720a586ceaSMark Shellenbaum
117327dd1e87SMark Shellenbaum int
zfs_acl_chown_setattr(znode_t * zp)117427dd1e87SMark Shellenbaum zfs_acl_chown_setattr(znode_t *zp)
117527dd1e87SMark Shellenbaum {
117627dd1e87SMark Shellenbaum int error;
117727dd1e87SMark Shellenbaum zfs_acl_t *aclp;
117827dd1e87SMark Shellenbaum
11791412a1a2SMark Shellenbaum ASSERT(MUTEX_HELD(&zp->z_lock));
1180*06799660SGordon Ross ASSERT(RW_ISWRITER(&zp->z_acl_lock));
118127dd1e87SMark Shellenbaum
11821412a1a2SMark Shellenbaum if ((error = zfs_acl_node_read(zp, B_TRUE, &aclp, B_FALSE)) == 0)
118327dd1e87SMark Shellenbaum zp->z_mode = zfs_mode_compute(zp->z_mode, aclp,
1184f1696b23SMark Shellenbaum &zp->z_pflags, zp->z_uid, zp->z_gid);
118527dd1e87SMark Shellenbaum return (error);
118627dd1e87SMark Shellenbaum }
118727dd1e87SMark Shellenbaum
1188fa9e4066Sahrens /*
1189da6c28aaSamw * common code for setting ACLs.
1190fa9e4066Sahrens *
1191fa9e4066Sahrens * This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl.
1192fa9e4066Sahrens * zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's
1193fa9e4066Sahrens * already checked the acl and knows whether to inherit.
1194fa9e4066Sahrens */
1195fa9e4066Sahrens int
zfs_aclset_common(znode_t * zp,zfs_acl_t * aclp,cred_t * cr,dmu_tx_t * tx)119689459e17SMark Shellenbaum zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx)
1197fa9e4066Sahrens {
11980a586ceaSMark Shellenbaum int error;
11990a586ceaSMark Shellenbaum zfsvfs_t *zfsvfs = zp->z_zfsvfs;
12000a586ceaSMark Shellenbaum dmu_object_type_t otype;
12010a586ceaSMark Shellenbaum zfs_acl_locator_cb_t locate = { 0 };
12020a586ceaSMark Shellenbaum uint64_t mode;
12030a586ceaSMark Shellenbaum sa_bulk_attr_t bulk[5];
12040a586ceaSMark Shellenbaum uint64_t ctime[2];
12050a586ceaSMark Shellenbaum int count = 0;
120682693e09SWHR zfs_acl_phys_t acl_phys;
1207*06799660SGordon Ross zfs_acl_iter_t zai = {0};
1208*06799660SGordon Ross
1209*06799660SGordon Ross /*
1210*06799660SGordon Ross * One might be tempted to add here:
1211*06799660SGordon Ross * ASSERT(RW_ISWRITER(&zp->z_acl_lock));
1212*06799660SGordon Ross * and most callers have that lock, but zfs_mknode
1213*06799660SGordon Ross * calls without the lock when making a new node,
1214*06799660SGordon Ross * which is OK because it's not visible yet.
1215*06799660SGordon Ross */
12160a586ceaSMark Shellenbaum
12170a586ceaSMark Shellenbaum mode = zp->z_mode;
121827dd1e87SMark Shellenbaum
1219f1696b23SMark Shellenbaum mode = zfs_mode_compute(mode, aclp, &zp->z_pflags,
1220f1696b23SMark Shellenbaum zp->z_uid, zp->z_gid);
12210a586ceaSMark Shellenbaum
12220a586ceaSMark Shellenbaum zp->z_mode = mode;
12230a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zfsvfs), NULL,
12240a586ceaSMark Shellenbaum &mode, sizeof (mode));
12250a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs), NULL,
12260a586ceaSMark Shellenbaum &zp->z_pflags, sizeof (zp->z_pflags));
12270a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL,
12280a586ceaSMark Shellenbaum &ctime, sizeof (ctime));
1229fa9e4066Sahrens
12304929fd5eSTim Haley if (zp->z_acl_cached) {
1231d47621a4STim Haley zfs_acl_free(zp->z_acl_cached);
1232d47621a4STim Haley zp->z_acl_cached = NULL;
1233d47621a4STim Haley }
1234d47621a4STim Haley
1235fa9e4066Sahrens /*
12360a586ceaSMark Shellenbaum * Upgrade needed?
1237fa9e4066Sahrens */
1238da6c28aaSamw if (!zfsvfs->z_use_fuids) {
1239da6c28aaSamw otype = DMU_OT_OLDACL;
1240da6c28aaSamw } else {
1241da6c28aaSamw if ((aclp->z_version == ZFS_ACL_VERSION_INITIAL) &&
1242da6c28aaSamw (zfsvfs->z_version >= ZPL_VERSION_FUID))
124389459e17SMark Shellenbaum zfs_acl_xform(zp, aclp, cr);
1244da6c28aaSamw ASSERT(aclp->z_version >= ZFS_ACL_VERSION_FUID);
1245da6c28aaSamw otype = DMU_OT_ACL;
1246da6c28aaSamw }
1247da6c28aaSamw
12480a586ceaSMark Shellenbaum /*
12490a586ceaSMark Shellenbaum * Arrgh, we have to handle old on disk format
12500a586ceaSMark Shellenbaum * as well as newer (preferred) SA format.
12510a586ceaSMark Shellenbaum */
12520a586ceaSMark Shellenbaum
12530a586ceaSMark Shellenbaum if (zp->z_is_sa) { /* the easy case, just update the ACL attribute */
12540a586ceaSMark Shellenbaum locate.cb_aclp = aclp;
12550a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_ACES(zfsvfs),
12560a586ceaSMark Shellenbaum zfs_acl_data_locator, &locate, aclp->z_acl_bytes);
12570a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_COUNT(zfsvfs),
12580a586ceaSMark Shellenbaum NULL, &aclp->z_acl_count, sizeof (uint64_t));
12590a586ceaSMark Shellenbaum } else { /* Painful legacy way */
12600a586ceaSMark Shellenbaum zfs_acl_node_t *aclnode;
12610a586ceaSMark Shellenbaum uint64_t off = 0;
12620a586ceaSMark Shellenbaum uint64_t aoid;
12630a586ceaSMark Shellenbaum
12640a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs),
12650a586ceaSMark Shellenbaum &acl_phys, sizeof (acl_phys))) != 0)
12660a586ceaSMark Shellenbaum return (error);
12670a586ceaSMark Shellenbaum
12680a586ceaSMark Shellenbaum aoid = acl_phys.z_acl_extern_obj;
12690a586ceaSMark Shellenbaum
12700a586ceaSMark Shellenbaum if (aclp->z_acl_bytes > ZFS_ACE_SPACE) {
12710a586ceaSMark Shellenbaum /*
12720a586ceaSMark Shellenbaum * If ACL was previously external and we are now
12730a586ceaSMark Shellenbaum * converting to new ACL format then release old
12740a586ceaSMark Shellenbaum * ACL object and create a new one.
12750a586ceaSMark Shellenbaum */
12760a586ceaSMark Shellenbaum if (aoid &&
12770a586ceaSMark Shellenbaum aclp->z_version != acl_phys.z_acl_version) {
12780a586ceaSMark Shellenbaum error = dmu_object_free(zfsvfs->z_os, aoid, tx);
12790a586ceaSMark Shellenbaum if (error)
12800a586ceaSMark Shellenbaum return (error);
12810a586ceaSMark Shellenbaum aoid = 0;
12820a586ceaSMark Shellenbaum }
12830a586ceaSMark Shellenbaum if (aoid == 0) {
12840a586ceaSMark Shellenbaum aoid = dmu_object_alloc(zfsvfs->z_os,
12850a586ceaSMark Shellenbaum otype, aclp->z_acl_bytes,
12860a586ceaSMark Shellenbaum otype == DMU_OT_ACL ?
12870a586ceaSMark Shellenbaum DMU_OT_SYSACL : DMU_OT_NONE,
12880a586ceaSMark Shellenbaum otype == DMU_OT_ACL ?
128954811da5SToomas Soome DN_OLD_MAX_BONUSLEN : 0, tx);
12900a586ceaSMark Shellenbaum } else {
12910a586ceaSMark Shellenbaum (void) dmu_object_set_blocksize(zfsvfs->z_os,
12920a586ceaSMark Shellenbaum aoid, aclp->z_acl_bytes, 0, tx);
12930a586ceaSMark Shellenbaum }
12940a586ceaSMark Shellenbaum acl_phys.z_acl_extern_obj = aoid;
12950a586ceaSMark Shellenbaum for (aclnode = list_head(&aclp->z_acl); aclnode;
12960a586ceaSMark Shellenbaum aclnode = list_next(&aclp->z_acl, aclnode)) {
12970a586ceaSMark Shellenbaum if (aclnode->z_ace_count == 0)
12980a586ceaSMark Shellenbaum continue;
12990a586ceaSMark Shellenbaum dmu_write(zfsvfs->z_os, aoid, off,
13000a586ceaSMark Shellenbaum aclnode->z_size, aclnode->z_acldata, tx);
13010a586ceaSMark Shellenbaum off += aclnode->z_size;
13020a586ceaSMark Shellenbaum }
1303fa9e4066Sahrens } else {
13040a586ceaSMark Shellenbaum void *start = acl_phys.z_ace_data;
13050a586ceaSMark Shellenbaum /*
13060a586ceaSMark Shellenbaum * Migrating back embedded?
13070a586ceaSMark Shellenbaum */
13080a586ceaSMark Shellenbaum if (acl_phys.z_acl_extern_obj) {
13090a586ceaSMark Shellenbaum error = dmu_object_free(zfsvfs->z_os,
13100a586ceaSMark Shellenbaum acl_phys.z_acl_extern_obj, tx);
13110a586ceaSMark Shellenbaum if (error)
13120a586ceaSMark Shellenbaum return (error);
13130a586ceaSMark Shellenbaum acl_phys.z_acl_extern_obj = 0;
13140a586ceaSMark Shellenbaum }
13150a586ceaSMark Shellenbaum
13160a586ceaSMark Shellenbaum for (aclnode = list_head(&aclp->z_acl); aclnode;
13170a586ceaSMark Shellenbaum aclnode = list_next(&aclp->z_acl, aclnode)) {
13180a586ceaSMark Shellenbaum if (aclnode->z_ace_count == 0)
13190a586ceaSMark Shellenbaum continue;
13200a586ceaSMark Shellenbaum bcopy(aclnode->z_acldata, start,
13210a586ceaSMark Shellenbaum aclnode->z_size);
13220a586ceaSMark Shellenbaum start = (caddr_t)start + aclnode->z_size;
13230a586ceaSMark Shellenbaum }
1324da6c28aaSamw }
1325fa9e4066Sahrens /*
13260a586ceaSMark Shellenbaum * If Old version then swap count/bytes to match old
13270a586ceaSMark Shellenbaum * layout of znode_acl_phys_t.
1328fa9e4066Sahrens */
13290a586ceaSMark Shellenbaum if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) {
13300a586ceaSMark Shellenbaum acl_phys.z_acl_size = aclp->z_acl_count;
13310a586ceaSMark Shellenbaum acl_phys.z_acl_count = aclp->z_acl_bytes;
13320a586ceaSMark Shellenbaum } else {
13330a586ceaSMark Shellenbaum acl_phys.z_acl_size = aclp->z_acl_bytes;
13340a586ceaSMark Shellenbaum acl_phys.z_acl_count = aclp->z_acl_count;
1335da6c28aaSamw }
13360a586ceaSMark Shellenbaum acl_phys.z_acl_version = aclp->z_version;
1337de122929Smarks
13380a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ZNODE_ACL(zfsvfs), NULL,
13390a586ceaSMark Shellenbaum &acl_phys, sizeof (acl_phys));
1340de122929Smarks }
1341fa9e4066Sahrens
1342da6c28aaSamw /*
1343da6c28aaSamw * Replace ACL wide bits, but first clear them.
1344da6c28aaSamw */
13450a586ceaSMark Shellenbaum zp->z_pflags &= ~ZFS_ACL_WIDE_FLAGS;
1346da6c28aaSamw
13470a586ceaSMark Shellenbaum zp->z_pflags |= aclp->z_hints;
1348fa9e4066Sahrens
1349*06799660SGordon Ross zai.zai_aclp = aclp;
1350*06799660SGordon Ross if (ace_trivial_common(&zai, 0, zfs_ace_walk) == 0)
13510a586ceaSMark Shellenbaum zp->z_pflags |= ZFS_ACL_TRIVIAL;
1352da6c28aaSamw
13530a586ceaSMark Shellenbaum zfs_tstamp_update_setup(zp, STATE_CHANGED, NULL, ctime, B_TRUE);
13540a586ceaSMark Shellenbaum return (sa_bulk_update(zp->z_sa_hdl, bulk, count, tx));
1355fa9e4066Sahrens }
1356fa9e4066Sahrens
1357fa9e4066Sahrens static void
zfs_acl_chmod(vtype_t vtype,uint64_t mode,boolean_t split,boolean_t trim,zfs_acl_t * aclp)1358de0f1ddbSAlbert Lee zfs_acl_chmod(vtype_t vtype, uint64_t mode, boolean_t split, boolean_t trim,
1359de0f1ddbSAlbert Lee zfs_acl_t *aclp)
1360fa9e4066Sahrens {
136127dd1e87SMark Shellenbaum void *acep = NULL;
1362da6c28aaSamw uint64_t who;
136327dd1e87SMark Shellenbaum int new_count, new_bytes;
136427dd1e87SMark Shellenbaum int ace_size;
136554811da5SToomas Soome int entry_type;
1366da6c28aaSamw uint16_t iflags, type;
1367da6c28aaSamw uint32_t access_mask;
136827dd1e87SMark Shellenbaum zfs_acl_node_t *newnode;
136954811da5SToomas Soome size_t abstract_size = aclp->z_ops.ace_abstract_size();
137054811da5SToomas Soome void *zacep;
1371a3c49ce1SAlbert Lee boolean_t isdir;
1372a3c49ce1SAlbert Lee trivial_acl_t masks;
1373*06799660SGordon Ross zfs_acl_iter_t zai = {0};
137427dd1e87SMark Shellenbaum
137527dd1e87SMark Shellenbaum new_count = new_bytes = 0;
137627dd1e87SMark Shellenbaum
1377a3c49ce1SAlbert Lee isdir = (vtype == VDIR);
1378a3c49ce1SAlbert Lee
1379a3c49ce1SAlbert Lee acl_trivial_access_masks((mode_t)mode, isdir, &masks);
138027dd1e87SMark Shellenbaum
138127dd1e87SMark Shellenbaum newnode = zfs_acl_node_alloc((abstract_size * 6) + aclp->z_acl_bytes);
138227dd1e87SMark Shellenbaum
138327dd1e87SMark Shellenbaum zacep = newnode->z_acldata;
1384a3c49ce1SAlbert Lee if (masks.allow0) {
1385a3c49ce1SAlbert Lee zfs_set_ace(aclp, zacep, masks.allow0, ALLOW, -1, ACE_OWNER);
138627dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size);
138727dd1e87SMark Shellenbaum new_count++;
138827dd1e87SMark Shellenbaum new_bytes += abstract_size;
1389f7170741SWill Andrews }
1390f7170741SWill Andrews if (masks.deny1) {
1391a3c49ce1SAlbert Lee zfs_set_ace(aclp, zacep, masks.deny1, DENY, -1, ACE_OWNER);
139227dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size);
139327dd1e87SMark Shellenbaum new_count++;
139427dd1e87SMark Shellenbaum new_bytes += abstract_size;
139527dd1e87SMark Shellenbaum }
1396a3c49ce1SAlbert Lee if (masks.deny2) {
1397a3c49ce1SAlbert Lee zfs_set_ace(aclp, zacep, masks.deny2, DENY, -1, OWNING_GROUP);
139827dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size);
139927dd1e87SMark Shellenbaum new_count++;
140027dd1e87SMark Shellenbaum new_bytes += abstract_size;
140127dd1e87SMark Shellenbaum }
14022459a9eaSmarks
1403*06799660SGordon Ross zai.zai_aclp = aclp;
1404*06799660SGordon Ross while (acep = zfs_acl_next_ace(&zai, acep, &who, &access_mask,
1405da6c28aaSamw &iflags, &type)) {
1406da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS);
1407de0f1ddbSAlbert Lee /*
1408de0f1ddbSAlbert Lee * ACEs used to represent the file mode may be divided
1409de0f1ddbSAlbert Lee * into an equivalent pair of inherit-only and regular
1410de0f1ddbSAlbert Lee * ACEs, if they are inheritable.
1411de0f1ddbSAlbert Lee * Skip regular ACEs, which are replaced by the new mode.
1412de0f1ddbSAlbert Lee */
1413de0f1ddbSAlbert Lee if (split && (entry_type == ACE_OWNER ||
1414de0f1ddbSAlbert Lee entry_type == OWNING_GROUP ||
1415de0f1ddbSAlbert Lee entry_type == ACE_EVERYONE)) {
1416de0f1ddbSAlbert Lee if (!isdir || !(iflags &
1417de0f1ddbSAlbert Lee (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE)))
1418de0f1ddbSAlbert Lee continue;
1419de0f1ddbSAlbert Lee /*
1420de0f1ddbSAlbert Lee * We preserve owner@, group@, or @everyone
1421de0f1ddbSAlbert Lee * permissions, if they are inheritable, by
1422de0f1ddbSAlbert Lee * copying them to inherit_only ACEs. This
1423de0f1ddbSAlbert Lee * prevents inheritable permissions from being
1424de0f1ddbSAlbert Lee * altered along with the file mode.
1425de0f1ddbSAlbert Lee */
1426de0f1ddbSAlbert Lee iflags |= ACE_INHERIT_ONLY_ACE;
142727dd1e87SMark Shellenbaum }
1428da6c28aaSamw
1429a3c49ce1SAlbert Lee /*
1430a3c49ce1SAlbert Lee * If this ACL has any inheritable ACEs, mark that in
1431a3c49ce1SAlbert Lee * the hints (which are later masked into the pflags)
1432a3c49ce1SAlbert Lee * so create knows to do inheritance.
1433a3c49ce1SAlbert Lee */
1434de0f1ddbSAlbert Lee if (isdir && (iflags &
1435a3c49ce1SAlbert Lee (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE)))
1436a3c49ce1SAlbert Lee aclp->z_hints |= ZFS_INHERIT_ACE;
1437a3c49ce1SAlbert Lee
1438da6c28aaSamw if ((type != ALLOW && type != DENY) ||
1439de0f1ddbSAlbert Lee (iflags & ACE_INHERIT_ONLY_ACE)) {
1440da6c28aaSamw switch (type) {
1441da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
1442da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
1443da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
1444da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
1445da6c28aaSamw aclp->z_hints |= ZFS_ACL_OBJ_ACE;
1446da6c28aaSamw break;
1447da6c28aaSamw }
1448fa9e4066Sahrens } else {
144927dd1e87SMark Shellenbaum /*
1450851632d6SAlbert Lee * Limit permissions granted by ACEs to be no greater
1451851632d6SAlbert Lee * than permissions of the requested group mode.
1452851632d6SAlbert Lee * Applies when the "aclmode" property is set to
1453851632d6SAlbert Lee * "groupmask".
145427dd1e87SMark Shellenbaum */
1455a3c49ce1SAlbert Lee if ((type == ALLOW) && trim)
1456a3c49ce1SAlbert Lee access_mask &= masks.group;
1457fa9e4066Sahrens }
145827dd1e87SMark Shellenbaum zfs_set_ace(aclp, zacep, access_mask, type, who, iflags);
145927dd1e87SMark Shellenbaum ace_size = aclp->z_ops.ace_size(acep);
146027dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + ace_size);
146127dd1e87SMark Shellenbaum new_count++;
146227dd1e87SMark Shellenbaum new_bytes += ace_size;
1463fa9e4066Sahrens }
1464de0f1ddbSAlbert Lee zfs_set_ace(aclp, zacep, masks.owner, ALLOW, -1, ACE_OWNER);
146527dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size);
1466de0f1ddbSAlbert Lee zfs_set_ace(aclp, zacep, masks.group, ALLOW, -1, OWNING_GROUP);
146727dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size);
1468de0f1ddbSAlbert Lee zfs_set_ace(aclp, zacep, masks.everyone, ALLOW, -1, ACE_EVERYONE);
146927dd1e87SMark Shellenbaum
147027dd1e87SMark Shellenbaum new_count += 3;
147127dd1e87SMark Shellenbaum new_bytes += abstract_size * 3;
147227dd1e87SMark Shellenbaum zfs_acl_release_nodes(aclp);
147327dd1e87SMark Shellenbaum aclp->z_acl_count = new_count;
147427dd1e87SMark Shellenbaum aclp->z_acl_bytes = new_bytes;
147527dd1e87SMark Shellenbaum newnode->z_ace_count = new_count;
147627dd1e87SMark Shellenbaum newnode->z_size = new_bytes;
147727dd1e87SMark Shellenbaum list_insert_tail(&aclp->z_acl, newnode);
1478fa9e4066Sahrens }
1479fa9e4066Sahrens
1480a3c49ce1SAlbert Lee int
zfs_acl_chmod_setattr(znode_t * zp,zfs_acl_t ** aclp,uint64_t mode)14814c841f60Smarks zfs_acl_chmod_setattr(znode_t *zp, zfs_acl_t **aclp, uint64_t mode)
1482fa9e4066Sahrens {
1483a3c49ce1SAlbert Lee int error = 0;
1484a3c49ce1SAlbert Lee
1485*06799660SGordon Ross rw_enter(&zp->z_acl_lock, RW_WRITER);
14861412a1a2SMark Shellenbaum mutex_enter(&zp->z_lock);
1487a3c49ce1SAlbert Lee if (zp->z_zfsvfs->z_acl_mode == ZFS_ACL_DISCARD)
1488a3c49ce1SAlbert Lee *aclp = zfs_acl_alloc(zfs_acl_version_zp(zp));
1489a3c49ce1SAlbert Lee else
1490a3c49ce1SAlbert Lee error = zfs_acl_node_read(zp, B_TRUE, aclp, B_TRUE);
1491a3c49ce1SAlbert Lee
1492a3c49ce1SAlbert Lee if (error == 0) {
1493a3c49ce1SAlbert Lee (*aclp)->z_hints = zp->z_pflags & V4_ACL_WIDE_FLAGS;
1494de0f1ddbSAlbert Lee zfs_acl_chmod(ZTOV(zp)->v_type, mode, B_TRUE,
1495a3c49ce1SAlbert Lee (zp->z_zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK), *aclp);
1496a3c49ce1SAlbert Lee }
14974c841f60Smarks mutex_exit(&zp->z_lock);
1498*06799660SGordon Ross rw_exit(&zp->z_acl_lock);
1499a3c49ce1SAlbert Lee
1500a3c49ce1SAlbert Lee return (error);
1501fa9e4066Sahrens }
1502fa9e4066Sahrens
1503da6c28aaSamw /*
1504da6c28aaSamw * Should ACE be inherited?
1505da6c28aaSamw */
1506da6c28aaSamw static int
zfs_ace_can_use(vtype_t vtype,uint16_t acep_flags)150789459e17SMark Shellenbaum zfs_ace_can_use(vtype_t vtype, uint16_t acep_flags)
1508da6c28aaSamw {
1509da6c28aaSamw int iflags = (acep_flags & 0xf);
1510da6c28aaSamw
1511da6c28aaSamw if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE))
1512da6c28aaSamw return (1);
1513da6c28aaSamw else if (iflags & ACE_FILE_INHERIT_ACE)
1514da6c28aaSamw return (!((vtype == VDIR) &&
1515da6c28aaSamw (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)));
1516da6c28aaSamw return (0);
1517fa9e4066Sahrens }
1518fa9e4066Sahrens
1519fa9e4066Sahrens /*
1520fa9e4066Sahrens * inherit inheritable ACEs from parent
1521fa9e4066Sahrens */
1522fa9e4066Sahrens static zfs_acl_t *
zfs_acl_inherit(zfsvfs_t * zfsvfs,vtype_t vtype,zfs_acl_t * paclp,uint64_t mode,boolean_t * need_chmod)152389459e17SMark Shellenbaum zfs_acl_inherit(zfsvfs_t *zfsvfs, vtype_t vtype, zfs_acl_t *paclp,
1524e9bacc6dSDominik Hassler uint64_t mode, boolean_t *need_chmod)
1525fa9e4066Sahrens {
1526de0f1ddbSAlbert Lee void *pacep = NULL;
152727dd1e87SMark Shellenbaum void *acep;
152827dd1e87SMark Shellenbaum zfs_acl_node_t *aclnode;
1529fa9e4066Sahrens zfs_acl_t *aclp = NULL;
1530da6c28aaSamw uint64_t who;
1531da6c28aaSamw uint32_t access_mask;
1532da6c28aaSamw uint16_t iflags, newflags, type;
1533da6c28aaSamw size_t ace_size;
1534da6c28aaSamw void *data1, *data2;
1535da6c28aaSamw size_t data1sz, data2sz;
1536de0f1ddbSAlbert Lee uint_t aclinherit;
1537de0f1ddbSAlbert Lee boolean_t isdir = (vtype == VDIR);
1538e9bacc6dSDominik Hassler boolean_t isreg = (vtype == VREG);
1539*06799660SGordon Ross zfs_acl_iter_t zai = {0};
1540e9bacc6dSDominik Hassler
1541e9bacc6dSDominik Hassler *need_chmod = B_TRUE;
1542de0f1ddbSAlbert Lee
1543003c2582SMark Shellenbaum aclp = zfs_acl_alloc(paclp->z_version);
1544de0f1ddbSAlbert Lee aclinherit = zfsvfs->z_acl_inherit;
1545de0f1ddbSAlbert Lee if (aclinherit == ZFS_ACL_DISCARD || vtype == VLNK)
1546d0f3f37eSMark Shellenbaum return (aclp);
1547de0f1ddbSAlbert Lee
1548*06799660SGordon Ross zai.zai_aclp = paclp;
1549*06799660SGordon Ross while (pacep = zfs_acl_next_ace(&zai, pacep, &who,
1550d0f3f37eSMark Shellenbaum &access_mask, &iflags, &type)) {
1551fa9e4066Sahrens
1552d0f3f37eSMark Shellenbaum /*
1553d0f3f37eSMark Shellenbaum * don't inherit bogus ACEs
1554d0f3f37eSMark Shellenbaum */
1555d0f3f37eSMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags))
1556d0f3f37eSMark Shellenbaum continue;
1557003c2582SMark Shellenbaum
1558de0f1ddbSAlbert Lee /*
1559de0f1ddbSAlbert Lee * Check if ACE is inheritable by this vnode
1560de0f1ddbSAlbert Lee */
1561de0f1ddbSAlbert Lee if ((aclinherit == ZFS_ACL_NOALLOW && type == ALLOW) ||
1562de0f1ddbSAlbert Lee !zfs_ace_can_use(vtype, iflags))
1563d0f3f37eSMark Shellenbaum continue;
1564b3d141f8Smarks
1565e9bacc6dSDominik Hassler /*
1566e9bacc6dSDominik Hassler * If owner@, group@, or everyone@ inheritable
1567e9bacc6dSDominik Hassler * then zfs_acl_chmod() isn't needed.
1568e9bacc6dSDominik Hassler */
1569e9bacc6dSDominik Hassler if ((aclinherit == ZFS_ACL_PASSTHROUGH ||
1570e9bacc6dSDominik Hassler aclinherit == ZFS_ACL_PASSTHROUGH_X) &&
1571e9bacc6dSDominik Hassler ((iflags & (ACE_OWNER|ACE_EVERYONE)) ||
1572e9bacc6dSDominik Hassler ((iflags & OWNING_GROUP) == OWNING_GROUP)) &&
1573e9bacc6dSDominik Hassler (isreg || (isdir && (iflags & ACE_DIRECTORY_INHERIT_ACE))))
1574e9bacc6dSDominik Hassler *need_chmod = B_FALSE;
1575e9bacc6dSDominik Hassler
1576d0f3f37eSMark Shellenbaum /*
1577de0f1ddbSAlbert Lee * Strip inherited execute permission from file if
1578de0f1ddbSAlbert Lee * not in mode
1579d0f3f37eSMark Shellenbaum */
1580de0f1ddbSAlbert Lee if (aclinherit == ZFS_ACL_PASSTHROUGH_X && type == ALLOW &&
1581de0f1ddbSAlbert Lee !isdir && ((mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0)) {
1582de0f1ddbSAlbert Lee access_mask &= ~ACE_EXECUTE;
1583c694df91SMark Shellenbaum }
1584d0f3f37eSMark Shellenbaum
1585de0f1ddbSAlbert Lee /*
1586de0f1ddbSAlbert Lee * Strip write_acl and write_owner from permissions
1587de0f1ddbSAlbert Lee * when inheriting an ACE
1588de0f1ddbSAlbert Lee */
1589de0f1ddbSAlbert Lee if (aclinherit == ZFS_ACL_RESTRICTED && type == ALLOW) {
1590de0f1ddbSAlbert Lee access_mask &= ~RESTRICTED_CLEAR;
1591d0f3f37eSMark Shellenbaum }
1592d0f3f37eSMark Shellenbaum
1593de0f1ddbSAlbert Lee ace_size = aclp->z_ops.ace_size(pacep);
1594d0f3f37eSMark Shellenbaum aclnode = zfs_acl_node_alloc(ace_size);
1595d0f3f37eSMark Shellenbaum list_insert_tail(&aclp->z_acl, aclnode);
1596d0f3f37eSMark Shellenbaum acep = aclnode->z_acldata;
1597d0f3f37eSMark Shellenbaum
1598d0f3f37eSMark Shellenbaum zfs_set_ace(aclp, acep, access_mask, type,
1599d0f3f37eSMark Shellenbaum who, iflags|ACE_INHERITED_ACE);
1600d0f3f37eSMark Shellenbaum
1601d0f3f37eSMark Shellenbaum /*
1602d0f3f37eSMark Shellenbaum * Copy special opaque data if any
1603d0f3f37eSMark Shellenbaum */
1604d0f3f37eSMark Shellenbaum if ((data1sz = paclp->z_ops.ace_data(pacep, &data1)) != 0) {
1605d0f3f37eSMark Shellenbaum VERIFY((data2sz = aclp->z_ops.ace_data(acep,
1606d0f3f37eSMark Shellenbaum &data2)) == data1sz);
1607d0f3f37eSMark Shellenbaum bcopy(data1, data2, data2sz);
1608d0f3f37eSMark Shellenbaum }
160927dd1e87SMark Shellenbaum
1610d0f3f37eSMark Shellenbaum aclp->z_acl_count++;
1611d0f3f37eSMark Shellenbaum aclnode->z_ace_count++;
1612d0f3f37eSMark Shellenbaum aclp->z_acl_bytes += aclnode->z_size;
1613d0f3f37eSMark Shellenbaum newflags = aclp->z_ops.ace_flags_get(acep);
1614d0f3f37eSMark Shellenbaum
1615de0f1ddbSAlbert Lee /*
1616de0f1ddbSAlbert Lee * If ACE is not to be inherited further, or if the vnode is
1617de0f1ddbSAlbert Lee * not a directory, remove all inheritance flags
1618de0f1ddbSAlbert Lee */
1619de0f1ddbSAlbert Lee if (!isdir || (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)) {
1620d0f3f37eSMark Shellenbaum newflags &= ~ALL_INHERIT;
1621d0f3f37eSMark Shellenbaum aclp->z_ops.ace_flags_set(acep,
1622d0f3f37eSMark Shellenbaum newflags|ACE_INHERITED_ACE);
1623d0f3f37eSMark Shellenbaum continue;
1624d0f3f37eSMark Shellenbaum }
1625d0f3f37eSMark Shellenbaum
1626de0f1ddbSAlbert Lee /*
1627de0f1ddbSAlbert Lee * This directory has an inheritable ACE
1628de0f1ddbSAlbert Lee */
1629de0f1ddbSAlbert Lee aclp->z_hints |= ZFS_INHERIT_ACE;
1630d0f3f37eSMark Shellenbaum
163127dd1e87SMark Shellenbaum /*
163227dd1e87SMark Shellenbaum * If only FILE_INHERIT is set then turn on
163327dd1e87SMark Shellenbaum * inherit_only
163427dd1e87SMark Shellenbaum */
1635d0f3f37eSMark Shellenbaum if ((iflags & (ACE_FILE_INHERIT_ACE |
1636485adf61SMark Shellenbaum ACE_DIRECTORY_INHERIT_ACE)) == ACE_FILE_INHERIT_ACE) {
1637d0f3f37eSMark Shellenbaum newflags |= ACE_INHERIT_ONLY_ACE;
1638d0f3f37eSMark Shellenbaum aclp->z_ops.ace_flags_set(acep,
1639d0f3f37eSMark Shellenbaum newflags|ACE_INHERITED_ACE);
1640485adf61SMark Shellenbaum } else {
1641485adf61SMark Shellenbaum newflags &= ~ACE_INHERIT_ONLY_ACE;
1642485adf61SMark Shellenbaum aclp->z_ops.ace_flags_set(acep,
1643485adf61SMark Shellenbaum newflags|ACE_INHERITED_ACE);
1644fa9e4066Sahrens }
1645fa9e4066Sahrens }
1646de0f1ddbSAlbert Lee
1647fa9e4066Sahrens return (aclp);
1648fa9e4066Sahrens }
1649fa9e4066Sahrens
1650fa9e4066Sahrens /*
1651fa9e4066Sahrens * Create file system object initial permissions
1652fa9e4066Sahrens * including inheritable ACEs.
1653de0f1ddbSAlbert Lee * Also, create FUIDs for owner and group.
1654fa9e4066Sahrens */
165589459e17SMark Shellenbaum int
zfs_acl_ids_create(znode_t * dzp,int flag,vattr_t * vap,cred_t * cr,vsecattr_t * vsecp,zfs_acl_ids_t * acl_ids)165689459e17SMark Shellenbaum zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
165789459e17SMark Shellenbaum vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids)
1658fa9e4066Sahrens {
1659fa9e4066Sahrens int error;
166089459e17SMark Shellenbaum zfsvfs_t *zfsvfs = dzp->z_zfsvfs;
1661da6c28aaSamw zfs_acl_t *paclp;
1662e0d35c44Smarks gid_t gid;
1663e9bacc6dSDominik Hassler boolean_t need_chmod = B_TRUE;
1664de0f1ddbSAlbert Lee boolean_t trim = B_FALSE;
16650a586ceaSMark Shellenbaum boolean_t inherited = B_FALSE;
1666da6c28aaSamw
166789459e17SMark Shellenbaum bzero(acl_ids, sizeof (zfs_acl_ids_t));
166889459e17SMark Shellenbaum acl_ids->z_mode = MAKEIMODE(vap->va_type, vap->va_mode);
1669fa9e4066Sahrens
167089459e17SMark Shellenbaum if (vsecp)
167189459e17SMark Shellenbaum if ((error = zfs_vsec_2_aclp(zfsvfs, vap->va_type, vsecp, cr,
167289459e17SMark Shellenbaum &acl_ids->z_fuidp, &acl_ids->z_aclp)) != 0)
167389459e17SMark Shellenbaum return (error);
1674fa9e4066Sahrens /*
1675fa9e4066Sahrens * Determine uid and gid.
1676fa9e4066Sahrens */
16774a1f0cc9SMark Shellenbaum if ((flag & IS_ROOT_NODE) || zfsvfs->z_replay ||
1678fa9e4066Sahrens ((flag & IS_XATTR) && (vap->va_type == VDIR))) {
167989459e17SMark Shellenbaum acl_ids->z_fuid = zfs_fuid_create(zfsvfs,
168089459e17SMark Shellenbaum (uint64_t)vap->va_uid, cr,
168189459e17SMark Shellenbaum ZFS_OWNER, &acl_ids->z_fuidp);
168289459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create(zfsvfs,
168389459e17SMark Shellenbaum (uint64_t)vap->va_gid, cr,
168489459e17SMark Shellenbaum ZFS_GROUP, &acl_ids->z_fuidp);
1685e0d35c44Smarks gid = vap->va_gid;
1686fa9e4066Sahrens } else {
168789459e17SMark Shellenbaum acl_ids->z_fuid = zfs_fuid_create_cred(zfsvfs, ZFS_OWNER,
168889459e17SMark Shellenbaum cr, &acl_ids->z_fuidp);
168989459e17SMark Shellenbaum acl_ids->z_fgid = 0;
1690e0d35c44Smarks if (vap->va_mask & AT_GID) {
169189459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create(zfsvfs,
169289459e17SMark Shellenbaum (uint64_t)vap->va_gid,
169389459e17SMark Shellenbaum cr, ZFS_GROUP, &acl_ids->z_fuidp);
1694e0d35c44Smarks gid = vap->va_gid;
1695f1696b23SMark Shellenbaum if (acl_ids->z_fgid != dzp->z_gid &&
1696e0d35c44Smarks !groupmember(vap->va_gid, cr) &&
1697e0d35c44Smarks secpolicy_vnode_create_gid(cr) != 0)
169889459e17SMark Shellenbaum acl_ids->z_fgid = 0;
1699e0d35c44Smarks }
170089459e17SMark Shellenbaum if (acl_ids->z_fgid == 0) {
17010a586ceaSMark Shellenbaum if (dzp->z_mode & S_ISGID) {
1702b3874165SJohn Harres char *domain;
1703b3874165SJohn Harres uint32_t rid;
1704b3874165SJohn Harres
1705f1696b23SMark Shellenbaum acl_ids->z_fgid = dzp->z_gid;
170689459e17SMark Shellenbaum gid = zfs_fuid_map_id(zfsvfs, acl_ids->z_fgid,
1707e0d35c44Smarks cr, ZFS_GROUP);
1708b3874165SJohn Harres
1709b3874165SJohn Harres if (zfsvfs->z_use_fuids &&
1710b3874165SJohn Harres IS_EPHEMERAL(acl_ids->z_fgid)) {
1711b3874165SJohn Harres domain = zfs_fuid_idx_domain(
1712b3874165SJohn Harres &zfsvfs->z_fuid_idx,
1713b3874165SJohn Harres FUID_INDEX(acl_ids->z_fgid));
1714b3874165SJohn Harres rid = FUID_RID(acl_ids->z_fgid);
1715b3874165SJohn Harres zfs_fuid_node_add(&acl_ids->z_fuidp,
1716b3874165SJohn Harres domain, rid,
1717b3874165SJohn Harres FUID_INDEX(acl_ids->z_fgid),
1718b3874165SJohn Harres acl_ids->z_fgid, ZFS_GROUP);
1719b3874165SJohn Harres }
1720e0d35c44Smarks } else {
172189459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create_cred(zfsvfs,
172289459e17SMark Shellenbaum ZFS_GROUP, cr, &acl_ids->z_fuidp);
1723e0d35c44Smarks gid = crgetgid(cr);
1724e0d35c44Smarks }
1725da6c28aaSamw }
1726fa9e4066Sahrens }
1727fa9e4066Sahrens
1728fa9e4066Sahrens /*
1729fa9e4066Sahrens * If we're creating a directory, and the parent directory has the
1730fa9e4066Sahrens * set-GID bit set, set in on the new directory.
1731fa9e4066Sahrens * Otherwise, if the user is neither privileged nor a member of the
1732fa9e4066Sahrens * file's new group, clear the file's set-GID bit.
1733fa9e4066Sahrens */
1734fa9e4066Sahrens
17350a586ceaSMark Shellenbaum if (!(flag & IS_ROOT_NODE) && (dzp->z_mode & S_ISGID) &&
173689459e17SMark Shellenbaum (vap->va_type == VDIR)) {
173789459e17SMark Shellenbaum acl_ids->z_mode |= S_ISGID;
1738e0d35c44Smarks } else {
173989459e17SMark Shellenbaum if ((acl_ids->z_mode & S_ISGID) &&
1740fa9e4066Sahrens secpolicy_vnode_setids_setgids(cr, gid) != 0)
174189459e17SMark Shellenbaum acl_ids->z_mode &= ~S_ISGID;
1742fa9e4066Sahrens }
1743fa9e4066Sahrens
174489459e17SMark Shellenbaum if (acl_ids->z_aclp == NULL) {
1745*06799660SGordon Ross rw_enter(&dzp->z_acl_lock, RW_WRITER);
174689459e17SMark Shellenbaum mutex_enter(&dzp->z_lock);
1747a3c49ce1SAlbert Lee if (!(flag & IS_ROOT_NODE) &&
1748a3c49ce1SAlbert Lee (dzp->z_pflags & ZFS_INHERIT_ACE) &&
17490a586ceaSMark Shellenbaum !(dzp->z_pflags & ZFS_XATTR)) {
17501412a1a2SMark Shellenbaum VERIFY(0 == zfs_acl_node_read(dzp, B_TRUE,
17511412a1a2SMark Shellenbaum &paclp, B_FALSE));
175289459e17SMark Shellenbaum acl_ids->z_aclp = zfs_acl_inherit(zfsvfs,
1753e9bacc6dSDominik Hassler vap->va_type, paclp, acl_ids->z_mode, &need_chmod);
17540a586ceaSMark Shellenbaum inherited = B_TRUE;
1755da6c28aaSamw } else {
175689459e17SMark Shellenbaum acl_ids->z_aclp =
175789459e17SMark Shellenbaum zfs_acl_alloc(zfs_acl_version_zp(dzp));
17580a586ceaSMark Shellenbaum acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL;
175989459e17SMark Shellenbaum }
176089459e17SMark Shellenbaum mutex_exit(&dzp->z_lock);
1761*06799660SGordon Ross rw_exit(&dzp->z_acl_lock);
1762de0f1ddbSAlbert Lee
1763e9bacc6dSDominik Hassler if (need_chmod) {
1764e9bacc6dSDominik Hassler if (vap->va_type == VDIR)
1765e9bacc6dSDominik Hassler acl_ids->z_aclp->z_hints |=
1766e9bacc6dSDominik Hassler ZFS_ACL_AUTO_INHERIT;
1767e9bacc6dSDominik Hassler
1768e9bacc6dSDominik Hassler if (zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK &&
1769e9bacc6dSDominik Hassler zfsvfs->z_acl_inherit != ZFS_ACL_PASSTHROUGH &&
1770e9bacc6dSDominik Hassler zfsvfs->z_acl_inherit != ZFS_ACL_PASSTHROUGH_X)
1771e9bacc6dSDominik Hassler trim = B_TRUE;
1772e9bacc6dSDominik Hassler zfs_acl_chmod(vap->va_type, acl_ids->z_mode, B_FALSE,
1773e9bacc6dSDominik Hassler trim, acl_ids->z_aclp);
1774e9bacc6dSDominik Hassler }
1775fa9e4066Sahrens }
1776da6c28aaSamw
17770a586ceaSMark Shellenbaum if (inherited || vsecp) {
1778*06799660SGordon Ross zfs_acl_iter_t zai = {0};
1779*06799660SGordon Ross
17800a586ceaSMark Shellenbaum acl_ids->z_mode = zfs_mode_compute(acl_ids->z_mode,
178127dd1e87SMark Shellenbaum acl_ids->z_aclp, &acl_ids->z_aclp->z_hints,
178227dd1e87SMark Shellenbaum acl_ids->z_fuid, acl_ids->z_fgid);
1783*06799660SGordon Ross
1784*06799660SGordon Ross zai.zai_aclp = acl_ids->z_aclp;
1785*06799660SGordon Ross if (ace_trivial_common(&zai, 0, zfs_ace_walk) == 0)
17860a586ceaSMark Shellenbaum acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL;
17870a586ceaSMark Shellenbaum }
17880a586ceaSMark Shellenbaum
178989459e17SMark Shellenbaum return (0);
179089459e17SMark Shellenbaum }
1791fa9e4066Sahrens
179289459e17SMark Shellenbaum /*
179389459e17SMark Shellenbaum * Free ACL and fuid_infop, but not the acl_ids structure
179489459e17SMark Shellenbaum */
179589459e17SMark Shellenbaum void
zfs_acl_ids_free(zfs_acl_ids_t * acl_ids)179689459e17SMark Shellenbaum zfs_acl_ids_free(zfs_acl_ids_t *acl_ids)
179789459e17SMark Shellenbaum {
179889459e17SMark Shellenbaum if (acl_ids->z_aclp)
179989459e17SMark Shellenbaum zfs_acl_free(acl_ids->z_aclp);
180089459e17SMark Shellenbaum if (acl_ids->z_fuidp)
180189459e17SMark Shellenbaum zfs_fuid_info_free(acl_ids->z_fuidp);
180289459e17SMark Shellenbaum acl_ids->z_aclp = NULL;
180389459e17SMark Shellenbaum acl_ids->z_fuidp = NULL;
1804fa9e4066Sahrens }
1805fa9e4066Sahrens
180614843421SMatthew Ahrens boolean_t
zfs_acl_ids_overquota(zfsvfs_t * zv,zfs_acl_ids_t * acl_ids,uint64_t projid)1807f67950b2SNasf-Fan zfs_acl_ids_overquota(zfsvfs_t *zv, zfs_acl_ids_t *acl_ids, uint64_t projid)
180814843421SMatthew Ahrens {
1809f67950b2SNasf-Fan return (zfs_id_overquota(zv, DMU_USERUSED_OBJECT, acl_ids->z_fuid) ||
1810f67950b2SNasf-Fan zfs_id_overquota(zv, DMU_GROUPUSED_OBJECT, acl_ids->z_fgid) ||
1811f67950b2SNasf-Fan (projid != ZFS_DEFAULT_PROJID && projid != ZFS_INVALID_PROJID &&
1812f67950b2SNasf-Fan zfs_id_overquota(zv, DMU_PROJECTUSED_OBJECT, projid)));
181314843421SMatthew Ahrens }
181489459e17SMark Shellenbaum
1815fa9e4066Sahrens /*
1816f7170741SWill Andrews * Retrieve a file's ACL
1817fa9e4066Sahrens */
1818fa9e4066Sahrens int
zfs_getacl(znode_t * zp,vsecattr_t * vsecp,boolean_t skipaclchk,cred_t * cr)1819da6c28aaSamw zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
1820fa9e4066Sahrens {
1821fa9e4066Sahrens zfs_acl_t *aclp;
1822da6c28aaSamw ulong_t mask;
1823fa9e4066Sahrens int error;
182454811da5SToomas Soome int count = 0;
1825da6c28aaSamw int largeace = 0;
1826fa9e4066Sahrens
1827da6c28aaSamw mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT |
1828da6c28aaSamw VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
1829da6c28aaSamw
1830fa9e4066Sahrens if (mask == 0)
1831be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS));
1832fa9e4066Sahrens
18330a586ceaSMark Shellenbaum if (error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr))
18340a586ceaSMark Shellenbaum return (error);
18350a586ceaSMark Shellenbaum
1836*06799660SGordon Ross /*
1837*06799660SGordon Ross * This may be frequently called, so when possible
1838*06799660SGordon Ross * try to avoid entering z_acl_lock as writer.
1839*06799660SGordon Ross */
1840*06799660SGordon Ross rw_enter(&zp->z_acl_lock, RW_READER);
1841*06799660SGordon Ross aclp = zp->z_acl_cached;
1842*06799660SGordon Ross if (aclp == NULL) {
1843*06799660SGordon Ross /*
1844*06799660SGordon Ross * OK, need WRITER to load the ACL. Note:
1845*06799660SGordon Ross * zfs_acl_node_read() re-checks zp->z_acl_cached
1846*06799660SGordon Ross * and just returns if it's set.
1847*06799660SGordon Ross */
1848*06799660SGordon Ross rw_exit(&zp->z_acl_lock);
1849*06799660SGordon Ross rw_enter(&zp->z_acl_lock, RW_WRITER);
1850fa9e4066Sahrens
1851*06799660SGordon Ross error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE);
1852*06799660SGordon Ross if (error != 0) {
1853*06799660SGordon Ross rw_exit(&zp->z_acl_lock);
1854*06799660SGordon Ross return (error);
1855*06799660SGordon Ross }
1856*06799660SGordon Ross rw_downgrade(&zp->z_acl_lock); /* now RW_READER */
1857*06799660SGordon Ross ASSERT(zp->z_acl_cached);
1858ea8dc4b6Seschrock }
1859ea8dc4b6Seschrock
1860da6c28aaSamw /*
1861da6c28aaSamw * Scan ACL to determine number of ACEs
1862da6c28aaSamw */
18630a586ceaSMark Shellenbaum if ((zp->z_pflags & ZFS_ACL_OBJ_ACE) && !(mask & VSA_ACE_ALLTYPES)) {
1864da6c28aaSamw void *zacep = NULL;
1865da6c28aaSamw uint64_t who;
1866da6c28aaSamw uint32_t access_mask;
1867da6c28aaSamw uint16_t type, iflags;
1868*06799660SGordon Ross zfs_acl_iter_t zai = {0};
1869da6c28aaSamw
1870*06799660SGordon Ross zai.zai_aclp = aclp;
1871*06799660SGordon Ross while (zacep = zfs_acl_next_ace(&zai, zacep,
1872da6c28aaSamw &who, &access_mask, &iflags, &type)) {
1873da6c28aaSamw switch (type) {
1874da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
1875da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
1876da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
1877da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
1878da6c28aaSamw largeace++;
1879da6c28aaSamw continue;
1880da6c28aaSamw default:
1881da6c28aaSamw count++;
1882da6c28aaSamw }
1883da6c28aaSamw }
1884da6c28aaSamw vsecp->vsa_aclcnt = count;
1885da6c28aaSamw } else
18860a586ceaSMark Shellenbaum count = (int)aclp->z_acl_count;
1887fa9e4066Sahrens
1888fa9e4066Sahrens if (mask & VSA_ACECNT) {
1889da6c28aaSamw vsecp->vsa_aclcnt = count;
1890fa9e4066Sahrens }
1891fa9e4066Sahrens
1892fa9e4066Sahrens if (mask & VSA_ACE) {
1893da6c28aaSamw size_t aclsz;
1894da6c28aaSamw
1895da6c28aaSamw aclsz = count * sizeof (ace_t) +
1896da6c28aaSamw sizeof (ace_object_t) * largeace;
1897da6c28aaSamw
1898da6c28aaSamw vsecp->vsa_aclentp = kmem_alloc(aclsz, KM_SLEEP);
1899da6c28aaSamw vsecp->vsa_aclentsz = aclsz;
1900da6c28aaSamw
1901da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_FUID)
1902bda89588Sjp zfs_copy_fuid_2_ace(zp->z_zfsvfs, aclp, cr,
1903da6c28aaSamw vsecp->vsa_aclentp, !(mask & VSA_ACE_ALLTYPES));
1904da6c28aaSamw else {
19052e7d9b42SMark Shellenbaum zfs_acl_node_t *aclnode;
19062e7d9b42SMark Shellenbaum void *start = vsecp->vsa_aclentp;
19072e7d9b42SMark Shellenbaum
19082e7d9b42SMark Shellenbaum for (aclnode = list_head(&aclp->z_acl); aclnode;
19092e7d9b42SMark Shellenbaum aclnode = list_next(&aclp->z_acl, aclnode)) {
19102e7d9b42SMark Shellenbaum bcopy(aclnode->z_acldata, start,
19112e7d9b42SMark Shellenbaum aclnode->z_size);
19122e7d9b42SMark Shellenbaum start = (caddr_t)start + aclnode->z_size;
19132e7d9b42SMark Shellenbaum }
19142e7d9b42SMark Shellenbaum ASSERT((caddr_t)start - (caddr_t)vsecp->vsa_aclentp ==
19152e7d9b42SMark Shellenbaum aclp->z_acl_bytes);
1916da6c28aaSamw }
1917da6c28aaSamw }
1918da6c28aaSamw if (mask & VSA_ACE_ACLFLAGS) {
1919da6c28aaSamw vsecp->vsa_aclflags = 0;
19200a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_ACL_DEFAULTED)
1921da6c28aaSamw vsecp->vsa_aclflags |= ACL_DEFAULTED;
19220a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_ACL_PROTECTED)
1923da6c28aaSamw vsecp->vsa_aclflags |= ACL_PROTECTED;
19240a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_ACL_AUTO_INHERIT)
1925da6c28aaSamw vsecp->vsa_aclflags |= ACL_AUTO_INHERIT;
1926fa9e4066Sahrens }
1927fa9e4066Sahrens
1928*06799660SGordon Ross rw_exit(&zp->z_acl_lock);
1929fa9e4066Sahrens
1930fa9e4066Sahrens return (0);
1931fa9e4066Sahrens }
1932fa9e4066Sahrens
1933da6c28aaSamw int
zfs_vsec_2_aclp(zfsvfs_t * zfsvfs,vtype_t obj_type,vsecattr_t * vsecp,cred_t * cr,zfs_fuid_info_t ** fuidp,zfs_acl_t ** zaclp)1934da6c28aaSamw zfs_vsec_2_aclp(zfsvfs_t *zfsvfs, vtype_t obj_type,
193589459e17SMark Shellenbaum vsecattr_t *vsecp, cred_t *cr, zfs_fuid_info_t **fuidp, zfs_acl_t **zaclp)
1936da6c28aaSamw {
1937da6c28aaSamw zfs_acl_t *aclp;
1938da6c28aaSamw zfs_acl_node_t *aclnode;
1939da6c28aaSamw int aclcnt = vsecp->vsa_aclcnt;
1940da6c28aaSamw int error;
1941da6c28aaSamw
1942da6c28aaSamw if (vsecp->vsa_aclcnt > MAX_ACL_ENTRIES || vsecp->vsa_aclcnt <= 0)
1943be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL));
1944da6c28aaSamw
1945da6c28aaSamw aclp = zfs_acl_alloc(zfs_acl_version(zfsvfs->z_version));
1946da6c28aaSamw
1947da6c28aaSamw aclp->z_hints = 0;
1948da6c28aaSamw aclnode = zfs_acl_node_alloc(aclcnt * sizeof (zfs_object_ace_t));
1949da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) {
1950da6c28aaSamw if ((error = zfs_copy_ace_2_oldace(obj_type, aclp,
1951da6c28aaSamw (ace_t *)vsecp->vsa_aclentp, aclnode->z_acldata,
1952da6c28aaSamw aclcnt, &aclnode->z_size)) != 0) {
1953da6c28aaSamw zfs_acl_free(aclp);
1954da6c28aaSamw zfs_acl_node_free(aclnode);
1955da6c28aaSamw return (error);
1956da6c28aaSamw }
1957da6c28aaSamw } else {
195889459e17SMark Shellenbaum if ((error = zfs_copy_ace_2_fuid(zfsvfs, obj_type, aclp,
1959da6c28aaSamw vsecp->vsa_aclentp, aclnode->z_acldata, aclcnt,
196089459e17SMark Shellenbaum &aclnode->z_size, fuidp, cr)) != 0) {
1961da6c28aaSamw zfs_acl_free(aclp);
1962da6c28aaSamw zfs_acl_node_free(aclnode);
1963da6c28aaSamw return (error);
1964da6c28aaSamw }
1965da6c28aaSamw }
1966da6c28aaSamw aclp->z_acl_bytes = aclnode->z_size;
1967da6c28aaSamw aclnode->z_ace_count = aclcnt;
1968da6c28aaSamw aclp->z_acl_count = aclcnt;
1969da6c28aaSamw list_insert_head(&aclp->z_acl, aclnode);
1970da6c28aaSamw
1971da6c28aaSamw /*
1972da6c28aaSamw * If flags are being set then add them to z_hints
1973da6c28aaSamw */
1974da6c28aaSamw if (vsecp->vsa_mask & VSA_ACE_ACLFLAGS) {
1975da6c28aaSamw if (vsecp->vsa_aclflags & ACL_PROTECTED)
1976da6c28aaSamw aclp->z_hints |= ZFS_ACL_PROTECTED;
1977da6c28aaSamw if (vsecp->vsa_aclflags & ACL_DEFAULTED)
1978da6c28aaSamw aclp->z_hints |= ZFS_ACL_DEFAULTED;
1979da6c28aaSamw if (vsecp->vsa_aclflags & ACL_AUTO_INHERIT)
1980da6c28aaSamw aclp->z_hints |= ZFS_ACL_AUTO_INHERIT;
1981da6c28aaSamw }
1982da6c28aaSamw
1983da6c28aaSamw *zaclp = aclp;
1984da6c28aaSamw
1985da6c28aaSamw return (0);
1986da6c28aaSamw }
1987da6c28aaSamw
1988fa9e4066Sahrens /*
1989f7170741SWill Andrews * Set a file's ACL
1990fa9e4066Sahrens */
1991fa9e4066Sahrens int
zfs_setacl(znode_t * zp,vsecattr_t * vsecp,boolean_t skipaclchk,cred_t * cr)1992da6c28aaSamw zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
1993fa9e4066Sahrens {
1994fa9e4066Sahrens zfsvfs_t *zfsvfs = zp->z_zfsvfs;
1995fa9e4066Sahrens zilog_t *zilog = zfsvfs->z_log;
1996fa9e4066Sahrens ulong_t mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT);
1997fa9e4066Sahrens dmu_tx_t *tx;
1998fa9e4066Sahrens int error;
1999fa9e4066Sahrens zfs_acl_t *aclp;
2000da6c28aaSamw zfs_fuid_info_t *fuidp = NULL;
200189459e17SMark Shellenbaum boolean_t fuid_dirtied;
20021412a1a2SMark Shellenbaum uint64_t acl_obj;
2003fa9e4066Sahrens
2004fa9e4066Sahrens if (mask == 0)
2005be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS));
2006fa9e4066Sahrens
20070a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_IMMUTABLE)
2008be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM));
2009da6c28aaSamw
2010da6c28aaSamw if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr))
2011da6c28aaSamw return (error);
2012da6c28aaSamw
201389459e17SMark Shellenbaum error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, cr, &fuidp,
201489459e17SMark Shellenbaum &aclp);
2015da6c28aaSamw if (error)
2016da6c28aaSamw return (error);
2017da6c28aaSamw
2018da6c28aaSamw /*
2019da6c28aaSamw * If ACL wide flags aren't being set then preserve any
2020da6c28aaSamw * existing flags.
2021da6c28aaSamw */
2022da6c28aaSamw if (!(vsecp->vsa_mask & VSA_ACE_ACLFLAGS)) {
20230a586ceaSMark Shellenbaum aclp->z_hints |=
20240a586ceaSMark Shellenbaum (zp->z_pflags & V4_ACL_WIDE_FLAGS);
2025da6c28aaSamw }
2026fa9e4066Sahrens top:
2027*06799660SGordon Ross rw_enter(&zp->z_acl_lock, RW_WRITER);
20281412a1a2SMark Shellenbaum mutex_enter(&zp->z_lock);
2029fa9e4066Sahrens
2030fa9e4066Sahrens tx = dmu_tx_create(zfsvfs->z_os);
20310a586ceaSMark Shellenbaum
20320a586ceaSMark Shellenbaum dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);
20330a586ceaSMark Shellenbaum
20340a586ceaSMark Shellenbaum fuid_dirtied = zfsvfs->z_fuid_dirty;
20350a586ceaSMark Shellenbaum if (fuid_dirtied)
20360a586ceaSMark Shellenbaum zfs_fuid_txhold(zfsvfs, tx);
20370a586ceaSMark Shellenbaum
20380a586ceaSMark Shellenbaum /*
20390a586ceaSMark Shellenbaum * If old version and ACL won't fit in bonus and we aren't
20400a586ceaSMark Shellenbaum * upgrading then take out necessary DMU holds
20410a586ceaSMark Shellenbaum */
20420a586ceaSMark Shellenbaum
20431412a1a2SMark Shellenbaum if ((acl_obj = zfs_external_acl(zp)) != 0) {
20442bd6c4deSMark Shellenbaum if (zfsvfs->z_version >= ZPL_VERSION_FUID &&
20451412a1a2SMark Shellenbaum zfs_znode_acl_version(zp) <= ZFS_ACL_VERSION_INITIAL) {
20461412a1a2SMark Shellenbaum dmu_tx_hold_free(tx, acl_obj, 0,
20470a586ceaSMark Shellenbaum DMU_OBJECT_END);
20482bd6c4deSMark Shellenbaum dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
20492bd6c4deSMark Shellenbaum aclp->z_acl_bytes);
2050da6c28aaSamw } else {
20511412a1a2SMark Shellenbaum dmu_tx_hold_write(tx, acl_obj, 0, aclp->z_acl_bytes);
2052da6c28aaSamw }
20530a586ceaSMark Shellenbaum } else if (!zp->z_is_sa && aclp->z_acl_bytes > ZFS_ACE_SPACE) {
2054da6c28aaSamw dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes);
2055da6c28aaSamw }
2056fa9e4066Sahrens
20570a586ceaSMark Shellenbaum zfs_sa_upgrade_txholds(tx, zp);
20581209a471SNeil Perrin error = dmu_tx_assign(tx, TXG_NOWAIT);
2059fa9e4066Sahrens if (error) {
2060*06799660SGordon Ross rw_exit(&zp->z_acl_lock);
2061fa9e4066Sahrens mutex_exit(&zp->z_lock);
2062fa9e4066Sahrens
20631209a471SNeil Perrin if (error == ERESTART) {
20648a2f1b91Sahrens dmu_tx_wait(tx);
20658a2f1b91Sahrens dmu_tx_abort(tx);
2066fa9e4066Sahrens goto top;
2067fa9e4066Sahrens }
20688a2f1b91Sahrens dmu_tx_abort(tx);
2069da6c28aaSamw zfs_acl_free(aclp);
2070fa9e4066Sahrens return (error);
2071fa9e4066Sahrens }
2072fa9e4066Sahrens
207389459e17SMark Shellenbaum error = zfs_aclset_common(zp, aclp, cr, tx);
2074fa9e4066Sahrens ASSERT(error == 0);
20750b2a8171SMark Shellenbaum ASSERT(zp->z_acl_cached == NULL);
20764929fd5eSTim Haley zp->z_acl_cached = aclp;
2077fa9e4066Sahrens
207889459e17SMark Shellenbaum if (fuid_dirtied)
207989459e17SMark Shellenbaum zfs_fuid_sync(zfsvfs, tx);
208089459e17SMark Shellenbaum
2081da6c28aaSamw zfs_log_acl(zilog, tx, zp, vsecp, fuidp);
2082da6c28aaSamw
2083da6c28aaSamw if (fuidp)
2084da6c28aaSamw zfs_fuid_info_free(fuidp);
2085fa9e4066Sahrens dmu_tx_commit(tx);
2086fa9e4066Sahrens done:
2087fa9e4066Sahrens mutex_exit(&zp->z_lock);
2088*06799660SGordon Ross rw_exit(&zp->z_acl_lock);
2089fa9e4066Sahrens
2090fa9e4066Sahrens return (error);
2091fa9e4066Sahrens }
2092fa9e4066Sahrens
2093da6c28aaSamw /*
2094e802abbdSTim Haley * Check accesses of interest (AoI) against attributes of the dataset
2095e802abbdSTim Haley * such as read-only. Returns zero if no AoI conflict with dataset
2096e802abbdSTim Haley * attributes, otherwise an appropriate errno is returned.
2097da6c28aaSamw */
2098fa9e4066Sahrens static int
zfs_zaccess_dataset_check(znode_t * zp,uint32_t v4_mode)2099e802abbdSTim Haley zfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode)
2100fa9e4066Sahrens {
2101fa9e4066Sahrens if ((v4_mode & WRITE_MASK) &&
2102fa9e4066Sahrens (zp->z_zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) &&
2103f52e0e2bSMark Shellenbaum (!IS_DEVVP(ZTOV(zp)) ||
2104f52e0e2bSMark Shellenbaum (IS_DEVVP(ZTOV(zp)) && (v4_mode & WRITE_MASK_ATTRS)))) {
2105be6fd75aSMatthew Ahrens return (SET_ERROR(EROFS));
2106fa9e4066Sahrens }
2107fa9e4066Sahrens
2108da6c28aaSamw /*
21092889ec41SGordon Ross * Intentionally allow ZFS_READONLY through here.
21102889ec41SGordon Ross * See zfs_zaccess_common().
2111da6c28aaSamw */
2112da6c28aaSamw if ((v4_mode & WRITE_MASK_DATA) &&
21132889ec41SGordon Ross (zp->z_pflags & ZFS_IMMUTABLE)) {
2114be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM));
2115da6c28aaSamw }
2116da6c28aaSamw
2117da6c28aaSamw if ((v4_mode & (ACE_DELETE | ACE_DELETE_CHILD)) &&
21180a586ceaSMark Shellenbaum (zp->z_pflags & ZFS_NOUNLINK)) {
2119be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM));
2120da6c28aaSamw }
2121da6c28aaSamw
2122da6c28aaSamw if (((v4_mode & (ACE_READ_DATA|ACE_EXECUTE)) &&
21230a586ceaSMark Shellenbaum (zp->z_pflags & ZFS_AV_QUARANTINED))) {
2124be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES));
2125da6c28aaSamw }
2126da6c28aaSamw
2127e802abbdSTim Haley return (0);
2128e802abbdSTim Haley }
2129e802abbdSTim Haley
2130e802abbdSTim Haley /*
2131e802abbdSTim Haley * The primary usage of this function is to loop through all of the
2132e802abbdSTim Haley * ACEs in the znode, determining what accesses of interest (AoI) to
2133e802abbdSTim Haley * the caller are allowed or denied. The AoI are expressed as bits in
2134e802abbdSTim Haley * the working_mode parameter. As each ACE is processed, bits covered
2135e802abbdSTim Haley * by that ACE are removed from the working_mode. This removal
2136e802abbdSTim Haley * facilitates two things. The first is that when the working mode is
2137e802abbdSTim Haley * empty (= 0), we know we've looked at all the AoI. The second is
2138e802abbdSTim Haley * that the ACE interpretation rules don't allow a later ACE to undo
2139e802abbdSTim Haley * something granted or denied by an earlier ACE. Removing the
2140e802abbdSTim Haley * discovered access or denial enforces this rule. At the end of
2141e802abbdSTim Haley * processing the ACEs, all AoI that were found to be denied are
2142e802abbdSTim Haley * placed into the working_mode, giving the caller a mask of denied
2143e802abbdSTim Haley * accesses. Returns:
2144e802abbdSTim Haley * 0 if all AoI granted
21451eb4e906SKevin Crowe * EACCES if the denied mask is non-zero
2146e802abbdSTim Haley * other error if abnormal failure (e.g., IO error)
2147e802abbdSTim Haley *
2148e802abbdSTim Haley * A secondary usage of the function is to determine if any of the
2149e802abbdSTim Haley * AoI are granted. If an ACE grants any access in
2150e802abbdSTim Haley * the working_mode, we immediately short circuit out of the function.
2151e802abbdSTim Haley * This mode is chosen by setting anyaccess to B_TRUE. The
2152e802abbdSTim Haley * working_mode is not a denied access mask upon exit if the function
2153e802abbdSTim Haley * is used in this manner.
2154e802abbdSTim Haley */
2155e802abbdSTim Haley static int
zfs_zaccess_aces_check(znode_t * zp,uint32_t * working_mode,boolean_t anyaccess,cred_t * cr)2156e802abbdSTim Haley zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode,
2157e802abbdSTim Haley boolean_t anyaccess, cred_t *cr)
2158e802abbdSTim Haley {
2159e802abbdSTim Haley zfsvfs_t *zfsvfs = zp->z_zfsvfs;
2160e802abbdSTim Haley zfs_acl_t *aclp;
2161e802abbdSTim Haley int error;
21624fbfc69bSGordon Ross uint64_t who; /* FUID from the ACE */
2163e802abbdSTim Haley uint16_t type, iflags;
2164e802abbdSTim Haley uint16_t entry_type;
2165e802abbdSTim Haley uint32_t access_mask;
2166e802abbdSTim Haley uint32_t deny_mask = 0;
2167e802abbdSTim Haley zfs_ace_hdr_t *acep = NULL;
21684fbfc69bSGordon Ross boolean_t checkit; /* ACE ID matches */
2169*06799660SGordon Ross zfs_acl_iter_t zai = {0};
2170da6c28aaSamw
2171*06799660SGordon Ross /*
2172*06799660SGordon Ross * This can be a HOT code path, so when possible
2173*06799660SGordon Ross * try to avoid entering z_acl_lock as writer.
2174*06799660SGordon Ross */
2175*06799660SGordon Ross rw_enter(&zp->z_acl_lock, RW_READER);
2176*06799660SGordon Ross aclp = zp->z_acl_cached;
2177*06799660SGordon Ross if (aclp == NULL) {
2178*06799660SGordon Ross /*
2179*06799660SGordon Ross * OK, need WRITER to load the ACL. Note:
2180*06799660SGordon Ross * zfs_acl_node_read() re-checks zp->z_acl_cached
2181*06799660SGordon Ross * and just returns if it's set.
2182*06799660SGordon Ross */
2183*06799660SGordon Ross rw_exit(&zp->z_acl_lock);
2184*06799660SGordon Ross rw_enter(&zp->z_acl_lock, RW_WRITER);
2185fa9e4066Sahrens
2186*06799660SGordon Ross error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE);
2187*06799660SGordon Ross if (error != 0) {
2188*06799660SGordon Ross rw_exit(&zp->z_acl_lock);
2189*06799660SGordon Ross return (error);
2190*06799660SGordon Ross }
2191*06799660SGordon Ross rw_downgrade(&zp->z_acl_lock); /* now RW_READER */
2192*06799660SGordon Ross ASSERT(zp->z_acl_cached);
2193ea8dc4b6Seschrock }
2194ea8dc4b6Seschrock
2195*06799660SGordon Ross zai.zai_aclp = aclp;
2196*06799660SGordon Ross while (acep = zfs_acl_next_ace(&zai, acep, &who, &access_mask,
2197da6c28aaSamw &iflags, &type)) {
2198e802abbdSTim Haley uint32_t mask_matched;
2199fa9e4066Sahrens
2200003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags))
2201003c2582SMark Shellenbaum continue;
2202003c2582SMark Shellenbaum
2203b249c65cSmarks if (ZTOV(zp)->v_type == VDIR && (iflags & ACE_INHERIT_ONLY_ACE))
2204da6c28aaSamw continue;
2205fa9e4066Sahrens
2206e802abbdSTim Haley /* Skip ACE if it does not affect any AoI */
2207e802abbdSTim Haley mask_matched = (access_mask & *working_mode);
2208e802abbdSTim Haley if (!mask_matched)
2209e802abbdSTim Haley continue;
2210e802abbdSTim Haley
2211da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS);
2212169cdae2Smarks
2213da6c28aaSamw checkit = B_FALSE;
2214fa9e4066Sahrens
2215fa9e4066Sahrens switch (entry_type) {
2216fa9e4066Sahrens case ACE_OWNER:
22174fbfc69bSGordon Ross who = zp->z_uid;
22184fbfc69bSGordon Ross /*FALLTHROUGH*/
22194fbfc69bSGordon Ross case 0: /* USER Entry */
22204fbfc69bSGordon Ross checkit = zfs_user_in_cred(zfsvfs, who, cr);
2221fa9e4066Sahrens break;
2222da6c28aaSamw case OWNING_GROUP:
22234fbfc69bSGordon Ross who = zp->z_gid;
2224da6c28aaSamw /*FALLTHROUGH*/
2225fa9e4066Sahrens case ACE_IDENTIFIER_GROUP:
2226da6c28aaSamw checkit = zfs_groupmember(zfsvfs, who, cr);
2227fa9e4066Sahrens break;
2228fa9e4066Sahrens case ACE_EVERYONE:
2229da6c28aaSamw checkit = B_TRUE;
2230fa9e4066Sahrens break;
2231fa9e4066Sahrens
2232fa9e4066Sahrens default:
22334fbfc69bSGordon Ross /*
22344fbfc69bSGordon Ross * The zfs_acl_valid_ace_type check above
22354fbfc69bSGordon Ross * should make this case impossible.
22364fbfc69bSGordon Ross */
2237*06799660SGordon Ross rw_exit(&zp->z_acl_lock);
22384fbfc69bSGordon Ross return (SET_ERROR(EIO));
2239da6c28aaSamw }
2240da6c28aaSamw
2241da6c28aaSamw if (checkit) {
2242e802abbdSTim Haley if (type == DENY) {
2243e802abbdSTim Haley DTRACE_PROBE3(zfs__ace__denies,
2244e802abbdSTim Haley znode_t *, zp,
2245e802abbdSTim Haley zfs_ace_hdr_t *, acep,
2246e802abbdSTim Haley uint32_t, mask_matched);
2247e802abbdSTim Haley deny_mask |= mask_matched;
2248e802abbdSTim Haley } else {
2249e802abbdSTim Haley DTRACE_PROBE3(zfs__ace__allows,
2250e802abbdSTim Haley znode_t *, zp,
2251e802abbdSTim Haley zfs_ace_hdr_t *, acep,
2252e802abbdSTim Haley uint32_t, mask_matched);
2253e802abbdSTim Haley if (anyaccess) {
2254*06799660SGordon Ross rw_exit(&zp->z_acl_lock);
2255e802abbdSTim Haley return (0);
2256e802abbdSTim Haley }
2257fa9e4066Sahrens }
2258e802abbdSTim Haley *working_mode &= ~mask_matched;
2259fa9e4066Sahrens }
2260fa9e4066Sahrens
226190fafcf0Smarks /* Are we done? */
226290fafcf0Smarks if (*working_mode == 0)
2263fa9e4066Sahrens break;
2264fa9e4066Sahrens }
2265fa9e4066Sahrens
2266*06799660SGordon Ross rw_exit(&zp->z_acl_lock);
226790fafcf0Smarks
226890fafcf0Smarks /* Put the found 'denies' back on the working mode */
22697ed7e920Smarks if (deny_mask) {
22707ed7e920Smarks *working_mode |= deny_mask;
2271be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES));
22727ed7e920Smarks } else if (*working_mode) {
22737ed7e920Smarks return (-1);
22747ed7e920Smarks }
227590fafcf0Smarks
227690fafcf0Smarks return (0);
2277fa9e4066Sahrens }
2278fa9e4066Sahrens
2279e802abbdSTim Haley /*
2280e802abbdSTim Haley * Return true if any access whatsoever granted, we don't actually
2281e802abbdSTim Haley * care what access is granted.
2282e802abbdSTim Haley */
2283e802abbdSTim Haley boolean_t
zfs_has_access(znode_t * zp,cred_t * cr)2284e802abbdSTim Haley zfs_has_access(znode_t *zp, cred_t *cr)
2285e802abbdSTim Haley {
2286e802abbdSTim Haley uint32_t have = ACE_ALL_PERMS;
2287e802abbdSTim Haley
2288e802abbdSTim Haley if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) {
2289f1696b23SMark Shellenbaum uid_t owner;
2290f1696b23SMark Shellenbaum
2291f1696b23SMark Shellenbaum owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER);
2292f1696b23SMark Shellenbaum return (secpolicy_vnode_any_access(cr, ZTOV(zp), owner) == 0);
2293e802abbdSTim Haley }
2294e802abbdSTim Haley return (B_TRUE);
2295e802abbdSTim Haley }
2296e802abbdSTim Haley
2297e802abbdSTim Haley static int
zfs_zaccess_common(znode_t * zp,uint32_t v4_mode,uint32_t * working_mode,boolean_t * check_privs,boolean_t skipaclchk,cred_t * cr)2298e802abbdSTim Haley zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode,
2299e802abbdSTim Haley boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr)
2300e802abbdSTim Haley {
2301e802abbdSTim Haley zfsvfs_t *zfsvfs = zp->z_zfsvfs;
2302e802abbdSTim Haley int err;
2303e802abbdSTim Haley
2304e802abbdSTim Haley *working_mode = v4_mode;
2305e802abbdSTim Haley *check_privs = B_TRUE;
2306e802abbdSTim Haley
2307e802abbdSTim Haley /*
2308e802abbdSTim Haley * Short circuit empty requests
2309e802abbdSTim Haley */
2310e802abbdSTim Haley if (v4_mode == 0 || zfsvfs->z_replay) {
2311e802abbdSTim Haley *working_mode = 0;
2312e802abbdSTim Haley return (0);
2313e802abbdSTim Haley }
2314e802abbdSTim Haley
2315e802abbdSTim Haley if ((err = zfs_zaccess_dataset_check(zp, v4_mode)) != 0) {
2316e802abbdSTim Haley *check_privs = B_FALSE;
2317e802abbdSTim Haley return (err);
2318e802abbdSTim Haley }
2319e802abbdSTim Haley
2320e802abbdSTim Haley /*
2321e802abbdSTim Haley * The caller requested that the ACL check be skipped. This
2322e802abbdSTim Haley * would only happen if the caller checked VOP_ACCESS() with a
2323e802abbdSTim Haley * 32 bit ACE mask and already had the appropriate permissions.
2324e802abbdSTim Haley */
2325e802abbdSTim Haley if (skipaclchk) {
2326e802abbdSTim Haley *working_mode = 0;
2327e802abbdSTim Haley return (0);
2328e802abbdSTim Haley }
2329e802abbdSTim Haley
23302889ec41SGordon Ross /*
23312889ec41SGordon Ross * Note: ZFS_READONLY represents the "DOS R/O" attribute.
23322889ec41SGordon Ross * When that flag is set, we should behave as if write access
23332889ec41SGordon Ross * were not granted by anything in the ACL. In particular:
23342889ec41SGordon Ross * We _must_ allow writes after opening the file r/w, then
23352889ec41SGordon Ross * setting the DOS R/O attribute, and writing some more.
23362889ec41SGordon Ross * (Similar to how you can write after fchmod(fd, 0444).)
23372889ec41SGordon Ross *
23382889ec41SGordon Ross * Therefore ZFS_READONLY is ignored in the dataset check
23392889ec41SGordon Ross * above, and checked here as if part of the ACL check.
23402889ec41SGordon Ross * Also note: DOS R/O is ignored for directories.
23412889ec41SGordon Ross */
23422889ec41SGordon Ross if ((v4_mode & WRITE_MASK_DATA) &&
23432889ec41SGordon Ross (ZTOV(zp)->v_type != VDIR) &&
23442889ec41SGordon Ross (zp->z_pflags & ZFS_READONLY)) {
23452889ec41SGordon Ross return (SET_ERROR(EPERM));
23462889ec41SGordon Ross }
23472889ec41SGordon Ross
2348e802abbdSTim Haley return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr));
2349e802abbdSTim Haley }
2350e802abbdSTim Haley
2351da6c28aaSamw static int
zfs_zaccess_append(znode_t * zp,uint32_t * working_mode,boolean_t * check_privs,cred_t * cr)2352da6c28aaSamw zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs,
2353da6c28aaSamw cred_t *cr)
2354da6c28aaSamw {
2355da6c28aaSamw if (*working_mode != ACE_WRITE_DATA)
2356be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES));
2357da6c28aaSamw
2358da6c28aaSamw return (zfs_zaccess_common(zp, ACE_APPEND_DATA, working_mode,
2359da6c28aaSamw check_privs, B_FALSE, cr));
2360da6c28aaSamw }
2361fa9e4066Sahrens
2362d47621a4STim Haley int
zfs_fastaccesschk_execute(znode_t * zdp,cred_t * cr,boolean_t skipaclchk)2363f37b3cbbSMatt Barden zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr, boolean_t skipaclchk)
2364d47621a4STim Haley {
2365d47621a4STim Haley boolean_t owner = B_FALSE;
2366d47621a4STim Haley boolean_t groupmbr = B_FALSE;
2367d47621a4STim Haley boolean_t is_attr;
2368d47621a4STim Haley uid_t uid = crgetuid(cr);
2369d47621a4STim Haley int error;
2370d47621a4STim Haley
23710a586ceaSMark Shellenbaum if (zdp->z_pflags & ZFS_AV_QUARANTINED)
2372be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES));
2373d47621a4STim Haley
23740a586ceaSMark Shellenbaum is_attr = ((zdp->z_pflags & ZFS_XATTR) &&
2375d47621a4STim Haley (ZTOV(zdp)->v_type == VDIR));
2376d47621a4STim Haley if (is_attr)
2377d47621a4STim Haley goto slow;
2378d47621a4STim Haley
23790a586ceaSMark Shellenbaum
2380*06799660SGordon Ross rw_enter(&zdp->z_acl_lock, RW_READER);
2381d47621a4STim Haley
23820a586ceaSMark Shellenbaum if (zdp->z_pflags & ZFS_NO_EXECS_DENIED) {
2383*06799660SGordon Ross rw_exit(&zdp->z_acl_lock);
2384d47621a4STim Haley return (0);
2385d47621a4STim Haley }
2386d47621a4STim Haley
2387f1696b23SMark Shellenbaum if (FUID_INDEX(zdp->z_uid) != 0 || FUID_INDEX(zdp->z_gid) != 0) {
2388*06799660SGordon Ross rw_exit(&zdp->z_acl_lock);
2389d47621a4STim Haley goto slow;
2390d47621a4STim Haley }
2391d47621a4STim Haley
23920a586ceaSMark Shellenbaum if (uid == zdp->z_uid) {
2393d47621a4STim Haley owner = B_TRUE;
23940a586ceaSMark Shellenbaum if (zdp->z_mode & S_IXUSR) {
2395*06799660SGordon Ross rw_exit(&zdp->z_acl_lock);
2396d47621a4STim Haley return (0);
2397e4f96946STim Haley } else {
2398*06799660SGordon Ross rw_exit(&zdp->z_acl_lock);
2399e4f96946STim Haley goto slow;
2400d47621a4STim Haley }
2401d47621a4STim Haley }
24020a586ceaSMark Shellenbaum if (groupmember(zdp->z_gid, cr)) {
2403d47621a4STim Haley groupmbr = B_TRUE;
24040a586ceaSMark Shellenbaum if (zdp->z_mode & S_IXGRP) {
2405*06799660SGordon Ross rw_exit(&zdp->z_acl_lock);
2406d47621a4STim Haley return (0);
2407e4f96946STim Haley } else {
2408*06799660SGordon Ross rw_exit(&zdp->z_acl_lock);
2409e4f96946STim Haley goto slow;
2410d47621a4STim Haley }
2411d47621a4STim Haley }
2412d47621a4STim Haley if (!owner && !groupmbr) {
24130a586ceaSMark Shellenbaum if (zdp->z_mode & S_IXOTH) {
2414*06799660SGordon Ross rw_exit(&zdp->z_acl_lock);
2415d47621a4STim Haley return (0);
2416d47621a4STim Haley }
2417d47621a4STim Haley }
2418d47621a4STim Haley
2419*06799660SGordon Ross rw_exit(&zdp->z_acl_lock);
2420d47621a4STim Haley
2421d47621a4STim Haley slow:
2422d47621a4STim Haley DTRACE_PROBE(zfs__fastpath__execute__access__miss);
2423d47621a4STim Haley ZFS_ENTER(zdp->z_zfsvfs);
2424f37b3cbbSMatt Barden error = zfs_zaccess(zdp, ACE_EXECUTE, 0, skipaclchk, cr);
2425d47621a4STim Haley ZFS_EXIT(zdp->z_zfsvfs);
2426d47621a4STim Haley return (error);
2427d47621a4STim Haley }
2428d47621a4STim Haley
2429fa9e4066Sahrens /*
2430134a1f4eSCasper H.S. Dik * Determine whether Access should be granted/denied.
2431f7170741SWill Andrews *
2432edc8ef7dSToomas Soome * The least priv subsystem is always consulted as a basic privilege
2433134a1f4eSCasper H.S. Dik * can define any form of access.
2434fa9e4066Sahrens */
2435fa9e4066Sahrens int
zfs_zaccess(znode_t * zp,int mode,int flags,boolean_t skipaclchk,cred_t * cr)2436da6c28aaSamw zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
2437fa9e4066Sahrens {
2438da6c28aaSamw uint32_t working_mode;
2439da6c28aaSamw int error;
2440da6c28aaSamw int is_attr;
244154811da5SToomas Soome boolean_t check_privs;
2442da6c28aaSamw znode_t *xzp;
244354811da5SToomas Soome znode_t *check_zp = zp;
2444134a1f4eSCasper H.S. Dik mode_t needed_bits;
2445f1696b23SMark Shellenbaum uid_t owner;
2446fa9e4066Sahrens
24470a586ceaSMark Shellenbaum is_attr = ((zp->z_pflags & ZFS_XATTR) && (ZTOV(zp)->v_type == VDIR));
2448fa9e4066Sahrens
2449fa9e4066Sahrens /*
2450fa9e4066Sahrens * If attribute then validate against base file
2451fa9e4066Sahrens */
2452fa9e4066Sahrens if (is_attr) {
24530a586ceaSMark Shellenbaum uint64_t parent;
24540a586ceaSMark Shellenbaum
24550a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl,
24560a586ceaSMark Shellenbaum SA_ZPL_PARENT(zp->z_zfsvfs), &parent,
24570a586ceaSMark Shellenbaum sizeof (parent))) != 0)
24580a586ceaSMark Shellenbaum return (error);
24590a586ceaSMark Shellenbaum
2460fa9e4066Sahrens if ((error = zfs_zget(zp->z_zfsvfs,
24610a586ceaSMark Shellenbaum parent, &xzp)) != 0) {
2462fa9e4066Sahrens return (error);
2463fa9e4066Sahrens }
2464da6c28aaSamw
2465fa9e4066Sahrens check_zp = xzp;
2466da6c28aaSamw
2467fa9e4066Sahrens /*
2468fa9e4066Sahrens * fixup mode to map to xattr perms
2469fa9e4066Sahrens */
2470fa9e4066Sahrens
2471fa9e4066Sahrens if (mode & (ACE_WRITE_DATA|ACE_APPEND_DATA)) {
2472fa9e4066Sahrens mode &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
2473fa9e4066Sahrens mode |= ACE_WRITE_NAMED_ATTRS;
2474fa9e4066Sahrens }
2475fa9e4066Sahrens
2476fa9e4066Sahrens if (mode & (ACE_READ_DATA|ACE_EXECUTE)) {
2477fa9e4066Sahrens mode &= ~(ACE_READ_DATA|ACE_EXECUTE);
2478fa9e4066Sahrens mode |= ACE_READ_NAMED_ATTRS;
2479fa9e4066Sahrens }
2480fa9e4066Sahrens }
2481fa9e4066Sahrens
2482f1696b23SMark Shellenbaum owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER);
2483134a1f4eSCasper H.S. Dik /*
2484134a1f4eSCasper H.S. Dik * Map the bits required to the standard vnode flags VREAD|VWRITE|VEXEC
2485134a1f4eSCasper H.S. Dik * in needed_bits. Map the bits mapped by working_mode (currently
2486134a1f4eSCasper H.S. Dik * missing) in missing_bits.
2487134a1f4eSCasper H.S. Dik * Call secpolicy_vnode_access2() with (needed_bits & ~checkmode),
2488134a1f4eSCasper H.S. Dik * needed_bits.
2489134a1f4eSCasper H.S. Dik */
2490134a1f4eSCasper H.S. Dik needed_bits = 0;
2491134a1f4eSCasper H.S. Dik
2492134a1f4eSCasper H.S. Dik working_mode = mode;
249370561057SGordon Ross
2494134a1f4eSCasper H.S. Dik if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) &&
2495f1696b23SMark Shellenbaum owner == crgetuid(cr))
2496134a1f4eSCasper H.S. Dik working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES);
2497134a1f4eSCasper H.S. Dik
2498134a1f4eSCasper H.S. Dik if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS|
2499134a1f4eSCasper H.S. Dik ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE))
2500134a1f4eSCasper H.S. Dik needed_bits |= VREAD;
2501134a1f4eSCasper H.S. Dik if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS|
2502134a1f4eSCasper H.S. Dik ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE))
2503134a1f4eSCasper H.S. Dik needed_bits |= VWRITE;
2504134a1f4eSCasper H.S. Dik if (working_mode & ACE_EXECUTE)
2505134a1f4eSCasper H.S. Dik needed_bits |= VEXEC;
2506134a1f4eSCasper H.S. Dik
2507da6c28aaSamw if ((error = zfs_zaccess_common(check_zp, mode, &working_mode,
2508da6c28aaSamw &check_privs, skipaclchk, cr)) == 0) {
2509da6c28aaSamw if (is_attr)
2510da6c28aaSamw VN_RELE(ZTOV(xzp));
2511f1696b23SMark Shellenbaum return (secpolicy_vnode_access2(cr, ZTOV(zp), owner,
2512134a1f4eSCasper H.S. Dik needed_bits, needed_bits));
2513da6c28aaSamw }
2514fa9e4066Sahrens
2515e0d35c44Smarks if (error && !check_privs) {
2516fa9e4066Sahrens if (is_attr)
2517fa9e4066Sahrens VN_RELE(ZTOV(xzp));
2518fa9e4066Sahrens return (error);
2519fa9e4066Sahrens }
2520fa9e4066Sahrens
2521da6c28aaSamw if (error && (flags & V_APPEND)) {
2522da6c28aaSamw error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr);
2523da6c28aaSamw }
2524da6c28aaSamw
2525da6c28aaSamw if (error && check_privs) {
2526da6c28aaSamw mode_t checkmode = 0;
2527da6c28aaSamw
2528da6c28aaSamw /*
2529da6c28aaSamw * First check for implicit owner permission on
2530da6c28aaSamw * read_acl/read_attributes
2531da6c28aaSamw */
2532da6c28aaSamw
2533da6c28aaSamw error = 0;
2534da6c28aaSamw ASSERT(working_mode != 0);
2535da6c28aaSamw
2536da6c28aaSamw if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) &&
2537f1696b23SMark Shellenbaum owner == crgetuid(cr)))
2538da6c28aaSamw working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES);
2539da6c28aaSamw
2540da6c28aaSamw if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS|
254147def0dcSMark Shellenbaum ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE))
2542da6c28aaSamw checkmode |= VREAD;
2543da6c28aaSamw if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS|
254447def0dcSMark Shellenbaum ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE))
2545da6c28aaSamw checkmode |= VWRITE;
2546da6c28aaSamw if (working_mode & ACE_EXECUTE)
2547da6c28aaSamw checkmode |= VEXEC;
2548da6c28aaSamw
2549f1696b23SMark Shellenbaum error = secpolicy_vnode_access2(cr, ZTOV(check_zp), owner,
2550134a1f4eSCasper H.S. Dik needed_bits & ~checkmode, needed_bits);
2551da6c28aaSamw
2552da6c28aaSamw if (error == 0 && (working_mode & ACE_WRITE_OWNER))
2553f1696b23SMark Shellenbaum error = secpolicy_vnode_chown(cr, owner);
2554da6c28aaSamw if (error == 0 && (working_mode & ACE_WRITE_ACL))
255570561057SGordon Ross error = secpolicy_vnode_setdac3(cr, owner,
255670561057SGordon Ross zp->z_zfsvfs->z_acl_implicit);
2557da6c28aaSamw
2558da6c28aaSamw if (error == 0 && (working_mode &
2559da6c28aaSamw (ACE_DELETE|ACE_DELETE_CHILD)))
2560da6c28aaSamw error = secpolicy_vnode_remove(cr);
2561da6c28aaSamw
256247def0dcSMark Shellenbaum if (error == 0 && (working_mode & ACE_SYNCHRONIZE)) {
2563f1696b23SMark Shellenbaum error = secpolicy_vnode_chown(cr, owner);
256447def0dcSMark Shellenbaum }
2565da6c28aaSamw if (error == 0) {
2566da6c28aaSamw /*
2567da6c28aaSamw * See if any bits other than those already checked
2568da6c28aaSamw * for are still present. If so then return EACCES
2569da6c28aaSamw */
2570da6c28aaSamw if (working_mode & ~(ZFS_CHECKED_MASKS)) {
2571be6fd75aSMatthew Ahrens error = SET_ERROR(EACCES);
2572da6c28aaSamw }
2573da6c28aaSamw }
2574134a1f4eSCasper H.S. Dik } else if (error == 0) {
2575f1696b23SMark Shellenbaum error = secpolicy_vnode_access2(cr, ZTOV(zp), owner,
2576134a1f4eSCasper H.S. Dik needed_bits, needed_bits);
2577fa9e4066Sahrens }
2578fa9e4066Sahrens
2579134a1f4eSCasper H.S. Dik
2580fa9e4066Sahrens if (is_attr)
2581fa9e4066Sahrens VN_RELE(ZTOV(xzp));
2582fa9e4066Sahrens
2583fa9e4066Sahrens return (error);
2584fa9e4066Sahrens }
2585fa9e4066Sahrens
2586fa9e4066Sahrens /*
2587da6c28aaSamw * Translate traditional unix VREAD/VWRITE/VEXEC mode into
2588da6c28aaSamw * native ACL format and call zfs_zaccess()
2589fa9e4066Sahrens */
2590fa9e4066Sahrens int
zfs_zaccess_rwx(znode_t * zp,mode_t mode,int flags,cred_t * cr)2591da6c28aaSamw zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr)
2592fa9e4066Sahrens {
2593da6c28aaSamw return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr));
2594fa9e4066Sahrens }
2595fa9e4066Sahrens
2596fa9e4066Sahrens /*
2597da6c28aaSamw * Access function for secpolicy_vnode_setattr
2598fa9e4066Sahrens */
2599fa9e4066Sahrens int
zfs_zaccess_unix(znode_t * zp,mode_t mode,cred_t * cr)2600da6c28aaSamw zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr)
2601fa9e4066Sahrens {
2602fa9e4066Sahrens int v4_mode = zfs_unix_to_v4(mode >> 6);
2603fa9e4066Sahrens
2604da6c28aaSamw return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr));
2605fa9e4066Sahrens }
2606fa9e4066Sahrens
26071eb4e906SKevin Crowe /* See zfs_zaccess_delete() */
26081eb4e906SKevin Crowe int zfs_write_implies_delete_child = 1;
260947db7e74Smarks
2610fa9e4066Sahrens /*
26111eb4e906SKevin Crowe * Determine whether delete access should be granted.
2612fa9e4066Sahrens *
2613da412744SKevin Crowe * The following chart outlines how we handle delete permissions which is
2614da412744SKevin Crowe * how recent versions of windows (Windows 2008) handles it. The efficiency
2615da412744SKevin Crowe * comes from not having to check the parent ACL where the object itself grants
2616da412744SKevin Crowe * delete:
2617fa9e4066Sahrens *
2618fa9e4066Sahrens * -------------------------------------------------------
26191eb4e906SKevin Crowe * | Parent Dir | Target Object Permissions |
2620fa9e4066Sahrens * | permissions | |
2621fa9e4066Sahrens * -------------------------------------------------------
2622fa9e4066Sahrens * | | ACL Allows | ACL Denies| Delete |
2623fa9e4066Sahrens * | | Delete | Delete | unspecified|
2624fa9e4066Sahrens * -------------------------------------------------------
2625da412744SKevin Crowe * | ACL Allows | Permit | Deny * | Permit |
2626da412744SKevin Crowe * | DELETE_CHILD | | | |
2627fa9e4066Sahrens * -------------------------------------------------------
2628da412744SKevin Crowe * | ACL Denies | Permit | Deny | Deny |
2629da412744SKevin Crowe * | DELETE_CHILD | | | |
2630fa9e4066Sahrens * -------------------------------------------------------
2631fa9e4066Sahrens * | ACL specifies | | | |
2632da412744SKevin Crowe * | only allow | Permit | Deny * | Permit |
2633fa9e4066Sahrens * | write and | | | |
2634fa9e4066Sahrens * | execute | | | |
2635fa9e4066Sahrens * -------------------------------------------------------
2636fa9e4066Sahrens * | ACL denies | | | |
2637fa9e4066Sahrens * | write and | Permit | Deny | Deny |
2638fa9e4066Sahrens * | execute | | | |
2639fa9e4066Sahrens * -------------------------------------------------------
2640fa9e4066Sahrens * ^
2641fa9e4066Sahrens * |
26421eb4e906SKevin Crowe * Re. execute permission on the directory: if that's missing,
26431eb4e906SKevin Crowe * the vnode lookup of the target will fail before we get here.
26441eb4e906SKevin Crowe *
2645da412744SKevin Crowe * Re [*] in the table above: NFSv4 would normally Permit delete for
2646da412744SKevin Crowe * these two cells of the matrix.
2647da412744SKevin Crowe * See acl.h for notes on which ACE_... flags should be checked for which
2648da412744SKevin Crowe * operations. Specifically, the NFSv4 committee recommendation is in
2649da412744SKevin Crowe * conflict with the Windows interpretation of DENY ACEs, where DENY ACEs
26501eb4e906SKevin Crowe * should take precedence ahead of ALLOW ACEs.
26511eb4e906SKevin Crowe *
2652da412744SKevin Crowe * This implementation always consults the target object's ACL first.
2653da412744SKevin Crowe * If a DENY ACE is present on the target object that specifies ACE_DELETE,
2654da412744SKevin Crowe * delete access is denied. If an ALLOW ACE with ACE_DELETE is present on
2655da412744SKevin Crowe * the target object, access is allowed. If and only if no entries with
2656da412744SKevin Crowe * ACE_DELETE are present in the object's ACL, check the container's ACL
2657da412744SKevin Crowe * for entries with ACE_DELETE_CHILD.
26581eb4e906SKevin Crowe *
2659da412744SKevin Crowe * A summary of the logic implemented from the table above is as follows:
2660fa9e4066Sahrens *
26611eb4e906SKevin Crowe * First check for DENY ACEs that apply.
26621eb4e906SKevin Crowe * If either target or container has a deny, EACCES.
26631eb4e906SKevin Crowe *
26641eb4e906SKevin Crowe * Delete access can then be summarized as follows:
26651eb4e906SKevin Crowe * 1: The object to be deleted grants ACE_DELETE, or
26661eb4e906SKevin Crowe * 2: The containing directory grants ACE_DELETE_CHILD.
26671eb4e906SKevin Crowe * In a Windows system, that would be the end of the story.
26681eb4e906SKevin Crowe * In this system, (2) has some complications...
26691eb4e906SKevin Crowe * 2a: "sticky" bit on a directory adds restrictions, and
26701eb4e906SKevin Crowe * 2b: existing ACEs from previous versions of ZFS may
26711eb4e906SKevin Crowe * not carry ACE_DELETE_CHILD where they should, so we
26721eb4e906SKevin Crowe * also allow delete when ACE_WRITE_DATA is granted.
26731eb4e906SKevin Crowe *
26741eb4e906SKevin Crowe * Note: 2b is technically a work-around for a prior bug,
26751eb4e906SKevin Crowe * which hopefully can go away some day. For those who
26761eb4e906SKevin Crowe * no longer need the work around, and for testing, this
26771eb4e906SKevin Crowe * work-around is made conditional via the tunable:
26781eb4e906SKevin Crowe * zfs_write_implies_delete_child
2679fa9e4066Sahrens */
2680fa9e4066Sahrens int
zfs_zaccess_delete(znode_t * dzp,znode_t * zp,cred_t * cr)2681fa9e4066Sahrens zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
2682fa9e4066Sahrens {
26831eb4e906SKevin Crowe uint32_t wanted_dirperms;
2684da6c28aaSamw uint32_t dzp_working_mode = 0;
2685da6c28aaSamw uint32_t zp_working_mode = 0;
2686fa9e4066Sahrens int dzp_error, zp_error;
26871eb4e906SKevin Crowe boolean_t dzpcheck_privs;
26881eb4e906SKevin Crowe boolean_t zpcheck_privs;
2689fa9e4066Sahrens
26900a586ceaSMark Shellenbaum if (zp->z_pflags & (ZFS_IMMUTABLE | ZFS_NOUNLINK))
2691be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM));
2692da6c28aaSamw
269323d5bb1fSmarks /*
26941eb4e906SKevin Crowe * Case 1:
26951eb4e906SKevin Crowe * If target object grants ACE_DELETE then we are done. This is
26961eb4e906SKevin Crowe * indicated by a return value of 0. For this case we don't worry
26971eb4e906SKevin Crowe * about the sticky bit because sticky only applies to the parent
26981eb4e906SKevin Crowe * directory and this is the child access result.
26991eb4e906SKevin Crowe *
27001eb4e906SKevin Crowe * If we encounter a DENY ACE here, we're also done (EACCES).
27011eb4e906SKevin Crowe * Note that if we hit a DENY ACE here (on the target) it should
27021eb4e906SKevin Crowe * take precedence over a DENY ACE on the container, so that when
27031eb4e906SKevin Crowe * we have more complete auditing support we will be able to
27041eb4e906SKevin Crowe * report an access failure against the specific target.
27051eb4e906SKevin Crowe * (This is part of why we're checking the target first.)
270623d5bb1fSmarks */
27071eb4e906SKevin Crowe zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode,
27081eb4e906SKevin Crowe &zpcheck_privs, B_FALSE, cr);
27091eb4e906SKevin Crowe if (zp_error == EACCES) {
27101eb4e906SKevin Crowe /* We hit a DENY ACE. */
27111eb4e906SKevin Crowe if (!zpcheck_privs)
27121eb4e906SKevin Crowe return (SET_ERROR(zp_error));
27131eb4e906SKevin Crowe return (secpolicy_vnode_remove(cr));
27141eb4e906SKevin Crowe
27151eb4e906SKevin Crowe }
27161eb4e906SKevin Crowe if (zp_error == 0)
271723d5bb1fSmarks return (0);
2718fa9e4066Sahrens
271923d5bb1fSmarks /*
27201eb4e906SKevin Crowe * Case 2:
27211eb4e906SKevin Crowe * If the containing directory grants ACE_DELETE_CHILD,
27221eb4e906SKevin Crowe * or we're in backward compatibility mode and the
27231eb4e906SKevin Crowe * containing directory has ACE_WRITE_DATA, allow.
27241eb4e906SKevin Crowe * Case 2b is handled with wanted_dirperms.
272523d5bb1fSmarks */
27261eb4e906SKevin Crowe wanted_dirperms = ACE_DELETE_CHILD;
27271eb4e906SKevin Crowe if (zfs_write_implies_delete_child)
27281eb4e906SKevin Crowe wanted_dirperms |= ACE_WRITE_DATA;
27291eb4e906SKevin Crowe dzp_error = zfs_zaccess_common(dzp, wanted_dirperms,
27301eb4e906SKevin Crowe &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr);
27311eb4e906SKevin Crowe if (dzp_error == EACCES) {
27321eb4e906SKevin Crowe /* We hit a DENY ACE. */
27331eb4e906SKevin Crowe if (!dzpcheck_privs)
27341eb4e906SKevin Crowe return (SET_ERROR(dzp_error));
27351eb4e906SKevin Crowe return (secpolicy_vnode_remove(cr));
27361eb4e906SKevin Crowe }
2737fa9e4066Sahrens
2738fa9e4066Sahrens /*
27391eb4e906SKevin Crowe * Cases 2a, 2b (continued)
27407ed7e920Smarks *
27411eb4e906SKevin Crowe * Note: dzp_working_mode now contains any permissions
27421eb4e906SKevin Crowe * that were NOT granted. Therefore, if any of the
27431eb4e906SKevin Crowe * wanted_dirperms WERE granted, we will have:
27441eb4e906SKevin Crowe * dzp_working_mode != wanted_dirperms
27451eb4e906SKevin Crowe * We're really asking if ANY of those permissions
27461eb4e906SKevin Crowe * were granted, and if so, grant delete access.
274747db7e74Smarks */
27481eb4e906SKevin Crowe if (dzp_working_mode != wanted_dirperms)
27491eb4e906SKevin Crowe dzp_error = 0;
275047db7e74Smarks
2751fa9e4066Sahrens /*
27521eb4e906SKevin Crowe * dzp_error is 0 if the container granted us permissions to "modify".
27531eb4e906SKevin Crowe * If we do not have permission via one or more ACEs, our current
27541eb4e906SKevin Crowe * privileges may still permit us to modify the container.
27551eb4e906SKevin Crowe *
27561eb4e906SKevin Crowe * dzpcheck_privs is false when i.e. the FS is read-only.
27571eb4e906SKevin Crowe * Otherwise, do privilege checks for the container.
2758fa9e4066Sahrens */
27591eb4e906SKevin Crowe if (dzp_error != 0 && dzpcheck_privs) {
27601eb4e906SKevin Crowe uid_t owner;
2761fa9e4066Sahrens
27621eb4e906SKevin Crowe /*
27631eb4e906SKevin Crowe * The secpolicy call needs the requested access and
27641eb4e906SKevin Crowe * the current access mode of the container, but it
27651eb4e906SKevin Crowe * only knows about Unix-style modes (VEXEC, VWRITE),
27661eb4e906SKevin Crowe * so this must condense the fine-grained ACE bits into
27671eb4e906SKevin Crowe * Unix modes.
27681eb4e906SKevin Crowe *
27691eb4e906SKevin Crowe * The VEXEC flag is easy, because we know that has
27701eb4e906SKevin Crowe * always been checked before we get here (during the
27711eb4e906SKevin Crowe * lookup of the target vnode). The container has not
27721eb4e906SKevin Crowe * granted us permissions to "modify", so we do not set
27731eb4e906SKevin Crowe * the VWRITE flag in the current access mode.
27741eb4e906SKevin Crowe */
27751eb4e906SKevin Crowe owner = zfs_fuid_map_id(dzp->z_zfsvfs, dzp->z_uid, cr,
27761eb4e906SKevin Crowe ZFS_OWNER);
27771eb4e906SKevin Crowe dzp_error = secpolicy_vnode_access2(cr, ZTOV(dzp),
27781eb4e906SKevin Crowe owner, VEXEC, VWRITE|VEXEC);
27791eb4e906SKevin Crowe }
27801eb4e906SKevin Crowe if (dzp_error != 0) {
27811eb4e906SKevin Crowe /*
27821eb4e906SKevin Crowe * Note: We may have dzp_error = -1 here (from
27831eb4e906SKevin Crowe * zfs_zacess_common). Don't return that.
27841eb4e906SKevin Crowe */
27851eb4e906SKevin Crowe return (SET_ERROR(EACCES));
27861eb4e906SKevin Crowe }
27877ed7e920Smarks
2788fa9e4066Sahrens /*
27891eb4e906SKevin Crowe * At this point, we know that the directory permissions allow
27901eb4e906SKevin Crowe * us to modify, but we still need to check for the additional
27911eb4e906SKevin Crowe * restrictions that apply when the "sticky bit" is set.
27921eb4e906SKevin Crowe *
27931eb4e906SKevin Crowe * Yes, zfs_sticky_remove_access() also checks this bit, but
27941eb4e906SKevin Crowe * checking it here and skipping the call below is nice when
27951eb4e906SKevin Crowe * you're watching all of this with dtrace.
2796fa9e4066Sahrens */
27971eb4e906SKevin Crowe if ((dzp->z_mode & S_ISVTX) == 0)
27981eb4e906SKevin Crowe return (0);
2799fa9e4066Sahrens
28001eb4e906SKevin Crowe /*
28011eb4e906SKevin Crowe * zfs_sticky_remove_access will succeed if:
28021eb4e906SKevin Crowe * 1. The sticky bit is absent.
28031eb4e906SKevin Crowe * 2. We pass the sticky bit restrictions.
28041eb4e906SKevin Crowe * 3. We have privileges that always allow file removal.
28051eb4e906SKevin Crowe */
28061eb4e906SKevin Crowe return (zfs_sticky_remove_access(dzp, zp, cr));
2807fa9e4066Sahrens }
2808fa9e4066Sahrens
2809fa9e4066Sahrens int
zfs_zaccess_rename(znode_t * sdzp,znode_t * szp,znode_t * tdzp,znode_t * tzp,cred_t * cr)2810fa9e4066Sahrens zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
2811fa9e4066Sahrens znode_t *tzp, cred_t *cr)
2812fa9e4066Sahrens {
2813fa9e4066Sahrens int add_perm;
2814fa9e4066Sahrens int error;
2815fa9e4066Sahrens
28160a586ceaSMark Shellenbaum if (szp->z_pflags & ZFS_AV_QUARANTINED)
2817be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES));
2818da6c28aaSamw
2819fa9e4066Sahrens add_perm = (ZTOV(szp)->v_type == VDIR) ?
2820fa9e4066Sahrens ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE;
2821fa9e4066Sahrens
2822fa9e4066Sahrens /*
2823fa9e4066Sahrens * Rename permissions are combination of delete permission +
2824fa9e4066Sahrens * add file/subdir permission.
2825fa9e4066Sahrens */
2826fa9e4066Sahrens
2827fa9e4066Sahrens /*
2828fa9e4066Sahrens * first make sure we do the delete portion.
2829fa9e4066Sahrens *
2830fa9e4066Sahrens * If that succeeds then check for add_file/add_subdir permissions
2831fa9e4066Sahrens */
2832fa9e4066Sahrens
2833fa9e4066Sahrens if (error = zfs_zaccess_delete(sdzp, szp, cr))
2834fa9e4066Sahrens return (error);
2835fa9e4066Sahrens
2836fa9e4066Sahrens /*
2837fa9e4066Sahrens * If we have a tzp, see if we can delete it?
2838fa9e4066Sahrens */
2839fa9e4066Sahrens if (tzp) {
2840fa9e4066Sahrens if (error = zfs_zaccess_delete(tdzp, tzp, cr))
2841fa9e4066Sahrens return (error);
2842fa9e4066Sahrens }
2843fa9e4066Sahrens
2844fa9e4066Sahrens /*
2845fa9e4066Sahrens * Now check for add permissions
2846fa9e4066Sahrens */
2847da6c28aaSamw error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr);
2848fa9e4066Sahrens
2849fa9e4066Sahrens return (error);
2850fa9e4066Sahrens }
2851