1eda14cbcSMatt Macy /*
2eda14cbcSMatt Macy * CDDL HEADER START
3eda14cbcSMatt Macy *
4eda14cbcSMatt Macy * The contents of this file are subject to the terms of the
5eda14cbcSMatt Macy * Common Development and Distribution License (the "License").
6eda14cbcSMatt Macy * You may not use this file except in compliance with the License.
7eda14cbcSMatt Macy *
8eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9271171e0SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0.
10eda14cbcSMatt Macy * See the License for the specific language governing permissions
11eda14cbcSMatt Macy * and limitations under the License.
12eda14cbcSMatt Macy *
13eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each
14eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the
16eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying
17eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner]
18eda14cbcSMatt Macy *
19eda14cbcSMatt Macy * CDDL HEADER END
20eda14cbcSMatt Macy */
21eda14cbcSMatt Macy /*
22eda14cbcSMatt Macy * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23eda14cbcSMatt Macy * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
24eda14cbcSMatt Macy */
25eda14cbcSMatt Macy
26eda14cbcSMatt Macy #include <sys/types.h>
27eda14cbcSMatt Macy #include <sys/stat.h>
28eda14cbcSMatt Macy #include <sys/avl.h>
29eda14cbcSMatt Macy #include <sys/misc.h>
30eda14cbcSMatt Macy #if defined(_KERNEL)
31eda14cbcSMatt Macy #include <sys/kmem.h>
32eda14cbcSMatt Macy #include <sys/systm.h>
33eda14cbcSMatt Macy #include <sys/sysmacros.h>
34eda14cbcSMatt Macy #include <acl/acl_common.h>
35eda14cbcSMatt Macy #include <sys/debug.h>
36eda14cbcSMatt Macy #else
37eda14cbcSMatt Macy #include <errno.h>
38eda14cbcSMatt Macy #include <stdlib.h>
39eda14cbcSMatt Macy #include <stddef.h>
40eda14cbcSMatt Macy #include <unistd.h>
41eda14cbcSMatt Macy #include <assert.h>
42eda14cbcSMatt Macy #include <grp.h>
43eda14cbcSMatt Macy #include <pwd.h>
44eda14cbcSMatt Macy #include <acl_common.h>
45eda14cbcSMatt Macy #endif
46eda14cbcSMatt Macy
47eda14cbcSMatt Macy #define ACE_POSIX_SUPPORTED_BITS (ACE_READ_DATA | \
48eda14cbcSMatt Macy ACE_WRITE_DATA | ACE_APPEND_DATA | ACE_EXECUTE | \
49eda14cbcSMatt Macy ACE_READ_ATTRIBUTES | ACE_READ_ACL | ACE_WRITE_ACL)
50eda14cbcSMatt Macy
51eda14cbcSMatt Macy
52eda14cbcSMatt Macy #define ACL_SYNCHRONIZE_SET_DENY 0x0000001
53eda14cbcSMatt Macy #define ACL_SYNCHRONIZE_SET_ALLOW 0x0000002
54eda14cbcSMatt Macy #define ACL_SYNCHRONIZE_ERR_DENY 0x0000004
55eda14cbcSMatt Macy #define ACL_SYNCHRONIZE_ERR_ALLOW 0x0000008
56eda14cbcSMatt Macy
57eda14cbcSMatt Macy #define ACL_WRITE_OWNER_SET_DENY 0x0000010
58eda14cbcSMatt Macy #define ACL_WRITE_OWNER_SET_ALLOW 0x0000020
59eda14cbcSMatt Macy #define ACL_WRITE_OWNER_ERR_DENY 0x0000040
60eda14cbcSMatt Macy #define ACL_WRITE_OWNER_ERR_ALLOW 0x0000080
61eda14cbcSMatt Macy
62eda14cbcSMatt Macy #define ACL_DELETE_SET_DENY 0x0000100
63eda14cbcSMatt Macy #define ACL_DELETE_SET_ALLOW 0x0000200
64eda14cbcSMatt Macy #define ACL_DELETE_ERR_DENY 0x0000400
65eda14cbcSMatt Macy #define ACL_DELETE_ERR_ALLOW 0x0000800
66eda14cbcSMatt Macy
67eda14cbcSMatt Macy #define ACL_WRITE_ATTRS_OWNER_SET_DENY 0x0001000
68eda14cbcSMatt Macy #define ACL_WRITE_ATTRS_OWNER_SET_ALLOW 0x0002000
69eda14cbcSMatt Macy #define ACL_WRITE_ATTRS_OWNER_ERR_DENY 0x0004000
70eda14cbcSMatt Macy #define ACL_WRITE_ATTRS_OWNER_ERR_ALLOW 0x0008000
71eda14cbcSMatt Macy
72eda14cbcSMatt Macy #define ACL_WRITE_ATTRS_WRITER_SET_DENY 0x0010000
73eda14cbcSMatt Macy #define ACL_WRITE_ATTRS_WRITER_SET_ALLOW 0x0020000
74eda14cbcSMatt Macy #define ACL_WRITE_ATTRS_WRITER_ERR_DENY 0x0040000
75eda14cbcSMatt Macy #define ACL_WRITE_ATTRS_WRITER_ERR_ALLOW 0x0080000
76eda14cbcSMatt Macy
77eda14cbcSMatt Macy #define ACL_WRITE_NAMED_WRITER_SET_DENY 0x0100000
78eda14cbcSMatt Macy #define ACL_WRITE_NAMED_WRITER_SET_ALLOW 0x0200000
79eda14cbcSMatt Macy #define ACL_WRITE_NAMED_WRITER_ERR_DENY 0x0400000
80eda14cbcSMatt Macy #define ACL_WRITE_NAMED_WRITER_ERR_ALLOW 0x0800000
81eda14cbcSMatt Macy
82eda14cbcSMatt Macy #define ACL_READ_NAMED_READER_SET_DENY 0x1000000
83eda14cbcSMatt Macy #define ACL_READ_NAMED_READER_SET_ALLOW 0x2000000
84eda14cbcSMatt Macy #define ACL_READ_NAMED_READER_ERR_DENY 0x4000000
85eda14cbcSMatt Macy #define ACL_READ_NAMED_READER_ERR_ALLOW 0x8000000
86eda14cbcSMatt Macy
87eda14cbcSMatt Macy
88eda14cbcSMatt Macy #define ACE_VALID_MASK_BITS (\
89eda14cbcSMatt Macy ACE_READ_DATA | \
90eda14cbcSMatt Macy ACE_LIST_DIRECTORY | \
91eda14cbcSMatt Macy ACE_WRITE_DATA | \
92eda14cbcSMatt Macy ACE_ADD_FILE | \
93eda14cbcSMatt Macy ACE_APPEND_DATA | \
94eda14cbcSMatt Macy ACE_ADD_SUBDIRECTORY | \
95eda14cbcSMatt Macy ACE_READ_NAMED_ATTRS | \
96eda14cbcSMatt Macy ACE_WRITE_NAMED_ATTRS | \
97eda14cbcSMatt Macy ACE_EXECUTE | \
98eda14cbcSMatt Macy ACE_DELETE_CHILD | \
99eda14cbcSMatt Macy ACE_READ_ATTRIBUTES | \
100eda14cbcSMatt Macy ACE_WRITE_ATTRIBUTES | \
101eda14cbcSMatt Macy ACE_DELETE | \
102eda14cbcSMatt Macy ACE_READ_ACL | \
103eda14cbcSMatt Macy ACE_WRITE_ACL | \
104eda14cbcSMatt Macy ACE_WRITE_OWNER | \
105eda14cbcSMatt Macy ACE_SYNCHRONIZE)
106eda14cbcSMatt Macy
107eda14cbcSMatt Macy #define ACE_MASK_UNDEFINED 0x80000000
108eda14cbcSMatt Macy
109eda14cbcSMatt Macy #define ACE_VALID_FLAG_BITS (ACE_FILE_INHERIT_ACE | \
110eda14cbcSMatt Macy ACE_DIRECTORY_INHERIT_ACE | \
111eda14cbcSMatt Macy ACE_NO_PROPAGATE_INHERIT_ACE | ACE_INHERIT_ONLY_ACE | \
112eda14cbcSMatt Macy ACE_SUCCESSFUL_ACCESS_ACE_FLAG | ACE_FAILED_ACCESS_ACE_FLAG | \
113eda14cbcSMatt Macy ACE_IDENTIFIER_GROUP | ACE_OWNER | ACE_GROUP | ACE_EVERYONE)
114eda14cbcSMatt Macy
115eda14cbcSMatt Macy /*
116eda14cbcSMatt Macy * ACL conversion helpers
117eda14cbcSMatt Macy */
118eda14cbcSMatt Macy
119eda14cbcSMatt Macy typedef enum {
120eda14cbcSMatt Macy ace_unused,
121eda14cbcSMatt Macy ace_user_obj,
122eda14cbcSMatt Macy ace_user,
123eda14cbcSMatt Macy ace_group, /* includes GROUP and GROUP_OBJ */
124eda14cbcSMatt Macy ace_other_obj
125eda14cbcSMatt Macy } ace_to_aent_state_t;
126eda14cbcSMatt Macy
127eda14cbcSMatt Macy typedef struct acevals {
128eda14cbcSMatt Macy uid_t key;
129eda14cbcSMatt Macy avl_node_t avl;
130eda14cbcSMatt Macy uint32_t mask;
131eda14cbcSMatt Macy uint32_t allowed;
132eda14cbcSMatt Macy uint32_t denied;
133eda14cbcSMatt Macy int aent_type;
134eda14cbcSMatt Macy } acevals_t;
135eda14cbcSMatt Macy
136eda14cbcSMatt Macy typedef struct ace_list {
137eda14cbcSMatt Macy acevals_t user_obj;
138eda14cbcSMatt Macy avl_tree_t user;
139eda14cbcSMatt Macy int numusers;
140eda14cbcSMatt Macy acevals_t group_obj;
141eda14cbcSMatt Macy avl_tree_t group;
142eda14cbcSMatt Macy int numgroups;
143eda14cbcSMatt Macy acevals_t other_obj;
144eda14cbcSMatt Macy uint32_t acl_mask;
145eda14cbcSMatt Macy int hasmask;
146eda14cbcSMatt Macy int dfacl_flag;
147eda14cbcSMatt Macy ace_to_aent_state_t state;
148eda14cbcSMatt Macy int seen; /* bitmask of all aclent_t a_type values seen */
149eda14cbcSMatt Macy } ace_list_t;
150eda14cbcSMatt Macy
151eda14cbcSMatt Macy /*
152eda14cbcSMatt Macy * Generic shellsort, from K&R (1st ed, p 58.), somewhat modified.
153eda14cbcSMatt Macy * v = Ptr to array/vector of objs
154eda14cbcSMatt Macy * n = # objs in the array
155eda14cbcSMatt Macy * s = size of each obj (must be multiples of a word size)
156eda14cbcSMatt Macy * f = ptr to function to compare two objs
157eda14cbcSMatt Macy * returns (-1 = less than, 0 = equal, 1 = greater than
158eda14cbcSMatt Macy */
159eda14cbcSMatt Macy void
ksort(caddr_t v,int n,int s,int (* f)(void *,void *))160eda14cbcSMatt Macy ksort(caddr_t v, int n, int s, int (*f)(void *, void *))
161eda14cbcSMatt Macy {
162eda14cbcSMatt Macy int g, i, j, ii;
163eda14cbcSMatt Macy unsigned int *p1, *p2;
164eda14cbcSMatt Macy unsigned int tmp;
165eda14cbcSMatt Macy
166eda14cbcSMatt Macy /* No work to do */
167eda14cbcSMatt Macy if (v == NULL || n <= 1)
168eda14cbcSMatt Macy return;
169eda14cbcSMatt Macy
170eda14cbcSMatt Macy /* Sanity check on arguments */
17116038816SMartin Matuska ASSERT3U(((uintptr_t)v & 0x3), ==, 0);
17216038816SMartin Matuska ASSERT3S((s & 0x3), ==, 0);
17316038816SMartin Matuska ASSERT3S(s, >, 0);
174eda14cbcSMatt Macy for (g = n / 2; g > 0; g /= 2) {
175eda14cbcSMatt Macy for (i = g; i < n; i++) {
176eda14cbcSMatt Macy for (j = i - g; j >= 0 &&
177eda14cbcSMatt Macy (*f)(v + j * s, v + (j + g) * s) == 1;
178eda14cbcSMatt Macy j -= g) {
179eda14cbcSMatt Macy p1 = (void *)(v + j * s);
180eda14cbcSMatt Macy p2 = (void *)(v + (j + g) * s);
181eda14cbcSMatt Macy for (ii = 0; ii < s / 4; ii++) {
182eda14cbcSMatt Macy tmp = *p1;
183eda14cbcSMatt Macy *p1++ = *p2;
184eda14cbcSMatt Macy *p2++ = tmp;
185eda14cbcSMatt Macy }
186eda14cbcSMatt Macy }
187eda14cbcSMatt Macy }
188eda14cbcSMatt Macy }
189eda14cbcSMatt Macy }
190eda14cbcSMatt Macy
191eda14cbcSMatt Macy /*
192eda14cbcSMatt Macy * Compare two acls, all fields. Returns:
193eda14cbcSMatt Macy * -1 (less than)
194eda14cbcSMatt Macy * 0 (equal)
195eda14cbcSMatt Macy * +1 (greater than)
196eda14cbcSMatt Macy */
197eda14cbcSMatt Macy int
cmp2acls(void * a,void * b)198eda14cbcSMatt Macy cmp2acls(void *a, void *b)
199eda14cbcSMatt Macy {
200eda14cbcSMatt Macy aclent_t *x = (aclent_t *)a;
201eda14cbcSMatt Macy aclent_t *y = (aclent_t *)b;
202eda14cbcSMatt Macy
203eda14cbcSMatt Macy /* Compare types */
204eda14cbcSMatt Macy if (x->a_type < y->a_type)
205eda14cbcSMatt Macy return (-1);
206eda14cbcSMatt Macy if (x->a_type > y->a_type)
207eda14cbcSMatt Macy return (1);
208eda14cbcSMatt Macy /* Equal types; compare id's */
209eda14cbcSMatt Macy if (x->a_id < y->a_id)
210eda14cbcSMatt Macy return (-1);
211eda14cbcSMatt Macy if (x->a_id > y->a_id)
212eda14cbcSMatt Macy return (1);
213eda14cbcSMatt Macy /* Equal ids; compare perms */
214eda14cbcSMatt Macy if (x->a_perm < y->a_perm)
215eda14cbcSMatt Macy return (-1);
216eda14cbcSMatt Macy if (x->a_perm > y->a_perm)
217eda14cbcSMatt Macy return (1);
218eda14cbcSMatt Macy /* Totally equal */
219eda14cbcSMatt Macy return (0);
220eda14cbcSMatt Macy }
221eda14cbcSMatt Macy
222eda14cbcSMatt Macy static int
cacl_malloc(void ** ptr,size_t size)223eda14cbcSMatt Macy cacl_malloc(void **ptr, size_t size)
224eda14cbcSMatt Macy {
225eda14cbcSMatt Macy *ptr = kmem_zalloc(size, KM_SLEEP);
226eda14cbcSMatt Macy return (0);
227eda14cbcSMatt Macy }
228eda14cbcSMatt Macy
229eda14cbcSMatt Macy
230eda14cbcSMatt Macy #if !defined(_KERNEL)
231eda14cbcSMatt Macy acl_t *
acl_alloc(enum acl_type type)232eda14cbcSMatt Macy acl_alloc(enum acl_type type)
233eda14cbcSMatt Macy {
234eda14cbcSMatt Macy acl_t *aclp;
235eda14cbcSMatt Macy
236eda14cbcSMatt Macy if (cacl_malloc((void **)&aclp, sizeof (acl_t)) != 0)
237eda14cbcSMatt Macy return (NULL);
238eda14cbcSMatt Macy
239eda14cbcSMatt Macy aclp->acl_aclp = NULL;
240eda14cbcSMatt Macy aclp->acl_cnt = 0;
241eda14cbcSMatt Macy
242eda14cbcSMatt Macy switch (type) {
243eda14cbcSMatt Macy case ACE_T:
244eda14cbcSMatt Macy aclp->acl_type = ACE_T;
245eda14cbcSMatt Macy aclp->acl_entry_size = sizeof (ace_t);
246eda14cbcSMatt Macy break;
247eda14cbcSMatt Macy case ACLENT_T:
248eda14cbcSMatt Macy aclp->acl_type = ACLENT_T;
249eda14cbcSMatt Macy aclp->acl_entry_size = sizeof (aclent_t);
250eda14cbcSMatt Macy break;
251eda14cbcSMatt Macy default:
252eda14cbcSMatt Macy acl_free(aclp);
253eda14cbcSMatt Macy aclp = NULL;
254eda14cbcSMatt Macy }
255eda14cbcSMatt Macy return (aclp);
256eda14cbcSMatt Macy }
257eda14cbcSMatt Macy
258eda14cbcSMatt Macy /*
259eda14cbcSMatt Macy * Free acl_t structure
260eda14cbcSMatt Macy */
261eda14cbcSMatt Macy void
acl_free(acl_t * aclp)262eda14cbcSMatt Macy acl_free(acl_t *aclp)
263eda14cbcSMatt Macy {
264eda14cbcSMatt Macy int acl_size;
265eda14cbcSMatt Macy
266eda14cbcSMatt Macy if (aclp == NULL)
267eda14cbcSMatt Macy return;
268eda14cbcSMatt Macy
269eda14cbcSMatt Macy if (aclp->acl_aclp) {
270eda14cbcSMatt Macy acl_size = aclp->acl_cnt * aclp->acl_entry_size;
271eda14cbcSMatt Macy cacl_free(aclp->acl_aclp, acl_size);
272eda14cbcSMatt Macy }
273eda14cbcSMatt Macy
274eda14cbcSMatt Macy cacl_free(aclp, sizeof (acl_t));
275eda14cbcSMatt Macy }
276eda14cbcSMatt Macy
277eda14cbcSMatt Macy static uint32_t
access_mask_set(int haswriteperm,int hasreadperm,int isowner,int isallow)278eda14cbcSMatt Macy access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow)
279eda14cbcSMatt Macy {
280eda14cbcSMatt Macy uint32_t access_mask = 0;
281eda14cbcSMatt Macy int acl_produce;
282eda14cbcSMatt Macy int synchronize_set = 0, write_owner_set = 0;
283eda14cbcSMatt Macy int delete_set = 0, write_attrs_set = 0;
284eda14cbcSMatt Macy int read_named_set = 0, write_named_set = 0;
285eda14cbcSMatt Macy
286eda14cbcSMatt Macy acl_produce = (ACL_SYNCHRONIZE_SET_ALLOW |
287eda14cbcSMatt Macy ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
288eda14cbcSMatt Macy ACL_WRITE_ATTRS_WRITER_SET_DENY);
289eda14cbcSMatt Macy
290eda14cbcSMatt Macy if (isallow) {
291eda14cbcSMatt Macy synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW;
292eda14cbcSMatt Macy write_owner_set = ACL_WRITE_OWNER_SET_ALLOW;
293eda14cbcSMatt Macy delete_set = ACL_DELETE_SET_ALLOW;
294eda14cbcSMatt Macy if (hasreadperm)
295eda14cbcSMatt Macy read_named_set = ACL_READ_NAMED_READER_SET_ALLOW;
296eda14cbcSMatt Macy if (haswriteperm)
297eda14cbcSMatt Macy write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW;
298eda14cbcSMatt Macy if (isowner)
299eda14cbcSMatt Macy write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW;
300eda14cbcSMatt Macy else if (haswriteperm)
301eda14cbcSMatt Macy write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW;
302eda14cbcSMatt Macy } else {
303eda14cbcSMatt Macy
304eda14cbcSMatt Macy synchronize_set = ACL_SYNCHRONIZE_SET_DENY;
305eda14cbcSMatt Macy write_owner_set = ACL_WRITE_OWNER_SET_DENY;
306eda14cbcSMatt Macy delete_set = ACL_DELETE_SET_DENY;
307eda14cbcSMatt Macy if (hasreadperm)
308eda14cbcSMatt Macy read_named_set = ACL_READ_NAMED_READER_SET_DENY;
309eda14cbcSMatt Macy if (haswriteperm)
310eda14cbcSMatt Macy write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY;
311eda14cbcSMatt Macy if (isowner)
312eda14cbcSMatt Macy write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY;
313eda14cbcSMatt Macy else if (haswriteperm)
314eda14cbcSMatt Macy write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY;
315eda14cbcSMatt Macy else
316eda14cbcSMatt Macy /*
317eda14cbcSMatt Macy * If the entity is not the owner and does not
318eda14cbcSMatt Macy * have write permissions ACE_WRITE_ATTRIBUTES will
319eda14cbcSMatt Macy * always go in the DENY ACE.
320eda14cbcSMatt Macy */
321eda14cbcSMatt Macy access_mask |= ACE_WRITE_ATTRIBUTES;
322eda14cbcSMatt Macy }
323eda14cbcSMatt Macy
324eda14cbcSMatt Macy if (acl_produce & synchronize_set)
325eda14cbcSMatt Macy access_mask |= ACE_SYNCHRONIZE;
326eda14cbcSMatt Macy if (acl_produce & write_owner_set)
327eda14cbcSMatt Macy access_mask |= ACE_WRITE_OWNER;
328eda14cbcSMatt Macy if (acl_produce & delete_set)
329eda14cbcSMatt Macy access_mask |= ACE_DELETE;
330eda14cbcSMatt Macy if (acl_produce & write_attrs_set)
331eda14cbcSMatt Macy access_mask |= ACE_WRITE_ATTRIBUTES;
332eda14cbcSMatt Macy if (acl_produce & read_named_set)
333eda14cbcSMatt Macy access_mask |= ACE_READ_NAMED_ATTRS;
334eda14cbcSMatt Macy if (acl_produce & write_named_set)
335eda14cbcSMatt Macy access_mask |= ACE_WRITE_NAMED_ATTRS;
336eda14cbcSMatt Macy
337eda14cbcSMatt Macy return (access_mask);
338eda14cbcSMatt Macy }
339eda14cbcSMatt Macy
340eda14cbcSMatt Macy /*
341eda14cbcSMatt Macy * Given an mode_t, convert it into an access_mask as used
342eda14cbcSMatt Macy * by nfsace, assuming aclent_t -> nfsace semantics.
343eda14cbcSMatt Macy */
344eda14cbcSMatt Macy static uint32_t
mode_to_ace_access(mode_t mode,boolean_t isdir,int isowner,int isallow)345eda14cbcSMatt Macy mode_to_ace_access(mode_t mode, boolean_t isdir, int isowner, int isallow)
346eda14cbcSMatt Macy {
347eda14cbcSMatt Macy uint32_t access = 0;
348eda14cbcSMatt Macy int haswriteperm = 0;
349eda14cbcSMatt Macy int hasreadperm = 0;
350eda14cbcSMatt Macy
351eda14cbcSMatt Macy if (isallow) {
352eda14cbcSMatt Macy haswriteperm = (mode & S_IWOTH);
353eda14cbcSMatt Macy hasreadperm = (mode & S_IROTH);
354eda14cbcSMatt Macy } else {
355eda14cbcSMatt Macy haswriteperm = !(mode & S_IWOTH);
356eda14cbcSMatt Macy hasreadperm = !(mode & S_IROTH);
357eda14cbcSMatt Macy }
358eda14cbcSMatt Macy
359eda14cbcSMatt Macy /*
360eda14cbcSMatt Macy * The following call takes care of correctly setting the following
361eda14cbcSMatt Macy * mask bits in the access_mask:
362eda14cbcSMatt Macy * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE,
363eda14cbcSMatt Macy * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS
364eda14cbcSMatt Macy */
365eda14cbcSMatt Macy access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow);
366eda14cbcSMatt Macy
367eda14cbcSMatt Macy if (isallow) {
368eda14cbcSMatt Macy access |= ACE_READ_ACL | ACE_READ_ATTRIBUTES;
369eda14cbcSMatt Macy if (isowner)
370eda14cbcSMatt Macy access |= ACE_WRITE_ACL;
371eda14cbcSMatt Macy } else {
372eda14cbcSMatt Macy if (! isowner)
373eda14cbcSMatt Macy access |= ACE_WRITE_ACL;
374eda14cbcSMatt Macy }
375eda14cbcSMatt Macy
376eda14cbcSMatt Macy /* read */
377eda14cbcSMatt Macy if (mode & S_IROTH) {
378eda14cbcSMatt Macy access |= ACE_READ_DATA;
379eda14cbcSMatt Macy }
380eda14cbcSMatt Macy /* write */
381eda14cbcSMatt Macy if (mode & S_IWOTH) {
382eda14cbcSMatt Macy access |= ACE_WRITE_DATA |
383eda14cbcSMatt Macy ACE_APPEND_DATA;
384eda14cbcSMatt Macy if (isdir)
385eda14cbcSMatt Macy access |= ACE_DELETE_CHILD;
386eda14cbcSMatt Macy }
387eda14cbcSMatt Macy /* exec */
388eda14cbcSMatt Macy if (mode & S_IXOTH) {
389eda14cbcSMatt Macy access |= ACE_EXECUTE;
390eda14cbcSMatt Macy }
391eda14cbcSMatt Macy
392eda14cbcSMatt Macy return (access);
393eda14cbcSMatt Macy }
394eda14cbcSMatt Macy
395eda14cbcSMatt Macy /*
396eda14cbcSMatt Macy * Given an nfsace (presumably an ALLOW entry), make a
397eda14cbcSMatt Macy * corresponding DENY entry at the address given.
398eda14cbcSMatt Macy */
399eda14cbcSMatt Macy static void
ace_make_deny(ace_t * allow,ace_t * deny,int isdir,int isowner)400eda14cbcSMatt Macy ace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner)
401eda14cbcSMatt Macy {
402eda14cbcSMatt Macy (void) memcpy(deny, allow, sizeof (ace_t));
403eda14cbcSMatt Macy
404eda14cbcSMatt Macy deny->a_who = allow->a_who;
405eda14cbcSMatt Macy
406eda14cbcSMatt Macy deny->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
407eda14cbcSMatt Macy deny->a_access_mask ^= ACE_POSIX_SUPPORTED_BITS;
408eda14cbcSMatt Macy if (isdir)
409eda14cbcSMatt Macy deny->a_access_mask ^= ACE_DELETE_CHILD;
410eda14cbcSMatt Macy
411eda14cbcSMatt Macy deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER |
412eda14cbcSMatt Macy ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
413eda14cbcSMatt Macy ACE_WRITE_NAMED_ATTRS);
414eda14cbcSMatt Macy deny->a_access_mask |= access_mask_set((allow->a_access_mask &
415eda14cbcSMatt Macy ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner,
416eda14cbcSMatt Macy B_FALSE);
417eda14cbcSMatt Macy }
418eda14cbcSMatt Macy /*
419eda14cbcSMatt Macy * Make an initial pass over an array of aclent_t's. Gather
420eda14cbcSMatt Macy * information such as an ACL_MASK (if any), number of users,
421eda14cbcSMatt Macy * number of groups, and whether the array needs to be sorted.
422eda14cbcSMatt Macy */
423eda14cbcSMatt Macy static int
ln_aent_preprocess(aclent_t * aclent,int n,int * hasmask,mode_t * mask,int * numuser,int * numgroup,int * needsort)424eda14cbcSMatt Macy ln_aent_preprocess(aclent_t *aclent, int n,
425eda14cbcSMatt Macy int *hasmask, mode_t *mask,
426eda14cbcSMatt Macy int *numuser, int *numgroup, int *needsort)
427eda14cbcSMatt Macy {
428eda14cbcSMatt Macy int error = 0;
429eda14cbcSMatt Macy int i;
430eda14cbcSMatt Macy int curtype = 0;
431eda14cbcSMatt Macy
432eda14cbcSMatt Macy *hasmask = 0;
433eda14cbcSMatt Macy *mask = 07;
434eda14cbcSMatt Macy *needsort = 0;
435eda14cbcSMatt Macy *numuser = 0;
436eda14cbcSMatt Macy *numgroup = 0;
437eda14cbcSMatt Macy
438eda14cbcSMatt Macy for (i = 0; i < n; i++) {
439eda14cbcSMatt Macy if (aclent[i].a_type < curtype)
440eda14cbcSMatt Macy *needsort = 1;
441eda14cbcSMatt Macy else if (aclent[i].a_type > curtype)
442eda14cbcSMatt Macy curtype = aclent[i].a_type;
443eda14cbcSMatt Macy if (aclent[i].a_type & USER)
444eda14cbcSMatt Macy (*numuser)++;
445eda14cbcSMatt Macy if (aclent[i].a_type & (GROUP | GROUP_OBJ))
446eda14cbcSMatt Macy (*numgroup)++;
447eda14cbcSMatt Macy if (aclent[i].a_type & CLASS_OBJ) {
448eda14cbcSMatt Macy if (*hasmask) {
449eda14cbcSMatt Macy error = EINVAL;
450eda14cbcSMatt Macy goto out;
451eda14cbcSMatt Macy } else {
452eda14cbcSMatt Macy *hasmask = 1;
453eda14cbcSMatt Macy *mask = aclent[i].a_perm;
454eda14cbcSMatt Macy }
455eda14cbcSMatt Macy }
456eda14cbcSMatt Macy }
457eda14cbcSMatt Macy
458eda14cbcSMatt Macy if ((! *hasmask) && (*numuser + *numgroup > 1)) {
459eda14cbcSMatt Macy error = EINVAL;
460eda14cbcSMatt Macy goto out;
461eda14cbcSMatt Macy }
462eda14cbcSMatt Macy
463eda14cbcSMatt Macy out:
464eda14cbcSMatt Macy return (error);
465eda14cbcSMatt Macy }
466eda14cbcSMatt Macy
467eda14cbcSMatt Macy /*
468eda14cbcSMatt Macy * Convert an array of aclent_t into an array of nfsace entries,
469eda14cbcSMatt Macy * following POSIX draft -> nfsv4 conversion semantics as outlined in
470eda14cbcSMatt Macy * the IETF draft.
471eda14cbcSMatt Macy */
472eda14cbcSMatt Macy static int
ln_aent_to_ace(aclent_t * aclent,int n,ace_t ** acepp,int * rescount,int isdir)473eda14cbcSMatt Macy ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir)
474eda14cbcSMatt Macy {
475eda14cbcSMatt Macy int error = 0;
476eda14cbcSMatt Macy mode_t mask;
477eda14cbcSMatt Macy int numuser, numgroup, needsort;
478eda14cbcSMatt Macy int resultsize = 0;
479eda14cbcSMatt Macy int i, groupi = 0, skip;
480eda14cbcSMatt Macy ace_t *acep, *result = NULL;
481eda14cbcSMatt Macy int hasmask;
482eda14cbcSMatt Macy
483eda14cbcSMatt Macy error = ln_aent_preprocess(aclent, n, &hasmask, &mask,
484eda14cbcSMatt Macy &numuser, &numgroup, &needsort);
485eda14cbcSMatt Macy if (error != 0)
486eda14cbcSMatt Macy goto out;
487eda14cbcSMatt Macy
488eda14cbcSMatt Macy /* allow + deny for each aclent */
489eda14cbcSMatt Macy resultsize = n * 2;
490eda14cbcSMatt Macy if (hasmask) {
491eda14cbcSMatt Macy /*
492eda14cbcSMatt Macy * stick extra deny on the group_obj and on each
493eda14cbcSMatt Macy * user|group for the mask (the group_obj was added
494eda14cbcSMatt Macy * into the count for numgroup)
495eda14cbcSMatt Macy */
496eda14cbcSMatt Macy resultsize += numuser + numgroup;
497eda14cbcSMatt Macy /* ... and don't count the mask itself */
498eda14cbcSMatt Macy resultsize -= 2;
499eda14cbcSMatt Macy }
500eda14cbcSMatt Macy
501eda14cbcSMatt Macy /* sort the source if necessary */
502eda14cbcSMatt Macy if (needsort)
503eda14cbcSMatt Macy ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls);
504eda14cbcSMatt Macy
505eda14cbcSMatt Macy if (cacl_malloc((void **)&result, resultsize * sizeof (ace_t)) != 0)
506eda14cbcSMatt Macy goto out;
507eda14cbcSMatt Macy
508eda14cbcSMatt Macy acep = result;
509eda14cbcSMatt Macy
510eda14cbcSMatt Macy for (i = 0; i < n; i++) {
511eda14cbcSMatt Macy /*
512eda14cbcSMatt Macy * don't process CLASS_OBJ (mask); mask was grabbed in
513eda14cbcSMatt Macy * ln_aent_preprocess()
514eda14cbcSMatt Macy */
515eda14cbcSMatt Macy if (aclent[i].a_type & CLASS_OBJ)
516eda14cbcSMatt Macy continue;
517eda14cbcSMatt Macy
518eda14cbcSMatt Macy /* If we need an ACL_MASK emulator, prepend it now */
519eda14cbcSMatt Macy if ((hasmask) &&
520eda14cbcSMatt Macy (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) {
521eda14cbcSMatt Macy acep->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
522eda14cbcSMatt Macy acep->a_flags = 0;
523eda14cbcSMatt Macy if (aclent[i].a_type & GROUP_OBJ) {
524eda14cbcSMatt Macy acep->a_who = (uid_t)-1;
525eda14cbcSMatt Macy acep->a_flags |=
526eda14cbcSMatt Macy (ACE_IDENTIFIER_GROUP|ACE_GROUP);
527eda14cbcSMatt Macy } else if (aclent[i].a_type & USER) {
528eda14cbcSMatt Macy acep->a_who = aclent[i].a_id;
529eda14cbcSMatt Macy } else {
530eda14cbcSMatt Macy acep->a_who = aclent[i].a_id;
531eda14cbcSMatt Macy acep->a_flags |= ACE_IDENTIFIER_GROUP;
532eda14cbcSMatt Macy }
533eda14cbcSMatt Macy if (aclent[i].a_type & ACL_DEFAULT) {
534eda14cbcSMatt Macy acep->a_flags |= ACE_INHERIT_ONLY_ACE |
535eda14cbcSMatt Macy ACE_FILE_INHERIT_ACE |
536eda14cbcSMatt Macy ACE_DIRECTORY_INHERIT_ACE;
537eda14cbcSMatt Macy }
538eda14cbcSMatt Macy /*
539eda14cbcSMatt Macy * Set the access mask for the prepended deny
540eda14cbcSMatt Macy * ace. To do this, we invert the mask (found
541eda14cbcSMatt Macy * in ln_aent_preprocess()) then convert it to an
542eda14cbcSMatt Macy * DENY ace access_mask.
543eda14cbcSMatt Macy */
544eda14cbcSMatt Macy acep->a_access_mask = mode_to_ace_access((mask ^ 07),
545eda14cbcSMatt Macy isdir, 0, 0);
546eda14cbcSMatt Macy acep += 1;
547eda14cbcSMatt Macy }
548eda14cbcSMatt Macy
549eda14cbcSMatt Macy /* handle a_perm -> access_mask */
550eda14cbcSMatt Macy acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm,
551eda14cbcSMatt Macy isdir, aclent[i].a_type & USER_OBJ, 1);
552eda14cbcSMatt Macy
553eda14cbcSMatt Macy /* emulate a default aclent */
554eda14cbcSMatt Macy if (aclent[i].a_type & ACL_DEFAULT) {
555eda14cbcSMatt Macy acep->a_flags |= ACE_INHERIT_ONLY_ACE |
556eda14cbcSMatt Macy ACE_FILE_INHERIT_ACE |
557eda14cbcSMatt Macy ACE_DIRECTORY_INHERIT_ACE;
558eda14cbcSMatt Macy }
559eda14cbcSMatt Macy
560eda14cbcSMatt Macy /*
561eda14cbcSMatt Macy * handle a_perm and a_id
562eda14cbcSMatt Macy *
563eda14cbcSMatt Macy * this must be done last, since it involves the
564eda14cbcSMatt Macy * corresponding deny aces, which are handled
565eda14cbcSMatt Macy * differently for each different a_type.
566eda14cbcSMatt Macy */
567eda14cbcSMatt Macy if (aclent[i].a_type & USER_OBJ) {
568eda14cbcSMatt Macy acep->a_who = (uid_t)-1;
569eda14cbcSMatt Macy acep->a_flags |= ACE_OWNER;
570eda14cbcSMatt Macy ace_make_deny(acep, acep + 1, isdir, B_TRUE);
571eda14cbcSMatt Macy acep += 2;
572eda14cbcSMatt Macy } else if (aclent[i].a_type & USER) {
573eda14cbcSMatt Macy acep->a_who = aclent[i].a_id;
574eda14cbcSMatt Macy ace_make_deny(acep, acep + 1, isdir, B_FALSE);
575eda14cbcSMatt Macy acep += 2;
576eda14cbcSMatt Macy } else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) {
577eda14cbcSMatt Macy if (aclent[i].a_type & GROUP_OBJ) {
578eda14cbcSMatt Macy acep->a_who = (uid_t)-1;
579eda14cbcSMatt Macy acep->a_flags |= ACE_GROUP;
580eda14cbcSMatt Macy } else {
581eda14cbcSMatt Macy acep->a_who = aclent[i].a_id;
582eda14cbcSMatt Macy }
583eda14cbcSMatt Macy acep->a_flags |= ACE_IDENTIFIER_GROUP;
584eda14cbcSMatt Macy /*
585eda14cbcSMatt Macy * Set the corresponding deny for the group ace.
586eda14cbcSMatt Macy *
587eda14cbcSMatt Macy * The deny aces go after all of the groups, unlike
588eda14cbcSMatt Macy * everything else, where they immediately follow
589eda14cbcSMatt Macy * the allow ace.
590eda14cbcSMatt Macy *
591eda14cbcSMatt Macy * We calculate "skip", the number of slots to
592eda14cbcSMatt Macy * skip ahead for the deny ace, here.
593eda14cbcSMatt Macy *
594eda14cbcSMatt Macy * The pattern is:
595eda14cbcSMatt Macy * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3
596eda14cbcSMatt Macy * thus, skip is
597eda14cbcSMatt Macy * (2 * numgroup) - 1 - groupi
598eda14cbcSMatt Macy * (2 * numgroup) to account for MD + A
599eda14cbcSMatt Macy * - 1 to account for the fact that we're on the
600eda14cbcSMatt Macy * access (A), not the mask (MD)
601eda14cbcSMatt Macy * - groupi to account for the fact that we have
602eda14cbcSMatt Macy * passed up groupi number of MD's.
603eda14cbcSMatt Macy */
604eda14cbcSMatt Macy skip = (2 * numgroup) - 1 - groupi;
605eda14cbcSMatt Macy ace_make_deny(acep, acep + skip, isdir, B_FALSE);
606eda14cbcSMatt Macy /*
607eda14cbcSMatt Macy * If we just did the last group, skip acep past
608eda14cbcSMatt Macy * all of the denies; else, just move ahead one.
609eda14cbcSMatt Macy */
610eda14cbcSMatt Macy if (++groupi >= numgroup)
611eda14cbcSMatt Macy acep += numgroup + 1;
612eda14cbcSMatt Macy else
613eda14cbcSMatt Macy acep += 1;
614eda14cbcSMatt Macy } else if (aclent[i].a_type & OTHER_OBJ) {
615eda14cbcSMatt Macy acep->a_who = (uid_t)-1;
616eda14cbcSMatt Macy acep->a_flags |= ACE_EVERYONE;
617eda14cbcSMatt Macy ace_make_deny(acep, acep + 1, isdir, B_FALSE);
618eda14cbcSMatt Macy acep += 2;
619eda14cbcSMatt Macy } else {
620eda14cbcSMatt Macy error = EINVAL;
621eda14cbcSMatt Macy goto out;
622eda14cbcSMatt Macy }
623eda14cbcSMatt Macy }
624eda14cbcSMatt Macy
625eda14cbcSMatt Macy *acepp = result;
626eda14cbcSMatt Macy *rescount = resultsize;
627eda14cbcSMatt Macy
628eda14cbcSMatt Macy out:
629eda14cbcSMatt Macy if (error != 0) {
630eda14cbcSMatt Macy if ((result != NULL) && (resultsize > 0)) {
631eda14cbcSMatt Macy cacl_free(result, resultsize * sizeof (ace_t));
632eda14cbcSMatt Macy }
633eda14cbcSMatt Macy }
634eda14cbcSMatt Macy
635eda14cbcSMatt Macy return (error);
636eda14cbcSMatt Macy }
637eda14cbcSMatt Macy
638eda14cbcSMatt Macy static int
convert_aent_to_ace(aclent_t * aclentp,int aclcnt,boolean_t isdir,ace_t ** retacep,int * retacecnt)639eda14cbcSMatt Macy convert_aent_to_ace(aclent_t *aclentp, int aclcnt, boolean_t isdir,
640eda14cbcSMatt Macy ace_t **retacep, int *retacecnt)
641eda14cbcSMatt Macy {
642eda14cbcSMatt Macy ace_t *acep;
643eda14cbcSMatt Macy ace_t *dfacep;
644eda14cbcSMatt Macy int acecnt = 0;
645eda14cbcSMatt Macy int dfacecnt = 0;
646eda14cbcSMatt Macy int dfaclstart = 0;
647eda14cbcSMatt Macy int dfaclcnt = 0;
648eda14cbcSMatt Macy aclent_t *aclp;
649eda14cbcSMatt Macy int i;
650eda14cbcSMatt Macy int error;
651eda14cbcSMatt Macy int acesz, dfacesz;
652eda14cbcSMatt Macy
653eda14cbcSMatt Macy ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls);
654eda14cbcSMatt Macy
655eda14cbcSMatt Macy for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) {
656eda14cbcSMatt Macy if (aclp->a_type & ACL_DEFAULT)
657eda14cbcSMatt Macy break;
658eda14cbcSMatt Macy }
659eda14cbcSMatt Macy
660eda14cbcSMatt Macy if (i < aclcnt) {
661eda14cbcSMatt Macy dfaclstart = i;
662eda14cbcSMatt Macy dfaclcnt = aclcnt - i;
663eda14cbcSMatt Macy }
664eda14cbcSMatt Macy
665eda14cbcSMatt Macy if (dfaclcnt && !isdir) {
666eda14cbcSMatt Macy return (EINVAL);
667eda14cbcSMatt Macy }
668eda14cbcSMatt Macy
669eda14cbcSMatt Macy error = ln_aent_to_ace(aclentp, i, &acep, &acecnt, isdir);
670eda14cbcSMatt Macy if (error)
671eda14cbcSMatt Macy return (error);
672eda14cbcSMatt Macy
673eda14cbcSMatt Macy if (dfaclcnt) {
674eda14cbcSMatt Macy error = ln_aent_to_ace(&aclentp[dfaclstart], dfaclcnt,
675eda14cbcSMatt Macy &dfacep, &dfacecnt, isdir);
676eda14cbcSMatt Macy if (error) {
677eda14cbcSMatt Macy if (acep) {
678eda14cbcSMatt Macy cacl_free(acep, acecnt * sizeof (ace_t));
679eda14cbcSMatt Macy }
680eda14cbcSMatt Macy return (error);
681eda14cbcSMatt Macy }
682eda14cbcSMatt Macy }
683eda14cbcSMatt Macy
684eda14cbcSMatt Macy if (dfacecnt != 0) {
685eda14cbcSMatt Macy acesz = sizeof (ace_t) * acecnt;
686eda14cbcSMatt Macy dfacesz = sizeof (ace_t) * dfacecnt;
687eda14cbcSMatt Macy acep = cacl_realloc(acep, acesz, acesz + dfacesz);
688eda14cbcSMatt Macy if (acep == NULL)
689eda14cbcSMatt Macy return (ENOMEM);
690eda14cbcSMatt Macy if (dfaclcnt) {
691eda14cbcSMatt Macy (void) memcpy(acep + acecnt, dfacep, dfacesz);
692eda14cbcSMatt Macy }
693eda14cbcSMatt Macy }
694eda14cbcSMatt Macy if (dfaclcnt)
695eda14cbcSMatt Macy cacl_free(dfacep, dfacecnt * sizeof (ace_t));
696eda14cbcSMatt Macy
697eda14cbcSMatt Macy *retacecnt = acecnt + dfacecnt;
698eda14cbcSMatt Macy *retacep = acep;
699eda14cbcSMatt Macy return (0);
700eda14cbcSMatt Macy }
701eda14cbcSMatt Macy
702eda14cbcSMatt Macy static int
ace_mask_to_mode(uint32_t mask,o_mode_t * modep,boolean_t isdir)703eda14cbcSMatt Macy ace_mask_to_mode(uint32_t mask, o_mode_t *modep, boolean_t isdir)
704eda14cbcSMatt Macy {
705eda14cbcSMatt Macy int error = 0;
706eda14cbcSMatt Macy o_mode_t mode = 0;
707eda14cbcSMatt Macy uint32_t bits, wantbits;
708eda14cbcSMatt Macy
709eda14cbcSMatt Macy /* read */
710eda14cbcSMatt Macy if (mask & ACE_READ_DATA)
711eda14cbcSMatt Macy mode |= S_IROTH;
712eda14cbcSMatt Macy
713eda14cbcSMatt Macy /* write */
714eda14cbcSMatt Macy wantbits = (ACE_WRITE_DATA | ACE_APPEND_DATA);
715eda14cbcSMatt Macy if (isdir)
716eda14cbcSMatt Macy wantbits |= ACE_DELETE_CHILD;
717eda14cbcSMatt Macy bits = mask & wantbits;
718eda14cbcSMatt Macy if (bits != 0) {
719eda14cbcSMatt Macy if (bits != wantbits) {
720eda14cbcSMatt Macy error = ENOTSUP;
721eda14cbcSMatt Macy goto out;
722eda14cbcSMatt Macy }
723eda14cbcSMatt Macy mode |= S_IWOTH;
724eda14cbcSMatt Macy }
725eda14cbcSMatt Macy
726eda14cbcSMatt Macy /* exec */
727eda14cbcSMatt Macy if (mask & ACE_EXECUTE) {
728eda14cbcSMatt Macy mode |= S_IXOTH;
729eda14cbcSMatt Macy }
730eda14cbcSMatt Macy
731eda14cbcSMatt Macy *modep = mode;
732eda14cbcSMatt Macy
733eda14cbcSMatt Macy out:
734eda14cbcSMatt Macy return (error);
735eda14cbcSMatt Macy }
736eda14cbcSMatt Macy
737eda14cbcSMatt Macy static void
acevals_init(acevals_t * vals,uid_t key)738eda14cbcSMatt Macy acevals_init(acevals_t *vals, uid_t key)
739eda14cbcSMatt Macy {
740da5137abSMartin Matuska memset(vals, 0, sizeof (*vals));
741eda14cbcSMatt Macy vals->allowed = ACE_MASK_UNDEFINED;
742eda14cbcSMatt Macy vals->denied = ACE_MASK_UNDEFINED;
743eda14cbcSMatt Macy vals->mask = ACE_MASK_UNDEFINED;
744eda14cbcSMatt Macy vals->key = key;
745eda14cbcSMatt Macy }
746eda14cbcSMatt Macy
747eda14cbcSMatt Macy static void
ace_list_init(ace_list_t * al,int dfacl_flag)748eda14cbcSMatt Macy ace_list_init(ace_list_t *al, int dfacl_flag)
749eda14cbcSMatt Macy {
750eda14cbcSMatt Macy acevals_init(&al->user_obj, 0);
751eda14cbcSMatt Macy acevals_init(&al->group_obj, 0);
752eda14cbcSMatt Macy acevals_init(&al->other_obj, 0);
753eda14cbcSMatt Macy al->numusers = 0;
754eda14cbcSMatt Macy al->numgroups = 0;
755eda14cbcSMatt Macy al->acl_mask = 0;
756eda14cbcSMatt Macy al->hasmask = 0;
757eda14cbcSMatt Macy al->state = ace_unused;
758eda14cbcSMatt Macy al->seen = 0;
759eda14cbcSMatt Macy al->dfacl_flag = dfacl_flag;
760eda14cbcSMatt Macy }
761eda14cbcSMatt Macy
762eda14cbcSMatt Macy /*
763eda14cbcSMatt Macy * Find or create an acevals holder for a given id and avl tree.
764eda14cbcSMatt Macy *
765eda14cbcSMatt Macy * Note that only one thread will ever touch these avl trees, so
766eda14cbcSMatt Macy * there is no need for locking.
767eda14cbcSMatt Macy */
768eda14cbcSMatt Macy static acevals_t *
acevals_find(ace_t * ace,avl_tree_t * avl,int * num)769eda14cbcSMatt Macy acevals_find(ace_t *ace, avl_tree_t *avl, int *num)
770eda14cbcSMatt Macy {
771eda14cbcSMatt Macy acevals_t key, *rc;
772eda14cbcSMatt Macy avl_index_t where;
773eda14cbcSMatt Macy
774eda14cbcSMatt Macy key.key = ace->a_who;
775eda14cbcSMatt Macy rc = avl_find(avl, &key, &where);
776eda14cbcSMatt Macy if (rc != NULL)
777eda14cbcSMatt Macy return (rc);
778eda14cbcSMatt Macy
779eda14cbcSMatt Macy /* this memory is freed by ln_ace_to_aent()->ace_list_free() */
780eda14cbcSMatt Macy if (cacl_malloc((void **)&rc, sizeof (acevals_t)) != 0)
781eda14cbcSMatt Macy return (NULL);
782eda14cbcSMatt Macy
783eda14cbcSMatt Macy acevals_init(rc, ace->a_who);
784eda14cbcSMatt Macy avl_insert(avl, rc, where);
785eda14cbcSMatt Macy (*num)++;
786eda14cbcSMatt Macy
787eda14cbcSMatt Macy return (rc);
788eda14cbcSMatt Macy }
789eda14cbcSMatt Macy
790eda14cbcSMatt Macy static int
access_mask_check(ace_t * acep,int mask_bit,int isowner)791eda14cbcSMatt Macy access_mask_check(ace_t *acep, int mask_bit, int isowner)
792eda14cbcSMatt Macy {
793eda14cbcSMatt Macy int set_deny, err_deny;
794eda14cbcSMatt Macy int set_allow, err_allow;
795eda14cbcSMatt Macy int acl_consume;
796eda14cbcSMatt Macy int haswriteperm, hasreadperm;
797eda14cbcSMatt Macy
798eda14cbcSMatt Macy if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) {
799eda14cbcSMatt Macy haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 0 : 1;
800eda14cbcSMatt Macy hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 0 : 1;
801eda14cbcSMatt Macy } else {
802eda14cbcSMatt Macy haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 1 : 0;
803eda14cbcSMatt Macy hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 1 : 0;
804eda14cbcSMatt Macy }
805eda14cbcSMatt Macy
806eda14cbcSMatt Macy acl_consume = (ACL_SYNCHRONIZE_ERR_DENY |
807eda14cbcSMatt Macy ACL_DELETE_ERR_DENY |
808eda14cbcSMatt Macy ACL_WRITE_OWNER_ERR_DENY |
809eda14cbcSMatt Macy ACL_WRITE_OWNER_ERR_ALLOW |
810eda14cbcSMatt Macy ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
811eda14cbcSMatt Macy ACL_WRITE_ATTRS_OWNER_ERR_DENY |
812eda14cbcSMatt Macy ACL_WRITE_ATTRS_WRITER_SET_DENY |
813eda14cbcSMatt Macy ACL_WRITE_ATTRS_WRITER_ERR_ALLOW |
814eda14cbcSMatt Macy ACL_WRITE_NAMED_WRITER_ERR_DENY |
815eda14cbcSMatt Macy ACL_READ_NAMED_READER_ERR_DENY);
816eda14cbcSMatt Macy
817eda14cbcSMatt Macy if (mask_bit == ACE_SYNCHRONIZE) {
818eda14cbcSMatt Macy set_deny = ACL_SYNCHRONIZE_SET_DENY;
819eda14cbcSMatt Macy err_deny = ACL_SYNCHRONIZE_ERR_DENY;
820eda14cbcSMatt Macy set_allow = ACL_SYNCHRONIZE_SET_ALLOW;
821eda14cbcSMatt Macy err_allow = ACL_SYNCHRONIZE_ERR_ALLOW;
822eda14cbcSMatt Macy } else if (mask_bit == ACE_WRITE_OWNER) {
823eda14cbcSMatt Macy set_deny = ACL_WRITE_OWNER_SET_DENY;
824eda14cbcSMatt Macy err_deny = ACL_WRITE_OWNER_ERR_DENY;
825eda14cbcSMatt Macy set_allow = ACL_WRITE_OWNER_SET_ALLOW;
826eda14cbcSMatt Macy err_allow = ACL_WRITE_OWNER_ERR_ALLOW;
827eda14cbcSMatt Macy } else if (mask_bit == ACE_DELETE) {
828eda14cbcSMatt Macy set_deny = ACL_DELETE_SET_DENY;
829eda14cbcSMatt Macy err_deny = ACL_DELETE_ERR_DENY;
830eda14cbcSMatt Macy set_allow = ACL_DELETE_SET_ALLOW;
831eda14cbcSMatt Macy err_allow = ACL_DELETE_ERR_ALLOW;
832eda14cbcSMatt Macy } else if (mask_bit == ACE_WRITE_ATTRIBUTES) {
833eda14cbcSMatt Macy if (isowner) {
834eda14cbcSMatt Macy set_deny = ACL_WRITE_ATTRS_OWNER_SET_DENY;
835eda14cbcSMatt Macy err_deny = ACL_WRITE_ATTRS_OWNER_ERR_DENY;
836eda14cbcSMatt Macy set_allow = ACL_WRITE_ATTRS_OWNER_SET_ALLOW;
837eda14cbcSMatt Macy err_allow = ACL_WRITE_ATTRS_OWNER_ERR_ALLOW;
838eda14cbcSMatt Macy } else if (haswriteperm) {
839eda14cbcSMatt Macy set_deny = ACL_WRITE_ATTRS_WRITER_SET_DENY;
840eda14cbcSMatt Macy err_deny = ACL_WRITE_ATTRS_WRITER_ERR_DENY;
841eda14cbcSMatt Macy set_allow = ACL_WRITE_ATTRS_WRITER_SET_ALLOW;
842eda14cbcSMatt Macy err_allow = ACL_WRITE_ATTRS_WRITER_ERR_ALLOW;
843eda14cbcSMatt Macy } else {
844eda14cbcSMatt Macy if ((acep->a_access_mask & mask_bit) &&
845eda14cbcSMatt Macy (acep->a_type & ACE_ACCESS_ALLOWED_ACE_TYPE)) {
846eda14cbcSMatt Macy return (ENOTSUP);
847eda14cbcSMatt Macy }
848eda14cbcSMatt Macy return (0);
849eda14cbcSMatt Macy }
850eda14cbcSMatt Macy } else if (mask_bit == ACE_READ_NAMED_ATTRS) {
851eda14cbcSMatt Macy if (!hasreadperm)
852eda14cbcSMatt Macy return (0);
853eda14cbcSMatt Macy
854eda14cbcSMatt Macy set_deny = ACL_READ_NAMED_READER_SET_DENY;
855eda14cbcSMatt Macy err_deny = ACL_READ_NAMED_READER_ERR_DENY;
856eda14cbcSMatt Macy set_allow = ACL_READ_NAMED_READER_SET_ALLOW;
857eda14cbcSMatt Macy err_allow = ACL_READ_NAMED_READER_ERR_ALLOW;
858eda14cbcSMatt Macy } else if (mask_bit == ACE_WRITE_NAMED_ATTRS) {
859eda14cbcSMatt Macy if (!haswriteperm)
860eda14cbcSMatt Macy return (0);
861eda14cbcSMatt Macy
862eda14cbcSMatt Macy set_deny = ACL_WRITE_NAMED_WRITER_SET_DENY;
863eda14cbcSMatt Macy err_deny = ACL_WRITE_NAMED_WRITER_ERR_DENY;
864eda14cbcSMatt Macy set_allow = ACL_WRITE_NAMED_WRITER_SET_ALLOW;
865eda14cbcSMatt Macy err_allow = ACL_WRITE_NAMED_WRITER_ERR_ALLOW;
866eda14cbcSMatt Macy } else {
867eda14cbcSMatt Macy return (EINVAL);
868eda14cbcSMatt Macy }
869eda14cbcSMatt Macy
870eda14cbcSMatt Macy if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) {
871eda14cbcSMatt Macy if (acl_consume & set_deny) {
872eda14cbcSMatt Macy if (!(acep->a_access_mask & mask_bit)) {
873eda14cbcSMatt Macy return (ENOTSUP);
874eda14cbcSMatt Macy }
875eda14cbcSMatt Macy } else if (acl_consume & err_deny) {
876eda14cbcSMatt Macy if (acep->a_access_mask & mask_bit) {
877eda14cbcSMatt Macy return (ENOTSUP);
878eda14cbcSMatt Macy }
879eda14cbcSMatt Macy }
880eda14cbcSMatt Macy } else {
881eda14cbcSMatt Macy /* ACE_ACCESS_ALLOWED_ACE_TYPE */
882eda14cbcSMatt Macy if (acl_consume & set_allow) {
883eda14cbcSMatt Macy if (!(acep->a_access_mask & mask_bit)) {
884eda14cbcSMatt Macy return (ENOTSUP);
885eda14cbcSMatt Macy }
886eda14cbcSMatt Macy } else if (acl_consume & err_allow) {
887eda14cbcSMatt Macy if (acep->a_access_mask & mask_bit) {
888eda14cbcSMatt Macy return (ENOTSUP);
889eda14cbcSMatt Macy }
890eda14cbcSMatt Macy }
891eda14cbcSMatt Macy }
892eda14cbcSMatt Macy return (0);
893eda14cbcSMatt Macy }
894eda14cbcSMatt Macy
895eda14cbcSMatt Macy static int
ace_to_aent_legal(ace_t * acep)896eda14cbcSMatt Macy ace_to_aent_legal(ace_t *acep)
897eda14cbcSMatt Macy {
898eda14cbcSMatt Macy int error = 0;
899eda14cbcSMatt Macy int isowner;
900eda14cbcSMatt Macy
901eda14cbcSMatt Macy /* only ALLOW or DENY */
902eda14cbcSMatt Macy if ((acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE) &&
903eda14cbcSMatt Macy (acep->a_type != ACE_ACCESS_DENIED_ACE_TYPE)) {
904eda14cbcSMatt Macy error = ENOTSUP;
905eda14cbcSMatt Macy goto out;
906eda14cbcSMatt Macy }
907eda14cbcSMatt Macy
908eda14cbcSMatt Macy /* check for invalid flags */
909eda14cbcSMatt Macy if (acep->a_flags & ~(ACE_VALID_FLAG_BITS)) {
910eda14cbcSMatt Macy error = EINVAL;
911eda14cbcSMatt Macy goto out;
912eda14cbcSMatt Macy }
913eda14cbcSMatt Macy
914eda14cbcSMatt Macy /* some flags are illegal */
915eda14cbcSMatt Macy if (acep->a_flags & (ACE_SUCCESSFUL_ACCESS_ACE_FLAG |
916eda14cbcSMatt Macy ACE_FAILED_ACCESS_ACE_FLAG |
917eda14cbcSMatt Macy ACE_NO_PROPAGATE_INHERIT_ACE)) {
918eda14cbcSMatt Macy error = ENOTSUP;
919eda14cbcSMatt Macy goto out;
920eda14cbcSMatt Macy }
921eda14cbcSMatt Macy
922eda14cbcSMatt Macy /* check for invalid masks */
923eda14cbcSMatt Macy if (acep->a_access_mask & ~(ACE_VALID_MASK_BITS)) {
924eda14cbcSMatt Macy error = EINVAL;
925eda14cbcSMatt Macy goto out;
926eda14cbcSMatt Macy }
927eda14cbcSMatt Macy
928eda14cbcSMatt Macy if ((acep->a_flags & ACE_OWNER)) {
929eda14cbcSMatt Macy isowner = 1;
930eda14cbcSMatt Macy } else {
931eda14cbcSMatt Macy isowner = 0;
932eda14cbcSMatt Macy }
933eda14cbcSMatt Macy
934eda14cbcSMatt Macy error = access_mask_check(acep, ACE_SYNCHRONIZE, isowner);
935eda14cbcSMatt Macy if (error)
936eda14cbcSMatt Macy goto out;
937eda14cbcSMatt Macy
938eda14cbcSMatt Macy error = access_mask_check(acep, ACE_WRITE_OWNER, isowner);
939eda14cbcSMatt Macy if (error)
940eda14cbcSMatt Macy goto out;
941eda14cbcSMatt Macy
942eda14cbcSMatt Macy error = access_mask_check(acep, ACE_DELETE, isowner);
943eda14cbcSMatt Macy if (error)
944eda14cbcSMatt Macy goto out;
945eda14cbcSMatt Macy
946eda14cbcSMatt Macy error = access_mask_check(acep, ACE_WRITE_ATTRIBUTES, isowner);
947eda14cbcSMatt Macy if (error)
948eda14cbcSMatt Macy goto out;
949eda14cbcSMatt Macy
950eda14cbcSMatt Macy error = access_mask_check(acep, ACE_READ_NAMED_ATTRS, isowner);
951eda14cbcSMatt Macy if (error)
952eda14cbcSMatt Macy goto out;
953eda14cbcSMatt Macy
954eda14cbcSMatt Macy error = access_mask_check(acep, ACE_WRITE_NAMED_ATTRS, isowner);
955eda14cbcSMatt Macy if (error)
956eda14cbcSMatt Macy goto out;
957eda14cbcSMatt Macy
958eda14cbcSMatt Macy /* more detailed checking of masks */
959eda14cbcSMatt Macy if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
960eda14cbcSMatt Macy if (! (acep->a_access_mask & ACE_READ_ATTRIBUTES)) {
961eda14cbcSMatt Macy error = ENOTSUP;
962eda14cbcSMatt Macy goto out;
963eda14cbcSMatt Macy }
964eda14cbcSMatt Macy if ((acep->a_access_mask & ACE_WRITE_DATA) &&
965eda14cbcSMatt Macy (! (acep->a_access_mask & ACE_APPEND_DATA))) {
966eda14cbcSMatt Macy error = ENOTSUP;
967eda14cbcSMatt Macy goto out;
968eda14cbcSMatt Macy }
969eda14cbcSMatt Macy if ((! (acep->a_access_mask & ACE_WRITE_DATA)) &&
970eda14cbcSMatt Macy (acep->a_access_mask & ACE_APPEND_DATA)) {
971eda14cbcSMatt Macy error = ENOTSUP;
972eda14cbcSMatt Macy goto out;
973eda14cbcSMatt Macy }
974eda14cbcSMatt Macy }
975eda14cbcSMatt Macy
976eda14cbcSMatt Macy /* ACL enforcement */
977eda14cbcSMatt Macy if ((acep->a_access_mask & ACE_READ_ACL) &&
978eda14cbcSMatt Macy (acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE)) {
979eda14cbcSMatt Macy error = ENOTSUP;
980eda14cbcSMatt Macy goto out;
981eda14cbcSMatt Macy }
982eda14cbcSMatt Macy if (acep->a_access_mask & ACE_WRITE_ACL) {
983eda14cbcSMatt Macy if ((acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) &&
984eda14cbcSMatt Macy (isowner)) {
985eda14cbcSMatt Macy error = ENOTSUP;
986eda14cbcSMatt Macy goto out;
987eda14cbcSMatt Macy }
988eda14cbcSMatt Macy if ((acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) &&
989eda14cbcSMatt Macy (! isowner)) {
990eda14cbcSMatt Macy error = ENOTSUP;
991eda14cbcSMatt Macy goto out;
992eda14cbcSMatt Macy }
993eda14cbcSMatt Macy }
994eda14cbcSMatt Macy
995eda14cbcSMatt Macy out:
996eda14cbcSMatt Macy return (error);
997eda14cbcSMatt Macy }
998eda14cbcSMatt Macy
999eda14cbcSMatt Macy static int
ace_allow_to_mode(uint32_t mask,o_mode_t * modep,boolean_t isdir)1000eda14cbcSMatt Macy ace_allow_to_mode(uint32_t mask, o_mode_t *modep, boolean_t isdir)
1001eda14cbcSMatt Macy {
1002eda14cbcSMatt Macy /* ACE_READ_ACL and ACE_READ_ATTRIBUTES must both be set */
1003eda14cbcSMatt Macy if ((mask & (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) !=
1004eda14cbcSMatt Macy (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) {
1005eda14cbcSMatt Macy return (ENOTSUP);
1006eda14cbcSMatt Macy }
1007eda14cbcSMatt Macy
1008eda14cbcSMatt Macy return (ace_mask_to_mode(mask, modep, isdir));
1009eda14cbcSMatt Macy }
1010eda14cbcSMatt Macy
1011eda14cbcSMatt Macy static int
acevals_to_aent(acevals_t * vals,aclent_t * dest,ace_list_t * list,uid_t owner,gid_t group,boolean_t isdir)1012eda14cbcSMatt Macy acevals_to_aent(acevals_t *vals, aclent_t *dest, ace_list_t *list,
1013eda14cbcSMatt Macy uid_t owner, gid_t group, boolean_t isdir)
1014eda14cbcSMatt Macy {
1015eda14cbcSMatt Macy int error;
1016eda14cbcSMatt Macy uint32_t flips = ACE_POSIX_SUPPORTED_BITS;
1017eda14cbcSMatt Macy
1018eda14cbcSMatt Macy if (isdir)
1019eda14cbcSMatt Macy flips |= ACE_DELETE_CHILD;
1020eda14cbcSMatt Macy if (vals->allowed != (vals->denied ^ flips)) {
1021eda14cbcSMatt Macy error = ENOTSUP;
1022eda14cbcSMatt Macy goto out;
1023eda14cbcSMatt Macy }
1024eda14cbcSMatt Macy if ((list->hasmask) && (list->acl_mask != vals->mask) &&
1025eda14cbcSMatt Macy (vals->aent_type & (USER | GROUP | GROUP_OBJ))) {
1026eda14cbcSMatt Macy error = ENOTSUP;
1027eda14cbcSMatt Macy goto out;
1028eda14cbcSMatt Macy }
1029eda14cbcSMatt Macy error = ace_allow_to_mode(vals->allowed, &dest->a_perm, isdir);
1030eda14cbcSMatt Macy if (error != 0)
1031eda14cbcSMatt Macy goto out;
1032eda14cbcSMatt Macy dest->a_type = vals->aent_type;
1033eda14cbcSMatt Macy if (dest->a_type & (USER | GROUP)) {
1034eda14cbcSMatt Macy dest->a_id = vals->key;
1035eda14cbcSMatt Macy } else if (dest->a_type & USER_OBJ) {
1036eda14cbcSMatt Macy dest->a_id = owner;
1037eda14cbcSMatt Macy } else if (dest->a_type & GROUP_OBJ) {
1038eda14cbcSMatt Macy dest->a_id = group;
1039eda14cbcSMatt Macy } else if (dest->a_type & OTHER_OBJ) {
1040eda14cbcSMatt Macy dest->a_id = 0;
1041eda14cbcSMatt Macy } else {
1042eda14cbcSMatt Macy error = EINVAL;
1043eda14cbcSMatt Macy goto out;
1044eda14cbcSMatt Macy }
1045eda14cbcSMatt Macy
1046eda14cbcSMatt Macy out:
1047eda14cbcSMatt Macy return (error);
1048eda14cbcSMatt Macy }
1049eda14cbcSMatt Macy
1050eda14cbcSMatt Macy
1051eda14cbcSMatt Macy static int
ace_list_to_aent(ace_list_t * list,aclent_t ** aclentp,int * aclcnt,uid_t owner,gid_t group,boolean_t isdir)1052eda14cbcSMatt Macy ace_list_to_aent(ace_list_t *list, aclent_t **aclentp, int *aclcnt,
1053eda14cbcSMatt Macy uid_t owner, gid_t group, boolean_t isdir)
1054eda14cbcSMatt Macy {
1055eda14cbcSMatt Macy int error = 0;
1056eda14cbcSMatt Macy aclent_t *aent, *result = NULL;
1057eda14cbcSMatt Macy acevals_t *vals;
1058eda14cbcSMatt Macy int resultcount;
1059eda14cbcSMatt Macy
1060eda14cbcSMatt Macy if ((list->seen & (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) !=
1061eda14cbcSMatt Macy (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) {
1062eda14cbcSMatt Macy error = ENOTSUP;
1063eda14cbcSMatt Macy goto out;
1064eda14cbcSMatt Macy }
1065eda14cbcSMatt Macy if ((! list->hasmask) && (list->numusers + list->numgroups > 0)) {
1066eda14cbcSMatt Macy error = ENOTSUP;
1067eda14cbcSMatt Macy goto out;
1068eda14cbcSMatt Macy }
1069eda14cbcSMatt Macy
1070eda14cbcSMatt Macy resultcount = 3 + list->numusers + list->numgroups;
1071eda14cbcSMatt Macy /*
1072eda14cbcSMatt Macy * This must be the same condition as below, when we add the CLASS_OBJ
1073eda14cbcSMatt Macy * (aka ACL mask)
1074eda14cbcSMatt Macy */
1075eda14cbcSMatt Macy if ((list->hasmask) || (! list->dfacl_flag))
1076eda14cbcSMatt Macy resultcount += 1;
1077eda14cbcSMatt Macy
1078eda14cbcSMatt Macy if (cacl_malloc((void **)&result,
1079eda14cbcSMatt Macy resultcount * sizeof (aclent_t)) != 0) {
1080eda14cbcSMatt Macy error = ENOMEM;
1081eda14cbcSMatt Macy goto out;
1082eda14cbcSMatt Macy }
1083eda14cbcSMatt Macy aent = result;
1084eda14cbcSMatt Macy
1085eda14cbcSMatt Macy /* USER_OBJ */
1086eda14cbcSMatt Macy if (!(list->user_obj.aent_type & USER_OBJ)) {
1087eda14cbcSMatt Macy error = EINVAL;
1088eda14cbcSMatt Macy goto out;
1089eda14cbcSMatt Macy }
1090eda14cbcSMatt Macy
1091eda14cbcSMatt Macy error = acevals_to_aent(&list->user_obj, aent, list, owner, group,
1092eda14cbcSMatt Macy isdir);
1093eda14cbcSMatt Macy
1094eda14cbcSMatt Macy if (error != 0)
1095eda14cbcSMatt Macy goto out;
1096eda14cbcSMatt Macy ++aent;
1097eda14cbcSMatt Macy /* USER */
1098eda14cbcSMatt Macy vals = NULL;
1099eda14cbcSMatt Macy for (vals = avl_first(&list->user); vals != NULL;
1100eda14cbcSMatt Macy vals = AVL_NEXT(&list->user, vals)) {
1101eda14cbcSMatt Macy if (!(vals->aent_type & USER)) {
1102eda14cbcSMatt Macy error = EINVAL;
1103eda14cbcSMatt Macy goto out;
1104eda14cbcSMatt Macy }
1105eda14cbcSMatt Macy error = acevals_to_aent(vals, aent, list, owner, group,
1106eda14cbcSMatt Macy isdir);
1107eda14cbcSMatt Macy if (error != 0)
1108eda14cbcSMatt Macy goto out;
1109eda14cbcSMatt Macy ++aent;
1110eda14cbcSMatt Macy }
1111eda14cbcSMatt Macy /* GROUP_OBJ */
1112eda14cbcSMatt Macy if (!(list->group_obj.aent_type & GROUP_OBJ)) {
1113eda14cbcSMatt Macy error = EINVAL;
1114eda14cbcSMatt Macy goto out;
1115eda14cbcSMatt Macy }
1116eda14cbcSMatt Macy error = acevals_to_aent(&list->group_obj, aent, list, owner, group,
1117eda14cbcSMatt Macy isdir);
1118eda14cbcSMatt Macy if (error != 0)
1119eda14cbcSMatt Macy goto out;
1120eda14cbcSMatt Macy ++aent;
1121eda14cbcSMatt Macy /* GROUP */
1122eda14cbcSMatt Macy vals = NULL;
1123eda14cbcSMatt Macy for (vals = avl_first(&list->group); vals != NULL;
1124eda14cbcSMatt Macy vals = AVL_NEXT(&list->group, vals)) {
1125eda14cbcSMatt Macy if (!(vals->aent_type & GROUP)) {
1126eda14cbcSMatt Macy error = EINVAL;
1127eda14cbcSMatt Macy goto out;
1128eda14cbcSMatt Macy }
1129eda14cbcSMatt Macy error = acevals_to_aent(vals, aent, list, owner, group,
1130eda14cbcSMatt Macy isdir);
1131eda14cbcSMatt Macy if (error != 0)
1132eda14cbcSMatt Macy goto out;
1133eda14cbcSMatt Macy ++aent;
1134eda14cbcSMatt Macy }
1135eda14cbcSMatt Macy /*
1136eda14cbcSMatt Macy * CLASS_OBJ (aka ACL_MASK)
1137eda14cbcSMatt Macy *
1138eda14cbcSMatt Macy * An ACL_MASK is not fabricated if the ACL is a default ACL.
1139eda14cbcSMatt Macy * This is to follow UFS's behavior.
1140eda14cbcSMatt Macy */
1141eda14cbcSMatt Macy if ((list->hasmask) || (! list->dfacl_flag)) {
1142eda14cbcSMatt Macy if (list->hasmask) {
1143eda14cbcSMatt Macy uint32_t flips = ACE_POSIX_SUPPORTED_BITS;
1144eda14cbcSMatt Macy if (isdir)
1145eda14cbcSMatt Macy flips |= ACE_DELETE_CHILD;
1146eda14cbcSMatt Macy error = ace_mask_to_mode(list->acl_mask ^ flips,
1147eda14cbcSMatt Macy &aent->a_perm, isdir);
1148eda14cbcSMatt Macy if (error != 0)
1149eda14cbcSMatt Macy goto out;
1150eda14cbcSMatt Macy } else {
1151eda14cbcSMatt Macy /* fabricate the ACL_MASK from the group permissions */
1152eda14cbcSMatt Macy error = ace_mask_to_mode(list->group_obj.allowed,
1153eda14cbcSMatt Macy &aent->a_perm, isdir);
1154eda14cbcSMatt Macy if (error != 0)
1155eda14cbcSMatt Macy goto out;
1156eda14cbcSMatt Macy }
1157eda14cbcSMatt Macy aent->a_id = 0;
1158eda14cbcSMatt Macy aent->a_type = CLASS_OBJ | list->dfacl_flag;
1159eda14cbcSMatt Macy ++aent;
1160eda14cbcSMatt Macy }
1161eda14cbcSMatt Macy /* OTHER_OBJ */
1162eda14cbcSMatt Macy if (!(list->other_obj.aent_type & OTHER_OBJ)) {
1163eda14cbcSMatt Macy error = EINVAL;
1164eda14cbcSMatt Macy goto out;
1165eda14cbcSMatt Macy }
1166eda14cbcSMatt Macy error = acevals_to_aent(&list->other_obj, aent, list, owner, group,
1167eda14cbcSMatt Macy isdir);
1168eda14cbcSMatt Macy if (error != 0)
1169eda14cbcSMatt Macy goto out;
1170eda14cbcSMatt Macy ++aent;
1171eda14cbcSMatt Macy
1172eda14cbcSMatt Macy *aclentp = result;
1173eda14cbcSMatt Macy *aclcnt = resultcount;
1174eda14cbcSMatt Macy
1175eda14cbcSMatt Macy out:
1176eda14cbcSMatt Macy if (error != 0) {
1177eda14cbcSMatt Macy if (result != NULL)
1178eda14cbcSMatt Macy cacl_free(result, resultcount * sizeof (aclent_t));
1179eda14cbcSMatt Macy }
1180eda14cbcSMatt Macy
1181eda14cbcSMatt Macy return (error);
1182eda14cbcSMatt Macy }
1183eda14cbcSMatt Macy
1184eda14cbcSMatt Macy
1185eda14cbcSMatt Macy /*
1186eda14cbcSMatt Macy * free all data associated with an ace_list
1187eda14cbcSMatt Macy */
1188eda14cbcSMatt Macy static void
ace_list_free(ace_list_t * al)1189eda14cbcSMatt Macy ace_list_free(ace_list_t *al)
1190eda14cbcSMatt Macy {
1191eda14cbcSMatt Macy acevals_t *node;
1192eda14cbcSMatt Macy void *cookie;
1193eda14cbcSMatt Macy
1194eda14cbcSMatt Macy if (al == NULL)
1195eda14cbcSMatt Macy return;
1196eda14cbcSMatt Macy
1197eda14cbcSMatt Macy cookie = NULL;
1198eda14cbcSMatt Macy while ((node = avl_destroy_nodes(&al->user, &cookie)) != NULL)
1199eda14cbcSMatt Macy cacl_free(node, sizeof (acevals_t));
1200eda14cbcSMatt Macy cookie = NULL;
1201eda14cbcSMatt Macy while ((node = avl_destroy_nodes(&al->group, &cookie)) != NULL)
1202eda14cbcSMatt Macy cacl_free(node, sizeof (acevals_t));
1203eda14cbcSMatt Macy
1204eda14cbcSMatt Macy avl_destroy(&al->user);
1205eda14cbcSMatt Macy avl_destroy(&al->group);
1206eda14cbcSMatt Macy
1207eda14cbcSMatt Macy /* free the container itself */
1208eda14cbcSMatt Macy cacl_free(al, sizeof (ace_list_t));
1209eda14cbcSMatt Macy }
1210eda14cbcSMatt Macy
1211eda14cbcSMatt Macy static int
acevals_compare(const void * va,const void * vb)1212eda14cbcSMatt Macy acevals_compare(const void *va, const void *vb)
1213eda14cbcSMatt Macy {
1214eda14cbcSMatt Macy const acevals_t *a = va, *b = vb;
1215eda14cbcSMatt Macy
1216eda14cbcSMatt Macy if (a->key == b->key)
1217eda14cbcSMatt Macy return (0);
1218eda14cbcSMatt Macy
1219eda14cbcSMatt Macy if (a->key > b->key)
1220eda14cbcSMatt Macy return (1);
1221eda14cbcSMatt Macy
1222eda14cbcSMatt Macy else
1223eda14cbcSMatt Macy return (-1);
1224eda14cbcSMatt Macy }
1225eda14cbcSMatt Macy
1226eda14cbcSMatt Macy /*
1227eda14cbcSMatt Macy * Convert a list of ace_t entries to equivalent regular and default
1228eda14cbcSMatt Macy * aclent_t lists. Return error (ENOTSUP) when conversion is not possible.
1229eda14cbcSMatt Macy */
1230eda14cbcSMatt Macy static int
ln_ace_to_aent(ace_t * ace,int n,uid_t owner,gid_t group,aclent_t ** aclentp,int * aclcnt,aclent_t ** dfaclentp,int * dfaclcnt,boolean_t isdir)1231eda14cbcSMatt Macy ln_ace_to_aent(ace_t *ace, int n, uid_t owner, gid_t group,
1232eda14cbcSMatt Macy aclent_t **aclentp, int *aclcnt, aclent_t **dfaclentp, int *dfaclcnt,
1233eda14cbcSMatt Macy boolean_t isdir)
1234eda14cbcSMatt Macy {
1235eda14cbcSMatt Macy int error = 0;
1236eda14cbcSMatt Macy ace_t *acep;
1237eda14cbcSMatt Macy uint32_t bits;
1238eda14cbcSMatt Macy int i;
1239eda14cbcSMatt Macy ace_list_t *normacl = NULL, *dfacl = NULL, *acl;
1240eda14cbcSMatt Macy acevals_t *vals;
1241eda14cbcSMatt Macy
1242eda14cbcSMatt Macy *aclentp = NULL;
1243eda14cbcSMatt Macy *aclcnt = 0;
1244eda14cbcSMatt Macy *dfaclentp = NULL;
1245eda14cbcSMatt Macy *dfaclcnt = 0;
1246eda14cbcSMatt Macy
1247eda14cbcSMatt Macy /* we need at least user_obj, group_obj, and other_obj */
1248eda14cbcSMatt Macy if (n < 6) {
1249eda14cbcSMatt Macy error = ENOTSUP;
1250eda14cbcSMatt Macy goto out;
1251eda14cbcSMatt Macy }
1252eda14cbcSMatt Macy if (ace == NULL) {
1253eda14cbcSMatt Macy error = EINVAL;
1254eda14cbcSMatt Macy goto out;
1255eda14cbcSMatt Macy }
1256eda14cbcSMatt Macy
1257eda14cbcSMatt Macy error = cacl_malloc((void **)&normacl, sizeof (ace_list_t));
1258eda14cbcSMatt Macy if (error != 0)
1259eda14cbcSMatt Macy goto out;
1260eda14cbcSMatt Macy
1261eda14cbcSMatt Macy avl_create(&normacl->user, acevals_compare, sizeof (acevals_t),
1262eda14cbcSMatt Macy offsetof(acevals_t, avl));
1263eda14cbcSMatt Macy avl_create(&normacl->group, acevals_compare, sizeof (acevals_t),
1264eda14cbcSMatt Macy offsetof(acevals_t, avl));
1265eda14cbcSMatt Macy
1266eda14cbcSMatt Macy ace_list_init(normacl, 0);
1267eda14cbcSMatt Macy
1268eda14cbcSMatt Macy error = cacl_malloc((void **)&dfacl, sizeof (ace_list_t));
1269eda14cbcSMatt Macy if (error != 0)
1270eda14cbcSMatt Macy goto out;
1271eda14cbcSMatt Macy
1272eda14cbcSMatt Macy avl_create(&dfacl->user, acevals_compare, sizeof (acevals_t),
1273eda14cbcSMatt Macy offsetof(acevals_t, avl));
1274eda14cbcSMatt Macy avl_create(&dfacl->group, acevals_compare, sizeof (acevals_t),
1275eda14cbcSMatt Macy offsetof(acevals_t, avl));
1276eda14cbcSMatt Macy ace_list_init(dfacl, ACL_DEFAULT);
1277eda14cbcSMatt Macy
1278eda14cbcSMatt Macy /* process every ace_t... */
1279eda14cbcSMatt Macy for (i = 0; i < n; i++) {
1280eda14cbcSMatt Macy acep = &ace[i];
1281eda14cbcSMatt Macy
1282eda14cbcSMatt Macy /* rule out certain cases quickly */
1283eda14cbcSMatt Macy error = ace_to_aent_legal(acep);
1284eda14cbcSMatt Macy if (error != 0)
1285eda14cbcSMatt Macy goto out;
1286eda14cbcSMatt Macy
1287eda14cbcSMatt Macy /*
1288eda14cbcSMatt Macy * Turn off these bits in order to not have to worry about
1289eda14cbcSMatt Macy * them when doing the checks for compliments.
1290eda14cbcSMatt Macy */
1291eda14cbcSMatt Macy acep->a_access_mask &= ~(ACE_WRITE_OWNER | ACE_DELETE |
1292eda14cbcSMatt Macy ACE_SYNCHRONIZE | ACE_WRITE_ATTRIBUTES |
1293eda14cbcSMatt Macy ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS);
1294eda14cbcSMatt Macy
1295eda14cbcSMatt Macy /* see if this should be a regular or default acl */
1296eda14cbcSMatt Macy bits = acep->a_flags &
1297eda14cbcSMatt Macy (ACE_INHERIT_ONLY_ACE |
1298eda14cbcSMatt Macy ACE_FILE_INHERIT_ACE |
1299eda14cbcSMatt Macy ACE_DIRECTORY_INHERIT_ACE);
1300eda14cbcSMatt Macy if (bits != 0) {
1301eda14cbcSMatt Macy /* all or nothing on these inherit bits */
1302eda14cbcSMatt Macy if (bits != (ACE_INHERIT_ONLY_ACE |
1303eda14cbcSMatt Macy ACE_FILE_INHERIT_ACE |
1304eda14cbcSMatt Macy ACE_DIRECTORY_INHERIT_ACE)) {
1305eda14cbcSMatt Macy error = ENOTSUP;
1306eda14cbcSMatt Macy goto out;
1307eda14cbcSMatt Macy }
1308eda14cbcSMatt Macy acl = dfacl;
1309eda14cbcSMatt Macy } else {
1310eda14cbcSMatt Macy acl = normacl;
1311eda14cbcSMatt Macy }
1312eda14cbcSMatt Macy
1313eda14cbcSMatt Macy if ((acep->a_flags & ACE_OWNER)) {
1314eda14cbcSMatt Macy if (acl->state > ace_user_obj) {
1315eda14cbcSMatt Macy error = ENOTSUP;
1316eda14cbcSMatt Macy goto out;
1317eda14cbcSMatt Macy }
1318eda14cbcSMatt Macy acl->state = ace_user_obj;
1319eda14cbcSMatt Macy acl->seen |= USER_OBJ;
1320eda14cbcSMatt Macy vals = &acl->user_obj;
1321eda14cbcSMatt Macy vals->aent_type = USER_OBJ | acl->dfacl_flag;
1322eda14cbcSMatt Macy } else if ((acep->a_flags & ACE_EVERYONE)) {
1323eda14cbcSMatt Macy acl->state = ace_other_obj;
1324eda14cbcSMatt Macy acl->seen |= OTHER_OBJ;
1325eda14cbcSMatt Macy vals = &acl->other_obj;
1326eda14cbcSMatt Macy vals->aent_type = OTHER_OBJ | acl->dfacl_flag;
1327eda14cbcSMatt Macy } else if (acep->a_flags & ACE_IDENTIFIER_GROUP) {
1328eda14cbcSMatt Macy if (acl->state > ace_group) {
1329eda14cbcSMatt Macy error = ENOTSUP;
1330eda14cbcSMatt Macy goto out;
1331eda14cbcSMatt Macy }
1332eda14cbcSMatt Macy if ((acep->a_flags & ACE_GROUP)) {
1333eda14cbcSMatt Macy acl->seen |= GROUP_OBJ;
1334eda14cbcSMatt Macy vals = &acl->group_obj;
1335eda14cbcSMatt Macy vals->aent_type = GROUP_OBJ | acl->dfacl_flag;
1336eda14cbcSMatt Macy } else {
1337eda14cbcSMatt Macy acl->seen |= GROUP;
1338eda14cbcSMatt Macy vals = acevals_find(acep, &acl->group,
1339eda14cbcSMatt Macy &acl->numgroups);
1340eda14cbcSMatt Macy if (vals == NULL) {
1341eda14cbcSMatt Macy error = ENOMEM;
1342eda14cbcSMatt Macy goto out;
1343eda14cbcSMatt Macy }
1344eda14cbcSMatt Macy vals->aent_type = GROUP | acl->dfacl_flag;
1345eda14cbcSMatt Macy }
1346eda14cbcSMatt Macy acl->state = ace_group;
1347eda14cbcSMatt Macy } else {
1348eda14cbcSMatt Macy if (acl->state > ace_user) {
1349eda14cbcSMatt Macy error = ENOTSUP;
1350eda14cbcSMatt Macy goto out;
1351eda14cbcSMatt Macy }
1352eda14cbcSMatt Macy acl->state = ace_user;
1353eda14cbcSMatt Macy acl->seen |= USER;
1354eda14cbcSMatt Macy vals = acevals_find(acep, &acl->user,
1355eda14cbcSMatt Macy &acl->numusers);
1356eda14cbcSMatt Macy if (vals == NULL) {
1357eda14cbcSMatt Macy error = ENOMEM;
1358eda14cbcSMatt Macy goto out;
1359eda14cbcSMatt Macy }
1360eda14cbcSMatt Macy vals->aent_type = USER | acl->dfacl_flag;
1361eda14cbcSMatt Macy }
1362eda14cbcSMatt Macy
1363eda14cbcSMatt Macy if (!(acl->state > ace_unused)) {
1364eda14cbcSMatt Macy error = EINVAL;
1365eda14cbcSMatt Macy goto out;
1366eda14cbcSMatt Macy }
1367eda14cbcSMatt Macy
1368eda14cbcSMatt Macy if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
1369eda14cbcSMatt Macy /* no more than one allowed per aclent_t */
1370eda14cbcSMatt Macy if (vals->allowed != ACE_MASK_UNDEFINED) {
1371eda14cbcSMatt Macy error = ENOTSUP;
1372eda14cbcSMatt Macy goto out;
1373eda14cbcSMatt Macy }
1374eda14cbcSMatt Macy vals->allowed = acep->a_access_mask;
1375eda14cbcSMatt Macy } else {
1376eda14cbcSMatt Macy /*
1377eda14cbcSMatt Macy * it's a DENY; if there was a previous DENY, it
1378eda14cbcSMatt Macy * must have been an ACL_MASK.
1379eda14cbcSMatt Macy */
1380eda14cbcSMatt Macy if (vals->denied != ACE_MASK_UNDEFINED) {
1381eda14cbcSMatt Macy /* ACL_MASK is for USER and GROUP only */
1382eda14cbcSMatt Macy if ((acl->state != ace_user) &&
1383eda14cbcSMatt Macy (acl->state != ace_group)) {
1384eda14cbcSMatt Macy error = ENOTSUP;
1385eda14cbcSMatt Macy goto out;
1386eda14cbcSMatt Macy }
1387eda14cbcSMatt Macy
1388eda14cbcSMatt Macy if (! acl->hasmask) {
1389eda14cbcSMatt Macy acl->hasmask = 1;
1390eda14cbcSMatt Macy acl->acl_mask = vals->denied;
1391eda14cbcSMatt Macy /* check for mismatched ACL_MASK emulations */
1392eda14cbcSMatt Macy } else if (acl->acl_mask != vals->denied) {
1393eda14cbcSMatt Macy error = ENOTSUP;
1394eda14cbcSMatt Macy goto out;
1395eda14cbcSMatt Macy }
1396eda14cbcSMatt Macy vals->mask = vals->denied;
1397eda14cbcSMatt Macy }
1398eda14cbcSMatt Macy vals->denied = acep->a_access_mask;
1399eda14cbcSMatt Macy }
1400eda14cbcSMatt Macy }
1401eda14cbcSMatt Macy
1402eda14cbcSMatt Macy /* done collating; produce the aclent_t lists */
1403eda14cbcSMatt Macy if (normacl->state != ace_unused) {
1404eda14cbcSMatt Macy error = ace_list_to_aent(normacl, aclentp, aclcnt,
1405eda14cbcSMatt Macy owner, group, isdir);
1406eda14cbcSMatt Macy if (error != 0) {
1407eda14cbcSMatt Macy goto out;
1408eda14cbcSMatt Macy }
1409eda14cbcSMatt Macy }
1410eda14cbcSMatt Macy if (dfacl->state != ace_unused) {
1411eda14cbcSMatt Macy error = ace_list_to_aent(dfacl, dfaclentp, dfaclcnt,
1412eda14cbcSMatt Macy owner, group, isdir);
1413eda14cbcSMatt Macy if (error != 0) {
1414eda14cbcSMatt Macy goto out;
1415eda14cbcSMatt Macy }
1416eda14cbcSMatt Macy }
1417eda14cbcSMatt Macy
1418eda14cbcSMatt Macy out:
1419eda14cbcSMatt Macy if (normacl != NULL)
1420eda14cbcSMatt Macy ace_list_free(normacl);
1421eda14cbcSMatt Macy if (dfacl != NULL)
1422eda14cbcSMatt Macy ace_list_free(dfacl);
1423eda14cbcSMatt Macy
1424eda14cbcSMatt Macy return (error);
1425eda14cbcSMatt Macy }
1426eda14cbcSMatt Macy
1427eda14cbcSMatt Macy static int
convert_ace_to_aent(ace_t * acebufp,int acecnt,boolean_t isdir,uid_t owner,gid_t group,aclent_t ** retaclentp,int * retaclcnt)1428eda14cbcSMatt Macy convert_ace_to_aent(ace_t *acebufp, int acecnt, boolean_t isdir,
1429eda14cbcSMatt Macy uid_t owner, gid_t group, aclent_t **retaclentp, int *retaclcnt)
1430eda14cbcSMatt Macy {
1431eda14cbcSMatt Macy int error = 0;
1432eda14cbcSMatt Macy aclent_t *aclentp, *dfaclentp;
1433eda14cbcSMatt Macy int aclcnt, dfaclcnt;
1434eda14cbcSMatt Macy int aclsz, dfaclsz;
1435eda14cbcSMatt Macy
1436eda14cbcSMatt Macy error = ln_ace_to_aent(acebufp, acecnt, owner, group,
1437eda14cbcSMatt Macy &aclentp, &aclcnt, &dfaclentp, &dfaclcnt, isdir);
1438eda14cbcSMatt Macy
1439eda14cbcSMatt Macy if (error)
1440eda14cbcSMatt Macy return (error);
1441eda14cbcSMatt Macy
1442eda14cbcSMatt Macy
1443eda14cbcSMatt Macy if (dfaclcnt != 0) {
1444eda14cbcSMatt Macy /*
1445eda14cbcSMatt Macy * Slap aclentp and dfaclentp into a single array.
1446eda14cbcSMatt Macy */
1447eda14cbcSMatt Macy aclsz = sizeof (aclent_t) * aclcnt;
1448eda14cbcSMatt Macy dfaclsz = sizeof (aclent_t) * dfaclcnt;
1449eda14cbcSMatt Macy aclentp = cacl_realloc(aclentp, aclsz, aclsz + dfaclsz);
1450eda14cbcSMatt Macy if (aclentp != NULL) {
1451eda14cbcSMatt Macy (void) memcpy(aclentp + aclcnt, dfaclentp, dfaclsz);
1452eda14cbcSMatt Macy } else {
1453eda14cbcSMatt Macy error = ENOMEM;
1454eda14cbcSMatt Macy }
1455eda14cbcSMatt Macy }
1456eda14cbcSMatt Macy
1457eda14cbcSMatt Macy if (aclentp) {
1458eda14cbcSMatt Macy *retaclentp = aclentp;
1459eda14cbcSMatt Macy *retaclcnt = aclcnt + dfaclcnt;
1460eda14cbcSMatt Macy }
1461eda14cbcSMatt Macy
1462eda14cbcSMatt Macy if (dfaclentp)
1463eda14cbcSMatt Macy cacl_free(dfaclentp, dfaclsz);
1464eda14cbcSMatt Macy
1465eda14cbcSMatt Macy return (error);
1466eda14cbcSMatt Macy }
1467eda14cbcSMatt Macy
1468eda14cbcSMatt Macy
1469eda14cbcSMatt Macy int
acl_translate(acl_t * aclp,int target_flavor,boolean_t isdir,uid_t owner,gid_t group)1470eda14cbcSMatt Macy acl_translate(acl_t *aclp, int target_flavor, boolean_t isdir, uid_t owner,
1471eda14cbcSMatt Macy gid_t group)
1472eda14cbcSMatt Macy {
1473eda14cbcSMatt Macy int aclcnt;
1474eda14cbcSMatt Macy void *acldata;
1475eda14cbcSMatt Macy int error;
1476eda14cbcSMatt Macy
1477eda14cbcSMatt Macy /*
1478eda14cbcSMatt Macy * See if we need to translate
1479eda14cbcSMatt Macy */
1480eda14cbcSMatt Macy if ((target_flavor == _ACL_ACE_ENABLED && aclp->acl_type == ACE_T) ||
1481eda14cbcSMatt Macy (target_flavor == _ACL_ACLENT_ENABLED &&
1482eda14cbcSMatt Macy aclp->acl_type == ACLENT_T))
1483eda14cbcSMatt Macy return (0);
1484eda14cbcSMatt Macy
1485eda14cbcSMatt Macy if (target_flavor == -1) {
1486eda14cbcSMatt Macy error = EINVAL;
1487eda14cbcSMatt Macy goto out;
1488eda14cbcSMatt Macy }
1489eda14cbcSMatt Macy
1490eda14cbcSMatt Macy if (target_flavor == _ACL_ACE_ENABLED &&
1491eda14cbcSMatt Macy aclp->acl_type == ACLENT_T) {
1492eda14cbcSMatt Macy error = convert_aent_to_ace(aclp->acl_aclp,
1493eda14cbcSMatt Macy aclp->acl_cnt, isdir, (ace_t **)&acldata, &aclcnt);
1494eda14cbcSMatt Macy if (error)
1495eda14cbcSMatt Macy goto out;
1496eda14cbcSMatt Macy
1497eda14cbcSMatt Macy } else if (target_flavor == _ACL_ACLENT_ENABLED &&
1498eda14cbcSMatt Macy aclp->acl_type == ACE_T) {
1499eda14cbcSMatt Macy error = convert_ace_to_aent(aclp->acl_aclp, aclp->acl_cnt,
1500eda14cbcSMatt Macy isdir, owner, group, (aclent_t **)&acldata, &aclcnt);
1501eda14cbcSMatt Macy if (error)
1502eda14cbcSMatt Macy goto out;
1503eda14cbcSMatt Macy } else {
1504eda14cbcSMatt Macy error = ENOTSUP;
1505eda14cbcSMatt Macy goto out;
1506eda14cbcSMatt Macy }
1507eda14cbcSMatt Macy
1508eda14cbcSMatt Macy /*
1509eda14cbcSMatt Macy * replace old acl with newly translated acl
1510eda14cbcSMatt Macy */
1511eda14cbcSMatt Macy cacl_free(aclp->acl_aclp, aclp->acl_cnt * aclp->acl_entry_size);
1512eda14cbcSMatt Macy aclp->acl_aclp = acldata;
1513eda14cbcSMatt Macy aclp->acl_cnt = aclcnt;
1514eda14cbcSMatt Macy if (target_flavor == _ACL_ACE_ENABLED) {
1515eda14cbcSMatt Macy aclp->acl_type = ACE_T;
1516eda14cbcSMatt Macy aclp->acl_entry_size = sizeof (ace_t);
1517eda14cbcSMatt Macy } else {
1518eda14cbcSMatt Macy aclp->acl_type = ACLENT_T;
1519eda14cbcSMatt Macy aclp->acl_entry_size = sizeof (aclent_t);
1520eda14cbcSMatt Macy }
1521eda14cbcSMatt Macy return (0);
1522eda14cbcSMatt Macy
1523eda14cbcSMatt Macy out:
1524eda14cbcSMatt Macy
1525eda14cbcSMatt Macy #if !defined(_KERNEL)
1526eda14cbcSMatt Macy errno = error;
1527eda14cbcSMatt Macy return (-1);
1528eda14cbcSMatt Macy #else
1529eda14cbcSMatt Macy return (error);
1530eda14cbcSMatt Macy #endif
1531eda14cbcSMatt Macy }
1532eda14cbcSMatt Macy #endif /* !_KERNEL */
1533eda14cbcSMatt Macy
1534eda14cbcSMatt Macy #define SET_ACE(acl, index, who, mask, type, flags) { \
1535eda14cbcSMatt Macy acl[0][index].a_who = (uint32_t)who; \
1536eda14cbcSMatt Macy acl[0][index].a_type = type; \
1537eda14cbcSMatt Macy acl[0][index].a_flags = flags; \
1538eda14cbcSMatt Macy acl[0][index++].a_access_mask = mask; \
1539eda14cbcSMatt Macy }
1540eda14cbcSMatt Macy
1541eda14cbcSMatt Macy void
acl_trivial_access_masks(mode_t mode,boolean_t isdir,trivial_acl_t * masks)1542eda14cbcSMatt Macy acl_trivial_access_masks(mode_t mode, boolean_t isdir, trivial_acl_t *masks)
1543eda14cbcSMatt Macy {
1544eda14cbcSMatt Macy uint32_t read_mask = ACE_READ_DATA;
1545eda14cbcSMatt Macy uint32_t write_mask = ACE_WRITE_DATA|ACE_APPEND_DATA;
1546eda14cbcSMatt Macy uint32_t execute_mask = ACE_EXECUTE;
1547eda14cbcSMatt Macy
1548eda14cbcSMatt Macy (void) isdir; /* will need this later */
1549eda14cbcSMatt Macy
1550eda14cbcSMatt Macy masks->deny1 = 0;
1551eda14cbcSMatt Macy if (!(mode & S_IRUSR) && (mode & (S_IRGRP|S_IROTH)))
1552eda14cbcSMatt Macy masks->deny1 |= read_mask;
1553eda14cbcSMatt Macy if (!(mode & S_IWUSR) && (mode & (S_IWGRP|S_IWOTH)))
1554eda14cbcSMatt Macy masks->deny1 |= write_mask;
1555eda14cbcSMatt Macy if (!(mode & S_IXUSR) && (mode & (S_IXGRP|S_IXOTH)))
1556eda14cbcSMatt Macy masks->deny1 |= execute_mask;
1557eda14cbcSMatt Macy
1558eda14cbcSMatt Macy masks->deny2 = 0;
1559eda14cbcSMatt Macy if (!(mode & S_IRGRP) && (mode & S_IROTH))
1560eda14cbcSMatt Macy masks->deny2 |= read_mask;
1561eda14cbcSMatt Macy if (!(mode & S_IWGRP) && (mode & S_IWOTH))
1562eda14cbcSMatt Macy masks->deny2 |= write_mask;
1563eda14cbcSMatt Macy if (!(mode & S_IXGRP) && (mode & S_IXOTH))
1564eda14cbcSMatt Macy masks->deny2 |= execute_mask;
1565eda14cbcSMatt Macy
1566eda14cbcSMatt Macy masks->allow0 = 0;
1567eda14cbcSMatt Macy if ((mode & S_IRUSR) && (!(mode & S_IRGRP) && (mode & S_IROTH)))
1568eda14cbcSMatt Macy masks->allow0 |= read_mask;
1569eda14cbcSMatt Macy if ((mode & S_IWUSR) && (!(mode & S_IWGRP) && (mode & S_IWOTH)))
1570eda14cbcSMatt Macy masks->allow0 |= write_mask;
1571eda14cbcSMatt Macy if ((mode & S_IXUSR) && (!(mode & S_IXGRP) && (mode & S_IXOTH)))
1572eda14cbcSMatt Macy masks->allow0 |= execute_mask;
1573eda14cbcSMatt Macy
1574eda14cbcSMatt Macy masks->owner = ACE_WRITE_ATTRIBUTES|ACE_WRITE_OWNER|ACE_WRITE_ACL|
1575eda14cbcSMatt Macy ACE_WRITE_NAMED_ATTRS|ACE_READ_ACL|ACE_READ_ATTRIBUTES|
1576eda14cbcSMatt Macy ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE;
1577eda14cbcSMatt Macy if (mode & S_IRUSR)
1578eda14cbcSMatt Macy masks->owner |= read_mask;
1579eda14cbcSMatt Macy if (mode & S_IWUSR)
1580eda14cbcSMatt Macy masks->owner |= write_mask;
1581eda14cbcSMatt Macy if (mode & S_IXUSR)
1582eda14cbcSMatt Macy masks->owner |= execute_mask;
1583eda14cbcSMatt Macy
1584eda14cbcSMatt Macy masks->group = ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_NAMED_ATTRS|
1585eda14cbcSMatt Macy ACE_SYNCHRONIZE;
1586eda14cbcSMatt Macy if (mode & S_IRGRP)
1587eda14cbcSMatt Macy masks->group |= read_mask;
1588eda14cbcSMatt Macy if (mode & S_IWGRP)
1589eda14cbcSMatt Macy masks->group |= write_mask;
1590eda14cbcSMatt Macy if (mode & S_IXGRP)
1591eda14cbcSMatt Macy masks->group |= execute_mask;
1592eda14cbcSMatt Macy
1593eda14cbcSMatt Macy masks->everyone = ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_NAMED_ATTRS|
1594eda14cbcSMatt Macy ACE_SYNCHRONIZE;
1595eda14cbcSMatt Macy if (mode & S_IROTH)
1596eda14cbcSMatt Macy masks->everyone |= read_mask;
1597eda14cbcSMatt Macy if (mode & S_IWOTH)
1598eda14cbcSMatt Macy masks->everyone |= write_mask;
1599eda14cbcSMatt Macy if (mode & S_IXOTH)
1600eda14cbcSMatt Macy masks->everyone |= execute_mask;
1601eda14cbcSMatt Macy }
1602eda14cbcSMatt Macy
1603eda14cbcSMatt Macy int
acl_trivial_create(mode_t mode,boolean_t isdir,ace_t ** acl,int * count)1604eda14cbcSMatt Macy acl_trivial_create(mode_t mode, boolean_t isdir, ace_t **acl, int *count)
1605eda14cbcSMatt Macy {
1606eda14cbcSMatt Macy int index = 0;
1607eda14cbcSMatt Macy int error;
1608eda14cbcSMatt Macy trivial_acl_t masks;
1609eda14cbcSMatt Macy
1610eda14cbcSMatt Macy *count = 3;
1611eda14cbcSMatt Macy acl_trivial_access_masks(mode, isdir, &masks);
1612eda14cbcSMatt Macy
1613eda14cbcSMatt Macy if (masks.allow0)
1614eda14cbcSMatt Macy (*count)++;
1615eda14cbcSMatt Macy if (masks.deny1)
1616eda14cbcSMatt Macy (*count)++;
1617eda14cbcSMatt Macy if (masks.deny2)
1618eda14cbcSMatt Macy (*count)++;
1619eda14cbcSMatt Macy
1620eda14cbcSMatt Macy if ((error = cacl_malloc((void **)acl, *count * sizeof (ace_t))) != 0)
1621eda14cbcSMatt Macy return (error);
1622eda14cbcSMatt Macy
1623eda14cbcSMatt Macy if (masks.allow0) {
1624eda14cbcSMatt Macy SET_ACE(acl, index, -1, masks.allow0,
1625eda14cbcSMatt Macy ACE_ACCESS_ALLOWED_ACE_TYPE, ACE_OWNER);
1626eda14cbcSMatt Macy }
1627eda14cbcSMatt Macy if (masks.deny1) {
1628eda14cbcSMatt Macy SET_ACE(acl, index, -1, masks.deny1,
1629eda14cbcSMatt Macy ACE_ACCESS_DENIED_ACE_TYPE, ACE_OWNER);
1630eda14cbcSMatt Macy }
1631eda14cbcSMatt Macy if (masks.deny2) {
1632eda14cbcSMatt Macy SET_ACE(acl, index, -1, masks.deny2,
1633eda14cbcSMatt Macy ACE_ACCESS_DENIED_ACE_TYPE, ACE_GROUP|ACE_IDENTIFIER_GROUP);
1634eda14cbcSMatt Macy }
1635eda14cbcSMatt Macy
1636eda14cbcSMatt Macy SET_ACE(acl, index, -1, masks.owner, ACE_ACCESS_ALLOWED_ACE_TYPE,
1637eda14cbcSMatt Macy ACE_OWNER);
1638eda14cbcSMatt Macy SET_ACE(acl, index, -1, masks.group, ACE_ACCESS_ALLOWED_ACE_TYPE,
1639eda14cbcSMatt Macy ACE_IDENTIFIER_GROUP|ACE_GROUP);
1640eda14cbcSMatt Macy SET_ACE(acl, index, -1, masks.everyone, ACE_ACCESS_ALLOWED_ACE_TYPE,
1641eda14cbcSMatt Macy ACE_EVERYONE);
1642eda14cbcSMatt Macy
1643eda14cbcSMatt Macy return (0);
1644eda14cbcSMatt Macy }
1645eda14cbcSMatt Macy
1646eda14cbcSMatt Macy /*
1647eda14cbcSMatt Macy * ace_trivial:
1648eda14cbcSMatt Macy * determine whether an ace_t acl is trivial
1649eda14cbcSMatt Macy *
1650eda14cbcSMatt Macy * Trivialness implies that the acl is composed of only
1651eda14cbcSMatt Macy * owner, group, everyone entries. ACL can't
1652eda14cbcSMatt Macy * have read_acl denied, and write_owner/write_acl/write_attributes
1653eda14cbcSMatt Macy * can only be owner@ entry.
1654eda14cbcSMatt Macy */
1655eda14cbcSMatt Macy int
ace_trivial_common(void * acep,int aclcnt,uintptr_t (* walk)(void *,uintptr_t,int aclcnt,uint16_t *,uint16_t *,uint32_t *))1656eda14cbcSMatt Macy ace_trivial_common(void *acep, int aclcnt,
1657*dbd5678dSMartin Matuska uintptr_t (*walk)(void *, uintptr_t, int aclcnt,
1658eda14cbcSMatt Macy uint16_t *, uint16_t *, uint32_t *))
1659eda14cbcSMatt Macy {
1660eda14cbcSMatt Macy uint16_t flags;
1661eda14cbcSMatt Macy uint32_t mask;
1662eda14cbcSMatt Macy uint16_t type;
1663*dbd5678dSMartin Matuska uintptr_t cookie = 0;
1664eda14cbcSMatt Macy
1665eda14cbcSMatt Macy while ((cookie = walk(acep, cookie, aclcnt, &flags, &type, &mask))) {
1666eda14cbcSMatt Macy switch (flags & ACE_TYPE_FLAGS) {
1667eda14cbcSMatt Macy case ACE_OWNER:
1668eda14cbcSMatt Macy case ACE_GROUP|ACE_IDENTIFIER_GROUP:
1669eda14cbcSMatt Macy case ACE_EVERYONE:
1670eda14cbcSMatt Macy break;
1671eda14cbcSMatt Macy default:
1672eda14cbcSMatt Macy return (1);
1673eda14cbcSMatt Macy
1674eda14cbcSMatt Macy }
1675eda14cbcSMatt Macy
1676eda14cbcSMatt Macy if (flags & (ACE_FILE_INHERIT_ACE|
1677eda14cbcSMatt Macy ACE_DIRECTORY_INHERIT_ACE|ACE_NO_PROPAGATE_INHERIT_ACE|
1678eda14cbcSMatt Macy ACE_INHERIT_ONLY_ACE))
1679eda14cbcSMatt Macy return (1);
1680eda14cbcSMatt Macy
1681eda14cbcSMatt Macy /*
1682eda14cbcSMatt Macy * Special check for some special bits
1683eda14cbcSMatt Macy *
1684eda14cbcSMatt Macy * Don't allow anybody to deny reading basic
1685eda14cbcSMatt Macy * attributes or a files ACL.
1686eda14cbcSMatt Macy */
1687eda14cbcSMatt Macy if ((mask & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) &&
1688eda14cbcSMatt Macy (type == ACE_ACCESS_DENIED_ACE_TYPE))
1689eda14cbcSMatt Macy return (1);
1690eda14cbcSMatt Macy
1691eda14cbcSMatt Macy /*
1692eda14cbcSMatt Macy * Delete permissions are never set by default
1693eda14cbcSMatt Macy */
1694eda14cbcSMatt Macy if (mask & (ACE_DELETE|ACE_DELETE_CHILD))
1695eda14cbcSMatt Macy return (1);
1696eda14cbcSMatt Macy /*
1697eda14cbcSMatt Macy * only allow owner@ to have
1698eda14cbcSMatt Macy * write_acl/write_owner/write_attributes/write_xattr/
1699eda14cbcSMatt Macy */
1700eda14cbcSMatt Macy if (type == ACE_ACCESS_ALLOWED_ACE_TYPE &&
1701eda14cbcSMatt Macy (!(flags & ACE_OWNER) && (mask &
1702eda14cbcSMatt Macy (ACE_WRITE_OWNER|ACE_WRITE_ACL| ACE_WRITE_ATTRIBUTES|
1703eda14cbcSMatt Macy ACE_WRITE_NAMED_ATTRS))))
1704eda14cbcSMatt Macy return (1);
1705eda14cbcSMatt Macy
1706eda14cbcSMatt Macy }
1707eda14cbcSMatt Macy return (0);
1708eda14cbcSMatt Macy }
1709