]> git.saurik.com Git - apple/libc.git/blame - posix1e/acl_translate.c
Libc-498.1.7.tar.gz
[apple/libc.git] / posix1e / acl_translate.c
CommitLineData
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
50ssize_t
51acl_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 */
86ssize_t
87acl_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
126acl_t
127acl_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 */
158acl_t
159acl_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
191static 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
216static 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
234static int
235raosnprintf(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
260static char *
261uuid_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:
281errout: ; //warn("Unable to translate qualifier on ACL\n");
282 }
283 }
224c7076 284 return NULL;
3d9156a7
A
285}
286
287acl_t
288acl_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 }
563exit:
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
574char *
575acl_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
678err_nomem:
679 if (buf != NULL)
680 free(buf);
681
682 errno = ENOMEM;
683 return NULL;
3d9156a7
A
684}
685
686ssize_t
687acl_size(acl_t acl)
688{
689 _ACL_VALIDATE_ACL(acl);
690
691 return(_ACL_HEADER_SIZE + acl->a_entries * _ACL_ENTRY_SIZE);
692}