]>
Commit | Line | Data |
---|---|---|
3d9156a7 A |
1 | /* |
2 | * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | #include <sys/appleapiopts.h> | |
25 | #include <sys/types.h> | |
26 | #include <sys/acl.h> | |
27 | #include <errno.h> | |
28 | #include <stdio.h> | |
29 | #include <stdarg.h> | |
30 | #include <stdlib.h> | |
31 | #include <string.h> | |
32 | #include <membership.h> | |
224c7076 | 33 | #include <membershipPriv.h> |
3d9156a7 A |
34 | #include <pwd.h> |
35 | #include <grp.h> | |
36 | ||
eb1cde05 A |
37 | #include <libkern/OSByteOrder.h> |
38 | ||
3d9156a7 A |
39 | #include "aclvar.h" |
40 | ||
eb1cde05 A |
41 | /* |
42 | * NOTE: the copy_int/copy_ext functions are duplicated here, one version of each for | |
43 | * each of native and portable endianity. A more elegant solution might be called for | |
44 | * if the functions become much more complicated. | |
45 | */ | |
46 | ||
47 | /* | |
48 | * acl_t -> external representation, portable endianity | |
49 | */ | |
3d9156a7 A |
50 | ssize_t |
51 | acl_copy_ext(void *buf, acl_t acl, ssize_t size) | |
52 | { | |
53 | struct kauth_filesec *ext = (struct kauth_filesec *)buf; | |
54 | ssize_t reqsize; | |
55 | int i; | |
56 | ||
57 | /* validate arguments, compute required size */ | |
58 | reqsize = acl_size(acl); | |
59 | if (reqsize < 0) | |
60 | return(-1); | |
61 | if (reqsize > size) { | |
62 | errno = ERANGE; | |
63 | return(-1); | |
64 | } | |
65 | ||
eb1cde05 A |
66 | /* export the header */ |
67 | ext->fsec_magic = OSSwapHostToBigInt32(KAUTH_FILESEC_MAGIC); | |
68 | ext->fsec_entrycount = OSSwapHostToBigInt32(acl->a_entries); | |
69 | ext->fsec_flags = OSSwapHostToBigInt32(acl->a_flags); | |
70 | ||
71 | /* copy ACEs */ | |
72 | for (i = 0; i < acl->a_entries; i++) { | |
73 | /* ACE contents are almost identical */ | |
74 | ext->fsec_ace[i].ace_applicable = acl->a_ace[i].ae_applicable; | |
75 | ext->fsec_ace[i].ace_flags = | |
76 | OSSwapHostToBigInt32((acl->a_ace[i].ae_tag & KAUTH_ACE_KINDMASK) | (acl->a_ace[i].ae_flags & ~KAUTH_ACE_KINDMASK)); | |
77 | ext->fsec_ace[i].ace_rights = OSSwapHostToBigInt32(acl->a_ace[i].ae_perms); | |
78 | } | |
79 | ||
80 | return(reqsize); | |
81 | } | |
82 | ||
83 | /* | |
84 | * acl_t -> external representation, native system endianity | |
85 | */ | |
86 | ssize_t | |
87 | acl_copy_ext_native(void *buf, acl_t acl, ssize_t size) | |
88 | { | |
89 | struct kauth_filesec *ext = (struct kauth_filesec *)buf; | |
90 | ssize_t reqsize; | |
91 | int i; | |
92 | ||
93 | /* validate arguments, compute required size */ | |
94 | reqsize = acl_size(acl); | |
95 | if (reqsize < 0) | |
96 | return(-1); | |
97 | if (reqsize > size) { | |
98 | errno = ERANGE; | |
99 | return(-1); | |
100 | } | |
101 | ||
3d9156a7 A |
102 | /* export the header */ |
103 | ext->fsec_magic = KAUTH_FILESEC_MAGIC; | |
104 | ext->fsec_entrycount = acl->a_entries; | |
105 | ext->fsec_flags = acl->a_flags; | |
106 | /* XXX owner? */ | |
107 | ||
108 | /* copy ACEs */ | |
109 | for (i = 0; i < acl->a_entries; i++) { | |
110 | /* ACE contents are almost identical */ | |
111 | ext->fsec_ace[i].ace_applicable = acl->a_ace[i].ae_applicable; | |
112 | ext->fsec_ace[i].ace_flags = | |
113 | (acl->a_ace[i].ae_tag & KAUTH_ACE_KINDMASK) | | |
114 | (acl->a_ace[i].ae_flags & ~KAUTH_ACE_KINDMASK); | |
115 | ext->fsec_ace[i].ace_rights = acl->a_ace[i].ae_perms; | |
116 | } | |
117 | ||
118 | return(reqsize); | |
119 | } | |
120 | ||
eb1cde05 A |
121 | /* |
122 | * external representation, portable system endianity -> acl_t | |
123 | * | |
124 | * Unlike acl_copy_ext, we can't mung the buffer as it doesn't belong to us. | |
125 | */ | |
3d9156a7 A |
126 | acl_t |
127 | acl_copy_int(const void *buf) | |
128 | { | |
129 | struct kauth_filesec *ext = (struct kauth_filesec *)buf; | |
130 | acl_t ap; | |
131 | int i; | |
132 | ||
eb1cde05 A |
133 | if (ext->fsec_magic != OSSwapHostToBigInt32(KAUTH_FILESEC_MAGIC)) { |
134 | errno = EINVAL; | |
135 | return(NULL); | |
136 | } | |
137 | ||
138 | if ((ap = acl_init(OSSwapBigToHostInt32(ext->fsec_entrycount))) != NULL) { | |
139 | /* copy useful header fields */ | |
140 | ap->a_flags = OSSwapBigToHostInt32(ext->fsec_flags); | |
141 | ap->a_entries = OSSwapBigToHostInt32(ext->fsec_entrycount); | |
142 | /* copy ACEs */ | |
143 | for (i = 0; i < ap->a_entries; i++) { | |
144 | /* ACE contents are literally identical */ | |
145 | ap->a_ace[i].ae_magic = _ACL_ENTRY_MAGIC; | |
146 | ap->a_ace[i].ae_applicable = ext->fsec_ace[i].ace_applicable; | |
147 | ap->a_ace[i].ae_flags = OSSwapBigToHostInt32(ext->fsec_ace[i].ace_flags) & ~KAUTH_ACE_KINDMASK; | |
148 | ap->a_ace[i].ae_tag = OSSwapBigToHostInt32(ext->fsec_ace[i].ace_flags) & KAUTH_ACE_KINDMASK; | |
149 | ap->a_ace[i].ae_perms = OSSwapBigToHostInt32(ext->fsec_ace[i].ace_rights); | |
150 | } | |
151 | } | |
152 | return(ap); | |
153 | } | |
154 | ||
155 | /* | |
156 | * external representation, native system endianity -> acl_t | |
157 | */ | |
158 | acl_t | |
159 | acl_copy_int_native(const void *buf) | |
160 | { | |
161 | struct kauth_filesec *ext = (struct kauth_filesec *)buf; | |
162 | acl_t ap; | |
163 | int i; | |
164 | ||
3d9156a7 A |
165 | if (ext->fsec_magic != KAUTH_FILESEC_MAGIC) { |
166 | errno = EINVAL; | |
167 | return(NULL); | |
168 | } | |
169 | ||
170 | if ((ap = acl_init(ext->fsec_entrycount)) != NULL) { | |
171 | /* copy useful header fields */ | |
172 | ap->a_flags = ext->fsec_flags; | |
173 | ap->a_entries = ext->fsec_entrycount; | |
174 | /* copy ACEs */ | |
175 | for (i = 0; i < ap->a_entries; i++) { | |
176 | /* ACE contents are literally identical */ | |
3d9156a7 A |
177 | ap->a_ace[i].ae_magic = _ACL_ENTRY_MAGIC; |
178 | ap->a_ace[i].ae_applicable = ext->fsec_ace[i].ace_applicable; | |
179 | ap->a_ace[i].ae_flags = ext->fsec_ace[i].ace_flags & ~KAUTH_ACE_KINDMASK; | |
180 | ap->a_ace[i].ae_tag = ext->fsec_ace[i].ace_flags & KAUTH_ACE_KINDMASK; | |
181 | ap->a_ace[i].ae_perms = ext->fsec_ace[i].ace_rights; | |
182 | } | |
183 | } | |
184 | return(ap); | |
185 | } | |
186 | ||
187 | #define ACL_TYPE_DIR (1<<0) | |
188 | #define ACL_TYPE_FILE (1<<1) | |
189 | #define ACL_TYPE_ACL (1<<2) | |
190 | ||
191 | static struct { | |
192 | acl_perm_t perm; | |
193 | char *name; | |
194 | int type; | |
195 | } acl_perms[] = { | |
196 | {ACL_READ_DATA, "read", ACL_TYPE_FILE}, | |
197 | // {ACL_LIST_DIRECTORY, "list", ACL_TYPE_DIR}, | |
198 | {ACL_WRITE_DATA, "write", ACL_TYPE_FILE}, | |
199 | // {ACL_ADD_FILE, "add_file", ACL_TYPE_DIR}, | |
200 | {ACL_EXECUTE, "execute", ACL_TYPE_FILE}, | |
201 | // {ACL_SEARCH, "search", ACL_TYPE_DIR}, | |
202 | {ACL_DELETE, "delete", ACL_TYPE_FILE | ACL_TYPE_DIR}, | |
203 | {ACL_APPEND_DATA, "append", ACL_TYPE_FILE}, | |
204 | // {ACL_ADD_SUBDIRECTORY, "add_subdirectory", ACL_TYPE_DIR}, | |
205 | {ACL_DELETE_CHILD, "delete_child", ACL_TYPE_DIR}, | |
206 | {ACL_READ_ATTRIBUTES, "readattr", ACL_TYPE_FILE | ACL_TYPE_DIR}, | |
207 | {ACL_WRITE_ATTRIBUTES, "writeattr", ACL_TYPE_FILE | ACL_TYPE_DIR}, | |
208 | {ACL_READ_EXTATTRIBUTES, "readextattr", ACL_TYPE_FILE | ACL_TYPE_DIR}, | |
209 | {ACL_WRITE_EXTATTRIBUTES, "writeextattr", ACL_TYPE_FILE | ACL_TYPE_DIR}, | |
210 | {ACL_READ_SECURITY, "readsecurity", ACL_TYPE_FILE | ACL_TYPE_DIR}, | |
211 | {ACL_WRITE_SECURITY, "writesecurity", ACL_TYPE_FILE | ACL_TYPE_DIR}, | |
212 | {ACL_CHANGE_OWNER, "chown", ACL_TYPE_FILE | ACL_TYPE_DIR}, | |
213 | {0, NULL, 0} | |
214 | }; | |
215 | ||
216 | static struct { | |
217 | acl_flag_t flag; | |
218 | char *name; | |
219 | int type; | |
220 | } acl_flags[] = { | |
7c78c529 | 221 | {ACL_ENTRY_INHERITED, "inherited", ACL_TYPE_FILE | ACL_TYPE_DIR}, |
3d9156a7 A |
222 | {ACL_FLAG_DEFER_INHERIT, "defer_inherit", ACL_TYPE_ACL}, |
223 | {ACL_ENTRY_FILE_INHERIT, "file_inherit", ACL_TYPE_DIR}, | |
224 | {ACL_ENTRY_DIRECTORY_INHERIT, "directory_inherit", ACL_TYPE_DIR}, | |
225 | {ACL_ENTRY_LIMIT_INHERIT, "limit_inherit", ACL_TYPE_FILE | ACL_TYPE_DIR}, | |
226 | {ACL_ENTRY_ONLY_INHERIT, "only_inherit", ACL_TYPE_DIR}, | |
227 | {0, NULL, 0} | |
228 | }; | |
229 | ||
230 | /* | |
231 | * reallocing snprintf with offset | |
232 | */ | |
233 | ||
234 | static int | |
235 | raosnprintf(char **buf, size_t *size, ssize_t *offset, char *fmt, ...) | |
236 | { | |
237 | va_list ap; | |
238 | int ret; | |
239 | ||
240 | do | |
241 | { | |
242 | if (*offset < *size) | |
243 | { | |
244 | va_start(ap, fmt); | |
245 | ret = vsnprintf(*buf + *offset, *size - *offset, fmt, ap); | |
246 | va_end(ap); | |
7c78c529 | 247 | if (ret < (*size - *offset)) |
3d9156a7 A |
248 | { |
249 | *offset += ret; | |
250 | return ret; | |
251 | } | |
252 | } | |
7c78c529 | 253 | *buf = reallocf(*buf, (*size *= 2)); |
3d9156a7 A |
254 | } while (*buf); |
255 | ||
7c78c529 | 256 | //warn("reallocf failure"); |
3d9156a7 A |
257 | return 0; |
258 | } | |
259 | ||
260 | static char * | |
261 | uuid_to_name(uuid_t *uu, uid_t *id, int *isgid) | |
262 | { | |
263 | struct group *tgrp = NULL; | |
264 | struct passwd *tpass = NULL; | |
265 | ||
266 | if (0 == mbr_uuid_to_id(*uu, id, isgid)) | |
267 | { | |
268 | switch (*isgid) | |
269 | { | |
270 | case ID_TYPE_UID: | |
271 | if (!(tpass = getpwuid(*id))) | |
272 | goto errout; | |
273 | return strdup(tpass->pw_name); | |
274 | break; | |
275 | case ID_TYPE_GID: | |
276 | if (!(tgrp = getgrgid((gid_t) *id))) | |
277 | goto errout; | |
278 | return strdup(tgrp->gr_name); | |
279 | break; | |
280 | default: | |
281 | errout: ; //warn("Unable to translate qualifier on ACL\n"); | |
282 | } | |
283 | } | |
224c7076 | 284 | return NULL; |
3d9156a7 A |
285 | } |
286 | ||
287 | acl_t | |
288 | acl_from_text(const char *buf_p) | |
289 | { | |
224c7076 A |
290 | int i, error = 0, need_tag, ug_tag; |
291 | char *buf, *orig_buf; | |
292 | char *entry, *field, *sub; | |
3d9156a7 A |
293 | uuid_t *uu; |
294 | struct passwd *tpass = NULL; | |
295 | struct group *tgrp = NULL; | |
296 | acl_entry_t acl_entry; | |
297 | acl_flagset_t flags = NULL; | |
298 | acl_permset_t perms = NULL; | |
299 | acl_tag_t tag; | |
300 | acl_t acl_ret; | |
301 | ||
3d9156a7 | 302 | if (buf_p == NULL) |
224c7076 A |
303 | { |
304 | errno = EINVAL; | |
3d9156a7 | 305 | return NULL; |
224c7076 | 306 | } |
3d9156a7 A |
307 | |
308 | if ((buf = strdup(buf_p)) == NULL) | |
309 | return NULL; | |
310 | ||
224c7076 A |
311 | if ((acl_ret = acl_init(1)) == NULL) |
312 | return NULL; | |
313 | ||
314 | orig_buf = buf; | |
315 | ||
316 | /* global acl flags | |
317 | * format: !#acl <version> [<flags>] | |
318 | */ | |
319 | if ((entry = strsep(&buf, "\n")) != NULL && *entry) | |
3d9156a7 | 320 | { |
224c7076 A |
321 | /* field 1: !#acl */ |
322 | field = strsep(&entry, " "); | |
323 | if (*field && strncmp(field, "!#acl", strlen("!#acl"))) | |
3d9156a7 A |
324 | { |
325 | error = EINVAL; | |
326 | goto exit; | |
327 | } | |
328 | ||
224c7076 A |
329 | /* field 2: <version> |
330 | * currently only accepts 1 | |
331 | */ | |
332 | field = strsep(&entry, " "); | |
3d9156a7 | 333 | errno = 0; |
224c7076 | 334 | if (!*field || strtol(field, NULL, 0) != 1) |
3d9156a7 A |
335 | { |
336 | error = EINVAL; | |
337 | goto exit; | |
338 | } | |
339 | ||
224c7076 A |
340 | /* field 3: <flags> |
341 | * optional | |
342 | */ | |
343 | if((field = strsep(&entry, " ")) != NULL && *field) | |
3d9156a7 A |
344 | { |
345 | acl_get_flagset_np(acl_ret, &flags); | |
224c7076 | 346 | while ((sub = strsep(&field, ",")) && *sub) |
3d9156a7 A |
347 | { |
348 | for (i = 0; acl_flags[i].name != NULL; ++i) | |
349 | { | |
350 | if (acl_flags[i].type & ACL_TYPE_ACL | |
351 | && !strcmp(acl_flags[i].name, sub)) | |
352 | { | |
353 | acl_add_flag_np(flags, acl_flags[i].flag); | |
354 | break; | |
355 | } | |
356 | } | |
357 | if (acl_flags[i].name == NULL) | |
358 | { | |
359 | /* couldn't find flag */ | |
360 | error = EINVAL; | |
361 | goto exit; | |
362 | } | |
363 | } | |
364 | } | |
224c7076 A |
365 | } else { |
366 | error = EINVAL; | |
367 | goto exit; | |
3d9156a7 A |
368 | } |
369 | ||
224c7076 A |
370 | /* parse each acl line |
371 | * format: <user|group>: | |
372 | * [<uuid>]: | |
373 | * [<user|group>]: | |
374 | * [<uid|gid>]: | |
375 | * <allow|deny>[,<flags>] | |
376 | * [:<permissions>[,<permissions>]] | |
377 | * | |
378 | * only one of the user/group identifies is required | |
379 | * the first one found is used | |
380 | */ | |
381 | while ((entry = strsep(&buf, "\n")) && *entry) | |
3d9156a7 | 382 | { |
224c7076 A |
383 | need_tag = 1; |
384 | ug_tag = -1; | |
385 | ||
386 | /* field 1: <user|group> */ | |
387 | field = strsep(&entry, ":"); | |
3d9156a7 A |
388 | |
389 | if((uu = calloc(1, sizeof(uuid_t))) == NULL) | |
224c7076 A |
390 | { |
391 | error = errno; | |
3d9156a7 | 392 | goto exit; |
224c7076 | 393 | } |
3d9156a7 A |
394 | |
395 | if(acl_create_entry(&acl_ret, &acl_entry)) | |
224c7076 A |
396 | { |
397 | error = errno; | |
3d9156a7 | 398 | goto exit; |
224c7076 | 399 | } |
3d9156a7 | 400 | |
224c7076 A |
401 | if (-1 == acl_get_flagset_np(acl_entry, &flags) |
402 | || -1 == acl_get_permset(acl_entry, &perms)) | |
403 | { | |
404 | error = errno; | |
405 | goto exit; | |
406 | } | |
3d9156a7 A |
407 | |
408 | switch(*field) | |
409 | { | |
410 | case 'u': | |
224c7076 | 411 | if(!strcmp(field, "user")) |
3d9156a7 A |
412 | ug_tag = ID_TYPE_UID; |
413 | break; | |
414 | case 'g': | |
224c7076 | 415 | if(!strcmp(field, "group")) |
3d9156a7 A |
416 | ug_tag = ID_TYPE_GID; |
417 | break; | |
224c7076 A |
418 | default: |
419 | error = EINVAL; | |
420 | goto exit; | |
3d9156a7 A |
421 | } |
422 | ||
224c7076 A |
423 | /* field 2: <uuid> */ |
424 | if ((field = strsep(&entry, ":")) != NULL && *field) | |
3d9156a7 A |
425 | { |
426 | mbr_string_to_uuid(field, *uu); | |
427 | need_tag = 0; | |
428 | } | |
224c7076 A |
429 | |
430 | /* field 3: <username|groupname> */ | |
431 | if ((field = strsep(&entry, ":")) != NULL && *field && need_tag) | |
3d9156a7 A |
432 | { |
433 | switch(ug_tag) | |
434 | { | |
435 | case ID_TYPE_UID: | |
436 | if((tpass = getpwnam(field)) != NULL) | |
437 | if (mbr_uid_to_uuid(tpass->pw_uid, *uu) != 0) | |
438 | { | |
439 | error = EINVAL; | |
440 | goto exit; | |
441 | } | |
442 | break; | |
443 | case ID_TYPE_GID: | |
444 | if ((tgrp = getgrnam(field)) != NULL) | |
445 | if (mbr_gid_to_uuid(tgrp->gr_gid, *uu) != 0) | |
446 | { | |
447 | error = EINVAL; | |
448 | goto exit; | |
449 | } | |
450 | break; | |
224c7076 A |
451 | default: |
452 | error = EINVAL; | |
453 | goto exit; | |
3d9156a7 A |
454 | } |
455 | need_tag = 0; | |
456 | } | |
224c7076 A |
457 | |
458 | /* field 4: <uid|gid> */ | |
459 | if ((field = strsep(&entry, ":")) != NULL && *field && need_tag) | |
3d9156a7 A |
460 | { |
461 | uid_t id; | |
462 | error = 0; | |
463 | ||
464 | if((id = strtol(field, NULL, 10)) == 0 && error) | |
465 | { | |
466 | error = EINVAL; | |
467 | goto exit; | |
468 | } | |
469 | ||
470 | switch(ug_tag) | |
471 | { | |
472 | case ID_TYPE_UID: | |
473 | if((tpass = getpwuid((uid_t)id)) != NULL) | |
474 | if (mbr_uid_to_uuid(tpass->pw_uid, *uu) != 0) | |
475 | { | |
476 | error = EINVAL; | |
477 | goto exit; | |
478 | } | |
479 | break; | |
480 | case ID_TYPE_GID: | |
481 | if ((tgrp = getgrgid((gid_t)id)) != NULL) | |
482 | if (mbr_gid_to_uuid(tgrp->gr_gid, *uu) != 0) | |
483 | { | |
484 | error = EINVAL; | |
485 | goto exit; | |
486 | } | |
487 | break; | |
488 | } | |
489 | need_tag = 0; | |
490 | } | |
491 | ||
224c7076 | 492 | /* sanity check: nothing set as qualifier */ |
3d9156a7 A |
493 | if (need_tag) |
494 | { | |
495 | error = EINVAL; | |
496 | goto exit; | |
497 | } | |
498 | ||
224c7076 A |
499 | /* field 5: <flags> */ |
500 | if((field = strsep(&entry, ":")) == NULL || !*field) | |
3d9156a7 A |
501 | { |
502 | error = EINVAL; | |
503 | goto exit; | |
504 | } | |
505 | ||
224c7076 | 506 | for (tag = 0; (sub = strsep(&field, ",")) && *sub;) |
3d9156a7 | 507 | { |
224c7076 A |
508 | if (!tag) |
509 | { | |
510 | if (!strcmp(sub, "allow")) | |
3d9156a7 | 511 | tag = ACL_EXTENDED_ALLOW; |
224c7076 | 512 | else if (!strcmp(sub, "deny")) |
3d9156a7 | 513 | tag = ACL_EXTENDED_DENY; |
224c7076 A |
514 | else { |
515 | error = EINVAL; | |
516 | goto exit; | |
517 | } | |
518 | continue; | |
3d9156a7 | 519 | } |
224c7076 | 520 | |
3d9156a7 A |
521 | for (i = 0; acl_flags[i].name != NULL; ++i) |
522 | { | |
523 | if (acl_flags[i].type & (ACL_TYPE_FILE | ACL_TYPE_DIR) | |
524 | && !strcmp(acl_flags[i].name, sub)) | |
525 | { | |
526 | acl_add_flag_np(flags, acl_flags[i].flag); | |
527 | break; | |
528 | } | |
529 | } | |
530 | if (acl_flags[i].name == NULL) | |
531 | { | |
532 | /* couldn't find perm */ | |
533 | error = EINVAL; | |
534 | goto exit; | |
535 | } | |
536 | } | |
537 | ||
224c7076 A |
538 | /* field 6: <perms> (can be empty) */ |
539 | if((field = strsep(&entry, ":")) != NULL && *field) | |
540 | { | |
541 | while ((sub = strsep(&field, ",")) && *sub) | |
3d9156a7 | 542 | { |
7c78c529 | 543 | for (i = 0; acl_perms[i].name != NULL; i++) |
3d9156a7 | 544 | { |
7c78c529 A |
545 | if (acl_perms[i].type & (ACL_TYPE_FILE | ACL_TYPE_DIR) |
546 | && !strcmp(acl_perms[i].name, sub)) | |
547 | { | |
548 | acl_add_perm(perms, acl_perms[i].perm); | |
549 | break; | |
550 | } | |
551 | } | |
552 | if (acl_perms[i].name == NULL) | |
553 | { | |
554 | /* couldn't find perm */ | |
555 | error = EINVAL; | |
556 | goto exit; | |
3d9156a7 | 557 | } |
3d9156a7 A |
558 | } |
559 | } | |
560 | acl_set_tag_type(acl_entry, tag); | |
561 | acl_set_qualifier(acl_entry, *uu); | |
562 | } | |
563 | exit: | |
224c7076 | 564 | free(orig_buf); |
3d9156a7 A |
565 | if (error) |
566 | { | |
567 | acl_free(acl_ret); | |
568 | acl_ret = NULL; | |
569 | errno = error; | |
570 | } | |
571 | return acl_ret; | |
572 | } | |
573 | ||
574 | char * | |
575 | acl_to_text(acl_t acl, ssize_t *len_p) | |
576 | { | |
3d9156a7 A |
577 | acl_tag_t tag; |
578 | acl_entry_t entry = NULL; | |
579 | acl_flagset_t flags; | |
580 | acl_permset_t perms; | |
581 | uid_t id; | |
3d9156a7 A |
582 | int i, first; |
583 | int isgid; | |
3d9156a7 | 584 | size_t bufsize = 1024; |
224c7076 | 585 | char *buf = NULL; |
7c78c529 A |
586 | |
587 | if (!_ACL_VALID_ACL(acl)) { | |
588 | errno = EINVAL; | |
589 | return NULL; | |
590 | } | |
3d9156a7 A |
591 | |
592 | if (len_p == NULL) | |
224c7076 A |
593 | if ((len_p = alloca(sizeof(ssize_t))) == NULL) |
594 | goto err_nomem; | |
3d9156a7 A |
595 | |
596 | *len_p = 0; | |
597 | ||
224c7076 A |
598 | if ((buf = malloc(bufsize)) == NULL) |
599 | goto err_nomem; | |
600 | ||
7c78c529 | 601 | if (!raosnprintf(&buf, &bufsize, len_p, "!#acl %d", 1)) |
224c7076 | 602 | goto err_nomem; |
3d9156a7 A |
603 | |
604 | if (acl_get_flagset_np(acl, &flags) == 0) | |
605 | { | |
606 | for (i = 0, first = 0; acl_flags[i].name != NULL; ++i) | |
607 | { | |
608 | if (acl_flags[i].type & ACL_TYPE_ACL | |
609 | && acl_get_flag_np(flags, acl_flags[i].flag) != 0) | |
610 | { | |
611 | if(!raosnprintf(&buf, &bufsize, len_p, "%s%s", | |
612 | first++ ? "," : " ", acl_flags[i].name)) | |
224c7076 | 613 | goto err_nomem; |
3d9156a7 A |
614 | } |
615 | } | |
616 | } | |
617 | for (;acl_get_entry(acl, | |
618 | entry == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY, &entry) == 0;) | |
619 | { | |
224c7076 A |
620 | int valid; |
621 | uuid_t *uu; | |
622 | char *str, uu_str[37]; | |
623 | ||
3d9156a7 A |
624 | if (((uu = (uuid_t *) acl_get_qualifier(entry)) == NULL) |
625 | || (acl_get_tag_type(entry, &tag) != 0) | |
626 | || (acl_get_flagset_np(entry, &flags) != 0) | |
224c7076 A |
627 | || (acl_get_permset(entry, &perms) != 0) |
628 | || ((str = uuid_to_name(uu, &id, &isgid)) == NULL)) { | |
629 | if (uu != NULL) acl_free(uu); | |
3d9156a7 | 630 | continue; |
224c7076 | 631 | } |
3d9156a7 | 632 | |
224c7076 | 633 | uuid_unparse_upper(*uu, uu_str); |
3d9156a7 | 634 | |
224c7076 | 635 | valid = raosnprintf(&buf, &bufsize, len_p, "\n%s:%s:%s:%d:%s", |
3d9156a7 A |
636 | isgid ? "group" : "user", |
637 | uu_str, | |
638 | str, | |
639 | id, | |
224c7076 | 640 | (tag == ACL_EXTENDED_ALLOW) ? "allow" : "deny"); |
3d9156a7 A |
641 | |
642 | free(str); | |
224c7076 A |
643 | acl_free(uu); |
644 | ||
645 | if (!valid) | |
646 | goto err_nomem; | |
3d9156a7 A |
647 | |
648 | for (i = 0; acl_flags[i].name != NULL; ++i) | |
649 | { | |
650 | if (acl_flags[i].type & (ACL_TYPE_DIR | ACL_TYPE_FILE)) | |
651 | { | |
652 | if(acl_get_flag_np(flags, acl_flags[i].flag) != 0) | |
653 | { | |
654 | if(!raosnprintf(&buf, &bufsize, len_p, ",%s", | |
655 | acl_flags[i].name)) | |
224c7076 | 656 | goto err_nomem; |
3d9156a7 A |
657 | } |
658 | } | |
659 | } | |
660 | ||
661 | for (i = 0, first = 0; acl_perms[i].name != NULL; ++i) | |
662 | { | |
663 | if (acl_perms[i].type & (ACL_TYPE_DIR | ACL_TYPE_FILE)) | |
664 | { | |
665 | if(acl_get_perm_np(perms, acl_perms[i].perm) != 0) | |
666 | { | |
667 | if(!raosnprintf(&buf, &bufsize, len_p, "%s%s", | |
224c7076 A |
668 | first++ ? "," : ":", acl_perms[i].name)) |
669 | goto err_nomem; | |
3d9156a7 A |
670 | } |
671 | } | |
672 | } | |
673 | } | |
674 | buf[(*len_p)++] = '\n'; | |
7c78c529 | 675 | buf[(*len_p)] = 0; |
3d9156a7 | 676 | return buf; |
224c7076 A |
677 | |
678 | err_nomem: | |
679 | if (buf != NULL) | |
680 | free(buf); | |
681 | ||
682 | errno = ENOMEM; | |
683 | return NULL; | |
3d9156a7 A |
684 | } |
685 | ||
686 | ssize_t | |
687 | acl_size(acl_t acl) | |
688 | { | |
689 | _ACL_VALIDATE_ACL(acl); | |
690 | ||
691 | return(_ACL_HEADER_SIZE + acl->a_entries * _ACL_ENTRY_SIZE); | |
692 | } |