X-Git-Url: https://git.saurik.com/apple/libc.git/blobdiff_plain/eb1cde05bb040f65c511ae4fa854abf1628afdf2..6465356a983ac139f81d3b7913cdb548477c346c:/posix1e/acl_translate.c diff --git a/posix1e/acl_translate.c b/posix1e/acl_translate.c index 960a6d1..527f686 100644 --- a/posix1e/acl_translate.c +++ b/posix1e/acl_translate.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004, 2010, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -24,12 +24,15 @@ #include #include #include +#include #include #include #include #include #include +#include #include +#include #include #include @@ -61,9 +64,17 @@ acl_copy_ext(void *buf, acl_t acl, ssize_t size) errno = ERANGE; return(-1); } + + bzero(ext, reqsize); + ext->fsec_magic = OSSwapHostToBigInt32(KAUTH_FILESEC_MAGIC); + + /* special case for _FILESEC_REMOVE_ACL */ + if (acl == (acl_t)_FILESEC_REMOVE_ACL) { + ext->fsec_entrycount = OSSwapHostToBigInt32(KAUTH_FILESEC_NOACL); + return(reqsize); + } /* export the header */ - ext->fsec_magic = OSSwapHostToBigInt32(KAUTH_FILESEC_MAGIC); ext->fsec_entrycount = OSSwapHostToBigInt32(acl->a_entries); ext->fsec_flags = OSSwapHostToBigInt32(acl->a_flags); @@ -97,12 +108,19 @@ acl_copy_ext_native(void *buf, acl_t acl, ssize_t size) errno = ERANGE; return(-1); } + + bzero(ext, reqsize); + ext->fsec_magic = KAUTH_FILESEC_MAGIC; + + /* special case for _FILESEC_REMOVE_ACL */ + if (acl == (acl_t)_FILESEC_REMOVE_ACL) { + ext->fsec_entrycount = KAUTH_FILESEC_NOACL; + return(reqsize); + } /* export the header */ - ext->fsec_magic = KAUTH_FILESEC_MAGIC; ext->fsec_entrycount = acl->a_entries; ext->fsec_flags = acl->a_flags; - /* XXX owner? */ /* copy ACEs */ for (i = 0; i < acl->a_entries; i++) { @@ -223,6 +241,7 @@ static struct { {ACL_ENTRY_DIRECTORY_INHERIT, "directory_inherit", ACL_TYPE_DIR}, {ACL_ENTRY_LIMIT_INHERIT, "limit_inherit", ACL_TYPE_FILE | ACL_TYPE_DIR}, {ACL_ENTRY_ONLY_INHERIT, "only_inherit", ACL_TYPE_DIR}, + {ACL_FLAG_NO_INHERIT, "no_inherit", ACL_TYPE_ACL}, {0, NULL, 0} }; @@ -280,17 +299,16 @@ uuid_to_name(uuid_t *uu, uid_t *id, int *isgid) errout: ; //warn("Unable to translate qualifier on ACL\n"); } } - return strdup(""); + return NULL; } acl_t acl_from_text(const char *buf_p) { - int i, error = 0, need_tag = 1, ug_tag = -1; - char *buf; - char *entry, *field, *sub, - *last_field, *last_entry, *last_sub; - uuid_t *uu; + int i, error = 0, need_tag, ug_tag; + char *buf, *orig_buf; + char *entry, *field, *sub; + uuid_t *uu = NULL; struct passwd *tpass = NULL; struct group *tgrp = NULL; acl_entry_t acl_entry; @@ -299,41 +317,51 @@ acl_from_text(const char *buf_p) acl_tag_t tag; acl_t acl_ret; - if ((acl_ret = acl_init(1)) == NULL) - return NULL; - if (buf_p == NULL) + { + errno = EINVAL; return NULL; + } if ((buf = strdup(buf_p)) == NULL) return NULL; - /* acl flags */ - if ((entry = strtok_r(buf, "\n", &last_entry)) != NULL) + if ((acl_ret = acl_init(1)) == NULL) + return NULL; + + orig_buf = buf; + + /* global acl flags + * format: !#acl [] + */ + if ((entry = strsep(&buf, "\n")) != NULL && *entry) { - /* stamp */ - field = strtok_r(entry, " ", &last_field); - if (field && strncmp(field, "!#acl", strlen("!#acl"))) + /* field 1: !#acl */ + field = strsep(&entry, " "); + if (*field && strncmp(field, "!#acl", strlen("!#acl"))) { error = EINVAL; goto exit; } - /* version */ - field = strtok_r(NULL, " ", &last_field); + /* field 2: + * currently only accepts 1 + */ + field = strsep(&entry, " "); errno = 0; - if (field == NULL || strtol(field, NULL, 0) != 1) + if (!*field || strtol(field, NULL, 0) != 1) { error = EINVAL; goto exit; } - /* optional flags */ - if((field = strtok_r(NULL, " ", &last_field)) != NULL) + /* field 3: + * optional + */ + if((field = strsep(&entry, " ")) != NULL && *field) { acl_get_flagset_np(acl_ret, &flags); - for (sub = strtok_r(field, ",", &last_sub); sub; - sub = strtok_r(NULL, ",", &last_sub)) + while ((sub = strsep(&field, ",")) && *sub) { for (i = 0; acl_flags[i].name != NULL; ++i) { @@ -352,45 +380,75 @@ acl_from_text(const char *buf_p) } } } + } else { + error = EINVAL; + goto exit; } - for (entry = strtok_r(NULL, "\n", &last_entry); entry; - entry = strtok_r(NULL, "\n", &last_entry)) + /* parse each acl line + * format: : + * []: + * []: + * []: + * [,] + * [:[,]] + * + * only one of the user/group identifies is required + * the first one found is used + */ + while ((entry = strsep(&buf, "\n")) && *entry) { - field = strtok_r(entry, ":", &last_field); + need_tag = 1; + ug_tag = -1; + + /* field 1: */ + field = strsep(&entry, ":"); - if((uu = calloc(1, sizeof(uuid_t))) == NULL) + if(uu) + bzero(uu, sizeof(uuid_t)); + else if((uu = calloc(1, sizeof(uuid_t))) == NULL) + { + error = errno; goto exit; + } if(acl_create_entry(&acl_ret, &acl_entry)) + { + error = errno; goto exit; + } - acl_get_flagset_np(acl_entry, &flags); - acl_get_permset(acl_entry, &perms); + if (-1 == acl_get_flagset_np(acl_entry, &flags) + || -1 == acl_get_permset(acl_entry, &perms)) + { + error = errno; + goto exit; + } switch(*field) { case 'u': - if(!strncmp(buf, "user", strlen(field))) + if(!strcmp(field, "user")) ug_tag = ID_TYPE_UID; break; case 'g': - if(!strncmp(buf, "group", strlen(field))) + if(!strcmp(field, "group")) ug_tag = ID_TYPE_GID; break; - + default: + error = EINVAL; + goto exit; } - /* uuid */ - if ((field = strtok_r(NULL, ":", &last_field)) != NULL) + /* field 2: */ + if ((field = strsep(&entry, ":")) != NULL && *field) { - mbr_string_to_uuid(field, *uu); + uuid_parse(field, *uu); need_tag = 0; } - /* name */ - if (*last_field == ':') // empty username field - last_field++; - else if ((field = strtok_r(NULL, ":", &last_field)) != NULL && need_tag) + + /* field 3: */ + if ((field = strsep(&entry, ":")) != NULL && *field && need_tag) { switch(ug_tag) { @@ -410,13 +468,15 @@ acl_from_text(const char *buf_p) goto exit; } break; + default: + error = EINVAL; + goto exit; } need_tag = 0; } - /* uid */ - if (*last_field == ':') // empty uid field - last_field++; - else if ((field = strtok_r(NULL, ":", &last_field)) != NULL && need_tag) + + /* field 4: */ + if ((field = strsep(&entry, ":")) != NULL && *field && need_tag) { uid_t id; error = 0; @@ -449,30 +509,35 @@ acl_from_text(const char *buf_p) need_tag = 0; } - /* nothing do set as qualifier */ + /* sanity check: nothing set as qualifier */ if (need_tag) { error = EINVAL; goto exit; } - /* flags */ - if((field = strtok_r(NULL, ":", &last_field)) == NULL) + /* field 5: */ + if((field = strsep(&entry, ":")) == NULL || !*field) { error = EINVAL; goto exit; } - for (tag = 0, sub = strtok_r(field, ",", &last_sub); sub; - sub = strtok_r(NULL, ",", &last_sub)) + for (tag = 0; (sub = strsep(&field, ",")) && *sub;) { - if (!tag && !strcmp(sub, "allow")) { + if (!tag) + { + if (!strcmp(sub, "allow")) tag = ACL_EXTENDED_ALLOW; - continue; - } else if (!tag && !strcmp(sub, "deny")) { + else if (!strcmp(sub, "deny")) tag = ACL_EXTENDED_DENY; - continue; + else { + error = EINVAL; + goto exit; + } + continue; } + for (i = 0; acl_flags[i].name != NULL; ++i) { if (acl_flags[i].type & (ACL_TYPE_FILE | ACL_TYPE_DIR) @@ -490,9 +555,10 @@ acl_from_text(const char *buf_p) } } - if((field = strtok_r(NULL, ":", &last_field)) != NULL) { - for (sub = strtok_r(field, ",", &last_sub); sub; - sub = strtok_r(NULL, ",", &last_sub)) + /* field 6: (can be empty) */ + if((field = strsep(&entry, ":")) != NULL && *field) + { + while ((sub = strsep(&field, ",")) && *sub) { for (i = 0; acl_perms[i].name != NULL; i++) { @@ -515,7 +581,9 @@ acl_from_text(const char *buf_p) acl_set_qualifier(acl_entry, *uu); } exit: - free(buf); + if(uu) + free(uu); + free(orig_buf); if (error) { acl_free(acl_ret); @@ -528,31 +596,32 @@ exit: char * acl_to_text(acl_t acl, ssize_t *len_p) { - uuid_t *uu; acl_tag_t tag; acl_entry_t entry = NULL; acl_flagset_t flags; acl_permset_t perms; uid_t id; - char *str, uu_str[256]; int i, first; int isgid; size_t bufsize = 1024; - char *buf; + char *buf = NULL; if (!_ACL_VALID_ACL(acl)) { errno = EINVAL; return NULL; } - buf = malloc(bufsize); if (len_p == NULL) - len_p = alloca(sizeof(ssize_t)); + if ((len_p = alloca(sizeof(ssize_t))) == NULL) + goto err_nomem; *len_p = 0; + if ((buf = malloc(bufsize)) == NULL) + goto err_nomem; + if (!raosnprintf(&buf, &bufsize, len_p, "!#acl %d", 1)) - return NULL; + goto err_nomem; if (acl_get_flagset_np(acl, &flags) == 0) { @@ -563,31 +632,45 @@ acl_to_text(acl_t acl, ssize_t *len_p) { if(!raosnprintf(&buf, &bufsize, len_p, "%s%s", first++ ? "," : " ", acl_flags[i].name)) - return NULL; + goto err_nomem; } } } for (;acl_get_entry(acl, entry == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY, &entry) == 0;) { + int valid; + uuid_t *uu; + char *str, uu_str[37]; + if (((uu = (uuid_t *) acl_get_qualifier(entry)) == NULL) || (acl_get_tag_type(entry, &tag) != 0) || (acl_get_flagset_np(entry, &flags) != 0) - || (acl_get_permset(entry, &perms) != 0)) + || (acl_get_permset(entry, &perms) != 0)) { + if (uu != NULL) acl_free(uu); continue; + } - str = uuid_to_name(uu, &id, &isgid); - mbr_uuid_to_string(uu, uu_str); // XXX how big should uu_str be? // XXX error? - - if(!raosnprintf(&buf, &bufsize, len_p, "\n%s:%s:%s:%d:%s", - isgid ? "group" : "user", - uu_str, - str, - id, - (tag == ACL_EXTENDED_ALLOW) ? "allow" : "deny")) - return NULL; + uuid_unparse_upper(*uu, uu_str); + + if ((str = uuid_to_name(uu, &id, &isgid)) != NULL) { + valid = raosnprintf(&buf, &bufsize, len_p, "\n%s:%s:%s:%d:%s", + isgid ? "group" : "user", + uu_str, + str, + id, + (tag == ACL_EXTENDED_ALLOW) ? "allow" : "deny"); + } else { + valid = raosnprintf(&buf, &bufsize, len_p, "\nuser:%s:::%s", + uu_str, + (tag == ACL_EXTENDED_ALLOW) ? "allow" : "deny"); + } free(str); + acl_free(uu); + + if (!valid) + goto err_nomem; for (i = 0; acl_flags[i].name != NULL; ++i) { @@ -597,7 +680,7 @@ acl_to_text(acl_t acl, ssize_t *len_p) { if(!raosnprintf(&buf, &bufsize, len_p, ",%s", acl_flags[i].name)) - return NULL; + goto err_nomem; } } } @@ -609,9 +692,8 @@ acl_to_text(acl_t acl, ssize_t *len_p) if(acl_get_perm_np(perms, acl_perms[i].perm) != 0) { if(!raosnprintf(&buf, &bufsize, len_p, "%s%s", - first++ ? "," : ":", - acl_perms[i].name)) - return NULL; + first++ ? "," : ":", acl_perms[i].name)) + goto err_nomem; } } } @@ -619,12 +701,23 @@ acl_to_text(acl_t acl, ssize_t *len_p) buf[(*len_p)++] = '\n'; buf[(*len_p)] = 0; return buf; + +err_nomem: + if (buf != NULL) + free(buf); + + errno = ENOMEM; + return NULL; } ssize_t acl_size(acl_t acl) { + /* special case for _FILESEC_REMOVE_ACL */ + if (acl == (acl_t)_FILESEC_REMOVE_ACL) + return KAUTH_FILESEC_SIZE(0); + _ACL_VALIDATE_ACL(acl); - return(_ACL_HEADER_SIZE + acl->a_entries * _ACL_ENTRY_SIZE); + return(KAUTH_FILESEC_SIZE(acl->a_entries)); }