/* * remove extended entries */ void remove_ext(acl_t *prev_acl) { acl_t acl_new, acl_old; acl_entry_t entry, entry_new; acl_permset_t perm; acl_tag_t tag; int entry_id, have_mask_entry; if (acl_type == ACL_TYPE_ACCESS) acl_old = acl_dup(prev_acl[ACCESS_ACL]); else acl_old = acl_dup(prev_acl[DEFAULT_ACL]); if (acl_old == NULL) err(1, "acl_dup() failed"); have_mask_entry = 0; acl_new = acl_init(ACL_MAX_ENTRIES); if (acl_new == NULL) err(1, "acl_init() failed"); tag = ACL_UNDEFINED_TAG; /* only save the default user/group/other entries */ entry_id = ACL_FIRST_ENTRY; while (acl_get_entry(acl_old, entry_id, &entry) == 1) { entry_id = ACL_NEXT_ENTRY; if (acl_get_tag_type(entry, &tag) == -1) err(1, "acl_get_tag_type() failed"); switch(tag) { case ACL_USER_OBJ: case ACL_GROUP_OBJ: case ACL_OTHER: if (acl_get_tag_type(entry, &tag) == -1) err(1, "acl_get_tag_type() failed"); if (acl_get_permset(entry, &perm) == -1) err(1, "acl_get_permset() failed"); if (acl_create_entry(&acl_new, &entry_new) == -1) err(1, "acl_create_entry() failed"); if (acl_set_tag_type(entry_new, tag) == -1) err(1, "acl_set_tag_type() failed"); if (acl_set_permset(entry_new, perm) == -1) err(1, "acl_get_permset() failed"); if (acl_copy_entry(entry_new, entry) == -1) err(1, "acl_copy_entry() failed"); break; case ACL_MASK: have_mask_entry = 1; break; default: break; } } if (have_mask_entry && n_flag == 0) { if (acl_calc_mask(&acl_new) == -1) err(1, "acl_calc_mask() failed"); } else { have_mask = 1; } 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; } }
static acl_t _posix1e_acl_strip_np(const acl_t aclp, int recalculate_mask) { acl_t acl_new, acl_old; acl_entry_t entry, entry_new; acl_permset_t perm; acl_tag_t tag; int entry_id, have_mask_entry; assert(_acl_brand(aclp) == ACL_BRAND_POSIX); acl_old = acl_dup(aclp); if (acl_old == NULL) return (NULL); assert(_acl_brand(acl_old) == ACL_BRAND_POSIX); have_mask_entry = 0; acl_new = acl_init(ACL_MAX_ENTRIES); if (acl_new == NULL) return (NULL); tag = ACL_UNDEFINED_TAG; /* only save the default user/group/other entries */ entry_id = ACL_FIRST_ENTRY; while (acl_get_entry(acl_old, entry_id, &entry) == 1) { entry_id = ACL_NEXT_ENTRY; assert(_entry_brand(entry) == ACL_BRAND_POSIX); if (acl_get_tag_type(entry, &tag) == -1) return (NULL); switch(tag) { case ACL_USER_OBJ: case ACL_GROUP_OBJ: case ACL_OTHER: if (acl_get_tag_type(entry, &tag) == -1) return (NULL); if (acl_get_permset(entry, &perm) == -1) return (NULL); if (acl_create_entry(&acl_new, &entry_new) == -1) return (NULL); if (acl_set_tag_type(entry_new, tag) == -1) return (NULL); if (acl_set_permset(entry_new, perm) == -1) return (NULL); if (acl_copy_entry(entry_new, entry) == -1) return (NULL); assert(_entry_brand(entry_new) == ACL_BRAND_POSIX); break; case ACL_MASK: have_mask_entry = 1; break; default: break; } } assert(_acl_brand(acl_new) == ACL_BRAND_POSIX); if (have_mask_entry && recalculate_mask) { if (acl_calc_mask(&acl_new) == -1) return (NULL); } return (acl_new); }
static int CheckPosixLinuxACEs(EvalContext *ctx, Rlist *aces, AclMethod method, const char *file_path, acl_type_t acl_type, Attributes a, const Promise *pp, PromiseResult *result) { acl_t acl_existing; acl_t acl_new; acl_t acl_tmp; acl_entry_t ace_parsed; acl_entry_t ace_current; acl_permset_t perms; char *cf_ace; int retv; int has_mask; Rlist *rp; char *acl_type_str; acl_new = NULL; acl_existing = NULL; acl_tmp = NULL; has_mask = false; acl_type_str = acl_type == ACL_TYPE_ACCESS ? "Access" : "Default"; // read existing acl if ((acl_existing = acl_get_file(file_path, acl_type)) == NULL) { Log(LOG_LEVEL_VERBOSE, "No ACL for '%s' could be read. (acl_get_file: %s)", file_path, GetErrorStr()); return false; } // allocate memory for temp ace (it needs to reside in a temp acl) if ((acl_tmp = acl_init(1)) == NULL) { Log(LOG_LEVEL_ERR, "New ACL could not be allocated (acl_init: %s)", GetErrorStr()); acl_free((void *) acl_existing); return false; } if (acl_create_entry(&acl_tmp, &ace_parsed) != 0) { Log(LOG_LEVEL_ERR, "New ACL could not be allocated (acl_create_entry: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); return false; } // copy existing aces if we are appending if (method == ACL_METHOD_APPEND) { if ((acl_new = acl_dup(acl_existing)) == NULL) { Log(LOG_LEVEL_ERR, "Error copying existing ACL (acl_dup: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); return false; } } else // overwrite existing acl { if ((acl_new = acl_init(5)) == NULL) // TODO: Always OK with 5 here ? { Log(LOG_LEVEL_ERR, "New ACL could not be allocated (acl_init: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); return false; } } for (rp = aces; rp != NULL; rp = rp->next) { cf_ace = RlistScalarValue(rp); if (!ParseEntityPosixLinux(&cf_ace, ace_parsed, &has_mask)) { Log(LOG_LEVEL_ERR, "Error parsing entity in 'cf_ace'."); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } // check if an ACE with this entity-type and id already exist in the Posix Linux ACL ace_current = FindACE(acl_new, ace_parsed); // create new entry in ACL if it did not exist if (ace_current == NULL) { if (acl_create_entry(&acl_new, &ace_current) != 0) { Log(LOG_LEVEL_ERR, "Failed to allocate ace (acl_create_entry: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } // copy parsed entity-type and id if (acl_copy_entry(ace_current, ace_parsed) != 0) { Log(LOG_LEVEL_ERR, "Error copying Linux entry in 'cf_ace' (acl_copy_entry: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } // clear ace_current's permissions to avoid ace_parsed from last // loop iteration to be taken into account when applying mode below if ((acl_get_permset(ace_current, &perms) != 0)) { Log(LOG_LEVEL_ERR, "Error obtaining permset for 'ace_current' (acl_get_permset: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } if (acl_clear_perms(perms) != 0) { Log(LOG_LEVEL_ERR, "Error clearing permset for 'ace_current'. (acl_clear_perms: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } } // mode string should be prefixed with an entry seperator if (*cf_ace != ':') { Log(LOG_LEVEL_ERR, "No separator before mode-string in 'cf_ace'"); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } cf_ace += 1; if (acl_get_permset(ace_current, &perms) != 0) { Log(LOG_LEVEL_ERR, "Error obtaining permset for 'cf_ace'"); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } if (!ParseModePosixLinux(cf_ace, perms)) { Log(LOG_LEVEL_ERR, "Error parsing mode-string in 'cf_ace'"); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } // only allow permissions exist on posix acls, so we do // not check what follows next } // if no mask exists, calculate one (or both?): run acl_calc_mask and add one if (!has_mask) { if (acl_calc_mask(&acl_new) != 0) { Log(LOG_LEVEL_ERR, "Error calculating new acl mask"); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } } if ((retv = ACLEquals(acl_existing, acl_new)) == -1) { Log(LOG_LEVEL_ERR, "Error while comparing existing and new ACL, unable to repair."); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } if (retv == 1) // existing and new acl differ, update existing { switch (a.transaction.action) { case cfa_warn: cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_WARN, pp, a, "%s ACL on file '%s' needs to be updated", acl_type_str, file_path); *result = PromiseResultUpdate(*result, PROMISE_RESULT_WARN); break; case cfa_fix: if (!DONTDO) { if ((retv = acl_set_file(file_path, acl_type, acl_new)) != 0) { Log(LOG_LEVEL_ERR, "Error setting new %s ACL on file '%s' (acl_set_file: %s), are required ACEs present ?", acl_type_str, file_path, GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } } cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_CHANGE, pp, a, "%s ACL on '%s' successfully changed.", acl_type_str, file_path); *result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE); break; default: ProgrammingError("CFEngine: internal error: illegal file action"); } } else { cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_NOOP, pp, a, "'%s' ACL on '%s' needs no modification.", acl_type_str, file_path); } acl_free((void *) acl_existing); acl_free((void *) acl_new); acl_free((void *) acl_tmp); return true; }
/* * merge an ACL into existing file's ACL */ int merge_acl(acl_t acl, acl_t *prev_acl, const char *filename) { acl_entry_t entry, entry_new; acl_permset_t permset; acl_t acl_new; acl_tag_t tag, tag_new; acl_entry_type_t entry_type, entry_type_new; acl_flagset_t flagset; int entry_id, entry_id_new, have_entry, had_entry, entry_number = 0; int acl_brand, prev_acl_brand; 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 merged is %s", filename, brand_name(prev_acl_brand), brand_name(acl_brand)); return (-1); } acl_new = acl_dup(*prev_acl); if (acl_new == NULL) err(1, "%s: acl_dup() failed", filename); entry_id = ACL_FIRST_ENTRY; while (acl_get_entry(acl, entry_id, &entry) == 1) { entry_id = ACL_NEXT_ENTRY; have_entry = 0; had_entry = 0; /* keep track of existing ACL_MASK entries */ if (acl_get_tag_type(entry, &tag) == -1) err(1, "%s: acl_get_tag_type() failed - " "invalid ACL entry", filename); if (tag == ACL_MASK) have_mask = 1; /* check against the existing ACL entries */ entry_id_new = ACL_FIRST_ENTRY; while (acl_get_entry(acl_new, entry_id_new, &entry_new) == 1) { entry_id_new = ACL_NEXT_ENTRY; if (acl_get_tag_type(entry, &tag) == -1) err(1, "%s: acl_get_tag_type() failed", filename); if (acl_get_tag_type(entry_new, &tag_new) == -1) err(1, "%s: acl_get_tag_type() failed", filename); if (tag != tag_new) continue; /* * For NFSv4, in addition to "tag" and "id" we also * compare "entry_type". */ if (acl_brand == ACL_BRAND_NFS4) { if (acl_get_entry_type_np(entry, &entry_type)) err(1, "%s: acl_get_entry_type_np() " "failed", filename); if (acl_get_entry_type_np(entry_new, &entry_type_new)) err(1, "%s: acl_get_entry_type_np() " "failed", filename); if (entry_type != entry_type_new) continue; } switch(tag) { case ACL_USER: case ACL_GROUP: have_entry = merge_user_group(&entry, &entry_new, acl_brand); if (have_entry == 0) break; /* FALLTHROUGH */ case ACL_USER_OBJ: case ACL_GROUP_OBJ: case ACL_OTHER: case ACL_MASK: case ACL_EVERYONE: if (acl_get_permset(entry, &permset) == -1) err(1, "%s: acl_get_permset() failed", filename); if (acl_set_permset(entry_new, permset) == -1) err(1, "%s: acl_set_permset() failed", filename); if (acl_brand == ACL_BRAND_NFS4) { if (acl_get_entry_type_np(entry, &entry_type)) err(1, "%s: acl_get_entry_type_np() failed", filename); if (acl_set_entry_type_np(entry_new, entry_type)) err(1, "%s: acl_set_entry_type_np() failed", filename); if (acl_get_flagset_np(entry, &flagset)) err(1, "%s: acl_get_flagset_np() failed", filename); if (acl_set_flagset_np(entry_new, flagset)) err(1, "%s: acl_set_flagset_np() failed", filename); } had_entry = have_entry = 1; break; default: /* should never be here */ errx(1, "%s: invalid tag type: %i", filename, tag); break; } } /* if this entry has not been found, it must be new */ if (had_entry == 0) { /* * NFSv4 ACL entries must be prepended to the ACL. * Appending them at the end makes no sense, since * in most cases they wouldn't even get evaluated. */ if (acl_brand == ACL_BRAND_NFS4) { if (acl_create_entry_np(&acl_new, &entry_new, entry_number) == -1) { warn("%s: acl_create_entry_np() failed", filename); acl_free(acl_new); return (-1); } /* * Without this increment, adding several * entries at once, for example * "setfacl -m user:1:r:allow,user:2:r:allow", * would make them appear in reverse order. */ entry_number++; } else { if (acl_create_entry(&acl_new, &entry_new) == -1) { warn("%s: acl_create_entry() failed", filename); acl_free(acl_new); return (-1); } } if (acl_copy_entry(entry_new, entry) == -1) err(1, "%s: acl_copy_entry() failed", filename); } } acl_free(*prev_acl); *prev_acl = acl_new; return (0); }
/* merge 2 acl's together */ static int merge_acl(acl_t acl, acl_t *prev_acl, const char *path) { acl_t acl_new; acl_permset_t permset; acl_flagset_t flagset; acl_tag_t tag, tag_new; acl_entry_t entry, entry_new; acl_entry_type_t entry_type, entry_type_new; int entry_id, entry_id_new, have_entry, had_entry, entry_number = 0; if ((acl_new = acl_dup(*prev_acl)) == NULL) err(EX_OSERR, "%s: acl_dup() failed", path); entry_id = ACL_FIRST_ENTRY; while (acl_get_entry(acl, entry_id, &entry) == 1) { entry_id = ACL_NEXT_ENTRY; have_entry = had_entry = 0; entry_id_new = ACL_FIRST_ENTRY; while (acl_get_entry(acl_new, entry_id_new, &entry_new) > 0) { entry_id_new = ACL_NEXT_ENTRY; if (acl_get_tag_type(entry, &tag) < 0) err(EX_OSERR, "%s: acl_get_tag_type() failed", path); if (acl_get_tag_type(entry_new, &tag_new) < 0) err(EX_OSERR, "%s: acl_get_tag_type() failed", path); if (tag != tag_new) continue; if (acl_get_entry_type_np(entry, &entry_type) < 0) err(EX_OSERR, "%s: acl_get_entry_type_np() failed", path); if (acl_get_entry_type_np(entry_new, &entry_type_new) < 0) err(EX_OSERR, "%s: acl_get_entry_type_np() failed", path); if (entry_type != entry_type_new) continue; switch(tag) { case ACL_USER: case ACL_GROUP: have_entry = merge_user_group(&entry, &entry_new); if (have_entry == 0) break; case ACL_USER_OBJ: case ACL_GROUP_OBJ: case ACL_EVERYONE: merge_acl_entries(&entry, &entry_new); had_entry = have_entry = 1; break; default: errx(EX_OSERR, "%s: invalid tag type: %i", path, tag); break; } } if (had_entry == 0) { if (acl_create_entry_np(&acl_new, &entry_new, entry_number) < 0) { warn("%s: acl_create_entry_np() failed", path); acl_free(acl_new); return (-1); } entry_number++; if (acl_copy_entry(entry_new, entry) < 0) err(EX_OSERR, "%s: acl_copy_entry() failed", path); } } acl_free(*prev_acl); *prev_acl = acl_new; return (0); }
/* set the appropriate mask the given ACL's */ int set_acl_mask(acl_t *prev_acl, const char *filename) { acl_entry_t entry; acl_t acl; acl_tag_t tag; int entry_id; entry = NULL; /* * ... if a mask entry is specified, then the permissions of the mask * entry in the resulting ACL shall be set to the permissions in the * specified ACL mask entry. */ if (have_mask) return (0); acl = acl_dup(*prev_acl); if (acl == NULL) err(1, "%s: acl_dup() failed", filename); if (n_flag == 0) { /* * If no mask entry is specified and the -n option is not * specified, then the permissions of the resulting ACL mask * entry shall be set to the union of the permissions * associated with all entries which belong to the file group * class in the resulting ACL */ if (acl_calc_mask(&acl)) { warn("%s: acl_calc_mask() failed", filename); acl_free(acl); return (-1); } } else { /* * If no mask entry is specified and the -n option is * specified, then the permissions of the resulting ACL * mask entry shall remain unchanged ... */ 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) { acl_free(acl); return (0); } } /* * If no mask entry is specified, the -n option is specified, * and no ACL mask entry exists in the ACL associated with the * file, then write an error message to standard error and * continue with the next file. */ warnx("%s: warning: no mask entry", filename); acl_free(acl); return (0); } acl_free(*prev_acl); *prev_acl = acl_dup(acl); acl_free(acl); return (0); }
int 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; extern int chmod_fflag; /* XXX acl_get_file() returns a zero entry ACL if an ACL was previously * associated with the file, and has had its entries removed. * However, POSIX 1003.1e states that a zero entry ACL should be * returned if the caller asks for ACL_TYPE_DEFAULT, and no ACL is * associated with the path; it * does not specifically state that a request for ACL_TYPE_EXTENDED * should not return a zero entry ACL, however. */ /* Determine if we've been given a zero entry ACL, or create an ACL if * none exists. There are some issues to consider here: Should we create * a zero-entry ACL for a delete or check canonicity operation? */ if (path == NULL) chmod_usage(); if (optflags & ACL_CLEAR_FLAG) { filesec_t fsec = filesec_init(); if (fsec == NULL) { // err(1, "filesec_init() failed"); fprintf(stderr, "chmod: filesec_init() failed: %s\n", strerror(errno)); pthread_exit(NULL); } if (filesec_set_property(fsec, FILESEC_ACL, _FILESEC_REMOVE_ACL) != 0) { // err(1, "filesec_set_property() failed"); fprintf(stderr, "chmod: filesec_set_property() failed: %s\n", strerror(errno)); pthread_exit(NULL); } if (follow) { if (chmodx_np(path, fsec) != 0) { if (!chmod_fflag) { // warn("Failed to clear ACL on file %s", path); fprintf(stderr, "chmod: Failed to clear ACL on file %s: %s\n", path, strerror(errno)); } retval = 1; } } else { int fd = open(path, O_SYMLINK); if (fd != -1) { if (fchmodx_np(fd, fsec) != 0) { if (!chmod_fflag) { fprintf(stderr, "chmod: Failed to clear ACL on file %s: %s\n", path, strerror(errno)); // warn("Failed to clear ACL on file %s", path); } retval = 1; } close(fd); } else { if (!chmod_fflag) { // warn("Failed to open file %s", path); fprintf(stderr, "chmod: Failed to open file %s: %s\n", path, strerror(errno)); } retval = 1; } } filesec_free(fsec); return (retval); } if (optflags & ACL_FROM_STDIN) { oacl = acl_dup(modifier); } 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) { // err(1, "acl_init() failed"); fprintf(stderr, "chmod: acl_init() failed: %s\n", strerror(errno)); pthread_exit(NULL); } flag_new_acl = 1; position = 0; } if ((0 == flag_new_acl) && (optflags & (ACL_REMOVE_INHERIT_FLAG | ACL_REMOVE_INHERITED_ENTRIES))) { acl_t facl = NULL; if ((facl = acl_init(1)) == NULL) { //err(1, "acl_init() failed"); fprintf(stderr, "chmod: acl_init() failed: %s\n", strerror(errno)); pthread_exit(NULL); } for (aindex = 0; acl_get_entry(oacl, (entry == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY), &entry) == 0; aindex++) { acl_flagset_t eflags; acl_entry_t fent = NULL; if (acl_get_flagset_np(entry, &eflags) != 0) { fprintf(stderr, "chmod: Unable to obtain flagset: %s\n", strerror(errno)); pthread_exit(NULL); // err(1, "Unable to obtain flagset"); } if (acl_get_flag_np(eflags, ACL_ENTRY_INHERITED)) { if (optflags & ACL_REMOVE_INHERIT_FLAG) { acl_delete_flag_np(eflags, ACL_ENTRY_INHERITED); acl_set_flagset_np(entry, eflags); acl_create_entry(&facl, &fent); acl_copy_entry(fent, entry); } } else { acl_create_entry(&facl, &fent); acl_copy_entry(fent, entry); } } if (oacl) acl_free(oacl); oacl = facl; } else if (optflags & ACL_TO_STDOUT) { ssize_t len; /* need to get printacl() from ls(1) */ char *text = acl_to_text(oacl, &len); puts(text); acl_free(text); } else if (optflags & ACL_CHECK_CANONICITY) { if (flag_new_acl) { // warnx("No ACL currently associated with file '%s'", path); fprintf(stderr, "chmod: No ACL currently associated with file '%s'\n", path); } retval = is_canonical(oacl); } else if ((optflags & ACL_SET_FLAG) && (position == -1) && (!is_canonical(oacl))) { // warnx("The specified file '%s' does not have an ACL in canonical order, please specify a position with +a# ", path); fprintf(stderr, "chmod: The specified file '%s' does not have an ACL in canonical order, please specify a position with +a# \n", path); retval = 1; } else if (((optflags & ACL_DELETE_FLAG) && (position != -1)) || (optflags & ACL_CHECK_CANONICITY)) { retval = modify_acl(&oacl, NULL, optflags, position, 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); fprintf(stderr, "chmod: No ACL currently associated with file '%s'\n", path); retval = 1; } else { if (!modifier) { /* avoid bus error in acl_get_entry */ // errx(1, "Internal error: modifier should not be NULL"); fprintf(stderr, "Internal error: modifier should not be NULL\n"); pthread_exit(NULL); } for (aindex = 0; acl_get_entry(modifier, (entry == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY), &entry) == 0; aindex++) { retval += modify_acl(&oacl, entry, optflags, position, inheritance_level, flag_new_acl, path); } } } /* XXX Potential race here, since someone else could've modified or * read the ACL on this file (with the intention of modifying it) in * the interval from acl_get_file() to acl_set_file(); we can * minimize one aspect of this window by comparing the original acl * to a fresh one from acl_get_file() but we could consider a * "changeset" mechanism, common locking strategy, or kernel * supplied reservation mechanism to prevent this race. */ 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 (!chmod_fflag) fprintf(stderr, "chmod: Failed to set ACL on file '%s': %s\n", path, strerror(errno)); // warn("Failed to set ACL on file '%s'", path); retval = 1; } } if (oacl) acl_free(oacl); return retval; }
static int open_listener(struct listen_config_t *lc) { struct listen_t *l; int i; l = listener_alloc(); l->id = lc->id; l->hidden = lc->hidden; l->corepeer = lc->corepeer; l->client_flags = lc->client_flags; l->clients_max = lc->clients_max; l->portaccount = port_accounter_alloc(); /* Pick first of the AIs for this listen definition */ l->addr_s = strsockaddr( lc->ai->ai_addr, lc->ai->ai_addrlen ); l->name = hstrdup(lc->name); l->portnum = lc->portnum; l->ai_protocol = lc->ai->ai_protocol; l->listener_id = keyhash(l->addr_s, strlen(l->addr_s), 0); l->listener_id = keyhash(&lc->ai->ai_socktype, sizeof(lc->ai->ai_socktype), l->listener_id); l->listener_id = keyhash(&lc->ai->ai_protocol, sizeof(lc->ai->ai_protocol), l->listener_id); hlog(LOG_DEBUG, "Opening listener %d/%d '%s': %s", lc->id, l->listener_id, lc->name, l->addr_s); if (lc->ai->ai_socktype == SOCK_DGRAM && lc->ai->ai_protocol == IPPROTO_UDP) { /* UDP listenting is not quite same as TCP listening.. */ i = open_udp_listener(l, lc->ai); } else if (lc->ai->ai_socktype == SOCK_STREAM && lc->ai->ai_protocol == IPPROTO_TCP) { /* TCP listenting... */ i = open_tcp_listener(l, lc->ai, "TCP"); #ifdef USE_SCTP } else if (lc->ai->ai_socktype == SOCK_STREAM && lc->ai->ai_protocol == IPPROTO_SCTP) { i = open_tcp_listener(l, lc->ai, "SCTP"); if (i >= 0) i = sctp_set_listen_params(l); #endif } else { hlog(LOG_ERR, "Unsupported listener protocol for '%s'", l->name); listener_free(l); return -1; } if (i < 0) { hlog(LOG_DEBUG, "... failed"); listener_free(l); return -1; } hlog(LOG_DEBUG, "... ok, bound"); /* Set up an SSL context if necessary */ #ifdef USE_SSL if (lc->keyfile && lc->certfile) { l->ssl = ssl_alloc(); if (ssl_create(l->ssl, (void *)l)) { hlog(LOG_ERR, "Failed to create SSL context for '%s*': %s", lc->name, l->addr_s); listener_free(l); return -1; } if (ssl_certificate(l->ssl, lc->certfile, lc->keyfile)) { hlog(LOG_ERR, "Failed to load SSL key and certificates for '%s*': %s", lc->name, l->addr_s); listener_free(l); return -1; } /* optional client cert validation */ if (lc->cafile) { if (ssl_ca_certificate(l->ssl, lc->cafile, 2)) { hlog(LOG_ERR, "Failed to load trusted SSL CA certificates for '%s*': %s", lc->name, l->addr_s); listener_free(l); return -1; } } hlog(LOG_INFO, "SSL initialized for '%s': %s%s", lc->name, l->addr_s, (lc->cafile) ? " (client validation enabled)" : ""); } #endif /* Copy access lists */ if (lc->acl) l->acl = acl_dup(lc->acl); /* Copy filter definitions */ listener_copy_filters(l, lc); hlog(LOG_DEBUG, "... adding %s to listened sockets", l->addr_s); // put (first) in the list of listening sockets l->next = listen_list; l->prevp = &listen_list; if (listen_list) listen_list->prevp = &l->next; listen_list = l; return 0; }
/* * acl_calc_mask() (23.4.2): calculate and set the permissions * associated with the ACL_MASK ACL entry. If the ACL already * contains an ACL_MASK entry, its permissions shall be * overwritten; if not, one shall be added. */ int acl_calc_mask(acl_t *acl_p) { struct acl *acl_int, *acl_int_new; acl_t acl_new; int i, mask_mode, mask_num; /* * (23.4.2.4) requires acl_p to point to a pointer to a valid ACL. * Since one of the primary reasons to use this function would be * to calculate the appropriate mask to obtain a valid ACL, we only * perform sanity checks here and validate the ACL prior to * returning. */ if (acl_p == NULL || *acl_p == NULL) { errno = EINVAL; return (-1); } if (!_acl_brand_may_be(*acl_p, ACL_BRAND_POSIX)) { errno = EINVAL; return (-1); } _acl_brand_as(*acl_p, ACL_BRAND_POSIX); acl_int = &(*acl_p)->ats_acl; if ((acl_int->acl_cnt < 3) || (acl_int->acl_cnt > ACL_MAX_ENTRIES)) { errno = EINVAL; return (-1); } acl_new = acl_dup(*acl_p); if (acl_new == NULL) return (-1); acl_int_new = &acl_new->ats_acl; mask_mode = 0; mask_num = -1; /* gather permissions and find a mask entry */ for (i = 0; i < acl_int_new->acl_cnt; i++) { switch(acl_int_new->acl_entry[i].ae_tag) { case ACL_USER: case ACL_GROUP: case ACL_GROUP_OBJ: mask_mode |= acl_int_new->acl_entry[i].ae_perm & ACL_PERM_BITS; break; case ACL_MASK: mask_num = i; break; } } /* if a mask entry already exists, overwrite the perms */ if (mask_num != -1) acl_int_new->acl_entry[mask_num].ae_perm = mask_mode; else { /* if no mask exists, check acl_cnt... */ if (acl_int_new->acl_cnt == ACL_MAX_ENTRIES) { errno = ENOMEM; acl_free(acl_new); return (-1); } /* ...and add the mask entry */ acl_int_new->acl_entry[acl_int_new->acl_cnt].ae_tag = ACL_MASK; acl_int_new->acl_entry[acl_int_new->acl_cnt].ae_id = ACL_UNDEFINED_ID; acl_int_new->acl_entry[acl_int_new->acl_cnt].ae_perm = mask_mode; acl_int_new->acl_cnt++; } if (acl_valid(acl_new) == -1) { errno = EINVAL; acl_free(acl_new); return (-1); } **acl_p = *acl_new; acl_free(acl_new); return (0); }