/* * deletes an access acl or directory default acl if one exists */ static int acl_delete_file(const char *path, acl_type_t type) { int error = 0; /* converts access ACL to a minimal ACL */ if (type == ACL_TYPE_ACCESS) { acl_t acl; acl_entry_t entry; acl_tag_t tag; acl = acl_get_file(path, ACL_TYPE_ACCESS); if (!acl) return -1; error = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); while (error == 1) { acl_get_tag_type(entry, &tag); switch(tag) { case ACL_USER: case ACL_GROUP: case ACL_MASK: acl_delete_entry(acl, entry); break; } error = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry); } if (!error) error = acl_set_file(path, ACL_TYPE_ACCESS, acl); } else error = acl_delete_def_file(path); return(error); }
static int flush_acl(acl_t acl) { acl_entry_t i; int found; bool changed = false; assert(acl); for (found = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); found > 0; found = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { acl_tag_t tag; if (acl_get_tag_type(i, &tag) < 0) return -errno; if (tag != ACL_USER) continue; if (acl_delete_entry(acl, i) < 0) return -errno; changed = true; } if (found < 0) return -errno; return changed; }
/** * removes entry in ptr from acl * acl: ptr to acl to modify * entry: ptr to entry to remove * returns: status **/ _BOOL acl_remove(acl_t * acl, acl_entry_t *entry,acl_entry_in *entry_in){ if(acl==NULL || entry==NULL){errno = EINVAL; return FALSE;} #ifdef POSIXLY_CORRECT if(entry_in->no_perm){ errno = EINVAL; return FALSE; } acl_permset_t permset; if(acl_get_permset(*entry,&permset)!=ACL_OK) return FALSE; int verify_bits = 0; verify_bits += ((entry_in->permset.nibble)&READ&&acl_get_perm(permset,ACL_READ)|| !(entry_in->permset.nibble&READ)) ? 1 : 0; verify_bits += ((entry_in->permset.nibble&WRITE)&&acl_get_perm(permset,ACL_WRITE)|| !(entry_in->permset.nibble&WRITE)) ? 1 : 0; verify_bits += ((entry_in->permset.nibble&EXEC)&&acl_get_perm(permset,ACL_EXECUTE)|| !(entry_in->permset.nibble&EXEC)) ? 1 : 0; if(verify_bits!=VERIFIED_BITS){errno = EINVAL; return FALSE;} #else if(!entry_in->no_perm){ errno = EINVAL; return FALSE; } #endif if(acl_delete_entry(*acl,*entry)!=ACL_OK) return FALSE; return TRUE; }
static int remove_extended_entries( acl_t acl) { acl_entry_t ent, group_obj; acl_permset_t mask_permset, group_obj_permset; acl_tag_t tag; int error; /* * Removing the ACL_MASK entry from the ACL results in * increased permissions for the owning group if the * ACL_GROUP_OBJ entry contains permissions not contained * in the ACL_MASK entry. We remove these permissions from * the ACL_GROUP_OBJ entry to avoid that. * * After removing the ACL, the file owner and the owning group * therefore have the same permissions as before. */ ent = find_entry(acl, ACL_MASK, ACL_UNDEFINED_ID); group_obj = find_entry(acl, ACL_GROUP_OBJ, ACL_UNDEFINED_ID); if (ent && group_obj) { if (!acl_get_permset(ent, &mask_permset) && !acl_get_permset(group_obj, &group_obj_permset)) { if (!acl_get_perm(mask_permset, ACL_READ)) acl_delete_perm(group_obj_permset, ACL_READ); if (!acl_get_perm(mask_permset, ACL_WRITE)) acl_delete_perm(group_obj_permset, ACL_WRITE); if (!acl_get_perm(mask_permset, ACL_EXECUTE)) acl_delete_perm(group_obj_permset, ACL_EXECUTE); } } error = acl_get_entry(acl, ACL_FIRST_ENTRY, &ent); while (error == 1) { acl_get_tag_type(ent, &tag); switch(tag) { case ACL_USER: case ACL_GROUP: case ACL_MASK: acl_delete_entry(acl, ent); break; default: break; } error = acl_get_entry(acl, ACL_NEXT_ENTRY, &ent); } if (error < 0) return -1; return 0; }
/* * remove ACL entries from an ACL */ int remove_acl(acl_t acl, acl_t *prev_acl, const char *filename) { acl_entry_t entry; acl_t acl_new; acl_tag_t tag; int carried_error, entry_id, acl_brand, prev_acl_brand; carried_error = 0; acl_get_brand_np(acl, &acl_brand); acl_get_brand_np(*prev_acl, &prev_acl_brand); if (branding_mismatch(acl_brand, prev_acl_brand)) { warnx("%s: branding mismatch; existing ACL is %s, " "entry to be removed is %s", filename, brand_name(prev_acl_brand), brand_name(acl_brand)); return (-1); } carried_error = 0; acl_new = acl_dup(*prev_acl); if (acl_new == NULL) err(1, "%s: acl_dup() failed", filename); tag = ACL_UNDEFINED_TAG; /* find and delete the entry */ entry_id = ACL_FIRST_ENTRY; while (acl_get_entry(acl, entry_id, &entry) == 1) { entry_id = ACL_NEXT_ENTRY; if (acl_get_tag_type(entry, &tag) == -1) err(1, "%s: acl_get_tag_type() failed", filename); if (tag == ACL_MASK) have_mask++; if (acl_delete_entry(acl_new, entry) == -1) { carried_error++; warnx("%s: cannot remove non-existent ACL entry", filename); } } acl_free(*prev_acl); *prev_acl = acl_new; if (carried_error) return (-1); return (0); }
/* * remove ACL entries from an ACL */ int remove_acl(acl_t acl, acl_t *prev_acl) { acl_entry_t entry; acl_t acl_new; acl_tag_t tag; int carried_error, entry_id; carried_error = 0; if (acl_type == ACL_TYPE_ACCESS) acl_new = acl_dup(prev_acl[ACCESS_ACL]); else acl_new = acl_dup(prev_acl[DEFAULT_ACL]); if (acl_new == NULL) err(1, "acl_dup() failed"); tag = ACL_UNDEFINED_TAG; /* find and delete the entry */ entry_id = ACL_FIRST_ENTRY; while (acl_get_entry(acl, entry_id, &entry) == 1) { entry_id = ACL_NEXT_ENTRY; if (acl_get_tag_type(entry, &tag) == -1) err(1, "acl_get_tag_type() failed"); if (tag == ACL_MASK) have_mask++; if (acl_delete_entry(acl_new, entry) == -1) { carried_error++; warnx("cannot remove non-existent acl entry"); } } if (acl_type == ACL_TYPE_ACCESS) { acl_free(prev_acl[ACCESS_ACL]); prev_acl[ACCESS_ACL] = acl_new; } else { acl_free(prev_acl[DEFAULT_ACL]); prev_acl[DEFAULT_ACL] = acl_new; } if (carried_error) return (-1); return (0); }
/*! * Remove any ACL_USER, ACL_GROUP, ACL_MASK or ACL_TYPE_DEFAULT ACEs from an object * * @param name (r) filesystem object name * * @returns AFP error code, AFP_OK (= 0) on success, AFPERR_MISC on error */ int remove_acl_vfs(const char *name) { EC_INIT; struct stat st; acl_t acl = NULL; acl_entry_t e; acl_tag_t tag; int entry_id = ACL_FIRST_ENTRY; /* Remove default ACL if it's a dir */ EC_ZERO_ERR(stat(name, &st), AFPERR_MISC); if (S_ISDIR(st.st_mode)) { EC_NULL_LOG_ERR(acl = acl_init(0), AFPERR_MISC); EC_ZERO_LOG_ERR(acl_set_file(name, ACL_TYPE_DEFAULT, acl), AFPERR_MISC); EC_ZERO_LOG_ERR(acl_free(acl), AFPERR_MISC); acl = NULL; } /* Now get ACL and remove ACL_MASK, ACL_USER or ACL_GROUP entries, then re-set * the ACL again. acl_calc_mask() must not be called because there is no need * for an ACL_MASK entry in a basic ACL. */ EC_NULL_LOG_ERR(acl = acl_get_file(name, ACL_TYPE_ACCESS), AFPERR_MISC); for ( ; acl_get_entry(acl, entry_id, &e) == 1; entry_id = ACL_NEXT_ENTRY) { EC_ZERO_LOG_ERR(acl_get_tag_type(e, &tag), AFPERR_MISC); if (tag == ACL_USER || tag == ACL_GROUP || tag == ACL_MASK) EC_ZERO_LOG_ERR(acl_delete_entry(acl, e), AFPERR_MISC); } EC_ZERO_LOG_ERR(acl_valid(acl), AFPERR_MISC); EC_ZERO_LOG_ERR(acl_set_file(name, ACL_TYPE_ACCESS, acl), AFPERR_MISC); EC_CLEANUP: if (errno == ENOENT) EC_STATUS(0); if (acl) acl_free(acl); EC_EXIT; }
static int set_facl(const char* filename, uid_t uid, int add) { int get; acl_t acl; acl_entry_t entry = NULL; acl_entry_t e; acl_permset_t permset; int ret; /* don't touch ACLs for root */ if (uid == 0) return 0; /* read current record */ acl = acl_get_file(filename, ACL_TYPE_ACCESS); if (!acl) return -1; /* locate ACL_USER entry for uid */ get = acl_get_entry(acl, ACL_FIRST_ENTRY, &e); while (get == 1) { acl_tag_t t; acl_get_tag_type(e, &t); if (t == ACL_USER) { uid_t *u; u = (uid_t*)acl_get_qualifier(e); if (u == NULL) { ret = -1; goto out; } if (*u == uid) { entry = e; acl_free(u); break; } acl_free(u); } get = acl_get_entry(acl, ACL_NEXT_ENTRY, &e); } /* remove ACL_USER entry for uid */ if (!add) { if (entry == NULL) { ret = 0; goto out; } acl_delete_entry(acl, entry); goto update; } /* create ACL_USER entry for uid */ if (entry == NULL) { ret = acl_create_entry(&acl, &entry); if (ret != 0) goto out; acl_set_tag_type(entry, ACL_USER); acl_set_qualifier(entry, &uid); } /* add permissions for uid */ acl_get_permset(entry, &permset); acl_add_perm(permset, ACL_READ|ACL_WRITE); update: /* update record */ if (debug) printf("%c%u %s\n", add ? '+' : '-', uid, filename); acl_calc_mask(&acl); ret = acl_set_file(filename, ACL_TYPE_ACCESS, acl); if (ret != 0) goto out; out: acl_free(acl); return ret; }
int devnode_acl(const char *path, bool flush, bool del, uid_t old_uid, bool add, uid_t new_uid) { acl_t acl; int r = 0; bool changed = false; assert(path); acl = acl_get_file(path, ACL_TYPE_ACCESS); if (!acl) return -errno; if (flush) { r = flush_acl(acl); if (r < 0) goto finish; if (r > 0) changed = true; } else if (del && old_uid > 0) { acl_entry_t entry; r = acl_find_uid(acl, old_uid, &entry); if (r < 0) goto finish; if (r > 0) { if (acl_delete_entry(acl, entry) < 0) { r = -errno; goto finish; } changed = true; } } if (add && new_uid > 0) { acl_entry_t entry; acl_permset_t permset; int rd, wt; r = acl_find_uid(acl, new_uid, &entry); if (r < 0) goto finish; if (r == 0) { if (acl_create_entry(&acl, &entry) < 0) { r = -errno; goto finish; } if (acl_set_tag_type(entry, ACL_USER) < 0 || acl_set_qualifier(entry, &new_uid) < 0) { r = -errno; goto finish; } } if (acl_get_permset(entry, &permset) < 0) { r = -errno; goto finish; } rd = acl_get_perm(permset, ACL_READ); if (rd < 0) { r = -errno; goto finish; } wt = acl_get_perm(permset, ACL_WRITE); if (wt < 0) { r = -errno; goto finish; } if (!rd || !wt) { if (acl_add_perm(permset, ACL_READ|ACL_WRITE) < 0) { r = -errno; goto finish; } changed = true; } } if (!changed) goto finish; if (acl_calc_mask(&acl) < 0) { r = -errno; goto finish; } if (acl_set_file(path, ACL_TYPE_ACCESS, acl) < 0) { r = -errno; goto finish; } r = 0; finish: acl_free(acl); return r; }
int do_set( const char *path_p, const struct stat *st, const seq_t seq) { acl_t old_acl = NULL, old_default_acl = NULL; acl_t acl = NULL, default_acl = NULL; acl_t *xacl, *old_xacl; acl_entry_t ent; cmd_t cmd; int which_entry; int errors = 0, error; char *acl_text; int acl_modified = 0, default_acl_modified = 0; int acl_mask_provided = 0, default_acl_mask_provided = 0; /* Execute the commands in seq (read ACLs on demand) */ error = seq_get_cmd(seq, SEQ_FIRST_CMD, &cmd); if (error == 0) return 0; while (error == 1) { if (cmd->c_type == ACL_TYPE_ACCESS) { xacl = &acl; old_xacl = &old_acl; acl_modified = 1; if (cmd->c_tag == ACL_MASK) acl_mask_provided = 1; } else { xacl = &default_acl; old_xacl = &old_default_acl; default_acl_modified = 1; if (cmd->c_tag == ACL_MASK) default_acl_mask_provided = 1; } RETRIEVE_ACL(cmd->c_type); /* Check for `X', and replace with `x' as appropriate. */ if (cmd->c_perm & CMD_PERM_COND_EXECUTE) { cmd->c_perm &= ~CMD_PERM_COND_EXECUTE; if (S_ISDIR(st->st_mode) || has_execute_perms(*xacl)) cmd->c_perm |= CMD_PERM_EXECUTE; } switch(cmd->c_cmd) { case CMD_ENTRY_REPLACE: ent = find_entry(*xacl, cmd->c_tag, cmd->c_id); if (!ent) { if (acl_create_entry(xacl, &ent) != 0) goto fail; acl_set_tag_type(ent, cmd->c_tag); if (cmd->c_id != ACL_UNDEFINED_ID) acl_set_qualifier(ent, &cmd->c_id); } set_perm(ent, cmd->c_perm, ~cmd->c_perm); break; case CMD_ENTRY_ADD: ent = find_entry(*xacl, cmd->c_tag, cmd->c_id); if (ent) set_perm(ent, cmd->c_perm, 0); break; case CMD_ENTRY_SUBTRACT: ent = find_entry(*xacl, cmd->c_tag, cmd->c_id); if (ent) set_perm(ent, 0, cmd->c_perm); break; case CMD_REMOVE_ENTRY: ent = find_entry(*xacl, cmd->c_tag, cmd->c_id); if (ent) acl_delete_entry(*xacl, ent); else /* ignore */; break; case CMD_REMOVE_EXTENDED_ACL: remove_extended_entries(acl); break; case CMD_REMOVE_ACL: acl_free(*xacl); *xacl = acl_init(5); if (!*xacl) goto fail; break; default: errno = EINVAL; goto fail; } error = seq_get_cmd(seq, SEQ_NEXT_CMD, &cmd); } if (error < 0) goto fail; /* Try to fill in missing entries */ if (default_acl && acl_entries(default_acl) != 0) { xacl = &acl; old_xacl = &old_acl; if (!find_entry(default_acl, ACL_USER_OBJ, ACL_UNDEFINED_ID)) { if (!acl) RETRIEVE_ACL(ACL_TYPE_ACCESS); clone_entry(acl, ACL_USER_OBJ, &default_acl, ACL_USER_OBJ); } if (!find_entry(default_acl, ACL_GROUP_OBJ, ACL_UNDEFINED_ID)) { if (!acl) RETRIEVE_ACL(ACL_TYPE_ACCESS); clone_entry(acl, ACL_GROUP_OBJ, &default_acl, ACL_GROUP_OBJ); } if (!find_entry(default_acl, ACL_OTHER, ACL_UNDEFINED_ID)) { if (!acl) RETRIEVE_ACL(ACL_TYPE_ACCESS); clone_entry(acl, ACL_OTHER, &default_acl, ACL_OTHER); } } /* update mask entries and check if ACLs are valid */ if (acl && acl_modified) { if (acl_equiv_mode(acl, NULL) != 0) { if (!acl_mask_provided && !find_entry(acl, ACL_MASK, ACL_UNDEFINED_ID)) clone_entry(acl, ACL_GROUP_OBJ, &acl, ACL_MASK); if (opt_recalculate != -1 && (!acl_mask_provided || opt_recalculate == 1)) acl_calc_mask(&acl); } error = acl_check(acl, &which_entry); if (error < 0) goto fail; if (error > 0) { acl_text = acl_to_any_text(acl, NULL, ',', 0); fprintf(stderr, gettext("%s: %s: Malformed access ACL " "`%s': %s at entry %d\n"), progname, path_p, acl_text, acl_error(error), which_entry+1); acl_free(acl_text); errors++; goto cleanup; } } if (default_acl && acl_entries(default_acl) != 0 && default_acl_modified) { if (acl_equiv_mode(default_acl, NULL) != 0) { if (!default_acl_mask_provided && !find_entry(default_acl,ACL_MASK,ACL_UNDEFINED_ID)) clone_entry(default_acl, ACL_GROUP_OBJ, &default_acl, ACL_MASK); if (opt_recalculate != -1 && (!default_acl_mask_provided || opt_recalculate == 1)) acl_calc_mask(&default_acl); } error = acl_check(default_acl, &which_entry); if (error < 0) goto fail; if (error > 0) { acl_text = acl_to_any_text(default_acl, NULL, ',', 0); fprintf(stderr, gettext("%s: %s: Malformed default ACL " "`%s': %s at entry %d\n"), progname, path_p, acl_text, acl_error(error), which_entry+1); acl_free(acl_text); errors++; goto cleanup; } } /* Only directores can have default ACLs */ if (default_acl && !S_ISDIR(st->st_mode) && opt_recursive) { /* In recursive mode, ignore default ACLs for files */ acl_free(default_acl); default_acl = NULL; } /* check which ACLs have changed */ if (acl && old_acl && acl_cmp(old_acl, acl) == 0) { acl_free(acl); acl = NULL; } if ((default_acl && old_default_acl && acl_cmp(old_default_acl, default_acl) == 0)) { acl_free(default_acl); default_acl = NULL; } /* update the file system */ if (opt_test) { print_test(stdout, path_p, st, acl, default_acl); goto cleanup; } if (acl) { if (acl_set_file(path_p, ACL_TYPE_ACCESS, acl) != 0) { if (errno == ENOSYS || errno == ENOTSUP) { int saved_errno = errno; mode_t mode; if (acl_equiv_mode(acl, &mode) != 0) { errno = saved_errno; goto fail; } else if (chmod(path_p, mode) != 0) goto fail; } else goto fail; } } if (default_acl) { if (S_ISDIR(st->st_mode)) { if (acl_entries(default_acl) == 0) { if (acl_delete_def_file(path_p) != 0 && errno != ENOSYS && errno != ENOTSUP) goto fail; } else { if (acl_set_file(path_p, ACL_TYPE_DEFAULT, default_acl) != 0) goto fail; } } else { if (acl_entries(default_acl) != 0) { fprintf(stderr, gettext( "%s: %s: Only directories " "can have default ACLs\n"), progname, path_p); errors++; goto cleanup; } } } error = 0; cleanup: if (acl) acl_free(acl); if (old_acl) acl_free(old_acl); if (default_acl) acl_free(default_acl); if (old_default_acl) acl_free(old_default_acl); return errors; fail: fprintf(stderr, "%s: %s: %s\n", progname, path_p, strerror(errno)); errors++; goto cleanup; }
int main(int argc, char *argv[]) { Boolean recalcMask, useDefaultACL; Boolean modifyACL, removeACL, removeDefaultACL, checkValidity; int optCnt, j, opt, numEntries, en; acl_type_t type; char *aclSpec; acl_t acl; acl_entry_t entry; struct AccessControlEntry aclist[MAX_ENTRIES]; if (argc < 2 || strcmp(argv[1], "--help") == 0) usageError(argv[0], NULL, FALSE); /* Parse command-line options */ recalcMask = TRUE; useDefaultACL = FALSE; modifyACL = FALSE; removeACL = FALSE; checkValidity = FALSE; removeDefaultACL = FALSE; optCnt = 0; while ((opt = getopt(argc, argv, "m:x:kdnV:")) != -1) { switch (opt) { case 'm': modifyACL = TRUE; aclSpec = optarg; optCnt++; break; case 'x': removeACL = TRUE; aclSpec = optarg; optCnt++; break; case 'k': removeDefaultACL = TRUE; optCnt++; break; case 'V': checkValidity = TRUE; aclSpec = optarg; optCnt++; break; case 'd': useDefaultACL = TRUE; break; case 'n': recalcMask = FALSE; break; default: usageError(argv[0], "Bad option\n", TRUE); break; } } if (optCnt != 1) usageError(argv[0], "Specify exactly one of -m, -x, -k, or -V\n", TRUE); if (checkValidity && useDefaultACL) usageError(argv[0], "Can't specify -d with -V\n", TRUE); if (checkValidity) { if (parseACL(aclSpec, aclist, TRUE) == -1) { fatal("Bad ACL entry specification"); } else { printf("ACL is valid\n"); exit(EXIT_SUCCESS); } } if (modifyACL || removeACL) { numEntries = parseACL(aclSpec, aclist, modifyACL); if (numEntries == -1) usageError(argv[0], "Bad ACL specification\n", TRUE); } type = useDefaultACL ? ACL_TYPE_DEFAULT : ACL_TYPE_ACCESS; /* Perform the operation on each file argument */ for (j = optind; j < argc; j++) { if (removeDefaultACL) { if (acl_delete_def_file(argv[j]) == -1) errExit("acl_delete_def_file: %s", argv[j]); } else if (modifyACL || removeACL) { acl = acl_get_file(argv[j], type); if (acl == NULL) errExit("acl_get_file"); /* Apply each of the entries in 'aclist' to the current file */ for (en = 0; en < numEntries; en++) { entry = findEntry(acl, aclist[en].tag, aclist[en].qual); if (removeACL) { if (entry != NULL) if (acl_delete_entry(acl, entry) == -1) errExit("acl_delete_entry"); } else { /* modifyACL */ if (entry == NULL) { /* Entry didn't exist in ACL -- create a new entry with required tag and qualifier */ if (acl_create_entry(&acl, &entry) == -1) errExit("acl_create_entry"); if (acl_set_tag_type(entry, aclist[en].tag) == -1) errExit("acl_set_tag_type"); if (aclist[en].tag == ACL_USER || aclist[en].tag == ACL_GROUP) if (acl_set_qualifier(entry, &aclist[en].qual) == -1) errExit("acl_set_qualifier"); } setPerms(entry, aclist[en].perms); } /* Recalculate the mask entry if requested */ if (recalcMask) if (acl_calc_mask(&acl) == -1) errExit("acl_calc_mask"); /* Update the file ACL */ if (acl_valid(acl) == -1) errExit("acl_valid"); if (acl_set_file(argv[j], type, acl) == -1) errExit("acl_set_file"); } if (acl_free(acl) == -1) errExit("acl_free"); } else { fatal("Bad logic!"); } } exit(EXIT_SUCCESS); }
int modify_acl(acl_t *oaclp, acl_entry_t modifier, unsigned int optflags, int position, int inheritance_level, unsigned flag_new_acl, const char* path) { unsigned cpos = 0; acl_entry_t newent = NULL; int dmatch = 0; acl_entry_t rentry = NULL; unsigned retval = 0; acl_t oacl = *oaclp; /* Add the inherited flag if requested by the user*/ if (modifier && (optflags & ACL_INHERIT_FLAG)) { acl_flagset_t mflags; acl_get_flagset_np(modifier, &mflags); acl_add_flag_np(mflags, ACL_ENTRY_INHERITED); acl_set_flagset_np(modifier, mflags); } if (optflags & ACL_SET_FLAG) { if (position != -1) { if (0 != acl_create_entry_np(&oacl, &newent, position)) { // err(1, "acl_create_entry() failed"); fprintf(stderr, "chmod: acl_create_entry() failed: %s\n", strerror(errno)); pthread_exit(NULL); } acl_copy_entry(newent, modifier); } else { /* If an entry exists, add the new permissions to it, else add an * entry in the canonical position. */ /* First, check for a matching entry - if one exists, merge flags */ dmatch = find_matching_entry(oacl, modifier, &rentry, 1); if (dmatch != MATCH_NONE) { if (dmatch == MATCH_EXACT) /* Nothing to be done */ goto ma_exit; if (dmatch == MATCH_PARTIAL) { merge_entry_perms(rentry, modifier); goto ma_exit; } } /* Insert the entry in canonical order */ cpos = find_canonical_position(oacl, modifier); if (0!= acl_create_entry_np(&oacl, &newent, cpos)) { // err(1, "acl_create_entry() failed"); fprintf(stderr, "chmod: acl_create_entry() failed: %s\n", strerror(errno)); pthread_exit(NULL); } acl_copy_entry(newent, modifier); } } else if (optflags & ACL_DELETE_FLAG) { if (flag_new_acl) { fprintf(stderr, "chmod: No ACL present '%s'\n", path); // warnx("No ACL present '%s'", path); retval = 1; } else if (position != -1 ) { if (0 != acl_get_entry(oacl, position, &rentry)) { fprintf(stderr, "chmod: Invalid entry number '%s'\n", path); // 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 { int valid_perms; /* In the event of a partial match, remove the specified perms from the * entry */ 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) { fprintf(stderr, "chmod: Entry not found when attempting delete '%s'\n",path); // warnx("Entry not found when attempting delete '%s'",path); retval = 1; } } } else if (optflags & ACL_REWRITE_FLAG) { acl_entry_t rentry; if (-1 == position) { chmod_usage(); } if (0 == flag_new_acl) { if (0 != acl_get_entry(oacl, position, &rentry)) { // err(1, "Invalid entry number '%s'", path); fprintf(stderr, "chmod: Invalid entry number '%s': %s\n", path, strerror(errno)); pthread_exit(NULL); } if (0 != acl_delete_entry(oacl, rentry)) { // err(1, "Unable to delete entry '%s'", path); fprintf(stderr, "chmod: Unable to delete entry '%s': %s\n", path, strerror(errno)); pthread_exit(NULL); } } if (0!= acl_create_entry_np(&oacl, &newent, position)) { // err(1, "acl_create_entry() failed"); fprintf(stderr, "chmod: acl_create_entry() failed: %s\n", strerror(errno)); pthread_exit(NULL); } acl_copy_entry(newent, modifier); } ma_exit: *oaclp = oacl; return retval; }