1fa9e4066Sahrens /*
2fa9e4066Sahrens * CDDL HEADER START
3fa9e4066Sahrens *
4fa9e4066Sahrens * The contents of this file are subject to the terms of the
53eb3c573Smarks * Common Development and Distribution License (the "License").
63eb3c573Smarks * 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.
23*a3c49ce1SAlbert Lee * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
24fa9e4066Sahrens */
25fa9e4066Sahrens
26fa9e4066Sahrens
27fa9e4066Sahrens #include <stdlib.h>
28fa9e4066Sahrens #include <string.h>
29fa9e4066Sahrens #include <unistd.h>
30fa9e4066Sahrens #include <limits.h>
31fa9e4066Sahrens #include <grp.h>
32fa9e4066Sahrens #include <pwd.h>
333eb3c573Smarks #include <strings.h>
34fa9e4066Sahrens #include <sys/types.h>
35fa9e4066Sahrens #include <errno.h>
36fa9e4066Sahrens #include <sys/stat.h>
375a5eeccaSmarks #include <sys/varargs.h>
38fa9e4066Sahrens #include <locale.h>
39fa9e4066Sahrens #include <aclutils.h>
403eb3c573Smarks #include <sys/avl.h>
41da6c28aaSamw #include <acl_common.h>
42b249c65cSmarks #include <idmap.h>
43fa9e4066Sahrens
44fa9e4066Sahrens #define ACL_PATH 0
45fa9e4066Sahrens #define ACL_FD 1
46fa9e4066Sahrens
47d2443e76Smarks
48fa9e4066Sahrens typedef union {
49fa9e4066Sahrens const char *file;
50fa9e4066Sahrens int fd;
51fa9e4066Sahrens } acl_inp;
52fa9e4066Sahrens
53fa9e4066Sahrens
54fa9e4066Sahrens /*
55fa9e4066Sahrens * Determine whether a file has a trivial ACL
56fa9e4066Sahrens * returns: 0 = trivial
57fa9e4066Sahrens * 1 = nontrivial
58fa9e4066Sahrens * <0 some other system failure, such as ENOENT or EPERM
59fa9e4066Sahrens */
60fa9e4066Sahrens int
acl_trivial(const char * filename)61fa9e4066Sahrens acl_trivial(const char *filename)
62fa9e4066Sahrens {
63fa9e4066Sahrens int acl_flavor;
64fa9e4066Sahrens int aclcnt;
65fa9e4066Sahrens int cntcmd;
66fa9e4066Sahrens int val = 0;
67fa9e4066Sahrens ace_t *acep;
68fa9e4066Sahrens
69fa9e4066Sahrens acl_flavor = pathconf(filename, _PC_ACL_ENABLED);
70fa9e4066Sahrens
71fa9e4066Sahrens if (acl_flavor == _ACL_ACE_ENABLED)
72fa9e4066Sahrens cntcmd = ACE_GETACLCNT;
73fa9e4066Sahrens else
74fa9e4066Sahrens cntcmd = GETACLCNT;
75fa9e4066Sahrens
76fa9e4066Sahrens aclcnt = acl(filename, cntcmd, 0, NULL);
77fa9e4066Sahrens if (aclcnt > 0) {
78fa9e4066Sahrens if (acl_flavor == _ACL_ACE_ENABLED) {
79fa9e4066Sahrens acep = malloc(sizeof (ace_t) * aclcnt);
80fa9e4066Sahrens if (acep == NULL)
81fa9e4066Sahrens return (-1);
82fa9e4066Sahrens if (acl(filename, ACE_GETACL,
83fa9e4066Sahrens aclcnt, acep) < 0) {
84fa9e4066Sahrens free(acep);
85fa9e4066Sahrens return (-1);
86fa9e4066Sahrens }
87fa9e4066Sahrens
88fa9e4066Sahrens val = ace_trivial(acep, aclcnt);
89fa9e4066Sahrens free(acep);
90d2443e76Smarks
91fa9e4066Sahrens } else if (aclcnt > MIN_ACL_ENTRIES)
92fa9e4066Sahrens val = 1;
93fa9e4066Sahrens }
94fa9e4066Sahrens return (val);
95fa9e4066Sahrens }
96fa9e4066Sahrens
973eb3c573Smarks
980157963dSmarks static int
cacl_get(acl_inp inp,int get_flag,int type,acl_t ** aclp)99fa9e4066Sahrens cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp)
100fa9e4066Sahrens {
101fa9e4066Sahrens const char *fname;
102fa9e4066Sahrens int fd;
103fa9e4066Sahrens int ace_acl = 0;
104fa9e4066Sahrens int error;
105fa9e4066Sahrens int getcmd, cntcmd;
106fa9e4066Sahrens acl_t *acl_info;
107fa9e4066Sahrens int save_errno;
108fa9e4066Sahrens int stat_error;
109fa9e4066Sahrens struct stat64 statbuf;
110fa9e4066Sahrens
111fa9e4066Sahrens *aclp = NULL;
112fa9e4066Sahrens if (type == ACL_PATH) {
113fa9e4066Sahrens fname = inp.file;
114fa9e4066Sahrens ace_acl = pathconf(fname, _PC_ACL_ENABLED);
115fa9e4066Sahrens } else {
116fa9e4066Sahrens fd = inp.fd;
117fa9e4066Sahrens ace_acl = fpathconf(fd, _PC_ACL_ENABLED);
118fa9e4066Sahrens }
119fa9e4066Sahrens
120fa9e4066Sahrens /*
121fa9e4066Sahrens * if acl's aren't supported then
122fa9e4066Sahrens * send it through the old GETACL interface
123fa9e4066Sahrens */
124a222db82Smarks if (ace_acl == 0 || ace_acl == -1) {
125fa9e4066Sahrens ace_acl = _ACL_ACLENT_ENABLED;
126fa9e4066Sahrens }
127fa9e4066Sahrens
128fa9e4066Sahrens if (ace_acl & _ACL_ACE_ENABLED) {
129fa9e4066Sahrens cntcmd = ACE_GETACLCNT;
130fa9e4066Sahrens getcmd = ACE_GETACL;
131fa9e4066Sahrens acl_info = acl_alloc(ACE_T);
132fa9e4066Sahrens } else {
133fa9e4066Sahrens cntcmd = GETACLCNT;
134fa9e4066Sahrens getcmd = GETACL;
135fa9e4066Sahrens acl_info = acl_alloc(ACLENT_T);
136fa9e4066Sahrens }
137fa9e4066Sahrens
138fa9e4066Sahrens if (acl_info == NULL)
139fa9e4066Sahrens return (-1);
140fa9e4066Sahrens
141fa9e4066Sahrens if (type == ACL_PATH) {
142fa9e4066Sahrens acl_info->acl_cnt = acl(fname, cntcmd, 0, NULL);
143fa9e4066Sahrens } else {
144fa9e4066Sahrens acl_info->acl_cnt = facl(fd, cntcmd, 0, NULL);
145fa9e4066Sahrens }
146fa9e4066Sahrens
147fa9e4066Sahrens save_errno = errno;
148fa9e4066Sahrens if (acl_info->acl_cnt < 0) {
149fa9e4066Sahrens acl_free(acl_info);
150fa9e4066Sahrens errno = save_errno;
151fa9e4066Sahrens return (-1);
152fa9e4066Sahrens }
153fa9e4066Sahrens
154fa9e4066Sahrens if (acl_info->acl_cnt == 0) {
155fa9e4066Sahrens acl_free(acl_info);
156fa9e4066Sahrens errno = save_errno;
157fa9e4066Sahrens return (0);
158fa9e4066Sahrens }
159fa9e4066Sahrens
160fa9e4066Sahrens acl_info->acl_aclp =
161fa9e4066Sahrens malloc(acl_info->acl_cnt * acl_info->acl_entry_size);
162fa9e4066Sahrens save_errno = errno;
163fa9e4066Sahrens
164fa9e4066Sahrens if (acl_info->acl_aclp == NULL) {
165fa9e4066Sahrens acl_free(acl_info);
166fa9e4066Sahrens errno = save_errno;
167fa9e4066Sahrens return (-1);
168fa9e4066Sahrens }
169fa9e4066Sahrens
170fa9e4066Sahrens if (type == ACL_PATH) {
171fa9e4066Sahrens stat_error = stat64(fname, &statbuf);
172fa9e4066Sahrens error = acl(fname, getcmd, acl_info->acl_cnt,
173fa9e4066Sahrens acl_info->acl_aclp);
174fa9e4066Sahrens } else {
175fa9e4066Sahrens stat_error = fstat64(fd, &statbuf);
176fa9e4066Sahrens error = facl(fd, getcmd, acl_info->acl_cnt,
177fa9e4066Sahrens acl_info->acl_aclp);
178fa9e4066Sahrens }
179fa9e4066Sahrens
180fa9e4066Sahrens save_errno = errno;
181fa9e4066Sahrens if (error == -1) {
182fa9e4066Sahrens acl_free(acl_info);
183fa9e4066Sahrens errno = save_errno;
184fa9e4066Sahrens return (-1);
185fa9e4066Sahrens }
186fa9e4066Sahrens
187fa9e4066Sahrens
188fa9e4066Sahrens if (stat_error == 0) {
189fa9e4066Sahrens acl_info->acl_flags =
190fa9e4066Sahrens (S_ISDIR(statbuf.st_mode) ? ACL_IS_DIR : 0);
191fa9e4066Sahrens } else
192fa9e4066Sahrens acl_info->acl_flags = 0;
193fa9e4066Sahrens
194fa9e4066Sahrens switch (acl_info->acl_type) {
195fa9e4066Sahrens case ACLENT_T:
196fa9e4066Sahrens if (acl_info->acl_cnt <= MIN_ACL_ENTRIES)
197fa9e4066Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL;
198fa9e4066Sahrens break;
199fa9e4066Sahrens case ACE_T:
200fa9e4066Sahrens if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0)
201fa9e4066Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL;
202fa9e4066Sahrens break;
203fa9e4066Sahrens default:
204fa9e4066Sahrens errno = EINVAL;
205fa9e4066Sahrens acl_free(acl_info);
206fa9e4066Sahrens return (-1);
207fa9e4066Sahrens }
208fa9e4066Sahrens
209fa9e4066Sahrens if ((acl_info->acl_flags & ACL_IS_TRIVIAL) &&
210fa9e4066Sahrens (get_flag & ACL_NO_TRIVIAL)) {
211fa9e4066Sahrens acl_free(acl_info);
212fa9e4066Sahrens errno = 0;
213fa9e4066Sahrens return (0);
214fa9e4066Sahrens }
215fa9e4066Sahrens
216fa9e4066Sahrens *aclp = acl_info;
217fa9e4066Sahrens return (0);
218fa9e4066Sahrens }
219fa9e4066Sahrens
220fa9e4066Sahrens /*
221fa9e4066Sahrens * return -1 on failure, otherwise the number of acl
222fa9e4066Sahrens * entries is returned
223fa9e4066Sahrens */
224fa9e4066Sahrens int
acl_get(const char * path,int get_flag,acl_t ** aclp)225fa9e4066Sahrens acl_get(const char *path, int get_flag, acl_t **aclp)
226fa9e4066Sahrens {
227fa9e4066Sahrens acl_inp acl_inp;
228fa9e4066Sahrens acl_inp.file = path;
229fa9e4066Sahrens
230fa9e4066Sahrens return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp));
231fa9e4066Sahrens }
232fa9e4066Sahrens
233fa9e4066Sahrens int
facl_get(int fd,int get_flag,acl_t ** aclp)234fa9e4066Sahrens facl_get(int fd, int get_flag, acl_t **aclp)
235fa9e4066Sahrens {
236fa9e4066Sahrens
237fa9e4066Sahrens acl_inp acl_inp;
238fa9e4066Sahrens acl_inp.fd = fd;
239fa9e4066Sahrens
240fa9e4066Sahrens return (cacl_get(acl_inp, get_flag, ACL_FD, aclp));
241fa9e4066Sahrens }
242fa9e4066Sahrens
243fa9e4066Sahrens /*
244fa9e4066Sahrens * Set an ACL, translates acl to ace_t when appropriate.
245fa9e4066Sahrens */
246fa9e4066Sahrens static int
cacl_set(acl_inp * acl_inp,acl_t * aclp,int type)247fa9e4066Sahrens cacl_set(acl_inp *acl_inp, acl_t *aclp, int type)
248fa9e4066Sahrens {
249fa9e4066Sahrens int error = 0;
250fa9e4066Sahrens int acl_flavor_target;
251fa9e4066Sahrens struct stat64 statbuf;
252fa9e4066Sahrens int stat_error;
253fa9e4066Sahrens int isdir;
254fa9e4066Sahrens
255fa9e4066Sahrens
256fa9e4066Sahrens if (type == ACL_PATH) {
257fa9e4066Sahrens stat_error = stat64(acl_inp->file, &statbuf);
258fa9e4066Sahrens if (stat_error)
259fa9e4066Sahrens return (-1);
260fa9e4066Sahrens acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED);
261fa9e4066Sahrens } else {
262fa9e4066Sahrens stat_error = fstat64(acl_inp->fd, &statbuf);
263fa9e4066Sahrens if (stat_error)
264fa9e4066Sahrens return (-1);
265fa9e4066Sahrens acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED);
266fa9e4066Sahrens }
267fa9e4066Sahrens
268a222db82Smarks /*
269a222db82Smarks * If target returns an error or 0 from pathconf call then
270a222db82Smarks * fall back to UFS/POSIX Draft interface.
271a222db82Smarks * In the case of 0 we will then fail in either acl(2) or
272a222db82Smarks * acl_translate(). We could erroneously get 0 back from
273a222db82Smarks * a file system that is using fs_pathconf() and not answering
274a222db82Smarks * the _PC_ACL_ENABLED question itself.
275a222db82Smarks */
276a222db82Smarks if (acl_flavor_target == 0 || acl_flavor_target == -1)
277a222db82Smarks acl_flavor_target = _ACL_ACLENT_ENABLED;
278a222db82Smarks
279fa9e4066Sahrens isdir = S_ISDIR(statbuf.st_mode);
280fa9e4066Sahrens
2813eb3c573Smarks if ((error = acl_translate(aclp, acl_flavor_target, isdir,
2823eb3c573Smarks statbuf.st_uid, statbuf.st_gid)) != 0) {
2833eb3c573Smarks return (error);
284fa9e4066Sahrens }
285fa9e4066Sahrens
286fa9e4066Sahrens if (type == ACL_PATH) {
287fa9e4066Sahrens error = acl(acl_inp->file,
288fa9e4066Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL,
289fa9e4066Sahrens aclp->acl_cnt, aclp->acl_aclp);
290fa9e4066Sahrens } else {
291fa9e4066Sahrens error = facl(acl_inp->fd,
292fa9e4066Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL,
293fa9e4066Sahrens aclp->acl_cnt, aclp->acl_aclp);
294fa9e4066Sahrens }
295fa9e4066Sahrens
296fa9e4066Sahrens return (error);
297fa9e4066Sahrens }
298fa9e4066Sahrens
299fa9e4066Sahrens int
acl_set(const char * path,acl_t * aclp)300fa9e4066Sahrens acl_set(const char *path, acl_t *aclp)
301fa9e4066Sahrens {
302fa9e4066Sahrens acl_inp acl_inp;
303fa9e4066Sahrens
304fa9e4066Sahrens acl_inp.file = path;
305fa9e4066Sahrens
306fa9e4066Sahrens return (cacl_set(&acl_inp, aclp, ACL_PATH));
307fa9e4066Sahrens }
308fa9e4066Sahrens
309fa9e4066Sahrens int
facl_set(int fd,acl_t * aclp)310fa9e4066Sahrens facl_set(int fd, acl_t *aclp)
311fa9e4066Sahrens {
312fa9e4066Sahrens acl_inp acl_inp;
313fa9e4066Sahrens
314fa9e4066Sahrens acl_inp.fd = fd;
315fa9e4066Sahrens
316fa9e4066Sahrens return (cacl_set(&acl_inp, aclp, ACL_FD));
317fa9e4066Sahrens }
318fa9e4066Sahrens
319fa9e4066Sahrens int
acl_cnt(acl_t * aclp)320fa9e4066Sahrens acl_cnt(acl_t *aclp)
321fa9e4066Sahrens {
322fa9e4066Sahrens return (aclp->acl_cnt);
323fa9e4066Sahrens }
324fa9e4066Sahrens
325fa9e4066Sahrens int
acl_type(acl_t * aclp)326fa9e4066Sahrens acl_type(acl_t *aclp)
327fa9e4066Sahrens {
328fa9e4066Sahrens return (aclp->acl_type);
329fa9e4066Sahrens }
330fa9e4066Sahrens
331fa9e4066Sahrens acl_t *
acl_dup(acl_t * aclp)332fa9e4066Sahrens acl_dup(acl_t *aclp)
333fa9e4066Sahrens {
334fa9e4066Sahrens acl_t *newaclp;
335fa9e4066Sahrens
336fa9e4066Sahrens newaclp = acl_alloc(aclp->acl_type);
337fa9e4066Sahrens if (newaclp == NULL)
338fa9e4066Sahrens return (NULL);
339fa9e4066Sahrens
340fa9e4066Sahrens newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt);
341fa9e4066Sahrens if (newaclp->acl_aclp == NULL) {
342fa9e4066Sahrens acl_free(newaclp);
343fa9e4066Sahrens return (NULL);
344fa9e4066Sahrens }
345fa9e4066Sahrens
346fa9e4066Sahrens (void) memcpy(newaclp->acl_aclp,
347fa9e4066Sahrens aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt);
348fa9e4066Sahrens newaclp->acl_cnt = aclp->acl_cnt;
349fa9e4066Sahrens
350fa9e4066Sahrens return (newaclp);
351fa9e4066Sahrens }
352fa9e4066Sahrens
353fa9e4066Sahrens int
acl_flags(acl_t * aclp)354fa9e4066Sahrens acl_flags(acl_t *aclp)
355fa9e4066Sahrens {
356fa9e4066Sahrens return (aclp->acl_flags);
357fa9e4066Sahrens }
358fa9e4066Sahrens
359fa9e4066Sahrens void *
acl_data(acl_t * aclp)360fa9e4066Sahrens acl_data(acl_t *aclp)
361fa9e4066Sahrens {
362fa9e4066Sahrens return (aclp->acl_aclp);
363fa9e4066Sahrens }
364fa9e4066Sahrens
365fa9e4066Sahrens /*
36649f0e518Smarks * Take an acl array and build an acl_t.
36749f0e518Smarks */
36849f0e518Smarks acl_t *
acl_to_aclp(enum acl_type type,void * acl,int count)36949f0e518Smarks acl_to_aclp(enum acl_type type, void *acl, int count)
37049f0e518Smarks {
37149f0e518Smarks acl_t *aclp;
37249f0e518Smarks
37349f0e518Smarks
37449f0e518Smarks aclp = acl_alloc(type);
37549f0e518Smarks if (aclp == NULL)
37649f0e518Smarks return (aclp);
37749f0e518Smarks
37849f0e518Smarks aclp->acl_aclp = acl;
37949f0e518Smarks aclp->acl_cnt = count;
38049f0e518Smarks
38149f0e518Smarks return (aclp);
38249f0e518Smarks }
38349f0e518Smarks
38449f0e518Smarks /*
385fa9e4066Sahrens * Remove an ACL from a file and create a trivial ACL based
386fa9e4066Sahrens * off of the mode argument. After acl has been set owner/group
387fa9e4066Sahrens * are updated to match owner,group arguments
388fa9e4066Sahrens */
389fa9e4066Sahrens int
acl_strip(const char * file,uid_t owner,gid_t group,mode_t mode)390fa9e4066Sahrens acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode)
391fa9e4066Sahrens {
392fa9e4066Sahrens int error = 0;
393fa9e4066Sahrens aclent_t min_acl[MIN_ACL_ENTRIES];
39427dd1e87SMark Shellenbaum ace_t *min_ace_acl;
395fa9e4066Sahrens int acl_flavor;
396fa9e4066Sahrens int aclcnt;
397*a3c49ce1SAlbert Lee struct stat64 statbuf;
398fa9e4066Sahrens
399fa9e4066Sahrens acl_flavor = pathconf(file, _PC_ACL_ENABLED);
400fa9e4066Sahrens
401*a3c49ce1SAlbert Lee if (stat64(file, &statbuf) != 0) {
402*a3c49ce1SAlbert Lee error = 1;
403*a3c49ce1SAlbert Lee return (error);
404*a3c49ce1SAlbert Lee }
405*a3c49ce1SAlbert Lee
406fa9e4066Sahrens /*
407fa9e4066Sahrens * force it through aclent flavor when file system doesn't
408fa9e4066Sahrens * understand question
409fa9e4066Sahrens */
410a222db82Smarks if (acl_flavor == 0 || acl_flavor == -1)
411fa9e4066Sahrens acl_flavor = _ACL_ACLENT_ENABLED;
412fa9e4066Sahrens
413fa9e4066Sahrens if (acl_flavor & _ACL_ACLENT_ENABLED) {
414fa9e4066Sahrens min_acl[0].a_type = USER_OBJ;
415fa9e4066Sahrens min_acl[0].a_id = owner;
416fa9e4066Sahrens min_acl[0].a_perm = ((mode & 0700) >> 6);
417fa9e4066Sahrens min_acl[1].a_type = GROUP_OBJ;
418fa9e4066Sahrens min_acl[1].a_id = group;
419fa9e4066Sahrens min_acl[1].a_perm = ((mode & 0070) >> 3);
420fa9e4066Sahrens min_acl[2].a_type = CLASS_OBJ;
421fa9e4066Sahrens min_acl[2].a_id = (uid_t)-1;
422fa9e4066Sahrens min_acl[2].a_perm = ((mode & 0070) >> 3);
423fa9e4066Sahrens min_acl[3].a_type = OTHER_OBJ;
424fa9e4066Sahrens min_acl[3].a_id = (uid_t)-1;
425fa9e4066Sahrens min_acl[3].a_perm = (mode & 0007);
426fa9e4066Sahrens aclcnt = 4;
427fa9e4066Sahrens error = acl(file, SETACL, aclcnt, min_acl);
428fa9e4066Sahrens } else if (acl_flavor & _ACL_ACE_ENABLED) {
429*a3c49ce1SAlbert Lee if ((error = acl_trivial_create(mode, S_ISDIR(statbuf.st_mode),
430*a3c49ce1SAlbert Lee &min_ace_acl, &aclcnt)) != 0)
43127dd1e87SMark Shellenbaum return (error);
43227dd1e87SMark Shellenbaum error = acl(file, ACE_SETACL, aclcnt, min_ace_acl);
43327dd1e87SMark Shellenbaum free(min_ace_acl);
434fa9e4066Sahrens } else {
435fa9e4066Sahrens errno = EINVAL;
436fa9e4066Sahrens error = 1;
437fa9e4066Sahrens }
438fa9e4066Sahrens
439fa9e4066Sahrens if (error == 0)
440fa9e4066Sahrens error = chown(file, owner, group);
441fa9e4066Sahrens return (error);
442fa9e4066Sahrens }
443fa9e4066Sahrens
444fa9e4066Sahrens static int
ace_match(void * entry1,void * entry2)445fa9e4066Sahrens ace_match(void *entry1, void *entry2)
446fa9e4066Sahrens {
447fa9e4066Sahrens ace_t *p1 = (ace_t *)entry1;
448fa9e4066Sahrens ace_t *p2 = (ace_t *)entry2;
449fa9e4066Sahrens ace_t ace1, ace2;
450fa9e4066Sahrens
451fa9e4066Sahrens ace1 = *p1;
452fa9e4066Sahrens ace2 = *p2;
453fa9e4066Sahrens
454fa9e4066Sahrens /*
455fa9e4066Sahrens * Need to fixup who field for abstrations for
456fa9e4066Sahrens * accurate comparison, since field is undefined.
457fa9e4066Sahrens */
458fa9e4066Sahrens if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE))
459f48205beScasper ace1.a_who = (uid_t)-1;
460fa9e4066Sahrens if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE))
461f48205beScasper ace2.a_who = (uid_t)-1;
462fa9e4066Sahrens return (memcmp(&ace1, &ace2, sizeof (ace_t)));
463fa9e4066Sahrens }
464fa9e4066Sahrens
465fa9e4066Sahrens static int
aclent_match(void * entry1,void * entry2)466fa9e4066Sahrens aclent_match(void *entry1, void *entry2)
467fa9e4066Sahrens {
468fa9e4066Sahrens aclent_t *aclent1 = (aclent_t *)entry1;
469fa9e4066Sahrens aclent_t *aclent2 = (aclent_t *)entry2;
470fa9e4066Sahrens
471fa9e4066Sahrens return (memcmp(aclent1, aclent2, sizeof (aclent_t)));
472fa9e4066Sahrens }
473fa9e4066Sahrens
474fa9e4066Sahrens /*
475fa9e4066Sahrens * Find acl entries in acl that correspond to removeacl. Search
476fa9e4066Sahrens * is started from slot. The flag argument indicates whether to
477fa9e4066Sahrens * remove all matches or just the first match.
478fa9e4066Sahrens */
479fa9e4066Sahrens int
acl_removeentries(acl_t * acl,acl_t * removeacl,int start_slot,int flag)480fa9e4066Sahrens acl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag)
481fa9e4066Sahrens {
482fa9e4066Sahrens int i, j;
483fa9e4066Sahrens int match;
484fa9e4066Sahrens int (*acl_match)(void *acl1, void *acl2);
485fa9e4066Sahrens void *acl_entry, *remove_entry;
486fa9e4066Sahrens void *start;
487fa9e4066Sahrens int found = 0;
488fa9e4066Sahrens
489fa9e4066Sahrens if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST)
490fa9e4066Sahrens flag = ACL_REMOVE_FIRST;
491fa9e4066Sahrens
492fa9e4066Sahrens if (acl == NULL || removeacl == NULL)
493fa9e4066Sahrens return (EACL_NO_ACL_ENTRY);
494fa9e4066Sahrens
495fa9e4066Sahrens if (acl->acl_type != removeacl->acl_type)
496fa9e4066Sahrens return (EACL_DIFF_TYPE);
497fa9e4066Sahrens
498fa9e4066Sahrens if (acl->acl_type == ACLENT_T)
499fa9e4066Sahrens acl_match = aclent_match;
500fa9e4066Sahrens else
501fa9e4066Sahrens acl_match = ace_match;
502fa9e4066Sahrens
503fa9e4066Sahrens for (i = 0, remove_entry = removeacl->acl_aclp;
504fa9e4066Sahrens i != removeacl->acl_cnt; i++) {
505fa9e4066Sahrens
506fa9e4066Sahrens j = 0;
507fa9e4066Sahrens acl_entry = (char *)acl->acl_aclp +
508fa9e4066Sahrens (acl->acl_entry_size * start_slot);
509fa9e4066Sahrens for (;;) {
510fa9e4066Sahrens match = acl_match(acl_entry, remove_entry);
511fa9e4066Sahrens if (match == 0) {
512fa9e4066Sahrens found++;
51357841ad7SRenaud Manus
51457841ad7SRenaud Manus /* avoid memmove if last entry */
51557841ad7SRenaud Manus if (acl->acl_cnt == (j + 1)) {
51657841ad7SRenaud Manus acl->acl_cnt--;
51757841ad7SRenaud Manus break;
51857841ad7SRenaud Manus }
51957841ad7SRenaud Manus
520fa9e4066Sahrens start = (char *)acl_entry +
521fa9e4066Sahrens acl->acl_entry_size;
522fa9e4066Sahrens (void) memmove(acl_entry, start,
523fa9e4066Sahrens acl->acl_entry_size *
52457841ad7SRenaud Manus (acl->acl_cnt-- - (j + 1)));
525fa9e4066Sahrens
526fa9e4066Sahrens if (flag == ACL_REMOVE_FIRST)
527fa9e4066Sahrens break;
528fa9e4066Sahrens /*
529b249c65cSmarks * List has changed, just continue so this
530b249c65cSmarks * slot gets checked with it's new contents.
531fa9e4066Sahrens */
532fa9e4066Sahrens continue;
533fa9e4066Sahrens }
534fa9e4066Sahrens acl_entry = ((char *)acl_entry + acl->acl_entry_size);
535fa9e4066Sahrens if (++j >= acl->acl_cnt) {
536fa9e4066Sahrens break;
537fa9e4066Sahrens }
538fa9e4066Sahrens }
539b249c65cSmarks remove_entry = (char *)remove_entry + removeacl->acl_entry_size;
540fa9e4066Sahrens }
541fa9e4066Sahrens
542fa9e4066Sahrens return ((found == 0) ? EACL_NO_ACL_ENTRY : 0);
543fa9e4066Sahrens }
544fa9e4066Sahrens
545fa9e4066Sahrens /*
546fa9e4066Sahrens * Replace entires entries in acl1 with the corresponding entries
547fa9e4066Sahrens * in newentries. The where argument specifies where to begin
548fa9e4066Sahrens * the replacement. If the where argument is 1 greater than the
549fa9e4066Sahrens * number of acl entries in acl1 then they are appended. If the
550fa9e4066Sahrens * where argument is 2+ greater than the number of acl entries then
551fa9e4066Sahrens * EACL_INVALID_SLOT is returned.
552fa9e4066Sahrens */
553fa9e4066Sahrens int
acl_modifyentries(acl_t * acl1,acl_t * newentries,int where)554fa9e4066Sahrens acl_modifyentries(acl_t *acl1, acl_t *newentries, int where)
555fa9e4066Sahrens {
556fa9e4066Sahrens
557fa9e4066Sahrens int slot;
558fa9e4066Sahrens int slots_needed;
559fa9e4066Sahrens int slots_left;
560fa9e4066Sahrens int newsize;
561fa9e4066Sahrens
562fa9e4066Sahrens if (acl1 == NULL || newentries == NULL)
563fa9e4066Sahrens return (EACL_NO_ACL_ENTRY);
564fa9e4066Sahrens
565fa9e4066Sahrens if (where < 0 || where >= acl1->acl_cnt)
566fa9e4066Sahrens return (EACL_INVALID_SLOT);
567fa9e4066Sahrens
568fa9e4066Sahrens if (acl1->acl_type != newentries->acl_type)
569fa9e4066Sahrens return (EACL_DIFF_TYPE);
570fa9e4066Sahrens
571fa9e4066Sahrens slot = where;
572fa9e4066Sahrens
573fa9e4066Sahrens slots_left = acl1->acl_cnt - slot + 1;
574fa9e4066Sahrens if (slots_left < newentries->acl_cnt) {
575fa9e4066Sahrens slots_needed = newentries->acl_cnt - slots_left;
576fa9e4066Sahrens newsize = (acl1->acl_entry_size * acl1->acl_cnt) +
577fa9e4066Sahrens (acl1->acl_entry_size * slots_needed);
578fa9e4066Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize);
579fa9e4066Sahrens if (acl1->acl_aclp == NULL)
580fa9e4066Sahrens return (-1);
581fa9e4066Sahrens }
582fa9e4066Sahrens (void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot),
583fa9e4066Sahrens newentries->acl_aclp,
584fa9e4066Sahrens newentries->acl_entry_size * newentries->acl_cnt);
585fa9e4066Sahrens
586fa9e4066Sahrens /*
587fa9e4066Sahrens * Did ACL grow?
588fa9e4066Sahrens */
589fa9e4066Sahrens
590fa9e4066Sahrens if ((slot + newentries->acl_cnt) > acl1->acl_cnt) {
591fa9e4066Sahrens acl1->acl_cnt = slot + newentries->acl_cnt;
592fa9e4066Sahrens }
593fa9e4066Sahrens
594fa9e4066Sahrens return (0);
595fa9e4066Sahrens }
596fa9e4066Sahrens
597fa9e4066Sahrens /*
598fa9e4066Sahrens * Add acl2 entries into acl1. The where argument specifies where
599fa9e4066Sahrens * to add the entries.
600fa9e4066Sahrens */
601fa9e4066Sahrens int
acl_addentries(acl_t * acl1,acl_t * acl2,int where)602fa9e4066Sahrens acl_addentries(acl_t *acl1, acl_t *acl2, int where)
603fa9e4066Sahrens {
604fa9e4066Sahrens
605fa9e4066Sahrens int newsize;
606fa9e4066Sahrens int len;
607fa9e4066Sahrens void *start;
608fa9e4066Sahrens void *to;
609fa9e4066Sahrens
610fa9e4066Sahrens if (acl1 == NULL || acl2 == NULL)
611fa9e4066Sahrens return (EACL_NO_ACL_ENTRY);
612fa9e4066Sahrens
613fa9e4066Sahrens if (acl1->acl_type != acl2->acl_type)
614fa9e4066Sahrens return (EACL_DIFF_TYPE);
615fa9e4066Sahrens
616fa9e4066Sahrens /*
617fa9e4066Sahrens * allow where to specify 1 past last slot for an append operation
618fa9e4066Sahrens * but anything greater is an error.
619fa9e4066Sahrens */
620fa9e4066Sahrens if (where < 0 || where > acl1->acl_cnt)
621fa9e4066Sahrens return (EACL_INVALID_SLOT);
622fa9e4066Sahrens
623fa9e4066Sahrens newsize = (acl2->acl_entry_size * acl2->acl_cnt) +
624fa9e4066Sahrens (acl1->acl_entry_size * acl1->acl_cnt);
625fa9e4066Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize);
626fa9e4066Sahrens if (acl1->acl_aclp == NULL)
627fa9e4066Sahrens return (-1);
628fa9e4066Sahrens
629fa9e4066Sahrens /*
630fa9e4066Sahrens * first push down entries where new ones will be inserted
631fa9e4066Sahrens */
632fa9e4066Sahrens
633fa9e4066Sahrens to = (void *)((char *)acl1->acl_aclp +
634fa9e4066Sahrens ((where + acl2->acl_cnt) * acl1->acl_entry_size));
635fa9e4066Sahrens
636fa9e4066Sahrens start = (void *)((char *)acl1->acl_aclp +
637fa9e4066Sahrens where * acl1->acl_entry_size);
638fa9e4066Sahrens
639fa9e4066Sahrens if (where < acl1->acl_cnt) {
640fa9e4066Sahrens len = (acl1->acl_cnt - where) * acl1->acl_entry_size;
641fa9e4066Sahrens (void) memmove(to, start, len);
642fa9e4066Sahrens }
643fa9e4066Sahrens
644fa9e4066Sahrens /*
645fa9e4066Sahrens * now stick in new entries.
646fa9e4066Sahrens */
647fa9e4066Sahrens
648fa9e4066Sahrens (void) memmove(start, acl2->acl_aclp,
649fa9e4066Sahrens acl2->acl_cnt * acl2->acl_entry_size);
650fa9e4066Sahrens
651fa9e4066Sahrens acl1->acl_cnt += acl2->acl_cnt;
652fa9e4066Sahrens return (0);
653fa9e4066Sahrens }
654fa9e4066Sahrens
655fa9e4066Sahrens /*
656fa9e4066Sahrens * return text for an ACL error.
657fa9e4066Sahrens */
658fa9e4066Sahrens char *
acl_strerror(int errnum)659fa9e4066Sahrens acl_strerror(int errnum)
660fa9e4066Sahrens {
661fa9e4066Sahrens switch (errnum) {
662fa9e4066Sahrens case EACL_GRP_ERROR:
663fa9e4066Sahrens return (dgettext(TEXT_DOMAIN,
6645a5eeccaSmarks "There is more than one group or default group entry"));
665fa9e4066Sahrens case EACL_USER_ERROR:
666fa9e4066Sahrens return (dgettext(TEXT_DOMAIN,
6675a5eeccaSmarks "There is more than one user or default user entry"));
668fa9e4066Sahrens case EACL_OTHER_ERROR:
669fa9e4066Sahrens return (dgettext(TEXT_DOMAIN,
670fa9e4066Sahrens "There is more than one other entry"));
671fa9e4066Sahrens case EACL_CLASS_ERROR:
672fa9e4066Sahrens return (dgettext(TEXT_DOMAIN,
673fa9e4066Sahrens "There is more than one mask entry"));
674fa9e4066Sahrens case EACL_DUPLICATE_ERROR:
675fa9e4066Sahrens return (dgettext(TEXT_DOMAIN,
676fa9e4066Sahrens "Duplicate user or group entries"));
677fa9e4066Sahrens case EACL_MISS_ERROR:
678fa9e4066Sahrens return (dgettext(TEXT_DOMAIN,
679fa9e4066Sahrens "Missing user/group owner, other, mask entry"));
680fa9e4066Sahrens case EACL_MEM_ERROR:
681fa9e4066Sahrens return (dgettext(TEXT_DOMAIN,
682fa9e4066Sahrens "Memory error"));
683fa9e4066Sahrens case EACL_ENTRY_ERROR:
684fa9e4066Sahrens return (dgettext(TEXT_DOMAIN,
685fa9e4066Sahrens "Unrecognized entry type"));
686fa9e4066Sahrens case EACL_INHERIT_ERROR:
687fa9e4066Sahrens return (dgettext(TEXT_DOMAIN,
688fa9e4066Sahrens "Invalid inheritance flags"));
689fa9e4066Sahrens case EACL_FLAGS_ERROR:
690fa9e4066Sahrens return (dgettext(TEXT_DOMAIN,
691fa9e4066Sahrens "Unrecognized entry flags"));
692fa9e4066Sahrens case EACL_PERM_MASK_ERROR:
693fa9e4066Sahrens return (dgettext(TEXT_DOMAIN,
694fa9e4066Sahrens "Invalid ACL permissions"));
695fa9e4066Sahrens case EACL_COUNT_ERROR:
696fa9e4066Sahrens return (dgettext(TEXT_DOMAIN,
697fa9e4066Sahrens "Invalid ACL count"));
698fa9e4066Sahrens case EACL_INVALID_SLOT:
699fa9e4066Sahrens return (dgettext(TEXT_DOMAIN,
700fa9e4066Sahrens "Invalid ACL entry number specified"));
701fa9e4066Sahrens case EACL_NO_ACL_ENTRY:
702fa9e4066Sahrens return (dgettext(TEXT_DOMAIN,
703fa9e4066Sahrens "ACL entry doesn't exist"));
704fa9e4066Sahrens case EACL_DIFF_TYPE:
705fa9e4066Sahrens return (dgettext(TEXT_DOMAIN,
7062269545aSstephanie scheffler "Different file system ACL types cannot be merged"));
707fa9e4066Sahrens case EACL_INVALID_USER_GROUP:
708fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Invalid user or group"));
709fa9e4066Sahrens case EACL_INVALID_STR:
710fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "ACL string is invalid"));
711fa9e4066Sahrens case EACL_FIELD_NOT_BLANK:
712fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Field expected to be blank"));
713fa9e4066Sahrens case EACL_INVALID_ACCESS_TYPE:
714fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Invalid access type"));
715fa9e4066Sahrens case EACL_UNKNOWN_DATA:
716fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Unrecognized entry"));
717fa9e4066Sahrens case EACL_MISSING_FIELDS:
718fa9e4066Sahrens return (dgettext(TEXT_DOMAIN,
719fa9e4066Sahrens "ACL specification missing required fields"));
720fa9e4066Sahrens case EACL_INHERIT_NOTDIR:
721fa9e4066Sahrens return (dgettext(TEXT_DOMAIN,
722fa9e4066Sahrens "Inheritance flags are only allowed on directories"));
723fa9e4066Sahrens case -1:
724fa9e4066Sahrens return (strerror(errno));
725fa9e4066Sahrens default:
726fa9e4066Sahrens errno = EINVAL;
727fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Unknown error"));
728fa9e4066Sahrens }
729fa9e4066Sahrens }
7305a5eeccaSmarks
7315a5eeccaSmarks extern int yyinteractive;
7325a5eeccaSmarks
7335a5eeccaSmarks /* PRINTFLIKE1 */
7345a5eeccaSmarks void
acl_error(const char * fmt,...)7355a5eeccaSmarks acl_error(const char *fmt, ...)
7365a5eeccaSmarks {
7375a5eeccaSmarks va_list va;
7385a5eeccaSmarks
7395a5eeccaSmarks if (yyinteractive == 0)
7405a5eeccaSmarks return;
7415a5eeccaSmarks
7425a5eeccaSmarks va_start(va, fmt);
7435a5eeccaSmarks (void) vfprintf(stderr, fmt, va);
7445a5eeccaSmarks va_end(va);
7455a5eeccaSmarks }
746b249c65cSmarks
747b249c65cSmarks int
sid_to_id(char * sid,boolean_t user,uid_t * id)748b249c65cSmarks sid_to_id(char *sid, boolean_t user, uid_t *id)
749b249c65cSmarks {
750b249c65cSmarks idmap_get_handle_t *get_hdl = NULL;
751b249c65cSmarks char *rid_start = NULL;
752b249c65cSmarks idmap_stat status;
753b249c65cSmarks char *end;
754909c9a9fSMark Shellenbaum int error = 1;
755b249c65cSmarks char *domain_start;
756b249c65cSmarks
757b249c65cSmarks if ((domain_start = strchr(sid, '@')) == NULL) {
758b249c65cSmarks idmap_rid_t rid;
759b249c65cSmarks
760b249c65cSmarks if ((rid_start = strrchr(sid, '-')) == NULL)
761909c9a9fSMark Shellenbaum return (1);
762b249c65cSmarks *rid_start++ = '\0';
763b249c65cSmarks errno = 0;
764b249c65cSmarks rid = strtoul(rid_start--, &end, 10);
765b249c65cSmarks if (errno == 0 && *end == '\0') {
7661fdeec65Sjoyce mcintosh if (idmap_get_create(&get_hdl) ==
767909c9a9fSMark Shellenbaum IDMAP_SUCCESS) {
768b249c65cSmarks if (user)
769b249c65cSmarks error = idmap_get_uidbysid(get_hdl,
7703ee87bcaSJulian Pullen sid, rid, IDMAP_REQ_FLG_USE_CACHE,
7713ee87bcaSJulian Pullen id, &status);
772b249c65cSmarks else
773b249c65cSmarks error = idmap_get_gidbysid(get_hdl,
7743ee87bcaSJulian Pullen sid, rid, IDMAP_REQ_FLG_USE_CACHE,
7753ee87bcaSJulian Pullen id, &status);
776909c9a9fSMark Shellenbaum if (error == IDMAP_SUCCESS) {
777909c9a9fSMark Shellenbaum error = idmap_get_mappings(get_hdl);
778909c9a9fSMark Shellenbaum if (error == IDMAP_SUCCESS &&
779909c9a9fSMark Shellenbaum status != IDMAP_SUCCESS)
780909c9a9fSMark Shellenbaum error = 1;
781909c9a9fSMark Shellenbaum else
782909c9a9fSMark Shellenbaum error = 0;
783b249c65cSmarks }
784b249c65cSmarks } else {
785909c9a9fSMark Shellenbaum error = 1;
786b249c65cSmarks }
787b249c65cSmarks if (get_hdl)
788b249c65cSmarks idmap_get_destroy(get_hdl);
789909c9a9fSMark Shellenbaum } else {
790909c9a9fSMark Shellenbaum error = 1;
791909c9a9fSMark Shellenbaum }
792b249c65cSmarks *rid_start = '-'; /* putback character removed earlier */
793b249c65cSmarks } else {
794b249c65cSmarks char *name = sid;
795b249c65cSmarks *domain_start++ = '\0';
796b249c65cSmarks
797b249c65cSmarks if (user)
7983ee87bcaSJulian Pullen error = idmap_getuidbywinname(name, domain_start,
7993ee87bcaSJulian Pullen IDMAP_REQ_FLG_USE_CACHE, id);
800b249c65cSmarks else
8013ee87bcaSJulian Pullen error = idmap_getgidbywinname(name, domain_start,
8023ee87bcaSJulian Pullen IDMAP_REQ_FLG_USE_CACHE, id);
803b249c65cSmarks *--domain_start = '@';
804909c9a9fSMark Shellenbaum error = (error == IDMAP_SUCCESS) ? 0 : 1;
805b249c65cSmarks }
806b249c65cSmarks
807b249c65cSmarks return (error);
808b249c65cSmarks }
809