liz_acl_t *lzfs_int_convert_fsal_acl(const fsal_acl_t *fsal_acl) { liz_acl_t *lzfs_acl = NULL; if (!fsal_acl || (!fsal_acl->aces && fsal_acl->naces > 0)) { return NULL; } int count = 0; for (unsigned i = 0; i < fsal_acl->naces; ++i) { fsal_ace_t *fsal_ace = fsal_acl->aces + i; count += (IS_FSAL_ACE_ALLOW(*fsal_ace) || IS_FSAL_ACE_DENY(*fsal_ace)) ? 1 : 0; } lzfs_acl = liz_create_acl(); if (!lzfs_acl) { return NULL; } for (unsigned i = 0; i < fsal_acl->naces; ++i) { fsal_ace_t *fsal_ace = fsal_acl->aces + i; if (!(IS_FSAL_ACE_ALLOW(*fsal_ace) || IS_FSAL_ACE_DENY(*fsal_ace))) { continue; } liz_acl_ace_t ace; ace.flags = fsal_ace->flag & 0xFF; ace.mask = fsal_ace->perm; ace.type = fsal_ace->type; if (IS_FSAL_ACE_GROUP_ID(*fsal_ace)) { ace.id = GET_FSAL_ACE_GROUP(*fsal_ace); } else { ace.id = GET_FSAL_ACE_USER(*fsal_ace); } if (IS_FSAL_ACE_SPECIAL_ID(*fsal_ace)) { ace.flags |= LIZ_ACL_SPECIAL_WHO; switch (GET_FSAL_ACE_USER(*fsal_ace)) { case FSAL_ACE_SPECIAL_OWNER: ace.id = LIZ_ACL_OWNER_SPECIAL_ID; break; case FSAL_ACE_SPECIAL_GROUP: ace.id = LIZ_ACL_GROUP_SPECIAL_ID; break; case FSAL_ACE_SPECIAL_EVERYONE: ace.id = LIZ_ACL_EVERYONE_SPECIAL_ID; break; default: LogFullDebug(COMPONENT_FSAL, "Invalid FSAL ACE special id type (%d)", (int)GET_FSAL_ACE_USER(*fsal_ace)); continue; } } liz_add_acl_entry(lzfs_acl, &ace); } return lzfs_acl; }
int display_fsal_ace(struct display_buffer *dspbuf, int ace_number, fsal_ace_t *pace, bool is_dir) { int b_left; if (!pace) return display_cat(dspbuf, "ACE: <NULL>"); /* Print the entire ACE. */ b_left = display_printf(dspbuf, "ACE %d:", ace_number); /* ACE type. */ if (b_left > 0) b_left = display_cat(dspbuf, IS_FSAL_ACE_ALLOW(*pace) ? " allow" : IS_FSAL_ACE_DENY(*pace) ? " deny" : IS_FSAL_ACE_AUDIT(*pace) ? " audit" : " ?"); /* ACE who and its type. */ if (b_left > 0 && IS_FSAL_ACE_SPECIAL_ID(*pace)) b_left = display_cat(dspbuf, IS_FSAL_ACE_SPECIAL_OWNER(*pace) ? " owner@" : IS_FSAL_ACE_SPECIAL_GROUP(*pace) ? " group@" : IS_FSAL_ACE_SPECIAL_EVERYONE(*pace) ? " everyone@" : ""); if (b_left > 0 && !IS_FSAL_ACE_SPECIAL_ID(*pace)) { if (IS_FSAL_ACE_SPECIAL_ID(*pace)) b_left = display_printf(dspbuf, " gid %d", pace->who.gid); else b_left = display_printf(dspbuf, " uid %d", pace->who.uid); } /* ACE mask. */ if (b_left > 0) b_left = display_fsal_v4mask(dspbuf, pace->perm, is_dir); /* ACE Inherit flags. */ if (b_left > 0 && IS_FSAL_ACE_INHERIT(*pace)) b_left = display_fsal_inherit_flags(dspbuf, pace); return b_left; }
static void fsal_print_ace(int ace_number, fsal_ace_t *pace, char *p_acebuf) { char inherit_flags[ACL_DEBUG_BUF_SIZE]; if(!pace || !p_acebuf) return; memset(p_acebuf, 0, ACL_DEBUG_BUF_SIZE); memset(inherit_flags, 0, ACL_DEBUG_BUF_SIZE); /* Get inherit flags if any. */ fsal_print_inherit_flags(pace, inherit_flags); /* Print the entire ACE. */ sprintf(p_acebuf, "ACE %d %s %s %d %c%c%c%c%c%c%c%c%c%c%c%c%c%c %s", ace_number, /* ACE type. */ IS_FSAL_ACE_ALLOW(*pace)? "allow": IS_FSAL_ACE_DENY(*pace) ? "deny": IS_FSAL_ACE_AUDIT(*pace)? "audit": "?", /* ACE who and its type. */ (IS_FSAL_ACE_SPECIAL_ID(*pace) && IS_FSAL_ACE_SPECIAL_OWNER(*pace)) ? "owner@": (IS_FSAL_ACE_SPECIAL_ID(*pace) && IS_FSAL_ACE_SPECIAL_GROUP(*pace)) ? "group@": (IS_FSAL_ACE_SPECIAL_ID(*pace) && IS_FSAL_ACE_SPECIAL_EVERYONE(*pace)) ? "everyone@": IS_FSAL_ACE_SPECIAL_ID(*pace) ? "specialid": IS_FSAL_ACE_GROUP_ID(*pace) ? "gid": "uid", GET_FSAL_ACE_WHO(*pace), /* ACE mask. */ IS_FSAL_ACE_READ_DATA(*pace) ? 'r':'-', IS_FSAL_ACE_WRITE_DATA(*pace) ? 'w':'-', IS_FSAL_ACE_EXECUTE(*pace) ? 'x':'-', IS_FSAL_ACE_ADD_SUBDIRECTORY(*pace) ? 'm':'-', IS_FSAL_ACE_READ_NAMED_ATTR(*pace) ? 'n':'-', IS_FSAL_ACE_WRITE_NAMED_ATTR(*pace) ? 'N':'-', IS_FSAL_ACE_DELETE_CHILD(*pace) ? 'p':'-', IS_FSAL_ACE_READ_ATTR(*pace) ? 't':'-', IS_FSAL_ACE_WRITE_ATTR(*pace) ? 'T':'-', IS_FSAL_ACE_DELETE(*pace) ? 'd':'-', IS_FSAL_ACE_READ_ACL(*pace) ? 'c':'-', IS_FSAL_ACE_WRITE_ACL(*pace) ? 'C':'-', IS_FSAL_ACE_WRITE_OWNER(*pace) ? 'o':'-', IS_FSAL_ACE_SYNCHRONIZE(*pace) ? 'z':'-', /* ACE Inherit flags. */ IS_FSAL_ACE_INHERIT(*pace)? inherit_flags: ""); }
static fsal_status_t fsal_check_access_acl(struct user_cred *creds, fsal_aceperm_t v4mask, fsal_accessflags_t *allowed, fsal_accessflags_t *denied, struct attrlist *p_object_attributes) { fsal_aceperm_t missing_access; fsal_aceperm_t tperm; uid_t uid; gid_t gid; fsal_acl_t *pacl = NULL; fsal_ace_t *pace = NULL; int ace_number = 0; bool is_dir = false; bool is_owner = false; bool is_group = false; bool is_root = false; if (allowed != NULL) *allowed = 0; if (denied != NULL) *denied = 0; if (!p_object_attributes->acl) { /* Means that FSAL_ACE4_REQ_FLAG was set, but no ACLs */ LogFullDebug(COMPONENT_NFS_V4_ACL, "Allow ACE required, but no ACLs"); return fsalstat(ERR_FSAL_NO_ACE, 0); } /* unsatisfied flags */ missing_access = v4mask & ~FSAL_ACE4_PERM_CONTINUE; if (!missing_access) { LogFullDebug(COMPONENT_NFS_V4_ACL, "Nothing was requested"); return fsalstat(ERR_FSAL_NO_ERROR, 0); } /* Get file ownership information. */ uid = p_object_attributes->owner; gid = p_object_attributes->group; pacl = p_object_attributes->acl; is_dir = (p_object_attributes->type == DIRECTORY); is_root = creds->caller_uid == 0; if (is_root) { if (is_dir) { if (allowed != NULL) *allowed = v4mask; /* On a directory, allow root anything. */ LogFullDebug(COMPONENT_NFS_V4_ACL, "Met root privileges on directory"); return fsalstat(ERR_FSAL_NO_ERROR, 0); } /* Otherwise, allow root anything but execute. */ missing_access &= FSAL_ACE_PERM_EXECUTE; if (allowed != NULL) *allowed = v4mask & ~FSAL_ACE_PERM_EXECUTE; if (!missing_access) { LogFullDebug(COMPONENT_NFS_V4_ACL, "Met root privileges"); return fsalstat(ERR_FSAL_NO_ERROR, 0); } } LogFullDebug(COMPONENT_NFS_V4_ACL, "file acl=%p, file uid=%u, file gid=%u, ", pacl, uid, gid); if (isFullDebug(COMPONENT_NFS_V4_ACL)) { char str[LOG_BUFF_LEN]; struct display_buffer dspbuf = { sizeof(str), str, str }; (void)display_fsal_v4mask(&dspbuf, v4mask, p_object_attributes->type == DIRECTORY); LogFullDebug(COMPONENT_NFS_V4_ACL, "user uid=%u, user gid= %u, v4mask=%s", creds->caller_uid, creds->caller_gid, str); } is_owner = fsal_check_ace_owner(uid, creds); is_group = fsal_check_ace_group(gid, creds); /* Always grant READ_ACL, WRITE_ACL and READ_ATTR, WRITE_ATTR * to the file owner. */ if (is_owner) { if (allowed != NULL) *allowed |= v4mask & (FSAL_ACE_PERM_WRITE_ACL | FSAL_ACE_PERM_READ_ACL | FSAL_ACE_PERM_WRITE_ATTR | FSAL_ACE_PERM_READ_ATTR); missing_access &= ~(FSAL_ACE_PERM_WRITE_ACL | FSAL_ACE_PERM_READ_ACL); missing_access &= ~(FSAL_ACE_PERM_WRITE_ATTR | FSAL_ACE_PERM_READ_ATTR); if (!missing_access) { LogFullDebug(COMPONENT_NFS_V4_ACL, "Met owner privileges"); return fsalstat(ERR_FSAL_NO_ERROR, 0); } } /** @todo Even if user is admin, audit/alarm checks should be done. */ for (pace = pacl->aces; pace < pacl->aces + pacl->naces; pace++) { ace_number += 1; LogFullDebug(COMPONENT_NFS_V4_ACL, "ace numnber: %d ace type 0x%X perm 0x%X flag 0x%X who %u", ace_number, pace->type, pace->perm, pace->flag, GET_FSAL_ACE_WHO(*pace)); /* Process Allow and Deny entries. */ if (!IS_FSAL_ACE_ALLOW(*pace) && !IS_FSAL_ACE_DENY(*pace)) { LogFullDebug(COMPONENT_NFS_V4_ACL, "not allow or deny"); continue; } LogFullDebug(COMPONENT_NFS_V4_ACL, "allow or deny"); /* Check if this ACE is applicable. */ if (fsal_check_ace_applicable(pace, creds, is_dir, is_owner, is_group, is_root)) { if (IS_FSAL_ACE_ALLOW(*pace)) { /* Do not set bits which are already denied */ if (denied) tperm = pace->perm & ~*denied; else tperm = pace->perm; LogFullDebug(COMPONENT_NFS_V4_ACL, "allow perm 0x%X remainingPerms 0x%X", tperm, missing_access); if (allowed != NULL) *allowed |= v4mask & tperm; missing_access &= ~(tperm & missing_access); if (!missing_access) { fsal_print_access_by_acl( pacl->naces, ace_number, pace, v4mask, ERR_FSAL_NO_ERROR, is_dir, creds); break; } } else if ((pace->perm & missing_access) && !is_root) { fsal_print_access_by_acl( pacl->naces, ace_number, pace, v4mask, #ifndef ENABLE_RFC_ACL (pace->perm & missing_access & (FSAL_ACE_PERM_WRITE_ATTR | FSAL_ACE_PERM_WRITE_ACL | FSAL_ACE_PERM_WRITE_OWNER)) != 0 ? ERR_FSAL_PERM : #endif /* ENABLE_RFC_ACL */ ERR_FSAL_ACCESS, is_dir, creds); if (denied != NULL) *denied |= v4mask & pace->perm; if (denied == NULL || (v4mask & FSAL_ACE4_PERM_CONTINUE) == 0) { #ifndef ENABLE_RFC_ACL if ((pace->perm & missing_access & (FSAL_ACE_PERM_WRITE_ATTR | FSAL_ACE_PERM_WRITE_ACL | FSAL_ACE_PERM_WRITE_OWNER)) != 0) { LogDebug(COMPONENT_NFS_V4_ACL, "access denied (EPERM)"); return fsalstat(ERR_FSAL_PERM, 0); } else { LogDebug(COMPONENT_NFS_V4_ACL, "access denied (EACCESS)"); return fsalstat(ERR_FSAL_ACCESS, 0); } #else /* ENABLE_RFC_ACL */ LogDebug(COMPONENT_NFS_V4_ACL, "access denied (EACCESS)"); return fsalstat(ERR_FSAL_ACCESS, 0); #endif /* ENABLE_RFC_ACL */ } missing_access &= ~(pace->perm & missing_access); /* If this DENY ACE blocked the last * remaining requested access * bits, break out of the loop because * we're done and don't * want to evaluate any more ACEs. */ if (!missing_access) break; } } } if (IS_FSAL_ACE4_REQ(v4mask) && missing_access) { LogDebug(COMPONENT_NFS_V4_ACL, "final access unknown (NO_ACE)"); return fsalstat(ERR_FSAL_NO_ACE, 0); } else if (missing_access || (denied != NULL && *denied != 0)) { #ifndef ENABLE_RFC_ACL if ((missing_access & (FSAL_ACE_PERM_WRITE_ATTR | FSAL_ACE_PERM_WRITE_ACL | FSAL_ACE_PERM_WRITE_OWNER)) != 0) { LogDebug(COMPONENT_NFS_V4_ACL, "final access denied (EPERM)"); return fsalstat(ERR_FSAL_PERM, 0); } else { LogDebug(COMPONENT_NFS_V4_ACL, "final access denied (EACCESS)"); return fsalstat(ERR_FSAL_ACCESS, 0); } #else /* ENABLE_RFC_ACL */ LogDebug(COMPONENT_NFS_V4_ACL, "final access denied (EACCESS)"); return fsalstat(ERR_FSAL_ACCESS, 0); #endif /* ENABLE_RFC_ACL */ } else { LogFullDebug(COMPONENT_NFS_V4_ACL, "access granted"); return fsalstat(ERR_FSAL_NO_ERROR, 0); } }
static fsal_status_t fsal_check_access_acl(fsal_op_context_t * p_context, /* IN */ fsal_aceperm_t v4mask, /* IN */ fsal_attrib_list_t * p_object_attributes /* IN */ ) { fsal_aceperm_t missing_access; fsal_uid_t uid; fsal_gid_t gid; fsal_acl_t *pacl = NULL; fsal_ace_t *pace = NULL; int ace_number = 0; fsal_boolean_t is_dir = FALSE; fsal_boolean_t is_owner = FALSE; fsal_boolean_t is_group = FALSE; /* unsatisfied flags */ missing_access = v4mask; if(!missing_access) { LogDebug(COMPONENT_FSAL, "fsal_check_access_acl: Nothing was requested"); ReturnCode(ERR_FSAL_NO_ERROR, 0); } /* Get file ownership information. */ uid = p_object_attributes->owner; gid = p_object_attributes->group; pacl = p_object_attributes->acl; is_dir = (p_object_attributes->type == FSAL_TYPE_DIR); LogDebug(COMPONENT_FSAL, "fsal_check_access_acl: file acl=%p, file uid=%d, file gid= %d", pacl,uid, gid); LogDebug(COMPONENT_FSAL, "fsal_check_access_acl: user uid=%d, user gid= %d, v4mask=0x%X", p_context->credential.user, p_context->credential.group, v4mask); is_owner = fsal_check_ace_owner(uid, p_context); is_group = fsal_check_ace_group(gid, p_context); /* Always grant READ_ACL, WRITE_ACL and READ_ATTR, WRITE_ATTR to the file * owner. */ if(is_owner) { missing_access &= ~(FSAL_ACE_PERM_WRITE_ACL | FSAL_ACE_PERM_READ_ACL); missing_access &= ~(FSAL_ACE_PERM_WRITE_ATTR | FSAL_ACE_PERM_READ_ATTR); if(!missing_access) { LogDebug(COMPONENT_FSAL, "fsal_check_access_acl: Met owner privileges"); ReturnCode(ERR_FSAL_NO_ERROR, 0); } } // TODO: Even if user is admin, audit/alarm checks should be done. ace_number = 1; for(pace = pacl->aces; pace < pacl->aces + pacl->naces; pace++) { LogDebug(COMPONENT_FSAL, "fsal_check_access_acl: ace type 0x%X perm 0x%X flag 0x%X who %d", pace->type, pace->perm, pace->flag, GET_FSAL_ACE_WHO(*pace)); /* Process Allow and Deny entries. */ if(IS_FSAL_ACE_ALLOW(*pace) || IS_FSAL_ACE_DENY(*pace)) { LogDebug(COMPONENT_FSAL, "fsal_check_access_acl: allow or deny"); /* Check if this ACE is applicable. */ if(fsal_check_ace_applicable(pace, p_context, is_dir, is_owner, is_group)) { if(IS_FSAL_ACE_ALLOW(*pace)) { LogDebug(COMPONENT_FSAL, "fsal_check_access_acl: allow perm 0x%X remainingPerms 0x%X", pace->perm, missing_access); missing_access &= ~(pace->perm & missing_access); if(!missing_access) { LogDebug(COMPONENT_FSAL, "fsal_check_access_acl: access granted"); fsal_print_access_by_acl(pacl->naces, ace_number, pace, v4mask, ERR_FSAL_NO_ERROR, is_dir, p_context); ReturnCode(ERR_FSAL_NO_ERROR, 0); } } else if(pace->perm & missing_access) { LogDebug(COMPONENT_FSAL, "fsal_check_access_acl: access denied"); fsal_print_access_by_acl(pacl->naces, ace_number, pace, v4mask, ERR_FSAL_ACCESS, is_dir, p_context); ReturnCode(ERR_FSAL_ACCESS, 0); } } } ace_number += 1; } if(missing_access) { LogDebug(COMPONENT_FSAL, "fsal_check_access_acl: access denied"); ReturnCode(ERR_FSAL_ACCESS, 0); } else { LogDebug(COMPONENT_FSAL, "fsal_check_access_acl: access granted"); ReturnCode(ERR_FSAL_NO_ERROR, 0); } ReturnCode(ERR_FSAL_NO_ERROR, 0); }