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; }
/* Convert one or more acl entries in string form to an acl_t */ acl_t parse_acl_entries(const char *input) { acl_t acl_input; acl_entry_t newent; char *inbuf; char *oinbuf; char **bufp, *entryv[ACL_MAX_ENTRIES]; #if 0 /* XXX acl_from_text(), when implemented, will presumably use the canonical * text representation format, which is what chmod should be using * We may need to add an entry number to the input */ /* Translate the user supplied ACL entry */ /* acl_input = acl_from_text(input); */ #else inbuf = malloc(MAX_ACL_TEXT_SIZE); if (inbuf == NULL) { // err(1, "malloc() failed"); fprintf(stderr, "chmod: malloc() failed: %s\n", strerror(errno)); pthread_exit(NULL); } strncpy(inbuf, input, MAX_ACL_TEXT_SIZE); inbuf[MAX_ACL_TEXT_SIZE - 1] = '\0'; if ((acl_input = acl_init(1)) == NULL) { // err(1, "acl_init() failed"); fprintf(stderr, "chmod: acl_init() failed: %s\n", strerror(errno)); pthread_exit(NULL); } oinbuf = inbuf; for (bufp = entryv; (*bufp = strsep(&oinbuf, "\n")) != NULL;) if (**bufp != '\0') { if (0 != acl_create_entry(&acl_input, &newent)) { // err(1, "acl_create_entry() failed"); fprintf(stderr, "chmod: acl_create_entry() failed: %s\n", strerror(errno)); pthread_exit(NULL); } if (0 != parse_entry(*bufp, newent)) { // errx(1, "Failed parsing entry '%s'", *bufp); fprintf(stderr, "chmod: Failed parsing entry '%s'\n", *bufp); pthread_exit(NULL); } if (++bufp >= &entryv[ACL_MAX_ENTRIES - 1]) { // errx(1, "Too many entries"); fprintf(stderr, "chmod: Too many entries\n"); pthread_exit(NULL); } } free(inbuf); return acl_input; #endif /* #if 0 */ }
int fpm_unix_set_socket_premissions(struct fpm_worker_pool_s *wp, const char *path) /* {{{ */ { #ifdef HAVE_FPM_ACL if (wp->socket_acl) { acl_t aclfile, aclconf; acl_entry_t entryfile, entryconf; int i; /* Read the socket ACL */ aclconf = wp->socket_acl; aclfile = acl_get_file (path, ACL_TYPE_ACCESS); if (!aclfile) { zlog(ZLOG_SYSERROR, "[pool %s] failed to read the ACL of the socket '%s'", wp->config->name, path); return -1; } /* Copy the new ACL entry from config */ for (i=ACL_FIRST_ENTRY ; acl_get_entry(aclconf, i, &entryconf) ; i=ACL_NEXT_ENTRY) { if (0 > acl_create_entry (&aclfile, &entryfile) || 0 > acl_copy_entry(entryfile, entryconf)) { zlog(ZLOG_SYSERROR, "[pool %s] failed to add entry to the ACL of the socket '%s'", wp->config->name, path); acl_free(aclfile); return -1; } } /* Write the socket ACL */ if (0 > acl_calc_mask (&aclfile) || 0 > acl_valid (aclfile) || 0 > acl_set_file (path, ACL_TYPE_ACCESS, aclfile)) { zlog(ZLOG_SYSERROR, "[pool %s] failed to write the ACL of the socket '%s'", wp->config->name, path); acl_free(aclfile); return -1; } else { zlog(ZLOG_DEBUG, "[pool %s] ACL of the socket '%s' is set", wp->config->name, path); } acl_free(aclfile); return 0; } /* When listen.users and listen.groups not configured, continue with standard right */ #endif if (wp->socket_uid != -1 || wp->socket_gid != -1) { if (0 > chown(path, wp->socket_uid, wp->socket_gid)) { zlog(ZLOG_SYSERROR, "[pool %s] failed to chown() the socket '%s'", wp->config->name, wp->config->listen_address); return -1; } } return 0; }
static int clone_entry (acl_t from_acl, acl_tag_t from_type, acl_t *to_acl, acl_tag_t to_type) { acl_entry_t from_entry; acl_entry_t to_entry; from_entry = find_entry(from_acl, from_type, ACL_UNDEFINED_ID); if (from_entry == NULL) return 1; if (acl_create_entry(to_acl, &to_entry) != 0) return -1; acl_copy_entry(to_entry, from_entry); acl_set_tag_type(to_entry, to_type); return 0; }
/** * creates a new acl_entry_t given acl and acl_entry * acl: ptr to acl to add to * acl_entry: where to get tag,qualifier, and perms * returns status **/ _BOOL acl_create(acl_t *acl,acl_entry_in *entry_in){ acl_entry_t entry; //create the entry if((acl_create_entry(acl,&entry))!=ACL_OK) return FALSE; //set the tag if((acl_set_tag_type(entry,entry_in->tag))!=ACL_OK) return FALSE; //set the qualifier if necessary if(entry_in->tag == ACL_USER) if(acl_set_qualifier(entry,&entry_in->qualifier.u_qual)!=ACL_OK) return FALSE; else if(entry_in->tag == ACL_GROUP) if(acl_set_qualifier(entry,&entry_in->qualifier.g_qual)!=ACL_OK) return FALSE; if(!acl_update_permset(&entry,entry_in)) return FALSE; return TRUE; }
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 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; }
static int parse_acl_entry(const char **text_p, acl_t *acl_p) { acl_entry_obj entry_obj; acl_entry_t entry_d; char *str; const char *backup; int error, perm_chars; new_obj_p_here(acl_entry, &entry_obj); init_acl_entry_obj(entry_obj); /* parse acl entry type */ SKIP_WS(*text_p); switch (**text_p) { case 'u': /* user */ if (!skip_tag_name(text_p, "user")) goto fail; backup = *text_p; str = get_token(text_p); if (str) { entry_obj.etag = ACL_USER; error = get_uid(unquote(str), &entry_obj.eid.qid); free(str); if (error) { *text_p = backup; return -1; } } else { entry_obj.etag = ACL_USER_OBJ; } break; case 'g': /* group */ if (!skip_tag_name(text_p, "group")) goto fail; backup = *text_p; str = get_token(text_p); if (str) { entry_obj.etag = ACL_GROUP; error = get_gid(unquote(str), &entry_obj.eid.qid); free(str); if (error) { *text_p = backup; return -1; } } else { entry_obj.etag = ACL_GROUP_OBJ; } break; case 'm': /* mask */ if (!skip_tag_name(text_p, "mask")) goto fail; /* skip empty entry qualifier field (this field may be missing for compatibility with Solaris.) */ SKIP_WS(*text_p); if (**text_p == ':') (*text_p)++; entry_obj.etag = ACL_MASK; break; case 'o': /* other */ if (!skip_tag_name(text_p, "other")) goto fail; /* skip empty entry qualifier field (this field may be missing for compatibility with Solaris.) */ SKIP_WS(*text_p); if (**text_p == ':') (*text_p)++; entry_obj.etag = ACL_OTHER; break; default: goto fail; } for (perm_chars=0; perm_chars<3; perm_chars++, (*text_p)++) { switch(**text_p) { case 'r': if (entry_obj.eperm.sperm & ACL_READ) goto fail; entry_obj.eperm.sperm |= ACL_READ; break; case 'w': if (entry_obj.eperm.sperm & ACL_WRITE) goto fail; entry_obj.eperm.sperm |= ACL_WRITE; break; case 'x': if (entry_obj.eperm.sperm & ACL_EXECUTE) goto fail; entry_obj.eperm.sperm |= ACL_EXECUTE; break; case '-': /* ignore */ break; default: if (perm_chars == 0) goto fail; goto create_entry; } } create_entry: if (acl_create_entry(acl_p, &entry_d) != 0) return -1; if (acl_copy_entry(entry_d, int2ext(&entry_obj)) != 0) return -1; return 0; fail: errno = EINVAL; return -1; }
int add_base_acls_if_needed(acl_t *acl_p, const char *path) { acl_entry_t i; int r; bool have_user_obj = false, have_group_obj = false, have_other = false; struct stat st; _cleanup_(acl_freep) acl_t basic = NULL; assert(acl_p); for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i); r > 0; r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) { acl_tag_t tag; if (acl_get_tag_type(i, &tag) < 0) return -errno; if (tag == ACL_USER_OBJ) have_user_obj = true; else if (tag == ACL_GROUP_OBJ) have_group_obj = true; else if (tag == ACL_OTHER) have_other = true; if (have_user_obj && have_group_obj && have_other) return 0; } if (r < 0) return -errno; r = stat(path, &st); if (r < 0) return -errno; basic = acl_from_mode(st.st_mode); if (!basic) return -errno; for (r = acl_get_entry(basic, ACL_FIRST_ENTRY, &i); r > 0; r = acl_get_entry(basic, ACL_NEXT_ENTRY, &i)) { acl_tag_t tag; acl_entry_t dst; if (acl_get_tag_type(i, &tag) < 0) return -errno; if ((tag == ACL_USER_OBJ && have_user_obj) || (tag == ACL_GROUP_OBJ && have_group_obj) || (tag == ACL_OTHER && have_other)) continue; r = acl_create_entry(acl_p, &dst); if (r < 0) return -errno; r = acl_copy_entry(dst, i); if (r < 0) return -errno; } if (r < 0) return -errno; return 0; }
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; }
void cupsdAddCert(int pid, /* I - Process ID */ const char *username, /* I - Username */ int type) /* I - AuthType for username */ { int i; /* Looping var */ cupsd_cert_t *cert; /* Current certificate */ int fd; /* Certificate file */ char filename[1024]; /* Certificate filename */ static const char hex[] = "0123456789ABCDEF"; /* Hex constants... */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddCert: Adding certificate for PID %d", pid); /* * Allocate memory for the certificate... */ if ((cert = calloc(sizeof(cupsd_cert_t), 1)) == NULL) return; /* * Fill in the certificate information... */ cert->pid = pid; cert->type = type; strlcpy(cert->username, username, sizeof(cert->username)); for (i = 0; i < 32; i ++) cert->certificate[i] = hex[CUPS_RAND() & 15]; /* * Save the certificate to a file readable only by the User and Group * (or root and SystemGroup for PID == 0)... */ snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, pid); unlink(filename); if ((fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0400)) < 0) { cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create certificate file %s - %s", filename, strerror(errno)); free(cert); return; } if (pid == 0) { #ifdef HAVE_ACL_INIT acl_t acl; /* ACL information */ acl_entry_t entry; /* ACL entry */ acl_permset_t permset; /* Permissions */ # ifdef HAVE_MBR_UID_TO_UUID uuid_t group; /* Group ID */ # endif /* HAVE_MBR_UID_TO_UUID */ static int acls_not_supported = 0; /* Only warn once */ #endif /* HAVE_ACL_INIT */ /* * Root certificate... */ fchmod(fd, 0440); fchown(fd, RunUser, SystemGroupIDs[0]); cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddCert: NumSystemGroups=%d", NumSystemGroups); #ifdef HAVE_ACL_INIT if (NumSystemGroups > 1) { /* * Set POSIX ACLs for the root certificate so that all system * groups can access it... */ int j; /* Looping var */ # ifdef HAVE_MBR_UID_TO_UUID /* * On MacOS X, ACLs use UUIDs instead of GIDs... */ acl = acl_init(NumSystemGroups - 1); for (i = 1; i < NumSystemGroups; i ++) { /* * Add each group ID to the ACL... */ for (j = 0; j < i; j ++) if (SystemGroupIDs[j] == SystemGroupIDs[i]) break; if (j < i) continue; /* Skip duplicate groups */ acl_create_entry(&acl, &entry); acl_get_permset(entry, &permset); acl_add_perm(permset, ACL_READ_DATA); acl_set_tag_type(entry, ACL_EXTENDED_ALLOW); mbr_gid_to_uuid((gid_t)SystemGroupIDs[i], group); acl_set_qualifier(entry, &group); acl_set_permset(entry, permset); } # else /* * POSIX ACLs need permissions for owner, group, other, and mask * in addition to the rest of the system groups... */ acl = acl_init(NumSystemGroups + 3); /* Owner */ acl_create_entry(&acl, &entry); acl_get_permset(entry, &permset); acl_add_perm(permset, ACL_READ); acl_set_tag_type(entry, ACL_USER_OBJ); acl_set_permset(entry, permset); /* Group */ acl_create_entry(&acl, &entry); acl_get_permset(entry, &permset); acl_add_perm(permset, ACL_READ); acl_set_tag_type(entry, ACL_GROUP_OBJ); acl_set_permset(entry, permset); /* Others */ acl_create_entry(&acl, &entry); acl_get_permset(entry, &permset); acl_add_perm(permset, 0); acl_set_tag_type(entry, ACL_OTHER); acl_set_permset(entry, permset); /* Mask */ acl_create_entry(&acl, &entry); acl_get_permset(entry, &permset); acl_add_perm(permset, ACL_READ); acl_set_tag_type(entry, ACL_MASK); acl_set_permset(entry, permset); for (i = 1; i < NumSystemGroups; i ++) { /* * Add each group ID to the ACL... */ for (j = 0; j < i; j ++) if (SystemGroupIDs[j] == SystemGroupIDs[i]) break; if (j < i) continue; /* Skip duplicate groups */ acl_create_entry(&acl, &entry); acl_get_permset(entry, &permset); acl_add_perm(permset, ACL_READ); acl_set_tag_type(entry, ACL_GROUP); acl_set_qualifier(entry, SystemGroupIDs + i); acl_set_permset(entry, permset); } if (acl_valid(acl)) { char *text, *textptr; /* Temporary string */ cupsdLogMessage(CUPSD_LOG_ERROR, "ACL did not validate: %s", strerror(errno)); text = acl_to_text(acl, NULL); for (textptr = strchr(text, '\n'); textptr; textptr = strchr(textptr + 1, '\n')) *textptr = ','; cupsdLogMessage(CUPSD_LOG_ERROR, "ACL: %s", text); acl_free(text); } # endif /* HAVE_MBR_UID_TO_UUID */ if (acl_set_fd(fd, acl)) { if (errno != EOPNOTSUPP || !acls_not_supported) cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to set ACLs on root certificate \"%s\" - %s", filename, strerror(errno)); if (errno == EOPNOTSUPP) acls_not_supported = 1; } acl_free(acl); } #endif /* HAVE_ACL_INIT */ RootCertTime = time(NULL); } else { /* * CGI certificate... */ fchmod(fd, 0400); fchown(fd, User, Group); } DEBUG_printf(("ADD pid=%d, username=%s, cert=%s\n", pid, username, cert->certificate)); write(fd, cert->certificate, strlen(cert->certificate)); close(fd); /* * Insert the certificate at the front of the list... */ cert->next = Certs; Certs = cert; }
static int acl_from_text_callback(acl_tag_t tag, int perms, const char *name, size_t name_len, void *params_casted) { DEBUG("acl_from_text: tag: %d, name: %s, name_len: %lu\n", tag, name, (long unsigned)name_len); struct acl_from_text_params *params = (struct acl_from_text_params *)(params_casted); if (params->acl != NULL) { resolve resolve_func = params->custom_resolve; void *resolve_data = params->custom_resolve_data; uint32_t id = ((name == NULL || name_len == 0) ? ACL_UNDEFINED_ID : resolve_func(tag, name, name_len, resolve_data)); switch (tag) { case ACL_USER: case ACL_GROUP: if (id == ACL_UNDEFINED_ID) { return -ENOENT; } break; } acl_entry_t entry = NULL; errno = 0; if (acl_create_entry(params->acl, &entry) != 0) { DEBUG("%d\n", 1); return -errno; } errno = 0; if (acl_set_tag_type(entry, tag) != 0) { DEBUG("%d\n", 2); return -errno; } acl_permset_t permset = NULL; errno = 0; if (acl_get_permset(entry, &permset) != 0) { return -errno; } if ((perms & ACL_READ) != 0) { errno = 0; if (acl_add_perm(permset, ACL_READ) != 0) { return -errno; } } if ((perms & ACL_WRITE) != 0) { errno = 0; if (acl_add_perm(permset, ACL_WRITE) != 0) { return -errno; } } if ((perms & ACL_EXECUTE) != 0) { errno = 0; if (acl_add_perm(permset, ACL_EXECUTE) != 0) { return -errno; } } errno = 0; if (acl_set_permset(entry, permset) != 0) { return -errno; } switch (tag) { case ACL_USER: { uid_t uid = (uid_t)(id); errno = 0; if (acl_set_qualifier(entry, (void *)&uid) != 0) { DEBUG("%d\n", 4); return -errno; } } case ACL_GROUP: { gid_t gid = (gid_t)(id); errno = 0; if (acl_set_qualifier(entry, (void *)&gid) != 0) { DEBUG("%d\n", 5); return -errno; } } break; } } ++params->count; return 0; }
MateVFSResult file_set_acl (const char *path, const MateVFSFileInfo *info, MateVFSContext *context) { #ifdef HAVE_SOLARIS_ACL GList *acls; GList *entry; guint len; MateVFSResult re; aclent_t *new_aclp; aclent_t *taclp; guint aclp_i; gboolean changed; if (info->acl == NULL) return MATE_VFS_ERROR_BAD_PARAMETERS; acls = mate_vfs_acl_get_ace_list (info->acl); if (acls == NULL) return MATE_VFS_OK; changed = fixup_acl (info->acl, acls); if (changed) { mate_vfs_acl_free_ace_list (acls); acls = mate_vfs_acl_get_ace_list (info->acl); if (acls == NULL) return MATE_VFS_OK; } len = g_list_length (acls); if (len <= 0) return MATE_VFS_OK; new_aclp = (aclent_t *) malloc (len * sizeof(aclent_t)); if (new_aclp == NULL) return MATE_VFS_ERROR_NO_MEMORY; memset (new_aclp, 0, len * sizeof(aclent_t)); aclp_i = 0; taclp = new_aclp; for (entry=acls; entry != NULL; entry = entry->next) { MateVFSACE *ace = MATE_VFS_ACE(entry->data); re = translate_ace_into_aclent (ace, taclp); if (re != MATE_VFS_OK) continue; aclp_i++; taclp++; } /* Sort it out */ re = aclsort (aclp_i, 0, (aclent_t *)new_aclp); if (re == -1) { g_free (new_aclp); return MATE_VFS_ERROR_INTERNAL; } /* Commit it to the file system */ re = acl (path, SETACL, aclp_i, (aclent_t *)new_aclp); if (re < 0) { int err = errno; g_free (new_aclp); return aclerrno_to_vfserror(err); } g_free (new_aclp); return MATE_VFS_OK; #elif defined(HAVE_POSIX_ACL) GList *acls; GList *entry; acl_t acl_obj; acl_t acl_obj_default; if (info->acl == NULL) return MATE_VFS_ERROR_BAD_PARAMETERS; /* POSIX ACL object */ acl_obj_default = acl_get_file (path, ACL_TYPE_DEFAULT); acl_obj = acl_get_file (path, ACL_TYPE_ACCESS); if (acl_obj == NULL) return MATE_VFS_ERROR_GENERIC; /* Parse stored information */ acls = mate_vfs_acl_get_ace_list (info->acl); if (acls == NULL) return MATE_VFS_OK; for (entry=acls; entry != NULL; entry = entry->next) { MateVFSACE *ace = MATE_VFS_ACE(entry->data); gboolean is_default = FALSE; const char *id_str; MateVFSACLKind kind; int id; int re; acl_tag_t type; mode_t perms = 0; acl_entry_t new_entry = NULL; acl_permset_t permset = NULL; id_str = mate_vfs_ace_get_id (ace); kind = mate_vfs_ace_get_kind (ace); is_default = mate_vfs_ace_get_inherit (ace); /* Perms */ if (mate_vfs_ace_check_perm (ace, MATE_VFS_ACL_READ)) perms |= CMD_PERM_READ; else if (mate_vfs_ace_check_perm (ace, MATE_VFS_ACL_WRITE)) perms |= CMD_PERM_WRITE; else if (mate_vfs_ace_check_perm (ace, MATE_VFS_ACL_EXECUTE)) perms |= CMD_PERM_EXECUTE; /* Type */ switch (kind) { case MATE_VFS_ACL_USER: id = string_to_uid (id_str); type = ACL_USER; break; case MATE_VFS_ACL_GROUP: id = string_to_gid (id_str); type = ACL_GROUP; break; case MATE_VFS_ACL_OTHER: type = ACL_OTHER; break; default: return MATE_VFS_ERROR_NOT_SUPPORTED; } /* Add the entry */ new_entry = find_entry (acl_obj, type, id); if (new_entry == NULL) { /* new */ if (is_default) re = acl_create_entry (&acl_obj_default, &new_entry); else re = acl_create_entry (&acl_obj, &new_entry); if (re != 0) return aclerrno_to_vfserror (errno); /* e_tag */ re = acl_set_tag_type (new_entry, type); if (re != 0) return aclerrno_to_vfserror (errno); /* e_id */ re = acl_set_qualifier (new_entry, &id); if (re != 0) return aclerrno_to_vfserror (errno); } /* e_perm */ re = acl_get_permset (new_entry, &permset); if (re != 0) return aclerrno_to_vfserror (errno); set_permset (permset, perms); /* Fix it up */ if (is_default && (acl_obj_default != NULL)) { if (! find_entry (acl_obj_default, ACL_USER_OBJ, ACL_UNDEFINED_ID)) { clone_entry (acl_obj, ACL_USER_OBJ, &acl_obj_default, ACL_USER_OBJ); } if (! find_entry (acl_obj_default, ACL_GROUP_OBJ, ACL_UNDEFINED_ID)) { clone_entry (acl_obj, ACL_GROUP_OBJ, &acl_obj_default, ACL_GROUP_OBJ); } if (! find_entry (acl_obj_default, ACL_OTHER, ACL_UNDEFINED_ID)) { clone_entry (acl_obj, ACL_OTHER, &acl_obj_default, ACL_OTHER); } } if (acl_equiv_mode (acl_obj, NULL) != 0) { if (! find_entry (acl_obj, ACL_MASK, ACL_UNDEFINED_ID)) { clone_entry (acl_obj, ACL_GROUP_OBJ, &acl_obj, ACL_MASK); } if (is_default) re = acl_calc_mask (&acl_obj_default); else re = acl_calc_mask (&acl_obj); if (re != 0) return aclerrno_to_vfserror (errno); } } mate_vfs_acl_free_ace_list (acls); return MATE_VFS_OK; #else return MATE_VFS_ERROR_NOT_SUPPORTED; #endif }
/* * return an ACL corresponding to the permissions * contained in struct stat */ static acl_t acl_from_stat(struct stat sb) { acl_t acl; acl_entry_t entry; acl_permset_t perms; /* create the ACL */ acl = acl_init(3); if (!acl) return NULL; /* First entry: ACL_USER_OBJ */ if (acl_create_entry(&acl, &entry) == -1) return NULL; if (acl_set_tag_type(entry, ACL_USER_OBJ) == -1) return NULL; if (acl_get_permset(entry, &perms) == -1) return NULL; if (acl_clear_perms(perms) == -1) return NULL; /* calculate user mode */ if (sb.st_mode & S_IRUSR) if (acl_add_perm(perms, ACL_READ) == -1) return NULL; if (sb.st_mode & S_IWUSR) if (acl_add_perm(perms, ACL_WRITE) == -1) return NULL; if (sb.st_mode & S_IXUSR) if (acl_add_perm(perms, ACL_EXECUTE) == -1) return NULL; if (acl_set_permset(entry, perms) == -1) return NULL; /* Second entry: ACL_GROUP_OBJ */ if (acl_create_entry(&acl, &entry) == -1) return NULL; if (acl_set_tag_type(entry, ACL_GROUP_OBJ) == -1) return NULL; if (acl_get_permset(entry, &perms) == -1) return NULL; if (acl_clear_perms(perms) == -1) return NULL; /* calculate group mode */ if (sb.st_mode & S_IRGRP) if (acl_add_perm(perms, ACL_READ) == -1) return NULL; if (sb.st_mode & S_IWGRP) if (acl_add_perm(perms, ACL_WRITE) == -1) return NULL; if (sb.st_mode & S_IXGRP) if (acl_add_perm(perms, ACL_EXECUTE) == -1) return NULL; if (acl_set_permset(entry, perms) == -1) return NULL; /* Third entry: ACL_OTHER */ if (acl_create_entry(&acl, &entry) == -1) return NULL; if (acl_set_tag_type(entry, ACL_OTHER) == -1) return NULL; if (acl_get_permset(entry, &perms) == -1) return NULL; if (acl_clear_perms(perms) == -1) return NULL; /* calculate other mode */ if (sb.st_mode & S_IROTH) if (acl_add_perm(perms, ACL_READ) == -1) return NULL; if (sb.st_mode & S_IWOTH) if (acl_add_perm(perms, ACL_WRITE) == -1) return NULL; if (sb.st_mode & S_IXOTH) if (acl_add_perm(perms, ACL_EXECUTE) == -1) return NULL; if (acl_set_permset(entry, perms) == -1) return NULL; return(acl); }
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; }
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 acl_from_text(const char *buf_p) { int i, error = 0, need_tag, ug_tag; char *buf, *orig_buf; char *entry, *field, *sub; uuid_t *uu = NULL; struct passwd *tpass = NULL; struct group *tgrp = NULL; acl_entry_t acl_entry; acl_flagset_t flags = NULL; acl_permset_t perms = NULL; acl_tag_t tag; acl_t acl_ret; if (buf_p == NULL) { errno = EINVAL; return NULL; } if ((buf = strdup(buf_p)) == NULL) return NULL; if ((acl_ret = acl_init(1)) == NULL) return NULL; orig_buf = buf; /* global acl flags * format: !#acl <version> [<flags>] */ if ((entry = strsep(&buf, "\n")) != NULL && *entry) { /* field 1: !#acl */ field = strsep(&entry, " "); if (*field && strncmp(field, "!#acl", strlen("!#acl"))) { error = EINVAL; goto exit; } /* field 2: <version> * currently only accepts 1 */ field = strsep(&entry, " "); errno = 0; if (!*field || strtol(field, NULL, 0) != 1) { error = EINVAL; goto exit; } /* field 3: <flags> * optional */ if((field = strsep(&entry, " ")) != NULL && *field) { acl_get_flagset_np(acl_ret, &flags); while ((sub = strsep(&field, ",")) && *sub) { for (i = 0; acl_flags[i].name != NULL; ++i) { if (acl_flags[i].type & ACL_TYPE_ACL && !strcmp(acl_flags[i].name, sub)) { acl_add_flag_np(flags, acl_flags[i].flag); break; } } if (acl_flags[i].name == NULL) { /* couldn't find flag */ error = EINVAL; goto exit; } } } } else { error = EINVAL; goto exit; } /* parse each acl line * format: <user|group>: * [<uuid>]: * [<user|group>]: * [<uid|gid>]: * <allow|deny>[,<flags>] * [:<permissions>[,<permissions>]] * * only one of the user/group identifies is required * the first one found is used */ while ((entry = strsep(&buf, "\n")) && *entry) { need_tag = 1; ug_tag = -1; /* field 1: <user|group> */ field = strsep(&entry, ":"); if(uu) bzero(uu, sizeof(uuid_t)); else if((uu = calloc(1, sizeof(uuid_t))) == NULL) { error = errno; goto exit; } if(acl_create_entry(&acl_ret, &acl_entry)) { error = errno; goto exit; } if (-1 == acl_get_flagset_np(acl_entry, &flags) || -1 == acl_get_permset(acl_entry, &perms)) { error = errno; goto exit; } switch(*field) { case 'u': if(!strcmp(field, "user")) ug_tag = ID_TYPE_UID; break; case 'g': if(!strcmp(field, "group")) ug_tag = ID_TYPE_GID; break; default: error = EINVAL; goto exit; } /* field 2: <uuid> */ if ((field = strsep(&entry, ":")) != NULL && *field) { uuid_parse(field, *uu); need_tag = 0; } /* field 3: <username|groupname> */ if ((field = strsep(&entry, ":")) != NULL && *field && need_tag) { switch(ug_tag) { case ID_TYPE_UID: if((tpass = getpwnam(field)) != NULL) if (mbr_uid_to_uuid(tpass->pw_uid, *uu) != 0) { error = EINVAL; goto exit; } break; case ID_TYPE_GID: if ((tgrp = getgrnam(field)) != NULL) if (mbr_gid_to_uuid(tgrp->gr_gid, *uu) != 0) { error = EINVAL; goto exit; } break; default: error = EINVAL; goto exit; } need_tag = 0; } /* field 4: <uid|gid> */ if ((field = strsep(&entry, ":")) != NULL && *field && need_tag) { uid_t id; error = 0; if((id = strtol(field, NULL, 10)) == 0 && error) { error = EINVAL; goto exit; } switch(ug_tag) { case ID_TYPE_UID: if((tpass = getpwuid((uid_t)id)) != NULL) if (mbr_uid_to_uuid(tpass->pw_uid, *uu) != 0) { error = EINVAL; goto exit; } break; case ID_TYPE_GID: if ((tgrp = getgrgid((gid_t)id)) != NULL) if (mbr_gid_to_uuid(tgrp->gr_gid, *uu) != 0) { error = EINVAL; goto exit; } break; } need_tag = 0; } /* sanity check: nothing set as qualifier */ if (need_tag) { error = EINVAL; goto exit; } /* field 5: <flags> */ if((field = strsep(&entry, ":")) == NULL || !*field) { error = EINVAL; goto exit; } for (tag = 0; (sub = strsep(&field, ",")) && *sub;) { if (!tag) { if (!strcmp(sub, "allow")) tag = ACL_EXTENDED_ALLOW; else if (!strcmp(sub, "deny")) tag = ACL_EXTENDED_DENY; else { error = EINVAL; goto exit; } continue; } for (i = 0; acl_flags[i].name != NULL; ++i) { if (acl_flags[i].type & (ACL_TYPE_FILE | ACL_TYPE_DIR) && !strcmp(acl_flags[i].name, sub)) { acl_add_flag_np(flags, acl_flags[i].flag); break; } } if (acl_flags[i].name == NULL) { /* couldn't find perm */ error = EINVAL; goto exit; } } /* field 6: <perms> (can be empty) */ if((field = strsep(&entry, ":")) != NULL && *field) { while ((sub = strsep(&field, ",")) && *sub) { for (i = 0; acl_perms[i].name != NULL; i++) { if (acl_perms[i].type & (ACL_TYPE_FILE | ACL_TYPE_DIR) && !strcmp(acl_perms[i].name, sub)) { acl_add_perm(perms, acl_perms[i].perm); break; } } if (acl_perms[i].name == NULL) { /* couldn't find perm */ error = EINVAL; goto exit; } } } acl_set_tag_type(acl_entry, tag); acl_set_qualifier(acl_entry, *uu); } exit: if(uu) free(uu); free(orig_buf); if (error) { acl_free(acl_ret); acl_ret = NULL; errno = error; } return acl_ret; }
/* * 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); }
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_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 acl_t smb_acl_to_posix(const struct smb_acl_t *acl) { acl_t result; int i; result = acl_init(acl->count); if (result == NULL) { DEBUG(10, ("acl_init failed\n")); return NULL; } for (i=0; i<acl->count; i++) { const struct smb_acl_entry *entry = &acl->acl[i]; acl_entry_t e; acl_tag_t tag; if (acl_create_entry(&result, &e) != 0) { DEBUG(1, ("acl_create_entry failed: %s\n", strerror(errno))); goto fail; } switch (entry->a_type) { case SMB_ACL_USER: tag = ACL_USER; break; case SMB_ACL_USER_OBJ: tag = ACL_USER_OBJ; break; case SMB_ACL_GROUP: tag = ACL_GROUP; break; case SMB_ACL_GROUP_OBJ: tag = ACL_GROUP_OBJ; break; case SMB_ACL_OTHER: tag = ACL_OTHER; break; case SMB_ACL_MASK: tag = ACL_MASK; break; default: DEBUG(1, ("Unknown tag value %d\n", entry->a_type)); goto fail; } if (acl_set_tag_type(e, tag) != 0) { DEBUG(10, ("acl_set_tag_type(%d) failed: %s\n", tag, strerror(errno))); goto fail; } switch (entry->a_type) { case SMB_ACL_USER: if (acl_set_qualifier(e, &entry->uid) != 0) { DEBUG(1, ("acl_set_qualifiier failed: %s\n", strerror(errno))); goto fail; } break; case SMB_ACL_GROUP: if (acl_set_qualifier(e, &entry->gid) != 0) { DEBUG(1, ("acl_set_qualifiier failed: %s\n", strerror(errno))); goto fail; } break; default: /* Shut up, compiler! :-) */ break; } if (smb_acl_set_mode(e, entry->a_perm) != 0) { goto fail; } } if (acl_valid(result) != 0) { DEBUG(0, ("smb_acl_to_posix: ACL is invalid for set (%s)\n", strerror(errno))); goto fail; } return result; fail: if (result != NULL) { acl_free(result); } return NULL; }
int fpm_unix_resolve_socket_premissions(struct fpm_worker_pool_s *wp) /* {{{ */ { struct fpm_worker_pool_config_s *c = wp->config; #ifdef HAVE_FPM_ACL int n; /* uninitialized */ wp->socket_acl = NULL; #endif wp->socket_uid = -1; wp->socket_gid = -1; wp->socket_mode = 0660; if (!c) { return 0; } if (c->listen_mode && *c->listen_mode) { wp->socket_mode = strtoul(c->listen_mode, 0, 8); } #ifdef HAVE_FPM_ACL /* count the users and groups configured */ n = 0; if (c->listen_acl_users && *c->listen_acl_users) { char *p; n++; for (p=strchr(c->listen_acl_users, ',') ; p ; p=strchr(p+1, ',')) { n++; } } if (c->listen_acl_groups && *c->listen_acl_groups) { char *p; n++; for (p=strchr(c->listen_acl_groups, ',') ; p ; p=strchr(p+1, ',')) { n++; } } /* if ACL configured */ if (n) { acl_t acl; acl_entry_t entry; acl_permset_t perm; char *tmp, *p, *end; acl = acl_init(n); if (!acl) { zlog(ZLOG_SYSERROR, "[pool %s] cannot allocate ACL", wp->config->name); return -1; } /* Create USER ACL */ if (c->listen_acl_users && *c->listen_acl_users) { struct passwd *pwd; tmp = estrdup(c->listen_acl_users); for (p=tmp ; p ; p=end) { if ((end = strchr(p, ','))) { *end++ = 0; } pwd = getpwnam(p); if (pwd) { zlog(ZLOG_DEBUG, "[pool %s] user '%s' have uid=%d", wp->config->name, p, pwd->pw_uid); } else { zlog(ZLOG_SYSERROR, "[pool %s] cannot get uid for user '%s'", wp->config->name, p); acl_free(acl); efree(tmp); return -1; } if (0 > acl_create_entry(&acl, &entry) || 0 > acl_set_tag_type(entry, ACL_USER) || 0 > acl_set_qualifier(entry, &pwd->pw_uid) || 0 > acl_get_permset(entry, &perm) || 0 > acl_clear_perms (perm) || 0 > acl_add_perm (perm, ACL_READ) || 0 > acl_add_perm (perm, ACL_WRITE)) { zlog(ZLOG_SYSERROR, "[pool %s] cannot create ACL for user '%s'", wp->config->name, p); acl_free(acl); efree(tmp); return -1; } } efree(tmp); } /* Create GROUP ACL */ if (c->listen_acl_groups && *c->listen_acl_groups) { struct group *grp; tmp = estrdup(c->listen_acl_groups); for (p=tmp ; p ; p=end) { if ((end = strchr(p, ','))) { *end++ = 0; } grp = getgrnam(p); if (grp) { zlog(ZLOG_DEBUG, "[pool %s] group '%s' have gid=%d", wp->config->name, p, grp->gr_gid); } else { zlog(ZLOG_SYSERROR, "[pool %s] cannot get gid for group '%s'", wp->config->name, p); acl_free(acl); efree(tmp); return -1; } if (0 > acl_create_entry(&acl, &entry) || 0 > acl_set_tag_type(entry, ACL_GROUP) || 0 > acl_set_qualifier(entry, &grp->gr_gid) || 0 > acl_get_permset(entry, &perm) || 0 > acl_clear_perms (perm) || 0 > acl_add_perm (perm, ACL_READ) || 0 > acl_add_perm (perm, ACL_WRITE)) { zlog(ZLOG_SYSERROR, "[pool %s] cannot create ACL for group '%s'", wp->config->name, p); acl_free(acl); efree(tmp); return -1; } } efree(tmp); } if (c->listen_owner && *c->listen_owner) { zlog(ZLOG_WARNING, "[pool %s] ACL set, listen.owner = '%s' is ignored", wp->config->name, c->listen_owner); } if (c->listen_group && *c->listen_group) { zlog(ZLOG_WARNING, "[pool %s] ACL set, listen.group = '%s' is ignored", wp->config->name, c->listen_group); } wp->socket_acl = acl; return 0; } /* When listen.users and listen.groups not configured, continue with standard right */ #endif if (c->listen_owner && *c->listen_owner) { struct passwd *pwd; pwd = getpwnam(c->listen_owner); if (!pwd) { zlog(ZLOG_SYSERROR, "[pool %s] cannot get uid for user '%s'", wp->config->name, c->listen_owner); return -1; } wp->socket_uid = pwd->pw_uid; wp->socket_gid = pwd->pw_gid; } if (c->listen_group && *c->listen_group) { struct group *grp; grp = getgrnam(c->listen_group); if (!grp) { zlog(ZLOG_SYSERROR, "[pool %s] cannot get gid for group '%s'", wp->config->name, c->listen_group); return -1; } wp->socket_gid = grp->gr_gid; } return 0; }
/* * 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; } }
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; }
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); }
int acl_readonly_example(uuid_t *uuid) { int fd; acl_t acl; acl_entry_t ace; acl_permset_t perms; filesec_t fsec; /* initialize our ACL */ if (NULL == (acl = acl_init(32))) err(1, "acl_init()"); /* * create an ACE * * acl_create_entry_np() has a position capability via the * 'entry_index' argument (ACL_FIRST_ENTRY or ACL_LAST_ENTRY) */ if (0 != acl_create_entry(&acl, &ace)) err(1, "acl_create_entry()"); /* allow or deny */ if (0 != acl_set_tag_type(ace, ACL_EXTENDED_ALLOW)) err(1, "acl_set_tag_type()"); /* associate this with our uuid */ if (0 != acl_set_qualifier(ace, uuid)) err(1, "acl_set_qualifier()"); /* grant "read only" permissions */ if (0 != acl_get_permset(ace, &perms)) err(1, "acl_get_permset()"); if (0 != acl_clear_perms(perms)) err(1, "acl_clear_perms()"); if (0 != acl_add_perm(perms, ROPERMS)) err(1, "acl_add_perm()"); if (0 != acl_set_permset(ace, perms)) err(1, "acl_set_permset()"); /* create a file security object */ fsec = filesec_init(); /* add the ACL to the security descriptor */ filesec_set_property(fsec, FILESEC_ACL, &acl); acl_free(acl); /* turn off all other permissions on the file */ filesec_set_property(fsec, FILESEC_MODE, 0); /* create a file using our ACL */ fd = openx_np("foo", O_CREAT|O_EXCL|O_RDWR, fsec); /* clean up */ filesec_free(fsec); if (-1 != fd ) close(fd); return(fd); }
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 set_acl(struct archive *a, int fd, const char *name, struct archive_acl *abstract_acl, acl_type_t acl_type, int ae_requested_type, const char *tname) { acl_t acl; acl_entry_t acl_entry; acl_permset_t acl_permset; #ifdef ACL_TYPE_NFS4 acl_flagset_t acl_flagset; int r; #endif int ret; int ae_type, ae_permset, ae_tag, ae_id; uid_t ae_uid; gid_t ae_gid; const char *ae_name; int entries; int i; ret = ARCHIVE_OK; entries = archive_acl_reset(abstract_acl, ae_requested_type); if (entries == 0) return (ARCHIVE_OK); acl = acl_init(entries); while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type, &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) { acl_create_entry(&acl, &acl_entry); switch (ae_tag) { case ARCHIVE_ENTRY_ACL_USER: acl_set_tag_type(acl_entry, ACL_USER); ae_uid = archive_write_disk_uid(a, ae_name, ae_id); acl_set_qualifier(acl_entry, &ae_uid); break; case ARCHIVE_ENTRY_ACL_GROUP: acl_set_tag_type(acl_entry, ACL_GROUP); ae_gid = archive_write_disk_gid(a, ae_name, ae_id); acl_set_qualifier(acl_entry, &ae_gid); break; case ARCHIVE_ENTRY_ACL_USER_OBJ: acl_set_tag_type(acl_entry, ACL_USER_OBJ); break; case ARCHIVE_ENTRY_ACL_GROUP_OBJ: acl_set_tag_type(acl_entry, ACL_GROUP_OBJ); break; case ARCHIVE_ENTRY_ACL_MASK: acl_set_tag_type(acl_entry, ACL_MASK); break; case ARCHIVE_ENTRY_ACL_OTHER: acl_set_tag_type(acl_entry, ACL_OTHER); break; #ifdef ACL_TYPE_NFS4 case ARCHIVE_ENTRY_ACL_EVERYONE: acl_set_tag_type(acl_entry, ACL_EVERYONE); break; #endif default: /* XXX */ break; } #ifdef ACL_TYPE_NFS4 switch (ae_type) { case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALLOW); break; case ARCHIVE_ENTRY_ACL_TYPE_DENY: acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_DENY); break; case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_AUDIT); break; case ARCHIVE_ENTRY_ACL_TYPE_ALARM: acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALARM); break; case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: // These don't translate directly into the system ACL. break; default: // XXX error handling here. break; } #endif acl_get_permset(acl_entry, &acl_permset); acl_clear_perms(acl_permset); for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) { if (ae_permset & acl_perm_map[i].archive_perm) acl_add_perm(acl_permset, acl_perm_map[i].platform_perm); } #ifdef ACL_TYPE_NFS4 // XXX acl_get_flagset_np on FreeBSD returns EINVAL for // non-NFSv4 ACLs r = acl_get_flagset_np(acl_entry, &acl_flagset); if (r == 0) { acl_clear_flags_np(acl_flagset); for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) { if (ae_permset & acl_inherit_map[i].archive_inherit) acl_add_flag_np(acl_flagset, acl_inherit_map[i].platform_inherit); } } #endif } /* Try restoring the ACL through 'fd' if we can. */ #if HAVE_ACL_SET_FD if (fd >= 0 && acl_type == ACL_TYPE_ACCESS && acl_set_fd(fd, acl) == 0) ret = ARCHIVE_OK; else #else #if HAVE_ACL_SET_FD_NP if (fd >= 0 && acl_set_fd_np(fd, acl, acl_type) == 0) ret = ARCHIVE_OK; else #endif #endif #if HAVE_ACL_SET_LINK_NP if (acl_set_link_np(name, acl_type, acl) != 0) { archive_set_error(a, errno, "Failed to set %s acl", tname); ret = ARCHIVE_WARN; } #else /* TODO: Skip this if 'name' is a symlink. */ if (acl_set_file(name, acl_type, acl) != 0) { archive_set_error(a, errno, "Failed to set %s acl", tname); ret = ARCHIVE_WARN; } #endif acl_free(acl); return (ret); }