int setacl(const char *pathp, int size, aclent_t *aclpbuf) { acl_t acl = NULL, default_acl = NULL, *current; acl_entry_t entry; acl_permset_t permset; int i, result, default_count = 0; struct stat st; if (stat(pathp, &st) != 0) { return -1; } for (i = 0; i < size; i++) { if (aclpbuf[i].a_type & ACL_DEFAULT) { default_count++; } } acl = acl_init(size - default_count); if (default_count > 0) { default_acl = acl_init(default_count); } for (i = 0; i < size; i++) { if (aclpbuf[i].a_type & ACL_DEFAULT) { current = &default_acl; } else { current = &acl; } acl_create_entry(current, &entry); acl_get_permset(entry, &permset); setmode(&permset, aclpbuf[i].a_perm); acl_set_tag_type(entry, aclpbuf[i].a_type & ~ACL_DEFAULT); acl_set_qualifier(entry, &aclpbuf[i].a_id); acl_free(entry); } result = acl_set_file(pathp, ACL_TYPE_ACCESS, acl); if (result != 0 && (errno == ENOSYS || errno == ENOTSUP)) { if (default_acl != NULL) { return result; } mode_t mode; if (acl_equiv_mode(acl, &mode) == 0) { result = chmod(pathp, mode); } } else if ((result == 0) && S_ISDIR(st.st_mode)) { if (default_acl == NULL) { result = acl_delete_def_file(pathp); } else { result = acl_set_file(pathp, ACL_TYPE_DEFAULT, default_acl); acl_free(default_acl); } } acl_free(acl); return result; }
/* Add the perms specified in modifier to rentry */ static int merge_entry_perms(acl_entry_t rentry, acl_entry_t modifier) { acl_permset_t rperms, mperms; acl_flagset_t rflags, mflags; int i; if ((acl_get_permset(rentry, &rperms) != 0) || (acl_get_flagset_np(rentry, &rflags) != 0) || (acl_get_permset(modifier, &mperms) != 0) || (acl_get_flagset_np(modifier, &mflags) != 0)) { // err(1, "error computing ACL modification"); fprintf(stderr, "chmod: error computing ACL modification: %s\n", strerror(errno)); pthread_exit(NULL); } for (i = 0; acl_perms[i].name != NULL; i++) { if (acl_get_perm_np(mperms, acl_perms[i].perm)) acl_add_perm(rperms, acl_perms[i].perm); } for (i = 0; acl_flags[i].name != NULL; i++) { if (acl_get_flag_np(mflags, acl_flags[i].flag)) acl_add_flag_np(rflags, acl_flags[i].flag); } acl_set_permset(rentry, rperms); acl_set_flagset_np(rentry, rflags); return 0; }
/* Remove all perms specified in modifier from rentry*/ int 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) || (acl_get_flagset_np(rentry, &rflags) != 0) || (acl_get_permset(modifier, &mperms) != 0) || (acl_get_flagset_np(modifier, &mflags) != 0)) { // err(1, "error computing ACL modification"); fprintf(stderr, "chmod: error computing ACL modification: %s\n", strerror(errno)); pthread_exit(NULL); } 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)) acl_delete_flag_np(rflags, acl_flags[i].flag); } acl_set_permset(rentry, rperms); acl_set_flagset_np(rentry, rflags); return 0; }
/* Add the perms specified in modifier to rentry */ static int merge_entry_perms(acl_entry_t rentry, acl_entry_t modifier) { acl_permset_t rperms, mperms; acl_flagset_t rflags, mflags; int i; if ((acl_get_permset(rentry, &rperms) != 0) || (acl_get_flagset_np(rentry, &rflags) != 0) || (acl_get_permset(modifier, &mperms) != 0) || (acl_get_flagset_np(modifier, &mflags) != 0)) err(1, "error computing ACL modification"); for (i = 0; acl_perms[i].name != NULL; i++) { if (acl_get_perm_np(mperms, acl_perms[i].perm)) acl_add_perm(rperms, acl_perms[i].perm); } for (i = 0; acl_flags[i].name != NULL; i++) { if (acl_get_flag_np(mflags, acl_flags[i].flag)) acl_add_flag_np(rflags, acl_flags[i].flag); } acl_set_permset(rentry, rperms); acl_set_flagset_np(rentry, rflags); return 0; }
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; }
/* Compares two ACL entries for equality */ int compare_acl_entries(acl_entry_t a, acl_entry_t b) { acl_tag_t atag, btag; 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 (compare != 0) return MATCH_NONE; if (0 != acl_get_tag_type(a, &atag)) { // err(1, "No tag type present in entry"); fprintf(stderr, "chmod: No tag type present in entry: %s\n", strerror(errno)); pthread_exit(NULL); } if (0!= acl_get_tag_type(b, &btag)) { // err(1, "No tag type present in entry"); fprintf(stderr, "chmod: No tag type present in entry: %s\n", strerror(errno)); pthread_exit(NULL); } if (atag != btag) return MATCH_NONE; if ((acl_get_permset(a, &aperms) != 0) || (acl_get_flagset_np(a, &aflags) != 0) || (acl_get_permset(b, &bperms) != 0) || (acl_get_flagset_np(b, &bflags) != 0)) { // err(1, "error fetching permissions"); fprintf(stderr, "chmod: error fetching permissions: %s\n", strerror(errno)); pthread_exit(NULL); } pcmp = compare_acl_permsets(aperms, bperms); fcmp = compare_acl_flagsets(aflags, bflags); if ((pcmp == MATCH_NONE) || (fcmp == MATCH_NONE)) return(MATCH_PARTIAL); else return(MATCH_EXACT); }
acl_entry_get_perm(acl_entry_t aclent) #endif { int permset = 0; #if HAVE_POSIX_ACL acl_permset_t opaque_ps; #endif #if HAVE_SUN_ACL if (aclent->a_perm & 1) permset |= ARCHIVE_ENTRY_ACL_EXECUTE; if (aclent->a_perm & 2) permset |= ARCHIVE_ENTRY_ACL_WRITE; if (aclent->a_perm & 4) permset |= ARCHIVE_ENTRY_ACL_READ; #else /* translate the silly opaque permset to a bitmap */ acl_get_permset(aclent, &opaque_ps); if (ACL_GET_PERM(opaque_ps, ACL_EXECUTE)) permset |= ARCHIVE_ENTRY_ACL_EXECUTE; if (ACL_GET_PERM(opaque_ps, ACL_WRITE)) permset |= ARCHIVE_ENTRY_ACL_WRITE; if (ACL_GET_PERM(opaque_ps, ACL_READ)) permset |= ARCHIVE_ENTRY_ACL_READ; #endif return permset; }
static int smb_acl_set_mode(acl_entry_t entry, SMB_ACL_PERM_T perm) { int ret; acl_permset_t permset; if ((ret = acl_get_permset(entry, &permset)) != 0) { return ret; } if ((ret = acl_clear_perms(permset)) != 0) { return ret; } if ((perm & SMB_ACL_READ) && ((ret = acl_add_perm(permset, ACL_READ)) != 0)) { return ret; } if ((perm & SMB_ACL_WRITE) && ((ret = acl_add_perm(permset, ACL_WRITE)) != 0)) { return ret; } if ((perm & SMB_ACL_EXECUTE) && ((ret = acl_add_perm(permset, ACL_EXECUTE)) != 0)) { return ret; } return acl_set_permset(entry, permset); }
/** * 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; }
/* * Translate POSIX.1e ACL into libarchive internal structure. */ static void setup_acl_posix1e(struct archive_read_disk *a, struct archive_entry *entry, acl_t acl, int archive_entry_acl_type) { acl_tag_t acl_tag; acl_entry_t acl_entry; acl_permset_t acl_permset; int s, ae_id, ae_tag, ae_perm; const char *ae_name; s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry); while (s == 1) { ae_id = -1; ae_name = NULL; acl_get_tag_type(acl_entry, &acl_tag); if (acl_tag == ACL_USER) { ae_id = (int)*(uid_t *)acl_get_qualifier(acl_entry); ae_name = archive_read_disk_uname(&a->archive, ae_id); ae_tag = ARCHIVE_ENTRY_ACL_USER; } else if (acl_tag == ACL_GROUP) { ae_id = (int)*(gid_t *)acl_get_qualifier(acl_entry); ae_name = archive_read_disk_gname(&a->archive, ae_id); ae_tag = ARCHIVE_ENTRY_ACL_GROUP; } else if (acl_tag == ACL_MASK) { ae_tag = ARCHIVE_ENTRY_ACL_MASK; } else if (acl_tag == ACL_USER_OBJ) { ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ; } else if (acl_tag == ACL_GROUP_OBJ) { ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; } else if (acl_tag == ACL_OTHER) { ae_tag = ARCHIVE_ENTRY_ACL_OTHER; } else { /* Skip types that libarchive can't support. */ continue; } acl_get_permset(acl_entry, &acl_permset); ae_perm = 0; /* * acl_get_perm() is spelled differently on different * platforms; see above. */ if (ACL_GET_PERM(acl_permset, ACL_EXECUTE)) ae_perm |= ARCHIVE_ENTRY_ACL_EXECUTE; if (ACL_GET_PERM(acl_permset, ACL_READ)) ae_perm |= ARCHIVE_ENTRY_ACL_READ; if (ACL_GET_PERM(acl_permset, ACL_WRITE)) ae_perm |= ARCHIVE_ENTRY_ACL_WRITE; archive_entry_acl_add_entry(entry, archive_entry_acl_type, ae_perm, ae_tag, ae_id, ae_name); s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); } }
static int acl_match(acl_entry_t aclent, struct myacl_t *myacl) { gid_t g, *gp; uid_t u, *up; acl_tag_t tag_type; acl_permset_t opaque_ps; int permset = 0; acl_get_tag_type(aclent, &tag_type); /* translate the silly opaque permset to a bitmap */ acl_get_permset(aclent, &opaque_ps); if (acl_get_perm_np(opaque_ps, ACL_EXECUTE)) permset |= ARCHIVE_ENTRY_ACL_EXECUTE; if (acl_get_perm_np(opaque_ps, ACL_WRITE)) permset |= ARCHIVE_ENTRY_ACL_WRITE; if (acl_get_perm_np(opaque_ps, ACL_READ)) permset |= ARCHIVE_ENTRY_ACL_READ; if (permset != myacl->permset) return (0); switch (tag_type) { case ACL_USER_OBJ: if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ) return (0); break; case ACL_USER: if (myacl->tag != ARCHIVE_ENTRY_ACL_USER) return (0); up = acl_get_qualifier(aclent); u = *up; acl_free(up); if ((uid_t)myacl->qual != u) return (0); break; case ACL_GROUP_OBJ: if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ) return (0); break; case ACL_GROUP: if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP) return (0); gp = acl_get_qualifier(aclent); g = *gp; acl_free(gp); if ((gid_t)myacl->qual != g) return (0); break; case ACL_MASK: if (myacl->tag != ARCHIVE_ENTRY_ACL_MASK) return (0); break; case ACL_OTHER: if (myacl->tag != ARCHIVE_ENTRY_ACL_OTHER) return (0); break; } return (1); }
void acl_perm_str(acl_entry_t entry, char *str) { acl_permset_t permset; int n; acl_get_permset(entry, &permset); for (n = 0; n < (int) ACL_PERMS; n++) { str[n] = (acl_get_perm(permset, acl_perm_defs[n].tag) ? acl_perm_defs[n].c : '-'); } str[n] = '\0'; }
static int acl_match(acl_entry_t aclent, struct myacl_t *myacl) { gid_t g, *gp; uid_t u, *up; acl_tag_t tag_type; acl_permset_t opaque_ps; acl_flagset_t opaque_fs; int perms; acl_get_tag_type(aclent, &tag_type); /* translate the silly opaque permset to a bitmap */ acl_get_permset(aclent, &opaque_ps); acl_get_flagset_np(aclent, &opaque_fs); perms = acl_permset_to_bitmap(opaque_ps) | acl_flagset_to_bitmap(opaque_fs); if (perms != myacl->permset) return (0); switch (tag_type) { case ACL_USER_OBJ: if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ) return (0); break; case ACL_USER: if (myacl->tag != ARCHIVE_ENTRY_ACL_USER) return (0); up = acl_get_qualifier(aclent); u = *up; acl_free(up); if ((uid_t)myacl->qual != u) return (0); break; case ACL_GROUP_OBJ: if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ) return (0); break; case ACL_GROUP: if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP) return (0); gp = acl_get_qualifier(aclent); g = *gp; acl_free(gp); if ((gid_t)myacl->qual != g) return (0); break; case ACL_MASK: if (myacl->tag != ARCHIVE_ENTRY_ACL_MASK) return (0); break; case ACL_EVERYONE: if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE) return (0); break; } return (1); }
aclent_t getentry(acl_entry_t acl_entry, struct stat st, int acl_default) { aclent_t aclent; acl_tag_t e_type; acl_get_tag_type(acl_entry, &e_type); acl_permset_t permset; acl_get_permset(acl_entry, &permset); void *qualifier = acl_get_qualifier(acl_entry); aclent.a_perm = getmode(permset); switch(e_type) { case ACL_USER_OBJ: aclent.a_id = st.st_uid; break; case ACL_USER: aclent.a_id = *(uid_t*)qualifier; break; case ACL_GROUP_OBJ: aclent.a_id = st.st_gid; break; case ACL_GROUP: aclent.a_id = *(gid_t*)qualifier; break; case ACL_MASK: aclent.a_id = -1; break; case ACL_OTHER: aclent.a_id = -1; break; } aclent.a_type = e_type | acl_default; if(qualifier != NULL) { acl_free(qualifier); } return aclent; }
int score_acl_entry(acl_entry_t entry) { acl_tag_t tag; acl_flagset_t flags; acl_permset_t perms; int score = 0; if (entry == NULL) return (MINIMUM_TIER); if (acl_get_tag_type(entry, &tag) != 0) { // err(1, "Malformed ACL entry, no tag present"); fprintf(stderr, "chmod: Malformed ACL entry, no tag present: %s\n", strerror(errno)); pthread_exit(NULL); } if (acl_get_flagset_np(entry, &flags) != 0){ // err(1, "Unable to obtain flagset"); fprintf(stderr, "chmod: Unable to obtain flagset: %s\n", strerror(errno)); pthread_exit(NULL); } if (acl_get_permset(entry, &perms) != 0) { // err(1, "Malformed ACL entry, no permt present"); fprintf(stderr, "chmod: Malformed ACL entry, no permt present: %s\n", strerror(errno)); pthread_exit(NULL); } switch(tag) { case ACL_EXTENDED_ALLOW: break; case ACL_EXTENDED_DENY: score++; break; default: // errx(1, "Unknown tag type %d present in ACL entry", tag); fprintf(stderr, "chmod: Unknown tag type %d present in ACL entry\n", tag); pthread_exit(NULL); /* NOTREACHED */ } if (acl_get_flag_np(flags, ACL_ENTRY_INHERITED)) score += get_inheritance_level(entry) * INHERITANCE_TIER; return score; }
static int fix_acl(int fd, uid_t uid) { #ifdef HAVE_ACL _cleanup_(acl_freep) acl_t acl = NULL; acl_entry_t entry; acl_permset_t permset; assert(fd >= 0); if (uid <= SYSTEM_UID_MAX) return 0; /* Make sure normal users can read (but not write or delete) * their own coredumps */ acl = acl_get_fd(fd); if (!acl) { log_error("Failed to get ACL: %m"); return -errno; } if (acl_create_entry(&acl, &entry) < 0 || acl_set_tag_type(entry, ACL_USER) < 0 || acl_set_qualifier(entry, &uid) < 0) { log_error("Failed to patch ACL: %m"); return -errno; } if (acl_get_permset(entry, &permset) < 0 || acl_add_perm(permset, ACL_READ) < 0 || calc_acl_mask_if_needed(&acl) < 0) { log_warning("Failed to patch ACL: %m"); return -errno; } if (acl_set_fd(fd, acl) < 0) { log_error("Failed to apply ACL: %m"); return -errno; } #endif return 0; }
static int merge_user_group(acl_entry_t *entry, acl_entry_t *entry_new, int acl_brand) { acl_permset_t permset; acl_entry_type_t entry_type; acl_flagset_t flagset; int have_entry; uid_t *id, *id_new; have_entry = 0; id = acl_get_qualifier(*entry); if (id == NULL) err(1, "acl_get_qualifier() failed"); id_new = acl_get_qualifier(*entry_new); if (id_new == NULL) err(1, "acl_get_qualifier() failed"); if (*id == *id_new) { /* any other matches */ if (acl_get_permset(*entry, &permset) == -1) err(1, "acl_get_permset() failed"); if (acl_set_permset(*entry_new, permset) == -1) err(1, "acl_set_permset() failed"); if (acl_brand == ACL_BRAND_NFS4) { if (acl_get_entry_type_np(*entry, &entry_type)) err(1, "acl_get_entry_type_np() failed"); if (acl_set_entry_type_np(*entry_new, entry_type)) err(1, "acl_set_entry_type_np() failed"); if (acl_get_flagset_np(*entry, &flagset)) err(1, "acl_get_flagset_np() failed"); if (acl_set_flagset_np(*entry_new, flagset)) err(1, "acl_set_flagset_np() failed"); } have_entry = 1; } acl_free(id); acl_free(id_new); return (have_entry); }
/** * update a perm_set_t in entry to the one in aclentry * entry: acl entry to change from in-memory * acl_entry: where to retrieve new perms from * returns status **/ static _BOOL acl_update_perm(acl_entry_t *entry,acl_entry_in *entry_in){ if(entry_in == NULL) return; acl_permset_t perm_set; if(acl_get_permset(*entry,&perm_set)!=ACL_OK) return FALSE; if(((entry_in->permset.nibble&READ) ? acl_add_perm(perm_set,ACL_READ) : acl_delete_perm(perm_set,ACL_READ))!=ACL_OK) return FALSE; if(((entry_in->permset.nibble&WRITE)? acl_add_perm(perm_set,ACL_WRITE) : acl_delete_perm(perm_set,ACL_WRITE))!=ACL_OK) return FALSE; if(((entry_in->permset.nibble&EXEC) ? acl_add_perm(perm_set,ACL_EXECUTE): acl_delete_perm(perm_set,ACL_EXECUTE))!=ACL_OK) return FALSE; if(acl_set_permset(*entry,perm_set)!=ACL_OK) return FALSE; return TRUE; }
int has_execute_perms( acl_t acl) { acl_entry_t ent; if (acl_get_entry(acl, ACL_FIRST_ENTRY, &ent) != 1) return 0; for(;;) { acl_permset_t permset; acl_get_permset(ent, &permset); if (acl_get_perm(permset, ACL_EXECUTE) != 0) return 1; if (acl_get_entry(acl, ACL_NEXT_ENTRY, &ent) != 1) return 0; } }
static int fix_acl(int fd, uid_t uid) { #if HAVE_ACL _cleanup_(acl_freep) acl_t acl = NULL; acl_entry_t entry; acl_permset_t permset; int r; assert(fd >= 0); if (uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY) return 0; /* Make sure normal users can read (but not write or delete) * their own coredumps */ acl = acl_get_fd(fd); if (!acl) return log_error_errno(errno, "Failed to get ACL: %m"); if (acl_create_entry(&acl, &entry) < 0 || acl_set_tag_type(entry, ACL_USER) < 0 || acl_set_qualifier(entry, &uid) < 0) return log_error_errno(errno, "Failed to patch ACL: %m"); if (acl_get_permset(entry, &permset) < 0 || acl_add_perm(permset, ACL_READ) < 0) return log_warning_errno(errno, "Failed to patch ACL: %m"); r = calc_acl_mask_if_needed(&acl); if (r < 0) return log_warning_errno(r, "Failed to patch ACL: %m"); if (acl_set_fd(fd, acl) < 0) return log_error_errno(errno, "Failed to apply ACL: %m"); #endif return 0; }
/* merge two acl entries together */ static int merge_acl_entries(acl_entry_t *entry1, acl_entry_t *entry2) { acl_permset_t permset; acl_entry_type_t entry_type; acl_flagset_t flagset; if (acl_get_permset(*entry1, &permset) < 0) err(EX_OSERR, "acl_get_permset() failed"); if (acl_set_permset(*entry2, permset) < 0) err(EX_OSERR, "acl_set_permset() failed"); if (acl_get_entry_type_np(*entry1, &entry_type) < 0) err(EX_OSERR, "acl_get_entry_type_np() failed"); if (acl_set_entry_type_np(*entry2, entry_type) < 0) err(EX_OSERR, "acl_set_entry_type_np() failed"); if (acl_get_flagset_np(*entry1, &flagset) < 0) err(EX_OSERR, "acl_get_flagset_np() failed"); if (acl_set_flagset_np(*entry2, flagset) < 0) err(EX_OSERR, "acl_set_flagset_np() failed"); return (0); }
static void set_perm( acl_entry_t ent, mode_t add, mode_t remove) { acl_permset_t set; acl_get_permset(ent, &set); if (remove & CMD_PERM_READ) acl_delete_perm(set, ACL_READ); if (remove & CMD_PERM_WRITE) acl_delete_perm(set, ACL_WRITE); if (remove & CMD_PERM_EXECUTE) acl_delete_perm(set, ACL_EXECUTE); if (add & CMD_PERM_READ) acl_add_perm(set, ACL_READ); if (add & CMD_PERM_WRITE) acl_add_perm(set, ACL_WRITE); if (add & CMD_PERM_EXECUTE) acl_add_perm(set, ACL_EXECUTE); }
static void setPerms(acl_entry_t entry, int perms) { acl_permset_t permset; if (acl_get_permset(entry, &permset) == -1) errExit("acl_get_permset"); if (acl_clear_perms(permset) == -1) errExit("acl_clear_perms"); if (perms & ACL_READ) if (acl_add_perm(permset, ACL_READ) == -1) errExit("acl_add_perm"); if (perms & ACL_WRITE) if (acl_add_perm(permset, ACL_WRITE) == -1) errExit("acl_add_perm"); if (perms & ACL_EXECUTE) if (acl_add_perm(permset, ACL_EXECUTE) == -1) errExit("acl_add_perm"); if (acl_set_permset(entry, permset) == -1) errExit("acl_set_permset"); }
static int translate_acl(struct archive_read_disk *a, struct archive_entry *entry, acl_t acl, int default_entry_acl_type) { acl_tag_t acl_tag; acl_entry_type_t acl_type; acl_flagset_t acl_flagset; acl_entry_t acl_entry; acl_permset_t acl_permset; int brand, i, r, entry_acl_type; int s, ae_id, ae_tag, ae_perm; const char *ae_name; // FreeBSD "brands" ACLs as POSIX.1e or NFSv4 // Make sure the "brand" on this ACL is consistent // with the default_entry_acl_type bits provided. acl_get_brand_np(acl, &brand); switch (brand) { case ACL_BRAND_POSIX: switch (default_entry_acl_type) { case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: break; default: // XXX set warning message? return ARCHIVE_FAILED; } break; case ACL_BRAND_NFS4: if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) { // XXX set warning message? return ARCHIVE_FAILED; } break; default: // XXX set warning message? return ARCHIVE_FAILED; break; } s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry); while (s == 1) { ae_id = -1; ae_name = NULL; ae_perm = 0; acl_get_tag_type(acl_entry, &acl_tag); switch (acl_tag) { case ACL_USER: ae_id = (int)*(uid_t *)acl_get_qualifier(acl_entry); ae_name = archive_read_disk_uname(&a->archive, ae_id); ae_tag = ARCHIVE_ENTRY_ACL_USER; break; case ACL_GROUP: ae_id = (int)*(gid_t *)acl_get_qualifier(acl_entry); ae_name = archive_read_disk_gname(&a->archive, ae_id); ae_tag = ARCHIVE_ENTRY_ACL_GROUP; break; case ACL_MASK: ae_tag = ARCHIVE_ENTRY_ACL_MASK; break; case ACL_USER_OBJ: ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ; break; case ACL_GROUP_OBJ: ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; break; case ACL_OTHER: ae_tag = ARCHIVE_ENTRY_ACL_OTHER; break; case ACL_EVERYONE: ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE; break; default: /* Skip types that libarchive can't support. */ s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); continue; } // XXX acl type maps to allow/deny/audit/YYYY bits // XXX acl_get_entry_type_np on FreeBSD returns EINVAL for // non-NFSv4 ACLs entry_acl_type = default_entry_acl_type; r = acl_get_entry_type_np(acl_entry, &acl_type); if (r == 0) { switch (acl_type) { case ACL_ENTRY_TYPE_ALLOW: entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; break; case ACL_ENTRY_TYPE_DENY: entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY; break; case ACL_ENTRY_TYPE_AUDIT: entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT; break; case ACL_ENTRY_TYPE_ALARM: entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; break; } } /* * Libarchive stores "flag" (NFSv4 inheritance bits) * in the ae_perm bitmap. */ acl_get_flagset_np(acl_entry, &acl_flagset); for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) { if (acl_get_flag_np(acl_flagset, acl_inherit_map[i].platform_inherit)) ae_perm |= acl_inherit_map[i].archive_inherit; } acl_get_permset(acl_entry, &acl_permset); for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) { /* * acl_get_perm() is spelled differently on different * platforms; see above. */ if (ACL_GET_PERM(acl_permset, acl_perm_map[i].platform_perm)) ae_perm |= acl_perm_map[i].archive_perm; } archive_entry_acl_add_entry(entry, entry_acl_type, ae_perm, ae_tag, ae_id, ae_name); s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); } return (ARCHIVE_OK); }
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); }
int main(int argc,char *argv[]) { acl_t acl; acl_type_t type; acl_entry_t entry; acl_tag_t tag; uid_t *uidp; gid_t *gidp; acl_permset_t permset; char *name; int entryId,permVal,opt; type = ACL_TYPE_ACCESS; while((opt = getopt(argc,argv,"d") != -1)) { switch(opt) { case 'd': type = ACL_TYPE_DEFAULT;break; case '?': usageError(argv[0]); } } if (optind + 1 != argc) { usageError(argv[0]); } acl = acl_get_file(argv[optind],type); if (acl == NULL) { errExit("acl_get_file"); } /* Walk through each entry in this ACL */ for (entryId = ACL_FIRST_ENTRY; ; entryId = ACL_NEXT_ENTRY) { if (acl_get_entry(acl,entryId,&entry) != 1) { break; /* Exit on error or no more entries */ } /* Retrieve and display tag type */ if (acl_get_tag_type(entry,&tag) == -1) { errExit("acl_get_tag_type"); } printf("%-12s", (tag == ACL_USER_OBJ) ? "user_obj" : (tag == ACL_USER) ? "user" : (tag == ACL_GROUP_OBJ) ? "group_obj": (tag == ACL_GROUP) ? "group": (tag == ACL_MASK) ? "mask": (tag == ACL_OTHER) ? "other":"???"); /* Retrieve and display otpional tag qualifier */ if (tag == ACL_USER) { uidp = acl_get_qualifier(entry); if (uidp == NULL) { errExit("acl_get_qualifier"); } name = userNameFromId(*uidp); if (name == NULL) { printf("%-8d",*uidp); } else { printf("%-8s",name); } if (acl_free(uidp) == -1) { errExit("acl_free"); } }else if (tag == ACL_GROUP) { gidp = acl_get_qualifier(entry); if (gidp == NULL) { errExit("acl_get_qualifier"); } name = groupNameFromId(*gidp); if (name == NULL) { printf("%-12d",*gidp); } else { printf("%-12s",name); } if (acl_free(gidp) == -1) { errExit("acl_free"); } }else { printf(" "); } /* Retrieve and display permissions */ if (acl_get_permset(entry,&permset) == -1) { errExit("acl_get_permset"); } permVal = acl_get_perm(permset,ACL_READ); if (permVal == -1) { errExit("acl_get_perm - ACL_READ"); } printf("%c", (permVal == 1) ? 'r' : '-'); permVal = acl_get_perm(permset,ACL_WRITE); if (permVal == -1) { errExit("acl_get_perm -ACL_WRITE"); } printf("%c", (permVal == 1) ? 'w': '-'); permVal = acl_get_perm(permset,ACL_EXECUTE); if (permVal == -1) { errExit("acl_get_perm - ACL_EXECUTE"); } printf("%c", (permVal == 1) ? 'x' : '-'); printf("\n"); } if (acl_free(acl) == -1) { errExit("acl_free"); } exit(EXIT_SUCCESS); }
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; }
acl_t pfl_acl_from_xattr(const void *buf, size_t size) { int i, entries; const struct acl_ea_header *h = buf; const struct acl_ea_entry *xe = PSC_AGP(h + 1, 0); unsigned int xperms; acl_permset_t permset; acl_entry_t e; acl_tag_t tag; acl_t a; if (size < sizeof(*h)) { errno = EINVAL; return (NULL); } if (le32toh(h->version) != ACL_EA_VERSION) { errno = EINVAL; return (NULL); } size -= sizeof(*h); if (size % sizeof(*xe)) { errno = EINVAL; return (NULL); } entries = size / sizeof(*xe); a = acl_init(entries); if (a == NULL) return (NULL); for (i = 0; i < entries; i++, xe++) { acl_create_entry(&a, &e); if (acl_get_permset(e, &permset) == -1) psclog_error("get_permset"); acl_clear_perms(permset); xperms = le16toh(xe->perm); if (xperms & ACL_READ) acl_add_perm(permset, ACL_READ); if (xperms & ACL_WRITE) acl_add_perm(permset, ACL_WRITE); if (xperms & ACL_EXECUTE) acl_add_perm(permset, ACL_EXECUTE); if (acl_set_permset(e, permset) == -1) psclog_error("set_permset"); acl_set_tag_type(e, tag = le16toh(xe->tag)); switch (tag) { case ACL_USER: { uid_t uid = le32toh(xe->id); acl_set_qualifier(e, &uid); break; } case ACL_GROUP: { gid_t gid = le32toh(xe->id); acl_set_qualifier(e, &gid); break; } } } return (a); }
static int check_facl(pool *p, const char *path, int mode, void *acl, int nents, struct stat *st, uid_t uid, gid_t gid, array_header *suppl_gids) { # if defined(HAVE_BSD_POSIX_ACL) || defined(HAVE_LINUX_POSIX_ACL) register unsigned int i; int have_access_entry = FALSE, res = -1; pool *acl_pool; acl_t facl = acl; acl_entry_t ae; acl_tag_t ae_type; acl_entry_t acl_user_entry = NULL; acl_entry_t acl_group_entry = NULL; acl_entry_t acl_other_entry = NULL; acl_entry_t acl_mask_entry = NULL; array_header *acl_groups; array_header *acl_users; /* Iterate through all of the ACL entries, sorting them for later * checking. */ res = acl_get_entry(facl, ACL_FIRST_ENTRY, &ae); if (res < 0) { pr_log_debug(DEBUG10, "FS: unable to retrieve first ACL entry for '%s': %s", path, strerror(errno)); errno = EACCES; return -1; } if (res == 0) { pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s' has no entries!", path); errno = EACCES; return -1; } acl_pool = make_sub_pool(p); acl_groups = make_array(acl_pool, 1, sizeof(acl_entry_t)); acl_users = make_array(acl_pool, 1, sizeof(acl_entry_t)); while (res > 0) { if (acl_get_tag_type(ae, &ae_type) < 0) { pr_log_debug(DEBUG5, "FS: error retrieving type of ACL entry for '%s': %s", path, strerror(errno)); res = acl_get_entry(facl, ACL_NEXT_ENTRY, &ae); continue; } if (ae_type & ACL_USER_OBJ) { acl_copy_entry(acl_user_entry, ae); } else if (ae_type & ACL_USER) { acl_entry_t *ae_dup = push_array(acl_users); acl_copy_entry(*ae_dup, ae); } else if (ae_type & ACL_GROUP_OBJ) { acl_copy_entry(acl_group_entry, ae); } else if (ae_type & ACL_GROUP) { acl_entry_t *ae_dup = push_array(acl_groups); acl_copy_entry(*ae_dup, ae); } else if (ae_type & ACL_OTHER) { acl_copy_entry(acl_other_entry, ae); } else if (ae_type & ACL_MASK) { acl_copy_entry(acl_mask_entry, ae); } res = acl_get_entry(facl, ACL_NEXT_ENTRY, &ae); } /* Select the ACL entry that determines access. */ res = -1; /* 1. If the given user ID matches the file owner, use that entry for * access. */ if (uid == st->st_uid) { /* Check the acl_user_entry for access. */ acl_copy_entry(ae, acl_user_entry); ae_type = ACL_USER_OBJ; have_access_entry = TRUE; } /* 2. If not matched above, and f the given user ID matches one of the * named user entries, use that entry for access. */ for (i = 0; !have_access_entry && i < acl_users->nelts; i++) { acl_entry_t e = ((acl_entry_t *) acl_users->elts)[i]; if (uid == *((uid_t *) acl_get_qualifier(e))) { /* Check this entry for access. Note that it'll need to * be modified by the mask, if any, later. */ acl_copy_entry(ae, e); ae_type = ACL_USER; have_access_entry = TRUE; break; } } /* 3. If not matched above, and if one of the group IDs matches the * group owner entry, and the group owner entry contains the * requested permissions, use that entry for access. */ if (!have_access_entry && gid == st->st_gid) { /* Check the acl_group_entry for access. First though, we need to * see if the acl_group_entry contains the requested permissions. */ acl_permset_t perms; acl_get_permset(acl_group_entry, &perms); # if defined(HAVE_BSD_POSIX_ACL) if (acl_get_perm_np(perms, mode) == 1) { # elif defined(HAVE_LINUX_POSIX_ACL) if (acl_get_perm(perms, mode) == 1) { # endif acl_copy_entry(ae, acl_group_entry); ae_type = ACL_GROUP_OBJ; have_access_entry = TRUE; } } if (suppl_gids) { for (i = 0; !have_access_entry && i < suppl_gids->nelts; i++) { gid_t suppl_gid = ((gid_t *) suppl_gids->elts)[i]; if (suppl_gid == st->st_gid) { /* Check the acl_group_entry for access. First though, we need to * see if the acl_group_entry contains the requested permissions. */ acl_permset_t perms; acl_get_permset(acl_group_entry, &perms); # if defined(HAVE_BSD_POSIX_ACL) if (acl_get_perm_np(perms, mode) == 1) { # elif defined(HAVE_LINUX_POSIX_ACL) if (acl_get_perm(perms, mode) == 1) { # endif acl_copy_entry(ae, acl_group_entry); ae_type = ACL_GROUP_OBJ; have_access_entry = TRUE; break; } } } } /* 5. If not matched above, and if one of the group IDs matches one * of the named group entries, and that entry contains the requested * permissions, use that entry for access. */ for (i = 0; !have_access_entry && i < acl_groups->nelts; i++) { acl_entry_t e = ((acl_entry_t *) acl_groups->elts)[i]; if (gid == *((gid_t *) acl_get_qualifier(e))) { /* Check this entry for access. Note that it'll need to * be modified by the mask, if any, later. */ acl_permset_t perms; acl_get_permset(e, &perms); # if defined(HAVE_BSD_POSIX_ACL) if (acl_get_perm_np(perms, mode) == 1) { # elif defined(HAVE_LINUX_POSIX_ACL) if (acl_get_perm(perms, mode) == 1) { # endif acl_copy_entry(ae, e); ae_type = ACL_GROUP; have_access_entry = TRUE; break; } } if (suppl_gids) { register unsigned int j; for (j = 0; !have_access_entry && j < suppl_gids->nelts; j++) { gid_t suppl_gid = ((gid_t *) suppl_gids->elts)[j]; if (suppl_gid == *((gid_t *) acl_get_qualifier(e))) { /* Check this entry for access. Note that it'll need to * be modified by the mask, if any, later. */ acl_permset_t perms; acl_get_permset(e, &perms); # if defined(HAVE_BSD_POSIX_ACL) if (acl_get_perm_np(perms, mode) == 1) { # elif defined(HAVE_LINUX_POSIX_ACL) if (acl_get_perm(perms, mode) == 1) { # endif acl_copy_entry(ae, e); ae_type = ACL_GROUP; have_access_entry = TRUE; break; } } } } } /* 6. If not matched above, and if one of the group IDs matches * the group owner or any of the named group entries, but neither * the group owner entry nor any of the named group entries contains * the requested permissions, access is denied. */ /* 7. If not matched above, the other entry determines access. */ if (!have_access_entry) { acl_copy_entry(ae, acl_other_entry); ae_type = ACL_OTHER; have_access_entry = TRUE; } /* Access determination: * * If either the user owner entry or other entry were used, and the * entry contains the requested permissions, access is permitted. * * Otherwise, if the selected entry and the mask entry both contain * the requested permissions, access is permitted. * * Otherwise, access is denied. */ switch (ae_type) { case ACL_USER_OBJ: case ACL_OTHER: { acl_permset_t perms; acl_get_permset(ae, &perms); # if defined(HAVE_BSD_POSIX_ACL) if (acl_get_perm_np(perms, mode) == 1) { # elif defined(HAVE_LINUX_POSIX_ACL) if (acl_get_perm(perms, mode) == 1) { # endif res = 0; } break; } default: { acl_permset_t ent_perms, mask_perms; acl_get_permset(ae, &ent_perms); acl_get_permset(acl_mask_entry, &mask_perms); # if defined(HAVE_BSD_POSIX_ACL) if (acl_get_perm_np(ent_perms, mode) == 1 && acl_get_perm_np(mask_perms, mode) == 1) { # elif defined(HAVE_LINUX_POSIX_ACL) if (acl_get_perm(ent_perms, mode) == 1 && acl_get_perm(mask_perms, mode) == 1) { # endif res = 0; } break; } } destroy_pool(acl_pool); if (res < 0) errno = EACCES; return res; # elif defined(HAVE_SOLARIS_POSIX_ACL) register unsigned int i; int have_access_entry = FALSE, idx, res = -1; pool *acl_pool; aclent_t *acls = acl; aclent_t ae; int ae_type = 0; aclent_t acl_user_entry; aclent_t acl_group_entry; aclent_t acl_other_entry; aclent_t acl_mask_entry; array_header *acl_groups; array_header *acl_users; /* In the absence of any clear documentation, I'll assume that * Solaris ACLs follow the same selection and checking algorithm * as do BSD and Linux. */ res = aclcheck(acls, nents, &idx); switch (res) { case 0: break; case GRP_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "too many GROUP entries"); errno = EACCES; return -1; case USER_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "too many USER entries"); errno = EACCES; return -1; case OTHER_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "too many OTHER entries"); errno = EACCES; return -1; case CLASS_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "too many CLASS entries"); errno = EACCES; return -1; case DUPLICATE_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "duplicate entries"); errno = EACCES; return -1; case MISS_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "missing required entry"); errno = EACCES; return -1; case MEM_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "Out of memory!"); errno = EACCES; return -1; case ENTRY_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "invalid entry type"); errno = EACCES; return -1; } /* Iterate through all of the ACL entries, sorting them for later * checking. */ acl_pool = make_sub_pool(p); acl_groups = make_array(acl_pool, 1, sizeof(aclent_t)); acl_users = make_array(acl_pool, 1, sizeof(aclent_t)); for (i = 0; i < nents; i++) { if (acls[i].a_type & USER_OBJ) { memcpy(&acl_user_entry, &(acls[i]), sizeof(aclent_t)); } else if (acls[i].a_type & USER) { aclent_t *ae_dup = push_array(acl_users); memcpy(ae_dup, &(acls[i]), sizeof(aclent_t)); } else if (acls[i].a_type & GROUP_OBJ) { memcpy(&acl_group_entry, &(acls[i]), sizeof(aclent_t)); } else if (acls[i].a_type & GROUP) { aclent_t *ae_dup = push_array(acl_groups); memcpy(ae_dup, &(acls[i]), sizeof(aclent_t)); } else if (acls[i].a_type & OTHER_OBJ) { memcpy(&acl_other_entry, &(acls[i]), sizeof(aclent_t)); } else if (acls[i].a_type & CLASS_OBJ) { memcpy(&acl_mask_entry, &(acls[i]), sizeof(aclent_t)); } } /* Select the ACL entry that determines access. */ res = -1; /* 1. If the given user ID matches the file owner, use that entry for * access. */ if (uid == st->st_uid) { /* Check the acl_user_entry for access. */ memcpy(&ae, &acl_user_entry, sizeof(aclent_t)); ae_type = USER_OBJ; have_access_entry = TRUE; } /* 2. If not matched above, and f the given user ID matches one of the * named user entries, use that entry for access. */ for (i = 0; !have_access_entry && i < acl_users->nelts; i++) { aclent_t e; memcpy(&e, &(((aclent_t *) acl_users->elts)[i]), sizeof(aclent_t)); if (uid == e.a_id) { /* Check this entry for access. Note that it'll need to * be modified by the mask, if any, later. */ memcpy(&ae, &e, sizeof(aclent_t)); ae_type = USER; have_access_entry = TRUE; break; } } /* 3. If not matched above, and if one of the group IDs matches the * group owner entry, and the group owner entry contains the * requested permissions, use that entry for access. */ if (!have_access_entry && gid == st->st_gid) { /* Check the acl_group_entry for access. First though, we need to * see if the acl_group_entry contains the requested permissions. */ if (acl_group_entry.a_perm & mode) { memcpy(&ae, &acl_group_entry, sizeof(aclent_t)); ae_type = GROUP_OBJ; have_access_entry = TRUE; } } if (suppl_gids) { for (i = 0; !have_access_entry && i < suppl_gids->nelts; i++) { gid_t suppl_gid = ((gid_t *) suppl_gids->elts)[i]; if (suppl_gid == st->st_gid) { /* Check the acl_group_entry for access. First though, we need to * see if the acl_group_entry contains the requested permissions. */ if (acl_group_entry.a_perm & mode) { memcpy(&ae, &acl_group_entry, sizeof(aclent_t)); ae_type = GROUP_OBJ; have_access_entry = TRUE; break; } } } } /* 5. If not matched above, and if one of the group IDs matches one * of the named group entries, and that entry contains the requested * permissions, use that entry for access. */ for (i = 0; !have_access_entry && i < acl_groups->nelts; i++) { aclent_t e; memcpy(&e, &(((aclent_t *) acl_groups->elts)[i]), sizeof(aclent_t)); if (gid == e.a_id) { /* Check this entry for access. Note that it'll need to * be modified by the mask, if any, later. */ if (e.a_perm & mode) { memcpy(&ae, &e, sizeof(aclent_t)); ae_type = GROUP; have_access_entry = TRUE; break; } } if (suppl_gids) { register unsigned int j; for (j = 0; !have_access_entry && j < suppl_gids->nelts; j++) { gid_t suppl_gid = ((gid_t *) suppl_gids->elts)[j]; if (suppl_gid == e.a_id) { /* Check this entry for access. Note that it'll need to * be modified by the mask, if any, later. */ if (e.a_perm & mode) { memcpy(&ae, &e, sizeof(aclent_t)); ae_type = GROUP; have_access_entry = TRUE; break; } } } } } /* 6. If not matched above, and if one of the group IDs matches * the group owner or any of the named group entries, but neither * the group owner entry nor any of the named group entries contains * the requested permissions, access is denied. */ /* 7. If not matched above, the other entry determines access. */ if (!have_access_entry) { memcpy(&ae, &acl_other_entry, sizeof(aclent_t)); ae_type = OTHER_OBJ; have_access_entry = TRUE; } /* Access determination: * * If either the user owner entry or other entry were used, and the * entry contains the requested permissions, access is permitted. * * Otherwise, if the selected entry and the mask entry both contain * the requested permissions, access is permitted. * * Otherwise, access is denied. */ switch (ae_type) { case USER_OBJ: case OTHER_OBJ: if (ae.a_perm & mode) res = 0; break; default: if ((ae.a_perm & mode) && (acl_mask_entry.a_perm & mode)) res = 0; break; } destroy_pool(acl_pool); if (res < 0) errno = EACCES; return res; # endif /* HAVE_SOLARIS_POSIX_ACL */ } /* FSIO handlers */ static int facl_fsio_access(pr_fs_t *fs, const char *path, int mode, uid_t uid, gid_t gid, array_header *suppl_gids) { int nents = 0; struct stat st; void *acls; pr_fs_clear_cache(); if (pr_fsio_stat(path, &st) < 0) return -1; /* Look up the acl for this path. */ # if defined(HAVE_BSD_POSIX_ACL) || defined(HAVE_LINUX_POSIX_ACL) acls = acl_get_file(path, ACL_TYPE_ACCESS); if (!acls) { pr_log_debug(DEBUG10, "FS: unable to retrieve ACL for '%s': %s", path, strerror(errno)); return -1; } # elif defined(HAVE_SOLARIS_POSIX_ACL) nents = acl(path, GETACLCNT, 0, NULL); if (nents < 0) { pr_log_debug(DEBUG10, "FS: unable to retrieve ACL count for '%s': %s", path, strerror(errno)); return -1; } acls = pcalloc(fs->fs_pool, nents * sizeof(aclent_t)); nents = acl(path, GETACL, nents, acls); if (nents < 0) { pr_log_debug(DEBUG10, "FS: unable to retrieve ACL for '%s': %s", path, strerror(errno)); return -1; } # endif return check_facl(fs->fs_pool, path, mode, acls, nents, &st, uid, gid, suppl_gids); } static int facl_fsio_faccess(pr_fh_t *fh, int mode, uid_t uid, gid_t gid, array_header *suppl_gids) { int nents = 0; struct stat st; void *acls; pr_fs_clear_cache(); if (pr_fsio_fstat(fh, &st) < 0) return -1; /* Look up the acl for this fd. */ # if defined(HAVE_BSD_POSIX_ACL) || defined(HAVE_LINUX_POSIX_ACL) acls = acl_get_fd(PR_FH_FD(fh)); if (!acls) { pr_log_debug(DEBUG10, "FS: unable to retrieve ACL for '%s': %s", fh->fh_path, strerror(errno)); return -1; } # elif defined(HAVE_SOLARIS_POSIX_ACL) nents = facl(PR_FH_FD(fh), GETACLCNT, 0, NULL); if (nents < 0) { pr_log_debug(DEBUG10, "FS: unable to retrieve ACL count for '%s': %s", fh->fh_path, strerror(errno)); return -1; } acls = pcalloc(fh->fh_fs->fs_pool, nents * sizeof(aclent_t)); nents = facl(PR_FH_FD(fh), GETACL, nents, acls); if (nents < 0) { pr_log_debug(DEBUG10, "FS: unable to retrieve ACL for '%s': %s", fh->fh_path, strerror(errno)); return -1; } # endif return check_facl(fh->fh_fs->fs_pool, fh->fh_path, mode, acls, nents, &st, uid, gid, suppl_gids); } #endif /* HAVE_POSIX_ACL */ /* Initialization routines */ static int facl_init(void) { #if defined(PR_USE_FACL) && defined(HAVE_POSIX_ACL) pr_fs_t *fs = pr_register_fs(permanent_pool, "facl", "/"); if (!fs) { pr_log_pri(PR_LOG_ERR, MOD_FACL_VERSION ": error registering fs: %s", strerror(errno)); return -1; } /* Ensure that our ACL-checking handlers are used. */ fs->access = facl_fsio_access; fs->faccess = facl_fsio_faccess; #endif /* PR_USE_FACL and HAVE_POSIX_ACL */ return 0; } /* Module Tables */ module facl_module = { /* Always NULL */ NULL, NULL, /* Module API version */ 0x20, /* Module name */ "facl", /* Module configuration directive handlers */ NULL, /* Module command handlers */ NULL, /* Module authentication handlers */ NULL, /* Module initialization */ facl_init, /* Session initialization */ NULL, /* Module version */ MOD_FACL_VERSION };
/* * 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; } }