📄 nfs4acl.c
字号:
struct posix_ace_state group; struct posix_ace_state other; struct posix_ace_state everyone; struct posix_ace_state mask; /* Deny unused in this case */ struct posix_ace_state_array *users; struct posix_ace_state_array *groups;};static intinit_state(struct posix_acl_state *state, int cnt){ int alloc; memset(state, 0, sizeof(struct posix_acl_state)); state->empty = 1; /* * In the worst case, each individual acl could be for a distinct * named user or group, but we don't no which, so we allocate * enough space for either: */ alloc = sizeof(struct posix_ace_state_array) + cnt*sizeof(struct posix_ace_state); state->users = kzalloc(alloc, GFP_KERNEL); if (!state->users) return -ENOMEM; state->groups = kzalloc(alloc, GFP_KERNEL); if (!state->groups) { kfree(state->users); return -ENOMEM; } return 0;}static voidfree_state(struct posix_acl_state *state) { kfree(state->users); kfree(state->groups);}static inline void add_to_mask(struct posix_acl_state *state, struct posix_ace_state *astate){ state->mask.allow |= astate->allow;}/* * Certain bits (SYNCHRONIZE, DELETE, WRITE_OWNER, READ/WRITE_NAMED_ATTRS, * READ_ATTRIBUTES, READ_ACL) are currently unenforceable and don't translate * to traditional read/write/execute permissions. * * It's problematic to reject acls that use certain mode bits, because it * places the burden on users to learn the rules about which bits one * particular server sets, without giving the user a lot of help--we return an * error that could mean any number of different things. To make matters * worse, the problematic bits might be introduced by some application that's * automatically mapping from some other acl model. * * So wherever possible we accept anything, possibly erring on the side of * denying more permissions than necessary. * * However we do reject *explicit* DENY's of a few bits representing * permissions we could never deny: */static inline int check_deny(u32 mask, int isowner){ if (mask & (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL)) return -EINVAL; if (!isowner) return 0; if (mask & (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL)) return -EINVAL; return 0;}static struct posix_acl *posix_state_to_acl(struct posix_acl_state *state, unsigned int flags){ struct posix_acl_entry *pace; struct posix_acl *pacl; int nace; int i, error = 0; /* * ACLs with no ACEs are treated differently in the inheritable * and effective cases: when there are no inheritable ACEs, we * set a zero-length default posix acl: */ if (state->empty && (flags & NFS4_ACL_TYPE_DEFAULT)) { pacl = posix_acl_alloc(0, GFP_KERNEL); return pacl ? pacl : ERR_PTR(-ENOMEM); } /* * When there are no effective ACEs, the following will end * up setting a 3-element effective posix ACL with all * permissions zero. */ nace = 4 + state->users->n + state->groups->n; pacl = posix_acl_alloc(nace, GFP_KERNEL); if (!pacl) return ERR_PTR(-ENOMEM); pace = pacl->a_entries; pace->e_tag = ACL_USER_OBJ; error = check_deny(state->owner.deny, 1); if (error) goto out_err; low_mode_from_nfs4(state->owner.allow, &pace->e_perm, flags); pace->e_id = ACL_UNDEFINED_ID; for (i=0; i < state->users->n; i++) { pace++; pace->e_tag = ACL_USER; error = check_deny(state->users->aces[i].perms.deny, 0); if (error) goto out_err; low_mode_from_nfs4(state->users->aces[i].perms.allow, &pace->e_perm, flags); pace->e_id = state->users->aces[i].uid; add_to_mask(state, &state->users->aces[i].perms); } pace++; pace->e_tag = ACL_GROUP_OBJ; error = check_deny(state->group.deny, 0); if (error) goto out_err; low_mode_from_nfs4(state->group.allow, &pace->e_perm, flags); pace->e_id = ACL_UNDEFINED_ID; add_to_mask(state, &state->group); for (i=0; i < state->groups->n; i++) { pace++; pace->e_tag = ACL_GROUP; error = check_deny(state->groups->aces[i].perms.deny, 0); if (error) goto out_err; low_mode_from_nfs4(state->groups->aces[i].perms.allow, &pace->e_perm, flags); pace->e_id = state->groups->aces[i].uid; add_to_mask(state, &state->groups->aces[i].perms); } pace++; pace->e_tag = ACL_MASK; low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags); pace->e_id = ACL_UNDEFINED_ID; pace++; pace->e_tag = ACL_OTHER; error = check_deny(state->other.deny, 0); if (error) goto out_err; low_mode_from_nfs4(state->other.allow, &pace->e_perm, flags); pace->e_id = ACL_UNDEFINED_ID; return pacl;out_err: posix_acl_release(pacl); return ERR_PTR(error);}static inline void allow_bits(struct posix_ace_state *astate, u32 mask){ /* Allow all bits in the mask not already denied: */ astate->allow |= mask & ~astate->deny;}static inline void deny_bits(struct posix_ace_state *astate, u32 mask){ /* Deny all bits in the mask not already allowed: */ astate->deny |= mask & ~astate->allow;}static int find_uid(struct posix_acl_state *state, struct posix_ace_state_array *a, uid_t uid){ int i; for (i = 0; i < a->n; i++) if (a->aces[i].uid == uid) return i; /* Not found: */ a->n++; a->aces[i].uid = uid; a->aces[i].perms.allow = state->everyone.allow; a->aces[i].perms.deny = state->everyone.deny; return i;}static void deny_bits_array(struct posix_ace_state_array *a, u32 mask){ int i; for (i=0; i < a->n; i++) deny_bits(&a->aces[i].perms, mask);}static void allow_bits_array(struct posix_ace_state_array *a, u32 mask){ int i; for (i=0; i < a->n; i++) allow_bits(&a->aces[i].perms, mask);}static void process_one_v4_ace(struct posix_acl_state *state, struct nfs4_ace *ace){ u32 mask = ace->access_mask; int i; state->empty = 0; switch (ace2type(ace)) { case ACL_USER_OBJ: if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { allow_bits(&state->owner, mask); } else { deny_bits(&state->owner, mask); } break; case ACL_USER: i = find_uid(state, state->users, ace->who); if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { allow_bits(&state->users->aces[i].perms, mask); } else { deny_bits(&state->users->aces[i].perms, mask); mask = state->users->aces[i].perms.deny; deny_bits(&state->owner, mask); } break; case ACL_GROUP_OBJ: if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { allow_bits(&state->group, mask); } else { deny_bits(&state->group, mask); mask = state->group.deny; deny_bits(&state->owner, mask); deny_bits(&state->everyone, mask); deny_bits_array(state->users, mask); deny_bits_array(state->groups, mask); } break; case ACL_GROUP: i = find_uid(state, state->groups, ace->who); if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { allow_bits(&state->groups->aces[i].perms, mask); } else { deny_bits(&state->groups->aces[i].perms, mask); mask = state->groups->aces[i].perms.deny; deny_bits(&state->owner, mask); deny_bits(&state->group, mask); deny_bits(&state->everyone, mask); deny_bits_array(state->users, mask); deny_bits_array(state->groups, mask); } break; case ACL_OTHER: if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { allow_bits(&state->owner, mask); allow_bits(&state->group, mask); allow_bits(&state->other, mask); allow_bits(&state->everyone, mask); allow_bits_array(state->users, mask); allow_bits_array(state->groups, mask); } else { deny_bits(&state->owner, mask); deny_bits(&state->group, mask); deny_bits(&state->other, mask); deny_bits(&state->everyone, mask); deny_bits_array(state->users, mask); deny_bits_array(state->groups, mask); } }}int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, struct posix_acl **dpacl, unsigned int flags){ struct posix_acl_state effective_acl_state, default_acl_state; struct nfs4_ace *ace; int ret; ret = init_state(&effective_acl_state, acl->naces); if (ret) return ret; ret = init_state(&default_acl_state, acl->naces); if (ret) goto out_estate; ret = -EINVAL; for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) { if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE && ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) goto out_dstate; if (ace->flag & ~NFS4_SUPPORTED_FLAGS) goto out_dstate; if ((ace->flag & NFS4_INHERITANCE_FLAGS) == 0) { process_one_v4_ace(&effective_acl_state, ace); continue; } if (!(flags & NFS4_ACL_DIR)) goto out_dstate; /* * Note that when only one of FILE_INHERIT or DIRECTORY_INHERIT * is set, we're effectively turning on the other. That's OK, * according to rfc 3530. */ process_one_v4_ace(&default_acl_state, ace); if (!(ace->flag & NFS4_ACE_INHERIT_ONLY_ACE)) process_one_v4_ace(&effective_acl_state, ace); } *pacl = posix_state_to_acl(&effective_acl_state, flags); if (IS_ERR(*pacl)) { ret = PTR_ERR(*pacl); *pacl = NULL; goto out_dstate; } *dpacl = posix_state_to_acl(&default_acl_state, flags | NFS4_ACL_TYPE_DEFAULT); if (IS_ERR(*dpacl)) { ret = PTR_ERR(*dpacl); *dpacl = NULL; posix_acl_release(*pacl); *pacl = NULL; goto out_dstate; } sort_pacl(*pacl); sort_pacl(*dpacl); ret = 0;out_dstate: free_state(&default_acl_state);out_estate: free_state(&effective_acl_state); return ret;}static shortace2type(struct nfs4_ace *ace){ switch (ace->whotype) { case NFS4_ACL_WHO_NAMED: return (ace->flag & NFS4_ACE_IDENTIFIER_GROUP ? ACL_GROUP : ACL_USER); case NFS4_ACL_WHO_OWNER: return ACL_USER_OBJ; case NFS4_ACL_WHO_GROUP: return ACL_GROUP_OBJ; case NFS4_ACL_WHO_EVERYONE: return ACL_OTHER; } BUG(); return -1;}EXPORT_SYMBOL(nfs4_acl_posix_to_nfsv4);EXPORT_SYMBOL(nfs4_acl_nfsv4_to_posix);struct nfs4_acl *nfs4_acl_new(int n){ struct nfs4_acl *acl; acl = kmalloc(sizeof(*acl) + n*sizeof(struct nfs4_ace), GFP_KERNEL); if (acl == NULL) return NULL; acl->naces = 0; return acl;}static struct { char *string; int stringlen; int type;} s2t_map[] = { { .string = "OWNER@", .stringlen = sizeof("OWNER@") - 1, .type = NFS4_ACL_WHO_OWNER, }, { .string = "GROUP@", .stringlen = sizeof("GROUP@") - 1, .type = NFS4_ACL_WHO_GROUP, }, { .string = "EVERYONE@", .stringlen = sizeof("EVERYONE@") - 1, .type = NFS4_ACL_WHO_EVERYONE, },};intnfs4_acl_get_whotype(char *p, u32 len){ int i; for (i = 0; i < ARRAY_SIZE(s2t_map); i++) { if (s2t_map[i].stringlen == len && 0 == memcmp(s2t_map[i].string, p, len)) return s2t_map[i].type; } return NFS4_ACL_WHO_NAMED;}intnfs4_acl_write_who(int who, char *p){ int i; for (i = 0; i < ARRAY_SIZE(s2t_map); i++) { if (s2t_map[i].type == who) { memcpy(p, s2t_map[i].string, s2t_map[i].stringlen); return s2t_map[i].stringlen; } } BUG(); return -1;}EXPORT_SYMBOL(nfs4_acl_new);EXPORT_SYMBOL(nfs4_acl_get_whotype);EXPORT_SYMBOL(nfs4_acl_write_who);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -