2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 #include <sys/appleapiopts.h>
25 #include <sys/types.h>
32 #include <membership.h>
39 acl_copy_ext(void *buf
, acl_t acl
, ssize_t size
)
41 struct kauth_filesec
*ext
= (struct kauth_filesec
*)buf
;
45 /* validate arguments, compute required size */
46 reqsize
= acl_size(acl
);
54 /* export the header */
55 ext
->fsec_magic
= KAUTH_FILESEC_MAGIC
;
56 ext
->fsec_entrycount
= acl
->a_entries
;
57 ext
->fsec_flags
= acl
->a_flags
;
61 for (i
= 0; i
< acl
->a_entries
; i
++) {
62 /* ACE contents are almost identical */
63 ext
->fsec_ace
[i
].ace_applicable
= acl
->a_ace
[i
].ae_applicable
;
64 ext
->fsec_ace
[i
].ace_flags
=
65 (acl
->a_ace
[i
].ae_tag
& KAUTH_ACE_KINDMASK
) |
66 (acl
->a_ace
[i
].ae_flags
& ~KAUTH_ACE_KINDMASK
);
67 ext
->fsec_ace
[i
].ace_rights
= acl
->a_ace
[i
].ae_perms
;
74 acl_copy_int(const void *buf
)
76 struct kauth_filesec
*ext
= (struct kauth_filesec
*)buf
;
80 if (ext
->fsec_magic
!= KAUTH_FILESEC_MAGIC
) {
85 if ((ap
= acl_init(ext
->fsec_entrycount
)) != NULL
) {
86 /* copy useful header fields */
87 ap
->a_flags
= ext
->fsec_flags
;
88 ap
->a_entries
= ext
->fsec_entrycount
;
90 for (i
= 0; i
< ap
->a_entries
; i
++) {
91 /* ACE contents are literally identical */
92 /* XXX Consider writing the magic out to the persistent store
93 * to detect corruption
95 ap
->a_ace
[i
].ae_magic
= _ACL_ENTRY_MAGIC
;
96 ap
->a_ace
[i
].ae_applicable
= ext
->fsec_ace
[i
].ace_applicable
;
97 ap
->a_ace
[i
].ae_flags
= ext
->fsec_ace
[i
].ace_flags
& ~KAUTH_ACE_KINDMASK
;
98 ap
->a_ace
[i
].ae_tag
= ext
->fsec_ace
[i
].ace_flags
& KAUTH_ACE_KINDMASK
;
99 ap
->a_ace
[i
].ae_perms
= ext
->fsec_ace
[i
].ace_rights
;
105 #define ACL_TYPE_DIR (1<<0)
106 #define ACL_TYPE_FILE (1<<1)
107 #define ACL_TYPE_ACL (1<<2)
114 {ACL_READ_DATA
, "read", ACL_TYPE_FILE
},
115 // {ACL_LIST_DIRECTORY, "list", ACL_TYPE_DIR},
116 {ACL_WRITE_DATA
, "write", ACL_TYPE_FILE
},
117 // {ACL_ADD_FILE, "add_file", ACL_TYPE_DIR},
118 {ACL_EXECUTE
, "execute", ACL_TYPE_FILE
},
119 // {ACL_SEARCH, "search", ACL_TYPE_DIR},
120 {ACL_DELETE
, "delete", ACL_TYPE_FILE
| ACL_TYPE_DIR
},
121 {ACL_APPEND_DATA
, "append", ACL_TYPE_FILE
},
122 // {ACL_ADD_SUBDIRECTORY, "add_subdirectory", ACL_TYPE_DIR},
123 {ACL_DELETE_CHILD
, "delete_child", ACL_TYPE_DIR
},
124 {ACL_READ_ATTRIBUTES
, "readattr", ACL_TYPE_FILE
| ACL_TYPE_DIR
},
125 {ACL_WRITE_ATTRIBUTES
, "writeattr", ACL_TYPE_FILE
| ACL_TYPE_DIR
},
126 {ACL_READ_EXTATTRIBUTES
, "readextattr", ACL_TYPE_FILE
| ACL_TYPE_DIR
},
127 {ACL_WRITE_EXTATTRIBUTES
, "writeextattr", ACL_TYPE_FILE
| ACL_TYPE_DIR
},
128 {ACL_READ_SECURITY
, "readsecurity", ACL_TYPE_FILE
| ACL_TYPE_DIR
},
129 {ACL_WRITE_SECURITY
, "writesecurity", ACL_TYPE_FILE
| ACL_TYPE_DIR
},
130 {ACL_CHANGE_OWNER
, "chown", ACL_TYPE_FILE
| ACL_TYPE_DIR
},
139 {ACL_ENTRY_INHERITED
, "inherited", ACL_TYPE_FILE
| ACL_TYPE_DIR
},
140 {ACL_FLAG_DEFER_INHERIT
, "defer_inherit", ACL_TYPE_ACL
},
141 {ACL_ENTRY_FILE_INHERIT
, "file_inherit", ACL_TYPE_DIR
},
142 {ACL_ENTRY_DIRECTORY_INHERIT
, "directory_inherit", ACL_TYPE_DIR
},
143 {ACL_ENTRY_LIMIT_INHERIT
, "limit_inherit", ACL_TYPE_FILE
| ACL_TYPE_DIR
},
144 {ACL_ENTRY_ONLY_INHERIT
, "only_inherit", ACL_TYPE_DIR
},
149 * reallocing snprintf with offset
153 raosnprintf(char **buf
, size_t *size
, ssize_t
*offset
, char *fmt
, ...)
163 ret
= vsnprintf(*buf
+ *offset
, *size
- *offset
, fmt
, ap
);
165 if (ret
< (*size
- *offset
))
171 *buf
= reallocf(*buf
, (*size
*= 2));
174 //warn("reallocf failure");
179 uuid_to_name(uuid_t
*uu
, uid_t
*id
, int *isgid
)
181 struct group
*tgrp
= NULL
;
182 struct passwd
*tpass
= NULL
;
184 if (0 == mbr_uuid_to_id(*uu
, id
, isgid
))
189 if (!(tpass
= getpwuid(*id
)))
191 return strdup(tpass
->pw_name
);
194 if (!(tgrp
= getgrgid((gid_t
) *id
)))
196 return strdup(tgrp
->gr_name
);
199 errout
: ; //warn("Unable to translate qualifier on ACL\n");
206 acl_from_text(const char *buf_p
)
208 int i
, error
= 0, need_tag
= 1, ug_tag
= -1;
210 char *entry
, *field
, *sub
,
211 *last_field
, *last_entry
, *last_sub
;
213 struct passwd
*tpass
= NULL
;
214 struct group
*tgrp
= NULL
;
215 acl_entry_t acl_entry
;
216 acl_flagset_t flags
= NULL
;
217 acl_permset_t perms
= NULL
;
221 if ((acl_ret
= acl_init(1)) == NULL
)
227 if ((buf
= strdup(buf_p
)) == NULL
)
231 if ((entry
= strtok_r(buf
, "\n", &last_entry
)) != NULL
)
234 field
= strtok_r(entry
, " ", &last_field
);
235 if (field
&& strncmp(field
, "!#acl", strlen("!#acl")))
242 field
= strtok_r(NULL
, " ", &last_field
);
244 if (field
== NULL
|| strtol(field
, NULL
, 0) != 1)
251 if((field
= strtok_r(NULL
, " ", &last_field
)) != NULL
)
253 acl_get_flagset_np(acl_ret
, &flags
);
254 for (sub
= strtok_r(field
, ",", &last_sub
); sub
;
255 sub
= strtok_r(NULL
, ",", &last_sub
))
257 for (i
= 0; acl_flags
[i
].name
!= NULL
; ++i
)
259 if (acl_flags
[i
].type
& ACL_TYPE_ACL
260 && !strcmp(acl_flags
[i
].name
, sub
))
262 acl_add_flag_np(flags
, acl_flags
[i
].flag
);
266 if (acl_flags
[i
].name
== NULL
)
268 /* couldn't find flag */
276 for (entry
= strtok_r(NULL
, "\n", &last_entry
); entry
;
277 entry
= strtok_r(NULL
, "\n", &last_entry
))
279 field
= strtok_r(entry
, ":", &last_field
);
281 if((uu
= calloc(1, sizeof(uuid_t
))) == NULL
)
284 if(acl_create_entry(&acl_ret
, &acl_entry
))
287 acl_get_flagset_np(acl_entry
, &flags
);
288 acl_get_permset(acl_entry
, &perms
);
293 if(!strncmp(buf
, "user", strlen(field
)))
294 ug_tag
= ID_TYPE_UID
;
297 if(!strncmp(buf
, "group", strlen(field
)))
298 ug_tag
= ID_TYPE_GID
;
304 if ((field
= strtok_r(NULL
, ":", &last_field
)) != NULL
)
306 mbr_string_to_uuid(field
, *uu
);
310 if (*last_field
== ':') // empty username field
312 else if ((field
= strtok_r(NULL
, ":", &last_field
)) != NULL
&& need_tag
)
317 if((tpass
= getpwnam(field
)) != NULL
)
318 if (mbr_uid_to_uuid(tpass
->pw_uid
, *uu
) != 0)
325 if ((tgrp
= getgrnam(field
)) != NULL
)
326 if (mbr_gid_to_uuid(tgrp
->gr_gid
, *uu
) != 0)
336 if (*last_field
== ':') // empty uid field
338 else if ((field
= strtok_r(NULL
, ":", &last_field
)) != NULL
&& need_tag
)
343 if((id
= strtol(field
, NULL
, 10)) == 0 && error
)
352 if((tpass
= getpwuid((uid_t
)id
)) != NULL
)
353 if (mbr_uid_to_uuid(tpass
->pw_uid
, *uu
) != 0)
360 if ((tgrp
= getgrgid((gid_t
)id
)) != NULL
)
361 if (mbr_gid_to_uuid(tgrp
->gr_gid
, *uu
) != 0)
371 /* nothing do set as qualifier */
379 if((field
= strtok_r(NULL
, ":", &last_field
)) == NULL
)
385 for (tag
= 0, sub
= strtok_r(field
, ",", &last_sub
); sub
;
386 sub
= strtok_r(NULL
, ",", &last_sub
))
388 if (!tag
&& !strcmp(sub
, "allow")) {
389 tag
= ACL_EXTENDED_ALLOW
;
391 } else if (!tag
&& !strcmp(sub
, "deny")) {
392 tag
= ACL_EXTENDED_DENY
;
395 for (i
= 0; acl_flags
[i
].name
!= NULL
; ++i
)
397 if (acl_flags
[i
].type
& (ACL_TYPE_FILE
| ACL_TYPE_DIR
)
398 && !strcmp(acl_flags
[i
].name
, sub
))
400 acl_add_flag_np(flags
, acl_flags
[i
].flag
);
404 if (acl_flags
[i
].name
== NULL
)
406 /* couldn't find perm */
412 if((field
= strtok_r(NULL
, ":", &last_field
)) != NULL
) {
413 for (sub
= strtok_r(field
, ",", &last_sub
); sub
;
414 sub
= strtok_r(NULL
, ",", &last_sub
))
416 for (i
= 0; acl_perms
[i
].name
!= NULL
; i
++)
418 if (acl_perms
[i
].type
& (ACL_TYPE_FILE
| ACL_TYPE_DIR
)
419 && !strcmp(acl_perms
[i
].name
, sub
))
421 acl_add_perm(perms
, acl_perms
[i
].perm
);
425 if (acl_perms
[i
].name
== NULL
)
427 /* couldn't find perm */
433 acl_set_tag_type(acl_entry
, tag
);
434 acl_set_qualifier(acl_entry
, *uu
);
448 acl_to_text(acl_t acl
, ssize_t
*len_p
)
452 acl_entry_t entry
= NULL
;
456 char *str
, uu_str
[256];
459 size_t bufsize
= 1024;
462 if (!_ACL_VALID_ACL(acl
)) {
467 buf
= malloc(bufsize
);
469 len_p
= alloca(sizeof(ssize_t
));
473 if (!raosnprintf(&buf
, &bufsize
, len_p
, "!#acl %d", 1))
476 if (acl_get_flagset_np(acl
, &flags
) == 0)
478 for (i
= 0, first
= 0; acl_flags
[i
].name
!= NULL
; ++i
)
480 if (acl_flags
[i
].type
& ACL_TYPE_ACL
481 && acl_get_flag_np(flags
, acl_flags
[i
].flag
) != 0)
483 if(!raosnprintf(&buf
, &bufsize
, len_p
, "%s%s",
484 first
++ ? "," : " ", acl_flags
[i
].name
))
489 for (;acl_get_entry(acl
,
490 entry
== NULL
? ACL_FIRST_ENTRY
: ACL_NEXT_ENTRY
, &entry
) == 0;)
492 if (((uu
= (uuid_t
*) acl_get_qualifier(entry
)) == NULL
)
493 || (acl_get_tag_type(entry
, &tag
) != 0)
494 || (acl_get_flagset_np(entry
, &flags
) != 0)
495 || (acl_get_permset(entry
, &perms
) != 0))
498 str
= uuid_to_name(uu
, &id
, &isgid
);
499 mbr_uuid_to_string(uu
, uu_str
); // XXX how big should uu_str be? // XXX error?
501 if(!raosnprintf(&buf
, &bufsize
, len_p
, "\n%s:%s:%s:%d:%s",
502 isgid
? "group" : "user",
506 (tag
== ACL_EXTENDED_ALLOW
) ? "allow" : "deny"))
511 for (i
= 0; acl_flags
[i
].name
!= NULL
; ++i
)
513 if (acl_flags
[i
].type
& (ACL_TYPE_DIR
| ACL_TYPE_FILE
))
515 if(acl_get_flag_np(flags
, acl_flags
[i
].flag
) != 0)
517 if(!raosnprintf(&buf
, &bufsize
, len_p
, ",%s",
524 for (i
= 0, first
= 0; acl_perms
[i
].name
!= NULL
; ++i
)
526 if (acl_perms
[i
].type
& (ACL_TYPE_DIR
| ACL_TYPE_FILE
))
528 if(acl_get_perm_np(perms
, acl_perms
[i
].perm
) != 0)
530 if(!raosnprintf(&buf
, &bufsize
, len_p
, "%s%s",
538 buf
[(*len_p
)++] = '\n';
546 _ACL_VALIDATE_ACL(acl
);
548 return(_ACL_HEADER_SIZE
+ acl
->a_entries
* _ACL_ENTRY_SIZE
);