1194955Strasz/*-
2194955Strasz * Copyright (c) 2008, 2009 Edward Tomasz Napiera��a <trasz@FreeBSD.org>
3194955Strasz * All rights reserved.
4194955Strasz *
5194955Strasz * Redistribution and use in source and binary forms, with or without
6194955Strasz * modification, are permitted provided that the following conditions
7194955Strasz * are met:
8194955Strasz * 1. Redistributions of source code must retain the above copyright
9194955Strasz *    notice, this list of conditions and the following disclaimer.
10194955Strasz * 2. Redistributions in binary form must reproduce the above copyright
11194955Strasz *    notice, this list of conditions and the following disclaimer in the
12194955Strasz *    documentation and/or other materials provided with the distribution.
13194955Strasz *
14194955Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15194955Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16194955Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17194955Strasz * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18194955Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19194955Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20194955Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21194955Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22194955Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23194955Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24194955Strasz * SUCH DAMAGE.
25194955Strasz */
26194955Strasz
27194955Strasz#include <sys/cdefs.h>
28194955Strasz__FBSDID("$FreeBSD: releng/11.0/lib/libc/posix1e/acl_support_nfs4.c 297790 2016-04-10 19:33:58Z pfg $");
29194955Strasz
30194955Strasz#include <stdio.h>
31194955Strasz#include <stdlib.h>
32194955Strasz#include <string.h>
33194955Strasz#include <assert.h>
34194955Strasz#include <err.h>
35194955Strasz#include <sys/acl.h>
36194955Strasz#include "acl_support.h"
37194955Strasz
38194955Straszstruct flagnames_struct {
39194955Strasz	uint32_t	flag;
40194955Strasz	const char	*name;
41194955Strasz	char		letter;
42194955Strasz};
43194955Strasz
44194955Straszstruct flagnames_struct a_flags[] =
45194955Strasz    {{ ACL_ENTRY_FILE_INHERIT, "file_inherit", 'f'},
46194955Strasz     { ACL_ENTRY_DIRECTORY_INHERIT, "dir_inherit", 'd'},
47194955Strasz     { ACL_ENTRY_INHERIT_ONLY, "inherit_only", 'i'},
48194955Strasz     { ACL_ENTRY_NO_PROPAGATE_INHERIT, "no_propagate", 'n'},
49194955Strasz     { ACL_ENTRY_SUCCESSFUL_ACCESS, "successfull_access", 'S'},
50194955Strasz     { ACL_ENTRY_FAILED_ACCESS, "failed_access", 'F'},
51287445Sdelphij     { ACL_ENTRY_INHERITED, "inherited", 'I' },
52194955Strasz     /*
53194955Strasz      * There is no ACE_IDENTIFIER_GROUP here - SunOS does not show it
54194955Strasz      * in the "flags" field.  There is no ACE_OWNER, ACE_GROUP or
55194955Strasz      * ACE_EVERYONE either, for obvious reasons.
56194955Strasz      */
57194955Strasz     { 0, 0, 0}};
58194955Strasz
59194955Straszstruct flagnames_struct a_access_masks[] =
60194955Strasz    {{ ACL_READ_DATA, "read_data", 'r'},
61194955Strasz     { ACL_WRITE_DATA, "write_data", 'w'},
62194955Strasz     { ACL_EXECUTE, "execute", 'x'},
63194955Strasz     { ACL_APPEND_DATA, "append_data", 'p'},
64194955Strasz     { ACL_DELETE_CHILD, "delete_child", 'D'},
65194955Strasz     { ACL_DELETE, "delete", 'd'},
66194955Strasz     { ACL_READ_ATTRIBUTES, "read_attributes", 'a'},
67194955Strasz     { ACL_WRITE_ATTRIBUTES, "write_attributes", 'A'},
68194955Strasz     { ACL_READ_NAMED_ATTRS, "read_xattr", 'R'},
69194955Strasz     { ACL_WRITE_NAMED_ATTRS, "write_xattr", 'W'},
70194955Strasz     { ACL_READ_ACL, "read_acl", 'c'},
71194955Strasz     { ACL_WRITE_ACL, "write_acl", 'C'},
72194955Strasz     { ACL_WRITE_OWNER, "write_owner", 'o'},
73194955Strasz     { ACL_SYNCHRONIZE, "synchronize", 's'},
74220465Strasz     { ACL_FULL_SET, "full_set", '\0'},
75220465Strasz     { ACL_MODIFY_SET, "modify_set", '\0'},
76220465Strasz     { ACL_READ_SET, "read_set", '\0'},
77220465Strasz     { ACL_WRITE_SET, "write_set", '\0'},
78194955Strasz     { 0, 0, 0}};
79194955Strasz
80194955Straszstatic const char *
81194955Straszformat_flag(uint32_t *var, const struct flagnames_struct *flags)
82194955Strasz{
83194955Strasz
84297790Spfg	for (; flags->name != NULL; flags++) {
85194955Strasz		if ((flags->flag & *var) == 0)
86194955Strasz			continue;
87194955Strasz
88194955Strasz		*var &= ~flags->flag;
89194955Strasz		return (flags->name);
90194955Strasz	}
91194955Strasz
92194955Strasz	return (NULL);
93194955Strasz}
94194955Strasz
95194955Straszstatic int
96194955Straszformat_flags_verbose(char *str, size_t size, uint32_t var,
97194955Strasz    const struct flagnames_struct *flags)
98194955Strasz{
99194955Strasz	size_t off = 0;
100194955Strasz	const char *tmp;
101194955Strasz
102194955Strasz	while ((tmp = format_flag(&var, flags)) != NULL) {
103194955Strasz		off += snprintf(str + off, size - off, "%s/", tmp);
104194955Strasz		assert (off < size);
105194955Strasz	}
106194955Strasz
107194955Strasz	/* If there were any flags added... */
108194955Strasz	if (off > 0) {
109194955Strasz		off--;
110194955Strasz		/* ... then remove the last slash. */
111194955Strasz		assert(str[off] == '/');
112194955Strasz	}
113194955Strasz
114194955Strasz	str[off] = '\0';
115194955Strasz
116194955Strasz	return (0);
117194955Strasz}
118194955Strasz
119194955Straszstatic int
120194955Straszformat_flags_compact(char *str, size_t size, uint32_t var,
121194955Strasz    const struct flagnames_struct *flags)
122194955Strasz{
123194955Strasz	size_t i;
124194955Strasz
125220465Strasz	for (i = 0; flags[i].letter != '\0'; i++) {
126194955Strasz		assert(i < size);
127194955Strasz		if ((flags[i].flag & var) == 0)
128194955Strasz			str[i] = '-';
129194955Strasz		else
130194955Strasz			str[i] = flags[i].letter;
131194955Strasz	}
132194955Strasz
133194955Strasz	str[i] = '\0';
134194955Strasz
135194955Strasz	return (0);
136194955Strasz}
137194955Strasz
138194955Straszstatic int
139194955Straszparse_flags_verbose(const char *strp, uint32_t *var,
140194955Strasz    const struct flagnames_struct *flags, const char *flags_name,
141194955Strasz    int *try_compact)
142194955Strasz{
143194955Strasz	int i, found, ever_found = 0;
144194955Strasz	char *str, *flag;
145194955Strasz
146194955Strasz	str = strdup(strp);
147194955Strasz	*try_compact = 0;
148194955Strasz	*var = 0;
149194955Strasz
150194955Strasz	while (str != NULL) {
151194955Strasz		flag = strsep(&str, "/:");
152194955Strasz
153194955Strasz		found = 0;
154194955Strasz		for (i = 0; flags[i].name != NULL; i++) {
155194955Strasz			if (strcmp(flags[i].name, flag) == 0) {
156194955Strasz				*var |= flags[i].flag;
157194955Strasz				found = 1;
158194955Strasz				ever_found = 1;
159194955Strasz			}
160194955Strasz		}
161194955Strasz
162194955Strasz		if (!found) {
163194955Strasz			if (ever_found)
164194955Strasz				warnx("malformed ACL: \"%s\" field contains "
165194955Strasz				    "invalid flag \"%s\"", flags_name, flag);
166194955Strasz			else
167194955Strasz				*try_compact = 1;
168194955Strasz			free(str);
169194955Strasz			return (-1);
170194955Strasz		}
171194955Strasz	}
172194955Strasz
173194955Strasz	free(str);
174194955Strasz	return (0);
175194955Strasz}
176194955Strasz
177194955Straszstatic int
178194955Straszparse_flags_compact(const char *str, uint32_t *var,
179194955Strasz    const struct flagnames_struct *flags, const char *flags_name)
180194955Strasz{
181194955Strasz	int i, j, found;
182194955Strasz
183194955Strasz	*var = 0;
184194955Strasz
185194955Strasz	for (i = 0;; i++) {
186194955Strasz		if (str[i] == '\0')
187194955Strasz			return (0);
188194955Strasz
189194955Strasz		/* Ignore minus signs. */
190194955Strasz		if (str[i] == '-')
191194955Strasz			continue;
192194955Strasz
193194955Strasz		found = 0;
194194955Strasz
195194955Strasz		for (j = 0; flags[j].name != NULL; j++) {
196194955Strasz			if (flags[j].letter == str[i]) {
197194955Strasz				*var |= flags[j].flag;
198194955Strasz				found = 1;
199194955Strasz				break;
200194955Strasz			}
201194955Strasz		}
202194955Strasz
203194955Strasz		if (!found) {
204194955Strasz			warnx("malformed ACL: \"%s\" field contains "
205194955Strasz			    "invalid flag \"%c\"", flags_name, str[i]);
206194955Strasz			return (-1);
207194955Strasz		}
208194955Strasz	}
209194955Strasz}
210194955Strasz
211194955Straszint
212194955Strasz_nfs4_format_flags(char *str, size_t size, acl_flag_t var, int verbose)
213194955Strasz{
214194955Strasz
215194955Strasz	if (verbose)
216194955Strasz		return (format_flags_verbose(str, size, var, a_flags));
217194955Strasz
218194955Strasz	return (format_flags_compact(str, size, var, a_flags));
219194955Strasz}
220194955Strasz
221194955Straszint
222194955Strasz_nfs4_format_access_mask(char *str, size_t size, acl_perm_t var, int verbose)
223194955Strasz{
224194955Strasz
225194955Strasz	if (verbose)
226194955Strasz		return (format_flags_verbose(str, size, var, a_access_masks));
227194955Strasz
228194955Strasz	return (format_flags_compact(str, size, var, a_access_masks));
229194955Strasz}
230194955Strasz
231194955Straszint
232194955Strasz_nfs4_parse_flags(const char *str, acl_flag_t *flags)
233194955Strasz{
234194955Strasz	int error, try_compact;
235194955Strasz	int tmpflags;
236194955Strasz
237194955Strasz	error = parse_flags_verbose(str, &tmpflags, a_flags, "flags", &try_compact);
238194955Strasz	if (error && try_compact)
239194955Strasz		error = parse_flags_compact(str, &tmpflags, a_flags, "flags");
240194955Strasz
241194955Strasz	*flags = tmpflags;
242194955Strasz
243194955Strasz	return (error);
244194955Strasz}
245194955Strasz
246194955Straszint
247194955Strasz_nfs4_parse_access_mask(const char *str, acl_perm_t *perms)
248194955Strasz{
249194955Strasz	int error, try_compact;
250194955Strasz	int tmpperms;
251194955Strasz
252194955Strasz	error = parse_flags_verbose(str, &tmpperms, a_access_masks,
253194955Strasz	    "access permissions", &try_compact);
254194955Strasz	if (error && try_compact)
255194955Strasz		error = parse_flags_compact(str, &tmpperms,
256194955Strasz		    a_access_masks, "access permissions");
257194955Strasz
258194955Strasz	*perms = tmpperms;
259194955Strasz
260194955Strasz	return (error);
261194955Strasz}
262