1789Sahrens /*
2789Sahrens * CDDL HEADER START
3789Sahrens *
4789Sahrens * The contents of this file are subject to the terms of the
51462Smarks * Common Development and Distribution License (the "License").
61462Smarks * You may not use this file except in compliance with the License.
7789Sahrens *
8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9789Sahrens * or http://www.opensolaris.org/os/licensing.
10789Sahrens * See the License for the specific language governing permissions
11789Sahrens * and limitations under the License.
12789Sahrens *
13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each
14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15789Sahrens * If applicable, add the following below this CDDL HEADER, with the
16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying
17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner]
18789Sahrens *
19789Sahrens * CDDL HEADER END
20789Sahrens */
21789Sahrens /*
2212164SMark.Shellenbaum@Sun.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23789Sahrens */
24789Sahrens
25789Sahrens
26789Sahrens #include <stdlib.h>
27789Sahrens #include <string.h>
28789Sahrens #include <unistd.h>
29789Sahrens #include <limits.h>
30789Sahrens #include <grp.h>
31789Sahrens #include <pwd.h>
321462Smarks #include <strings.h>
33789Sahrens #include <sys/types.h>
34789Sahrens #include <errno.h>
35789Sahrens #include <sys/stat.h>
361420Smarks #include <sys/varargs.h>
37789Sahrens #include <locale.h>
38789Sahrens #include <aclutils.h>
395331Samw #include <sys/avl.h>
40789Sahrens #include <acl_common.h>
417057Smarks #include <idmap.h>
42789Sahrens
43789Sahrens #define ACL_PATH 0
44789Sahrens #define ACL_FD 1
45789Sahrens
461231Smarks
47789Sahrens typedef union {
48789Sahrens const char *file;
49789Sahrens int fd;
50789Sahrens } acl_inp;
51789Sahrens
52789Sahrens
53789Sahrens /*
54789Sahrens * Determine whether a file has a trivial ACL
55789Sahrens * returns: 0 = trivial
56789Sahrens * 1 = nontrivial
57789Sahrens * <0 some other system failure, such as ENOENT or EPERM
58789Sahrens */
59789Sahrens int
acl_trivial(const char * filename)60789Sahrens acl_trivial(const char *filename)
61789Sahrens {
62789Sahrens int acl_flavor;
63789Sahrens int aclcnt;
64789Sahrens int cntcmd;
65789Sahrens int val = 0;
66789Sahrens ace_t *acep;
67789Sahrens
68789Sahrens acl_flavor = pathconf(filename, _PC_ACL_ENABLED);
69789Sahrens
70789Sahrens if (acl_flavor == _ACL_ACE_ENABLED)
71789Sahrens cntcmd = ACE_GETACLCNT;
72789Sahrens else
73789Sahrens cntcmd = GETACLCNT;
74789Sahrens
75789Sahrens aclcnt = acl(filename, cntcmd, 0, NULL);
76789Sahrens if (aclcnt > 0) {
77789Sahrens if (acl_flavor == _ACL_ACE_ENABLED) {
781231Smarks acep = malloc(sizeof (ace_t) * aclcnt);
791231Smarks if (acep == NULL)
801231Smarks return (-1);
811231Smarks if (acl(filename, ACE_GETACL,
821231Smarks aclcnt, acep) < 0) {
831231Smarks free(acep);
841231Smarks return (-1);
851231Smarks }
86789Sahrens
871231Smarks val = ace_trivial(acep, aclcnt);
881231Smarks free(acep);
891231Smarks
90789Sahrens } else if (aclcnt > MIN_ACL_ENTRIES)
91789Sahrens val = 1;
92789Sahrens }
93789Sahrens return (val);
94789Sahrens }
95789Sahrens
961462Smarks
971477Smarks static int
cacl_get(acl_inp inp,int get_flag,int type,acl_t ** aclp)98789Sahrens cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp)
99789Sahrens {
100789Sahrens const char *fname;
101789Sahrens int fd;
102789Sahrens int ace_acl = 0;
103789Sahrens int error;
104789Sahrens int getcmd, cntcmd;
105789Sahrens acl_t *acl_info;
106789Sahrens int save_errno;
107789Sahrens int stat_error;
108789Sahrens struct stat64 statbuf;
109789Sahrens
110789Sahrens *aclp = NULL;
111789Sahrens if (type == ACL_PATH) {
112789Sahrens fname = inp.file;
113789Sahrens ace_acl = pathconf(fname, _PC_ACL_ENABLED);
114789Sahrens } else {
115789Sahrens fd = inp.fd;
116789Sahrens ace_acl = fpathconf(fd, _PC_ACL_ENABLED);
117789Sahrens }
118789Sahrens
119789Sahrens /*
120789Sahrens * if acl's aren't supported then
121789Sahrens * send it through the old GETACL interface
122789Sahrens */
1231666Smarks if (ace_acl == 0 || ace_acl == -1) {
124789Sahrens ace_acl = _ACL_ACLENT_ENABLED;
125789Sahrens }
126789Sahrens
127789Sahrens if (ace_acl & _ACL_ACE_ENABLED) {
128789Sahrens cntcmd = ACE_GETACLCNT;
129789Sahrens getcmd = ACE_GETACL;
130789Sahrens acl_info = acl_alloc(ACE_T);
131789Sahrens } else {
132789Sahrens cntcmd = GETACLCNT;
133789Sahrens getcmd = GETACL;
134789Sahrens acl_info = acl_alloc(ACLENT_T);
135789Sahrens }
136789Sahrens
137789Sahrens if (acl_info == NULL)
138789Sahrens return (-1);
139789Sahrens
140789Sahrens if (type == ACL_PATH) {
141789Sahrens acl_info->acl_cnt = acl(fname, cntcmd, 0, NULL);
142789Sahrens } else {
143789Sahrens acl_info->acl_cnt = facl(fd, cntcmd, 0, NULL);
144789Sahrens }
145789Sahrens
146789Sahrens save_errno = errno;
147789Sahrens if (acl_info->acl_cnt < 0) {
148789Sahrens acl_free(acl_info);
149789Sahrens errno = save_errno;
150789Sahrens return (-1);
151789Sahrens }
152789Sahrens
153789Sahrens if (acl_info->acl_cnt == 0) {
154789Sahrens acl_free(acl_info);
155789Sahrens errno = save_errno;
156789Sahrens return (0);
157789Sahrens }
158789Sahrens
159789Sahrens acl_info->acl_aclp =
160789Sahrens malloc(acl_info->acl_cnt * acl_info->acl_entry_size);
161789Sahrens save_errno = errno;
162789Sahrens
163789Sahrens if (acl_info->acl_aclp == NULL) {
164789Sahrens acl_free(acl_info);
165789Sahrens errno = save_errno;
166789Sahrens return (-1);
167789Sahrens }
168789Sahrens
169789Sahrens if (type == ACL_PATH) {
170789Sahrens stat_error = stat64(fname, &statbuf);
171789Sahrens error = acl(fname, getcmd, acl_info->acl_cnt,
172789Sahrens acl_info->acl_aclp);
173789Sahrens } else {
174789Sahrens stat_error = fstat64(fd, &statbuf);
175789Sahrens error = facl(fd, getcmd, acl_info->acl_cnt,
176789Sahrens acl_info->acl_aclp);
177789Sahrens }
178789Sahrens
179789Sahrens save_errno = errno;
180789Sahrens if (error == -1) {
181789Sahrens acl_free(acl_info);
182789Sahrens errno = save_errno;
183789Sahrens return (-1);
184789Sahrens }
185789Sahrens
186789Sahrens
187789Sahrens if (stat_error == 0) {
188789Sahrens acl_info->acl_flags =
189789Sahrens (S_ISDIR(statbuf.st_mode) ? ACL_IS_DIR : 0);
190789Sahrens } else
191789Sahrens acl_info->acl_flags = 0;
192789Sahrens
193789Sahrens switch (acl_info->acl_type) {
194789Sahrens case ACLENT_T:
195789Sahrens if (acl_info->acl_cnt <= MIN_ACL_ENTRIES)
196789Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL;
197789Sahrens break;
198789Sahrens case ACE_T:
199789Sahrens if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0)
200789Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL;
201789Sahrens break;
202789Sahrens default:
203789Sahrens errno = EINVAL;
204789Sahrens acl_free(acl_info);
205789Sahrens return (-1);
206789Sahrens }
207789Sahrens
208789Sahrens if ((acl_info->acl_flags & ACL_IS_TRIVIAL) &&
209789Sahrens (get_flag & ACL_NO_TRIVIAL)) {
210789Sahrens acl_free(acl_info);
211789Sahrens errno = 0;
212789Sahrens return (0);
213789Sahrens }
214789Sahrens
215789Sahrens *aclp = acl_info;
216789Sahrens return (0);
217789Sahrens }
218789Sahrens
219789Sahrens /*
220789Sahrens * return -1 on failure, otherwise the number of acl
221789Sahrens * entries is returned
222789Sahrens */
223789Sahrens int
acl_get(const char * path,int get_flag,acl_t ** aclp)224789Sahrens acl_get(const char *path, int get_flag, acl_t **aclp)
225789Sahrens {
226789Sahrens acl_inp acl_inp;
227789Sahrens acl_inp.file = path;
228789Sahrens
229789Sahrens return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp));
230789Sahrens }
231789Sahrens
232789Sahrens int
facl_get(int fd,int get_flag,acl_t ** aclp)233789Sahrens facl_get(int fd, int get_flag, acl_t **aclp)
234789Sahrens {
235789Sahrens
236789Sahrens acl_inp acl_inp;
237789Sahrens acl_inp.fd = fd;
238789Sahrens
239789Sahrens return (cacl_get(acl_inp, get_flag, ACL_FD, aclp));
240789Sahrens }
241789Sahrens
242789Sahrens /*
243789Sahrens * Set an ACL, translates acl to ace_t when appropriate.
244789Sahrens */
245789Sahrens static int
cacl_set(acl_inp * acl_inp,acl_t * aclp,int type)246789Sahrens cacl_set(acl_inp *acl_inp, acl_t *aclp, int type)
247789Sahrens {
248789Sahrens int error = 0;
249789Sahrens int acl_flavor_target;
250789Sahrens struct stat64 statbuf;
251789Sahrens int stat_error;
252789Sahrens int isdir;
253789Sahrens
254789Sahrens
255789Sahrens if (type == ACL_PATH) {
256789Sahrens stat_error = stat64(acl_inp->file, &statbuf);
257789Sahrens if (stat_error)
258789Sahrens return (-1);
259789Sahrens acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED);
260789Sahrens } else {
261789Sahrens stat_error = fstat64(acl_inp->fd, &statbuf);
262789Sahrens if (stat_error)
263789Sahrens return (-1);
264789Sahrens acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED);
265789Sahrens }
266789Sahrens
2671666Smarks /*
2681666Smarks * If target returns an error or 0 from pathconf call then
2691666Smarks * fall back to UFS/POSIX Draft interface.
2701666Smarks * In the case of 0 we will then fail in either acl(2) or
2711666Smarks * acl_translate(). We could erroneously get 0 back from
2721666Smarks * a file system that is using fs_pathconf() and not answering
2731666Smarks * the _PC_ACL_ENABLED question itself.
2741666Smarks */
2751666Smarks if (acl_flavor_target == 0 || acl_flavor_target == -1)
2761666Smarks acl_flavor_target = _ACL_ACLENT_ENABLED;
2771666Smarks
278789Sahrens isdir = S_ISDIR(statbuf.st_mode);
279789Sahrens
2801462Smarks if ((error = acl_translate(aclp, acl_flavor_target, isdir,
2811462Smarks statbuf.st_uid, statbuf.st_gid)) != 0) {
2821462Smarks return (error);
283789Sahrens }
284789Sahrens
285789Sahrens if (type == ACL_PATH) {
286789Sahrens error = acl(acl_inp->file,
287789Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL,
288789Sahrens aclp->acl_cnt, aclp->acl_aclp);
289789Sahrens } else {
290789Sahrens error = facl(acl_inp->fd,
291789Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL,
292789Sahrens aclp->acl_cnt, aclp->acl_aclp);
293789Sahrens }
294789Sahrens
295789Sahrens return (error);
296789Sahrens }
297789Sahrens
298789Sahrens int
acl_set(const char * path,acl_t * aclp)299789Sahrens acl_set(const char *path, acl_t *aclp)
300789Sahrens {
301789Sahrens acl_inp acl_inp;
302789Sahrens
303789Sahrens acl_inp.file = path;
304789Sahrens
305789Sahrens return (cacl_set(&acl_inp, aclp, ACL_PATH));
306789Sahrens }
307789Sahrens
308789Sahrens int
facl_set(int fd,acl_t * aclp)309789Sahrens facl_set(int fd, acl_t *aclp)
310789Sahrens {
311789Sahrens acl_inp acl_inp;
312789Sahrens
313789Sahrens acl_inp.fd = fd;
314789Sahrens
315789Sahrens return (cacl_set(&acl_inp, aclp, ACL_FD));
316789Sahrens }
317789Sahrens
318789Sahrens int
acl_cnt(acl_t * aclp)319789Sahrens acl_cnt(acl_t *aclp)
320789Sahrens {
321789Sahrens return (aclp->acl_cnt);
322789Sahrens }
323789Sahrens
324789Sahrens int
acl_type(acl_t * aclp)325789Sahrens acl_type(acl_t *aclp)
326789Sahrens {
327789Sahrens return (aclp->acl_type);
328789Sahrens }
329789Sahrens
330789Sahrens acl_t *
acl_dup(acl_t * aclp)331789Sahrens acl_dup(acl_t *aclp)
332789Sahrens {
333789Sahrens acl_t *newaclp;
334789Sahrens
335789Sahrens newaclp = acl_alloc(aclp->acl_type);
336789Sahrens if (newaclp == NULL)
337789Sahrens return (NULL);
338789Sahrens
339789Sahrens newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt);
340789Sahrens if (newaclp->acl_aclp == NULL) {
341789Sahrens acl_free(newaclp);
342789Sahrens return (NULL);
343789Sahrens }
344789Sahrens
345789Sahrens (void) memcpy(newaclp->acl_aclp,
346789Sahrens aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt);
347789Sahrens newaclp->acl_cnt = aclp->acl_cnt;
348789Sahrens
349789Sahrens return (newaclp);
350789Sahrens }
351789Sahrens
352789Sahrens int
acl_flags(acl_t * aclp)353789Sahrens acl_flags(acl_t *aclp)
354789Sahrens {
355789Sahrens return (aclp->acl_flags);
356789Sahrens }
357789Sahrens
358789Sahrens void *
acl_data(acl_t * aclp)359789Sahrens acl_data(acl_t *aclp)
360789Sahrens {
361789Sahrens return (aclp->acl_aclp);
362789Sahrens }
363789Sahrens
364789Sahrens /*
3651953Smarks * Take an acl array and build an acl_t.
3661953Smarks */
3671953Smarks acl_t *
acl_to_aclp(enum acl_type type,void * acl,int count)3681953Smarks acl_to_aclp(enum acl_type type, void *acl, int count)
3691953Smarks {
3701953Smarks acl_t *aclp;
3711953Smarks
3721953Smarks
3731953Smarks aclp = acl_alloc(type);
3741953Smarks if (aclp == NULL)
3751953Smarks return (aclp);
3761953Smarks
3771953Smarks aclp->acl_aclp = acl;
3781953Smarks aclp->acl_cnt = count;
3791953Smarks
3801953Smarks return (aclp);
3811953Smarks }
3821953Smarks
3831953Smarks /*
384789Sahrens * Remove an ACL from a file and create a trivial ACL based
385789Sahrens * off of the mode argument. After acl has been set owner/group
386789Sahrens * are updated to match owner,group arguments
387789Sahrens */
388789Sahrens int
acl_strip(const char * file,uid_t owner,gid_t group,mode_t mode)389789Sahrens acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode)
390789Sahrens {
391789Sahrens int error = 0;
392789Sahrens aclent_t min_acl[MIN_ACL_ENTRIES];
39312164SMark.Shellenbaum@Sun.COM ace_t *min_ace_acl;
394789Sahrens int acl_flavor;
395789Sahrens int aclcnt;
396789Sahrens
397789Sahrens acl_flavor = pathconf(file, _PC_ACL_ENABLED);
398789Sahrens
399789Sahrens /*
400789Sahrens * force it through aclent flavor when file system doesn't
401789Sahrens * understand question
402789Sahrens */
4031666Smarks if (acl_flavor == 0 || acl_flavor == -1)
404789Sahrens acl_flavor = _ACL_ACLENT_ENABLED;
405789Sahrens
406789Sahrens if (acl_flavor & _ACL_ACLENT_ENABLED) {
407789Sahrens min_acl[0].a_type = USER_OBJ;
408789Sahrens min_acl[0].a_id = owner;
409789Sahrens min_acl[0].a_perm = ((mode & 0700) >> 6);
410789Sahrens min_acl[1].a_type = GROUP_OBJ;
411789Sahrens min_acl[1].a_id = group;
412789Sahrens min_acl[1].a_perm = ((mode & 0070) >> 3);
413789Sahrens min_acl[2].a_type = CLASS_OBJ;
414789Sahrens min_acl[2].a_id = (uid_t)-1;
415789Sahrens min_acl[2].a_perm = ((mode & 0070) >> 3);
416789Sahrens min_acl[3].a_type = OTHER_OBJ;
417789Sahrens min_acl[3].a_id = (uid_t)-1;
418789Sahrens min_acl[3].a_perm = (mode & 0007);
419789Sahrens aclcnt = 4;
420789Sahrens error = acl(file, SETACL, aclcnt, min_acl);
421789Sahrens } else if (acl_flavor & _ACL_ACE_ENABLED) {
42212164SMark.Shellenbaum@Sun.COM if ((error = acl_trivial_create(mode, &min_ace_acl,
42312164SMark.Shellenbaum@Sun.COM &aclcnt)) != 0)
42412164SMark.Shellenbaum@Sun.COM return (error);
42512164SMark.Shellenbaum@Sun.COM error = acl(file, ACE_SETACL, aclcnt, min_ace_acl);
42612164SMark.Shellenbaum@Sun.COM free(min_ace_acl);
427789Sahrens } else {
428789Sahrens errno = EINVAL;
429789Sahrens error = 1;
430789Sahrens }
431789Sahrens
432789Sahrens if (error == 0)
433789Sahrens error = chown(file, owner, group);
434789Sahrens return (error);
435789Sahrens }
436789Sahrens
437789Sahrens static int
ace_match(void * entry1,void * entry2)438789Sahrens ace_match(void *entry1, void *entry2)
439789Sahrens {
440789Sahrens ace_t *p1 = (ace_t *)entry1;
441789Sahrens ace_t *p2 = (ace_t *)entry2;
442789Sahrens ace_t ace1, ace2;
443789Sahrens
444789Sahrens ace1 = *p1;
445789Sahrens ace2 = *p2;
446789Sahrens
447789Sahrens /*
448789Sahrens * Need to fixup who field for abstrations for
449789Sahrens * accurate comparison, since field is undefined.
450789Sahrens */
451789Sahrens if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE))
4524321Scasper ace1.a_who = (uid_t)-1;
453789Sahrens if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE))
4544321Scasper ace2.a_who = (uid_t)-1;
455789Sahrens return (memcmp(&ace1, &ace2, sizeof (ace_t)));
456789Sahrens }
457789Sahrens
458789Sahrens static int
aclent_match(void * entry1,void * entry2)459789Sahrens aclent_match(void *entry1, void *entry2)
460789Sahrens {
461789Sahrens aclent_t *aclent1 = (aclent_t *)entry1;
462789Sahrens aclent_t *aclent2 = (aclent_t *)entry2;
463789Sahrens
464789Sahrens return (memcmp(aclent1, aclent2, sizeof (aclent_t)));
465789Sahrens }
466789Sahrens
467789Sahrens /*
468789Sahrens * Find acl entries in acl that correspond to removeacl. Search
469789Sahrens * is started from slot. The flag argument indicates whether to
470789Sahrens * remove all matches or just the first match.
471789Sahrens */
472789Sahrens int
acl_removeentries(acl_t * acl,acl_t * removeacl,int start_slot,int flag)473789Sahrens acl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag)
474789Sahrens {
475789Sahrens int i, j;
476789Sahrens int match;
477789Sahrens int (*acl_match)(void *acl1, void *acl2);
478789Sahrens void *acl_entry, *remove_entry;
479789Sahrens void *start;
480789Sahrens int found = 0;
481789Sahrens
482789Sahrens if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST)
483789Sahrens flag = ACL_REMOVE_FIRST;
484789Sahrens
485789Sahrens if (acl == NULL || removeacl == NULL)
486789Sahrens return (EACL_NO_ACL_ENTRY);
487789Sahrens
488789Sahrens if (acl->acl_type != removeacl->acl_type)
489789Sahrens return (EACL_DIFF_TYPE);
490789Sahrens
491789Sahrens if (acl->acl_type == ACLENT_T)
492789Sahrens acl_match = aclent_match;
493789Sahrens else
494789Sahrens acl_match = ace_match;
495789Sahrens
496789Sahrens for (i = 0, remove_entry = removeacl->acl_aclp;
497789Sahrens i != removeacl->acl_cnt; i++) {
498789Sahrens
499789Sahrens j = 0;
500789Sahrens acl_entry = (char *)acl->acl_aclp +
501789Sahrens (acl->acl_entry_size * start_slot);
502789Sahrens for (;;) {
503789Sahrens match = acl_match(acl_entry, remove_entry);
504789Sahrens if (match == 0) {
505789Sahrens found++;
5068672SRenaud.Manus@Sun.COM
5078672SRenaud.Manus@Sun.COM /* avoid memmove if last entry */
5088672SRenaud.Manus@Sun.COM if (acl->acl_cnt == (j + 1)) {
5098672SRenaud.Manus@Sun.COM acl->acl_cnt--;
5108672SRenaud.Manus@Sun.COM break;
5118672SRenaud.Manus@Sun.COM }
5128672SRenaud.Manus@Sun.COM
513789Sahrens start = (char *)acl_entry +
514789Sahrens acl->acl_entry_size;
515789Sahrens (void) memmove(acl_entry, start,
516789Sahrens acl->acl_entry_size *
5178672SRenaud.Manus@Sun.COM (acl->acl_cnt-- - (j + 1)));
518789Sahrens
519789Sahrens if (flag == ACL_REMOVE_FIRST)
520789Sahrens break;
521789Sahrens /*
5227057Smarks * List has changed, just continue so this
5237057Smarks * slot gets checked with it's new contents.
524789Sahrens */
525789Sahrens continue;
526789Sahrens }
527789Sahrens acl_entry = ((char *)acl_entry + acl->acl_entry_size);
528789Sahrens if (++j >= acl->acl_cnt) {
529789Sahrens break;
530789Sahrens }
531789Sahrens }
5327057Smarks remove_entry = (char *)remove_entry + removeacl->acl_entry_size;
533789Sahrens }
534789Sahrens
535789Sahrens return ((found == 0) ? EACL_NO_ACL_ENTRY : 0);
536789Sahrens }
537789Sahrens
538789Sahrens /*
539789Sahrens * Replace entires entries in acl1 with the corresponding entries
540789Sahrens * in newentries. The where argument specifies where to begin
541789Sahrens * the replacement. If the where argument is 1 greater than the
542789Sahrens * number of acl entries in acl1 then they are appended. If the
543789Sahrens * where argument is 2+ greater than the number of acl entries then
544789Sahrens * EACL_INVALID_SLOT is returned.
545789Sahrens */
546789Sahrens int
acl_modifyentries(acl_t * acl1,acl_t * newentries,int where)547789Sahrens acl_modifyentries(acl_t *acl1, acl_t *newentries, int where)
548789Sahrens {
549789Sahrens
550789Sahrens int slot;
551789Sahrens int slots_needed;
552789Sahrens int slots_left;
553789Sahrens int newsize;
554789Sahrens
555789Sahrens if (acl1 == NULL || newentries == NULL)
556789Sahrens return (EACL_NO_ACL_ENTRY);
557789Sahrens
558789Sahrens if (where < 0 || where >= acl1->acl_cnt)
559789Sahrens return (EACL_INVALID_SLOT);
560789Sahrens
561789Sahrens if (acl1->acl_type != newentries->acl_type)
562789Sahrens return (EACL_DIFF_TYPE);
563789Sahrens
564789Sahrens slot = where;
565789Sahrens
566789Sahrens slots_left = acl1->acl_cnt - slot + 1;
567789Sahrens if (slots_left < newentries->acl_cnt) {
568789Sahrens slots_needed = newentries->acl_cnt - slots_left;
569789Sahrens newsize = (acl1->acl_entry_size * acl1->acl_cnt) +
570789Sahrens (acl1->acl_entry_size * slots_needed);
571789Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize);
572789Sahrens if (acl1->acl_aclp == NULL)
573789Sahrens return (-1);
574789Sahrens }
575789Sahrens (void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot),
576789Sahrens newentries->acl_aclp,
577789Sahrens newentries->acl_entry_size * newentries->acl_cnt);
578789Sahrens
579789Sahrens /*
580789Sahrens * Did ACL grow?
581789Sahrens */
582789Sahrens
583789Sahrens if ((slot + newentries->acl_cnt) > acl1->acl_cnt) {
584789Sahrens acl1->acl_cnt = slot + newentries->acl_cnt;
585789Sahrens }
586789Sahrens
587789Sahrens return (0);
588789Sahrens }
589789Sahrens
590789Sahrens /*
591789Sahrens * Add acl2 entries into acl1. The where argument specifies where
592789Sahrens * to add the entries.
593789Sahrens */
594789Sahrens int
acl_addentries(acl_t * acl1,acl_t * acl2,int where)595789Sahrens acl_addentries(acl_t *acl1, acl_t *acl2, int where)
596789Sahrens {
597789Sahrens
598789Sahrens int newsize;
599789Sahrens int len;
600789Sahrens void *start;
601789Sahrens void *to;
602789Sahrens
603789Sahrens if (acl1 == NULL || acl2 == NULL)
604789Sahrens return (EACL_NO_ACL_ENTRY);
605789Sahrens
606789Sahrens if (acl1->acl_type != acl2->acl_type)
607789Sahrens return (EACL_DIFF_TYPE);
608789Sahrens
609789Sahrens /*
610789Sahrens * allow where to specify 1 past last slot for an append operation
611789Sahrens * but anything greater is an error.
612789Sahrens */
613789Sahrens if (where < 0 || where > acl1->acl_cnt)
614789Sahrens return (EACL_INVALID_SLOT);
615789Sahrens
616789Sahrens newsize = (acl2->acl_entry_size * acl2->acl_cnt) +
617789Sahrens (acl1->acl_entry_size * acl1->acl_cnt);
618789Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize);
619789Sahrens if (acl1->acl_aclp == NULL)
620789Sahrens return (-1);
621789Sahrens
622789Sahrens /*
623789Sahrens * first push down entries where new ones will be inserted
624789Sahrens */
625789Sahrens
626789Sahrens to = (void *)((char *)acl1->acl_aclp +
627789Sahrens ((where + acl2->acl_cnt) * acl1->acl_entry_size));
628789Sahrens
629789Sahrens start = (void *)((char *)acl1->acl_aclp +
630789Sahrens where * acl1->acl_entry_size);
631789Sahrens
632789Sahrens if (where < acl1->acl_cnt) {
633789Sahrens len = (acl1->acl_cnt - where) * acl1->acl_entry_size;
634789Sahrens (void) memmove(to, start, len);
635789Sahrens }
636789Sahrens
637789Sahrens /*
638789Sahrens * now stick in new entries.
639789Sahrens */
640789Sahrens
641789Sahrens (void) memmove(start, acl2->acl_aclp,
642789Sahrens acl2->acl_cnt * acl2->acl_entry_size);
643789Sahrens
644789Sahrens acl1->acl_cnt += acl2->acl_cnt;
645789Sahrens return (0);
646789Sahrens }
647789Sahrens
648789Sahrens /*
649789Sahrens * return text for an ACL error.
650789Sahrens */
651789Sahrens char *
acl_strerror(int errnum)652789Sahrens acl_strerror(int errnum)
653789Sahrens {
654789Sahrens switch (errnum) {
655789Sahrens case EACL_GRP_ERROR:
656789Sahrens return (dgettext(TEXT_DOMAIN,
6571420Smarks "There is more than one group or default group entry"));
658789Sahrens case EACL_USER_ERROR:
659789Sahrens return (dgettext(TEXT_DOMAIN,
6601420Smarks "There is more than one user or default user entry"));
661789Sahrens case EACL_OTHER_ERROR:
662789Sahrens return (dgettext(TEXT_DOMAIN,
663789Sahrens "There is more than one other entry"));
664789Sahrens case EACL_CLASS_ERROR:
665789Sahrens return (dgettext(TEXT_DOMAIN,
666789Sahrens "There is more than one mask entry"));
667789Sahrens case EACL_DUPLICATE_ERROR:
668789Sahrens return (dgettext(TEXT_DOMAIN,
669789Sahrens "Duplicate user or group entries"));
670789Sahrens case EACL_MISS_ERROR:
671789Sahrens return (dgettext(TEXT_DOMAIN,
672789Sahrens "Missing user/group owner, other, mask entry"));
673789Sahrens case EACL_MEM_ERROR:
674789Sahrens return (dgettext(TEXT_DOMAIN,
675789Sahrens "Memory error"));
676789Sahrens case EACL_ENTRY_ERROR:
677789Sahrens return (dgettext(TEXT_DOMAIN,
678789Sahrens "Unrecognized entry type"));
679789Sahrens case EACL_INHERIT_ERROR:
680789Sahrens return (dgettext(TEXT_DOMAIN,
681789Sahrens "Invalid inheritance flags"));
682789Sahrens case EACL_FLAGS_ERROR:
683789Sahrens return (dgettext(TEXT_DOMAIN,
684789Sahrens "Unrecognized entry flags"));
685789Sahrens case EACL_PERM_MASK_ERROR:
686789Sahrens return (dgettext(TEXT_DOMAIN,
687789Sahrens "Invalid ACL permissions"));
688789Sahrens case EACL_COUNT_ERROR:
689789Sahrens return (dgettext(TEXT_DOMAIN,
690789Sahrens "Invalid ACL count"));
691789Sahrens case EACL_INVALID_SLOT:
692789Sahrens return (dgettext(TEXT_DOMAIN,
693789Sahrens "Invalid ACL entry number specified"));
694789Sahrens case EACL_NO_ACL_ENTRY:
695789Sahrens return (dgettext(TEXT_DOMAIN,
696789Sahrens "ACL entry doesn't exist"));
697789Sahrens case EACL_DIFF_TYPE:
698789Sahrens return (dgettext(TEXT_DOMAIN,
69910228SStephanie.Scheffler@Sun.COM "Different file system ACL types cannot be merged"));
700789Sahrens case EACL_INVALID_USER_GROUP:
701789Sahrens return (dgettext(TEXT_DOMAIN, "Invalid user or group"));
702789Sahrens case EACL_INVALID_STR:
703789Sahrens return (dgettext(TEXT_DOMAIN, "ACL string is invalid"));
704789Sahrens case EACL_FIELD_NOT_BLANK:
705789Sahrens return (dgettext(TEXT_DOMAIN, "Field expected to be blank"));
706789Sahrens case EACL_INVALID_ACCESS_TYPE:
707789Sahrens return (dgettext(TEXT_DOMAIN, "Invalid access type"));
708789Sahrens case EACL_UNKNOWN_DATA:
709789Sahrens return (dgettext(TEXT_DOMAIN, "Unrecognized entry"));
710789Sahrens case EACL_MISSING_FIELDS:
711789Sahrens return (dgettext(TEXT_DOMAIN,
712789Sahrens "ACL specification missing required fields"));
713789Sahrens case EACL_INHERIT_NOTDIR:
714789Sahrens return (dgettext(TEXT_DOMAIN,
715789Sahrens "Inheritance flags are only allowed on directories"));
716789Sahrens case -1:
717789Sahrens return (strerror(errno));
718789Sahrens default:
719789Sahrens errno = EINVAL;
720789Sahrens return (dgettext(TEXT_DOMAIN, "Unknown error"));
721789Sahrens }
722789Sahrens }
7231420Smarks
7241420Smarks extern int yyinteractive;
7251420Smarks
7261420Smarks /* PRINTFLIKE1 */
7271420Smarks void
acl_error(const char * fmt,...)7281420Smarks acl_error(const char *fmt, ...)
7291420Smarks {
7301420Smarks va_list va;
7311420Smarks
7321420Smarks if (yyinteractive == 0)
7331420Smarks return;
7341420Smarks
7351420Smarks va_start(va, fmt);
7361420Smarks (void) vfprintf(stderr, fmt, va);
7371420Smarks va_end(va);
7381420Smarks }
7397057Smarks
7407057Smarks int
sid_to_id(char * sid,boolean_t user,uid_t * id)7417057Smarks sid_to_id(char *sid, boolean_t user, uid_t *id)
7427057Smarks {
7437057Smarks idmap_get_handle_t *get_hdl = NULL;
7447057Smarks char *rid_start = NULL;
7457057Smarks idmap_stat status;
7467057Smarks char *end;
7477680SMark.Shellenbaum@Sun.COM int error = 1;
7487057Smarks char *domain_start;
7497057Smarks
7507057Smarks if ((domain_start = strchr(sid, '@')) == NULL) {
7517057Smarks idmap_rid_t rid;
7527057Smarks
7537057Smarks if ((rid_start = strrchr(sid, '-')) == NULL)
7547680SMark.Shellenbaum@Sun.COM return (1);
7557057Smarks *rid_start++ = '\0';
7567057Smarks errno = 0;
7577057Smarks rid = strtoul(rid_start--, &end, 10);
7587057Smarks if (errno == 0 && *end == '\0') {
759*12914SJoyce.McIntosh@Sun.COM if (idmap_get_create(&get_hdl) ==
7607680SMark.Shellenbaum@Sun.COM IDMAP_SUCCESS) {
7617057Smarks if (user)
7627057Smarks error = idmap_get_uidbysid(get_hdl,
7637369SJulian.Pullen@Sun.COM sid, rid, IDMAP_REQ_FLG_USE_CACHE,
7647369SJulian.Pullen@Sun.COM id, &status);
7657057Smarks else
7667057Smarks error = idmap_get_gidbysid(get_hdl,
7677369SJulian.Pullen@Sun.COM sid, rid, IDMAP_REQ_FLG_USE_CACHE,
7687369SJulian.Pullen@Sun.COM id, &status);
7697680SMark.Shellenbaum@Sun.COM if (error == IDMAP_SUCCESS) {
7707680SMark.Shellenbaum@Sun.COM error = idmap_get_mappings(get_hdl);
7717680SMark.Shellenbaum@Sun.COM if (error == IDMAP_SUCCESS &&
7727680SMark.Shellenbaum@Sun.COM status != IDMAP_SUCCESS)
7737680SMark.Shellenbaum@Sun.COM error = 1;
7747680SMark.Shellenbaum@Sun.COM else
7757680SMark.Shellenbaum@Sun.COM error = 0;
7767680SMark.Shellenbaum@Sun.COM }
7777680SMark.Shellenbaum@Sun.COM } else {
7787680SMark.Shellenbaum@Sun.COM error = 1;
7797057Smarks }
7807680SMark.Shellenbaum@Sun.COM if (get_hdl)
7817680SMark.Shellenbaum@Sun.COM idmap_get_destroy(get_hdl);
7827057Smarks } else {
7837680SMark.Shellenbaum@Sun.COM error = 1;
7847057Smarks }
7857057Smarks *rid_start = '-'; /* putback character removed earlier */
7867057Smarks } else {
7877057Smarks char *name = sid;
7887057Smarks *domain_start++ = '\0';
7897057Smarks
7907057Smarks if (user)
7917369SJulian.Pullen@Sun.COM error = idmap_getuidbywinname(name, domain_start,
7927369SJulian.Pullen@Sun.COM IDMAP_REQ_FLG_USE_CACHE, id);
7937057Smarks else
7947369SJulian.Pullen@Sun.COM error = idmap_getgidbywinname(name, domain_start,
7957369SJulian.Pullen@Sun.COM IDMAP_REQ_FLG_USE_CACHE, id);
7967057Smarks *--domain_start = '@';
7977680SMark.Shellenbaum@Sun.COM error = (error == IDMAP_SUCCESS) ? 0 : 1;
7987057Smarks }
7997057Smarks
8007057Smarks return (error);
8017057Smarks }
802