xref: /freebsd/lib/libc/posix1e/acl_support_nfs4.c (revision aa0a1e58)
1 /*-
2  * Copyright (c) 2008, 2009 Edward Tomasz Napierała <trasz@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <assert.h>
34 #include <err.h>
35 #include <sys/acl.h>
36 #include "acl_support.h"
37 
38 struct flagnames_struct {
39 	uint32_t	flag;
40 	const char	*name;
41 	char		letter;
42 };
43 
44 struct flagnames_struct a_flags[] =
45     {{ ACL_ENTRY_FILE_INHERIT, "file_inherit", 'f'},
46      { ACL_ENTRY_DIRECTORY_INHERIT, "dir_inherit", 'd'},
47      { ACL_ENTRY_INHERIT_ONLY, "inherit_only", 'i'},
48      { ACL_ENTRY_NO_PROPAGATE_INHERIT, "no_propagate", 'n'},
49      { ACL_ENTRY_SUCCESSFUL_ACCESS, "successfull_access", 'S'},
50      { ACL_ENTRY_FAILED_ACCESS, "failed_access", 'F'},
51      /*
52       * There is no ACE_IDENTIFIER_GROUP here - SunOS does not show it
53       * in the "flags" field.  There is no ACE_OWNER, ACE_GROUP or
54       * ACE_EVERYONE either, for obvious reasons.
55       */
56      { 0, 0, 0}};
57 
58 struct flagnames_struct a_access_masks[] =
59     {{ ACL_READ_DATA, "read_data", 'r'},
60      { ACL_WRITE_DATA, "write_data", 'w'},
61      { ACL_EXECUTE, "execute", 'x'},
62      { ACL_APPEND_DATA, "append_data", 'p'},
63      { ACL_DELETE_CHILD, "delete_child", 'D'},
64      { ACL_DELETE, "delete", 'd'},
65      { ACL_READ_ATTRIBUTES, "read_attributes", 'a'},
66      { ACL_WRITE_ATTRIBUTES, "write_attributes", 'A'},
67      { ACL_READ_NAMED_ATTRS, "read_xattr", 'R'},
68      { ACL_WRITE_NAMED_ATTRS, "write_xattr", 'W'},
69      { ACL_READ_ACL, "read_acl", 'c'},
70      { ACL_WRITE_ACL, "write_acl", 'C'},
71      { ACL_WRITE_OWNER, "write_owner", 'o'},
72      { ACL_SYNCHRONIZE, "synchronize", 's'},
73      { 0, 0, 0}};
74 
75 static const char *
76 format_flag(uint32_t *var, const struct flagnames_struct *flags)
77 {
78 
79 	for (; flags->name != 0; flags++) {
80 		if ((flags->flag & *var) == 0)
81 			continue;
82 
83 		*var &= ~flags->flag;
84 		return (flags->name);
85 	}
86 
87 	return (NULL);
88 }
89 
90 static int
91 format_flags_verbose(char *str, size_t size, uint32_t var,
92     const struct flagnames_struct *flags)
93 {
94 	size_t off = 0;
95 	const char *tmp;
96 
97 	while ((tmp = format_flag(&var, flags)) != NULL) {
98 		off += snprintf(str + off, size - off, "%s/", tmp);
99 		assert (off < size);
100 	}
101 
102 	/* If there were any flags added... */
103 	if (off > 0) {
104 		off--;
105 		/* ... then remove the last slash. */
106 		assert(str[off] == '/');
107 	}
108 
109 	str[off] = '\0';
110 
111 	return (0);
112 }
113 
114 static int
115 format_flags_compact(char *str, size_t size, uint32_t var,
116     const struct flagnames_struct *flags)
117 {
118 	size_t i;
119 
120 	for (i = 0; flags[i].name != NULL; i++) {
121 		assert(i < size);
122 		if ((flags[i].flag & var) == 0)
123 			str[i] = '-';
124 		else
125 			str[i] = flags[i].letter;
126 	}
127 
128 	str[i] = '\0';
129 
130 	return (0);
131 }
132 
133 static int
134 parse_flags_verbose(const char *strp, uint32_t *var,
135     const struct flagnames_struct *flags, const char *flags_name,
136     int *try_compact)
137 {
138 	int i, found, ever_found = 0;
139 	char *str, *flag;
140 
141 	str = strdup(strp);
142 	*try_compact = 0;
143 	*var = 0;
144 
145 	while (str != NULL) {
146 		flag = strsep(&str, "/:");
147 
148 		found = 0;
149 		for (i = 0; flags[i].name != NULL; i++) {
150 			if (strcmp(flags[i].name, flag) == 0) {
151 				*var |= flags[i].flag;
152 				found = 1;
153 				ever_found = 1;
154 			}
155 		}
156 
157 		if (!found) {
158 			if (ever_found)
159 				warnx("malformed ACL: \"%s\" field contains "
160 				    "invalid flag \"%s\"", flags_name, flag);
161 			else
162 				*try_compact = 1;
163 			free(str);
164 			return (-1);
165 		}
166 	}
167 
168 	free(str);
169 	return (0);
170 }
171 
172 static int
173 parse_flags_compact(const char *str, uint32_t *var,
174     const struct flagnames_struct *flags, const char *flags_name)
175 {
176 	int i, j, found;
177 
178 	*var = 0;
179 
180 	for (i = 0;; i++) {
181 		if (str[i] == '\0')
182 			return (0);
183 
184 		/* Ignore minus signs. */
185 		if (str[i] == '-')
186 			continue;
187 
188 		found = 0;
189 
190 		for (j = 0; flags[j].name != NULL; j++) {
191 			if (flags[j].letter == str[i]) {
192 				*var |= flags[j].flag;
193 				found = 1;
194 				break;
195 			}
196 		}
197 
198 		if (!found) {
199 			warnx("malformed ACL: \"%s\" field contains "
200 			    "invalid flag \"%c\"", flags_name, str[i]);
201 			return (-1);
202 		}
203 	}
204 }
205 
206 int
207 _nfs4_format_flags(char *str, size_t size, acl_flag_t var, int verbose)
208 {
209 
210 	if (verbose)
211 		return (format_flags_verbose(str, size, var, a_flags));
212 
213 	return (format_flags_compact(str, size, var, a_flags));
214 }
215 
216 int
217 _nfs4_format_access_mask(char *str, size_t size, acl_perm_t var, int verbose)
218 {
219 
220 	if (verbose)
221 		return (format_flags_verbose(str, size, var, a_access_masks));
222 
223 	return (format_flags_compact(str, size, var, a_access_masks));
224 }
225 
226 int
227 _nfs4_parse_flags(const char *str, acl_flag_t *flags)
228 {
229 	int error, try_compact;
230 	int tmpflags;
231 
232 	error = parse_flags_verbose(str, &tmpflags, a_flags, "flags", &try_compact);
233 	if (error && try_compact)
234 		error = parse_flags_compact(str, &tmpflags, a_flags, "flags");
235 
236 	*flags = tmpflags;
237 
238 	return (error);
239 }
240 
241 int
242 _nfs4_parse_access_mask(const char *str, acl_perm_t *perms)
243 {
244 	int error, try_compact;
245 	int tmpperms;
246 
247 	error = parse_flags_verbose(str, &tmpperms, a_access_masks,
248 	    "access permissions", &try_compact);
249 	if (error && try_compact)
250 		error = parse_flags_compact(str, &tmpperms,
251 		    a_access_masks, "access permissions");
252 
253 	*perms = tmpperms;
254 
255 	return (error);
256 }
257