]> git.saurik.com Git - apple/file_cmds.git/blobdiff - chmod/chmod_acl.c
file_cmds-321.100.10.0.1.tar.gz
[apple/file_cmds.git] / chmod / chmod_acl.c
index f09f304cb5075d4462a1113c46ffe9e4d9000bdd..5ac4c177c04dd179c684c96f1053c35179c547b7 100644 (file)
@@ -100,31 +100,22 @@ static struct {
 
 uuid_t *
 name_to_uuid(char *tok, int nametype) {
-       struct passwd *tpass = NULL;
-       struct group *tgrp = NULL;
        uuid_t *entryg = NULL;
+       size_t len = strlen(tok);
 
-       if ((entryg = (uuid_t *) calloc(1,sizeof(uuid_t))) == NULL)
-               err(1, "Unable to allocate a uuid");
-
-       if (nametype & NAME_USER)
-               tpass = getpwnam(tok);
-
-       if (NULL == tpass && (nametype & NAME_GROUP))
-               tgrp = getgrnam(tok);
+       if ((entryg = (uuid_t *) calloc(1, sizeof(uuid_t))) == NULL) {
+               errx(1, "Unable to allocate a uuid");
+       }
 
-       if (tpass) {
-               if (0 != mbr_uid_to_uuid(tpass->pw_uid, *entryg)) {
-                       errx(1, "mbr_uid_to_uuid(): Unable to translate uid %d", tpass->pw_uid);
-               }
-       } else if (tgrp) {
-               if (0 != mbr_gid_to_uuid(tgrp->gr_gid, *entryg)) {
-                       errx(1, "mbr_gid_to_uuid(): Unable to translate gid %d", tgrp->gr_gid);
-               }
-       } else {
-               errx(1, "Unable to translate '%s' to a UID/GID", tok);
+       if ((nametype & NAME_USER) && mbr_identifier_to_uuid(ID_TYPE_USERNAME, tok, len, *entryg) == 0) {
+               return entryg;
+       }
+       
+       if ((nametype & NAME_GROUP) && mbr_identifier_to_uuid(ID_TYPE_GROUPNAME, tok, len, *entryg) == 0) {
+               return entryg;
        }
-       return entryg;
+       
+       errx(1, "Unable to translate '%s' to a UUID", tok);
 }
 
 /* Convert an acl entry in string form to an acl_entry_t */
@@ -341,7 +332,7 @@ compare_acl_permsets(acl_permset_t aperms, acl_permset_t bperms)
        return MATCH_EXACT;
 }
 
-int
+static int
 compare_acl_flagsets(acl_flagset_t aflags, acl_flagset_t bflags)
 {
        int i;
@@ -362,9 +353,16 @@ compare_acl_entries(acl_entry_t a, acl_entry_t b)
        acl_permset_t aperms, bperms;
        acl_flagset_t aflags, bflags;
        int pcmp = 0, fcmp = 0;
+       void *aqual, *bqual;
+
+       aqual = acl_get_qualifier(a);
+       bqual = acl_get_qualifier(b);
+
+       int compare = compare_acl_qualifiers(aqual, bqual);
+       acl_free(aqual);
+       acl_free(bqual);
 
-       if (0 != compare_acl_qualifiers(acl_get_qualifier(a), 
-                                       acl_get_qualifier(b)))
+       if (compare != 0)
                return MATCH_NONE;
 
        if (0 != acl_get_tag_type(a, &atag))
@@ -502,10 +500,12 @@ find_matching_entry (acl_t acl, acl_entry_t modifier, acl_entry_t *rentryp,
 
 /* Remove all perms specified in modifier from rentry*/
 int
-subtract_from_entry(acl_entry_t rentry, acl_entry_t  modifier)
+subtract_from_entry(acl_entry_t rentry, acl_entry_t  modifier, int* valid_perms)
 {
        acl_permset_t rperms, mperms;
        acl_flagset_t rflags, mflags;
+       if (valid_perms)
+               *valid_perms = 0;
        int i;
 
        if ((acl_get_permset(rentry, &rperms) != 0) ||
@@ -517,6 +517,8 @@ subtract_from_entry(acl_entry_t rentry, acl_entry_t  modifier)
        for (i = 0; acl_perms[i].name != NULL; i++) {
                if (acl_get_perm_np(mperms, acl_perms[i].perm))
                        acl_delete_perm(rperms, acl_perms[i].perm);
+               else if (valid_perms && acl_get_perm_np(rperms, acl_perms[i].perm)) 
+                       (*valid_perms)++;
        }
        for (i = 0; acl_flags[i].name != NULL; i++) {
                if (acl_get_flag_np(mflags, acl_flags[i].flag))
@@ -527,7 +529,7 @@ subtract_from_entry(acl_entry_t rentry, acl_entry_t  modifier)
        return 0;
 }
 /* Add the perms specified in modifier to rentry */
-int
+static int
 merge_entry_perms(acl_entry_t rentry, acl_entry_t  modifier)
 {
        acl_permset_t rperms, mperms;
@@ -556,7 +558,7 @@ merge_entry_perms(acl_entry_t rentry, acl_entry_t  modifier)
 int
 modify_acl(acl_t *oaclp, acl_entry_t modifier, unsigned int optflags,
           int position, int inheritance_level, 
-          unsigned flag_new_acl) {
+          unsigned flag_new_acl, const char* path) {
 
        unsigned cpos = 0;
        acl_entry_t newent = NULL;
@@ -579,8 +581,7 @@ modify_acl(acl_t *oaclp, acl_entry_t modifier, unsigned int optflags,
                        if (0 != acl_create_entry_np(&oacl, &newent, position))
                                err(1, "acl_create_entry() failed");
                        acl_copy_entry(newent, modifier);
-               }
-               else {
+               } else {
 /* If an entry exists, add the new permissions to it, else add an
  * entry in the canonical position.
  */
@@ -604,77 +605,78 @@ modify_acl(acl_t *oaclp, acl_entry_t modifier, unsigned int optflags,
                                err(1, "acl_create_entry() failed");
                        acl_copy_entry(newent, modifier);
                }
-       }
-       else
-               if (optflags & ACL_DELETE_FLAG) {
-
-                       if (flag_new_acl) {
-                               errx(1, "No ACL present");
-                       }
-                       if (position != -1 ) {
-                               if (0 != acl_get_entry(oacl, position, &rentry))
-                                       err(1, "Invalid entry number");
+       } else if (optflags & ACL_DELETE_FLAG) {
+               if (flag_new_acl) {
+                       warnx("No ACL present '%s'", path);
+                       retval = 1;
+               } else if (position != -1 ) {
+                       if (0 != acl_get_entry(oacl, position, &rentry)) {
+                               warnx("Invalid entry number '%s'", path);
+                               retval = 1;
+                       } else {
                                acl_delete_entry(oacl, rentry);
                        }
-                       else {
-                               unsigned match_found = 0, aindex;
-                               for (aindex = 0; 
-                                    acl_get_entry(oacl, rentry == NULL ? 
-                                                  ACL_FIRST_ENTRY : 
-                                                  ACL_NEXT_ENTRY, &rentry) 
-                                            == 0; aindex++)    {
-                                       unsigned cmp;
-                                       cmp = compare_acl_entries(rentry, 
-                                                                 modifier);
-                                       if ((cmp == MATCH_EXACT) || 
-                                           (cmp == MATCH_PARTIAL)) {
-                                               match_found++;
-                                               if (cmp == MATCH_EXACT)
-                                                       acl_delete_entry(oacl, rentry);
-                                               else
+               } else {
+                       unsigned match_found = 0, aindex;
+                       for (aindex = 0; 
+                            acl_get_entry(oacl, rentry == NULL ? 
+                                          ACL_FIRST_ENTRY : 
+                                          ACL_NEXT_ENTRY, &rentry) == 0;
+                            aindex++)  {
+                               unsigned cmp;
+                               cmp = compare_acl_entries(rentry, modifier);
+                               if ((cmp == MATCH_EXACT) || 
+                                   (cmp == MATCH_PARTIAL)) {
+                                       match_found++;
+                                       if (cmp == MATCH_EXACT)
+                                               acl_delete_entry(oacl, rentry);
+                                       else {
+                                               int valid_perms;
 /* In the event of a partial match, remove the specified perms from the 
  * entry */
-                                                       subtract_from_entry(rentry, modifier);
+                                               subtract_from_entry(rentry, modifier, &valid_perms);
+                                               /* if no perms survived then delete the entry */
+                                               if (valid_perms == 0)
+                                                       acl_delete_entry(oacl, rentry);
                                        }
                                }
-                               if (0 == match_found) {
-                                       warnx("Entry not found when attempting delete");
-                                       retval = 1;
-                               }
                        }
-               }
-               else
-                       if (optflags & ACL_REWRITE_FLAG) {
-                               acl_entry_t rentry;
-                               
-                               if (-1 == position) {
-                                       usage();
-                               }
-                               if (0 == flag_new_acl) {
-                                       if (0 != acl_get_entry(oacl, position,
-                                                              &rentry))
-                                               err(1, "Invalid entry number");
-                                       
-                                       if (0 != acl_delete_entry(oacl, rentry))
-                                               err(1, "Unable to delete entry");
-                               }
-                               if (0!= acl_create_entry_np(&oacl, &newent, position))
-                                       err(1, "acl_create_entry() failed");
-                               acl_copy_entry(newent, modifier);
+                       if (0 == match_found) {
+                               warnx("Entry not found when attempting delete '%s'",path);
+                               retval = 1;
                        }
+               }
+       } else if (optflags & ACL_REWRITE_FLAG) {
+               acl_entry_t rentry;
+               
+               if (-1 == position) {
+                       usage();
+               }
+               if (0 == flag_new_acl) {
+                       if (0 != acl_get_entry(oacl, position,
+                                              &rentry))
+                               err(1, "Invalid entry number '%s'", path);
+                       
+                       if (0 != acl_delete_entry(oacl, rentry))
+                               err(1, "Unable to delete entry '%s'", path);
+               }
+               if (0!= acl_create_entry_np(&oacl, &newent, position))
+                       err(1, "acl_create_entry() failed");
+               acl_copy_entry(newent, modifier);
+       }
 ma_exit:
        *oaclp = oacl;
        return retval;
 }
 
 int
-modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int position, int inheritance_level) {
+modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int position, int inheritance_level, int follow) {
        
        acl_t oacl = NULL;
        unsigned aindex  = 0, flag_new_acl = 0;
        acl_entry_t newent = NULL;
        acl_entry_t entry = NULL;
-       unsigned retval = 0 ;
+       unsigned retval = 0;
 
        extern int fflag;
 
@@ -697,26 +699,52 @@ modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int pos
 
        if (optflags & ACL_CLEAR_FLAG) {
                filesec_t fsec = filesec_init();
-               if (fsec == NULL)
+               if (fsec == NULL) {
                        err(1, "filesec_init() failed");
-               if (filesec_set_property(fsec, FILESEC_ACL,
-                                        _FILESEC_REMOVE_ACL) != 0)
+               }
+               if (filesec_set_property(fsec, FILESEC_ACL, _FILESEC_REMOVE_ACL) != 0) {
                        err(1, "filesec_set_property() failed");
-               if (chmodx_np(path, fsec) != 0) {
-                       if (!fflag)
-                               warn("Failed to clear ACL on file %s", path);
-                       retval = 1;
-               } else
-                       retval = 0;
+                }
+               if (follow) {
+                       if (chmodx_np(path, fsec) != 0) {
+                                if (!fflag) {
+                                       warn("Failed to clear ACL on file %s", path);
+                               }
+                               retval = 1;
+                       }
+               } else {
+                       int fd = open(path, O_SYMLINK);
+                       if (fd != -1) {
+                               if (fchmodx_np(fd, fsec) != 0) {
+                                       if (!fflag) {
+                                               warn("Failed to clear ACL on file %s", path);
+                                       }
+                                       retval = 1;
+                               }
+                               close(fd);
+                       } else {
+                               if (!fflag) {
+                                       warn("Failed to open file %s", path);
+                               }
+                               retval = 1;
+                       }
+               }
                filesec_free(fsec);
                return (retval);
        }
 
-       if (optflags & ACL_FROM_STDIN)
+       if (optflags & ACL_FROM_STDIN) {
                oacl = acl_dup(modifier);
-       else {
-               oacl = acl_get_file(path, ACL_TYPE_EXTENDED);
-               
+       } else {
+               if (follow) {
+                       oacl = acl_get_file(path, ACL_TYPE_EXTENDED);
+               } else {
+                       int fd = open(path, O_SYMLINK);
+                       if (fd != -1) {
+                               oacl = acl_get_fd_np(fd, ACL_TYPE_EXTENDED);
+                               close(fd);
+                       }
+               }
                if ((oacl == NULL) ||
                    (acl_get_entry(oacl,ACL_FIRST_ENTRY, &newent) != 0)) {
                        if ((oacl = acl_init(1)) == NULL)
@@ -774,7 +802,7 @@ modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int pos
                } else if (((optflags & ACL_DELETE_FLAG) && (position != -1))
                    || (optflags & ACL_CHECK_CANONICITY)) {
                        retval = modify_acl(&oacl, NULL, optflags, position, 
-                                  inheritance_level, flag_new_acl);
+                                           inheritance_level, flag_new_acl, path);
                } else if ((optflags & (ACL_REMOVE_INHERIT_FLAG|ACL_REMOVE_INHERITED_ENTRIES)) && flag_new_acl) {
                        warnx("No ACL currently associated with file '%s'", path);
                        retval = 1;
@@ -790,7 +818,7 @@ modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int pos
 
                                retval += modify_acl(&oacl, entry, optflags, 
                                                     position, inheritance_level, 
-                                                    flag_new_acl);
+                                                    flag_new_acl, path);
                        }
                }
        }
@@ -803,11 +831,23 @@ modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int pos
  * "changeset" mechanism, common locking  strategy, or kernel
  * supplied reservation mechanism to prevent this race.
  */
-       if (!(optflags & (ACL_TO_STDOUT|ACL_CHECK_CANONICITY)) && 
-           (0 != acl_set_file(path, ACL_TYPE_EXTENDED, oacl))){
-               if (!fflag)
-                       warn("Failed to set ACL on file '%s'", path);
-               retval = 1;
+       if (!(optflags & (ACL_TO_STDOUT|ACL_CHECK_CANONICITY))) {
+               int status = -1;
+               if (follow) {
+                       status = acl_set_file(path, ACL_TYPE_EXTENDED, oacl);
+               } else {
+                       int fd = open(path, O_SYMLINK);
+                       if (fd != -1) {
+                               status = acl_set_fd_np(fd, oacl,
+                                                       ACL_TYPE_EXTENDED);
+                               close(fd);
+                       }
+               }
+               if (status != 0) {
+                       if (!fflag)
+                               warn("Failed to set ACL on file '%s'", path);
+                       retval = 1;
+               }
        }
        
        if (oacl)