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 <unistd.h>
33 #include <errno.h>
34 #include <assert.h>
35 #include <string.h>
36 #include <pwd.h>
37 #include <grp.h>
38 #include <sys/syscall.h>
39 #include <sys/types.h>
40 #include <sys/acl.h>
41
42 #include "acl_support.h"
43
44 #define MAX_ENTRY_LENGTH 512
45
46 static int
format_who(char * str,size_t size,const acl_entry_t entry,int numeric)47 format_who(char *str, size_t size, const acl_entry_t entry, int numeric)
48 {
49 int error;
50 acl_tag_t tag;
51 struct passwd *pwd;
52 struct group *grp;
53 uid_t *id;
54
55 error = acl_get_tag_type(entry, &tag);
56 if (error)
57 return (error);
58
59 switch (tag) {
60 case ACL_USER_OBJ:
61 snprintf(str, size, "owner@");
62 break;
63
64 case ACL_USER:
65 id = (uid_t *)acl_get_qualifier(entry);
66 if (id == NULL)
67 return (-1);
68 /* XXX: Thread-unsafe. */
69 if (!numeric)
70 pwd = getpwuid(*id);
71 else
72 pwd = NULL;
73 if (pwd == NULL)
74 snprintf(str, size, "user:%d", (unsigned int)*id);
75 else
76 snprintf(str, size, "user:%s", pwd->pw_name);
77 break;
78
79 case ACL_GROUP_OBJ:
80 snprintf(str, size, "group@");
81 break;
82
83 case ACL_GROUP:
84 id = (uid_t *)acl_get_qualifier(entry);
85 if (id == NULL)
86 return (-1);
87 /* XXX: Thread-unsafe. */
88 if (!numeric)
89 grp = getgrgid(*id);
90 else
91 grp = NULL;
92 if (grp == NULL)
93 snprintf(str, size, "group:%d", (unsigned int)*id);
94 else
95 snprintf(str, size, "group:%s", grp->gr_name);
96 break;
97
98 case ACL_EVERYONE:
99 snprintf(str, size, "everyone@");
100 break;
101
102 default:
103 return (-1);
104 }
105
106 return (0);
107 }
108
109 static int
format_entry_type(char * str,size_t size,const acl_entry_t entry)110 format_entry_type(char *str, size_t size, const acl_entry_t entry)
111 {
112 int error;
113 acl_entry_type_t entry_type;
114
115 error = acl_get_entry_type_np(entry, &entry_type);
116 if (error)
117 return (error);
118
119 switch (entry_type) {
120 case ACL_ENTRY_TYPE_ALLOW:
121 snprintf(str, size, "allow");
122 break;
123 case ACL_ENTRY_TYPE_DENY:
124 snprintf(str, size, "deny");
125 break;
126 case ACL_ENTRY_TYPE_AUDIT:
127 snprintf(str, size, "audit");
128 break;
129 case ACL_ENTRY_TYPE_ALARM:
130 snprintf(str, size, "alarm");
131 break;
132 default:
133 return (-1);
134 }
135
136 return (0);
137 }
138
139 static int
format_additional_id(char * str,size_t size,const acl_entry_t entry)140 format_additional_id(char *str, size_t size, const acl_entry_t entry)
141 {
142 int error;
143 acl_tag_t tag;
144 uid_t *id;
145
146 error = acl_get_tag_type(entry, &tag);
147 if (error)
148 return (error);
149
150 switch (tag) {
151 case ACL_USER_OBJ:
152 case ACL_GROUP_OBJ:
153 case ACL_EVERYONE:
154 str[0] = '\0';
155 break;
156
157 default:
158 id = (uid_t *)acl_get_qualifier(entry);
159 if (id == NULL)
160 return (-1);
161 snprintf(str, size, ":%d", (unsigned int)*id);
162 }
163
164 return (0);
165 }
166
167 static int
format_entry(char * str,size_t size,const acl_entry_t entry,int flags)168 format_entry(char *str, size_t size, const acl_entry_t entry, int flags)
169 {
170 size_t off = 0, min_who_field_length = 18;
171 acl_permset_t permset;
172 acl_flagset_t flagset;
173 int error, len;
174 char buf[MAX_ENTRY_LENGTH + 1];
175
176 assert(_entry_brand(entry) == ACL_BRAND_NFS4);
177
178 error = acl_get_flagset_np(entry, &flagset);
179 if (error)
180 return (error);
181
182 error = acl_get_permset(entry, &permset);
183 if (error)
184 return (error);
185
186 error = format_who(buf, sizeof(buf), entry,
187 flags & ACL_TEXT_NUMERIC_IDS);
188 if (error)
189 return (error);
190 len = strlen(buf);
191 if (len < min_who_field_length)
192 len = min_who_field_length;
193 off += snprintf(str + off, size - off, "%*s:", len, buf);
194
195 error = _nfs4_format_access_mask(buf, sizeof(buf), *permset,
196 flags & ACL_TEXT_VERBOSE);
197 if (error)
198 return (error);
199 off += snprintf(str + off, size - off, "%s:", buf);
200
201 error = _nfs4_format_flags(buf, sizeof(buf), *flagset,
202 flags & ACL_TEXT_VERBOSE);
203 if (error)
204 return (error);
205 off += snprintf(str + off, size - off, "%s:", buf);
206
207 error = format_entry_type(buf, sizeof(buf), entry);
208 if (error)
209 return (error);
210 off += snprintf(str + off, size - off, "%s", buf);
211
212 if (flags & ACL_TEXT_APPEND_ID) {
213 error = format_additional_id(buf, sizeof(buf), entry);
214 if (error)
215 return (error);
216 off += snprintf(str + off, size - off, "%s", buf);
217 }
218
219 off += snprintf(str + off, size - off, "\n");
220
221 /* Make sure we didn't truncate anything. */
222 assert (off < size);
223
224 return (0);
225 }
226
227 char *
_nfs4_acl_to_text_np(const acl_t aclp,ssize_t * len_p,int flags)228 _nfs4_acl_to_text_np(const acl_t aclp, ssize_t *len_p, int flags)
229 {
230 int error, off = 0, size, entry_id = ACL_FIRST_ENTRY;
231 char *str;
232 acl_entry_t entry;
233
234 if (aclp->ats_acl.acl_cnt == 0)
235 return strdup("");
236
237 size = aclp->ats_acl.acl_cnt * MAX_ENTRY_LENGTH;
238 str = malloc(size);
239 if (str == NULL)
240 return (NULL);
241
242 while (acl_get_entry(aclp, entry_id, &entry) == 1) {
243 entry_id = ACL_NEXT_ENTRY;
244
245 assert(off < size);
246
247 error = format_entry(str + off, size - off, entry, flags);
248 if (error) {
249 free(str);
250 errno = EINVAL;
251 return (NULL);
252 }
253
254 off = strlen(str);
255 }
256
257 assert(off < size);
258 str[off] = '\0';
259
260 if (len_p != NULL)
261 *len_p = off;
262
263 return (str);
264 }
265