xref: /netbsd/lib/libc/posix1e/acl_support.c (revision b9c1fd7f)
1*b9c1fd7fSchristos /*-
2*b9c1fd7fSchristos  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*b9c1fd7fSchristos  *
4*b9c1fd7fSchristos  * Copyright (c) 1999-2001, 2008 Robert N. M. Watson
5*b9c1fd7fSchristos  * All rights reserved.
6*b9c1fd7fSchristos  *
7*b9c1fd7fSchristos  * Redistribution and use in source and binary forms, with or without
8*b9c1fd7fSchristos  * modification, are permitted provided that the following conditions
9*b9c1fd7fSchristos  * are met:
10*b9c1fd7fSchristos  * 1. Redistributions of source code must retain the above copyright
11*b9c1fd7fSchristos  *    notice, this list of conditions and the following disclaimer.
12*b9c1fd7fSchristos  * 2. Redistributions in binary form must reproduce the above copyright
13*b9c1fd7fSchristos  *    notice, this list of conditions and the following disclaimer in the
14*b9c1fd7fSchristos  *    documentation and/or other materials provided with the distribution.
15*b9c1fd7fSchristos  *
16*b9c1fd7fSchristos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*b9c1fd7fSchristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*b9c1fd7fSchristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*b9c1fd7fSchristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*b9c1fd7fSchristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*b9c1fd7fSchristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*b9c1fd7fSchristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*b9c1fd7fSchristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*b9c1fd7fSchristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*b9c1fd7fSchristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*b9c1fd7fSchristos  * SUCH DAMAGE.
27*b9c1fd7fSchristos  */
28*b9c1fd7fSchristos /*
29*b9c1fd7fSchristos  * Support functionality for the POSIX.1e ACL interface
30*b9c1fd7fSchristos  * These calls are intended only to be called within the library.
31*b9c1fd7fSchristos  */
32*b9c1fd7fSchristos 
33*b9c1fd7fSchristos #include <sys/cdefs.h>
34*b9c1fd7fSchristos #if 0
35*b9c1fd7fSchristos __FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_support.c 326193 2017-11-25 17:12:48Z pfg $");
36*b9c1fd7fSchristos #else
37*b9c1fd7fSchristos __RCSID("$NetBSD: acl_support.c,v 1.1 2020/05/16 18:31:47 christos Exp $");
38*b9c1fd7fSchristos #endif
39*b9c1fd7fSchristos 
40*b9c1fd7fSchristos #include "namespace.h"
41*b9c1fd7fSchristos #include <sys/types.h>
42*b9c1fd7fSchristos #include <sys/acl.h>
43*b9c1fd7fSchristos #include <errno.h>
44*b9c1fd7fSchristos #include <grp.h>
45*b9c1fd7fSchristos #include <pwd.h>
46*b9c1fd7fSchristos #include <stdio.h>
47*b9c1fd7fSchristos #include <stdlib.h>
48*b9c1fd7fSchristos #include <string.h>
49*b9c1fd7fSchristos #include <assert.h>
50*b9c1fd7fSchristos 
51*b9c1fd7fSchristos #include "acl_support.h"
52*b9c1fd7fSchristos 
53*b9c1fd7fSchristos #define ACL_STRING_PERM_WRITE   'w'
54*b9c1fd7fSchristos #define ACL_STRING_PERM_READ    'r'
55*b9c1fd7fSchristos #define ACL_STRING_PERM_EXEC    'x'
56*b9c1fd7fSchristos #define ACL_STRING_PERM_NONE    '-'
57*b9c1fd7fSchristos 
58*b9c1fd7fSchristos /*
59*b9c1fd7fSchristos  * Return 0, if both ACLs are identical.
60*b9c1fd7fSchristos  */
61*b9c1fd7fSchristos int
_acl_differs(const acl_t a,const acl_t b)62*b9c1fd7fSchristos _acl_differs(const acl_t a, const acl_t b)
63*b9c1fd7fSchristos {
64*b9c1fd7fSchristos 	size_t i;
65*b9c1fd7fSchristos 	struct acl_entry *entrya, *entryb;
66*b9c1fd7fSchristos 
67*b9c1fd7fSchristos 	assert(_acl_brand(a) == _acl_brand(b));
68*b9c1fd7fSchristos 	assert(_acl_brand(a) != ACL_BRAND_UNKNOWN);
69*b9c1fd7fSchristos 	assert(_acl_brand(b) != ACL_BRAND_UNKNOWN);
70*b9c1fd7fSchristos 
71*b9c1fd7fSchristos 	if (a->ats_acl.acl_cnt != b->ats_acl.acl_cnt)
72*b9c1fd7fSchristos 		return (1);
73*b9c1fd7fSchristos 
74*b9c1fd7fSchristos 	for (i = 0; i < b->ats_acl.acl_cnt; i++) {
75*b9c1fd7fSchristos 		entrya = &(a->ats_acl.acl_entry[i]);
76*b9c1fd7fSchristos 		entryb = &(b->ats_acl.acl_entry[i]);
77*b9c1fd7fSchristos 
78*b9c1fd7fSchristos 		if (entrya->ae_tag != entryb->ae_tag ||
79*b9c1fd7fSchristos 		    entrya->ae_id != entryb->ae_id ||
80*b9c1fd7fSchristos 		    entrya->ae_perm != entryb->ae_perm ||
81*b9c1fd7fSchristos 		    entrya->ae_entry_type != entryb->ae_entry_type ||
82*b9c1fd7fSchristos 		    entrya->ae_flags != entryb->ae_flags)
83*b9c1fd7fSchristos 			return (1);
84*b9c1fd7fSchristos 	}
85*b9c1fd7fSchristos 
86*b9c1fd7fSchristos 	return (0);
87*b9c1fd7fSchristos }
88*b9c1fd7fSchristos 
89*b9c1fd7fSchristos /*
90*b9c1fd7fSchristos  * _posix1e_acl_entry_compare -- compare two acl_entry structures to
91*b9c1fd7fSchristos  * determine the order they should appear in.  Used by _posix1e_acl_sort to
92*b9c1fd7fSchristos  * sort ACL entries into the kernel-desired order -- i.e., the order useful
93*b9c1fd7fSchristos  * for evaluation and O(n) validity checking.  Beter to have an O(nlogn) sort
94*b9c1fd7fSchristos  * in userland and an O(n) in kernel than to have both in kernel.
95*b9c1fd7fSchristos  */
96*b9c1fd7fSchristos typedef int (*compare)(const void *, const void *);
97*b9c1fd7fSchristos static int
_posix1e_acl_entry_compare(struct acl_entry * a,struct acl_entry * b)98*b9c1fd7fSchristos _posix1e_acl_entry_compare(struct acl_entry *a, struct acl_entry *b)
99*b9c1fd7fSchristos {
100*b9c1fd7fSchristos 
101*b9c1fd7fSchristos 	assert(_entry_brand(a) == ACL_BRAND_POSIX);
102*b9c1fd7fSchristos 	assert(_entry_brand(b) == ACL_BRAND_POSIX);
103*b9c1fd7fSchristos 
104*b9c1fd7fSchristos 	/*
105*b9c1fd7fSchristos 	 * First, sort between tags -- conveniently defined in the correct
106*b9c1fd7fSchristos 	 * order for verification.
107*b9c1fd7fSchristos 	 */
108*b9c1fd7fSchristos 	if (a->ae_tag < b->ae_tag)
109*b9c1fd7fSchristos 		return (-1);
110*b9c1fd7fSchristos 	if (a->ae_tag > b->ae_tag)
111*b9c1fd7fSchristos 		return (1);
112*b9c1fd7fSchristos 
113*b9c1fd7fSchristos 	/*
114*b9c1fd7fSchristos 	 * Next compare uids/gids on appropriate types.
115*b9c1fd7fSchristos 	 */
116*b9c1fd7fSchristos 
117*b9c1fd7fSchristos 	if (a->ae_tag == ACL_USER || a->ae_tag == ACL_GROUP) {
118*b9c1fd7fSchristos 		if (a->ae_id < b->ae_id)
119*b9c1fd7fSchristos 			return (-1);
120*b9c1fd7fSchristos 		if (a->ae_id > b->ae_id)
121*b9c1fd7fSchristos 			return (1);
122*b9c1fd7fSchristos 
123*b9c1fd7fSchristos 		/* shouldn't be equal, fall through to the invalid case */
124*b9c1fd7fSchristos 	}
125*b9c1fd7fSchristos 
126*b9c1fd7fSchristos 	/*
127*b9c1fd7fSchristos 	 * Don't know how to sort multiple entries of the rest--either it's
128*b9c1fd7fSchristos 	 * a bad entry, or there shouldn't be more than one.  Ignore and the
129*b9c1fd7fSchristos 	 * validity checker can get it later.
130*b9c1fd7fSchristos 	 */
131*b9c1fd7fSchristos 	return (0);
132*b9c1fd7fSchristos }
133*b9c1fd7fSchristos 
134*b9c1fd7fSchristos /*
135*b9c1fd7fSchristos  * _posix1e_acl_sort -- sort ACL entries in POSIX.1e-formatted ACLs.
136*b9c1fd7fSchristos  */
137*b9c1fd7fSchristos void
_posix1e_acl_sort(acl_t acl)138*b9c1fd7fSchristos _posix1e_acl_sort(acl_t acl)
139*b9c1fd7fSchristos {
140*b9c1fd7fSchristos 	struct acl *acl_int;
141*b9c1fd7fSchristos 
142*b9c1fd7fSchristos 	acl_int = &acl->ats_acl;
143*b9c1fd7fSchristos 
144*b9c1fd7fSchristos 	qsort(&acl_int->acl_entry[0], acl_int->acl_cnt,
145*b9c1fd7fSchristos 	    sizeof(struct acl_entry), (compare) _posix1e_acl_entry_compare);
146*b9c1fd7fSchristos }
147*b9c1fd7fSchristos 
148*b9c1fd7fSchristos /*
149*b9c1fd7fSchristos  * acl_posix1e -- in what situations should we acl_sort before submission?
150*b9c1fd7fSchristos  * We apply posix1e ACL semantics for any ACL of type ACL_TYPE_ACCESS or
151*b9c1fd7fSchristos  * ACL_TYPE_DEFAULT
152*b9c1fd7fSchristos  */
153*b9c1fd7fSchristos int
_posix1e_acl(acl_t acl,acl_type_t type)154*b9c1fd7fSchristos _posix1e_acl(acl_t acl, acl_type_t type)
155*b9c1fd7fSchristos {
156*b9c1fd7fSchristos 
157*b9c1fd7fSchristos 	if (_acl_brand(acl) != ACL_BRAND_POSIX)
158*b9c1fd7fSchristos 		return (0);
159*b9c1fd7fSchristos 
160*b9c1fd7fSchristos 	return ((type == ACL_TYPE_ACCESS) || (type == ACL_TYPE_DEFAULT));
161*b9c1fd7fSchristos }
162*b9c1fd7fSchristos 
163*b9c1fd7fSchristos /*
164*b9c1fd7fSchristos  * _posix1e_acl_check -- given an ACL, check its validity.  This is mirrored
165*b9c1fd7fSchristos  * from code in sys/kern/kern_acl.c, and if changes are made in one, they
166*b9c1fd7fSchristos  * should be made in the other also.  This copy of acl_check is made
167*b9c1fd7fSchristos  * available * in userland for the benefit of processes wanting to check ACLs
168*b9c1fd7fSchristos  * for validity before submitting them to the kernel, or for performing
169*b9c1fd7fSchristos  * in userland file system checking.  Needless to say, the kernel makes
170*b9c1fd7fSchristos  * the real checks on calls to get/setacl.
171*b9c1fd7fSchristos  *
172*b9c1fd7fSchristos  * See the comments in kernel for explanation -- just briefly, it assumes
173*b9c1fd7fSchristos  * an already sorted ACL, and checks based on that assumption.  The
174*b9c1fd7fSchristos  * POSIX.1e interface, acl_valid(), will perform the sort before calling
175*b9c1fd7fSchristos  * this.  Returns 0 on success, EINVAL on failure.
176*b9c1fd7fSchristos  */
177*b9c1fd7fSchristos int
_posix1e_acl_check(acl_t acl)178*b9c1fd7fSchristos _posix1e_acl_check(acl_t acl)
179*b9c1fd7fSchristos {
180*b9c1fd7fSchristos 	struct acl *acl_int;
181*b9c1fd7fSchristos 	struct acl_entry	*entry; 	/* current entry */
182*b9c1fd7fSchristos 	uid_t	highest_uid=0, highest_gid=0;
183*b9c1fd7fSchristos 	int	stage = ACL_USER_OBJ;
184*b9c1fd7fSchristos 	size_t	i = 0;
185*b9c1fd7fSchristos 	int	count_user_obj=0, count_user=0, count_group_obj=0,
186*b9c1fd7fSchristos 		count_group=0, count_mask=0, count_other=0;
187*b9c1fd7fSchristos 
188*b9c1fd7fSchristos 	acl_int = &acl->ats_acl;
189*b9c1fd7fSchristos 
190*b9c1fd7fSchristos 	/* printf("_posix1e_acl_check: checking acl with %d entries\n",
191*b9c1fd7fSchristos 	    acl->acl_cnt); */
192*b9c1fd7fSchristos 	while (i < acl_int->acl_cnt) {
193*b9c1fd7fSchristos 		entry = &acl_int->acl_entry[i];
194*b9c1fd7fSchristos 
195*b9c1fd7fSchristos 		if ((entry->ae_perm | ACL_PERM_BITS) != ACL_PERM_BITS)
196*b9c1fd7fSchristos 			return (EINVAL);
197*b9c1fd7fSchristos 
198*b9c1fd7fSchristos 		switch(entry->ae_tag) {
199*b9c1fd7fSchristos 		case ACL_USER_OBJ:
200*b9c1fd7fSchristos 			/* printf("_posix1e_acl_check: %d: ACL_USER_OBJ\n",
201*b9c1fd7fSchristos 			    i); */
202*b9c1fd7fSchristos 			if (stage > ACL_USER_OBJ)
203*b9c1fd7fSchristos 				return (EINVAL);
204*b9c1fd7fSchristos 			stage = ACL_USER;
205*b9c1fd7fSchristos 			count_user_obj++;
206*b9c1fd7fSchristos 			break;
207*b9c1fd7fSchristos 
208*b9c1fd7fSchristos 		case ACL_USER:
209*b9c1fd7fSchristos 			/* printf("_posix1e_acl_check: %d: ACL_USER\n", i); */
210*b9c1fd7fSchristos 			if (stage > ACL_USER)
211*b9c1fd7fSchristos 				return (EINVAL);
212*b9c1fd7fSchristos 			stage = ACL_USER;
213*b9c1fd7fSchristos 			if (count_user && (entry->ae_id <= highest_uid))
214*b9c1fd7fSchristos 				return (EINVAL);
215*b9c1fd7fSchristos 			highest_uid = entry->ae_id;
216*b9c1fd7fSchristos 			count_user++;
217*b9c1fd7fSchristos 			break;
218*b9c1fd7fSchristos 
219*b9c1fd7fSchristos 		case ACL_GROUP_OBJ:
220*b9c1fd7fSchristos 			/* printf("_posix1e_acl_check: %d: ACL_GROUP_OBJ\n",
221*b9c1fd7fSchristos 			    i); */
222*b9c1fd7fSchristos 			if (stage > ACL_GROUP_OBJ)
223*b9c1fd7fSchristos 				return (EINVAL);
224*b9c1fd7fSchristos 			stage = ACL_GROUP;
225*b9c1fd7fSchristos 			count_group_obj++;
226*b9c1fd7fSchristos 			break;
227*b9c1fd7fSchristos 
228*b9c1fd7fSchristos 		case ACL_GROUP:
229*b9c1fd7fSchristos 			/* printf("_posix1e_acl_check: %d: ACL_GROUP\n", i); */
230*b9c1fd7fSchristos 			if (stage > ACL_GROUP)
231*b9c1fd7fSchristos 				return (EINVAL);
232*b9c1fd7fSchristos 			stage = ACL_GROUP;
233*b9c1fd7fSchristos 			if (count_group && (entry->ae_id <= highest_gid))
234*b9c1fd7fSchristos 				return (EINVAL);
235*b9c1fd7fSchristos 			highest_gid = entry->ae_id;
236*b9c1fd7fSchristos 			count_group++;
237*b9c1fd7fSchristos 			break;
238*b9c1fd7fSchristos 
239*b9c1fd7fSchristos 		case ACL_MASK:
240*b9c1fd7fSchristos 			/* printf("_posix1e_acl_check: %d: ACL_MASK\n", i); */
241*b9c1fd7fSchristos 			if (stage > ACL_MASK)
242*b9c1fd7fSchristos 				return (EINVAL);
243*b9c1fd7fSchristos 			stage = ACL_MASK;
244*b9c1fd7fSchristos 			count_mask++;
245*b9c1fd7fSchristos 			break;
246*b9c1fd7fSchristos 
247*b9c1fd7fSchristos 		case ACL_OTHER:
248*b9c1fd7fSchristos 			/* printf("_posix1e_acl_check: %d: ACL_OTHER\n", i); */
249*b9c1fd7fSchristos 			if (stage > ACL_OTHER)
250*b9c1fd7fSchristos 				return (EINVAL);
251*b9c1fd7fSchristos 			stage = ACL_OTHER;
252*b9c1fd7fSchristos 			count_other++;
253*b9c1fd7fSchristos 			break;
254*b9c1fd7fSchristos 
255*b9c1fd7fSchristos 		default:
256*b9c1fd7fSchristos 			/* printf("_posix1e_acl_check: %d: INVALID\n", i); */
257*b9c1fd7fSchristos 			return (EINVAL);
258*b9c1fd7fSchristos 		}
259*b9c1fd7fSchristos 		i++;
260*b9c1fd7fSchristos 	}
261*b9c1fd7fSchristos 
262*b9c1fd7fSchristos 	if (count_user_obj != 1)
263*b9c1fd7fSchristos 		return (EINVAL);
264*b9c1fd7fSchristos 
265*b9c1fd7fSchristos 	if (count_group_obj != 1)
266*b9c1fd7fSchristos 		return (EINVAL);
267*b9c1fd7fSchristos 
268*b9c1fd7fSchristos 	if (count_mask != 0 && count_mask != 1)
269*b9c1fd7fSchristos 		return (EINVAL);
270*b9c1fd7fSchristos 
271*b9c1fd7fSchristos 	if (count_other != 1)
272*b9c1fd7fSchristos 		return (EINVAL);
273*b9c1fd7fSchristos 
274*b9c1fd7fSchristos 	return (0);
275*b9c1fd7fSchristos }
276*b9c1fd7fSchristos 
277*b9c1fd7fSchristos /*
278*b9c1fd7fSchristos  * Given a right-shifted permission (i.e., direct ACL_PERM_* mask), fill
279*b9c1fd7fSchristos  * in a string describing the permissions.
280*b9c1fd7fSchristos  */
281*b9c1fd7fSchristos int
_posix1e_acl_perm_to_string(acl_perm_t perm,ssize_t buf_len,char * buf)282*b9c1fd7fSchristos _posix1e_acl_perm_to_string(acl_perm_t perm, ssize_t buf_len, char *buf)
283*b9c1fd7fSchristos {
284*b9c1fd7fSchristos 
285*b9c1fd7fSchristos 	if (buf_len < _POSIX1E_ACL_STRING_PERM_MAXSIZE + 1) {
286*b9c1fd7fSchristos 		errno = ENOMEM;
287*b9c1fd7fSchristos 		return (-1);
288*b9c1fd7fSchristos 	}
289*b9c1fd7fSchristos 
290*b9c1fd7fSchristos 	if ((perm | ACL_PERM_BITS) != ACL_PERM_BITS) {
291*b9c1fd7fSchristos 		errno = EINVAL;
292*b9c1fd7fSchristos 		return (-1);
293*b9c1fd7fSchristos 	}
294*b9c1fd7fSchristos 
295*b9c1fd7fSchristos 	buf[3] = 0;	/* null terminate */
296*b9c1fd7fSchristos 
297*b9c1fd7fSchristos 	if (perm & ACL_READ)
298*b9c1fd7fSchristos 		buf[0] = ACL_STRING_PERM_READ;
299*b9c1fd7fSchristos 	else
300*b9c1fd7fSchristos 		buf[0] = ACL_STRING_PERM_NONE;
301*b9c1fd7fSchristos 
302*b9c1fd7fSchristos 	if (perm & ACL_WRITE)
303*b9c1fd7fSchristos 		buf[1] = ACL_STRING_PERM_WRITE;
304*b9c1fd7fSchristos 	else
305*b9c1fd7fSchristos 		buf[1] = ACL_STRING_PERM_NONE;
306*b9c1fd7fSchristos 
307*b9c1fd7fSchristos 	if (perm & ACL_EXECUTE)
308*b9c1fd7fSchristos 		buf[2] = ACL_STRING_PERM_EXEC;
309*b9c1fd7fSchristos 	else
310*b9c1fd7fSchristos 		buf[2] = ACL_STRING_PERM_NONE;
311*b9c1fd7fSchristos 
312*b9c1fd7fSchristos 	return (0);
313*b9c1fd7fSchristos }
314*b9c1fd7fSchristos 
315*b9c1fd7fSchristos /*
316*b9c1fd7fSchristos  * given a string, return a permission describing it
317*b9c1fd7fSchristos  */
318*b9c1fd7fSchristos int
_posix1e_acl_string_to_perm(char * string,acl_perm_t * perm)319*b9c1fd7fSchristos _posix1e_acl_string_to_perm(char *string, acl_perm_t *perm)
320*b9c1fd7fSchristos {
321*b9c1fd7fSchristos 	acl_perm_t	myperm = ACL_PERM_NONE;
322*b9c1fd7fSchristos 	char	*ch;
323*b9c1fd7fSchristos 
324*b9c1fd7fSchristos 	ch = string;
325*b9c1fd7fSchristos 	while (*ch) {
326*b9c1fd7fSchristos 		switch(*ch) {
327*b9c1fd7fSchristos 		case ACL_STRING_PERM_READ:
328*b9c1fd7fSchristos 			myperm |= ACL_READ;
329*b9c1fd7fSchristos 			break;
330*b9c1fd7fSchristos 		case ACL_STRING_PERM_WRITE:
331*b9c1fd7fSchristos 			myperm |= ACL_WRITE;
332*b9c1fd7fSchristos 			break;
333*b9c1fd7fSchristos 		case ACL_STRING_PERM_EXEC:
334*b9c1fd7fSchristos 			myperm |= ACL_EXECUTE;
335*b9c1fd7fSchristos 			break;
336*b9c1fd7fSchristos 		case ACL_STRING_PERM_NONE:
337*b9c1fd7fSchristos 			break;
338*b9c1fd7fSchristos 		default:
339*b9c1fd7fSchristos 			return (EINVAL);
340*b9c1fd7fSchristos 		}
341*b9c1fd7fSchristos 		ch++;
342*b9c1fd7fSchristos 	}
343*b9c1fd7fSchristos 
344*b9c1fd7fSchristos 	*perm = myperm;
345*b9c1fd7fSchristos 	return (0);
346*b9c1fd7fSchristos }
347*b9c1fd7fSchristos 
348*b9c1fd7fSchristos /*
349*b9c1fd7fSchristos  * Add an ACL entry without doing much checking, et al
350*b9c1fd7fSchristos  */
351*b9c1fd7fSchristos int
_posix1e_acl_add_entry(acl_t acl,acl_tag_t tag,uid_t id,acl_perm_t perm)352*b9c1fd7fSchristos _posix1e_acl_add_entry(acl_t acl, acl_tag_t tag, uid_t id, acl_perm_t perm)
353*b9c1fd7fSchristos {
354*b9c1fd7fSchristos 	struct acl		*acl_int;
355*b9c1fd7fSchristos 	struct acl_entry	*e;
356*b9c1fd7fSchristos 
357*b9c1fd7fSchristos 	acl_int = &acl->ats_acl;
358*b9c1fd7fSchristos 
359*b9c1fd7fSchristos 	if (acl_int->acl_cnt >= ACL_MAX_ENTRIES) {
360*b9c1fd7fSchristos 		errno = ENOMEM;
361*b9c1fd7fSchristos 		return (-1);
362*b9c1fd7fSchristos 	}
363*b9c1fd7fSchristos 
364*b9c1fd7fSchristos 	e = &(acl_int->acl_entry[acl_int->acl_cnt]);
365*b9c1fd7fSchristos 	e->ae_perm = perm;
366*b9c1fd7fSchristos 	e->ae_tag = tag;
367*b9c1fd7fSchristos 	e->ae_id = id;
368*b9c1fd7fSchristos 	acl_int->acl_cnt++;
369*b9c1fd7fSchristos 
370*b9c1fd7fSchristos 	return (0);
371*b9c1fd7fSchristos }
372*b9c1fd7fSchristos 
373*b9c1fd7fSchristos /*
374*b9c1fd7fSchristos  * Convert "old" type - ACL_TYPE_{ACCESS,DEFAULT}_OLD - into its "new"
375*b9c1fd7fSchristos  * counterpart.  It's necessary for the old (pre-NFSv4 ACLs) binaries
376*b9c1fd7fSchristos  * to work with new libc and kernel.  Fixing 'type' for old binaries with
377*b9c1fd7fSchristos  * old libc and new kernel is being done by kern/vfs_acl.c:type_unold().
378*b9c1fd7fSchristos  */
379*b9c1fd7fSchristos int
_acl_type_unold(acl_type_t type)380*b9c1fd7fSchristos _acl_type_unold(acl_type_t type)
381*b9c1fd7fSchristos {
382*b9c1fd7fSchristos 
383*b9c1fd7fSchristos 	switch (type) {
384*b9c1fd7fSchristos 	case ACL_TYPE_ACCESS_OLD:
385*b9c1fd7fSchristos 		return (ACL_TYPE_ACCESS);
386*b9c1fd7fSchristos 	case ACL_TYPE_DEFAULT_OLD:
387*b9c1fd7fSchristos 		return (ACL_TYPE_DEFAULT);
388*b9c1fd7fSchristos 	default:
389*b9c1fd7fSchristos 		return (type);
390*b9c1fd7fSchristos 	}
391*b9c1fd7fSchristos }
392*b9c1fd7fSchristos 
393*b9c1fd7fSchristos char *
string_skip_whitespace(char * string)394*b9c1fd7fSchristos string_skip_whitespace(char *string)
395*b9c1fd7fSchristos {
396*b9c1fd7fSchristos 
397*b9c1fd7fSchristos 	while (*string && ((*string == ' ') || (*string == '\t')))
398*b9c1fd7fSchristos 		string++;
399*b9c1fd7fSchristos 
400*b9c1fd7fSchristos 	return (string);
401*b9c1fd7fSchristos }
402*b9c1fd7fSchristos 
403*b9c1fd7fSchristos void
string_trim_trailing_whitespace(char * string)404*b9c1fd7fSchristos string_trim_trailing_whitespace(char *string)
405*b9c1fd7fSchristos {
406*b9c1fd7fSchristos 	char	*end;
407*b9c1fd7fSchristos 
408*b9c1fd7fSchristos 	if (*string == '\0')
409*b9c1fd7fSchristos 		return;
410*b9c1fd7fSchristos 
411*b9c1fd7fSchristos 	end = string + strlen(string) - 1;
412*b9c1fd7fSchristos 
413*b9c1fd7fSchristos 	while (end != string) {
414*b9c1fd7fSchristos 		if ((*end == ' ') || (*end == '\t')) {
415*b9c1fd7fSchristos 			*end = '\0';
416*b9c1fd7fSchristos 			end--;
417*b9c1fd7fSchristos 		} else {
418*b9c1fd7fSchristos 			return;
419*b9c1fd7fSchristos 		}
420*b9c1fd7fSchristos 	}
421*b9c1fd7fSchristos 
422*b9c1fd7fSchristos 	return;
423*b9c1fd7fSchristos }
424