From 66d053d21a9f40b896e75410ce8997d213e21e2b Mon Sep 17 00:00:00 2001 From: wangdi Date: Thu, 19 Oct 2006 14:39:16 +0000 Subject: [PATCH] Branch: b_new_cmd further update for mdd files recorganizing --- lustre/mdd/Makefile.in | 2 +- lustre/mdd/mdd_handler.c | 628 +------------------------------------------- lustre/mdd/mdd_internal.h | 38 +++ lustre/mdd/mdd_permission.c | 628 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 678 insertions(+), 618 deletions(-) create mode 100644 lustre/mdd/mdd_permission.c diff --git a/lustre/mdd/Makefile.in b/lustre/mdd/Makefile.in index afb8aee..cda9afd 100644 --- a/lustre/mdd/Makefile.in +++ b/lustre/mdd/Makefile.in @@ -1,6 +1,6 @@ MODULES := mdd mdd-objs := mdd_handler.o mdd_lov.o mdd_orphans.o mdd_lproc.o -mdd-objs += mdd_device.o mdd_trans.o mdd_object.o +mdd-objs += mdd_device.o mdd_trans.o mdd_object.o mdd_permission.o EXTRA_PRE_CFLAGS := -I@LINUX@/fs -I@LUSTRE@ -I@LUSTRE@/ldiskfs diff --git a/lustre/mdd/mdd_handler.c b/lustre/mdd/mdd_handler.c index feb40e6..015e1c9 100644 --- a/lustre/mdd/mdd_handler.c +++ b/lustre/mdd/mdd_handler.c @@ -45,19 +45,9 @@ #include "mdd_internal.h" -#if 0 -static int mdd_exec_permission_lite(const struct lu_env *env, - struct mdd_object *obj); -#endif - static const char dot[] = "."; static const char dotdot[] = ".."; -static inline int mdd_is_immutable(struct mdd_object *obj) -{ - return obj->mod_flags & IMMUTE_OBJ; -} - static inline int mdd_is_append(struct mdd_object *obj) { return obj->mod_flags & APPEND_OBJ; @@ -74,8 +64,8 @@ static inline int mdd_is_dead_obj(struct mdd_object *obj) return obj && obj->mod_flags & DEAD_OBJ; } -static inline int __mdd_la_get(const struct lu_env *env, struct mdd_object *obj, - struct lu_attr *la, struct lustre_capa *capa) +int mdd_la_get(const struct lu_env *env, struct mdd_object *obj, + struct lu_attr *la, struct lustre_capa *capa) { struct dt_object *next = mdd_object_child(obj); LASSERT(lu_object_exists(mdd2lu_obj(obj))); @@ -100,7 +90,7 @@ int mdd_get_flags(const struct lu_env *env, struct mdd_object *obj) ENTRY; mdd_read_lock(env, obj); - rc = __mdd_la_get(env, obj, la, BYPASS_CAPA); + rc = mdd_la_get(env, obj, la, BYPASS_CAPA); mdd_read_unlock(env, obj); if (rc == 0) mdd_flags_xlate(obj, la->la_flags); @@ -130,274 +120,6 @@ __mdd_ref_del(const struct lu_env *env, struct mdd_object *obj, EXIT; } -#define mdd_get_group_info(group_info) do { \ - atomic_inc(&(group_info)->usage); \ -} while (0) - -#define mdd_put_group_info(group_info) do { \ - if (atomic_dec_and_test(&(group_info)->usage)) \ - groups_free(group_info); \ -} while (0) - -#define MDD_NGROUPS_PER_BLOCK ((int)(CFS_PAGE_SIZE / sizeof(gid_t))) - -#define MDD_GROUP_AT(gi, i) \ - ((gi)->blocks[(i) / MDD_NGROUPS_PER_BLOCK][(i) % MDD_NGROUPS_PER_BLOCK]) - -/* groups_search() is copied from linux kernel! */ -/* a simple bsearch */ -static int mdd_groups_search(struct group_info *group_info, gid_t grp) -{ - int left, right; - - if (!group_info) - return 0; - - left = 0; - right = group_info->ngroups; - while (left < right) { - int mid = (left + right) / 2; - int cmp = grp - MDD_GROUP_AT(group_info, mid); - - if (cmp > 0) - left = mid + 1; - else if (cmp < 0) - right = mid; - else - return 1; - } - return 0; -} - -static int mdd_in_group_p(struct md_ucred *uc, gid_t grp) -{ - int rc = 1; - - if (grp != uc->mu_fsgid) { - struct group_info *group_info = NULL; - - if (uc->mu_ginfo || (uc->mu_valid == UCRED_OLD) || - (!uc->mu_ginfo && !uc->mu_identity)) - if ((grp == uc->mu_suppgids[0]) || - (grp == uc->mu_suppgids[1])) - return 1; - - if (uc->mu_ginfo) - group_info = uc->mu_ginfo; - else if (uc->mu_identity) - group_info = uc->mu_identity->mi_ginfo; - - if (!group_info) - return 0; - - mdd_get_group_info(group_info); - rc = mdd_groups_search(group_info, grp); - mdd_put_group_info(group_info); - } - return rc; -} - -#ifdef CONFIG_FS_POSIX_ACL -static int mdd_posix_acl_permission(struct md_ucred *uc, struct lu_attr *la, - int want, posix_acl_xattr_entry *entry, - int count) -{ - posix_acl_xattr_entry *pa, *pe, *mask_obj; - int found = 0; - ENTRY; - - if (count <= 0) - RETURN(-EACCES); - - pa = &entry[0]; - pe = &entry[count - 1]; - for (; pa <= pe; pa++) { - switch(pa->e_tag) { - case ACL_USER_OBJ: - /* (May have been checked already) */ - if (la->la_uid == uc->mu_fsuid) - goto check_perm; - break; - case ACL_USER: - if (pa->e_id == uc->mu_fsuid) - goto mask; - break; - case ACL_GROUP_OBJ: - if (mdd_in_group_p(uc, la->la_gid)) { - found = 1; - if ((pa->e_perm & want) == want) - goto mask; - } - break; - case ACL_GROUP: - if (mdd_in_group_p(uc, pa->e_id)) { - found = 1; - if ((pa->e_perm & want) == want) - goto mask; - } - break; - case ACL_MASK: - break; - case ACL_OTHER: - if (found) - RETURN(-EACCES); - else - goto check_perm; - default: - RETURN(-EIO); - } - } - RETURN(-EIO); - -mask: - for (mask_obj = pa + 1; mask_obj <= pe; mask_obj++) { - if (mask_obj->e_tag == ACL_MASK) { - if ((pa->e_perm & mask_obj->e_perm & want) == want) - RETURN(0); - - RETURN(-EACCES); - } - } - -check_perm: - if ((pa->e_perm & want) == want) - RETURN(0); - - RETURN(-EACCES); -} -#endif - -static int mdd_check_acl(const struct lu_env *env, struct mdd_object *obj, - struct lu_attr* la, int mask) -{ -#ifdef CONFIG_FS_POSIX_ACL - struct dt_object *next; - struct lu_buf *buf = &mdd_env_info(env)->mti_buf; - struct md_ucred *uc = md_ucred(env); - posix_acl_xattr_entry *entry; - int entry_count; - int rc; - ENTRY; - - next = mdd_object_child(obj); - - buf->lb_buf = mdd_env_info(env)->mti_xattr_buf; - buf->lb_len = sizeof(mdd_env_info(env)->mti_xattr_buf); - rc = next->do_ops->do_xattr_get(env, next, buf, - XATTR_NAME_ACL_ACCESS, - mdd_object_capa(env, obj)); - if (rc <= 0) - RETURN(rc ? : -EACCES); - - entry = ((posix_acl_xattr_header *)(buf->lb_buf))->a_entries; - entry_count = (rc - 4) / sizeof(posix_acl_xattr_entry); - - rc = mdd_posix_acl_permission(uc, la, mask, entry, entry_count); - RETURN(rc); -#else - ENTRY; - RETURN(-EAGAIN); -#endif -} - -#define mdd_cap_t(x) (x) - -#define MDD_CAP_TO_MASK(x) (1 << (x)) - -#define mdd_cap_raised(c, flag) (mdd_cap_t(c) & MDD_CAP_TO_MASK(flag)) - -/* capable() is copied from linux kernel! */ -static inline int mdd_capable(struct md_ucred *uc, int cap) -{ - if (mdd_cap_raised(uc->mu_cap, cap)) - return 1; - return 0; -} - -static int __mdd_permission_internal(const struct lu_env *env, - struct mdd_object *obj, - int mask, int getattr) -{ - struct lu_attr *la = &mdd_env_info(env)->mti_la; - struct md_ucred *uc = md_ucred(env); - __u32 mode; - int rc; - - ENTRY; - - if (mask == 0) - RETURN(0); - - /* These means unnecessary for permission check */ - if ((uc == NULL) || (uc->mu_valid == UCRED_INIT)) - RETURN(0); - - /* Invalid user credit */ - if (uc->mu_valid == UCRED_INVALID) - RETURN(-EACCES); - - /* - * Nobody gets write access to an immutable file. - */ - if ((mask & MAY_WRITE) && mdd_is_immutable(obj)) - RETURN(-EACCES); - - if (getattr) { - rc = __mdd_la_get(env, obj, la, BYPASS_CAPA); - if (rc) - RETURN(rc); - } - - mode = la->la_mode; - if (uc->mu_fsuid == la->la_uid) { - mode >>= 6; - } else { - if (mode & S_IRWXG) { - rc = mdd_check_acl(env, obj, la, mask); - if (rc == -EACCES) - goto check_capabilities; - else if ((rc != -EAGAIN) && (rc != -EOPNOTSUPP) && - (rc != -ENODATA)) - RETURN(rc); - } - if (mdd_in_group_p(uc, la->la_gid)) - mode >>= 3; - } - - /* - * If the DACs are ok we don't need any capability check. - */ - if (((mode & mask & S_IRWXO) == mask)) - RETURN(0); - -check_capabilities: - - /* - * Read/write DACs are always overridable. - * Executable DACs are overridable if at least one exec bit is set. - * Dir's DACs are always overridable. - */ - if (!(mask & MAY_EXEC) || - (la->la_mode & S_IXUGO) || S_ISDIR(la->la_mode)) - if (mdd_capable(uc, CAP_DAC_OVERRIDE)) - RETURN(0); - - /* - * Searching includes executable on directories, else just read. - */ - if ((mask == MAY_READ) || - (S_ISDIR(la->la_mode) && !(mask & MAY_WRITE))) - if (mdd_capable(uc, CAP_DAC_READ_SEARCH)) - RETURN(0); - - RETURN(-EACCES); -} - -static inline int mdd_permission_internal(const struct lu_env *env, - struct mdd_object *obj, int mask) -{ - return __mdd_permission_internal(env, obj, mask, 1); -} /*Check whether it may create the cobj under the pobj*/ static int mdd_may_create(const struct lu_env *env, @@ -433,13 +155,13 @@ static inline int mdd_is_sticky(const struct lu_env *env, struct md_ucred *uc = md_ucred(env); int rc; - rc = __mdd_la_get(env, cobj, tmp_la, BYPASS_CAPA); + rc = mdd_la_get(env, cobj, tmp_la, BYPASS_CAPA); if (rc) { return rc; } else if (tmp_la->la_uid == uc->mu_fsuid) { return 0; } else { - rc = __mdd_la_get(env, pobj, tmp_la, BYPASS_CAPA); + rc = mdd_la_get(env, pobj, tmp_la, BYPASS_CAPA); if (rc) return rc; else if (!(tmp_la->la_mode & S_ISVTX)) @@ -501,7 +223,7 @@ static int __mdd_iattr_get(const struct lu_env *env, int rc = 0; ENTRY; - rc = __mdd_la_get(env, mdd_obj, &ma->ma_attr, + rc = mdd_la_get(env, mdd_obj, &ma->ma_attr, mdd_object_capa(env, mdd_obj)); if (rc == 0) ma->ma_valid = MA_INODE; @@ -540,29 +262,6 @@ static int __mdd_lmv_get(const struct lu_env *env, RETURN(rc); } -#ifdef CONFIG_FS_POSIX_ACL -/* get default acl EA only */ -static int __mdd_acl_def_get(const struct lu_env *env, - struct mdd_object *mdd_obj, struct md_attr *ma) -{ - struct dt_object *next = mdd_object_child(mdd_obj); - int rc; - - rc = next->do_ops->do_xattr_get(env, next, - mdd_buf_get(env, ma->ma_lmv, - ma->ma_lmv_size), - XATTR_NAME_ACL_DEFAULT, BYPASS_CAPA); - if (rc > 0) { - ma->ma_lmv_size = rc; - ma->ma_valid |= MA_ACL_DEF; - rc = 0; - } else if ((rc == -EOPNOTSUPP) || (rc == -ENODATA)) { - rc = 0; - } - RETURN(rc); -} -#endif - static int mdd_attr_get_internal(const struct lu_env *env, struct mdd_object *mdd_obj, struct md_attr *ma) @@ -585,7 +284,7 @@ static int mdd_attr_get_internal(const struct lu_env *env, #ifdef CONFIG_FS_POSIX_ACL else if (rc == 0 && ma->ma_need & MA_ACL_DEF) { if (S_ISDIR(mdd_object_type(mdd_obj))) - rc = __mdd_acl_def_get(env, mdd_obj, ma); + rc = mdd_acl_def_get(env, mdd_obj, ma); } #endif CDEBUG(D_INODE, "after getattr rc = %d, ma_valid = "LPX64"\n", @@ -747,95 +446,6 @@ static int __mdd_object_create(const struct lu_env *env, RETURN(rc); } -#ifdef CONFIG_FS_POSIX_ACL -#include -#include - -/* - * Modify the ACL for the chmod. - */ -static int mdd_posix_acl_chmod_masq(posix_acl_xattr_entry *entry, - __u32 mode, int count) -{ - posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe; - - pa = &entry[0]; - pe = &entry[count - 1]; - for (; pa <= pe; pa++) { - switch(pa->e_tag) { - case ACL_USER_OBJ: - pa->e_perm = (mode & S_IRWXU) >> 6; - break; - - case ACL_USER: - case ACL_GROUP: - break; - - case ACL_GROUP_OBJ: - group_obj = pa; - break; - - case ACL_MASK: - mask_obj = pa; - break; - - case ACL_OTHER: - pa->e_perm = (mode & S_IRWXO); - break; - - default: - return -EIO; - } - } - - if (mask_obj) { - mask_obj->e_perm = (mode & S_IRWXG) >> 3; - } else { - if (!group_obj) - return -EIO; - group_obj->e_perm = (mode & S_IRWXG) >> 3; - } - - return 0; -} - -static int mdd_acl_chmod(const struct lu_env *env, struct mdd_object *o, - __u32 mode, struct thandle *handle) -{ - struct dt_object *next; - struct lu_buf *buf; - posix_acl_xattr_entry *entry; - int entry_count; - int rc; - - ENTRY; - - next = mdd_object_child(o); - buf = &mdd_env_info(env)->mti_buf; - buf->lb_buf = mdd_env_info(env)->mti_xattr_buf; - buf->lb_len = sizeof(mdd_env_info(env)->mti_xattr_buf); - rc = next->do_ops->do_xattr_get(env, next, buf, - XATTR_NAME_ACL_ACCESS, BYPASS_CAPA); - if ((rc == -EOPNOTSUPP) || (rc == -ENODATA)) - RETURN(0); - else if (rc <= 0) - RETURN(rc); - - buf->lb_len = rc; - entry = ((posix_acl_xattr_header *)(buf->lb_buf))->a_entries; - entry_count = (rc - 4) / sizeof(posix_acl_xattr_entry); - if (entry_count <= 0) - RETURN(0); - - rc = mdd_posix_acl_chmod_masq(entry, mode, entry_count); - if (rc) - RETURN(rc); - - rc = next->do_ops->do_xattr_set(env, next, buf, XATTR_NAME_ACL_ACCESS, - 0, handle, BYPASS_CAPA); - RETURN(rc); -} -#endif int mdd_attr_set_internal(const struct lu_env *env, struct mdd_object *o, const struct lu_attr *attr, struct thandle *handle, @@ -914,7 +524,7 @@ int mdd_fix_attr(const struct lu_env *env, struct mdd_object *obj, if (la->la_valid & (LA_NLINK | LA_RDEV | LA_BLKSIZE)) RETURN(-EPERM); - rc = __mdd_la_get(env, obj, tmp_la, BYPASS_CAPA); + rc = mdd_la_get(env, obj, tmp_la, BYPASS_CAPA); if (rc) RETURN(rc); @@ -1172,7 +782,7 @@ static int mdd_xattr_sanity_check(const struct lu_env *env, RETURN(-EPERM); mdd_read_lock(env, obj); - rc = __mdd_la_get(env, obj, tmp_la, BYPASS_CAPA); + rc = mdd_la_get(env, obj, tmp_la, BYPASS_CAPA); mdd_read_unlock(env, obj); if (rc) RETURN(rc); @@ -2073,131 +1683,6 @@ static int mdd_create_data(const struct lu_env *env, RETURN(rc); } -#ifdef CONFIG_FS_POSIX_ACL -/* - * Modify acl when creating a new obj. - * - * mode_p initially must contain the mode parameter to the open() / creat() - * system calls. All permissions that are not granted by the acl are removed. - * The permissions in the acl are changed to reflect the mode_p parameter. - */ -static int mdd_posix_acl_create_masq(posix_acl_xattr_entry *entry, - __u32 *mode_p, int count) -{ - posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe; - __u32 mode = *mode_p; - int not_equiv = 0; - - pa = &entry[0]; - pe = &entry[count - 1]; - for (; pa <= pe; pa++) { - switch(pa->e_tag) { - case ACL_USER_OBJ: - pa->e_perm &= (mode >> 6) | ~S_IRWXO; - mode &= (pa->e_perm << 6) | ~S_IRWXU; - break; - - case ACL_USER: - case ACL_GROUP: - not_equiv = 1; - break; - - case ACL_GROUP_OBJ: - group_obj = pa; - break; - - case ACL_OTHER: - pa->e_perm &= mode | ~S_IRWXO; - mode &= pa->e_perm | ~S_IRWXO; - break; - - case ACL_MASK: - mask_obj = pa; - not_equiv = 1; - break; - - default: - return -EIO; - } - } - - if (mask_obj) { - mask_obj->e_perm &= (mode >> 3) | ~S_IRWXO; - mode &= (mask_obj->e_perm << 3) | ~S_IRWXG; - } else { - if (!group_obj) - return -EIO; - group_obj->e_perm &= (mode >> 3) | ~S_IRWXO; - mode &= (group_obj->e_perm << 3) | ~S_IRWXG; - } - - *mode_p = (*mode_p & ~S_IRWXUGO) | mode; - return not_equiv; -} - -static int __mdd_acl_init(const struct lu_env *env, struct mdd_object *obj, - struct lu_buf *buf, __u32 *mode, - struct thandle *handle) -{ - struct dt_object *next; - posix_acl_xattr_entry *entry; - int entry_count; - int rc; - - ENTRY; - - entry = ((posix_acl_xattr_header *)(buf->lb_buf))->a_entries; - entry_count = (buf->lb_len - 4) / sizeof(posix_acl_xattr_entry); - if (entry_count <= 0) - RETURN(0); - - next = mdd_object_child(obj); - if (S_ISDIR(*mode)) { - rc = next->do_ops->do_xattr_set(env, next, buf, - XATTR_NAME_ACL_DEFAULT, - 0, handle, BYPASS_CAPA); - if (rc) - RETURN(rc); - } - - rc = mdd_posix_acl_create_masq(entry, mode, entry_count); - if (rc < 0) - RETURN(rc); - else if (rc > 0) - rc = next->do_ops->do_xattr_set(env, next, buf, - XATTR_NAME_ACL_ACCESS, - 0, handle, BYPASS_CAPA); - RETURN(rc); -} - -static int mdd_acl_init(const struct lu_env *env, struct mdd_object *pobj, - struct mdd_object *cobj, __u32 *mode, - struct thandle *handle) -{ - struct dt_object *next = mdd_object_child(pobj); - struct lu_buf *buf = &mdd_env_info(env)->mti_buf; - int rc; - - ENTRY; - - if (S_ISLNK(*mode)) - RETURN(0); - - buf->lb_buf = mdd_env_info(env)->mti_xattr_buf; - buf->lb_len = sizeof(mdd_env_info(env)->mti_xattr_buf); - rc = next->do_ops->do_xattr_get(env, next, buf, - XATTR_NAME_ACL_DEFAULT, BYPASS_CAPA); - if ((rc == -EOPNOTSUPP) || (rc == -ENODATA)) - RETURN(0); - else if (rc <= 0) - RETURN(rc); - - buf->lb_len = rc; - rc = __mdd_acl_init(env, cobj, buf, mode, handle); - RETURN(rc); -} -#endif - static int mdd_create_sanity_check(const struct lu_env *env, struct md_object *pobj, const char *name, struct md_attr *ma) @@ -2225,7 +1710,7 @@ static int mdd_create_sanity_check(const struct lu_env *env, /* sgid check */ mdd_read_lock(env, obj); - rc = __mdd_la_get(env, obj, la, BYPASS_CAPA); + rc = mdd_la_get(env, obj, la, BYPASS_CAPA); mdd_read_unlock(env, obj); if (rc != 0) RETURN(rc); @@ -2796,7 +2281,7 @@ static int mdd_open_sanity_check(const struct lu_env *env, if (mdd_is_dead_obj(obj)) RETURN(-ENOENT); - rc = __mdd_la_get(env, obj, tmp_la, BYPASS_CAPA); + rc = mdd_la_get(env, obj, tmp_la, BYPASS_CAPA); if (rc) RETURN(rc); @@ -2929,97 +2414,6 @@ out_unlock: RETURN(rc); } -#if 0 -static int mdd_exec_permission_lite(const struct lu_env *env, - struct mdd_object *obj) -{ - struct lu_attr *la = &mdd_env_info(env)->mti_la; - struct md_ucred *uc = md_ucred(env); - umode_t mode; - int rc; - ENTRY; - - /* These means unnecessary for permission check */ - if ((uc == NULL) || (uc->mu_valid == UCRED_INIT)) - RETURN(0); - - /* Invalid user credit */ - if (uc->mu_valid == UCRED_INVALID) - RETURN(-EACCES); - - rc = __mdd_la_get(env, obj, la, BYPASS_CAPA); - if (rc) - RETURN(rc); - - mode = la->la_mode; - if (uc->mu_fsuid == la->la_uid) - mode >>= 6; - else if (mdd_in_group_p(uc, la->la_gid)) - mode >>= 3; - - if (mode & MAY_EXEC) - RETURN(0); - - if (((la->la_mode & S_IXUGO) || S_ISDIR(la->la_mode)) && - mdd_capable(uc, CAP_DAC_OVERRIDE)) - RETURN(0); - - if (S_ISDIR(la->la_mode) && mdd_capable(uc, CAP_DAC_READ_SEARCH)) - RETURN(0); - - RETURN(-EACCES); -} -#endif - -static inline int mdd_permission_internal_locked(const struct lu_env *env, - struct mdd_object *obj, - int mask) -{ - int rc; - - mdd_read_lock(env, obj); - rc = mdd_permission_internal(env, obj, mask); - mdd_read_unlock(env, obj); - - return rc; -} - -static int mdd_permission(const struct lu_env *env, struct md_object *obj, - int mask) -{ - struct mdd_object *mdd_obj = md2mdd_obj(obj); - int rc; - ENTRY; - - rc = mdd_permission_internal_locked(env, mdd_obj, mask); - - RETURN(rc); -} - -static int mdd_capa_get(const struct lu_env *env, struct md_object *obj, - struct lustre_capa *capa, int renewal) -{ - struct dt_object *next; - struct mdd_object *mdd_obj = md2mdd_obj(obj); - struct obd_capa *oc; - int rc = 0; - ENTRY; - - LASSERT(lu_object_exists(mdd2lu_obj(mdd_obj))); - next = mdd_object_child(mdd_obj); - - oc = next->do_ops->do_capa_get(env, next, renewal ? capa : NULL, - capa->lc_opc); - if (IS_ERR(oc)) { - rc = PTR_ERR(oc); - } else { - capa_cpy(capa, oc); - capa_put(oc); - } - - RETURN(rc); -} - struct md_dir_operations mdd_dir_ops = { .mdo_is_subdir = mdd_is_subdir, .mdo_lookup = mdd_lookup, diff --git a/lustre/mdd/mdd_internal.h b/lustre/mdd/mdd_internal.h index a3d0ea6..110637c 100644 --- a/lustre/mdd/mdd_internal.h +++ b/lustre/mdd/mdd_internal.h @@ -107,6 +107,8 @@ int mdd_get_md(const struct lu_env *env, struct mdd_object *obj, void *md, int *md_size, const char *name); int mdd_get_md_locked(const struct lu_env *env, struct mdd_object *obj, void *md, int *md_size, const char *name); +int mdd_la_get(const struct lu_env *env, struct mdd_object *obj, + struct lu_attr *la, struct lustre_capa *capa); int mdd_unlink_log(const struct lu_env *env, struct mdd_device *mdd, struct mdd_object *mdd_cobj, struct md_attr *ma); @@ -202,6 +204,37 @@ extern struct lu_device_operations mdd_lu_ops; struct mdd_object *mdd_object_find(const struct lu_env *env, struct mdd_device *d, const struct lu_fid *f); +/* mdd_permission.c */ +#define mdd_cap_t(x) (x) + +#define MDD_CAP_TO_MASK(x) (1 << (x)) + +#define mdd_cap_raised(c, flag) (mdd_cap_t(c) & MDD_CAP_TO_MASK(flag)) + +/* capable() is copied from linux kernel! */ +static inline int mdd_capable(struct md_ucred *uc, int cap) +{ + if (mdd_cap_raised(uc->mu_cap, cap)) + return 1; + return 0; +} + +int mdd_permission_internal(const struct lu_env *env, struct mdd_object *obj, + int mask); +int __mdd_permission_internal(const struct lu_env *env, struct mdd_object *obj, + int mask, int getattr); +int mdd_in_group_p(struct md_ucred *uc, gid_t grp); +int mdd_acl_chmod(const struct lu_env *env, struct mdd_object *o, __u32 mode, + struct thandle *handle); +int mdd_acl_def_get(const struct lu_env *env, struct mdd_object *mdd_obj, + struct md_attr *ma); +int mdd_acl_init(const struct lu_env *env, struct mdd_object *pobj, + struct mdd_object *cobj, __u32 *mode, struct thandle *handle); +int __mdd_acl_init(const struct lu_env *env, struct mdd_object *obj, + struct lu_buf *buf, __u32 *mode, struct thandle *handle); +int mdd_permission(const struct lu_env *env, struct md_object *obj, int mask); +int mdd_capa_get(const struct lu_env *env, struct md_object *obj, + struct lustre_capa *capa, int renewal); static inline int lu_device_is_mdd(struct lu_device *d) { @@ -279,6 +312,11 @@ static inline int mdd_lov_cookiesize(const struct lu_env *env, return obd->u.mds.mds_max_cookiesize; } +static inline int mdd_is_immutable(struct mdd_object *obj) +{ + return obj->mod_flags & IMMUTE_OBJ; +} + static inline struct lustre_capa *mdd_object_capa(const struct lu_env *env, const struct mdd_object *obj) { diff --git a/lustre/mdd/mdd_permission.c b/lustre/mdd/mdd_permission.c new file mode 100644 index 0000000..be6ab74 --- /dev/null +++ b/lustre/mdd/mdd_permission.c @@ -0,0 +1,628 @@ +/* -*- MODE: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * mdd/mdd_handler.c + * Lustre Metadata Server (mdd) routines + * + * Copyright (C) 2006 Cluster File Systems, Inc. + * Author: fangyong@clusterfs.com + * lsy@clusterfs.com + * This file is part of the Lustre file system, http://www.lustre.org + * Lustre is a trademark of Cluster File Systems, Inc. + * + * You may have signed or agreed to another license before downloading + * this software. If so, you are bound by the terms and conditions + * of that agreement, and the following does not apply to you. See the + * LICENSE file included with this distribution for more information. + * + * If you did not agree to a different license, then this copy of Lustre + * is open source software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In either case, Lustre is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * license text for more details. + */ +#ifndef EXPORT_SYMTAB +# define EXPORT_SYMTAB +#endif +#define DEBUG_SUBSYSTEM S_MDS + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "mdd_internal.h" + +#define mdd_get_group_info(group_info) do { \ + atomic_inc(&(group_info)->usage); \ +} while (0) + +#define mdd_put_group_info(group_info) do { \ + if (atomic_dec_and_test(&(group_info)->usage)) \ + groups_free(group_info); \ +} while (0) + +#define MDD_NGROUPS_PER_BLOCK ((int)(CFS_PAGE_SIZE / sizeof(gid_t))) + +#define MDD_GROUP_AT(gi, i) \ + ((gi)->blocks[(i) / MDD_NGROUPS_PER_BLOCK][(i) % MDD_NGROUPS_PER_BLOCK]) + +/* groups_search() is copied from linux kernel! */ +/* a simple bsearch */ +static int mdd_groups_search(struct group_info *group_info, gid_t grp) +{ + int left, right; + + if (!group_info) + return 0; + + left = 0; + right = group_info->ngroups; + while (left < right) { + int mid = (left + right) / 2; + int cmp = grp - MDD_GROUP_AT(group_info, mid); + + if (cmp > 0) + left = mid + 1; + else if (cmp < 0) + right = mid; + else + return 1; + } + return 0; +} + +int mdd_in_group_p(struct md_ucred *uc, gid_t grp) +{ + int rc = 1; + + if (grp != uc->mu_fsgid) { + struct group_info *group_info = NULL; + + if (uc->mu_ginfo || (uc->mu_valid == UCRED_OLD) || + (!uc->mu_ginfo && !uc->mu_identity)) + if ((grp == uc->mu_suppgids[0]) || + (grp == uc->mu_suppgids[1])) + return 1; + + if (uc->mu_ginfo) + group_info = uc->mu_ginfo; + else if (uc->mu_identity) + group_info = uc->mu_identity->mi_ginfo; + + if (!group_info) + return 0; + + mdd_get_group_info(group_info); + rc = mdd_groups_search(group_info, grp); + mdd_put_group_info(group_info); + } + return rc; +} + +#ifdef CONFIG_FS_POSIX_ACL +static int mdd_posix_acl_permission(struct md_ucred *uc, struct lu_attr *la, + int want, posix_acl_xattr_entry *entry, + int count) +{ + posix_acl_xattr_entry *pa, *pe, *mask_obj; + int found = 0; + ENTRY; + + if (count <= 0) + RETURN(-EACCES); + + pa = &entry[0]; + pe = &entry[count - 1]; + for (; pa <= pe; pa++) { + switch(pa->e_tag) { + case ACL_USER_OBJ: + /* (May have been checked already) */ + if (la->la_uid == uc->mu_fsuid) + goto check_perm; + break; + case ACL_USER: + if (pa->e_id == uc->mu_fsuid) + goto mask; + break; + case ACL_GROUP_OBJ: + if (mdd_in_group_p(uc, la->la_gid)) { + found = 1; + if ((pa->e_perm & want) == want) + goto mask; + } + break; + case ACL_GROUP: + if (mdd_in_group_p(uc, pa->e_id)) { + found = 1; + if ((pa->e_perm & want) == want) + goto mask; + } + break; + case ACL_MASK: + break; + case ACL_OTHER: + if (found) + RETURN(-EACCES); + else + goto check_perm; + default: + RETURN(-EIO); + } + } + RETURN(-EIO); + +mask: + for (mask_obj = pa + 1; mask_obj <= pe; mask_obj++) { + if (mask_obj->e_tag == ACL_MASK) { + if ((pa->e_perm & mask_obj->e_perm & want) == want) + RETURN(0); + + RETURN(-EACCES); + } + } + +check_perm: + if ((pa->e_perm & want) == want) + RETURN(0); + + RETURN(-EACCES); +} +#endif + +static int mdd_check_acl(const struct lu_env *env, struct mdd_object *obj, + struct lu_attr* la, int mask) +{ +#ifdef CONFIG_FS_POSIX_ACL + struct dt_object *next; + struct lu_buf *buf = &mdd_env_info(env)->mti_buf; + struct md_ucred *uc = md_ucred(env); + posix_acl_xattr_entry *entry; + int entry_count; + int rc; + ENTRY; + + next = mdd_object_child(obj); + + buf->lb_buf = mdd_env_info(env)->mti_xattr_buf; + buf->lb_len = sizeof(mdd_env_info(env)->mti_xattr_buf); + rc = next->do_ops->do_xattr_get(env, next, buf, + XATTR_NAME_ACL_ACCESS, + mdd_object_capa(env, obj)); + if (rc <= 0) + RETURN(rc ? : -EACCES); + + entry = ((posix_acl_xattr_header *)(buf->lb_buf))->a_entries; + entry_count = (rc - 4) / sizeof(posix_acl_xattr_entry); + + rc = mdd_posix_acl_permission(uc, la, mask, entry, entry_count); + RETURN(rc); +#else + ENTRY; + RETURN(-EAGAIN); +#endif +} + +int __mdd_permission_internal(const struct lu_env *env, + struct mdd_object *obj, + int mask, int getattr) +{ + struct lu_attr *la = &mdd_env_info(env)->mti_la; + struct md_ucred *uc = md_ucred(env); + __u32 mode; + int rc; + + ENTRY; + + if (mask == 0) + RETURN(0); + + /* These means unnecessary for permission check */ + if ((uc == NULL) || (uc->mu_valid == UCRED_INIT)) + RETURN(0); + + /* Invalid user credit */ + if (uc->mu_valid == UCRED_INVALID) + RETURN(-EACCES); + + /* + * Nobody gets write access to an immutable file. + */ + if ((mask & MAY_WRITE) && mdd_is_immutable(obj)) + RETURN(-EACCES); + + if (getattr) { + rc = mdd_la_get(env, obj, la, BYPASS_CAPA); + if (rc) + RETURN(rc); + } + + mode = la->la_mode; + if (uc->mu_fsuid == la->la_uid) { + mode >>= 6; + } else { + if (mode & S_IRWXG) { + rc = mdd_check_acl(env, obj, la, mask); + if (rc == -EACCES) + goto check_capabilities; + else if ((rc != -EAGAIN) && (rc != -EOPNOTSUPP) && + (rc != -ENODATA)) + RETURN(rc); + } + if (mdd_in_group_p(uc, la->la_gid)) + mode >>= 3; + } + + /* + * If the DACs are ok we don't need any capability check. + */ + if (((mode & mask & S_IRWXO) == mask)) + RETURN(0); + +check_capabilities: + + /* + * Read/write DACs are always overridable. + * Executable DACs are overridable if at least one exec bit is set. + * Dir's DACs are always overridable. + */ + if (!(mask & MAY_EXEC) || + (la->la_mode & S_IXUGO) || S_ISDIR(la->la_mode)) + if (mdd_capable(uc, CAP_DAC_OVERRIDE)) + RETURN(0); + + /* + * Searching includes executable on directories, else just read. + */ + if ((mask == MAY_READ) || + (S_ISDIR(la->la_mode) && !(mask & MAY_WRITE))) + if (mdd_capable(uc, CAP_DAC_READ_SEARCH)) + RETURN(0); + + RETURN(-EACCES); +} + +int mdd_permission_internal(const struct lu_env *env, struct mdd_object *obj, + int mask) +{ + return __mdd_permission_internal(env, obj, mask, 1); +} + +#ifdef CONFIG_FS_POSIX_ACL +/* get default acl EA only */ +int mdd_acl_def_get(const struct lu_env *env, struct mdd_object *mdd_obj, + struct md_attr *ma) +{ + struct dt_object *next = mdd_object_child(mdd_obj); + int rc; + + rc = next->do_ops->do_xattr_get(env, next, + mdd_buf_get(env, ma->ma_lmv, + ma->ma_lmv_size), + XATTR_NAME_ACL_DEFAULT, BYPASS_CAPA); + if (rc > 0) { + ma->ma_lmv_size = rc; + ma->ma_valid |= MA_ACL_DEF; + rc = 0; + } else if ((rc == -EOPNOTSUPP) || (rc == -ENODATA)) { + rc = 0; + } + RETURN(rc); +} +#endif + +#ifdef CONFIG_FS_POSIX_ACL +#include +#include + +/* + * Modify the ACL for the chmod. + */ +static int mdd_posix_acl_chmod_masq(posix_acl_xattr_entry *entry, + __u32 mode, int count) +{ + posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe; + + pa = &entry[0]; + pe = &entry[count - 1]; + for (; pa <= pe; pa++) { + switch(pa->e_tag) { + case ACL_USER_OBJ: + pa->e_perm = (mode & S_IRWXU) >> 6; + break; + + case ACL_USER: + case ACL_GROUP: + break; + + case ACL_GROUP_OBJ: + group_obj = pa; + break; + + case ACL_MASK: + mask_obj = pa; + break; + + case ACL_OTHER: + pa->e_perm = (mode & S_IRWXO); + break; + + default: + return -EIO; + } + } + + if (mask_obj) { + mask_obj->e_perm = (mode & S_IRWXG) >> 3; + } else { + if (!group_obj) + return -EIO; + group_obj->e_perm = (mode & S_IRWXG) >> 3; + } + + return 0; +} + +int mdd_acl_chmod(const struct lu_env *env, struct mdd_object *o, __u32 mode, + struct thandle *handle) +{ + struct dt_object *next; + struct lu_buf *buf; + posix_acl_xattr_entry *entry; + int entry_count; + int rc; + + ENTRY; + + next = mdd_object_child(o); + buf = &mdd_env_info(env)->mti_buf; + buf->lb_buf = mdd_env_info(env)->mti_xattr_buf; + buf->lb_len = sizeof(mdd_env_info(env)->mti_xattr_buf); + rc = next->do_ops->do_xattr_get(env, next, buf, + XATTR_NAME_ACL_ACCESS, BYPASS_CAPA); + if ((rc == -EOPNOTSUPP) || (rc == -ENODATA)) + RETURN(0); + else if (rc <= 0) + RETURN(rc); + + buf->lb_len = rc; + entry = ((posix_acl_xattr_header *)(buf->lb_buf))->a_entries; + entry_count = (rc - 4) / sizeof(posix_acl_xattr_entry); + if (entry_count <= 0) + RETURN(0); + + rc = mdd_posix_acl_chmod_masq(entry, mode, entry_count); + if (rc) + RETURN(rc); + + rc = next->do_ops->do_xattr_set(env, next, buf, XATTR_NAME_ACL_ACCESS, + 0, handle, BYPASS_CAPA); + RETURN(rc); +} +#endif + +#ifdef CONFIG_FS_POSIX_ACL +/* + * Modify acl when creating a new obj. + * + * mode_p initially must contain the mode parameter to the open() / creat() + * system calls. All permissions that are not granted by the acl are removed. + * The permissions in the acl are changed to reflect the mode_p parameter. + */ +static int mdd_posix_acl_create_masq(posix_acl_xattr_entry *entry, + __u32 *mode_p, int count) +{ + posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe; + __u32 mode = *mode_p; + int not_equiv = 0; + + pa = &entry[0]; + pe = &entry[count - 1]; + for (; pa <= pe; pa++) { + switch(pa->e_tag) { + case ACL_USER_OBJ: + pa->e_perm &= (mode >> 6) | ~S_IRWXO; + mode &= (pa->e_perm << 6) | ~S_IRWXU; + break; + + case ACL_USER: + case ACL_GROUP: + not_equiv = 1; + break; + + case ACL_GROUP_OBJ: + group_obj = pa; + break; + + case ACL_OTHER: + pa->e_perm &= mode | ~S_IRWXO; + mode &= pa->e_perm | ~S_IRWXO; + break; + + case ACL_MASK: + mask_obj = pa; + not_equiv = 1; + break; + + default: + return -EIO; + } + } + + if (mask_obj) { + mask_obj->e_perm &= (mode >> 3) | ~S_IRWXO; + mode &= (mask_obj->e_perm << 3) | ~S_IRWXG; + } else { + if (!group_obj) + return -EIO; + group_obj->e_perm &= (mode >> 3) | ~S_IRWXO; + mode &= (group_obj->e_perm << 3) | ~S_IRWXG; + } + + *mode_p = (*mode_p & ~S_IRWXUGO) | mode; + return not_equiv; +} + +int __mdd_acl_init(const struct lu_env *env, struct mdd_object *obj, + struct lu_buf *buf, __u32 *mode, struct thandle *handle) +{ + struct dt_object *next; + posix_acl_xattr_entry *entry; + int entry_count; + int rc; + + ENTRY; + + entry = ((posix_acl_xattr_header *)(buf->lb_buf))->a_entries; + entry_count = (buf->lb_len - 4) / sizeof(posix_acl_xattr_entry); + if (entry_count <= 0) + RETURN(0); + + next = mdd_object_child(obj); + if (S_ISDIR(*mode)) { + rc = next->do_ops->do_xattr_set(env, next, buf, + XATTR_NAME_ACL_DEFAULT, + 0, handle, BYPASS_CAPA); + if (rc) + RETURN(rc); + } + + rc = mdd_posix_acl_create_masq(entry, mode, entry_count); + if (rc < 0) + RETURN(rc); + else if (rc > 0) + rc = next->do_ops->do_xattr_set(env, next, buf, + XATTR_NAME_ACL_ACCESS, + 0, handle, BYPASS_CAPA); + RETURN(rc); +} + +int mdd_acl_init(const struct lu_env *env, struct mdd_object *pobj, + struct mdd_object *cobj, __u32 *mode, + struct thandle *handle) +{ + struct dt_object *next = mdd_object_child(pobj); + struct lu_buf *buf = &mdd_env_info(env)->mti_buf; + int rc; + + ENTRY; + + if (S_ISLNK(*mode)) + RETURN(0); + + buf->lb_buf = mdd_env_info(env)->mti_xattr_buf; + buf->lb_len = sizeof(mdd_env_info(env)->mti_xattr_buf); + rc = next->do_ops->do_xattr_get(env, next, buf, + XATTR_NAME_ACL_DEFAULT, BYPASS_CAPA); + if ((rc == -EOPNOTSUPP) || (rc == -ENODATA)) + RETURN(0); + else if (rc <= 0) + RETURN(rc); + + buf->lb_len = rc; + rc = __mdd_acl_init(env, cobj, buf, mode, handle); + RETURN(rc); +} +#endif + +#if 0 +static int mdd_exec_permission_lite(const struct lu_env *env, + struct mdd_object *obj) +{ + struct lu_attr *la = &mdd_env_info(env)->mti_la; + struct md_ucred *uc = md_ucred(env); + umode_t mode; + int rc; + ENTRY; + + /* These means unnecessary for permission check */ + if ((uc == NULL) || (uc->mu_valid == UCRED_INIT)) + RETURN(0); + + /* Invalid user credit */ + if (uc->mu_valid == UCRED_INVALID) + RETURN(-EACCES); + + rc = __mdd_la_get(env, obj, la, BYPASS_CAPA); + if (rc) + RETURN(rc); + + mode = la->la_mode; + if (uc->mu_fsuid == la->la_uid) + mode >>= 6; + else if (mdd_in_group_p(uc, la->la_gid)) + mode >>= 3; + + if (mode & MAY_EXEC) + RETURN(0); + + if (((la->la_mode & S_IXUGO) || S_ISDIR(la->la_mode)) && + mdd_capable(uc, CAP_DAC_OVERRIDE)) + RETURN(0); + + if (S_ISDIR(la->la_mode) && mdd_capable(uc, CAP_DAC_READ_SEARCH)) + RETURN(0); + + RETURN(-EACCES); +} +#endif + +static inline int mdd_permission_internal_locked(const struct lu_env *env, + struct mdd_object *obj, + int mask) +{ + int rc; + + mdd_read_lock(env, obj); + rc = mdd_permission_internal(env, obj, mask); + mdd_read_unlock(env, obj); + + return rc; +} + +int mdd_permission(const struct lu_env *env, struct md_object *obj, int mask) +{ + struct mdd_object *mdd_obj = md2mdd_obj(obj); + int rc; + ENTRY; + + rc = mdd_permission_internal_locked(env, mdd_obj, mask); + + RETURN(rc); +} + +int mdd_capa_get(const struct lu_env *env, struct md_object *obj, + struct lustre_capa *capa, int renewal) +{ + struct dt_object *next; + struct mdd_object *mdd_obj = md2mdd_obj(obj); + struct obd_capa *oc; + int rc = 0; + ENTRY; + + LASSERT(lu_object_exists(mdd2lu_obj(mdd_obj))); + next = mdd_object_child(mdd_obj); + + oc = next->do_ops->do_capa_get(env, next, renewal ? capa : NULL, + capa->lc_opc); + if (IS_ERR(oc)) { + rc = PTR_ERR(oc); + } else { + capa_cpy(capa, oc); + capa_put(oc); + } + + RETURN(rc); +} + -- 1.8.3.1