xref: /freebsd/lib/libc/posix1e/acl_support_nfs4.c (revision aa015c8e4ad07fbe76ec137fa491c89856b871e0)
1aa015c8eSEdward Tomasz Napierala /*-
2aa015c8eSEdward Tomasz Napierala  * Copyright (c) 2008, 2009 Edward Tomasz Napierała <trasz@FreeBSD.org>
3aa015c8eSEdward Tomasz Napierala  * All rights reserved.
4aa015c8eSEdward Tomasz Napierala  *
5aa015c8eSEdward Tomasz Napierala  * Redistribution and use in source and binary forms, with or without
6aa015c8eSEdward Tomasz Napierala  * modification, are permitted provided that the following conditions
7aa015c8eSEdward Tomasz Napierala  * are met:
8aa015c8eSEdward Tomasz Napierala  * 1. Redistributions of source code must retain the above copyright
9aa015c8eSEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer.
10aa015c8eSEdward Tomasz Napierala  * 2. Redistributions in binary form must reproduce the above copyright
11aa015c8eSEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer in the
12aa015c8eSEdward Tomasz Napierala  *    documentation and/or other materials provided with the distribution.
13aa015c8eSEdward Tomasz Napierala  *
14aa015c8eSEdward Tomasz Napierala  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15aa015c8eSEdward Tomasz Napierala  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16aa015c8eSEdward Tomasz Napierala  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17aa015c8eSEdward Tomasz Napierala  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18aa015c8eSEdward Tomasz Napierala  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19aa015c8eSEdward Tomasz Napierala  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20aa015c8eSEdward Tomasz Napierala  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21aa015c8eSEdward Tomasz Napierala  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22aa015c8eSEdward Tomasz Napierala  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23aa015c8eSEdward Tomasz Napierala  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24aa015c8eSEdward Tomasz Napierala  * SUCH DAMAGE.
25aa015c8eSEdward Tomasz Napierala  */
26aa015c8eSEdward Tomasz Napierala 
27aa015c8eSEdward Tomasz Napierala #include <sys/cdefs.h>
28aa015c8eSEdward Tomasz Napierala __FBSDID("$FreeBSD$");
29aa015c8eSEdward Tomasz Napierala 
30aa015c8eSEdward Tomasz Napierala #include <stdio.h>
31aa015c8eSEdward Tomasz Napierala #include <stdlib.h>
32aa015c8eSEdward Tomasz Napierala #include <string.h>
33aa015c8eSEdward Tomasz Napierala #include <assert.h>
34aa015c8eSEdward Tomasz Napierala #include <err.h>
35aa015c8eSEdward Tomasz Napierala #include <sys/acl.h>
36aa015c8eSEdward Tomasz Napierala #include "acl_support.h"
37aa015c8eSEdward Tomasz Napierala 
38aa015c8eSEdward Tomasz Napierala struct flagnames_struct {
39aa015c8eSEdward Tomasz Napierala 	uint32_t	flag;
40aa015c8eSEdward Tomasz Napierala 	const char	*name;
41aa015c8eSEdward Tomasz Napierala 	char		letter;
42aa015c8eSEdward Tomasz Napierala };
43aa015c8eSEdward Tomasz Napierala 
44aa015c8eSEdward Tomasz Napierala struct flagnames_struct a_flags[] =
45aa015c8eSEdward Tomasz Napierala     {{ ACL_ENTRY_FILE_INHERIT, "file_inherit", 'f'},
46aa015c8eSEdward Tomasz Napierala      { ACL_ENTRY_DIRECTORY_INHERIT, "dir_inherit", 'd'},
47aa015c8eSEdward Tomasz Napierala      { ACL_ENTRY_INHERIT_ONLY, "inherit_only", 'i'},
48aa015c8eSEdward Tomasz Napierala      { ACL_ENTRY_NO_PROPAGATE_INHERIT, "no_propagate", 'n'},
49aa015c8eSEdward Tomasz Napierala      { ACL_ENTRY_SUCCESSFUL_ACCESS, "successfull_access", 'S'},
50aa015c8eSEdward Tomasz Napierala      { ACL_ENTRY_FAILED_ACCESS, "failed_access", 'F'},
51aa015c8eSEdward Tomasz Napierala      /*
52aa015c8eSEdward Tomasz Napierala       * There is no ACE_IDENTIFIER_GROUP here - SunOS does not show it
53aa015c8eSEdward Tomasz Napierala       * in the "flags" field.  There is no ACE_OWNER, ACE_GROUP or
54aa015c8eSEdward Tomasz Napierala       * ACE_EVERYONE either, for obvious reasons.
55aa015c8eSEdward Tomasz Napierala       */
56aa015c8eSEdward Tomasz Napierala      { 0, 0, 0}};
57aa015c8eSEdward Tomasz Napierala 
58aa015c8eSEdward Tomasz Napierala struct flagnames_struct a_access_masks[] =
59aa015c8eSEdward Tomasz Napierala     {{ ACL_READ_DATA, "read_data", 'r'},
60aa015c8eSEdward Tomasz Napierala      { ACL_WRITE_DATA, "write_data", 'w'},
61aa015c8eSEdward Tomasz Napierala      { ACL_EXECUTE, "execute", 'x'},
62aa015c8eSEdward Tomasz Napierala      { ACL_APPEND_DATA, "append_data", 'p'},
63aa015c8eSEdward Tomasz Napierala      { ACL_DELETE_CHILD, "delete_child", 'D'},
64aa015c8eSEdward Tomasz Napierala      { ACL_DELETE, "delete", 'd'},
65aa015c8eSEdward Tomasz Napierala      { ACL_READ_ATTRIBUTES, "read_attributes", 'a'},
66aa015c8eSEdward Tomasz Napierala      { ACL_WRITE_ATTRIBUTES, "write_attributes", 'A'},
67aa015c8eSEdward Tomasz Napierala      { ACL_READ_NAMED_ATTRS, "read_xattr", 'R'},
68aa015c8eSEdward Tomasz Napierala      { ACL_WRITE_NAMED_ATTRS, "write_xattr", 'W'},
69aa015c8eSEdward Tomasz Napierala      { ACL_READ_ACL, "read_acl", 'c'},
70aa015c8eSEdward Tomasz Napierala      { ACL_WRITE_ACL, "write_acl", 'C'},
71aa015c8eSEdward Tomasz Napierala      { ACL_WRITE_OWNER, "write_owner", 'o'},
72aa015c8eSEdward Tomasz Napierala      { ACL_SYNCHRONIZE, "synchronize", 's'},
73aa015c8eSEdward Tomasz Napierala      { 0, 0, 0}};
74aa015c8eSEdward Tomasz Napierala 
75aa015c8eSEdward Tomasz Napierala static const char *
76aa015c8eSEdward Tomasz Napierala format_flag(uint32_t *var, const struct flagnames_struct *flags)
77aa015c8eSEdward Tomasz Napierala {
78aa015c8eSEdward Tomasz Napierala 
79aa015c8eSEdward Tomasz Napierala 	for (; flags->name != 0; flags++) {
80aa015c8eSEdward Tomasz Napierala 		if ((flags->flag & *var) == 0)
81aa015c8eSEdward Tomasz Napierala 			continue;
82aa015c8eSEdward Tomasz Napierala 
83aa015c8eSEdward Tomasz Napierala 		*var &= ~flags->flag;
84aa015c8eSEdward Tomasz Napierala 		return (flags->name);
85aa015c8eSEdward Tomasz Napierala 	}
86aa015c8eSEdward Tomasz Napierala 
87aa015c8eSEdward Tomasz Napierala 	return (NULL);
88aa015c8eSEdward Tomasz Napierala }
89aa015c8eSEdward Tomasz Napierala 
90aa015c8eSEdward Tomasz Napierala static int
91aa015c8eSEdward Tomasz Napierala format_flags_verbose(char *str, size_t size, uint32_t var,
92aa015c8eSEdward Tomasz Napierala     const struct flagnames_struct *flags)
93aa015c8eSEdward Tomasz Napierala {
94aa015c8eSEdward Tomasz Napierala 	size_t off = 0;
95aa015c8eSEdward Tomasz Napierala 	const char *tmp;
96aa015c8eSEdward Tomasz Napierala 
97aa015c8eSEdward Tomasz Napierala 	while ((tmp = format_flag(&var, flags)) != NULL) {
98aa015c8eSEdward Tomasz Napierala 		off += snprintf(str + off, size - off, "%s/", tmp);
99aa015c8eSEdward Tomasz Napierala 		assert (off < size);
100aa015c8eSEdward Tomasz Napierala 	}
101aa015c8eSEdward Tomasz Napierala 
102aa015c8eSEdward Tomasz Napierala 	/* If there were any flags added... */
103aa015c8eSEdward Tomasz Napierala 	if (off > 0) {
104aa015c8eSEdward Tomasz Napierala 		off--;
105aa015c8eSEdward Tomasz Napierala 		/* ... then remove the last slash. */
106aa015c8eSEdward Tomasz Napierala 		assert(str[off] == '/');
107aa015c8eSEdward Tomasz Napierala 	}
108aa015c8eSEdward Tomasz Napierala 
109aa015c8eSEdward Tomasz Napierala 	str[off] = '\0';
110aa015c8eSEdward Tomasz Napierala 
111aa015c8eSEdward Tomasz Napierala 	return (0);
112aa015c8eSEdward Tomasz Napierala }
113aa015c8eSEdward Tomasz Napierala 
114aa015c8eSEdward Tomasz Napierala static int
115aa015c8eSEdward Tomasz Napierala format_flags_compact(char *str, size_t size, uint32_t var,
116aa015c8eSEdward Tomasz Napierala     const struct flagnames_struct *flags)
117aa015c8eSEdward Tomasz Napierala {
118aa015c8eSEdward Tomasz Napierala 	size_t i;
119aa015c8eSEdward Tomasz Napierala 
120aa015c8eSEdward Tomasz Napierala 	for (i = 0; flags[i].name != NULL; i++) {
121aa015c8eSEdward Tomasz Napierala 		assert(i < size);
122aa015c8eSEdward Tomasz Napierala 		if ((flags[i].flag & var) == 0)
123aa015c8eSEdward Tomasz Napierala 			str[i] = '-';
124aa015c8eSEdward Tomasz Napierala 		else
125aa015c8eSEdward Tomasz Napierala 			str[i] = flags[i].letter;
126aa015c8eSEdward Tomasz Napierala 	}
127aa015c8eSEdward Tomasz Napierala 
128aa015c8eSEdward Tomasz Napierala 	str[i] = '\0';
129aa015c8eSEdward Tomasz Napierala 
130aa015c8eSEdward Tomasz Napierala 	return (0);
131aa015c8eSEdward Tomasz Napierala }
132aa015c8eSEdward Tomasz Napierala 
133aa015c8eSEdward Tomasz Napierala static int
134aa015c8eSEdward Tomasz Napierala parse_flags_verbose(const char *strp, uint32_t *var,
135aa015c8eSEdward Tomasz Napierala     const struct flagnames_struct *flags, const char *flags_name,
136aa015c8eSEdward Tomasz Napierala     int *try_compact)
137aa015c8eSEdward Tomasz Napierala {
138aa015c8eSEdward Tomasz Napierala 	int i, found, ever_found = 0;
139aa015c8eSEdward Tomasz Napierala 	char *str, *flag;
140aa015c8eSEdward Tomasz Napierala 
141aa015c8eSEdward Tomasz Napierala 	str = strdup(strp);
142aa015c8eSEdward Tomasz Napierala 	*try_compact = 0;
143aa015c8eSEdward Tomasz Napierala 	*var = 0;
144aa015c8eSEdward Tomasz Napierala 
145aa015c8eSEdward Tomasz Napierala 	while (str != NULL) {
146aa015c8eSEdward Tomasz Napierala 		flag = strsep(&str, "/:");
147aa015c8eSEdward Tomasz Napierala 
148aa015c8eSEdward Tomasz Napierala 		found = 0;
149aa015c8eSEdward Tomasz Napierala 		for (i = 0; flags[i].name != NULL; i++) {
150aa015c8eSEdward Tomasz Napierala 			if (strcmp(flags[i].name, flag) == 0) {
151aa015c8eSEdward Tomasz Napierala 				*var |= flags[i].flag;
152aa015c8eSEdward Tomasz Napierala 				found = 1;
153aa015c8eSEdward Tomasz Napierala 				ever_found = 1;
154aa015c8eSEdward Tomasz Napierala 			}
155aa015c8eSEdward Tomasz Napierala 		}
156aa015c8eSEdward Tomasz Napierala 
157aa015c8eSEdward Tomasz Napierala 		if (!found) {
158aa015c8eSEdward Tomasz Napierala 			if (ever_found)
159aa015c8eSEdward Tomasz Napierala 				warnx("malformed ACL: \"%s\" field contains "
160aa015c8eSEdward Tomasz Napierala 				    "invalid flag \"%s\"", flags_name, flag);
161aa015c8eSEdward Tomasz Napierala 			else
162aa015c8eSEdward Tomasz Napierala 				*try_compact = 1;
163aa015c8eSEdward Tomasz Napierala 			free(str);
164aa015c8eSEdward Tomasz Napierala 			return (-1);
165aa015c8eSEdward Tomasz Napierala 		}
166aa015c8eSEdward Tomasz Napierala 	}
167aa015c8eSEdward Tomasz Napierala 
168aa015c8eSEdward Tomasz Napierala 	free(str);
169aa015c8eSEdward Tomasz Napierala 	return (0);
170aa015c8eSEdward Tomasz Napierala }
171aa015c8eSEdward Tomasz Napierala 
172aa015c8eSEdward Tomasz Napierala static int
173aa015c8eSEdward Tomasz Napierala parse_flags_compact(const char *str, uint32_t *var,
174aa015c8eSEdward Tomasz Napierala     const struct flagnames_struct *flags, const char *flags_name)
175aa015c8eSEdward Tomasz Napierala {
176aa015c8eSEdward Tomasz Napierala 	int i, j, found;
177aa015c8eSEdward Tomasz Napierala 
178aa015c8eSEdward Tomasz Napierala 	*var = 0;
179aa015c8eSEdward Tomasz Napierala 
180aa015c8eSEdward Tomasz Napierala 	for (i = 0;; i++) {
181aa015c8eSEdward Tomasz Napierala 		if (str[i] == '\0')
182aa015c8eSEdward Tomasz Napierala 			return (0);
183aa015c8eSEdward Tomasz Napierala 
184aa015c8eSEdward Tomasz Napierala 		/* Ignore minus signs. */
185aa015c8eSEdward Tomasz Napierala 		if (str[i] == '-')
186aa015c8eSEdward Tomasz Napierala 			continue;
187aa015c8eSEdward Tomasz Napierala 
188aa015c8eSEdward Tomasz Napierala 		found = 0;
189aa015c8eSEdward Tomasz Napierala 
190aa015c8eSEdward Tomasz Napierala 		for (j = 0; flags[j].name != NULL; j++) {
191aa015c8eSEdward Tomasz Napierala 			if (flags[j].letter == str[i]) {
192aa015c8eSEdward Tomasz Napierala 				*var |= flags[j].flag;
193aa015c8eSEdward Tomasz Napierala 				found = 1;
194aa015c8eSEdward Tomasz Napierala 				break;
195aa015c8eSEdward Tomasz Napierala 			}
196aa015c8eSEdward Tomasz Napierala 		}
197aa015c8eSEdward Tomasz Napierala 
198aa015c8eSEdward Tomasz Napierala 		if (!found) {
199aa015c8eSEdward Tomasz Napierala 			warnx("malformed ACL: \"%s\" field contains "
200aa015c8eSEdward Tomasz Napierala 			    "invalid flag \"%c\"", flags_name, str[i]);
201aa015c8eSEdward Tomasz Napierala 			return (-1);
202aa015c8eSEdward Tomasz Napierala 		}
203aa015c8eSEdward Tomasz Napierala 	}
204aa015c8eSEdward Tomasz Napierala }
205aa015c8eSEdward Tomasz Napierala 
206aa015c8eSEdward Tomasz Napierala int
207aa015c8eSEdward Tomasz Napierala _nfs4_format_flags(char *str, size_t size, acl_flag_t var, int verbose)
208aa015c8eSEdward Tomasz Napierala {
209aa015c8eSEdward Tomasz Napierala 
210aa015c8eSEdward Tomasz Napierala 	if (verbose)
211aa015c8eSEdward Tomasz Napierala 		return (format_flags_verbose(str, size, var, a_flags));
212aa015c8eSEdward Tomasz Napierala 
213aa015c8eSEdward Tomasz Napierala 	return (format_flags_compact(str, size, var, a_flags));
214aa015c8eSEdward Tomasz Napierala }
215aa015c8eSEdward Tomasz Napierala 
216aa015c8eSEdward Tomasz Napierala int
217aa015c8eSEdward Tomasz Napierala _nfs4_format_access_mask(char *str, size_t size, acl_perm_t var, int verbose)
218aa015c8eSEdward Tomasz Napierala {
219aa015c8eSEdward Tomasz Napierala 
220aa015c8eSEdward Tomasz Napierala 	if (verbose)
221aa015c8eSEdward Tomasz Napierala 		return (format_flags_verbose(str, size, var, a_access_masks));
222aa015c8eSEdward Tomasz Napierala 
223aa015c8eSEdward Tomasz Napierala 	return (format_flags_compact(str, size, var, a_access_masks));
224aa015c8eSEdward Tomasz Napierala }
225aa015c8eSEdward Tomasz Napierala 
226aa015c8eSEdward Tomasz Napierala int
227aa015c8eSEdward Tomasz Napierala _nfs4_parse_flags(const char *str, acl_flag_t *flags)
228aa015c8eSEdward Tomasz Napierala {
229aa015c8eSEdward Tomasz Napierala 	int error, try_compact;
230aa015c8eSEdward Tomasz Napierala 	int tmpflags;
231aa015c8eSEdward Tomasz Napierala 
232aa015c8eSEdward Tomasz Napierala 	error = parse_flags_verbose(str, &tmpflags, a_flags, "flags", &try_compact);
233aa015c8eSEdward Tomasz Napierala 	if (error && try_compact)
234aa015c8eSEdward Tomasz Napierala 		error = parse_flags_compact(str, &tmpflags, a_flags, "flags");
235aa015c8eSEdward Tomasz Napierala 
236aa015c8eSEdward Tomasz Napierala 	*flags = tmpflags;
237aa015c8eSEdward Tomasz Napierala 
238aa015c8eSEdward Tomasz Napierala 	return (error);
239aa015c8eSEdward Tomasz Napierala }
240aa015c8eSEdward Tomasz Napierala 
241aa015c8eSEdward Tomasz Napierala int
242aa015c8eSEdward Tomasz Napierala _nfs4_parse_access_mask(const char *str, acl_perm_t *perms)
243aa015c8eSEdward Tomasz Napierala {
244aa015c8eSEdward Tomasz Napierala 	int error, try_compact;
245aa015c8eSEdward Tomasz Napierala 	int tmpperms;
246aa015c8eSEdward Tomasz Napierala 
247aa015c8eSEdward Tomasz Napierala 	error = parse_flags_verbose(str, &tmpperms, a_access_masks,
248aa015c8eSEdward Tomasz Napierala 	    "access permissions", &try_compact);
249aa015c8eSEdward Tomasz Napierala 	if (error && try_compact)
250aa015c8eSEdward Tomasz Napierala 		error = parse_flags_compact(str, &tmpperms,
251aa015c8eSEdward Tomasz Napierala 		    a_access_masks, "access permissions");
252aa015c8eSEdward Tomasz Napierala 
253aa015c8eSEdward Tomasz Napierala 	*perms = tmpperms;
254aa015c8eSEdward Tomasz Napierala 
255aa015c8eSEdward Tomasz Napierala 	return (error);
256aa015c8eSEdward Tomasz Napierala }
257aa015c8eSEdward Tomasz Napierala /*-
258aa015c8eSEdward Tomasz Napierala  * Copyright (c) 2008, 2009 Edward Tomasz Napierała <trasz@FreeBSD.org>
259aa015c8eSEdward Tomasz Napierala  * All rights reserved.
260aa015c8eSEdward Tomasz Napierala  *
261aa015c8eSEdward Tomasz Napierala  * Redistribution and use in source and binary forms, with or without
262aa015c8eSEdward Tomasz Napierala  * modification, are permitted provided that the following conditions
263aa015c8eSEdward Tomasz Napierala  * are met:
264aa015c8eSEdward Tomasz Napierala  * 1. Redistributions of source code must retain the above copyright
265aa015c8eSEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer.
266aa015c8eSEdward Tomasz Napierala  * 2. Redistributions in binary form must reproduce the above copyright
267aa015c8eSEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer in the
268aa015c8eSEdward Tomasz Napierala  *    documentation and/or other materials provided with the distribution.
269aa015c8eSEdward Tomasz Napierala  *
270aa015c8eSEdward Tomasz Napierala  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
271aa015c8eSEdward Tomasz Napierala  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
272aa015c8eSEdward Tomasz Napierala  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
273aa015c8eSEdward Tomasz Napierala  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
274aa015c8eSEdward Tomasz Napierala  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
275aa015c8eSEdward Tomasz Napierala  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
276aa015c8eSEdward Tomasz Napierala  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
277aa015c8eSEdward Tomasz Napierala  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
278aa015c8eSEdward Tomasz Napierala  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
279aa015c8eSEdward Tomasz Napierala  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
280aa015c8eSEdward Tomasz Napierala  * SUCH DAMAGE.
281aa015c8eSEdward Tomasz Napierala  */
282aa015c8eSEdward Tomasz Napierala 
283aa015c8eSEdward Tomasz Napierala #include <sys/cdefs.h>
284aa015c8eSEdward Tomasz Napierala __FBSDID("$FreeBSD$");
285aa015c8eSEdward Tomasz Napierala 
286aa015c8eSEdward Tomasz Napierala #include <stdio.h>
287aa015c8eSEdward Tomasz Napierala #include <stdlib.h>
288aa015c8eSEdward Tomasz Napierala #include <string.h>
289aa015c8eSEdward Tomasz Napierala #include <assert.h>
290aa015c8eSEdward Tomasz Napierala #include <err.h>
291aa015c8eSEdward Tomasz Napierala #include <sys/acl.h>
292aa015c8eSEdward Tomasz Napierala #include "acl_support.h"
293aa015c8eSEdward Tomasz Napierala 
294aa015c8eSEdward Tomasz Napierala struct flagnames_struct {
295aa015c8eSEdward Tomasz Napierala 	uint32_t	flag;
296aa015c8eSEdward Tomasz Napierala 	const char	*name;
297aa015c8eSEdward Tomasz Napierala 	char		letter;
298aa015c8eSEdward Tomasz Napierala };
299aa015c8eSEdward Tomasz Napierala 
300aa015c8eSEdward Tomasz Napierala struct flagnames_struct a_flags[] =
301aa015c8eSEdward Tomasz Napierala     {{ ACL_ENTRY_FILE_INHERIT, "file_inherit", 'f'},
302aa015c8eSEdward Tomasz Napierala      { ACL_ENTRY_DIRECTORY_INHERIT, "dir_inherit", 'd'},
303aa015c8eSEdward Tomasz Napierala      { ACL_ENTRY_INHERIT_ONLY, "inherit_only", 'i'},
304aa015c8eSEdward Tomasz Napierala      { ACL_ENTRY_NO_PROPAGATE_INHERIT, "no_propagate", 'n'},
305aa015c8eSEdward Tomasz Napierala      { ACL_ENTRY_SUCCESSFUL_ACCESS, "successfull_access", 'S'},
306aa015c8eSEdward Tomasz Napierala      { ACL_ENTRY_FAILED_ACCESS, "failed_access", 'F'},
307aa015c8eSEdward Tomasz Napierala      /*
308aa015c8eSEdward Tomasz Napierala       * There is no ACE_IDENTIFIER_GROUP here - SunOS does not show it
309aa015c8eSEdward Tomasz Napierala       * in the "flags" field.  There is no ACE_OWNER, ACE_GROUP or
310aa015c8eSEdward Tomasz Napierala       * ACE_EVERYONE either, for obvious reasons.
311aa015c8eSEdward Tomasz Napierala       */
312aa015c8eSEdward Tomasz Napierala      { 0, 0, 0}};
313aa015c8eSEdward Tomasz Napierala 
314aa015c8eSEdward Tomasz Napierala struct flagnames_struct a_access_masks[] =
315aa015c8eSEdward Tomasz Napierala     {{ ACL_READ_DATA, "read_data", 'r'},
316aa015c8eSEdward Tomasz Napierala      { ACL_WRITE_DATA, "write_data", 'w'},
317aa015c8eSEdward Tomasz Napierala      { ACL_EXECUTE, "execute", 'x'},
318aa015c8eSEdward Tomasz Napierala      { ACL_APPEND_DATA, "append_data", 'p'},
319aa015c8eSEdward Tomasz Napierala      { ACL_DELETE_CHILD, "delete_child", 'D'},
320aa015c8eSEdward Tomasz Napierala      { ACL_DELETE, "delete", 'd'},
321aa015c8eSEdward Tomasz Napierala      { ACL_READ_ATTRIBUTES, "read_attributes", 'a'},
322aa015c8eSEdward Tomasz Napierala      { ACL_WRITE_ATTRIBUTES, "write_attributes", 'A'},
323aa015c8eSEdward Tomasz Napierala      { ACL_READ_NAMED_ATTRS, "read_xattr", 'R'},
324aa015c8eSEdward Tomasz Napierala      { ACL_WRITE_NAMED_ATTRS, "write_xattr", 'W'},
325aa015c8eSEdward Tomasz Napierala      { ACL_READ_ACL, "read_acl", 'c'},
326aa015c8eSEdward Tomasz Napierala      { ACL_WRITE_ACL, "write_acl", 'C'},
327aa015c8eSEdward Tomasz Napierala      { ACL_WRITE_OWNER, "write_owner", 'o'},
328aa015c8eSEdward Tomasz Napierala      { ACL_SYNCHRONIZE, "synchronize", 's'},
329aa015c8eSEdward Tomasz Napierala      { 0, 0, 0}};
330aa015c8eSEdward Tomasz Napierala 
331aa015c8eSEdward Tomasz Napierala static const char *
332aa015c8eSEdward Tomasz Napierala format_flag(uint32_t *var, const struct flagnames_struct *flags)
333aa015c8eSEdward Tomasz Napierala {
334aa015c8eSEdward Tomasz Napierala 
335aa015c8eSEdward Tomasz Napierala 	for (; flags->name != 0; flags++) {
336aa015c8eSEdward Tomasz Napierala 		if ((flags->flag & *var) == 0)
337aa015c8eSEdward Tomasz Napierala 			continue;
338aa015c8eSEdward Tomasz Napierala 
339aa015c8eSEdward Tomasz Napierala 		*var &= ~flags->flag;
340aa015c8eSEdward Tomasz Napierala 		return (flags->name);
341aa015c8eSEdward Tomasz Napierala 	}
342aa015c8eSEdward Tomasz Napierala 
343aa015c8eSEdward Tomasz Napierala 	return (NULL);
344aa015c8eSEdward Tomasz Napierala }
345aa015c8eSEdward Tomasz Napierala 
346aa015c8eSEdward Tomasz Napierala static int
347aa015c8eSEdward Tomasz Napierala format_flags_verbose(char *str, size_t size, uint32_t var,
348aa015c8eSEdward Tomasz Napierala     const struct flagnames_struct *flags)
349aa015c8eSEdward Tomasz Napierala {
350aa015c8eSEdward Tomasz Napierala 	size_t off = 0;
351aa015c8eSEdward Tomasz Napierala 	const char *tmp;
352aa015c8eSEdward Tomasz Napierala 
353aa015c8eSEdward Tomasz Napierala 	while ((tmp = format_flag(&var, flags)) != NULL) {
354aa015c8eSEdward Tomasz Napierala 		off += snprintf(str + off, size - off, "%s/", tmp);
355aa015c8eSEdward Tomasz Napierala 		assert (off < size);
356aa015c8eSEdward Tomasz Napierala 	}
357aa015c8eSEdward Tomasz Napierala 
358aa015c8eSEdward Tomasz Napierala 	/* If there were any flags added... */
359aa015c8eSEdward Tomasz Napierala 	if (off > 0) {
360aa015c8eSEdward Tomasz Napierala 		off--;
361aa015c8eSEdward Tomasz Napierala 		/* ... then remove the last slash. */
362aa015c8eSEdward Tomasz Napierala 		assert(str[off] == '/');
363aa015c8eSEdward Tomasz Napierala 	}
364aa015c8eSEdward Tomasz Napierala 
365aa015c8eSEdward Tomasz Napierala 	str[off] = '\0';
366aa015c8eSEdward Tomasz Napierala 
367aa015c8eSEdward Tomasz Napierala 	return (0);
368aa015c8eSEdward Tomasz Napierala }
369aa015c8eSEdward Tomasz Napierala 
370aa015c8eSEdward Tomasz Napierala static int
371aa015c8eSEdward Tomasz Napierala format_flags_compact(char *str, size_t size, uint32_t var,
372aa015c8eSEdward Tomasz Napierala     const struct flagnames_struct *flags)
373aa015c8eSEdward Tomasz Napierala {
374aa015c8eSEdward Tomasz Napierala 	size_t i;
375aa015c8eSEdward Tomasz Napierala 
376aa015c8eSEdward Tomasz Napierala 	for (i = 0; flags[i].name != NULL; i++) {
377aa015c8eSEdward Tomasz Napierala 		assert(i < size);
378aa015c8eSEdward Tomasz Napierala 		if ((flags[i].flag & var) == 0)
379aa015c8eSEdward Tomasz Napierala 			str[i] = '-';
380aa015c8eSEdward Tomasz Napierala 		else
381aa015c8eSEdward Tomasz Napierala 			str[i] = flags[i].letter;
382aa015c8eSEdward Tomasz Napierala 	}
383aa015c8eSEdward Tomasz Napierala 
384aa015c8eSEdward Tomasz Napierala 	str[i] = '\0';
385aa015c8eSEdward Tomasz Napierala 
386aa015c8eSEdward Tomasz Napierala 	return (0);
387aa015c8eSEdward Tomasz Napierala }
388aa015c8eSEdward Tomasz Napierala 
389aa015c8eSEdward Tomasz Napierala static int
390aa015c8eSEdward Tomasz Napierala parse_flags_verbose(const char *strp, uint32_t *var,
391aa015c8eSEdward Tomasz Napierala     const struct flagnames_struct *flags, const char *flags_name,
392aa015c8eSEdward Tomasz Napierala     int *try_compact)
393aa015c8eSEdward Tomasz Napierala {
394aa015c8eSEdward Tomasz Napierala 	int i, found, ever_found = 0;
395aa015c8eSEdward Tomasz Napierala 	char *str, *flag;
396aa015c8eSEdward Tomasz Napierala 
397aa015c8eSEdward Tomasz Napierala 	str = strdup(strp);
398aa015c8eSEdward Tomasz Napierala 	*try_compact = 0;
399aa015c8eSEdward Tomasz Napierala 	*var = 0;
400aa015c8eSEdward Tomasz Napierala 
401aa015c8eSEdward Tomasz Napierala 	while (str != NULL) {
402aa015c8eSEdward Tomasz Napierala 		flag = strsep(&str, "/:");
403aa015c8eSEdward Tomasz Napierala 
404aa015c8eSEdward Tomasz Napierala 		found = 0;
405aa015c8eSEdward Tomasz Napierala 		for (i = 0; flags[i].name != NULL; i++) {
406aa015c8eSEdward Tomasz Napierala 			if (strcmp(flags[i].name, flag) == 0) {
407aa015c8eSEdward Tomasz Napierala 				*var |= flags[i].flag;
408aa015c8eSEdward Tomasz Napierala 				found = 1;
409aa015c8eSEdward Tomasz Napierala 				ever_found = 1;
410aa015c8eSEdward Tomasz Napierala 			}
411aa015c8eSEdward Tomasz Napierala 		}
412aa015c8eSEdward Tomasz Napierala 
413aa015c8eSEdward Tomasz Napierala 		if (!found) {
414aa015c8eSEdward Tomasz Napierala 			if (ever_found)
415aa015c8eSEdward Tomasz Napierala 				warnx("malformed ACL: \"%s\" field contains "
416aa015c8eSEdward Tomasz Napierala 				    "invalid flag \"%s\"", flags_name, flag);
417aa015c8eSEdward Tomasz Napierala 			else
418aa015c8eSEdward Tomasz Napierala 				*try_compact = 1;
419aa015c8eSEdward Tomasz Napierala 			free(str);
420aa015c8eSEdward Tomasz Napierala 			return (-1);
421aa015c8eSEdward Tomasz Napierala 		}
422aa015c8eSEdward Tomasz Napierala 	}
423aa015c8eSEdward Tomasz Napierala 
424aa015c8eSEdward Tomasz Napierala 	free(str);
425aa015c8eSEdward Tomasz Napierala 	return (0);
426aa015c8eSEdward Tomasz Napierala }
427aa015c8eSEdward Tomasz Napierala 
428aa015c8eSEdward Tomasz Napierala static int
429aa015c8eSEdward Tomasz Napierala parse_flags_compact(const char *str, uint32_t *var,
430aa015c8eSEdward Tomasz Napierala     const struct flagnames_struct *flags, const char *flags_name)
431aa015c8eSEdward Tomasz Napierala {
432aa015c8eSEdward Tomasz Napierala 	int i, j, found;
433aa015c8eSEdward Tomasz Napierala 
434aa015c8eSEdward Tomasz Napierala 	*var = 0;
435aa015c8eSEdward Tomasz Napierala 
436aa015c8eSEdward Tomasz Napierala 	for (i = 0;; i++) {
437aa015c8eSEdward Tomasz Napierala 		if (str[i] == '\0')
438aa015c8eSEdward Tomasz Napierala 			return (0);
439aa015c8eSEdward Tomasz Napierala 
440aa015c8eSEdward Tomasz Napierala 		/* Ignore minus signs. */
441aa015c8eSEdward Tomasz Napierala 		if (str[i] == '-')
442aa015c8eSEdward Tomasz Napierala 			continue;
443aa015c8eSEdward Tomasz Napierala 
444aa015c8eSEdward Tomasz Napierala 		found = 0;
445aa015c8eSEdward Tomasz Napierala 
446aa015c8eSEdward Tomasz Napierala 		for (j = 0; flags[j].name != NULL; j++) {
447aa015c8eSEdward Tomasz Napierala 			if (flags[j].letter == str[i]) {
448aa015c8eSEdward Tomasz Napierala 				*var |= flags[j].flag;
449aa015c8eSEdward Tomasz Napierala 				found = 1;
450aa015c8eSEdward Tomasz Napierala 				break;
451aa015c8eSEdward Tomasz Napierala 			}
452aa015c8eSEdward Tomasz Napierala 		}
453aa015c8eSEdward Tomasz Napierala 
454aa015c8eSEdward Tomasz Napierala 		if (!found) {
455aa015c8eSEdward Tomasz Napierala 			warnx("malformed ACL: \"%s\" field contains "
456aa015c8eSEdward Tomasz Napierala 			    "invalid flag \"%c\"", flags_name, str[i]);
457aa015c8eSEdward Tomasz Napierala 			return (-1);
458aa015c8eSEdward Tomasz Napierala 		}
459aa015c8eSEdward Tomasz Napierala 	}
460aa015c8eSEdward Tomasz Napierala }
461aa015c8eSEdward Tomasz Napierala 
462aa015c8eSEdward Tomasz Napierala int
463aa015c8eSEdward Tomasz Napierala _nfs4_format_flags(char *str, size_t size, acl_flag_t var, int verbose)
464aa015c8eSEdward Tomasz Napierala {
465aa015c8eSEdward Tomasz Napierala 
466aa015c8eSEdward Tomasz Napierala 	if (verbose)
467aa015c8eSEdward Tomasz Napierala 		return (format_flags_verbose(str, size, var, a_flags));
468aa015c8eSEdward Tomasz Napierala 
469aa015c8eSEdward Tomasz Napierala 	return (format_flags_compact(str, size, var, a_flags));
470aa015c8eSEdward Tomasz Napierala }
471aa015c8eSEdward Tomasz Napierala 
472aa015c8eSEdward Tomasz Napierala int
473aa015c8eSEdward Tomasz Napierala _nfs4_format_access_mask(char *str, size_t size, acl_perm_t var, int verbose)
474aa015c8eSEdward Tomasz Napierala {
475aa015c8eSEdward Tomasz Napierala 
476aa015c8eSEdward Tomasz Napierala 	if (verbose)
477aa015c8eSEdward Tomasz Napierala 		return (format_flags_verbose(str, size, var, a_access_masks));
478aa015c8eSEdward Tomasz Napierala 
479aa015c8eSEdward Tomasz Napierala 	return (format_flags_compact(str, size, var, a_access_masks));
480aa015c8eSEdward Tomasz Napierala }
481aa015c8eSEdward Tomasz Napierala 
482aa015c8eSEdward Tomasz Napierala int
483aa015c8eSEdward Tomasz Napierala _nfs4_parse_flags(const char *str, acl_flag_t *flags)
484aa015c8eSEdward Tomasz Napierala {
485aa015c8eSEdward Tomasz Napierala 	int error, try_compact;
486aa015c8eSEdward Tomasz Napierala 	int tmpflags;
487aa015c8eSEdward Tomasz Napierala 
488aa015c8eSEdward Tomasz Napierala 	error = parse_flags_verbose(str, &tmpflags, a_flags, "flags", &try_compact);
489aa015c8eSEdward Tomasz Napierala 	if (error && try_compact)
490aa015c8eSEdward Tomasz Napierala 		error = parse_flags_compact(str, &tmpflags, a_flags, "flags");
491aa015c8eSEdward Tomasz Napierala 
492aa015c8eSEdward Tomasz Napierala 	*flags = tmpflags;
493aa015c8eSEdward Tomasz Napierala 
494aa015c8eSEdward Tomasz Napierala 	return (error);
495aa015c8eSEdward Tomasz Napierala }
496aa015c8eSEdward Tomasz Napierala 
497aa015c8eSEdward Tomasz Napierala int
498aa015c8eSEdward Tomasz Napierala _nfs4_parse_access_mask(const char *str, acl_perm_t *perms)
499aa015c8eSEdward Tomasz Napierala {
500aa015c8eSEdward Tomasz Napierala 	int error, try_compact;
501aa015c8eSEdward Tomasz Napierala 	int tmpperms;
502aa015c8eSEdward Tomasz Napierala 
503aa015c8eSEdward Tomasz Napierala 	error = parse_flags_verbose(str, &tmpperms, a_access_masks,
504aa015c8eSEdward Tomasz Napierala 	    "access permissions", &try_compact);
505aa015c8eSEdward Tomasz Napierala 	if (error && try_compact)
506aa015c8eSEdward Tomasz Napierala 		error = parse_flags_compact(str, &tmpperms,
507aa015c8eSEdward Tomasz Napierala 		    a_access_masks, "access permissions");
508aa015c8eSEdward Tomasz Napierala 
509aa015c8eSEdward Tomasz Napierala 	*perms = tmpperms;
510aa015c8eSEdward Tomasz Napierala 
511aa015c8eSEdward Tomasz Napierala 	return (error);
512aa015c8eSEdward Tomasz Napierala }
513aa015c8eSEdward Tomasz Napierala /*-
514aa015c8eSEdward Tomasz Napierala  * Copyright (c) 2008, 2009 Edward Tomasz Napierała <trasz@FreeBSD.org>
515aa015c8eSEdward Tomasz Napierala  * All rights reserved.
516aa015c8eSEdward Tomasz Napierala  *
517aa015c8eSEdward Tomasz Napierala  * Redistribution and use in source and binary forms, with or without
518aa015c8eSEdward Tomasz Napierala  * modification, are permitted provided that the following conditions
519aa015c8eSEdward Tomasz Napierala  * are met:
520aa015c8eSEdward Tomasz Napierala  * 1. Redistributions of source code must retain the above copyright
521aa015c8eSEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer.
522aa015c8eSEdward Tomasz Napierala  * 2. Redistributions in binary form must reproduce the above copyright
523aa015c8eSEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer in the
524aa015c8eSEdward Tomasz Napierala  *    documentation and/or other materials provided with the distribution.
525aa015c8eSEdward Tomasz Napierala  *
526aa015c8eSEdward Tomasz Napierala  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
527aa015c8eSEdward Tomasz Napierala  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
528aa015c8eSEdward Tomasz Napierala  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
529aa015c8eSEdward Tomasz Napierala  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
530aa015c8eSEdward Tomasz Napierala  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
531aa015c8eSEdward Tomasz Napierala  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
532aa015c8eSEdward Tomasz Napierala  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
533aa015c8eSEdward Tomasz Napierala  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
534aa015c8eSEdward Tomasz Napierala  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
535aa015c8eSEdward Tomasz Napierala  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
536aa015c8eSEdward Tomasz Napierala  * SUCH DAMAGE.
537aa015c8eSEdward Tomasz Napierala  */
538aa015c8eSEdward Tomasz Napierala 
539aa015c8eSEdward Tomasz Napierala #include <sys/cdefs.h>
540aa015c8eSEdward Tomasz Napierala __FBSDID("$FreeBSD$");
541aa015c8eSEdward Tomasz Napierala 
542aa015c8eSEdward Tomasz Napierala #include <stdio.h>
543aa015c8eSEdward Tomasz Napierala #include <stdlib.h>
544aa015c8eSEdward Tomasz Napierala #include <string.h>
545aa015c8eSEdward Tomasz Napierala #include <assert.h>
546aa015c8eSEdward Tomasz Napierala #include <err.h>
547aa015c8eSEdward Tomasz Napierala #include <sys/acl.h>
548aa015c8eSEdward Tomasz Napierala #include "acl_support.h"
549aa015c8eSEdward Tomasz Napierala 
550aa015c8eSEdward Tomasz Napierala struct flagnames_struct {
551aa015c8eSEdward Tomasz Napierala 	uint32_t	flag;
552aa015c8eSEdward Tomasz Napierala 	const char	*name;
553aa015c8eSEdward Tomasz Napierala 	char		letter;
554aa015c8eSEdward Tomasz Napierala };
555aa015c8eSEdward Tomasz Napierala 
556aa015c8eSEdward Tomasz Napierala struct flagnames_struct a_flags[] =
557aa015c8eSEdward Tomasz Napierala     {{ ACL_ENTRY_FILE_INHERIT, "file_inherit", 'f'},
558aa015c8eSEdward Tomasz Napierala      { ACL_ENTRY_DIRECTORY_INHERIT, "dir_inherit", 'd'},
559aa015c8eSEdward Tomasz Napierala      { ACL_ENTRY_INHERIT_ONLY, "inherit_only", 'i'},
560aa015c8eSEdward Tomasz Napierala      { ACL_ENTRY_NO_PROPAGATE_INHERIT, "no_propagate", 'n'},
561aa015c8eSEdward Tomasz Napierala      { ACL_ENTRY_SUCCESSFUL_ACCESS, "successfull_access", 'S'},
562aa015c8eSEdward Tomasz Napierala      { ACL_ENTRY_FAILED_ACCESS, "failed_access", 'F'},
563aa015c8eSEdward Tomasz Napierala      /*
564aa015c8eSEdward Tomasz Napierala       * There is no ACE_IDENTIFIER_GROUP here - SunOS does not show it
565aa015c8eSEdward Tomasz Napierala       * in the "flags" field.  There is no ACE_OWNER, ACE_GROUP or
566aa015c8eSEdward Tomasz Napierala       * ACE_EVERYONE either, for obvious reasons.
567aa015c8eSEdward Tomasz Napierala       */
568aa015c8eSEdward Tomasz Napierala      { 0, 0, 0}};
569aa015c8eSEdward Tomasz Napierala 
570aa015c8eSEdward Tomasz Napierala struct flagnames_struct a_access_masks[] =
571aa015c8eSEdward Tomasz Napierala     {{ ACL_READ_DATA, "read_data", 'r'},
572aa015c8eSEdward Tomasz Napierala      { ACL_WRITE_DATA, "write_data", 'w'},
573aa015c8eSEdward Tomasz Napierala      { ACL_EXECUTE, "execute", 'x'},
574aa015c8eSEdward Tomasz Napierala      { ACL_APPEND_DATA, "append_data", 'p'},
575aa015c8eSEdward Tomasz Napierala      { ACL_DELETE_CHILD, "delete_child", 'D'},
576aa015c8eSEdward Tomasz Napierala      { ACL_DELETE, "delete", 'd'},
577aa015c8eSEdward Tomasz Napierala      { ACL_READ_ATTRIBUTES, "read_attributes", 'a'},
578aa015c8eSEdward Tomasz Napierala      { ACL_WRITE_ATTRIBUTES, "write_attributes", 'A'},
579aa015c8eSEdward Tomasz Napierala      { ACL_READ_NAMED_ATTRS, "read_xattr", 'R'},
580aa015c8eSEdward Tomasz Napierala      { ACL_WRITE_NAMED_ATTRS, "write_xattr", 'W'},
581aa015c8eSEdward Tomasz Napierala      { ACL_READ_ACL, "read_acl", 'c'},
582aa015c8eSEdward Tomasz Napierala      { ACL_WRITE_ACL, "write_acl", 'C'},
583aa015c8eSEdward Tomasz Napierala      { ACL_WRITE_OWNER, "write_owner", 'o'},
584aa015c8eSEdward Tomasz Napierala      { ACL_SYNCHRONIZE, "synchronize", 's'},
585aa015c8eSEdward Tomasz Napierala      { 0, 0, 0}};
586aa015c8eSEdward Tomasz Napierala 
587aa015c8eSEdward Tomasz Napierala static const char *
588aa015c8eSEdward Tomasz Napierala format_flag(uint32_t *var, const struct flagnames_struct *flags)
589aa015c8eSEdward Tomasz Napierala {
590aa015c8eSEdward Tomasz Napierala 
591aa015c8eSEdward Tomasz Napierala 	for (; flags->name != 0; flags++) {
592aa015c8eSEdward Tomasz Napierala 		if ((flags->flag & *var) == 0)
593aa015c8eSEdward Tomasz Napierala 			continue;
594aa015c8eSEdward Tomasz Napierala 
595aa015c8eSEdward Tomasz Napierala 		*var &= ~flags->flag;
596aa015c8eSEdward Tomasz Napierala 		return (flags->name);
597aa015c8eSEdward Tomasz Napierala 	}
598aa015c8eSEdward Tomasz Napierala 
599aa015c8eSEdward Tomasz Napierala 	return (NULL);
600aa015c8eSEdward Tomasz Napierala }
601aa015c8eSEdward Tomasz Napierala 
602aa015c8eSEdward Tomasz Napierala static int
603aa015c8eSEdward Tomasz Napierala format_flags_verbose(char *str, size_t size, uint32_t var,
604aa015c8eSEdward Tomasz Napierala     const struct flagnames_struct *flags)
605aa015c8eSEdward Tomasz Napierala {
606aa015c8eSEdward Tomasz Napierala 	size_t off = 0;
607aa015c8eSEdward Tomasz Napierala 	const char *tmp;
608aa015c8eSEdward Tomasz Napierala 
609aa015c8eSEdward Tomasz Napierala 	while ((tmp = format_flag(&var, flags)) != NULL) {
610aa015c8eSEdward Tomasz Napierala 		off += snprintf(str + off, size - off, "%s/", tmp);
611aa015c8eSEdward Tomasz Napierala 		assert (off < size);
612aa015c8eSEdward Tomasz Napierala 	}
613aa015c8eSEdward Tomasz Napierala 
614aa015c8eSEdward Tomasz Napierala 	/* If there were any flags added... */
615aa015c8eSEdward Tomasz Napierala 	if (off > 0) {
616aa015c8eSEdward Tomasz Napierala 		off--;
617aa015c8eSEdward Tomasz Napierala 		/* ... then remove the last slash. */
618aa015c8eSEdward Tomasz Napierala 		assert(str[off] == '/');
619aa015c8eSEdward Tomasz Napierala 	}
620aa015c8eSEdward Tomasz Napierala 
621aa015c8eSEdward Tomasz Napierala 	str[off] = '\0';
622aa015c8eSEdward Tomasz Napierala 
623aa015c8eSEdward Tomasz Napierala 	return (0);
624aa015c8eSEdward Tomasz Napierala }
625aa015c8eSEdward Tomasz Napierala 
626aa015c8eSEdward Tomasz Napierala static int
627aa015c8eSEdward Tomasz Napierala format_flags_compact(char *str, size_t size, uint32_t var,
628aa015c8eSEdward Tomasz Napierala     const struct flagnames_struct *flags)
629aa015c8eSEdward Tomasz Napierala {
630aa015c8eSEdward Tomasz Napierala 	size_t i;
631aa015c8eSEdward Tomasz Napierala 
632aa015c8eSEdward Tomasz Napierala 	for (i = 0; flags[i].name != NULL; i++) {
633aa015c8eSEdward Tomasz Napierala 		assert(i < size);
634aa015c8eSEdward Tomasz Napierala 		if ((flags[i].flag & var) == 0)
635aa015c8eSEdward Tomasz Napierala 			str[i] = '-';
636aa015c8eSEdward Tomasz Napierala 		else
637aa015c8eSEdward Tomasz Napierala 			str[i] = flags[i].letter;
638aa015c8eSEdward Tomasz Napierala 	}
639aa015c8eSEdward Tomasz Napierala 
640aa015c8eSEdward Tomasz Napierala 	str[i] = '\0';
641aa015c8eSEdward Tomasz Napierala 
642aa015c8eSEdward Tomasz Napierala 	return (0);
643aa015c8eSEdward Tomasz Napierala }
644aa015c8eSEdward Tomasz Napierala 
645aa015c8eSEdward Tomasz Napierala static int
646aa015c8eSEdward Tomasz Napierala parse_flags_verbose(const char *strp, uint32_t *var,
647aa015c8eSEdward Tomasz Napierala     const struct flagnames_struct *flags, const char *flags_name,
648aa015c8eSEdward Tomasz Napierala     int *try_compact)
649aa015c8eSEdward Tomasz Napierala {
650aa015c8eSEdward Tomasz Napierala 	int i, found, ever_found = 0;
651aa015c8eSEdward Tomasz Napierala 	char *str, *flag;
652aa015c8eSEdward Tomasz Napierala 
653aa015c8eSEdward Tomasz Napierala 	str = strdup(strp);
654aa015c8eSEdward Tomasz Napierala 	*try_compact = 0;
655aa015c8eSEdward Tomasz Napierala 	*var = 0;
656aa015c8eSEdward Tomasz Napierala 
657aa015c8eSEdward Tomasz Napierala 	while (str != NULL) {
658aa015c8eSEdward Tomasz Napierala 		flag = strsep(&str, "/:");
659aa015c8eSEdward Tomasz Napierala 
660aa015c8eSEdward Tomasz Napierala 		found = 0;
661aa015c8eSEdward Tomasz Napierala 		for (i = 0; flags[i].name != NULL; i++) {
662aa015c8eSEdward Tomasz Napierala 			if (strcmp(flags[i].name, flag) == 0) {
663aa015c8eSEdward Tomasz Napierala 				*var |= flags[i].flag;
664aa015c8eSEdward Tomasz Napierala 				found = 1;
665aa015c8eSEdward Tomasz Napierala 				ever_found = 1;
666aa015c8eSEdward Tomasz Napierala 			}
667aa015c8eSEdward Tomasz Napierala 		}
668aa015c8eSEdward Tomasz Napierala 
669aa015c8eSEdward Tomasz Napierala 		if (!found) {
670aa015c8eSEdward Tomasz Napierala 			if (ever_found)
671aa015c8eSEdward Tomasz Napierala 				warnx("malformed ACL: \"%s\" field contains "
672aa015c8eSEdward Tomasz Napierala 				    "invalid flag \"%s\"", flags_name, flag);
673aa015c8eSEdward Tomasz Napierala 			else
674aa015c8eSEdward Tomasz Napierala 				*try_compact = 1;
675aa015c8eSEdward Tomasz Napierala 			free(str);
676aa015c8eSEdward Tomasz Napierala 			return (-1);
677aa015c8eSEdward Tomasz Napierala 		}
678aa015c8eSEdward Tomasz Napierala 	}
679aa015c8eSEdward Tomasz Napierala 
680aa015c8eSEdward Tomasz Napierala 	free(str);
681aa015c8eSEdward Tomasz Napierala 	return (0);
682aa015c8eSEdward Tomasz Napierala }
683aa015c8eSEdward Tomasz Napierala 
684aa015c8eSEdward Tomasz Napierala static int
685aa015c8eSEdward Tomasz Napierala parse_flags_compact(const char *str, uint32_t *var,
686aa015c8eSEdward Tomasz Napierala     const struct flagnames_struct *flags, const char *flags_name)
687aa015c8eSEdward Tomasz Napierala {
688aa015c8eSEdward Tomasz Napierala 	int i, j, found;
689aa015c8eSEdward Tomasz Napierala 
690aa015c8eSEdward Tomasz Napierala 	*var = 0;
691aa015c8eSEdward Tomasz Napierala 
692aa015c8eSEdward Tomasz Napierala 	for (i = 0;; i++) {
693aa015c8eSEdward Tomasz Napierala 		if (str[i] == '\0')
694aa015c8eSEdward Tomasz Napierala 			return (0);
695aa015c8eSEdward Tomasz Napierala 
696aa015c8eSEdward Tomasz Napierala 		/* Ignore minus signs. */
697aa015c8eSEdward Tomasz Napierala 		if (str[i] == '-')
698aa015c8eSEdward Tomasz Napierala 			continue;
699aa015c8eSEdward Tomasz Napierala 
700aa015c8eSEdward Tomasz Napierala 		found = 0;
701aa015c8eSEdward Tomasz Napierala 
702aa015c8eSEdward Tomasz Napierala 		for (j = 0; flags[j].name != NULL; j++) {
703aa015c8eSEdward Tomasz Napierala 			if (flags[j].letter == str[i]) {
704aa015c8eSEdward Tomasz Napierala 				*var |= flags[j].flag;
705aa015c8eSEdward Tomasz Napierala 				found = 1;
706aa015c8eSEdward Tomasz Napierala 				break;
707aa015c8eSEdward Tomasz Napierala 			}
708aa015c8eSEdward Tomasz Napierala 		}
709aa015c8eSEdward Tomasz Napierala 
710aa015c8eSEdward Tomasz Napierala 		if (!found) {
711aa015c8eSEdward Tomasz Napierala 			warnx("malformed ACL: \"%s\" field contains "
712aa015c8eSEdward Tomasz Napierala 			    "invalid flag \"%c\"", flags_name, str[i]);
713aa015c8eSEdward Tomasz Napierala 			return (-1);
714aa015c8eSEdward Tomasz Napierala 		}
715aa015c8eSEdward Tomasz Napierala 	}
716aa015c8eSEdward Tomasz Napierala }
717aa015c8eSEdward Tomasz Napierala 
718aa015c8eSEdward Tomasz Napierala int
719aa015c8eSEdward Tomasz Napierala _nfs4_format_flags(char *str, size_t size, acl_flag_t var, int verbose)
720aa015c8eSEdward Tomasz Napierala {
721aa015c8eSEdward Tomasz Napierala 
722aa015c8eSEdward Tomasz Napierala 	if (verbose)
723aa015c8eSEdward Tomasz Napierala 		return (format_flags_verbose(str, size, var, a_flags));
724aa015c8eSEdward Tomasz Napierala 
725aa015c8eSEdward Tomasz Napierala 	return (format_flags_compact(str, size, var, a_flags));
726aa015c8eSEdward Tomasz Napierala }
727aa015c8eSEdward Tomasz Napierala 
728aa015c8eSEdward Tomasz Napierala int
729aa015c8eSEdward Tomasz Napierala _nfs4_format_access_mask(char *str, size_t size, acl_perm_t var, int verbose)
730aa015c8eSEdward Tomasz Napierala {
731aa015c8eSEdward Tomasz Napierala 
732aa015c8eSEdward Tomasz Napierala 	if (verbose)
733aa015c8eSEdward Tomasz Napierala 		return (format_flags_verbose(str, size, var, a_access_masks));
734aa015c8eSEdward Tomasz Napierala 
735aa015c8eSEdward Tomasz Napierala 	return (format_flags_compact(str, size, var, a_access_masks));
736aa015c8eSEdward Tomasz Napierala }
737aa015c8eSEdward Tomasz Napierala 
738aa015c8eSEdward Tomasz Napierala int
739aa015c8eSEdward Tomasz Napierala _nfs4_parse_flags(const char *str, acl_flag_t *flags)
740aa015c8eSEdward Tomasz Napierala {
741aa015c8eSEdward Tomasz Napierala 	int error, try_compact;
742aa015c8eSEdward Tomasz Napierala 	int tmpflags;
743aa015c8eSEdward Tomasz Napierala 
744aa015c8eSEdward Tomasz Napierala 	error = parse_flags_verbose(str, &tmpflags, a_flags, "flags", &try_compact);
745aa015c8eSEdward Tomasz Napierala 	if (error && try_compact)
746aa015c8eSEdward Tomasz Napierala 		error = parse_flags_compact(str, &tmpflags, a_flags, "flags");
747aa015c8eSEdward Tomasz Napierala 
748aa015c8eSEdward Tomasz Napierala 	*flags = tmpflags;
749aa015c8eSEdward Tomasz Napierala 
750aa015c8eSEdward Tomasz Napierala 	return (error);
751aa015c8eSEdward Tomasz Napierala }
752aa015c8eSEdward Tomasz Napierala 
753aa015c8eSEdward Tomasz Napierala int
754aa015c8eSEdward Tomasz Napierala _nfs4_parse_access_mask(const char *str, acl_perm_t *perms)
755aa015c8eSEdward Tomasz Napierala {
756aa015c8eSEdward Tomasz Napierala 	int error, try_compact;
757aa015c8eSEdward Tomasz Napierala 	int tmpperms;
758aa015c8eSEdward Tomasz Napierala 
759aa015c8eSEdward Tomasz Napierala 	error = parse_flags_verbose(str, &tmpperms, a_access_masks,
760aa015c8eSEdward Tomasz Napierala 	    "access permissions", &try_compact);
761aa015c8eSEdward Tomasz Napierala 	if (error && try_compact)
762aa015c8eSEdward Tomasz Napierala 		error = parse_flags_compact(str, &tmpperms,
763aa015c8eSEdward Tomasz Napierala 		    a_access_masks, "access permissions");
764aa015c8eSEdward Tomasz Napierala 
765aa015c8eSEdward Tomasz Napierala 	*perms = tmpperms;
766aa015c8eSEdward Tomasz Napierala 
767aa015c8eSEdward Tomasz Napierala 	return (error);
768aa015c8eSEdward Tomasz Napierala }
769