]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - lib/libc/posix1e/acl_support_nfs4.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / lib / libc / posix1e / acl_support_nfs4.c
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 }