From: ericm Date: Tue, 29 Jan 2008 21:24:51 +0000 (+0000) Subject: land b_colibri_devel on HEAD: X-Git-Tag: v1_7_0_51~277 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=3192e52a89946f12fd36d28a686c169d01d36e64;ds=inline land b_colibri_devel on HEAD: - redesigned remote acl support, by FanYong b=11842 r=pravin.shelar, eric.mei - new sptlrpc configure interface b=13642 r=yong.fan, rahul.deshmukh - split kerberos keytab for lustre_root b=13873 r=yong.fan, h.huang - fix setuid for gss with linux keyring b=13899 r=yong.fan, h.huang --- diff --git a/lustre/ChangeLog b/lustre/ChangeLog index 3422dfb..b0b0823 100644 --- a/lustre/ChangeLog +++ b/lustre/ChangeLog @@ -61,6 +61,14 @@ Details : If an OST is down the MDS will hang indefinitely in MDS QOS usage of statfs, it should not stuck in waiting. Severity : enhancement +Bugzilla : 11842 +Description: remote_acl support +Details : Support ACL-based permission check for remote user. + Support setfacl/getfacl for remote user with the utils + "lfs {l,r}{s,g}etfacl" which follow the same parameter format as + the system "{s,g}etfacl" utils. + +Severity : enhancement Bugzilla : 14288 Description: Update to RHEL4 U6 kernel-2.6.9-67.EL. diff --git a/lustre/autoconf/kerberos5.m4 b/lustre/autoconf/kerberos5.m4 index 1dac9f0..dfa5738 100644 --- a/lustre/autoconf/kerberos5.m4 +++ b/lustre/autoconf/kerberos5.m4 @@ -36,6 +36,8 @@ AC_DEFUN([AC_KERBEROS_V5],[ AC_DEFINE_UNQUOTED(KRB5_VERSION, $K5VERS, [Define this as the Kerberos version number]) if test -f $dir/include/gssapi/gssapi_krb5.h -a \ \( -f $dir/lib/libgssapi_krb5.a -o \ + -f $dir/lib64/libgssapi_krb5.a -o \ + -f $dir/lib64/libgssapi_krb5.so -o \ -f $dir/lib/libgssapi_krb5.so \) ; then AC_DEFINE(HAVE_KRB5, 1, [Define this if you have MIT Kerberos libraries]) KRBDIR="$dir" @@ -91,6 +93,14 @@ AC_DEFUN([AC_KERBEROS_V5],[ AC_CHECK_LIB($gssapi_lib, gss_krb5_ccache_name, AC_DEFINE(HAVE_GSS_KRB5_CCACHE_NAME, 1, [Define this if the Kerberos GSS library supports gss_krb5_ccache_name]), ,$KRBLIBS) + dnl Check for newer error message facility + AC_CHECK_LIB($gssapi_lib, krb5_get_error_message, + AC_DEFINE(HAVE_KRB5_GET_ERROR_MESSAGE, 1, [Define this if the function krb5_get_error_message is available]), ,$KRBLIBS) + + dnl Check for function to specify addressless tickets + AC_CHECK_LIB($gssapi_lib, krb5_get_init_creds_opt_set_addressless, + AC_DEFINE(HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS, 1, [Define this if the function krb5_get_init_creds_opt_set_addressless is available]), ,$KRBLIBS) + dnl If they specified a directory and it didn't work, give them a warning if test "x$krb5_with" != "x" -a "$krb5_with" != "$KRBDIR"; then AC_MSG_WARN(Using $KRBDIR instead of requested value of $krb5_with for Kerberos!) diff --git a/lustre/include/Makefile.am b/lustre/include/Makefile.am index adf7c6e..27e62fc 100644 --- a/lustre/include/Makefile.am +++ b/lustre/include/Makefile.am @@ -15,5 +15,5 @@ EXTRA_DIST = ioctl.h liblustre.h lprocfs_status.h lustre_cfg.h \ obd_cache.h obd_class.h obd_echo.h obd.h obd_lov.h \ obd_ost.h obd_support.h lustre_ver.h lu_object.h lu_time.h \ md_object.h dt_object.h lustre_param.h lustre_mdt.h \ - lustre_fid.h lustre_fld.h lustre_req_layout.h lustre_capa.h - + lustre_fid.h lustre_fld.h lustre_req_layout.h lustre_capa.h \ + lustre_idmap.h lustre_eacl.h diff --git a/lustre/include/linux/lustre_acl.h b/lustre/include/linux/lustre_acl.h index 0583ea4..153ac74 100644 --- a/lustre/include/linux/lustre_acl.h +++ b/lustre/include/linux/lustre_acl.h @@ -16,15 +16,15 @@ # ifdef CONFIG_FS_POSIX_ACL # ifdef HAVE_XATTR_ACL # include -# endif +# endif /* HAVE_XATTR_ACL */ # ifdef HAVE_LINUX_POSIX_ACL_XATTR_H # include -# endif -# endif +# endif /* HAVE_LINUX_POSIX_ACL_XATTR_H */ +# endif /* CONFIG_FS_POSIX_ACL */ # ifndef HAVE_VFS_INTENT_PATCHES # include # endif -#endif +#endif /* __KERNEL__ */ /* ACL */ #ifdef CONFIG_FS_POSIX_ACL @@ -42,8 +42,8 @@ # define LUSTRE_POSIX_ACL_MAX_SIZE XATTR_ACL_SIZE -#else /* CONFIG_FS_POSIX_ACL */ +# else /* CONFIG_FS_POSIX_ACL */ # define LUSTRE_POSIX_ACL_MAX_SIZE 0 -#endif /* CONFIG_FS_POSIX_ACL */ +# endif /* CONFIG_FS_POSIX_ACL */ #endif /* _LUSTRE_ACL_H */ diff --git a/lustre/include/linux/lustre_mds.h b/lustre/include/linux/lustre_mds.h index 8e7c372..ce48c0d 100644 --- a/lustre/include/linux/lustre_mds.h +++ b/lustre/include/linux/lustre_mds.h @@ -20,15 +20,15 @@ # ifdef CONFIG_FS_POSIX_ACL # ifdef HAVE_XATTR_ACL # include -# endif +# endif /* HAVE_XATTR_ACL */ # ifdef HAVE_LINUX_POSIX_ACL_XATTR_H # include -# endif -# endif +# endif /* HAVE_LINUX_POSIX_ACL_XATTR_H */ +# endif /* CONFIG_FS_POSIX_ACL */ # ifndef HAVE_VFS_INTENT_PATCHES # include # endif -#endif +#endif /* __KERNEL__ */ struct mds_obd; struct ptlrpc_request; diff --git a/lustre/include/linux/lvfs.h b/lustre/include/linux/lvfs.h index 1cc27c4..e66a3a2 100644 --- a/lustre/include/linux/lvfs.h +++ b/lustre/include/linux/lvfs.h @@ -52,7 +52,7 @@ struct lvfs_ucred { __u32 luc_cap; __u32 luc_umask; struct group_info *luc_ginfo; - struct mdt_identity *luc_identity; + struct md_identity *luc_identity; }; struct lvfs_callback_ops { diff --git a/lustre/include/lustre/liblustreapi.h b/lustre/include/lustre/liblustreapi.h index cf63180..0e5b2bf 100644 --- a/lustre/include/lustre/liblustreapi.h +++ b/lustre/include/lustre/liblustreapi.h @@ -110,6 +110,10 @@ extern int llapi_quotacheck(char *mnt, int check_type); extern int llapi_poll_quotacheck(char *mnt, struct if_quotacheck *qchk); extern int llapi_quotactl(char *mnt, struct if_quotactl *qctl); extern int llapi_target_iterate(int type_num, char **obd_type, void *args, llapi_cb_t cb); -extern int llapi_getfacl(char *fname, char *cmd); -extern int llapi_setfacl(char *fname, char *cmd); +extern int llapi_lsetfacl(int argc, char *argv[]); +extern int llapi_lgetfacl(int argc, char *argv[]); +extern int llapi_rsetfacl(int argc, char *argv[]); +extern int llapi_rgetfacl(int argc, char *argv[]); +extern int llapi_cp(int argc, char *argv[]); +extern int llapi_ls(int argc, char *argv[]); #endif diff --git a/lustre/include/lustre/lustre_idl.h b/lustre/include/lustre/lustre_idl.h index d308bbc..c877670d 100644 --- a/lustre/include/lustre/lustre_idl.h +++ b/lustre/include/lustre/lustre_idl.h @@ -753,9 +753,6 @@ extern void lustre_swab_lov_mds_md(struct lov_mds_md *llm); #define XATTR_NAME_ACL_DEFAULT "system.posix_acl_default" #define XATTR_NAME_LOV "trusted.lov" -/* remote ACL */ -#define XATTR_NAME_LUSTRE_ACL "system.lustre_acl" - #define OBD_MD_FLID (0x00000001ULL) /* object ID */ #define OBD_MD_FLATIME (0x00000002ULL) /* access time */ #define OBD_MD_FLMTIME (0x00000004ULL) /* data modification time */ @@ -803,6 +800,11 @@ extern void lustre_swab_lov_mds_md(struct lov_mds_md *llm); #define OBD_MD_FLCKSPLIT (0x0000080000000000ULL) /* Check split on server */ #define OBD_MD_FLCROSSREF (0x0000100000000000ULL) /* Cross-ref case */ +#define OBD_MD_FLRMTLSETFACL (0x0001000000000000ULL) /* lfs lsetfacl case */ +#define OBD_MD_FLRMTLGETFACL (0x0002000000000000ULL) /* lfs lgetfacl case */ +#define OBD_MD_FLRMTRSETFACL (0x0004000000000000ULL) /* lfs rsetfacl case */ +#define OBD_MD_FLRMTRGETFACL (0x0008000000000000ULL) /* lfs rgetfacl case */ + #define OBD_MD_FLGETATTR (OBD_MD_FLID | OBD_MD_FLATIME | OBD_MD_FLMTIME | \ OBD_MD_FLCTIME | OBD_MD_FLSIZE | OBD_MD_FLBLKSZ | \ OBD_MD_FLMODE | OBD_MD_FLTYPE | OBD_MD_FLUID | \ @@ -1164,10 +1166,13 @@ struct mds_remote_perm { __u32 rp_access_perm; /* MAY_READ/WRITE/EXEC */ }; -/* setxid permissions for mds_setxid_perm.mp_perm */ -#define LUSTRE_SETUID_PERM 0x01 -#define LUSTRE_SETGID_PERM 0x02 -#define LUSTRE_SETGRP_PERM 0x04 +/* permissions for md_perm.mp_perm */ +enum { + CFS_SETUID_PERM = 0x01, + CFS_SETGID_PERM = 0x02, + CFS_SETGRP_PERM = 0x04, + CFS_RMTACL_PERM = 0x08 +}; extern void lustre_swab_mds_remote_perm(struct mds_remote_perm *p); @@ -1294,6 +1299,8 @@ extern void lustre_swab_mdt_rec_setattr (struct mdt_rec_setattr *sa); #define MAY_VTX_PART (1 << 12) /* full VTX permission check */ #define MAY_VTX_FULL (1 << 13) +/* lfs rgetfacl permission check */ +#define MAY_RGETFACL (1 << 14) enum { MDS_CHECK_SPLIT = 1 << 0, diff --git a/lustre/include/lustre/lustre_user.h b/lustre/include/lustre/lustre_user.h index 8c17bc5..0dc8b87 100644 --- a/lustre/include/lustre/lustre_user.h +++ b/lustre/include/lustre/lustre_user.h @@ -59,8 +59,7 @@ struct obd_statfs; #define IOC_OBD_STATFS _IOWR('f', 164, struct obd_statfs *) #define IOC_LOV_GETINFO _IOWR('f', 165, struct lov_user_mds_data *) #define LL_IOC_FLUSHCTX _IOW ('f', 166, long) -#define LL_IOC_GETFACL _IOWR('f', 167, struct rmtacl_ioctl_data *) -#define LL_IOC_SETFACL _IOWR('f', 168, struct rmtacl_ioctl_data *) +#define LL_IOC_RMTACL _IOW ('f', 167, long) #define LL_IOC_LLOOP_ATTACH _IOWR('f', 169, long) #define LL_IOC_LLOOP_DETACH _IOWR('f', 170, long) @@ -89,6 +88,7 @@ struct obd_statfs; #define LL_FILE_IGNORE_LOCK 0x00000001 #define LL_FILE_GROUP_LOCKED 0x00000002 #define LL_FILE_READAHEAD 0x00000004 +#define LL_FILE_RMTACL 0x00000008 #define LOV_USER_MAGIC_V1 0x0BD10BD0 #define LOV_USER_MAGIC LOV_USER_MAGIC_V1 @@ -188,10 +188,10 @@ struct if_quotacheck { #define IDENTITY_DOWNCALL_MAGIC 0x6d6dd620 -/* setxid permission */ -#define N_SETXID_PERMS_MAX 64 +/* permission */ +#define N_PERMS_MAX 64 -struct setxid_perm_downcall_data { +struct perm_downcall_data { __u64 pdd_nid; __u32 pdd_perm; }; @@ -202,21 +202,22 @@ struct identity_downcall_data { __u32 idd_uid; __u32 idd_gid; __u32 idd_nperms; - struct setxid_perm_downcall_data idd_perms[N_SETXID_PERMS_MAX]; + struct perm_downcall_data idd_perms[N_PERMS_MAX]; __u32 idd_ngroups; __u32 idd_groups[0]; }; -#define RMTACL_DOWNCALL_MAGIC 0x6d6dd620 -#define RMTACL_SIZE_MAX (4096) +/* for non-mapped uid/gid */ +#define NOBODY_UID 99 +#define NOBODY_GID 99 -struct rmtacl_downcall_data { - __u32 add_magic; - __u32 add_handle; - __u64 add_key; - __u32 add_buflen; - __u32 add_padding; - __u8 add_buf[0]; +#define INVALID_ID (-1) + +enum { + RMT_LSETFACL = 1, + RMT_LGETFACL = 2, + RMT_RSETFACL = 3, + RMT_RGETFACL = 4 }; #ifdef NEED_QUOTA_DEFS @@ -284,12 +285,4 @@ struct if_quotactl { # define offsetof(typ,memb) ((unsigned long)((char *)&(((typ *)0)->memb))) #endif -/* remote acl ioctl */ -struct rmtacl_ioctl_data { - char *cmd; /* IN */ - unsigned long cmd_len; - char *res; /* OUT */ - unsigned long res_len; -}; - #endif /* _LUSTRE_USER_H */ diff --git a/lustre/include/lustre_cfg.h b/lustre/include/lustre_cfg.h index 89c5447..5432519 100644 --- a/lustre/include/lustre_cfg.h +++ b/lustre/include/lustre_cfg.h @@ -58,7 +58,7 @@ enum lcfg_command_type { LCFG_LOV_ADD_INA = 0x00ce013, LCFG_ADD_MDC = 0x00cf014, LCFG_DEL_MDC = 0x00cf015, - LCFG_SEC_FLAVOR = 0x00ce016, + LCFG_SPTLRPC_CONF = 0x00cf016, }; struct lustre_cfg_bufs { @@ -256,9 +256,8 @@ static inline int lustre_cfg_sanity_check(void *buf, int len) RETURN(0); } -/* default value for nllu/nllg for llite */ -#define NOBODY_UID 99 -#define NOBODY_GID 99 +#include + #define INVALID_UID (-1) #endif // _LUSTRE_CFG_H diff --git a/lustre/include/lustre_disk.h b/lustre/include/lustre_disk.h index fd8c664..98ede40 100644 --- a/lustre/include/lustre_disk.h +++ b/lustre/include/lustre_disk.h @@ -141,10 +141,6 @@ struct lustre_mount_data { int lmd_exclude_count; char *lmd_dev; /* device name */ char *lmd_profile; /* client only */ - char *lmd_sec_mdt; /* sec from mdt (to ost/mdt) */ - char *lmd_sec_cli; /* sec from client (to ost/mdt) */ - uid_t lmd_nllu; /* non-lustre-local-user id */ - gid_t lmd_nllg; /* non-lustre-local-group id */ char *lmd_opts; /* lustre mount options (as opposed to _device_ mount options) */ __u32 *lmd_exclude; /* array of OSTs to ignore */ diff --git a/lustre/include/lustre_eacl.h b/lustre/include/lustre_eacl.h new file mode 100644 index 0000000..dddfde5 --- /dev/null +++ b/lustre/include/lustre_eacl.h @@ -0,0 +1,80 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * This file is part of Lustre, http://www.lustre.org + * + * MDS data structures. + * See also lustre_idl.h for wire formats of requests. + */ + +#ifndef _LUSTRE_EACL_H +#define _LUSTRE_EACL_H + +#ifdef CONFIG_FS_POSIX_ACL + +# ifdef HAVE_XATTR_ACL +# include +# endif /* HAVE_XATTR_ACL */ +# ifdef HAVE_LINUX_POSIX_ACL_XATTR_H +# include +# endif /* HAVE_LINUX_POSIX_ACL_XATTR_H */ + +#include +#include +#include + +typedef struct { + __u16 e_tag; + __u16 e_perm; + __u32 e_id; + __u32 e_stat; +} ext_acl_xattr_entry; + +typedef struct { + __u32 a_count; + ext_acl_xattr_entry a_entries[0]; +} ext_acl_xattr_header; + +#define CFS_ACL_XATTR_SIZE(count, prefix) \ + (sizeof(prefix ## _header) + (count) * sizeof(prefix ## _entry)) + +#define CFS_ACL_XATTR_COUNT(size, prefix) \ + (((size) - sizeof(prefix ## _header)) / sizeof(prefix ## _entry)) + +extern int lustre_posix_acl_permission(struct md_ucred *mu, struct lu_attr *la, + int want, posix_acl_xattr_entry *entry, + int count); +extern int lustre_posix_acl_chmod_masq(posix_acl_xattr_entry *entry, + __u32 mode, int count); +extern int lustre_posix_acl_create_masq(posix_acl_xattr_entry *entry, + __u32 *pmode, int count); + +extern ext_acl_xattr_header * +lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size); +extern int +lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, int size, + posix_acl_xattr_header **out); +extern int +lustre_posix_acl_xattr_id2client(struct md_ucred *mu, + struct lustre_idmap_table *t, + posix_acl_xattr_header *header, + int size, int flags); +extern void +lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size); +extern int +lustre_ext_acl_xattr_id2server(struct md_ucred *mu, + struct lustre_idmap_table *t, + ext_acl_xattr_header *header); +extern void +lustre_ext_acl_xattr_free(ext_acl_xattr_header *header); +extern int +lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size, + ext_acl_xattr_header *ext_header, + posix_acl_xattr_header **out); +extern ext_acl_xattr_header * +lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size, + ext_acl_xattr_header *ext_header); + +#endif /* CONFIG_FS_POSIX_ACL */ + +#endif diff --git a/lustre/include/lustre_export.h b/lustre/include/lustre_export.h index 047c98c..c87468b 100644 --- a/lustre/include/lustre_export.h +++ b/lustre/include/lustre_export.h @@ -23,9 +23,8 @@ struct mds_export_data { loff_t med_lr_off; int med_lr_idx; unsigned int med_rmtclient:1; /* remote client? */ - __u32 med_nllu; - __u32 med_nllg; - struct mds_idmap_table *med_idmap; + struct semaphore med_idmap_sem; + struct lustre_idmap_table *med_idmap; }; struct mdt_export_data { @@ -37,9 +36,8 @@ struct mdt_export_data { loff_t med_lr_off; int med_lr_idx; unsigned int med_rmtclient:1; /* remote client? */ - __u32 med_nllu; - __u32 med_nllg; - struct mdt_idmap_table *med_idmap; + struct semaphore med_idmap_sem; + struct lustre_idmap_table *med_idmap; }; struct osc_creator { @@ -111,7 +109,15 @@ struct obd_export { exp_req_replay_needed:1, exp_lock_replay_needed:1, exp_need_sync:1, + exp_flvr_changed:1, + exp_flvr_adapt:1, exp_libclient:1; /* liblustre client? */ + /* also protected by exp_lock */ + enum lustre_sec_part exp_sp_peer; + struct sptlrpc_flavor exp_flvr; /* current */ + struct sptlrpc_flavor exp_flvr_old[2]; /* about-to-expire */ + cfs_time_t exp_flvr_expire[2]; /* seconds */ + union { struct mds_export_data eu_mds_data; struct mdt_export_data eu_mdt_data; diff --git a/lustre/include/lustre_idmap.h b/lustre/include/lustre_idmap.h new file mode 100644 index 0000000..fa1a6cc --- /dev/null +++ b/lustre/include/lustre_idmap.h @@ -0,0 +1,63 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * This file is part of Lustre, http://www.lustre.org + * + * MDS data structures. + * See also lustre_idl.h for wire formats of requests. + */ + +#ifndef _LUSTRE_IDMAP_H +#define _LUSTRE_IDMAP_H + +#include + +#define CFS_NGROUPS_PER_BLOCK ((int)(CFS_PAGE_SIZE / sizeof(gid_t))) + +#define CFS_GROUP_AT(gi, i) \ + ((gi)->blocks[(i) / CFS_NGROUPS_PER_BLOCK][(i) % CFS_NGROUPS_PER_BLOCK]) + +enum { + CFS_IC_NOTHING = 0, /* convert nothing */ + CFS_IC_ALL = 1, /* convert all items */ + CFS_IC_MAPPED = 2, /* convert mapped uid/gid */ + CFS_IC_UNMAPPED = 3 /* convert unmapped uid/gid */ +}; + +#define CFS_IDMAP_NOTFOUND (-1) + +#define CFS_IDMAP_HASHSIZE 32 + +enum lustre_idmap_idx { + RMT_UIDMAP_IDX, + LCL_UIDMAP_IDX, + RMT_GIDMAP_IDX, + LCL_GIDMAP_IDX, + CFS_IDMAP_N_HASHES +}; + +struct lustre_idmap_table { + spinlock_t lit_lock; + struct list_head lit_idmaps[CFS_IDMAP_N_HASHES][CFS_IDMAP_HASHSIZE]; +}; + +extern void lustre_groups_from_list(struct group_info *ginfo, gid_t *glist); +extern void lustre_groups_sort(struct group_info *group_info); +extern int lustre_in_group_p(struct md_ucred *mu, gid_t grp); + +extern int lustre_idmap_add(struct lustre_idmap_table *t, + uid_t ruid, uid_t luid, + gid_t rgid, gid_t lgid); +extern int lustre_idmap_del(struct lustre_idmap_table *t, + uid_t ruid, uid_t luid, + gid_t rgid, gid_t lgid); +extern int lustre_idmap_lookup_uid(struct md_ucred *mu, + struct lustre_idmap_table *t, + int reverse, uid_t uid); +extern int lustre_idmap_lookup_gid(struct md_ucred *mu, + struct lustre_idmap_table *t, + int reverse, gid_t gid); +extern struct lustre_idmap_table *lustre_idmap_init(void); +extern void lustre_idmap_fini(struct lustre_idmap_table *t); + +#endif diff --git a/lustre/include/lustre_import.h b/lustre/include/lustre_import.h index 5dee54a..7a5c761 100644 --- a/lustre/include/lustre_import.h +++ b/lustre/include/lustre_import.h @@ -66,6 +66,8 @@ struct obd_import { struct obd_device *imp_obd; struct ptlrpc_sec *imp_sec; + struct semaphore imp_sec_mutex; + cfs_time_t imp_sec_expire; cfs_waitq_t imp_recovery_waitq; atomic_t imp_inflight; diff --git a/lustre/include/lustre_mdc.h b/lustre/include/lustre_mdc.h index f025ead..598754b 100644 --- a/lustre/include/lustre_mdc.h +++ b/lustre/include/lustre_mdc.h @@ -16,15 +16,15 @@ # ifdef CONFIG_FS_POSIX_ACL # ifdef HAVE_XATTR_ACL # include -# endif +# endif /*HAVE_XATTR_ACL */ # ifdef HAVE_LINUX_POSIX_ACL_XATTR_H # include -# endif -# endif +# endif /* HAVE_LINUX_POSIX_ACL_XATTR_H */ +# endif /* CONFIG_FS_POSIX_ACL */ # ifndef HAVE_VFS_INTENT_PATCHES # include -# endif -#endif +# endif /* HAVE_VFS_INTENT_PATCHES */ +#endif /* __KERNEL__ */ #include #include #include diff --git a/lustre/include/lustre_mdt.h b/lustre/include/lustre_mdt.h index 861a077..06ed6b18 100644 --- a/lustre/include/lustre_mdt.h +++ b/lustre/include/lustre_mdt.h @@ -40,24 +40,6 @@ struct com_thread_info { struct req_capsule cti_pill; }; -/* id map */ -#define MDT_IDMAP_HASHSIZE (32) -#define MDT_IDMAP_HASHFUNC(id) ((id) & (MDT_IDMAP_HASHSIZE - 1)) - -enum mdt_idmap_idx { - RMT_UIDMAP_IDX, - LCL_UIDMAP_IDX, - RMT_GIDMAP_IDX, - LCL_GIDMAP_IDX, - MDT_IDMAP_N_HASHES -}; - -struct mdt_idmap_table { - spinlock_t mit_lock; - struct list_head mit_idmaps[MDT_IDMAP_N_HASHES] - [MDT_IDMAP_HASHSIZE]; -}; - enum { ESERIOUS = 0x0001000 }; diff --git a/lustre/include/lustre_net.h b/lustre/include/lustre_net.h index 0635010..ca69a55 100644 --- a/lustre/include/lustre_net.h +++ b/lustre/include/lustre_net.h @@ -337,9 +337,12 @@ struct ptlrpc_request { struct ptlrpc_cli_ctx *rq_cli_ctx; /* client's half ctx */ struct ptlrpc_svc_ctx *rq_svc_ctx; /* server's half ctx */ struct list_head rq_ctx_chain; /* link to waited ctx */ - ptlrpc_sec_flavor_t rq_sec_flavor; /* client & server */ - /* client security flags */ - unsigned long rq_ctx_init:1, /* context initiation */ + + struct sptlrpc_flavor rq_flvr; /* client & server */ + enum lustre_sec_part rq_sp_from; + + unsigned long /* client/server security flags */ + rq_ctx_init:1, /* context initiation */ rq_ctx_fini:1, /* context destroy */ rq_bulk_read:1, /* request bulk read */ rq_bulk_write:1, /* request bulk write */ @@ -348,6 +351,9 @@ struct ptlrpc_request { rq_auth_remote:1, /* authed as remote user */ rq_auth_usr_root:1, /* authed as root */ rq_auth_usr_mdt:1, /* authed as mdt */ + /* security tfm flags */ + rq_pack_udesc:1, + rq_pack_bulk:1, /* doesn't expect reply FIXME */ rq_no_reply:1; diff --git a/lustre/include/lustre_param.h b/lustre/include/lustre_param.h index 8acf23e..afcc851 100644 --- a/lustre/include/lustre_param.h +++ b/lustre/include/lustre_param.h @@ -60,9 +60,9 @@ int do_lcfg(char *cfgname, lnet_nid_t nid, int cmd, #define PARAM_MDC "mdc." #define PARAM_LLITE "llite." #define PARAM_LOV "lov." +#define PARAM_SRPC "srpc." +#define PARAM_SRPC_FLVR "srpc.flavor." +#define PARAM_SRPC_UDESC "srpc.udesc.cli2mdt" #define PARAM_SEC "security." -#define PARAM_SEC_RPC PARAM_SEC"rpc." -#define PARAM_SEC_RPC_MDT PARAM_SEC_RPC"mdt=" -#define PARAM_SEC_RPC_CLI PARAM_SEC_RPC"cli=" #endif /* _LUSTRE_PARAM_H */ diff --git a/lustre/include/lustre_sec.h b/lustre/include/lustre_sec.h index e9fe854..6455858 100644 --- a/lustre/include/lustre_sec.h +++ b/lustre/include/lustre_sec.h @@ -1,7 +1,7 @@ /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * - * Copyright (C) 2004-2006 Cluster File Systems, Inc. + * Copyright (C) 2004-2007 Cluster File Systems, Inc. * * This file is part of Lustre, http://www.lustre.org. * @@ -32,6 +32,7 @@ struct ptlrpc_request; struct ptlrpc_reply_state; struct ptlrpc_bulk_desc; struct brw_page; +struct seq_file; /* * forward declaration @@ -51,7 +52,6 @@ enum sptlrpc_policy { SPTLRPC_POLICY_NULL = 0, SPTLRPC_POLICY_PLAIN = 1, SPTLRPC_POLICY_GSS = 2, - SPTLRPC_POLICY_GSS_PIPEFS = 3, SPTLRPC_POLICY_MAX, }; @@ -80,119 +80,169 @@ enum sptlrpc_service_type { }; /* - * flavor compose/extract + * rpc flavor compose/extract, represented as 16 bits + * + * 4b (reserved) | 4b (svc) | 4b (mech) | 4b (policy) */ +#define RPC_FLVR_POLICY_OFFSET (0) +#define RPC_FLVR_MECH_OFFSET (4) +#define RPC_FLVR_SVC_OFFSET (8) -typedef __u32 ptlrpc_sec_flavor_t; +#define MAKE_RPC_FLVR(policy, mech, svc) \ + (((__u16)(policy) << RPC_FLVR_POLICY_OFFSET) | \ + ((__u16)(mech) << RPC_FLVR_MECH_OFFSET) | \ + ((__u16)(svc) << RPC_FLVR_SVC_OFFSET)) -/* - * 8b (reserved) | 8b (flags) - * 4b (reserved) | 4b (svc) | 4b (mech) | 4b (policy) - */ -#define SEC_FLAVOR_POLICY_OFFSET (0) -#define SEC_FLAVOR_MECH_OFFSET (4) -#define SEC_FLAVOR_SVC_OFFSET (8) -#define SEC_FLAVOR_RESERVE1_OFFSET (12) -#define SEC_FLAVOR_FLAGS_OFFSET (16) - -#define SEC_MAKE_RPC_FLAVOR(policy, mech, svc) \ - (((__u32)(policy) << SEC_FLAVOR_POLICY_OFFSET) | \ - ((__u32)(mech) << SEC_FLAVOR_MECH_OFFSET) | \ - ((__u32)(svc) << SEC_FLAVOR_SVC_OFFSET)) - -#define SEC_MAKE_RPC_SUBFLAVOR(mech, svc) \ - ((__u32)(mech) | \ - ((__u32)(svc) << \ - (SEC_FLAVOR_SVC_OFFSET - SEC_FLAVOR_MECH_OFFSET))) - -#define SEC_FLAVOR_SUB(flavor) \ - ((((__u32)(flavor)) >> SEC_FLAVOR_MECH_OFFSET) & 0xFF) - -#define SEC_FLAVOR_POLICY(flavor) \ - ((((__u32)(flavor)) >> SEC_FLAVOR_POLICY_OFFSET) & 0xF) -#define SEC_FLAVOR_MECH(flavor) \ - ((((__u32)(flavor)) >> SEC_FLAVOR_MECH_OFFSET) & 0xF) -#define SEC_FLAVOR_SVC(flavor) \ - ((((__u32)(flavor)) >> SEC_FLAVOR_SVC_OFFSET) & 0xF) - -#define SEC_FLAVOR_RPC(f) \ - (((__u32) (f)) & ((1 << SEC_FLAVOR_RESERVE1_OFFSET) - 1)) +#define MAKE_RPC_SUBFLVR(mech, svc) \ + ((__u16)(mech) | \ + ((__u16)(svc) << (RPC_FLVR_SVC_OFFSET - RPC_FLVR_MECH_OFFSET))) + +#define RPC_FLVR_SUB(flavor) \ + ((((__u16)(flavor)) >> RPC_FLVR_MECH_OFFSET) & 0xFF) + +#define RPC_FLVR_POLICY(flavor) \ + ((((__u16)(flavor)) >> RPC_FLVR_POLICY_OFFSET) & 0xF) +#define RPC_FLVR_MECH(flavor) \ + ((((__u16)(flavor)) >> RPC_FLVR_MECH_OFFSET) & 0xF) +#define RPC_FLVR_SVC(flavor) \ + ((((__u16)(flavor)) >> RPC_FLVR_SVC_OFFSET) & 0xF) /* * gss subflavors */ -#define SPTLRPC_SUBFLVR_KRB5N \ - SEC_MAKE_RPC_SUBFLAVOR(SPTLRPC_MECH_GSS_KRB5, \ - SPTLRPC_SVC_NULL) -#define SPTLRPC_SUBFLVR_KRB5A \ - SEC_MAKE_RPC_SUBFLAVOR(SPTLRPC_MECH_GSS_KRB5, \ - SPTLRPC_SVC_AUTH) -#define SPTLRPC_SUBFLVR_KRB5I \ - SEC_MAKE_RPC_SUBFLAVOR(SPTLRPC_MECH_GSS_KRB5, \ - SPTLRPC_SVC_INTG) -#define SPTLRPC_SUBFLVR_KRB5P \ - SEC_MAKE_RPC_SUBFLAVOR(SPTLRPC_MECH_GSS_KRB5, \ - SPTLRPC_SVC_PRIV) +#define SPTLRPC_SUBFLVR_KRB5N \ + MAKE_RPC_SUBFLVR(SPTLRPC_MECH_GSS_KRB5, SPTLRPC_SVC_NULL) +#define SPTLRPC_SUBFLVR_KRB5A \ + MAKE_RPC_SUBFLVR(SPTLRPC_MECH_GSS_KRB5, SPTLRPC_SVC_AUTH) +#define SPTLRPC_SUBFLVR_KRB5I \ + MAKE_RPC_SUBFLVR(SPTLRPC_MECH_GSS_KRB5, SPTLRPC_SVC_INTG) +#define SPTLRPC_SUBFLVR_KRB5P \ + MAKE_RPC_SUBFLVR(SPTLRPC_MECH_GSS_KRB5, SPTLRPC_SVC_PRIV) /* * "end user" flavors */ -#define SPTLRPC_FLVR_NULL \ - SEC_MAKE_RPC_FLAVOR(SPTLRPC_POLICY_NULL, \ - SPTLRPC_MECH_NULL, \ - SPTLRPC_SVC_NULL) -#define SPTLRPC_FLVR_PLAIN \ - SEC_MAKE_RPC_FLAVOR(SPTLRPC_POLICY_PLAIN, \ - SPTLRPC_MECH_PLAIN, \ - SPTLRPC_SVC_NULL) -#define SPTLRPC_FLVR_KRB5N \ - SEC_MAKE_RPC_FLAVOR(SPTLRPC_POLICY_GSS, \ - SPTLRPC_MECH_GSS_KRB5, \ - SPTLRPC_SVC_NULL) -#define SPTLRPC_FLVR_KRB5A \ - SEC_MAKE_RPC_FLAVOR(SPTLRPC_POLICY_GSS, \ - SPTLRPC_MECH_GSS_KRB5, \ - SPTLRPC_SVC_AUTH) -#define SPTLRPC_FLVR_KRB5I \ - SEC_MAKE_RPC_FLAVOR(SPTLRPC_POLICY_GSS, \ - SPTLRPC_MECH_GSS_KRB5, \ - SPTLRPC_SVC_INTG) -#define SPTLRPC_FLVR_KRB5P \ - SEC_MAKE_RPC_FLAVOR(SPTLRPC_POLICY_GSS, \ - SPTLRPC_MECH_GSS_KRB5, \ - SPTLRPC_SVC_PRIV) - -#define SPTLRPC_FLVR_INVALID (-1) +#define SPTLRPC_FLVR_NULL \ + MAKE_RPC_FLVR(SPTLRPC_POLICY_NULL, \ + SPTLRPC_MECH_NULL, \ + SPTLRPC_SVC_NULL) +#define SPTLRPC_FLVR_PLAIN \ + MAKE_RPC_FLVR(SPTLRPC_POLICY_PLAIN, \ + SPTLRPC_MECH_PLAIN, \ + SPTLRPC_SVC_NULL) +#define SPTLRPC_FLVR_KRB5N \ + MAKE_RPC_FLVR(SPTLRPC_POLICY_GSS, \ + SPTLRPC_MECH_GSS_KRB5, \ + SPTLRPC_SVC_NULL) +#define SPTLRPC_FLVR_KRB5A \ + MAKE_RPC_FLVR(SPTLRPC_POLICY_GSS, \ + SPTLRPC_MECH_GSS_KRB5, \ + SPTLRPC_SVC_AUTH) +#define SPTLRPC_FLVR_KRB5I \ + MAKE_RPC_FLVR(SPTLRPC_POLICY_GSS, \ + SPTLRPC_MECH_GSS_KRB5, \ + SPTLRPC_SVC_INTG) +#define SPTLRPC_FLVR_KRB5P \ + MAKE_RPC_FLVR(SPTLRPC_POLICY_GSS, \ + SPTLRPC_MECH_GSS_KRB5, \ + SPTLRPC_SVC_PRIV) + +#define SPTLRPC_FLVR_INVALID ((__u16) -1) #define SPTLRPC_FLVR_DEFAULT SPTLRPC_FLVR_NULL /* - * flavor flags (maximum 8 flags) + * 32 bits wire flavor (msg->lm_secflvr), lower 12 bits is the rpc flavor, + * higher 20 bits is not defined right now. */ -#define SEC_FLAVOR_FL_BULK (1 << (0 + SEC_FLAVOR_FLAGS_OFFSET)) -#define SEC_FLAVOR_FL_USER (1 << (1 + SEC_FLAVOR_FLAGS_OFFSET)) +#define WIRE_FLVR_RPC(wflvr) (((__u16) (wflvr)) & 0x0FFF) + +static inline void rpc_flvr_set_svc(__u16 *flvr, __u16 svc) +{ + LASSERT(svc < SPTLRPC_SVC_MAX); + *flvr = MAKE_RPC_FLVR(RPC_FLVR_POLICY(*flvr), + RPC_FLVR_MECH(*flvr), + svc); +} + -#define SEC_FLAVOR_HAS_BULK(flavor) \ - (((flavor) & SEC_FLAVOR_FL_BULK) != 0) -#define SEC_FLAVOR_HAS_USER(flavor) \ - (((flavor) & SEC_FLAVOR_FL_USER) != 0) +struct sptlrpc_flavor { + __u16 sf_rpc; /* rpc flavor */ + __u8 sf_bulk_priv; /* bulk encrypt alg */ + __u8 sf_bulk_csum; /* bulk checksum alg */ + __u32 sf_flags; /* general flags */ +}; +enum lustre_sec_part { + LUSTRE_SP_CLI = 0, + LUSTRE_SP_MDT, + LUSTRE_SP_OST, + LUSTRE_SP_MGS, + LUSTRE_SP_ANY = 0xFF +}; -struct sec_flavor_config { - __u32 sfc_rpc_flavor; /* main rpc flavor */ - __u32 sfc_bulk_priv; /* bulk encryption algorithm */ - __u32 sfc_bulk_csum; /* bulk checksum algorithm */ - __u32 sfc_flags; /* extra flags */ +struct sptlrpc_rule { + __u32 sr_netid; /* LNET network ID */ + __u8 sr_from; /* sec_part */ + __u8 sr_to; /* sec_part */ + __u16 sr_padding; + struct sptlrpc_flavor sr_flvr; }; -enum lustre_part { - LUSTRE_CLI = 0, - LUSTRE_MDT, - LUSTRE_OST, - LUSTRE_MGC, - LUSTRE_MGS, +struct sptlrpc_rule_set { + int srs_nslot; + int srs_nrule; + struct sptlrpc_rule *srs_rules; +}; + +#define SPTLRPC_CONF_LOG_MAX (64) + +struct sptlrpc_conf_log { + __u32 scl_max; /* maximum rules # */ + __u32 scl_nrule; /* rules # */ + __u8 scl_part; /* which part am i */ + __u8 scl_pad0; + __u16 scl_pad1; + __u32 scl_pad2; + struct sptlrpc_rule scl_rules[SPTLRPC_CONF_LOG_MAX]; }; +static inline void sptlrpc_rule_set_init(struct sptlrpc_rule_set *set) +{ + memset(set, 0, sizeof(*set)); +} + +void sptlrpc_rule_set_free(struct sptlrpc_rule_set *set); +int sptlrpc_rule_set_expand(struct sptlrpc_rule_set *set, int expand); +int sptlrpc_rule_set_merge(struct sptlrpc_rule_set *set, + struct sptlrpc_rule *rule, + int expand); +int sptlrpc_rule_set_from_log(struct sptlrpc_rule_set *rset, + struct sptlrpc_conf_log *log); +void sptlrpc_rule_set_choose(struct sptlrpc_rule_set *rset, + enum lustre_sec_part from, + lnet_nid_t nid, + struct sptlrpc_flavor *flavor); +void sptlrpc_rule_set_dump(struct sptlrpc_rule_set *set); + +struct sptlrpc_conf_log *sptlrpc_conf_log_alloc(void); +void sptlrpc_conf_log_free(struct sptlrpc_conf_log *log); +int sptlrpc_conf_log_populate(struct sptlrpc_rule_set *gen, + struct sptlrpc_rule_set *tgt, + enum lustre_sec_part from, + enum lustre_sec_part to, + unsigned int fl_udesc, + struct sptlrpc_conf_log *log); +struct sptlrpc_conf_log *sptlrpc_conf_log_extract(struct lustre_cfg *lcfg); +void sptlrpc_conf_log_cleanup(struct sptlrpc_conf_log *log); +void sptlrpc_conf_log_dump(struct sptlrpc_conf_log *log); + +const char *sptlrpc_part2name(enum lustre_sec_part part); +enum lustre_sec_part sptlrpc_target_sec_part(struct obd_device *obd); + +int sptlrpc_cliobd_process_config(struct obd_device *obd, + struct lustre_cfg *lcfg); + /* The maximum length of security payload. 1024 is enough for Kerberos 5, * and should be enough for other future mechanisms but not sure. * Only used by pre-allocated request/reply pool. @@ -275,11 +325,15 @@ struct ptlrpc_sec_cops { */ struct ptlrpc_sec * (*create_sec) (struct obd_import *imp, struct ptlrpc_svc_ctx *ctx, - __u32 flavor, - unsigned long flags); + struct sptlrpc_flavor *flavor); void (*destroy_sec) (struct ptlrpc_sec *sec); /* + * notify to-be-dead + */ + void (*kill_sec) (struct ptlrpc_sec *sec); + + /* * context */ struct ptlrpc_cli_ctx * (*lookup_ctx) (struct ptlrpc_sec *sec, @@ -324,7 +378,7 @@ struct ptlrpc_sec_cops { * misc */ int (*display) (struct ptlrpc_sec *sec, - char *buf, int buflen); + struct seq_file *seq); }; struct ptlrpc_sec_sops { @@ -350,24 +404,27 @@ struct ptlrpc_sec_sops { struct ptlrpc_sec_policy { struct module *sp_owner; char *sp_name; - __u32 sp_policy; /* policy number */ + __u16 sp_policy; /* policy number */ struct ptlrpc_sec_cops *sp_cops; /* client ops */ struct ptlrpc_sec_sops *sp_sops; /* server ops */ }; #define PTLRPC_SEC_FL_REVERSE 0x0001 /* reverse sec */ #define PTLRPC_SEC_FL_ROOTONLY 0x0002 /* treat everyone as root */ -#define PTLRPC_SEC_FL_PAG 0x0004 /* PAG mode */ +#define PTLRPC_SEC_FL_UDESC 0x0004 /* ship udesc */ #define PTLRPC_SEC_FL_BULK 0x0008 /* intensive bulk i/o expected */ +#define PTLRPC_SEC_FL_PAG 0x0010 /* PAG mode */ struct ptlrpc_sec { struct ptlrpc_sec_policy *ps_policy; atomic_t ps_refcount; - __u32 ps_flavor; /* rpc flavor */ - unsigned long ps_flags; /* PTLRPC_SEC_FL_XX */ + atomic_t ps_nctx; /* statistic only */ + int ps_id; /* unique identifier */ + struct sptlrpc_flavor ps_flvr; /* flavor */ + enum lustre_sec_part ps_part; + unsigned int ps_dying:1; struct obd_import *ps_import; /* owning import */ spinlock_t ps_lock; /* protect ccache */ - atomic_t ps_busy; /* busy count */ /* * garbage collection */ @@ -378,12 +435,12 @@ struct ptlrpc_sec { static inline int sec_is_reverse(struct ptlrpc_sec *sec) { - return (sec->ps_flags & PTLRPC_SEC_FL_REVERSE); + return (sec->ps_flvr.sf_flags & PTLRPC_SEC_FL_REVERSE); } static inline int sec_is_rootonly(struct ptlrpc_sec *sec) { - return (sec->ps_flags & PTLRPC_SEC_FL_ROOTONLY); + return (sec->ps_flvr.sf_flags & PTLRPC_SEC_FL_ROOTONLY); } @@ -429,16 +486,16 @@ enum bulk_encrypt_alg { struct ptlrpc_bulk_sec_desc { __u32 bsd_version; - __u32 bsd_pad; - __u32 bsd_csum_alg; /* checksum algorithm */ - __u32 bsd_priv_alg; /* encrypt algorithm */ + __u8 bsd_csum_alg; /* checksum algorithm */ + __u8 bsd_priv_alg; /* encrypt algorithm */ + __u16 bsd_pad; __u8 bsd_iv[16]; /* encrypt iv */ __u8 bsd_csum[0]; }; -const char * sptlrpc_bulk_csum_alg2name(__u32 csum_alg); -const char * sptlrpc_bulk_priv_alg2name(__u32 priv_alg); -__u32 sptlrpc_bulk_priv_alg2flags(__u32 priv_alg); +const char * sptlrpc_bulk_csum_alg2name(__u8 csum_alg); +const char * sptlrpc_bulk_priv_alg2name(__u8 priv_alg); +__u32 sptlrpc_bulk_priv_alg2flags(__u8 priv_alg); /* * lprocfs @@ -474,8 +531,9 @@ void _sptlrpc_enlarge_msg_inplace(struct lustre_msg *msg, int sptlrpc_register_policy(struct ptlrpc_sec_policy *policy); int sptlrpc_unregister_policy(struct ptlrpc_sec_policy *policy); -__u32 sptlrpc_name2flavor(const char *name); -char *sptlrpc_flavor2name(__u32 flavor); +__u16 sptlrpc_name2rpcflavor(const char *name); +const char *sptlrpc_rpcflavor2name(__u16 flavor); +int sptlrpc_flavor2name(struct sptlrpc_flavor *sf, char *buf, int bufsize); static inline struct ptlrpc_sec_policy *sptlrpc_policy_get(struct ptlrpc_sec_policy *policy) @@ -536,8 +594,15 @@ int cli_ctx_is_eternal(struct ptlrpc_cli_ctx *ctx) } /* + * sec get/put + */ +struct ptlrpc_sec *sptlrpc_sec_get(struct ptlrpc_sec *sec); +void sptlrpc_sec_put(struct ptlrpc_sec *sec); + +/* * internal apis which only used by policy impelentation */ +int sptlrpc_get_next_secid(void); void sptlrpc_sec_destroy(struct ptlrpc_sec *sec); /* @@ -565,10 +630,14 @@ void sptlrpc_request_out_callback(struct ptlrpc_request *req); /* * exported higher interface of import & request */ -int sptlrpc_import_get_sec(struct obd_import *imp, struct ptlrpc_svc_ctx *svc_ctx, - __u32 flavor, unsigned long flags); -void sptlrpc_import_put_sec(struct obd_import *imp); +int sptlrpc_import_sec_adapt(struct obd_import *imp, + struct ptlrpc_svc_ctx *ctx, + __u16 rpc_flavor); +struct ptlrpc_sec *sptlrpc_import_sec_ref(struct obd_import *imp); +void sptlrpc_import_sec_put(struct obd_import *imp); + int sptlrpc_import_check_ctx(struct obd_import *imp); +void sptlrpc_import_inval_all_ctx(struct obd_import *imp); void sptlrpc_import_flush_root_ctx(struct obd_import *imp); void sptlrpc_import_flush_my_ctx(struct obd_import *imp); void sptlrpc_import_flush_all_ctx(struct obd_import *imp); @@ -578,8 +647,7 @@ int sptlrpc_req_refresh_ctx(struct ptlrpc_request *req, long timeout); int sptlrpc_req_replace_dead_ctx(struct ptlrpc_request *req); void sptlrpc_req_set_flavor(struct ptlrpc_request *req, int opcode); -int sptlrpc_parse_flavor(enum lustre_part from, enum lustre_part to, - char *str, struct sec_flavor_config *conf); +int sptlrpc_parse_rule(char *param, struct sptlrpc_rule *rule); /* gc */ void sptlrpc_gc_add_sec(struct ptlrpc_sec *sec); @@ -588,8 +656,7 @@ void sptlrpc_gc_add_ctx(struct ptlrpc_cli_ctx *ctx); /* misc */ const char * sec2target_str(struct ptlrpc_sec *sec); -int sptlrpc_lprocfs_rd(char *page, char **start, off_t off, int count, - int *eof, void *data); +int sptlrpc_lprocfs_cliobd_attach(struct obd_device *dev); /* * server side @@ -600,8 +667,6 @@ enum secsvc_accept_res { SECSVC_DROP, }; -int sptlrpc_target_export_check(struct obd_export *exp, - struct ptlrpc_request *req); int sptlrpc_svc_unwrap_request(struct ptlrpc_request *req); int sptlrpc_svc_alloc_rs(struct ptlrpc_request *req, int msglen); int sptlrpc_svc_wrap_reply(struct ptlrpc_request *req); @@ -610,6 +675,11 @@ void sptlrpc_svc_ctx_addref(struct ptlrpc_request *req); void sptlrpc_svc_ctx_decref(struct ptlrpc_request *req); void sptlrpc_svc_ctx_invalidate(struct ptlrpc_request *req); +int sptlrpc_target_export_check(struct obd_export *exp, + struct ptlrpc_request *req); +void sptlrpc_target_update_exp_flavor(struct obd_device *obd, + struct sptlrpc_rule_set *rset); + /* * reverse context */ @@ -647,7 +717,7 @@ int sptlrpc_pack_user_desc(struct lustre_msg *msg, int offset); int sptlrpc_unpack_user_desc(struct lustre_msg *msg, int offset); /* bulk helpers (internal use only by policies) */ -int bulk_sec_desc_size(__u32 csum_alg, int request, int read); +int bulk_sec_desc_size(__u8 csum_alg, int request, int read); int bulk_sec_desc_unpack(struct lustre_msg *msg, int offset); int bulk_csum_cli_request(struct ptlrpc_bulk_desc *desc, int read, diff --git a/lustre/include/lustre_ucache.h b/lustre/include/lustre_ucache.h index 0cba634..ecfdab8 100644 --- a/lustre/include/lustre_ucache.h +++ b/lustre/include/lustre_ucache.h @@ -29,47 +29,30 @@ struct upcall_cache_entry; -struct mdt_setxid_perm { +struct md_perm { lnet_nid_t mp_nid; __u32 mp_perm; }; -struct mdt_identity { +struct md_identity { struct upcall_cache_entry *mi_uc_entry; uid_t mi_uid; gid_t mi_gid; struct group_info *mi_ginfo; int mi_nperms; - struct mdt_setxid_perm *mi_perms; -}; - -struct rmtacl_upcall_data { - uid_t aud_uid; - gid_t aud_gid; - char *aud_cmd; -}; - -struct mdt_rmtacl { - uid_t ra_uid; - gid_t ra_gid; - __u32 ra_handle; - char *ra_cmd; - char *ra_buf; + struct md_perm *mi_perms; }; struct upcall_cache_entry { struct list_head ue_hash; __u64 ue_key; -// __u64 ue_primary; -// struct group_info *ue_group_info; atomic_t ue_refcount; int ue_flags; cfs_waitq_t ue_waitq; cfs_time_t ue_acquire_expire; cfs_time_t ue_expire; union { - struct mdt_identity identity; - struct mdt_rmtacl acl; + struct md_identity identity; } u; }; diff --git a/lustre/include/md_object.h b/lustre/include/md_object.h index 42fbe90..432cf0d 100644 --- a/lustre/include/md_object.h +++ b/lustre/include/md_object.h @@ -47,20 +47,15 @@ struct md_device_operations; struct md_object; -typedef enum { +enum { UCRED_INVALID = -1, UCRED_INIT = 0, UCRED_OLD = 1, - UCRED_NEW = 2, -} ucred_t; - -#define SQUASH_NONE 0x00 -#define SQUASH_UID 0x01 -#define SQUASH_GID 0x02 + UCRED_NEW = 2 +}; struct md_ucred { - ucred_t mu_valid; - __u32 mu_squash; + __u32 mu_valid; __u32 mu_o_uid; __u32 mu_o_gid; __u32 mu_o_fsuid; @@ -73,7 +68,7 @@ struct md_ucred { __u32 mu_cap; __u32 mu_umask; struct group_info *mu_ginfo; - struct mdt_identity *mu_identity; + struct md_identity *mu_identity; }; #define MD_CAPAINFO_MAX 5 diff --git a/lustre/include/obd.h b/lustre/include/obd.h index 8d6e9f1..1515bab 100644 --- a/lustre/include/obd.h +++ b/lustre/include/obd.h @@ -370,6 +370,10 @@ struct filter_obd { int fo_fmd_max_num; /* per exp filter_mod_data */ int fo_fmd_max_age; /* jiffies to fmd expiry */ + /* sptlrpc stuff */ + rwlock_t fo_sptlrpc_lock; + struct sptlrpc_rule_set fo_sptlrpc_rset; + /* capability related */ unsigned int fo_fl_oss_capa; struct list_head fo_capa_keys; @@ -399,7 +403,8 @@ struct client_obd { int cl_max_mds_cookiesize; /* security configuration */ - struct sec_flavor_config cl_sec_conf; + struct sptlrpc_rule_set cl_sptlrpc_rset; + enum lustre_sec_part cl_sec_part; //struct llog_canceld_ctxt *cl_llcd; /* it's included by obd_llog_ctxt */ void *cl_llcd_offset; @@ -492,15 +497,6 @@ struct mgs_obd { cfs_proc_dir_entry_t *mgs_proc_live; }; -/* hah, upper limit 64 should be enough */ -#define N_NOSQUASH_NIDS 64 -struct rootsquash_info { - uid_t rsi_uid; - gid_t rsi_gid; - int rsi_n_nosquash_nids; - lnet_nid_t rsi_nosquash_nids[N_NOSQUASH_NIDS]; -}; - struct mds_obd { /* NB this field MUST be first */ struct obd_device_target mds_obt; @@ -556,10 +552,6 @@ struct mds_obd { mds_fl_synced:1; struct upcall_cache *mds_identity_cache; - struct upcall_cache *mds_rmtacl_cache; - - /* root squash */ - struct rootsquash_info *mds_rootsquash_info; /* for capability keys update */ struct lustre_capa_key *mds_capa_keys; @@ -1070,7 +1062,8 @@ struct obd_ops { int (*o_connect)(const struct lu_env *env, struct lustre_handle *conn, struct obd_device *src, struct obd_uuid *cluuid, struct obd_connect_data *ocd); - int (*o_reconnect)(struct obd_export *exp, struct obd_device *src, + int (*o_reconnect)(const struct lu_env *env, + struct obd_export *exp, struct obd_device *src, struct obd_uuid *cluuid, struct obd_connect_data *ocd); int (*o_disconnect)(struct obd_export *exp); @@ -1293,7 +1286,7 @@ struct md_ops { struct ptlrpc_request **); int (*m_getattr_name)(struct obd_export *, const struct lu_fid *, struct obd_capa *, const char *, int, obd_valid, - int, struct ptlrpc_request **); + int, __u32, struct ptlrpc_request **); int (*m_intent_lock)(struct obd_export *, struct md_op_data *, void *, int, struct lookup_intent *, int, struct ptlrpc_request **, @@ -1320,7 +1313,7 @@ struct md_ops { int (*m_setxattr)(struct obd_export *, const struct lu_fid *, struct obd_capa *, obd_valid, const char *, - const char *, int, int, int, + const char *, int, int, int, __u32, struct ptlrpc_request **); int (*m_getxattr)(struct obd_export *, const struct lu_fid *, @@ -1355,7 +1348,8 @@ struct md_ops { renew_capa_cb_t cb); int (*m_get_remote_perm)(struct obd_export *, const struct lu_fid *, - struct obd_capa *, struct ptlrpc_request **); + struct obd_capa *, __u32, + struct ptlrpc_request **); /* * NOTE: If adding ops, add another LPROCFS_MD_OP_INIT() line to diff --git a/lustre/include/obd_class.h b/lustre/include/obd_class.h index 3f111f9..94cd618 100644 --- a/lustre/include/obd_class.h +++ b/lustre/include/obd_class.h @@ -814,7 +814,8 @@ static inline int obd_connect(const struct lu_env *env, RETURN(rc); } -static inline int obd_reconnect(struct obd_export *exp, +static inline int obd_reconnect(const struct lu_env *env, + struct obd_export *exp, struct obd_device *obd, struct obd_uuid *cluuid, struct obd_connect_data *d) @@ -831,7 +832,7 @@ static inline int obd_reconnect(struct obd_export *exp, OBD_CHECK_DT_OP(obd, reconnect, 0); OBD_COUNTER_INCREMENT(obd, reconnect); - rc = OBP(obd, reconnect)(exp, obd, cluuid, d); + rc = OBP(obd, reconnect)(env, exp, obd, cluuid, d); /* check that only subset is granted */ LASSERT(ergo(d != NULL, (d->ocd_connect_flags & ocf) == d->ocd_connect_flags)); @@ -1751,7 +1752,7 @@ static inline int md_enqueue(struct obd_export *exp, static inline int md_getattr_name(struct obd_export *exp, const struct lu_fid *fid, struct obd_capa *oc, const char *name, int namelen, - obd_valid valid, int ea_size, + obd_valid valid, int ea_size, __u32 suppgid, struct ptlrpc_request **request) { int rc; @@ -1759,7 +1760,7 @@ static inline int md_getattr_name(struct obd_export *exp, EXP_CHECK_MD_OP(exp, getattr_name); EXP_MD_COUNTER_INCREMENT(exp, getattr_name); rc = MDP(exp->exp_obd, getattr_name)(exp, fid, oc, name, namelen, - valid, ea_size, request); + valid, ea_size, suppgid, request); RETURN(rc); } @@ -1892,7 +1893,7 @@ static inline int md_setxattr(struct obd_export *exp, const struct lu_fid *fid, struct obd_capa *oc, obd_valid valid, const char *name, const char *input, int input_size, - int output_size, int flags, + int output_size, int flags, __u32 suppgid, struct ptlrpc_request **request) { ENTRY; @@ -1900,7 +1901,7 @@ static inline int md_setxattr(struct obd_export *exp, EXP_MD_COUNTER_INCREMENT(exp, setxattr); RETURN(MDP(exp->exp_obd, setxattr)(exp, fid, oc, valid, name, input, input_size, output_size, flags, - request)); + suppgid, request)); } static inline int md_getxattr(struct obd_export *exp, @@ -1988,13 +1989,14 @@ static inline int md_init_ea_size(struct obd_export *exp, int easize, static inline int md_get_remote_perm(struct obd_export *exp, const struct lu_fid *fid, - struct obd_capa *oc, + struct obd_capa *oc, __u32 suppgid, struct ptlrpc_request **request) { ENTRY; EXP_CHECK_MD_OP(exp, get_remote_perm); EXP_MD_COUNTER_INCREMENT(exp, get_remote_perm); - RETURN(MDP(exp->exp_obd, get_remote_perm)(exp, fid, oc, request)); + RETURN(MDP(exp->exp_obd, get_remote_perm)(exp, fid, oc, suppgid, + request)); } static inline int md_renew_capa(struct obd_export *exp, struct obd_capa *ocapa, diff --git a/lustre/kernel_patches/kernel_configs/kernel-2.6.16-2.6-sles10-i686-bigsmp.config b/lustre/kernel_patches/kernel_configs/kernel-2.6.16-2.6-sles10-i686-bigsmp.config index 013ad43..77bc38f 100644 --- a/lustre/kernel_patches/kernel_configs/kernel-2.6.16-2.6-sles10-i686-bigsmp.config +++ b/lustre/kernel_patches/kernel_configs/kernel-2.6.16-2.6-sles10-i686-bigsmp.config @@ -3424,7 +3424,8 @@ CONFIG_X86_MPPARSE=y # # Security options # -# CONFIG_KEYS is not set +CONFIG_KEYS=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y # CONFIG_SECURITY_NETWORK_XFRM is not set diff --git a/lustre/kernel_patches/kernel_configs/kernel-2.6.16-2.6-sles10-i686.config b/lustre/kernel_patches/kernel_configs/kernel-2.6.16-2.6-sles10-i686.config index 3d04f51..2c071b6 100644 --- a/lustre/kernel_patches/kernel_configs/kernel-2.6.16-2.6-sles10-i686.config +++ b/lustre/kernel_patches/kernel_configs/kernel-2.6.16-2.6-sles10-i686.config @@ -3424,7 +3424,8 @@ CONFIG_X86_MPPARSE=y # # Security options # -# CONFIG_KEYS is not set +CONFIG_KEYS=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y # CONFIG_SECURITY_NETWORK_XFRM is not set diff --git a/lustre/kernel_patches/kernel_configs/kernel-2.6.16-2.6-sles10-x86_64-smp.config b/lustre/kernel_patches/kernel_configs/kernel-2.6.16-2.6-sles10-x86_64-smp.config index 7391827..ab3b905 100644 --- a/lustre/kernel_patches/kernel_configs/kernel-2.6.16-2.6-sles10-x86_64-smp.config +++ b/lustre/kernel_patches/kernel_configs/kernel-2.6.16-2.6-sles10-x86_64-smp.config @@ -2997,7 +2997,8 @@ CONFIG_RCU_TORTURE_TEST=m # # Security options # -# CONFIG_KEYS is not set +CONFIG_KEYS=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y # CONFIG_SECURITY_NETWORK_XFRM is not set diff --git a/lustre/kernel_patches/kernel_configs/kernel-2.6.16-2.6-sles10-x86_64.config b/lustre/kernel_patches/kernel_configs/kernel-2.6.16-2.6-sles10-x86_64.config index d5e00e7..d9a018d 100644 --- a/lustre/kernel_patches/kernel_configs/kernel-2.6.16-2.6-sles10-x86_64.config +++ b/lustre/kernel_patches/kernel_configs/kernel-2.6.16-2.6-sles10-x86_64.config @@ -2985,7 +2985,8 @@ CONFIG_RCU_TORTURE_TEST=m # # Security options # -# CONFIG_KEYS is not set +CONFIG_KEYS=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y # CONFIG_SECURITY_NETWORK_XFRM is not set diff --git a/lustre/ldlm/ldlm_lib.c b/lustre/ldlm/ldlm_lib.c index 12ab289..197791e 100644 --- a/lustre/ldlm/ldlm_lib.c +++ b/lustre/ldlm/ldlm_lib.c @@ -180,11 +180,10 @@ out: static void destroy_import(struct obd_import *imp) { /* drop security policy instance after all rpc finished/aborted - * to let all busy credentials be released. - */ + * to let all busy contexts be released. */ class_import_get(imp); class_destroy_import(imp); - sptlrpc_import_put_sec(imp); + sptlrpc_import_sec_put(imp); class_import_put(imp); } @@ -247,10 +246,8 @@ int client_obd_setup(struct obd_device *obddev, struct lustre_cfg *lcfg) sema_init(&cli->cl_sem, 1); sema_init(&cli->cl_mgc_sem, 1); - cli->cl_sec_conf.sfc_rpc_flavor = SPTLRPC_FLVR_NULL; - cli->cl_sec_conf.sfc_bulk_csum = BULK_CSUM_ALG_NULL; - cli->cl_sec_conf.sfc_bulk_priv = BULK_PRIV_ALG_NULL; - cli->cl_sec_conf.sfc_flags = 0; + sptlrpc_rule_set_init(&cli->cl_sptlrpc_rset); + cli->cl_sec_part = LUSTRE_SP_ANY; cli->cl_conn_count = 0; memcpy(server_uuid.uuid, lustre_cfg_buf(lcfg, 2), min_t(unsigned int, LUSTRE_CFG_BUFLEN(lcfg, 2), @@ -359,6 +356,7 @@ err: int client_obd_cleanup(struct obd_device *obddev) { ENTRY; + sptlrpc_rule_set_free(&obddev->u.cli.cl_sptlrpc_rset); ldlm_put_ref(obddev->obd_force); RETURN(0); } @@ -400,11 +398,6 @@ int client_connect_import(const struct lu_env *env, if (rc != 0) GOTO(out_ldlm, rc); - rc = sptlrpc_import_get_sec(imp, NULL, cli->cl_sec_conf.sfc_rpc_flavor, - cli->cl_sec_conf.sfc_flags); - if (rc) - GOTO(out_ldlm, rc); - ocd = &imp->imp_connect_data; if (data) { *ocd = *data; @@ -810,7 +803,8 @@ dont_check_exports: &conn, target, &cluuid, data); } } else { - rc = obd_reconnect(export, target, &cluuid, data); + rc = obd_reconnect(req->rq_svc_thread->t_env, + export, target, &cluuid, data); } if (rc) GOTO(out, rc); @@ -915,6 +909,20 @@ dont_check_exports: /* destroyed import can be still referenced in ctxt */ obd_set_info_async(export, strlen(KEY_REVIMP_UPD), KEY_REVIMP_UPD, 0, NULL, NULL); + + /* in some recovery senarios, previous ctx init rpc handled + * in sptlrpc_target_export_check() might be used to install + * a reverse ctx in this reverse import, and later OBD_CONNECT + * using the same gss ctx could reach here and following new + * reverse import. note all reverse ctx in new/old import are + * actually based on the same gss ctx. so we invalidate ctx + * here before destroy import, otherwise flush old import will + * lead to remote reverse ctx be destroied, thus the reverse + * ctx of new import will lost its peer. + * there might be a better way to deal with this??? + */ + sptlrpc_import_inval_all_ctx(export->exp_imp_reverse); + destroy_import(export->exp_imp_reverse); } @@ -938,8 +946,8 @@ dont_check_exports: lustre_msg_add_op_flags(req->rq_repmsg, MSG_CONNECT_NEXT_VER); } - rc = sptlrpc_import_get_sec(revimp, req->rq_svc_ctx, - req->rq_sec_flavor, 0); + rc = sptlrpc_import_sec_adapt(revimp, req->rq_svc_ctx, + req->rq_flvr.sf_rpc); if (rc) { CERROR("Failed to get sec for reverse import: %d\n", rc); export->exp_imp_reverse = NULL; diff --git a/lustre/ldlm/ldlm_lockd.c b/lustre/ldlm/ldlm_lockd.c index 32a8d69..9e2e644 100644 --- a/lustre/ldlm/ldlm_lockd.c +++ b/lustre/ldlm/ldlm_lockd.c @@ -1412,6 +1412,9 @@ static void ldlm_handle_gl_callback(struct ptlrpc_request *req, static int ldlm_callback_reply(struct ptlrpc_request *req, int rc) { + if (req->rq_no_reply) + return 0; + req->rq_status = rc; if (req->rq_reply_state == NULL) { rc = lustre_pack_reply(req, 1, NULL, NULL); diff --git a/lustre/llite/Makefile.in b/lustre/llite/Makefile.in index 97bba78..5cfb431 100644 --- a/lustre/llite/Makefile.in +++ b/lustre/llite/Makefile.in @@ -1,7 +1,7 @@ MODULES := lustre llite_lloop lustre-objs := dcache.o dir.o file.o llite_close.o llite_lib.o llite_nfs.o lustre-objs += llite_fid.o rw.o lproc_llite.o namei.o symlink.o llite_mmap.o -lustre-objs += xattr.o remote_perm.o llite_capa.o +lustre-objs += xattr.o remote_perm.o llite_rmtacl.o llite_capa.o lustre-objs += rw26.o super25.o llite_lloop-objs := lloop.o diff --git a/lustre/llite/dir.c b/lustre/llite/dir.c index 2afec74..9f5f22a 100644 --- a/lustre/llite/dir.c +++ b/lustre/llite/dir.c @@ -723,7 +723,7 @@ static int ll_dir_ioctl(struct inode *inode, struct file *file, oc = ll_mdscapa_get(inode); rc = md_getattr_name(sbi->ll_md_exp, ll_inode2fid(inode), oc, filename, namelen, OBD_MD_FLID, 0, - &request); + ll_i2suppgid(inode), &request); capa_put(oc); if (rc < 0) { CDEBUG(D_INFO, "md_getattr_name: %d\n", rc); @@ -1119,22 +1119,22 @@ static int ll_dir_ioctl(struct inode *inode, struct file *file, } case LL_IOC_FLUSHCTX: RETURN(ll_flush_ctx(inode)); - case LL_IOC_GETFACL: { - struct rmtacl_ioctl_data ioc; - - if (copy_from_user(&ioc, (void *)arg, sizeof(ioc))) - RETURN(-EFAULT); - - RETURN(ll_ioctl_getfacl(inode, &ioc)); - } - case LL_IOC_SETFACL: { - struct rmtacl_ioctl_data ioc; - - if (copy_from_user(&ioc, (void *)arg, sizeof(ioc))) - RETURN(-EFAULT); +#ifdef CONFIG_FS_POSIX_ACL + case LL_IOC_RMTACL: { + if (sbi->ll_flags & LL_SBI_RMT_CLIENT && + inode == inode->i_sb->s_root->d_inode) { + struct ll_file_data *fd = LUSTRE_FPRIVATE(file); + int rc; - RETURN(ll_ioctl_setfacl(inode, &ioc)); + LASSERT(fd != NULL); + rc = rct_add(&sbi->ll_rct, cfs_curproc_pid(), arg); + if (!rc) + fd->fd_flags |= LL_FILE_RMTACL; + RETURN(rc); + } else + RETURN(0); } +#endif default: RETURN(obd_iocontrol(cmd, sbi->ll_dt_exp,0,NULL,(void *)arg)); } diff --git a/lustre/llite/file.c b/lustre/llite/file.c index 7a83bce..4ce948e 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -286,9 +286,19 @@ int ll_file_release(struct inode *inode, struct file *file) CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p)\n", inode->i_ino, inode->i_generation, inode); - /* don't do anything for / */ - if (inode->i_sb->s_root == file->f_dentry) - RETURN(0); +#ifdef CONFIG_FS_POSIX_ACL + if (sbi->ll_flags & LL_SBI_RMT_CLIENT && + inode == inode->i_sb->s_root->d_inode) { + struct ll_file_data *fd = LUSTRE_FPRIVATE(file); + + LASSERT(fd != NULL); + if (unlikely(fd->fd_flags & LL_FILE_RMTACL)) { + fd->fd_flags &= ~LL_FILE_RMTACL; + rct_del(&sbi->ll_rct, cfs_curproc_pid()); + et_search_free(&sbi->ll_et, cfs_curproc_pid()); + } + } +#endif ll_stats_ops_tally(sbi, LPROC_LL_RELEASE, 1); fd = LUSTRE_FPRIVATE(file); @@ -469,10 +479,6 @@ int ll_file_open(struct inode *inode, struct file *file) CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), flags %o\n", inode->i_ino, inode->i_generation, inode, file->f_flags); - /* don't do anything for / */ - if (inode->i_sb->s_root == file->f_dentry) - RETURN(0); - #ifdef HAVE_VFS_INTENT_PATCHES it = file->f_it; #else @@ -1799,7 +1805,8 @@ int ll_lov_getstripe_ea_info(struct inode *inode, const char *filename, oc = ll_mdscapa_get(inode); rc = md_getattr_name(sbi->ll_md_exp, ll_inode2fid(inode), oc, filename, strlen(filename) + 1, - OBD_MD_FLEASIZE | OBD_MD_FLDIREA, lmmsize, &req); + OBD_MD_FLEASIZE | OBD_MD_FLDIREA, lmmsize, + ll_i2suppgid(inode), &req); capa_put(oc); if (rc < 0) { CDEBUG(D_INFO, "md_getattr_name failed " @@ -2302,22 +2309,6 @@ int ll_file_ioctl(struct inode *inode, struct file *file, unsigned int cmd, */ case LL_IOC_FLUSHCTX: RETURN(ll_flush_ctx(inode)); - case LL_IOC_GETFACL: { - struct rmtacl_ioctl_data ioc; - - if (copy_from_user(&ioc, (void *)arg, sizeof(ioc))) - RETURN(-EFAULT); - - RETURN(ll_ioctl_getfacl(inode, &ioc)); - } - case LL_IOC_SETFACL: { - struct rmtacl_ioctl_data ioc; - - if (copy_from_user(&ioc, (void *)arg, sizeof(ioc))) - RETURN(-EFAULT); - - RETURN(ll_ioctl_setfacl(inode, &ioc)); - } default: { int err; diff --git a/lustre/llite/llite_internal.h b/lustre/llite/llite_internal.h index 6273f68..64022e5 100644 --- a/lustre/llite/llite_internal.h +++ b/lustre/llite/llite_internal.h @@ -11,15 +11,16 @@ # include #ifdef HAVE_XATTR_ACL # include -#endif +#endif /* HAVE_XATTR_ACL */ #ifdef HAVE_LINUX_POSIX_ACL_XATTR_H # include -#endif -#endif +#endif /* HAVE_LINUX_POSIX_ACL_XATTR_H */ +#endif /* CONFIG_FS_POSIX_ACL */ #include #include #include /* for s2sbi */ +#include #ifndef FMODE_EXEC #define FMODE_EXEC 0 @@ -233,6 +234,34 @@ enum stats_track_type { #define LL_SBI_LOCALFLOCK 0x200 /* Local flocks support by kernel */ #define LL_SBI_LRU_RESIZE 0x400 /* lru resize support */ +#define RCE_HASHES 32 + +struct rmtacl_ctl_entry { + struct list_head rce_list; + pid_t rce_key; /* hash key */ + int rce_ops; /* acl operation type */ +}; + +struct rmtacl_ctl_table { + spinlock_t rct_lock; + struct list_head rct_entries[RCE_HASHES]; +}; + +#define EE_HASHES 32 + +struct eacl_entry { + struct list_head ee_list; + pid_t ee_key; /* hash key */ + struct lu_fid ee_fid; + int ee_type; /* ACL type for ACCESS or DEFAULT */ + ext_acl_xattr_header *ee_acl; +}; + +struct eacl_table { + spinlock_t et_lock; + struct list_head et_entries[EE_HASHES]; +}; + struct ll_sb_info { struct list_head ll_list; /* this protects pglist and ra_info. It isn't safe to @@ -285,6 +314,8 @@ struct ll_sb_info { dev_t ll_sdev_orig; /* save s_dev before assign for * clustred nfs */ + struct rmtacl_ctl_table ll_rct; + struct eacl_table ll_et; }; #define LL_DEFAULT_MAX_RW_CHUNK (32 * 1024 * 1024) @@ -392,6 +423,7 @@ struct it_cb_data { obd_id hash; }; +__u32 ll_i2suppgid(struct inode *i); void ll_i2gids(__u32 *suppgids, struct inode *i1,struct inode *i2); #define LLAP_MAGIC 98764321 @@ -601,8 +633,6 @@ struct ll_async_page *llite_pglist_next_llap(struct ll_sb_info *sbi, int ll_obd_statfs(struct inode *inode, void *arg); int ll_get_max_mdsize(struct ll_sb_info *sbi, int *max_mdsize); int ll_process_config(struct lustre_cfg *lcfg); -int ll_ioctl_getfacl(struct inode *inode, struct rmtacl_ioctl_data *ioc); -int ll_ioctl_setfacl(struct inode *inode, struct rmtacl_ioctl_data *ioc); struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data, struct inode *i1, struct inode *i2, const char *name, int namelen, @@ -768,6 +798,25 @@ void ll_truncate_free_capa(struct obd_capa *ocapa); void ll_clear_inode_capas(struct inode *inode); void ll_print_capa_stat(struct ll_sb_info *sbi); +/* llite/llite_rmtacl.c */ +#ifdef CONFIG_FS_POSIX_ACL +obd_valid rce_ops2valid(int ops); +struct rmtacl_ctl_entry *rct_search(struct rmtacl_ctl_table *rct, pid_t key); +int rct_add(struct rmtacl_ctl_table *rct, pid_t key, int ops); +int rct_del(struct rmtacl_ctl_table *rct, pid_t key); +void rct_init(struct rmtacl_ctl_table *rct); +void rct_fini(struct rmtacl_ctl_table *rct); + +void ee_free(struct eacl_entry *ee); +int ee_add(struct eacl_table *et, pid_t key, struct lu_fid *fid, int type, + ext_acl_xattr_header *header); +struct eacl_entry *et_search_del(struct eacl_table *et, pid_t key, + struct lu_fid *fid, int type); +void et_search_free(struct eacl_table *et, pid_t key); +void et_init(struct eacl_table *et); +void et_fini(struct eacl_table *et); +#endif + /* llite ioctl register support rountine */ #ifdef __KERNEL__ enum llioc_iter { diff --git a/lustre/llite/llite_lib.c b/lustre/llite/llite_lib.c index ed8ae79..0f91ebc 100644 --- a/lustre/llite/llite_lib.c +++ b/lustre/llite/llite_lib.c @@ -161,8 +161,7 @@ static int ll_init_ea_size(struct obd_export *md_exp, struct obd_export *dt_exp) RETURN(rc); } -static int client_common_fill_super(struct super_block *sb, char *md, char *dt, - uid_t nllu, gid_t nllg) +static int client_common_fill_super(struct super_block *sb, char *md, char *dt) { struct inode *root = 0; struct ll_sb_info *sbi = ll_s2sbi(sb); @@ -238,8 +237,6 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, data->ocd_connect_flags &= ~OBD_CONNECT_RMT_CLIENT; data->ocd_connect_flags |= OBD_CONNECT_LCL_CLIENT; } - data->ocd_nllu = nllu; - data->ocd_nllg = nllg; err = obd_connect(NULL, &md_conn, obd, &sbi->ll_sb_uuid, data); if (err == -EBUSY) { @@ -487,6 +484,13 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, GOTO(out_root, err); } +#ifdef CONFIG_FS_POSIX_ACL + if (sbi->ll_flags & LL_SBI_RMT_CLIENT) { + rct_init(&sbi->ll_rct); + et_init(&sbi->ll_et); + } +#endif + checksum = sbi->ll_flags & LL_SBI_CHECKSUM; err = obd_set_info_async(sbi->ll_dt_exp, strlen("checksum"),"checksum", sizeof(checksum), &checksum, NULL); @@ -675,6 +679,13 @@ void client_common_put_super(struct super_block *sb) struct ll_sb_info *sbi = ll_s2sbi(sb); ENTRY; +#ifdef CONFIG_FS_POSIX_ACL + if (sbi->ll_flags & LL_SBI_RMT_CLIENT) { + et_fini(&sbi->ll_et); + rct_fini(&sbi->ll_rct); + } +#endif + obd_cancel_unused(sbi->ll_dt_exp, NULL, 0, NULL); ll_close_thread_shutdown(sbi->ll_lcq); @@ -932,9 +943,7 @@ int ll_fill_super(struct super_block *sb) sprintf(md, "%s-%s", lprof->lp_md, ll_instance); /* connections, registrations, sb setup */ - err = client_common_fill_super(sb, md, dt, - lsi->lsi_lmd->lmd_nllu, - lsi->lsi_lmd->lmd_nllg); + err = client_common_fill_super(sb, md, dt); out_free: if (md) @@ -2208,100 +2217,3 @@ void ll_finish_md_op_data(struct md_op_data *op_data) capa_put(op_data->op_capa2); OBD_FREE_PTR(op_data); } - -int ll_ioctl_getfacl(struct inode *inode, struct rmtacl_ioctl_data *ioc) -{ - struct ll_sb_info *sbi = ll_i2sbi(inode); - struct ptlrpc_request *req = NULL; - struct mdt_body *body; - char *cmd, *buf; - struct obd_capa *oc; - int rc, buflen; - ENTRY; - - if (!(sbi->ll_flags & LL_SBI_RMT_CLIENT)) - RETURN(-EBADE); - - LASSERT(ioc->cmd && ioc->cmd_len && ioc->res && ioc->res_len); - - OBD_ALLOC(cmd, ioc->cmd_len); - if (!cmd) - RETURN(-ENOMEM); - if (copy_from_user(cmd, ioc->cmd, ioc->cmd_len)) - GOTO(out, rc = -EFAULT); - - oc = ll_mdscapa_get(inode); - rc = md_getxattr(ll_i2sbi(inode)->ll_md_exp, ll_inode2fid(inode), oc, - OBD_MD_FLXATTR, XATTR_NAME_LUSTRE_ACL, cmd, - ioc->cmd_len, ioc->res_len, 0, &req); - capa_put(oc); - if (rc < 0) { - CERROR("mdc_getxattr %s [%s] failed: %d\n", - XATTR_NAME_LUSTRE_ACL, cmd, rc); - GOTO(out, rc); - } - - body = lustre_msg_buf(req->rq_repmsg, REPLY_REC_OFF, sizeof(*body)); - LASSERT(body); - - buflen = lustre_msg_buflen(req->rq_repmsg, REPLY_REC_OFF); - LASSERT(buflen <= ioc->res_len); - buf = lustre_msg_string(req->rq_repmsg, REPLY_REC_OFF + 1, ioc->res_len); - LASSERT(buf); - if (copy_to_user(ioc->res, buf, buflen)) - GOTO(out, rc = -EFAULT); - EXIT; -out: - if (req) - ptlrpc_req_finished(req); - OBD_FREE(cmd, ioc->cmd_len); - return rc; -} - -int ll_ioctl_setfacl(struct inode *inode, struct rmtacl_ioctl_data *ioc) -{ - struct ll_sb_info *sbi = ll_i2sbi(inode); - struct ptlrpc_request *req = NULL; - char *cmd, *buf; - struct obd_capa *oc; - int buflen, rc; - ENTRY; - - if (!(sbi->ll_flags & LL_SBI_RMT_CLIENT)) - RETURN(-EBADE); - - if (!(sbi->ll_flags & LL_SBI_ACL)) - RETURN(-EOPNOTSUPP); - - LASSERT(ioc->cmd && ioc->cmd_len && ioc->res && ioc->res_len); - - OBD_ALLOC(cmd, ioc->cmd_len); - if (!cmd) - RETURN(-ENOMEM); - if (copy_from_user(cmd, ioc->cmd, ioc->cmd_len)) - GOTO(out, rc = -EFAULT); - - oc = ll_mdscapa_get(inode); - rc = md_setxattr(ll_i2sbi(inode)->ll_md_exp, ll_inode2fid(inode), oc, - OBD_MD_FLXATTR, XATTR_NAME_LUSTRE_ACL, cmd, - ioc->cmd_len, ioc->res_len, 0, &req); - capa_put(oc); - if (rc) { - CERROR("mdc_setxattr %s [%s] failed: %d\n", - XATTR_NAME_LUSTRE_ACL, cmd, rc); - GOTO(out, rc); - } - - buflen = lustre_msg_buflen(req->rq_repmsg, REPLY_REC_OFF); - LASSERT(buflen <= ioc->res_len); - buf = lustre_msg_string(req->rq_repmsg, REPLY_REC_OFF, ioc->res_len); - LASSERT(buf); - if (copy_to_user(ioc->res, buf, buflen)) - GOTO(out, rc = -EFAULT); - EXIT; -out: - if (req) - ptlrpc_req_finished(req); - OBD_FREE(cmd, ioc->cmd_len); - return rc; -} diff --git a/lustre/llite/llite_nfs.c b/lustre/llite/llite_nfs.c index 754e49d..afd0c9b 100644 --- a/lustre/llite/llite_nfs.c +++ b/lustre/llite/llite_nfs.c @@ -213,7 +213,8 @@ static struct dentry *ll_get_parent(struct dentry *dchild) dir->i_ino, PFID(ll_inode2fid(dir))); rc = md_getattr_name(sbi->ll_md_exp, ll_inode2fid(dir), NULL, - dotdot, strlen(dotdot) + 1, 0, 0, &req); + dotdot, strlen(dotdot) + 1, 0, 0, + ll_i2suppgid(dir), &req); if (rc) { CERROR("failure %d inode %lu get parent\n", rc, dir->i_ino); RETURN(ERR_PTR(rc)); diff --git a/lustre/llite/llite_rmtacl.c b/lustre/llite/llite_rmtacl.c new file mode 100644 index 0000000..924092d --- /dev/null +++ b/lustre/llite/llite_rmtacl.c @@ -0,0 +1,283 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * lustre/llite/llite_rmtacl.c + * Lustre Remote User Access Control List. + * Author: Fan Yong + * + * Copyright (c) 2004-2007 Cluster File Systems, Inc. + * + * This file is part of Lustre, http://www.lustre.org. + * + * Lustre is free 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. + * + * 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 + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Lustre; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define DEBUG_SUBSYSTEM S_LLITE + +#ifdef CONFIG_FS_POSIX_ACL + +#include +#include "llite_internal.h" + +static inline __u32 rce_hashfunc(uid_t id) +{ + return id & (RCE_HASHES - 1); +} + +static inline __u32 ee_hashfunc(uid_t id) +{ + return id & (EE_HASHES - 1); +} + +obd_valid rce_ops2valid(int ops) +{ + switch (ops) { + case RMT_LSETFACL: + return OBD_MD_FLRMTLSETFACL; + case RMT_LGETFACL: + return OBD_MD_FLRMTLGETFACL; + case RMT_RSETFACL: + return OBD_MD_FLRMTRSETFACL; + case RMT_RGETFACL: + return OBD_MD_FLRMTRGETFACL; + default: + return 0; + } +} + +static struct rmtacl_ctl_entry *rce_alloc(pid_t key, int ops) +{ + struct rmtacl_ctl_entry *rce; + + OBD_ALLOC_PTR(rce); + if (!rce) + return NULL; + + CFS_INIT_LIST_HEAD(&rce->rce_list); + rce->rce_key = key; + rce->rce_ops = ops; + + return rce; +} + +static void rce_free(struct rmtacl_ctl_entry *rce) +{ + if (!list_empty(&rce->rce_list)) + list_del(&rce->rce_list); + + OBD_FREE_PTR(rce); +} + +static struct rmtacl_ctl_entry *__rct_search(struct rmtacl_ctl_table *rct, + pid_t key) +{ + struct rmtacl_ctl_entry *rce; + struct list_head *head = &rct->rct_entries[rce_hashfunc(key)]; + + list_for_each_entry(rce, head, rce_list) + if (rce->rce_key == key) + return rce; + + return NULL; +} + +struct rmtacl_ctl_entry *rct_search(struct rmtacl_ctl_table *rct, pid_t key) +{ + struct rmtacl_ctl_entry *rce; + + spin_lock(&rct->rct_lock); + rce = __rct_search(rct, key); + spin_unlock(&rct->rct_lock); + return rce; +} + +int rct_add(struct rmtacl_ctl_table *rct, pid_t key, int ops) +{ + struct rmtacl_ctl_entry *rce, *e; + + rce = rce_alloc(key, ops); + if (rce == NULL) + return -ENOMEM; + + spin_lock(&rct->rct_lock); + e = __rct_search(rct, key); + if (unlikely(e != NULL)) { + CWARN("Unexpected stale rmtacl_entry found: " + "[key: %d] [ops: %d]\n", (int)key, ops); + rce_free(e); + } + list_add_tail(&rce->rce_list, &rct->rct_entries[rce_hashfunc(key)]); + spin_unlock(&rct->rct_lock); + + return 0; +} + +int rct_del(struct rmtacl_ctl_table *rct, pid_t key) +{ + struct rmtacl_ctl_entry *rce; + + spin_lock(&rct->rct_lock); + rce = __rct_search(rct, key); + if (rce) + rce_free(rce); + spin_unlock(&rct->rct_lock); + + return rce ? 0 : -ENOENT; +} + +void rct_init(struct rmtacl_ctl_table *rct) +{ + int i; + + spin_lock_init(&rct->rct_lock); + for (i = 0; i < RCE_HASHES; i++) + CFS_INIT_LIST_HEAD(&rct->rct_entries[i]); +} + +void rct_fini(struct rmtacl_ctl_table *rct) +{ + struct rmtacl_ctl_entry *rce; + int i; + + spin_lock(&rct->rct_lock); + for (i = 0; i < RCE_HASHES; i++) + while (!list_empty(&rct->rct_entries[i])) { + rce = list_entry(rct->rct_entries[i].next, + struct rmtacl_ctl_entry, rce_list); + rce_free(rce); + } + spin_unlock(&rct->rct_lock); +} + + +static struct eacl_entry *ee_alloc(pid_t key, struct lu_fid *fid, int type, + ext_acl_xattr_header *header) +{ + struct eacl_entry *ee; + + OBD_ALLOC_PTR(ee); + if (!ee) + return NULL; + + CFS_INIT_LIST_HEAD(&ee->ee_list); + ee->ee_key = key; + ee->ee_fid = *fid; + ee->ee_type = type; + ee->ee_acl = header; + + return ee; +} + +void ee_free(struct eacl_entry *ee) +{ + if (!list_empty(&ee->ee_list)) + list_del(&ee->ee_list); + + if (ee->ee_acl) + lustre_ext_acl_xattr_free(ee->ee_acl); + + OBD_FREE_PTR(ee); +} + +static struct eacl_entry *__et_search_del(struct eacl_table *et, pid_t key, + struct lu_fid *fid, int type) +{ + struct eacl_entry *ee; + struct list_head *head = &et->et_entries[ee_hashfunc(key)]; + + LASSERT(fid != NULL); + list_for_each_entry(ee, head, ee_list) + if (ee->ee_key == key) { + if (lu_fid_eq(&ee->ee_fid, fid) && + ee->ee_type == type) { + list_del_init(&ee->ee_list); + return ee; + } + } + + return NULL; +} + +struct eacl_entry *et_search_del(struct eacl_table *et, pid_t key, + struct lu_fid *fid, int type) +{ + struct eacl_entry *ee; + + spin_lock(&et->et_lock); + ee = __et_search_del(et, key, fid, type); + spin_unlock(&et->et_lock); + return ee; +} + +void et_search_free(struct eacl_table *et, pid_t key) +{ + struct eacl_entry *ee, *next; + struct list_head *head = &et->et_entries[ee_hashfunc(key)]; + + spin_lock(&et->et_lock); + list_for_each_entry_safe(ee, next, head, ee_list) + if (ee->ee_key == key) + ee_free(ee); + + spin_unlock(&et->et_lock); +} + +int ee_add(struct eacl_table *et, pid_t key, struct lu_fid *fid, int type, + ext_acl_xattr_header *header) +{ + struct eacl_entry *ee, *e; + + ee = ee_alloc(key, fid, type, header); + if (ee == NULL) + return -ENOMEM; + + spin_lock(&et->et_lock); + e = __et_search_del(et, key, fid, type); + if (unlikely(e != NULL)) { + CWARN("Unexpected stale eacl_entry found: " + "[key: %d] [fid: "DFID"] [type: %d]\n", + (int)key, PFID(fid), type); + ee_free(e); + } + list_add_tail(&ee->ee_list, &et->et_entries[ee_hashfunc(key)]); + spin_unlock(&et->et_lock); + + return 0; +} + +void et_init(struct eacl_table *et) +{ + int i; + + spin_lock_init(&et->et_lock); + for (i = 0; i < EE_HASHES; i++) + CFS_INIT_LIST_HEAD(&et->et_entries[i]); +} + +void et_fini(struct eacl_table *et) +{ + struct eacl_entry *ee; + int i; + + spin_lock(&et->et_lock); + for (i = 0; i < EE_HASHES; i++) + while (!list_empty(&et->et_entries[i])) { + ee = list_entry(et->et_entries[i].next, + struct eacl_entry, ee_list); + ee_free(ee); + } + spin_unlock(&et->et_lock); +} + +#endif diff --git a/lustre/llite/namei.c b/lustre/llite/namei.c index e6e204a..c4cc5ed 100644 --- a/lustre/llite/namei.c +++ b/lustre/llite/namei.c @@ -214,31 +214,35 @@ int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc, RETURN(0); } +__u32 ll_i2suppgid(struct inode *i) +{ + if (in_group_p(i->i_gid)) + return (__u32)i->i_gid; + else + return (__u32)(-1); +} + /* Pack the required supplementary groups into the supplied groups array. * If we don't need to use the groups from the target inode(s) then we * instead pack one or more groups from the user's supplementary group * array in case it might be useful. Not needed if doing an MDS-side upcall. */ void ll_i2gids(__u32 *suppgids, struct inode *i1, struct inode *i2) { +#if 0 int i; +#endif LASSERT(i1 != NULL); LASSERT(suppgids != NULL); - if (in_group_p(i1->i_gid)) - suppgids[0] = i1->i_gid; - else - suppgids[0] = -1; + suppgids[0] = ll_i2suppgid(i1); - if (i2) { - if (in_group_p(i2->i_gid)) - suppgids[1] = i2->i_gid; + if (i2) + suppgids[1] = ll_i2suppgid(i2); else suppgids[1] = -1; - } else { - suppgids[1] = -1; - } +#if 0 for (i = 0; i < current_ngroups; i++) { if (suppgids[0] == -1) { if (current_groups[i] != suppgids[1]) @@ -252,6 +256,7 @@ void ll_i2gids(__u32 *suppgids, struct inode *i1, struct inode *i2) } break; } +#endif } static void ll_d_add(struct dentry *de, struct inode *inode) diff --git a/lustre/llite/remote_perm.c b/lustre/llite/remote_perm.c index ac0aec0..e87239d 100644 --- a/lustre/llite/remote_perm.c +++ b/lustre/llite/remote_perm.c @@ -263,7 +263,8 @@ check: } oc = ll_mdscapa_get(inode); - rc = md_get_remote_perm(sbi->ll_md_exp, ll_inode2fid(inode), oc, &req); + rc = md_get_remote_perm(sbi->ll_md_exp, ll_inode2fid(inode), oc, + ll_i2suppgid(inode), &req); capa_put(oc); if (rc) { up(&lli->lli_rmtperm_sem); diff --git a/lustre/llite/xattr.c b/lustre/llite/xattr.c index c040923..db1bd85 100644 --- a/lustre/llite/xattr.c +++ b/lustre/llite/xattr.c @@ -79,10 +79,9 @@ int get_xattr_type(const char *name) static int xattr_type_filter(struct ll_sb_info *sbi, int xattr_type) { - if (((xattr_type == XATTR_ACL_ACCESS_T) || - (xattr_type == XATTR_ACL_DEFAULT_T)) && - (!(sbi->ll_flags & LL_SBI_ACL) || - (sbi->ll_flags & LL_SBI_RMT_CLIENT))) + if ((xattr_type == XATTR_ACL_ACCESS_T || + xattr_type == XATTR_ACL_DEFAULT_T) && + !(sbi->ll_flags & LL_SBI_ACL)) return -EOPNOTSUPP; if (xattr_type == XATTR_USER_T && !(sbi->ll_flags & LL_SBI_USER_XATTR)) @@ -104,6 +103,10 @@ int ll_setxattr_common(struct inode *inode, const char *name, struct ptlrpc_request *req; int xattr_type, rc; struct obd_capa *oc; + posix_acl_xattr_header *new_value = NULL; + struct rmtacl_ctl_entry *rce = NULL; + ext_acl_xattr_header *acl = NULL; + const char *pv = value; ENTRY; xattr_type = get_xattr_type(name); @@ -116,10 +119,61 @@ int ll_setxattr_common(struct inode *inode, const char *name, (xattr_type == XATTR_LUSTRE_T && strcmp(name, "lustre.lov") == 0)) RETURN(0); +#ifdef CONFIG_FS_POSIX_ACL + if (sbi->ll_flags & LL_SBI_RMT_CLIENT && + (xattr_type == XATTR_ACL_ACCESS_T || + xattr_type == XATTR_ACL_DEFAULT_T)) { + rce = rct_search(&sbi->ll_rct, cfs_curproc_pid()); + if (rce == NULL || + (rce->rce_ops != RMT_LSETFACL && + rce->rce_ops != RMT_RSETFACL)) + RETURN(-EOPNOTSUPP); + + if (rce->rce_ops == RMT_LSETFACL) { + struct eacl_entry *ee; + + ee = et_search_del(&sbi->ll_et, cfs_curproc_pid(), + ll_inode2fid(inode), xattr_type); + LASSERT(ee != NULL); + if (valid & OBD_MD_FLXATTR) { + acl = lustre_acl_xattr_merge2ext( + (posix_acl_xattr_header *)value, + size, ee->ee_acl); + if (IS_ERR(acl)) { + ee_free(ee); + RETURN(PTR_ERR(acl)); + } + size = CFS_ACL_XATTR_SIZE(\ + le32_to_cpu(acl->a_count), \ + ext_acl_xattr); + pv = (const char *)acl; + } + ee_free(ee); + } else if (rce->rce_ops == RMT_RSETFACL) { + size = lustre_posix_acl_xattr_filter( + (posix_acl_xattr_header *)value, + size, &new_value); + if (unlikely(size < 0)) + RETURN(size); + + pv = (const char *)new_value; + } else + RETURN(-EOPNOTSUPP); + + valid |= rce_ops2valid(rce->rce_ops); + } +#endif oc = ll_mdscapa_get(inode); - rc = md_setxattr(sbi->ll_md_exp, ll_inode2fid(inode), oc, valid, name, - value, size, 0, flags, &req); + rc = md_setxattr(sbi->ll_md_exp, ll_inode2fid(inode), oc, + valid, name, pv, size, 0, flags, ll_i2suppgid(inode), + &req); capa_put(oc); +#ifdef CONFIG_FS_POSIX_ACL + if (new_value != NULL) + lustre_posix_acl_xattr_free(new_value, size); + if (acl != NULL) + lustre_ext_acl_xattr_free(acl); +#endif if (rc) { if (rc == -EOPNOTSUPP && xattr_type == XATTR_USER_T) { LCONSOLE_INFO("Disabling user_xattr feature because " @@ -200,6 +254,7 @@ int ll_getxattr_common(struct inode *inode, const char *name, int xattr_type, rc; void *xdata; struct obd_capa *oc; + struct rmtacl_ctl_entry *rce = NULL; ENTRY; CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p)\n", @@ -219,12 +274,27 @@ int ll_getxattr_common(struct inode *inode, const char *name, if (rc) RETURN(rc); +#ifdef CONFIG_FS_POSIX_ACL + if (sbi->ll_flags & LL_SBI_RMT_CLIENT && + (xattr_type == XATTR_ACL_ACCESS_T || + xattr_type == XATTR_ACL_DEFAULT_T)) { + rce = rct_search(&sbi->ll_rct, cfs_curproc_pid()); + if (rce == NULL || + (rce->rce_ops != RMT_LSETFACL && + rce->rce_ops != RMT_LGETFACL && + rce->rce_ops != RMT_RSETFACL && + rce->rce_ops != RMT_RGETFACL)) + RETURN(-EOPNOTSUPP); + } +#endif + /* posix acl is under protection of LOOKUP lock. when calling to this, * we just have path resolution to the target inode, so we have great * chance that cached ACL is uptodate. */ #ifdef CONFIG_FS_POSIX_ACL - if (xattr_type == XATTR_ACL_ACCESS_T) { + if (xattr_type == XATTR_ACL_ACCESS_T && + !(sbi->ll_flags & LL_SBI_RMT_CLIENT)) { struct ll_inode_info *lli = ll_i2info(inode); struct posix_acl *acl; @@ -243,8 +313,9 @@ int ll_getxattr_common(struct inode *inode, const char *name, do_getxattr: oc = ll_mdscapa_get(inode); - rc = md_getxattr(sbi->ll_md_exp, ll_inode2fid(inode), oc, valid, name, - NULL, 0, size, 0, &req); + rc = md_getxattr(sbi->ll_md_exp, ll_inode2fid(inode), oc, + valid | (rce ? rce_ops2valid(rce->rce_ops) : 0), + name, NULL, 0, size, 0, &req); capa_put(oc); if (rc) { if (rc == -EOPNOTSUPP && xattr_type == XATTR_USER_T) { @@ -285,12 +356,33 @@ do_getxattr: GOTO(out, rc = -EFAULT); } +#ifdef CONFIG_FS_POSIX_ACL + if (body->eadatasize >= 0 && rce && rce->rce_ops == RMT_LSETFACL) { + ext_acl_xattr_header *acl; + + acl = lustre_posix_acl_xattr_2ext((posix_acl_xattr_header *)xdata, + body->eadatasize); + if (IS_ERR(acl)) + GOTO(out, rc = PTR_ERR(acl)); + + rc = ee_add(&sbi->ll_et, cfs_curproc_pid(), ll_inode2fid(inode), + xattr_type, acl); + if (unlikely(rc < 0)) { + lustre_ext_acl_xattr_free(acl); + GOTO(out, rc); + } + } + + if (xattr_type == XATTR_ACL_ACCESS_T && !body->eadatasize) + GOTO(out, rc = -ENODATA); +#endif LASSERT(buffer); memcpy(buffer, xdata, body->eadatasize); rc = body->eadatasize; + EXIT; out: ptlrpc_req_finished(req); - RETURN(rc); + return rc; } ssize_t ll_getxattr(struct dentry *dentry, const char *name, diff --git a/lustre/lmv/lmv_obd.c b/lustre/lmv/lmv_obd.c index 9c6a4db..783f4b6 100644 --- a/lustre/lmv/lmv_obd.c +++ b/lustre/lmv/lmv_obd.c @@ -1128,7 +1128,8 @@ static int lmv_getxattr(struct obd_export *exp, const struct lu_fid *fid, static int lmv_setxattr(struct obd_export *exp, const struct lu_fid *fid, struct obd_capa *oc, obd_valid valid, const char *name, const char *input, int input_size, int output_size, - int flags, struct ptlrpc_request **request) + int flags, __u32 suppgid, + struct ptlrpc_request **request) { struct obd_device *obd = exp->exp_obd; struct lmv_obd *lmv = &obd->u.lmv; @@ -1145,7 +1146,8 @@ static int lmv_setxattr(struct obd_export *exp, const struct lu_fid *fid, RETURN(PTR_ERR(tgt_exp)); rc = md_setxattr(tgt_exp, fid, oc, valid, name, - input, input_size, output_size, flags, request); + input, input_size, output_size, flags, suppgid, + request); RETURN(rc); } @@ -1614,7 +1616,8 @@ lmv_enqueue(struct obd_export *exp, struct ldlm_enqueue_info *einfo, static int lmv_getattr_name(struct obd_export *exp, const struct lu_fid *fid, struct obd_capa *oc, const char *filename, int namelen, - obd_valid valid, int ea_size, struct ptlrpc_request **request) + obd_valid valid, int ea_size, __u32 suppgid, + struct ptlrpc_request **request) { struct obd_device *obd = exp->exp_obd; struct lmv_obd *lmv = &obd->u.lmv; @@ -1654,7 +1657,7 @@ repeat: namelen, filename, PFID(fid), PFID(&rid)); rc = md_getattr_name(tgt_exp, &rid, oc, filename, namelen, valid, - ea_size, request); + ea_size, suppgid, request); if (rc == 0) { body = lustre_msg_buf((*request)->rq_repmsg, REQ_REC_OFF, sizeof(*body)); @@ -1676,7 +1679,7 @@ repeat: rc = md_getattr_name(tgt_exp, &rid, NULL, NULL, 1, valid | OBD_MD_FLCROSSREF, - ea_size, &req); + ea_size, suppgid, &req); ptlrpc_req_finished(*request); *request = req; } @@ -2796,7 +2799,7 @@ int lmv_clear_open_replay_data(struct obd_export *exp, static int lmv_get_remote_perm(struct obd_export *exp, const struct lu_fid *fid, - struct obd_capa *oc, + struct obd_capa *oc, __u32 suppgid, struct ptlrpc_request **request) { struct obd_device *obd = exp->exp_obd; @@ -2814,7 +2817,7 @@ static int lmv_get_remote_perm(struct obd_export *exp, if (IS_ERR(tgt_exp)) RETURN(PTR_ERR(tgt_exp)); - rc = md_get_remote_perm(tgt_exp, fid, oc, request); + rc = md_get_remote_perm(tgt_exp, fid, oc, suppgid, request); RETURN(rc); } diff --git a/lustre/mdc/lproc_mdc.c b/lustre/mdc/lproc_mdc.c index 8ed8c92..bea58ac 100644 --- a/lustre/mdc/lproc_mdc.c +++ b/lustre/mdc/lproc_mdc.c @@ -79,7 +79,6 @@ static struct lprocfs_vars lprocfs_mdc_obd_vars[] = { { "mds_conn_uuid", lprocfs_rd_conn_uuid, 0, 0 }, { "max_rpcs_in_flight", mdc_rd_max_rpcs_in_flight, mdc_wr_max_rpcs_in_flight, 0 }, - { "sptlrpc", sptlrpc_lprocfs_rd, 0, 0 }, { 0 } }; diff --git a/lustre/mdc/mdc_internal.h b/lustre/mdc/mdc_internal.h index 595dfd4..dda6f11 100644 --- a/lustre/mdc/mdc_internal.h +++ b/lustre/mdc/mdc_internal.h @@ -37,7 +37,8 @@ static inline void lprocfs_mdc_init_vars(struct lprocfs_static_vars *lvars) #endif void mdc_pack_req_body(struct ptlrpc_request *req, int offset, __u64 valid, const struct lu_fid *fid, - struct obd_capa *oc, int ea_size, int flags); + struct obd_capa *oc, int ea_size, + __u32 suppgid, int flags); void mdc_pack_capa(struct ptlrpc_request *req, int offset, struct obd_capa *oc); void mdc_pack_rep_body(struct ptlrpc_request *); void mdc_is_subdir_pack(struct ptlrpc_request *req, int offset, diff --git a/lustre/mdc/mdc_lib.c b/lustre/mdc/mdc_lib.c index 8f4cd9e..66e5ad3 100644 --- a/lustre/mdc/mdc_lib.c +++ b/lustre/mdc/mdc_lib.c @@ -38,10 +38,13 @@ #endif #endif -static void mdc_pack_body(struct mdt_body *b) +static void mdc_pack_body(struct mdt_body *b, __u32 suppgid) { LASSERT (b != NULL); + b->suppgid = suppgid; + b->uid = current->uid; + b->gid = current->gid; b->fsuid = current->fsuid; b->fsgid = current->fsgid; b->capability = current->cap_effective; @@ -78,14 +81,15 @@ void mdc_is_subdir_pack(struct ptlrpc_request *req, int offset, void mdc_pack_req_body(struct ptlrpc_request *req, int offset, __u64 valid, const struct lu_fid *fid, - struct obd_capa *oc, int ea_size, int flags) + struct obd_capa *oc, int ea_size, __u32 suppgid, + int flags) { struct mdt_body *b = lustre_msg_buf(req->rq_reqmsg, offset, sizeof(*b)); b->valid = valid; b->eadatasize = ea_size; b->flags = flags; - mdc_pack_body(b); + mdc_pack_body(b, suppgid); if (fid) { b->fid1 = *fid; mdc_pack_capa(req, offset + 1, oc); @@ -100,9 +104,8 @@ void mdc_readdir_pack(struct ptlrpc_request *req, int offset, __u64 pgoff, b = lustre_msg_buf(req->rq_reqmsg, offset, sizeof(*b)); b->fid1 = *fid; b->size = pgoff; /* !! */ - b->suppgid = -1; b->nlink = size; /* !! */ - mdc_pack_body(b); + mdc_pack_body(b, -1); mdc_pack_capa(req, offset + 1, oc); } diff --git a/lustre/mdc/mdc_request.c b/lustre/mdc/mdc_request.c index e9334f9..b72e700 100644 --- a/lustre/mdc/mdc_request.c +++ b/lustre/mdc/mdc_request.c @@ -97,7 +97,7 @@ static int send_getstatus(struct obd_import *imp, struct lu_fid *rootfid, req->rq_send_state = level; ptlrpc_req_set_repsize(req, 3, size); - mdc_pack_req_body(req, REQ_REC_OFF, 0, NULL, NULL, 0, 0); + mdc_pack_req_body(req, REQ_REC_OFF, 0, NULL, NULL, 0, -1, 0); lustre_msg_add_flags(req->rq_reqmsg, msg_flags); rc = ptlrpc_queue_wait(req); @@ -244,7 +244,7 @@ int mdc_getattr(struct obd_export *exp, const struct lu_fid *fid, if (!req) GOTO(out, rc = -ENOMEM); - mdc_pack_req_body(req, REQ_REC_OFF, valid, fid, oc, ea_size, + mdc_pack_req_body(req, REQ_REC_OFF, valid, fid, oc, ea_size, -1, MDS_BFLAG_EXT_FLAGS/*request "new" flags(bug 9486)*/); if (valid & OBD_MD_FLRMTPERM) @@ -267,7 +267,7 @@ int mdc_getattr(struct obd_export *exp, const struct lu_fid *fid, int mdc_getattr_name(struct obd_export *exp, const struct lu_fid *fid, struct obd_capa *oc, const char *filename, int namelen, - obd_valid valid, int ea_size, + obd_valid valid, int ea_size, __u32 suppgid, struct ptlrpc_request **request) { struct ptlrpc_request *req; @@ -283,7 +283,7 @@ int mdc_getattr_name(struct obd_export *exp, const struct lu_fid *fid, if (!req) GOTO(out, rc = -ENOMEM); - mdc_pack_req_body(req, REQ_REC_OFF, valid, fid, oc, ea_size, + mdc_pack_req_body(req, REQ_REC_OFF, valid, fid, oc, ea_size, suppgid, MDS_BFLAG_EXT_FLAGS/*request "new" flags(bug 9486)*/); if (filename) { @@ -342,12 +342,12 @@ int mdc_xattr_common(struct obd_export *exp, const struct lu_fid *fid, struct obd_capa *oc, int opcode, obd_valid valid, const char *xattr_name, const char *input, int input_size, int output_size, - int flags, struct ptlrpc_request **request) + int flags, __u32 suppgid, struct ptlrpc_request **request) { struct ptlrpc_request *req; int size[5] = { sizeof(struct ptlrpc_body), sizeof(struct mdt_body) }; int bufcnt = 3, offset = REQ_REC_OFF + 2; - int rc, xattr_namelen = 0, remote_acl = 0; + int rc, xattr_namelen = 0; void *tmp; ENTRY; @@ -367,14 +367,13 @@ int mdc_xattr_common(struct obd_export *exp, const struct lu_fid *fid, GOTO(out, rc = -ENOMEM); /* request data */ - mdc_pack_req_body(req, REQ_REC_OFF, valid, fid, oc, output_size, flags); + mdc_pack_req_body(req, REQ_REC_OFF, valid, fid, oc, output_size, + suppgid, flags); if (xattr_name) { tmp = lustre_msg_buf(req->rq_reqmsg, offset++, xattr_namelen); memcpy(tmp, xattr_name, xattr_namelen); - if (!strcmp(xattr_name, XATTR_NAME_LUSTRE_ACL)) - remote_acl = 1; } if (input_size) { tmp = lustre_msg_buf(req->rq_reqmsg, offset++, input_size); @@ -394,15 +393,12 @@ int mdc_xattr_common(struct obd_export *exp, const struct lu_fid *fid, ptlrpc_req_set_repsize(req, bufcnt, size); /* make rpc */ - /* NB: set remote acl doesn't need hold rpc lock, because it just - * send command to MDS, and when it's executed on mountpoint on MDS, - * another mdc_xattr_common() will be invoked there. */ - if (opcode == MDS_SETXATTR && !remote_acl) + if (opcode == MDS_SETXATTR) mdc_get_rpc_lock(exp->exp_obd->u.cli.cl_rpc_lock, NULL); rc = ptlrpc_queue_wait(req); - if (opcode == MDS_SETXATTR && !remote_acl) + if (opcode == MDS_SETXATTR) mdc_put_rpc_lock(exp->exp_obd->u.cli.cl_rpc_lock, NULL); if (rc != 0) @@ -428,10 +424,11 @@ err_out: int mdc_setxattr(struct obd_export *exp, const struct lu_fid *fid, struct obd_capa *oc, obd_valid valid, const char *xattr_name, const char *input, int input_size, int output_size, int flags, - struct ptlrpc_request **request) + __u32 suppgid, struct ptlrpc_request **request) { return mdc_xattr_common(exp, fid, oc, MDS_SETXATTR, valid, xattr_name, - input, input_size, output_size, flags, request); + input, input_size, output_size, flags, suppgid, + request); } int mdc_getxattr(struct obd_export *exp, const struct lu_fid *fid, @@ -440,7 +437,8 @@ int mdc_getxattr(struct obd_export *exp, const struct lu_fid *fid, struct ptlrpc_request **request) { return mdc_xattr_common(exp, fid, oc, MDS_GETXATTR, valid, xattr_name, - input, input_size, output_size, flags, request); + input, input_size, output_size, flags, -1, + request); } #ifdef CONFIG_FS_POSIX_ACL @@ -1367,7 +1365,7 @@ int mdc_sync(struct obd_export *exp, const struct lu_fid *fid, if (!req) RETURN(rc = -ENOMEM); - mdc_pack_req_body(req, REQ_REC_OFF, 0, fid, oc, 0, 0); + mdc_pack_req_body(req, REQ_REC_OFF, 0, fid, oc, 0, -1, 0); ptlrpc_req_set_repsize(req, 2, size); @@ -1527,6 +1525,7 @@ static int mdc_setup(struct obd_device *obd, struct lustre_cfg *cfg) GOTO(err_close_lock, rc); lprocfs_mdc_init_vars(&lvars); lprocfs_obd_setup(obd, lvars.obd_vars); + sptlrpc_lprocfs_cliobd_attach(obd); ptlrpc_lprocfs_register_obd(obd); rc = obd_llog_init(obd, NULL, obd, 0, NULL, NULL); @@ -1662,14 +1661,23 @@ static int mdc_process_config(struct obd_device *obd, obd_count len, void *buf) int rc = 0; lprocfs_mdc_init_vars(&lvars); - - rc = class_process_proc_param(PARAM_MDC, lvars.obd_vars, lcfg, obd); + + switch (lcfg->lcfg_command) { + case LCFG_SPTLRPC_CONF: + rc = sptlrpc_cliobd_process_config(obd, lcfg); + break; + default: + rc = class_process_proc_param(PARAM_MDC, lvars.obd_vars, + lcfg, obd); + break; + } return(rc); } /* get remote permission for current user on fid */ int mdc_get_remote_perm(struct obd_export *exp, const struct lu_fid *fid, - struct obd_capa *oc, struct ptlrpc_request **request) + struct obd_capa *oc, __u32 suppgid, + struct ptlrpc_request **request) { struct ptlrpc_request *req; struct mdt_body *body; @@ -1686,7 +1694,8 @@ int mdc_get_remote_perm(struct obd_export *exp, const struct lu_fid *fid, if (!req) RETURN(-ENOMEM); - mdc_pack_req_body(req, REQ_REC_OFF, OBD_MD_FLRMTPERM, fid, oc, 0, 0); + mdc_pack_req_body(req, REQ_REC_OFF, OBD_MD_FLRMTPERM, fid, oc, 0, + suppgid, 0); size[REPLY_REC_OFF + 1] = sizeof(*perm); ptlrpc_req_set_repsize(req, 5, size); @@ -1753,7 +1762,7 @@ static int mdc_renew_capa(struct obd_export *exp, struct obd_capa *oc, RETURN(-ENOMEM); mdc_pack_req_body(req, REQ_REC_OFF, OBD_MD_FLOSSCAPA, - &oc->c_capa.lc_fid, oc, 0, 0); + &oc->c_capa.lc_fid, oc, 0, -1, 0); ptlrpc_req_set_repsize(req, 5, size); req->rq_async_args.pointer_arg[0] = oc; diff --git a/lustre/mdd/mdd_internal.h b/lustre/mdd/mdd_internal.h index 82efb15..a887733 100644 --- a/lustre/mdd/mdd_internal.h +++ b/lustre/mdd/mdd_internal.h @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -301,7 +302,6 @@ static inline int mdd_capable(struct md_ucred *uc, int cap) return 0; } -int mdd_in_group_p(struct md_ucred *uc, gid_t grp); int mdd_acl_def_get(const struct lu_env *env, struct mdd_object *mdd_obj, struct md_attr *ma); int mdd_acl_chmod(const struct lu_env *env, struct mdd_object *o, __u32 mode, diff --git a/lustre/mdd/mdd_object.c b/lustre/mdd/mdd_object.c index c10d4bc..758a1fc 100644 --- a/lustre/mdd/mdd_object.c +++ b/lustre/mdd/mdd_object.c @@ -664,7 +664,7 @@ static int mdd_fix_attr(const struct lu_env *env, struct mdd_object *obj, (tmp_la->la_mode & ~S_IALLUGO); /* Also check the setgid bit! */ - if (!mdd_in_group_p(uc, (la->la_valid & LA_GID) ? la->la_gid : + if (!lustre_in_group_p(uc, (la->la_valid & LA_GID) ? la->la_gid : tmp_la->la_gid) && !mdd_capable(uc, CAP_FSETID)) la->la_mode &= ~S_ISGID; } else { @@ -704,7 +704,7 @@ static int mdd_fix_attr(const struct lu_env *env, struct mdd_object *obj, la->la_gid = tmp_la->la_gid; if (((uc->mu_fsuid != tmp_la->la_uid) || ((la->la_gid != tmp_la->la_gid) && - !mdd_in_group_p(uc, la->la_gid))) && + !lustre_in_group_p(uc, la->la_gid))) && !mdd_capable(uc, CAP_CHOWN)) RETURN(-EPERM); diff --git a/lustre/mdd/mdd_permission.c b/lustre/mdd/mdd_permission.c index a6357f0..1dad3eb 100644 --- a/lustre/mdd/mdd_permission.c +++ b/lustre/mdd/mdd_permission.c @@ -42,167 +42,9 @@ #include #include -#ifdef CONFIG_FS_POSIX_ACL -# include -# include -#endif - #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_identity || - uc->mu_valid == UCRED_OLD) - 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 inline void mdd_acl_le_to_cpu(posix_acl_xattr_entry *p) -{ - p->e_tag = le16_to_cpu(p->e_tag); - p->e_perm = le16_to_cpu(p->e_perm); - p->e_id = le32_to_cpu(p->e_id); -} - -static inline void mdd_acl_cpu_to_le(posix_acl_xattr_entry *p) -{ - p->e_tag = cpu_to_le16(p->e_tag); - p->e_perm = cpu_to_le16(p->e_perm); - p->e_id = cpu_to_le32(p->e_id); -} - -/* - * Check permission based on 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); - - for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) { - mdd_acl_le_to_cpu(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++) { - mdd_acl_le_to_cpu(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); -} /* * Get default acl EA only. @@ -232,54 +74,6 @@ int mdd_acl_def_get(const struct lu_env *env, struct mdd_object *mdd_obj, } /* - * 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; - - for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) { - mdd_acl_le_to_cpu(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; - } - mdd_acl_cpu_to_le(pa); - } - - if (mask_obj) { - mask_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3); - } else { - if (!group_obj) - return -EIO; - group_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3); - } - - return 0; -} - -/* * Hold write_lock for o. */ int mdd_acl_chmod(const struct lu_env *env, struct mdd_object *o, __u32 mode, @@ -310,7 +104,7 @@ int mdd_acl_chmod(const struct lu_env *env, struct mdd_object *o, __u32 mode, if (entry_count <= 0) RETURN(0); - rc = mdd_posix_acl_chmod_masq(entry, mode, entry_count); + rc = lustre_posix_acl_chmod_masq(entry, mode, entry_count); if (rc) RETURN(rc); @@ -320,67 +114,6 @@ int mdd_acl_chmod(const struct lu_env *env, struct mdd_object *o, __u32 mode, } /* - * Modify acl when creating a new obj. - */ -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; - - for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) { - mdd_acl_le_to_cpu(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; - } - mdd_acl_cpu_to_le(pa); - } - - if (mask_obj) { - mask_obj->e_perm = le16_to_cpu(mask_obj->e_perm) & - ((mode >> 3) | ~S_IRWXO); - mode &= (mask_obj->e_perm << 3) | ~S_IRWXG; - mask_obj->e_perm = cpu_to_le16(mask_obj->e_perm); - } else { - if (!group_obj) - return -EIO; - group_obj->e_perm = le16_to_cpu(group_obj->e_perm) & - ((mode >> 3) | ~S_IRWXO); - mode &= (group_obj->e_perm << 3) | ~S_IRWXG; - group_obj->e_perm = cpu_to_le16(group_obj->e_perm); - } - - *mode_p = (*mode_p & ~S_IRWXUGO) | mode; - return not_equiv; -} - -/* * Hold write_lock for obj. */ int __mdd_acl_init(const struct lu_env *env, struct mdd_object *obj, @@ -407,7 +140,7 @@ int __mdd_acl_init(const struct lu_env *env, struct mdd_object *obj, RETURN(rc); } - rc = mdd_posix_acl_create_masq(entry, mode, entry_count); + rc = lustre_posix_acl_create_masq(entry, mode, entry_count); if (rc <= 0) RETURN(rc); @@ -472,7 +205,7 @@ static int mdd_check_acl(const struct lu_env *env, struct mdd_object *obj, entry_count = (buf->lb_len - sizeof(head->a_version)) / sizeof(posix_acl_xattr_entry); - rc = mdd_posix_acl_permission(uc, la, mask, entry, entry_count); + rc = lustre_posix_acl_permission(uc, la, mask, entry, entry_count); RETURN(rc); #else ENTRY; @@ -528,7 +261,7 @@ int __mdd_permission_internal(const struct lu_env *env, struct mdd_object *obj, (rc != -ENODATA)) RETURN(rc); } - if (mdd_in_group_p(uc, la->la_gid)) + if (lustre_in_group_p(uc, la->la_gid)) mode >>= 3; } @@ -554,11 +287,13 @@ int mdd_permission(const struct lu_env *env, struct md_attr *ma, int mask) { struct mdd_object *mdd_pobj, *mdd_cobj; + struct md_ucred *uc = NULL; struct lu_attr *la = NULL; int check_create, check_link; int check_unlink; int check_rename_src, check_rename_tar; int check_vtx_part, check_vtx_full; + int check_rgetfacl; int rc = 0; ENTRY; @@ -584,11 +319,13 @@ int mdd_permission(const struct lu_env *env, check_rename_tar = mask & MAY_RENAME_TAR; check_vtx_part = mask & MAY_VTX_PART; check_vtx_full = mask & MAY_VTX_FULL; + check_rgetfacl = mask & MAY_RGETFACL; mask &= ~(MAY_CREATE | MAY_LINK | MAY_UNLINK | MAY_RENAME_SRC | MAY_RENAME_TAR | - MAY_VTX_PART | MAY_VTX_FULL); + MAY_VTX_PART | MAY_VTX_FULL | + MAY_RGETFACL); rc = mdd_permission_internal_locked(env, mdd_cobj, NULL, mask); @@ -609,8 +346,7 @@ int mdd_permission(const struct lu_env *env, } if (!rc && (check_vtx_part || check_vtx_full)) { - struct md_ucred *uc = md_ucred(env); - + uc = md_ucred(env); LASSERT(ma); if (likely(!la)) { la = &mdd_env_info(env)->mti_la; @@ -630,6 +366,21 @@ int mdd_permission(const struct lu_env *env, } } + if (unlikely(!rc && check_rgetfacl)) { + if (likely(!uc)) + uc = md_ucred(env); + + if (likely(!la)) { + la = &mdd_env_info(env)->mti_la; + rc = mdd_la_get(env, mdd_cobj, la, BYPASS_CAPA); + if (rc) + RETURN(rc); + } + + if (la->la_uid != uc->mu_fsuid && !mdd_capable(uc, CAP_FOWNER)) + rc = -EPERM; + } + RETURN(rc); } diff --git a/lustre/mds/handler.c b/lustre/mds/handler.c index 4e16577..d5f60de 100644 --- a/lustre/mds/handler.c +++ b/lustre/mds/handler.c @@ -289,7 +289,8 @@ static int mds_connect_internal(struct obd_export *exp, return 0; } -static int mds_reconnect(struct obd_export *exp, struct obd_device *obd, +static int mds_reconnect(const struct lu_env *env, + struct obd_export *exp, struct obd_device *obd, struct obd_uuid *cluuid, struct obd_connect_data *data) { @@ -340,6 +341,8 @@ static int mds_connect(const struct lu_env *env, LASSERT(exp); med = &exp->exp_mds_data; + exp->exp_flvr.sf_rpc = SPTLRPC_FLVR_NULL; + rc = mds_connect_internal(exp, data); if (rc) GOTO(out, rc); diff --git a/lustre/mdt/Makefile.in b/lustre/mdt/Makefile.in index cc854bb..e06fd34 100644 --- a/lustre/mdt/Makefile.in +++ b/lustre/mdt/Makefile.in @@ -1,5 +1,5 @@ MODULES := mdt mdt-objs := mdt_handler.o mdt_lib.o mdt_reint.o mdt_xattr.o mdt_recovery.o -mdt-objs += mdt_open.o mdt_idmap.o mdt_identity.o mdt_rmtacl.o mdt_capa.o mdt_lproc.o +mdt-objs += mdt_open.o mdt_idmap.o mdt_identity.o mdt_capa.o mdt_lproc.o @INCLUDE_RULES@ diff --git a/lustre/mdt/mdt_handler.c b/lustre/mdt/mdt_handler.c index 206b5bd..001583f 100644 --- a/lustre/mdt/mdt_handler.c +++ b/lustre/mdt/mdt_handler.c @@ -1347,10 +1347,6 @@ static int mdt_readpage(struct mdt_thread_info *info) if (reqbody == NULL || repbody == NULL) RETURN(err_serious(-EFAULT)); - rc = mdt_check_ucred(info); - if (rc) - RETURN(err_serious(rc)); - /* * prepare @rdpg before calling lower layers and transfer itself. Here * reqbody->size contains offset of where to start to read and @@ -3676,9 +3672,6 @@ static void mdt_fini(const struct lu_env *env, struct mdt_device *m) mdt_fs_cleanup(env, m); - upcall_cache_cleanup(m->mdt_rmtacl_cache); - m->mdt_rmtacl_cache = NULL; - upcall_cache_cleanup(m->mdt_identity_cache); m->mdt_identity_cache = NULL; @@ -3694,10 +3687,7 @@ static void mdt_fini(const struct lu_env *env, struct mdt_device *m) ptlrpc_lprocfs_unregister_obd(d->ld_obd); lprocfs_obd_cleanup(d->ld_obd); - if (m->mdt_rootsquash_info) { - OBD_FREE_PTR(m->mdt_rootsquash_info); - m->mdt_rootsquash_info = NULL; - } + sptlrpc_rule_set_free(&m->mdt_sptlrpc_rset); next->md_ops->mdo_init_capa_ctxt(env, next, 0, 0, 0, NULL); del_timer(&m->mdt_ck_timer); @@ -3781,6 +3771,7 @@ static int mdt_init0(const struct lu_env *env, struct mdt_device *m, struct lustre_mount_info *lmi; struct lustre_sb_info *lsi; struct lu_site *s; + const char *identity_upcall = "NONE"; int rc; ENTRY; @@ -3807,6 +3798,9 @@ static int mdt_init0(const struct lu_env *env, struct mdt_device *m, server_put_mount_2(dev, lmi->lmi_mnt); } + m->mdt_sptlrpc_lock = RW_LOCK_UNLOCKED; + sptlrpc_rule_set_init(&m->mdt_sptlrpc_rset); + spin_lock_init(&m->mdt_ioepoch_lock); m->mdt_opts.mo_compat_resname = 0; m->mdt_capa_timeout = CAPA_TIMEOUT; @@ -3892,8 +3886,12 @@ static int mdt_init0(const struct lu_env *env, struct mdt_device *m, /* set obd_namespace for compatibility with old code */ obd->obd_namespace = m->mdt_namespace; - m->mdt_identity_cache = upcall_cache_init(obd->obd_name, - "NONE", + /* XXX: to support suppgid for ACL, we enable identity_upcall + * by default, otherwise, maybe got unexpected -EACCESS. */ + if (m->mdt_opts.mo_acl) + identity_upcall = MDT_IDENTITY_UPCALL_PATH; + + m->mdt_identity_cache = upcall_cache_init(obd->obd_name, identity_upcall, &mdt_identity_upcall_cache_ops); if (IS_ERR(m->mdt_identity_cache)) { rc = PTR_ERR(m->mdt_identity_cache); @@ -3901,15 +3899,6 @@ static int mdt_init0(const struct lu_env *env, struct mdt_device *m, GOTO(err_free_ns, rc); } - m->mdt_rmtacl_cache = upcall_cache_init(obd->obd_name, - MDT_RMTACL_UPCALL_PATH, - &mdt_rmtacl_upcall_cache_ops); - if (IS_ERR(m->mdt_rmtacl_cache)) { - rc = PTR_ERR(m->mdt_rmtacl_cache); - m->mdt_rmtacl_cache = NULL; - GOTO(err_free_ns, rc); - } - m->mdt_ck_timer.function = mdt_ck_timer_callback; m->mdt_ck_timer.data = (unsigned long)m; init_timer(&m->mdt_ck_timer); @@ -3953,8 +3942,6 @@ err_capa: del_timer(&m->mdt_ck_timer); mdt_ck_thread_stop(m); err_free_ns: - upcall_cache_cleanup(m->mdt_rmtacl_cache); - m->mdt_rmtacl_cache = NULL; upcall_cache_cleanup(m->mdt_identity_cache); m->mdt_identity_cache = NULL; ldlm_namespace_free(m->mdt_namespace, 0); @@ -3988,6 +3975,34 @@ static int mdt_process_config(const struct lu_env *env, ENTRY; switch (cfg->lcfg_command) { + case LCFG_SPTLRPC_CONF: { + struct sptlrpc_conf_log *log; + struct sptlrpc_rule_set tmp_rset; + + log = sptlrpc_conf_log_extract(cfg); + if (IS_ERR(log)) { + rc = PTR_ERR(log); + break; + } + + sptlrpc_rule_set_init(&tmp_rset); + + rc = sptlrpc_rule_set_from_log(&tmp_rset, log); + if (rc) { + CERROR("mdt %p: failed get sptlrpc rules: %d\n", m, rc); + break; + } + + write_lock(&m->mdt_sptlrpc_lock); + sptlrpc_rule_set_free(&m->mdt_sptlrpc_rset); + m->mdt_sptlrpc_rset = tmp_rset; + write_unlock(&m->mdt_sptlrpc_lock); + + sptlrpc_target_update_exp_flavor( + md2lu_dev(&m->mdt_md_dev)->ld_obd, &tmp_rset); + + break; + } case LCFG_PARAM: { struct lprocfs_static_vars lvars; struct obd_device *obd = d->ld_obd; @@ -4173,9 +4188,11 @@ static int mdt_obd_connect(const struct lu_env *env, struct obd_uuid *cluuid, struct obd_connect_data *data) { + struct mdt_thread_info *info; struct mdt_client_data *mcd; struct obd_export *exp; struct mdt_device *mdt; + struct ptlrpc_request *req; int rc; ENTRY; @@ -4183,6 +4200,8 @@ static int mdt_obd_connect(const struct lu_env *env, if (!conn || !obd || !cluuid) RETURN(-EINVAL); + info = lu_context_key_get(&env->le_ctx, &mdt_thread_key); + req = info->mti_pill.rc_req; mdt = mdt_dev(obd->obd_lu_dev); rc = class_connect(conn, obd, cluuid); @@ -4192,6 +4211,26 @@ static int mdt_obd_connect(const struct lu_env *env, exp = class_conn2export(conn); LASSERT(exp != NULL); + CDEBUG(D_SEC, "from %s\n", sptlrpc_part2name(req->rq_sp_from)); + + spin_lock(&exp->exp_lock); + exp->exp_sp_peer = req->rq_sp_from; + + read_lock(&mdt->mdt_sptlrpc_lock); + sptlrpc_rule_set_choose(&mdt->mdt_sptlrpc_rset, exp->exp_sp_peer, + req->rq_peer.nid, &exp->exp_flvr); + read_unlock(&mdt->mdt_sptlrpc_lock); + + if (exp->exp_flvr.sf_rpc != req->rq_flvr.sf_rpc) { + CERROR("invalid rpc flavor %x, expect %x, from %s\n", + req->rq_flvr.sf_rpc, exp->exp_flvr.sf_rpc, + libcfs_nid2str(req->rq_peer.nid)); + exp->exp_flvr.sf_rpc = SPTLRPC_FLVR_INVALID; + spin_unlock(&exp->exp_lock); + RETURN(-EACCES); + } + spin_unlock(&exp->exp_lock); + rc = mdt_connect_internal(exp, mdt, data); if (rc == 0) { OBD_ALLOC_PTR(mcd); @@ -4220,16 +4259,47 @@ static int mdt_obd_connect(const struct lu_env *env, RETURN(rc); } -static int mdt_obd_reconnect(struct obd_export *exp, struct obd_device *obd, +static int mdt_obd_reconnect(const struct lu_env *env, + struct obd_export *exp, struct obd_device *obd, struct obd_uuid *cluuid, struct obd_connect_data *data) { - int rc; + struct mdt_thread_info *info; + struct mdt_device *mdt; + struct ptlrpc_request *req; + int rc; ENTRY; if (exp == NULL || obd == NULL || cluuid == NULL) RETURN(-EINVAL); + info = lu_context_key_get(&env->le_ctx, &mdt_thread_key); + req = info->mti_pill.rc_req; + mdt = mdt_dev(obd->obd_lu_dev); + + CDEBUG(D_SEC, "from %s\n", sptlrpc_part2name(req->rq_sp_from)); + + spin_lock(&exp->exp_lock); + if (exp->exp_flvr.sf_rpc == SPTLRPC_FLVR_INVALID) { + exp->exp_sp_peer = req->rq_sp_from; + + read_lock(&mdt->mdt_sptlrpc_lock); + sptlrpc_rule_set_choose(&mdt->mdt_sptlrpc_rset, + exp->exp_sp_peer, + req->rq_peer.nid, &exp->exp_flvr); + read_unlock(&mdt->mdt_sptlrpc_lock); + + if (exp->exp_flvr.sf_rpc != req->rq_flvr.sf_rpc) { + CERROR("invalid rpc flavor %x, expect %x, from %s\n", + req->rq_flvr.sf_rpc, exp->exp_flvr.sf_rpc, + libcfs_nid2str(req->rq_peer.nid)); + exp->exp_flvr.sf_rpc = SPTLRPC_FLVR_INVALID; + spin_unlock(&exp->exp_lock); + RETURN(-EACCES); + } + } + spin_unlock(&exp->exp_lock); + rc = mdt_connect_internal(exp, mdt_dev(obd->obd_lu_dev), data); RETURN(rc); @@ -4276,6 +4346,8 @@ static int mdt_init_export(struct obd_export *exp) INIT_LIST_HEAD(&med->med_open_head); spin_lock_init(&med->med_open_lock); + sema_init(&med->med_idmap_sem, 1); + med->med_idmap = NULL; spin_lock(&exp->exp_lock); exp->exp_connecting = 1; spin_unlock(&exp->exp_lock); @@ -4775,6 +4847,11 @@ static struct mdt_opc_slice mdt_xmds_handlers[] = { .mos_hs = mdt_obd_ops }, { + .mos_opc_start = SEC_CTX_INIT, + .mos_opc_end = SEC_LAST_OPC, + .mos_hs = mdt_sec_ctx_ops + }, + { .mos_hs = NULL } }; diff --git a/lustre/mdt/mdt_identity.c b/lustre/mdt/mdt_identity.c index f196570..12ed4a8 100644 --- a/lustre/mdt/mdt_identity.c +++ b/lustre/mdt/mdt_identity.c @@ -67,15 +67,18 @@ static void mdt_identity_entry_init(struct upcall_cache_entry *entry, static void mdt_identity_entry_free(struct upcall_cache *cache, struct upcall_cache_entry *entry) { - struct mdt_identity *identity = &entry->u.identity; + struct md_identity *identity = &entry->u.identity; - if (identity->mi_ginfo) + if (identity->mi_ginfo) { groups_free(identity->mi_ginfo); + identity->mi_ginfo = NULL; + } if (identity->mi_nperms) { LASSERT(identity->mi_perms); OBD_FREE(identity->mi_perms, - identity->mi_nperms * sizeof(struct mdt_setxid_perm)); + identity->mi_nperms * sizeof(struct md_perm)); + identity->mi_nperms = 0; } } @@ -120,10 +123,10 @@ static int mdt_identity_parse_downcall(struct upcall_cache *cache, struct upcall_cache_entry *entry, void *args) { - struct mdt_identity *identity = &entry->u.identity; + struct md_identity *identity = &entry->u.identity; struct identity_downcall_data *data = args; struct group_info *ginfo; - struct mdt_setxid_perm *perms = NULL; + struct md_perm *perms = NULL; int size, i; ENTRY; @@ -137,9 +140,8 @@ static int mdt_identity_parse_downcall(struct upcall_cache *cache, RETURN(-ENOMEM); } - groups_from_list(ginfo, data->idd_groups); - groups_sort(ginfo); - identity->mi_ginfo = ginfo; + lustre_groups_from_list(ginfo, data->idd_groups); + lustre_groups_sort(ginfo); if (data->idd_nperms) { size = data->idd_nperms * sizeof(*perms); @@ -147,9 +149,10 @@ static int mdt_identity_parse_downcall(struct upcall_cache *cache, if (!perms) { CERROR("failed to alloc %d permissions\n", data->idd_nperms); - put_group_info(ginfo); + groups_free(ginfo); RETURN(-ENOMEM); } + for (i = 0; i < data->idd_nperms; i++) { perms[i].mp_nid = data->idd_perms[i].pdd_nid; perms[i].mp_perm = data->idd_perms[i].pdd_perm; @@ -169,7 +172,7 @@ static int mdt_identity_parse_downcall(struct upcall_cache *cache, RETURN(0); } -struct mdt_identity *mdt_identity_get(struct upcall_cache *cache, __u32 uid) +struct md_identity *mdt_identity_get(struct upcall_cache *cache, __u32 uid) { struct upcall_cache_entry *entry; @@ -185,7 +188,7 @@ struct mdt_identity *mdt_identity_get(struct upcall_cache *cache, __u32 uid) return &entry->u.identity; } -void mdt_identity_put(struct upcall_cache *cache, struct mdt_identity *identity) +void mdt_identity_put(struct upcall_cache *cache, struct md_identity *identity) { if (!cache) return; @@ -213,12 +216,18 @@ void mdt_flush_identity(struct upcall_cache *cache, int uid) * If there is LNET_NID_ANY in perm[i].mp_nid, * it must be perm[0].mp_nid, and act as default perm. */ -__u32 mdt_identity_get_setxid_perm(struct mdt_identity *identity, +__u32 mdt_identity_get_perm(struct md_identity *identity, __u32 is_rmtclient, lnet_nid_t nid) { - struct mdt_setxid_perm *perm = identity->mi_perms; + struct md_perm *perm; int i; + if (!identity) { + LASSERT(is_rmtclient == 0); + return CFS_SETGRP_PERM; + } + + perm = identity->mi_perms; /* check exactly matched nid first */ for (i = identity->mi_nperms - 1; i > 0; i--) { if (perm[i].mp_nid != nid) @@ -232,7 +241,7 @@ __u32 mdt_identity_get_setxid_perm(struct mdt_identity *identity, return perm[0].mp_perm; /* return default last */ - return is_rmtclient ? 0 : LUSTRE_SETGRP_PERM; + return is_rmtclient ? 0 : CFS_SETGRP_PERM; } int mdt_pack_remote_perm(struct mdt_thread_info *info, struct mdt_object *o, diff --git a/lustre/mdt/mdt_idmap.c b/lustre/mdt/mdt_idmap.c index 567c884..d7d602c 100644 --- a/lustre/mdt/mdt_idmap.c +++ b/lustre/mdt/mdt_idmap.c @@ -27,9 +27,7 @@ #endif #define DEBUG_SUBSYSTEM S_MDS -#ifndef AUTOCONF_INCLUDED #include -#endif #include #include #include @@ -60,63 +58,6 @@ #include "mdt_internal.h" -enum { - MDT_IDMAP_NOTFOUND = -1, -}; - -struct mdt_idmap_entry { - struct list_head mie_rmt_hash; /* hashed as mie_rmt_id; */ - struct list_head mie_lcl_hash; /* hashed as mie_lcl_id; */ - int mie_refcount; - uid_t mie_rmt_id; /* remote uid/gid */ - uid_t mie_lcl_id; /* local uid/gid */ -}; - -/* uid/gid mapping */ -static struct mdt_idmap_table *mdt_idmap_alloc(void) -{ - struct mdt_idmap_table *tbl; - int i, j; - - OBD_ALLOC_PTR(tbl); - if (!tbl) - return NULL; - - spin_lock_init(&tbl->mit_lock); - for (i = 0; i < ARRAY_SIZE(tbl->mit_idmaps); i++) - for (j = 0; j < ARRAY_SIZE(tbl->mit_idmaps[i]); j++) - INIT_LIST_HEAD(&tbl->mit_idmaps[i][j]); - - return tbl; -} - -static struct mdt_idmap_entry *idmap_entry_alloc(__u32 mie_rmt_id, - __u32 mie_lcl_id) -{ - struct mdt_idmap_entry *e; - - OBD_ALLOC_PTR(e); - if (!e) - return NULL; - - INIT_LIST_HEAD(&e->mie_rmt_hash); - INIT_LIST_HEAD(&e->mie_lcl_hash); - e->mie_refcount = 1; - e->mie_rmt_id = mie_rmt_id; - e->mie_lcl_id = mie_lcl_id; - - return e; -} - -static void idmap_entry_free(struct mdt_idmap_entry *e) -{ - if (!list_empty(&e->mie_rmt_hash)) - list_del(&e->mie_rmt_hash); - if (!list_empty(&e->mie_lcl_hash)) - list_del(&e->mie_lcl_hash); - OBD_FREE_PTR(e); -} - int mdt_init_idmap(struct mdt_thread_info *info) { struct ptlrpc_request *req = mdt_info_req(info); @@ -135,7 +76,6 @@ int mdt_init_idmap(struct mdt_thread_info *info) if (!req->rq_auth_gss || req->rq_auth_usr_mdt) { med->med_rmtclient = 0; reply->ocd_connect_flags &= ~OBD_CONNECT_RMT_CLIENT; - //reply->ocd_connect_flags |= OBD_CONNECT_LCL_CLIENT; RETURN(0); } @@ -153,22 +93,31 @@ int mdt_init_idmap(struct mdt_thread_info *info) } if (med->med_rmtclient) { - med->med_nllu = data->ocd_nllu; - med->med_nllg = data->ocd_nllg; + down(&med->med_idmap_sem); if (!med->med_idmap) - med->med_idmap = mdt_idmap_alloc(); - if (!med->med_idmap) { - CERROR("client %s -> target %s failed to alloc idmap!\n" - , client, obd->obd_name); + med->med_idmap = lustre_idmap_init(); + up(&med->med_idmap_sem); + + if (IS_ERR(med->med_idmap)) { + long err = PTR_ERR(med->med_idmap); + + med->med_idmap = NULL; + CERROR("client %s -> target %s " + "failed to init idmap [%ld]!\n", + client, obd->obd_name, err); + RETURN(err); + } else if (!med->med_idmap) { + CERROR("client %s -> target %s " + "failed to init(2) idmap!\n", + client, obd->obd_name); RETURN(-ENOMEM); } reply->ocd_connect_flags &= ~OBD_CONNECT_LCL_CLIENT; - //reply->ocd_connect_flags |= OBD_CONNECT_RMT_CLIENT; CDEBUG(D_SEC, "client %s -> target %s is remote.\n", client, obd->obd_name); - /* NB, MDT_CONNECT establish root idmap too! */ + /* NB, MDS_CONNECT establish root idmap too! */ rc = mdt_handle_idmap(info); } else { if (req->rq_auth_uid == INVALID_UID) { @@ -177,47 +126,21 @@ int mdt_init_idmap(struct mdt_thread_info *info) RETURN(-EACCES); } reply->ocd_connect_flags &= ~OBD_CONNECT_RMT_CLIENT; - //reply->ocd_connect_flags |= OBD_CONNECT_LCL_CLIENT; } RETURN(rc); } -static void idmap_clear_mie_rmt_hash(struct list_head *list) -{ - struct mdt_idmap_entry *e; - int i; - - for (i = 0; i < MDT_IDMAP_HASHSIZE; i++) { - while (!list_empty(&list[i])) { - e = list_entry(list[i].next, struct mdt_idmap_entry, - mie_rmt_hash); - idmap_entry_free(e); - } - } -} - void mdt_cleanup_idmap(struct mdt_export_data *med) { - struct mdt_idmap_table *tbl = med->med_idmap; - int i; - LASSERT(med->med_rmtclient); - LASSERT(tbl); - - spin_lock(&tbl->mit_lock); - idmap_clear_mie_rmt_hash(tbl->mit_idmaps[RMT_UIDMAP_IDX]); - idmap_clear_mie_rmt_hash(tbl->mit_idmaps[RMT_GIDMAP_IDX]); - - /* paranoid checking */ - for (i = 0; i < MDT_IDMAP_HASHSIZE; i++) { - LASSERT(list_empty(&tbl->mit_idmaps[LCL_UIDMAP_IDX][i])); - LASSERT(list_empty(&tbl->mit_idmaps[LCL_GIDMAP_IDX][i])); - } - spin_unlock(&tbl->mit_lock); - OBD_FREE_PTR(tbl); + down(&med->med_idmap_sem); + if (med->med_idmap != NULL) { + lustre_idmap_fini(med->med_idmap); med->med_idmap = NULL; + } + up(&med->med_idmap_sem); } static inline void mdt_revoke_export_locks(struct obd_export *exp) @@ -229,217 +152,15 @@ static inline void mdt_revoke_export_locks(struct obd_export *exp) ldlm_revoke_export_locks(exp); } -static -struct mdt_idmap_entry *idmap_lookup_entry(struct list_head *mie_rmt_hash, - uid_t mie_rmt_id, uid_t mie_lcl_id) -{ - struct list_head *rmt_head = - &mie_rmt_hash[MDT_IDMAP_HASHFUNC(mie_rmt_id)]; - struct mdt_idmap_entry *e; - - list_for_each_entry(e, rmt_head, mie_rmt_hash) { - if ((e->mie_rmt_id == mie_rmt_id) && - (e->mie_lcl_id == mie_lcl_id)) - return e; - } - return NULL; -} - -/* - * return value - * NULL: not found entry - * ERR_PTR(-EACCES): found multi->single mapped entry - * others: found normal entry - */ -static -struct mdt_idmap_entry *idmap_search_entry(struct list_head *mie_rmt_hash, - uid_t mie_rmt_id, - struct list_head *mie_lcl_hash, - uid_t mie_lcl_id, - const char *warn_msg) -{ - struct list_head *rmt_head = - &mie_rmt_hash[MDT_IDMAP_HASHFUNC(mie_rmt_id)]; - struct list_head *lcl_head = - &mie_lcl_hash[MDT_IDMAP_HASHFUNC(mie_lcl_id)]; - struct mdt_idmap_entry *e; - - list_for_each_entry(e, rmt_head, mie_rmt_hash) { - if (e->mie_rmt_id == mie_rmt_id) { - if (e->mie_lcl_id == mie_lcl_id) { - e->mie_refcount++; - return e; - } else { - CERROR("%s: rmt id %u already be mapped to %u" - " (new %u)\n", warn_msg, e->mie_rmt_id, - e->mie_lcl_id, mie_lcl_id); - return ERR_PTR(-EACCES); - } - } - } - - list_for_each_entry(e, lcl_head, mie_lcl_hash) { - if (e->mie_lcl_id == mie_lcl_id) { - if (e->mie_rmt_id == mie_rmt_id) { - e->mie_refcount++; - return e; - } else { - CERROR("%s: lcl id %u already be mapped from %u" - " (new %u)\n", warn_msg, e->mie_lcl_id, - e->mie_rmt_id, mie_rmt_id); - return ERR_PTR(-EACCES); - } - } - } - - return NULL; -} - -static -struct mdt_idmap_entry *idmap_insert_entry(struct list_head *mie_rmt_hash, - struct list_head *mie_lcl_hash, - struct mdt_idmap_entry *new, - const char *warn_msg) -{ - struct list_head *rmt_head = - &mie_rmt_hash[MDT_IDMAP_HASHFUNC(new->mie_rmt_id)]; - struct list_head *lcl_head = - &mie_lcl_hash[MDT_IDMAP_HASHFUNC(new->mie_lcl_id)]; - struct mdt_idmap_entry *e; - - e = idmap_search_entry(mie_rmt_hash, new->mie_rmt_id, - mie_lcl_hash, new->mie_lcl_id, - warn_msg); - if (e == NULL) { - list_add_tail(&new->mie_rmt_hash, rmt_head); - list_add_tail(&new->mie_lcl_hash, lcl_head); - } - return e; -} - -static int idmap_remove_entry(struct list_head *mie_rmt_hash, - struct list_head *mie_lcl_hash, - __u32 mie_rmt_id, __u32 mie_lcl_id) -{ - struct mdt_idmap_entry *e; - int rc = -ENOENT; - - e = idmap_lookup_entry(mie_rmt_hash, mie_rmt_id, mie_lcl_id); - if (e != NULL) { - e->mie_refcount--; - if ((rc = e->mie_refcount) <= 0) - idmap_entry_free(e); - } - return rc; -} - -static int mdt_idmap_add(struct mdt_idmap_table *tbl, - uid_t ruid, uid_t luid, - gid_t rgid, gid_t lgid) -{ - struct mdt_idmap_entry *ue0, *ue1, *ge0, *ge1; - ENTRY; - - LASSERT(tbl); - - spin_lock(&tbl->mit_lock); - ue0 = idmap_search_entry(tbl->mit_idmaps[RMT_UIDMAP_IDX], ruid, - tbl->mit_idmaps[LCL_UIDMAP_IDX], luid, - "UID mapping"); - spin_unlock(&tbl->mit_lock); - if (!ue0) { - ue0 = idmap_entry_alloc(ruid, luid); - if (!ue0) - RETURN(-ENOMEM); - - spin_lock(&tbl->mit_lock); - ue1 = idmap_insert_entry(tbl->mit_idmaps[RMT_UIDMAP_IDX], - tbl->mit_idmaps[LCL_UIDMAP_IDX], - ue0, "UID mapping"); - if (ue1 != NULL) { - idmap_entry_free(ue0); - ue0 = ue1; - } - spin_unlock(&tbl->mit_lock); - - if (IS_ERR(ue1)) - RETURN(PTR_ERR(ue1)); - } else if (IS_ERR(ue0)) { - RETURN(PTR_ERR(ue0)); - } - - spin_lock(&tbl->mit_lock); - ge0 = idmap_search_entry(tbl->mit_idmaps[RMT_GIDMAP_IDX], rgid, - tbl->mit_idmaps[LCL_GIDMAP_IDX], lgid, - "GID mapping"); - spin_unlock(&tbl->mit_lock); - if (!ge0) { - ge0 = idmap_entry_alloc(rgid, lgid); - spin_lock(&tbl->mit_lock); - if (!ge0) { - ue0->mie_refcount--; - if (ue0->mie_refcount <= 0) - idmap_entry_free(ue0); - spin_unlock(&tbl->mit_lock); - RETURN(-ENOMEM); - } - - ge1 = idmap_insert_entry(tbl->mit_idmaps[RMT_GIDMAP_IDX], - tbl->mit_idmaps[LCL_GIDMAP_IDX], - ge0, "GID mapping"); - if (ge1 != NULL) { - ue0->mie_refcount--; - if (ue0->mie_refcount <= 0) - idmap_entry_free(ue0); - idmap_entry_free(ge0); - } - spin_unlock(&tbl->mit_lock); - - if (IS_ERR(ge1)) - RETURN(PTR_ERR(ge1)); - } else if (IS_ERR(ge0)) { - spin_lock(&tbl->mit_lock); - ue0->mie_refcount--; - if (ue0->mie_refcount <= 0) - idmap_entry_free(ue0); - spin_unlock(&tbl->mit_lock); - RETURN(PTR_ERR(ge0)); - } - - RETURN(0); -} - -static int mdt_idmap_del(struct mdt_idmap_table *tbl, - uid_t ruid, uid_t luid, - gid_t rgid, gid_t lgid) -{ - ENTRY; - - if (!tbl) - RETURN(0); - - spin_lock(&tbl->mit_lock); - idmap_remove_entry(tbl->mit_idmaps[RMT_UIDMAP_IDX], - tbl->mit_idmaps[LCL_UIDMAP_IDX], - ruid, luid); - idmap_remove_entry(tbl->mit_idmaps[RMT_GIDMAP_IDX], - tbl->mit_idmaps[LCL_GIDMAP_IDX], - rgid, lgid); - spin_unlock(&tbl->mit_lock); - - RETURN(0); -} - int mdt_handle_idmap(struct mdt_thread_info *info) { struct ptlrpc_request *req = mdt_info_req(info); struct mdt_device *mdt = info->mti_mdt; struct mdt_export_data *med; struct ptlrpc_user_desc *pud = req->rq_user_desc; - struct mdt_identity *identity; + struct md_identity *identity; __u32 opc; int rc = 0; - ENTRY; if (!req->rq_export) @@ -455,9 +176,13 @@ int mdt_handle_idmap(struct mdt_thread_info *info) (opc != SEC_CTX_FINI) && (opc != MDS_CONNECT)) RETURN(0); - LASSERT(pud); LASSERT(med->med_idmap); + if (unlikely(!pud)) { + CERROR("remote client must run with rq_user_desc present\n"); + RETURN(-EACCES); + } + if (req->rq_auth_mapped_uid == INVALID_UID) { CERROR("invalid authorized mapped uid, please check " "/etc/lustre/idmap.conf!\n"); @@ -481,12 +206,12 @@ int mdt_handle_idmap(struct mdt_thread_info *info) case SEC_CTX_INIT: case SEC_CTX_INIT_CONT: case MDS_CONNECT: - rc = mdt_idmap_add(med->med_idmap, + rc = lustre_idmap_add(med->med_idmap, pud->pud_uid, identity->mi_uid, pud->pud_gid, identity->mi_gid); break; case SEC_CTX_FINI: - rc = mdt_idmap_del(med->med_idmap, + rc = lustre_idmap_del(med->med_idmap, pud->pud_uid, identity->mi_uid, pud->pud_gid, identity->mi_gid); break; @@ -504,67 +229,15 @@ int mdt_handle_idmap(struct mdt_thread_info *info) mdt_revoke_export_locks(req->rq_export); break; } - RETURN(0); -} - -static __u32 idmap_lookup_id(struct list_head *hash, int reverse, __u32 id) -{ - struct list_head *head = &hash[MDT_IDMAP_HASHFUNC(id)]; - struct mdt_idmap_entry *e; - - if (!reverse) { - list_for_each_entry(e, head, mie_rmt_hash) { - if (e->mie_rmt_id == id) - return e->mie_lcl_id; - } - } else { - list_for_each_entry(e, head, mie_lcl_hash) { - if (e->mie_lcl_id == id) - return e->mie_rmt_id; - } - } - return MDT_IDMAP_NOTFOUND; -} - -static int mdt_idmap_lookup_uid(struct mdt_idmap_table *tbl, int reverse, - uid_t uid) -{ - struct list_head *hash; - - if (!tbl) - return MDT_IDMAP_NOTFOUND; - - hash = tbl->mit_idmaps[reverse ? LCL_UIDMAP_IDX : RMT_UIDMAP_IDX]; - - spin_lock(&tbl->mit_lock); - uid = idmap_lookup_id(hash, reverse, uid); - spin_unlock(&tbl->mit_lock); - - return uid; -} - -static int mdt_idmap_lookup_gid(struct mdt_idmap_table *tbl, int reverse, - gid_t gid) -{ - struct list_head *hash; - - if (!tbl) - return MDT_IDMAP_NOTFOUND; - - hash = tbl->mit_idmaps[reverse ? LCL_GIDMAP_IDX : RMT_GIDMAP_IDX]; - - spin_lock(&tbl->mit_lock); - gid = idmap_lookup_id(hash, reverse, gid); - spin_unlock(&tbl->mit_lock); - return gid; + RETURN(0); } int ptlrpc_user_desc_do_idmap(struct ptlrpc_request *req, struct ptlrpc_user_desc *pud) { struct mdt_export_data *med = mdt_req2med(req); - struct mdt_idmap_table *idmap = med->med_idmap; + struct lustre_idmap_table *idmap = med->med_idmap; uid_t uid, fsuid; gid_t gid, fsgid; @@ -572,8 +245,8 @@ int ptlrpc_user_desc_do_idmap(struct ptlrpc_request *req, if (!med->med_rmtclient) return 0; - uid = mdt_idmap_lookup_uid(idmap, 0, pud->pud_uid); - if (uid == MDT_IDMAP_NOTFOUND) { + uid = lustre_idmap_lookup_uid(NULL, idmap, 0, pud->pud_uid); + if (uid == CFS_IDMAP_NOTFOUND) { CERROR("no mapping for uid %u\n", pud->pud_uid); return -EACCES; } @@ -581,15 +254,15 @@ int ptlrpc_user_desc_do_idmap(struct ptlrpc_request *req, if (pud->pud_uid == pud->pud_fsuid) { fsuid = uid; } else { - fsuid = mdt_idmap_lookup_uid(idmap, 0, pud->pud_fsuid); - if (fsuid == MDT_IDMAP_NOTFOUND) { + fsuid = lustre_idmap_lookup_uid(NULL, idmap, 0, pud->pud_fsuid); + if (fsuid == CFS_IDMAP_NOTFOUND) { CERROR("no mapping for fsuid %u\n", pud->pud_fsuid); return -EACCES; } } - gid = mdt_idmap_lookup_gid(idmap, 0, pud->pud_gid); - if (gid == MDT_IDMAP_NOTFOUND) { + gid = lustre_idmap_lookup_gid(NULL, idmap, 0, pud->pud_gid); + if (gid == CFS_IDMAP_NOTFOUND) { CERROR("no mapping for gid %u\n", pud->pud_gid); return -EACCES; } @@ -597,8 +270,8 @@ int ptlrpc_user_desc_do_idmap(struct ptlrpc_request *req, if (pud->pud_gid == pud->pud_fsgid) { fsgid = gid; } else { - fsgid = mdt_idmap_lookup_gid(idmap, 0, pud->pud_fsgid); - if (fsgid == MDT_IDMAP_NOTFOUND) { + fsgid = lustre_idmap_lookup_gid(NULL, idmap, 0, pud->pud_fsgid); + if (fsgid == CFS_IDMAP_NOTFOUND) { CERROR("no mapping for fsgid %u\n", pud->pud_fsgid); return -EACCES; } @@ -613,37 +286,23 @@ int ptlrpc_user_desc_do_idmap(struct ptlrpc_request *req, } /* - * Reverse map - * Do not ignore rootsquash. + * Reverse mapping */ void mdt_body_reverse_idmap(struct mdt_thread_info *info, struct mdt_body *body) { struct ptlrpc_request *req = mdt_info_req(info); struct md_ucred *uc = mdt_ucred(info); struct mdt_export_data *med = mdt_req2med(req); - struct mdt_idmap_table *idmap = med->med_idmap; - uid_t uid; - gid_t gid; + struct lustre_idmap_table *idmap = med->med_idmap; if (!med->med_rmtclient) return; if (body->valid & OBD_MD_FLUID) { - if (((uc->mu_valid == UCRED_OLD) || - (uc->mu_valid == UCRED_NEW)) && - !(uc->mu_squash & SQUASH_UID)) { - if (body->uid == uc->mu_uid) - uid = uc->mu_o_uid; - else if (body->uid == uc->mu_fsuid) - uid = uc->mu_o_fsuid; - else - uid = mdt_idmap_lookup_uid(idmap, 1, body->uid); - } else { - uid = mdt_idmap_lookup_uid(idmap, 1, body->uid); - } + uid_t uid = lustre_idmap_lookup_uid(uc, idmap, 1, body->uid); - if (uid == MDT_IDMAP_NOTFOUND) { - uid = med->med_nllu; + if (uid == CFS_IDMAP_NOTFOUND) { + uid = NOBODY_UID; if (body->valid & OBD_MD_FLMODE) body->mode = (body->mode & ~S_IRWXU) | ((body->mode & S_IRWXO) << 6); @@ -653,21 +312,10 @@ void mdt_body_reverse_idmap(struct mdt_thread_info *info, struct mdt_body *body) } if (body->valid & OBD_MD_FLGID) { - if (((uc->mu_valid == UCRED_OLD) || - (uc->mu_valid == UCRED_NEW)) && - !(uc->mu_squash & SQUASH_GID)) { - if (body->gid == uc->mu_gid) - gid = uc->mu_o_gid; - else if (body->gid == uc->mu_fsgid) - gid = uc->mu_o_fsgid; - else - gid = mdt_idmap_lookup_gid(idmap, 1, body->gid); - } else { - gid = mdt_idmap_lookup_gid(idmap, 1, body->gid); - } + gid_t gid = lustre_idmap_lookup_gid(uc, idmap, 1, body->gid); - if (gid == MDT_IDMAP_NOTFOUND) { - gid = med->med_nllg; + if (gid == CFS_IDMAP_NOTFOUND) { + gid = NOBODY_GID; if (body->valid & OBD_MD_FLMODE) body->mode = (body->mode & ~S_IRWXG) | ((body->mode & S_IRWXO) << 3); @@ -677,124 +325,50 @@ void mdt_body_reverse_idmap(struct mdt_thread_info *info, struct mdt_body *body) } } -/* NB: return error if no mapping, so this will look strange: - * if client hasn't kinit the to map xid for the mapped xid, client - * will always get -EPERM, and the same for rootsquash case. */ -int mdt_remote_perm_reverse_idmap(struct ptlrpc_request *req, - struct mdt_remote_perm *perm) -{ - struct mdt_export_data *med = mdt_req2med(req); - uid_t uid, fsuid; - gid_t gid, fsgid; - - LASSERT(med->med_rmtclient); - - uid = mdt_idmap_lookup_uid(med->med_idmap, 1, perm->rp_uid); - if (uid == MDT_IDMAP_NOTFOUND) { - CERROR("no mapping for uid %u\n", perm->rp_uid); - return -EPERM; - } - - gid = mdt_idmap_lookup_gid(med->med_idmap, 1, perm->rp_gid); - if (gid == MDT_IDMAP_NOTFOUND) { - CERROR("no mapping for gid %u\n", perm->rp_gid); - return -EPERM; - } - - if (perm->rp_uid != perm->rp_fsuid) { - fsuid = mdt_idmap_lookup_uid(med->med_idmap, 1, perm->rp_fsuid); - if (fsuid == MDT_IDMAP_NOTFOUND) { - CERROR("no mapping for fsuid %u\n", perm->rp_fsuid); - return -EPERM; - } - } else { - fsuid = uid; - } - - if (perm->rp_gid != perm->rp_fsgid) { - fsgid = mdt_idmap_lookup_gid(med->med_idmap, 1, perm->rp_fsgid); - if (fsgid == MDT_IDMAP_NOTFOUND) { - CERROR("no mapping for fsgid %u\n", perm->rp_fsgid); - return -EPERM; - } - } else { - fsgid = gid; - } - - perm->rp_uid = uid; - perm->rp_gid = gid; - perm->rp_fsuid = fsuid; - perm->rp_fsgid = fsgid; - return 0; -} - -/* Process remote client and rootsquash */ +/* Do not ignore root_squash for non-setattr case. */ int mdt_fix_attr_ucred(struct mdt_thread_info *info, __u32 op) { struct ptlrpc_request *req = mdt_info_req(info); struct md_ucred *uc = mdt_ucred(info); struct lu_attr *attr = &info->mti_attr.ma_attr; struct mdt_export_data *med = mdt_req2med(req); - struct mdt_idmap_table *idmap = med->med_idmap; - - ENTRY; + struct lustre_idmap_table *idmap = med->med_idmap; if ((uc->mu_valid != UCRED_OLD) && (uc->mu_valid != UCRED_NEW)) - RETURN(-EINVAL); - - if (!med->med_rmtclient && (uc->mu_squash == SQUASH_NONE)) - RETURN(0); + return -EINVAL; if (op != REINT_SETATTR) { if ((attr->la_valid & LA_UID) && (attr->la_uid != -1)) attr->la_uid = uc->mu_fsuid; - if (op != REINT_CREATE) { + /* for S_ISGID, inherit gid from his parent, such work will be + * done in cmm/mdd layer, here set all cases as uc->mu_fsgid. */ if ((attr->la_valid & LA_GID) && (attr->la_gid != -1)) attr->la_gid = uc->mu_fsgid; - } else { - /* for S_ISGID, inherit gid from his parent */ - if (!(attr->la_mode & S_ISGID) && (attr->la_gid != -1)) - attr->la_gid = uc->mu_fsgid; - } } else if (med->med_rmtclient) { /* NB: -1 case will be handled by mdt_fix_attr() later. */ if ((attr->la_valid & LA_UID) && (attr->la_uid != -1)) { - uid_t uid; - - if (attr->la_uid == uc->mu_o_uid) - uid = uc->mu_uid; - else if (attr->la_uid == uc->mu_o_fsuid) - uid = uc->mu_fsuid; - else - uid = mdt_idmap_lookup_uid(idmap, 0, + uid_t uid = lustre_idmap_lookup_uid(uc, idmap, 0, attr->la_uid); - if (uid == MDT_IDMAP_NOTFOUND) { + if (uid == CFS_IDMAP_NOTFOUND) { CWARN("Deny chown to uid %u\n", attr->la_uid); - RETURN(-EPERM); + return -EPERM; } attr->la_uid = uid; } if ((attr->la_valid & LA_GID) && (attr->la_gid != -1)) { - gid_t gid; - - if (attr->la_gid == uc->mu_o_gid) - gid = uc->mu_gid; - else if (attr->la_gid == uc->mu_o_fsgid) - gid = uc->mu_fsgid; - else - gid = mdt_idmap_lookup_gid(idmap, 0, + gid_t gid = lustre_idmap_lookup_gid(uc, idmap, 0, attr->la_gid); - if (gid == MDT_IDMAP_NOTFOUND) { + if (gid == CFS_IDMAP_NOTFOUND) { CWARN("Deny chown to gid %u\n", attr->la_gid); - RETURN(-EPERM); + return -EPERM; } attr->la_gid = gid; } } - RETURN(0); + return 0; } diff --git a/lustre/mdt/mdt_internal.h b/lustre/mdt/mdt_internal.h index 4ff1b1e..1745876 100644 --- a/lustre/mdt/mdt_internal.h +++ b/lustre/mdt/mdt_internal.h @@ -55,6 +55,8 @@ #include #include #include +#include +#include /* Data stored per client in the last_rcvd file. In le32 order. */ @@ -177,10 +179,10 @@ struct mdt_device { unsigned long mdt_client_bitmap[(LR_MAX_CLIENTS >> 3) / sizeof(long)]; struct upcall_cache *mdt_identity_cache; - struct upcall_cache *mdt_rmtacl_cache; - /* root squash */ - struct rootsquash_info *mdt_rootsquash_info; + /* sptlrpc rules */ + rwlock_t mdt_sptlrpc_lock; + struct sptlrpc_rule_set mdt_sptlrpc_rset; /* capability keys */ unsigned long mdt_capa_timeout; @@ -599,17 +601,10 @@ const struct lu_buf *mdt_buf_const(const struct lu_env *env, void mdt_dump_lmm(int level, const struct lov_mds_md *lmm); int mdt_check_ucred(struct mdt_thread_info *); - int mdt_init_ucred(struct mdt_thread_info *, struct mdt_body *); - int mdt_init_ucred_reint(struct mdt_thread_info *); - void mdt_exit_ucred(struct mdt_thread_info *); -int groups_from_list(struct group_info *, gid_t *); - -void groups_sort(struct group_info *); - /* mdt_idmap.c */ int mdt_init_idmap(struct mdt_thread_info *); @@ -639,23 +634,16 @@ static inline struct mdt_device *mdt_dev(struct lu_device *d) extern struct upcall_cache_ops mdt_identity_upcall_cache_ops; -struct mdt_identity *mdt_identity_get(struct upcall_cache *, __u32); +struct md_identity *mdt_identity_get(struct upcall_cache *, __u32); -void mdt_identity_put(struct upcall_cache *, struct mdt_identity *); +void mdt_identity_put(struct upcall_cache *, struct md_identity *); void mdt_flush_identity(struct upcall_cache *, int); -__u32 mdt_identity_get_setxid_perm(struct mdt_identity *, __u32, lnet_nid_t); +__u32 mdt_identity_get_perm(struct md_identity *, __u32, lnet_nid_t); int mdt_pack_remote_perm(struct mdt_thread_info *, struct mdt_object *, void *); -/* mdt/mdt_rmtacl.c */ -#define MDT_RMTACL_UPCALL_PATH "/usr/sbin/l_facl" - -extern struct upcall_cache_ops mdt_rmtacl_upcall_cache_ops; - -int mdt_rmtacl_upcall(struct mdt_thread_info *, char *, struct lu_buf *); - extern struct lu_context_key mdt_thread_key; /* debug issues helper starts here*/ static inline void mdt_fail_write(const struct lu_env *env, diff --git a/lustre/mdt/mdt_lib.c b/lustre/mdt/mdt_lib.c index 28500c9..37cb8f0 100644 --- a/lustre/mdt/mdt_lib.c +++ b/lustre/mdt/mdt_lib.c @@ -11,6 +11,7 @@ * Author: Mike Shaver * Author: Nikita Danilov * Author: Huang Hua + * Author: Fan Yong * * * This file is part of the Lustre file system, http://www.lustre.org @@ -47,55 +48,6 @@ typedef enum ucred_init_type { REC_INIT = 2 } ucred_init_type_t; -int groups_from_list(struct group_info *ginfo, gid_t *glist) -{ - int i; - int count = ginfo->ngroups; - - /* fill group_info from gid array */ - for (i = 0; i < ginfo->nblocks; i++) { - int cp_count = min(NGROUPS_PER_BLOCK, count); - int off = i * NGROUPS_PER_BLOCK; - int len = cp_count * sizeof(*glist); - - if (memcpy(ginfo->blocks[i], glist + off, len)) - return -EFAULT; - - count -= cp_count; - } - return 0; -} - -/* groups_sort() is copied from linux kernel! */ -/* a simple shell-metzner sort */ -void groups_sort(struct group_info *group_info) -{ - int base, max, stride; - int gidsetsize = group_info->ngroups; - - for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1) - ; /* nothing */ - stride /= 3; - - while (stride) { - max = gidsetsize - stride; - for (base = 0; base < max; base++) { - int left = base; - int right = left + stride; - gid_t tmp = GROUP_AT(group_info, right); - - while (left >= 0 && GROUP_AT(group_info, left) > tmp) { - GROUP_AT(group_info, right) = - GROUP_AT(group_info, left); - right = left; - left -= stride; - } - GROUP_AT(group_info, right) = tmp; - } - stride /= 3; - } -} - void mdt_exit_ucred(struct mdt_thread_info *info) { struct md_ucred *uc = mdt_ucred(info); @@ -116,168 +68,13 @@ void mdt_exit_ucred(struct mdt_thread_info *info) } } -static int old_init_ucred(struct mdt_thread_info *info, - struct mdt_body *body) +/* XXX: root_squash will be redesigned in Lustre 1.7. + * Do not root_squash for inter-MDS operations */ +static int mdt_root_squash(struct mdt_thread_info *info) { - struct md_ucred *uc = mdt_ucred(info); - struct mdt_device *mdt = info->mti_mdt; - struct mdt_identity *identity = NULL; - - ENTRY; - - uc->mu_valid = UCRED_INVALID; - - if (!is_identity_get_disabled(mdt->mdt_identity_cache)) { - /* get identity info of this user */ - identity = mdt_identity_get(mdt->mdt_identity_cache, - body->fsuid); - if (!identity) { - CERROR("Deny access without identity: uid %d\n", - body->fsuid); - RETURN(-EACCES); - } - } - - uc->mu_valid = UCRED_OLD; - uc->mu_squash = SQUASH_NONE; - uc->mu_o_uid = uc->mu_uid = body->uid; - uc->mu_o_gid = uc->mu_gid = body->gid; - uc->mu_o_fsuid = uc->mu_fsuid = body->fsuid; - uc->mu_o_fsgid = uc->mu_fsgid = body->fsgid; - uc->mu_suppgids[0] = body->suppgid; - uc->mu_suppgids[1] = -1; - if (uc->mu_fsuid) - uc->mu_cap = body->capability & ~CAP_FS_MASK; - else - uc->mu_cap = body->capability; - uc->mu_ginfo = NULL; - uc->mu_identity = identity; - - RETURN(0); -} - -static int old_init_ucred_reint(struct mdt_thread_info *info) -{ - struct md_ucred *uc = mdt_ucred(info); - struct mdt_device *mdt = info->mti_mdt; - struct mdt_identity *identity = NULL; - - ENTRY; - - uc->mu_valid = UCRED_INVALID; - - if (!is_identity_get_disabled(mdt->mdt_identity_cache)) { - /* get identity info of this user */ - identity = mdt_identity_get(mdt->mdt_identity_cache, - uc->mu_fsuid); - if (!identity) { - CERROR("Deny access without identity: uid %d\n", - uc->mu_fsuid); - RETURN(-EACCES); - } - } - - uc->mu_valid = UCRED_OLD; - uc->mu_squash = SQUASH_NONE; - uc->mu_o_uid = uc->mu_o_fsuid = uc->mu_uid = uc->mu_fsuid; - uc->mu_o_gid = uc->mu_o_fsgid = uc->mu_gid = uc->mu_fsgid; - if (uc->mu_fsuid) - uc->mu_cap &= ~CAP_FS_MASK; - uc->mu_ginfo = NULL; - uc->mu_identity = identity; - - RETURN(0); -} - -static int nid_nosquash(struct mdt_device *mdt, lnet_nid_t nid) -{ - struct rootsquash_info *rsi = mdt->mdt_rootsquash_info; - int i; - - for (i = 0; i < rsi->rsi_n_nosquash_nids; i++) - if ((rsi->rsi_nosquash_nids[i] == nid) || - (rsi->rsi_nosquash_nids[i] == LNET_NID_ANY)) - return 1; - return 0; } -static int mdt_squash_root(struct mdt_device *mdt, struct md_ucred *ucred, - struct ptlrpc_user_desc *pud, lnet_nid_t peernid) -{ - struct rootsquash_info *rsi = mdt->mdt_rootsquash_info; - - if (!rsi || (!rsi->rsi_uid && !rsi->rsi_gid) || - nid_nosquash(mdt, peernid)) - return 0; - - CDEBUG(D_SEC, "squash req from "LPX64":" - "(%u:%u-%u:%u/%x)=>(%u:%u-%u:%u/%x)\n", peernid, - pud->pud_uid, pud->pud_gid, - pud->pud_fsuid, pud->pud_fsgid, pud->pud_cap, - pud->pud_uid ? pud->pud_uid : rsi->rsi_uid, - pud->pud_uid ? pud->pud_gid : rsi->rsi_gid, - pud->pud_fsuid ? pud->pud_fsuid : rsi->rsi_uid, - pud->pud_fsuid ? pud->pud_fsgid : rsi->rsi_gid, - pud->pud_cap & ~CAP_FS_MASK); - - if (rsi->rsi_uid) { - if (!pud->pud_uid) { - ucred->mu_uid = rsi->rsi_uid; - ucred->mu_squash |= SQUASH_UID; - } else { - ucred->mu_uid = pud->pud_uid; - } - - if (!pud->pud_fsuid) { - ucred->mu_fsuid = rsi->rsi_uid; - ucred->mu_squash |= SQUASH_UID; - } else { - ucred->mu_fsuid = pud->pud_fsuid; - } - } else { - ucred->mu_uid = pud->pud_uid; - ucred->mu_fsuid = pud->pud_fsuid; - } - - if (rsi->rsi_gid) { - int i; - - if (!pud->pud_gid) { - ucred->mu_gid = rsi->rsi_gid; - ucred->mu_squash |= SQUASH_GID; - } else { - ucred->mu_gid = pud->pud_gid; - } - - if (!pud->pud_fsgid) { - ucred->mu_fsgid = rsi->rsi_gid; - ucred->mu_squash |= SQUASH_GID; - } else { - ucred->mu_fsgid = pud->pud_fsgid; - } - - for (i = 0; i < 2; i++) { - if (!ucred->mu_suppgids[i]) { - ucred->mu_suppgids[i] = rsi->rsi_gid; - ucred->mu_squash |= SQUASH_GID; - } - } - - for (i = 0; i < pud->pud_ngroups; i++) { - if (!pud->pud_groups[i]) { - pud->pud_groups[i] = rsi->rsi_gid; - ucred->mu_squash |= SQUASH_GID; - } - } - } else { - ucred->mu_gid = pud->pud_gid; - ucred->mu_fsgid = pud->pud_fsgid; - } - - return 1; -} - static int new_init_ucred(struct mdt_thread_info *info, ucred_init_type_t type, void *buf) { @@ -286,9 +83,8 @@ static int new_init_ucred(struct mdt_thread_info *info, ucred_init_type_t type, struct mdt_device *mdt = info->mti_mdt; struct ptlrpc_user_desc *pud = req->rq_user_desc; struct md_ucred *ucred = mdt_ucred(info); - struct mdt_identity *identity = NULL; lnet_nid_t peernid = req->rq_peer.nid; - __u32 setxid_perm = 0; + __u32 perm = 0; int setuid; int setgid; int rc = 0; @@ -324,10 +120,12 @@ static int new_init_ucred(struct mdt_thread_info *info, ucred_init_type_t type, RETURN(-EACCES); if (req->rq_auth_mapped_uid != pud->pud_uid) { - CERROR("remote client "LPU64": auth uid %u " + CERROR("remote client "LPU64": auth/mapped uid %u/%u " "while client claim %u:%u/%u:%u\n", - peernid, req->rq_auth_uid, pud->pud_uid, - pud->pud_gid, pud->pud_fsuid, pud->pud_fsgid); + peernid, req->rq_auth_uid, + req->rq_auth_mapped_uid, + pud->pud_uid, pud->pud_gid, + pud->pud_fsuid, pud->pud_fsgid); RETURN(-EACCES); } } else { @@ -346,87 +144,100 @@ static int new_init_ucred(struct mdt_thread_info *info, ucred_init_type_t type, "enabled!\n"); RETURN(-EACCES); } else { - setxid_perm |= LUSTRE_SETGRP_PERM; - goto check_squash; + ucred->mu_identity = NULL; + perm = CFS_SETUID_PERM | CFS_SETGID_PERM | + CFS_SETGRP_PERM; } - } - - identity = mdt_identity_get(mdt->mdt_identity_cache, pud->pud_uid); - if (!identity) { - CERROR("Deny access without identity: uid %d\n", pud->pud_uid); + } else { + ucred->mu_identity = mdt_identity_get(mdt->mdt_identity_cache, + pud->pud_uid); + if (!ucred->mu_identity) { + CERROR("Deny access without identity: uid %d\n", + pud->pud_uid); RETURN(-EACCES); - } - - setxid_perm = mdt_identity_get_setxid_perm(identity, + } else { + perm = mdt_identity_get_perm(ucred->mu_identity, med->med_rmtclient, peernid); + } + } /* find out the setuid/setgid attempt */ setuid = (pud->pud_uid != pud->pud_fsuid); - setgid = (pud->pud_gid != pud->pud_fsgid || - pud->pud_gid != identity->mi_gid); + setgid = ((pud->pud_gid != pud->pud_fsgid) || + (ucred->mu_identity && + (pud->pud_gid != ucred->mu_identity->mi_gid))); /* check permission of setuid */ - if (setuid && !(setxid_perm & LUSTRE_SETUID_PERM)) { + if (setuid && !(perm & CFS_SETUID_PERM)) { CWARN("mdt blocked setuid attempt (%u -> %u) from " LPX64"\n", pud->pud_uid, pud->pud_fsuid, peernid); GOTO(out, rc = -EACCES); } /* check permission of setgid */ - if (setgid && !(setxid_perm & LUSTRE_SETGID_PERM)) { + if (setgid && !(perm & CFS_SETGID_PERM)) { CWARN("mdt blocked setgid attempt (%u:%u/%u:%u -> %u) " "from "LPX64"\n", pud->pud_uid, pud->pud_gid, - pud->pud_fsuid, pud->pud_fsgid, identity->mi_gid, - peernid); + pud->pud_fsuid, pud->pud_fsgid, + ucred->mu_identity->mi_gid, peernid); GOTO(out, rc = -EACCES); } -check_squash: - /* FIXME: The exact behavior of root_squash is not defined. */ - ucred->mu_squash = SQUASH_NONE; - if (mdt_squash_root(mdt, ucred, pud, peernid) == 0) { - ucred->mu_uid = pud->pud_uid; - ucred->mu_gid = pud->pud_gid; - ucred->mu_fsuid = pud->pud_fsuid; - ucred->mu_fsgid = pud->pud_fsgid; - } - - /* remove fs privilege for non-root user */ - if (ucred->mu_fsuid) - ucred->mu_cap = pud->pud_cap & ~CAP_FS_MASK; - else - ucred->mu_cap = pud->pud_cap; - /* * NB: remote client not allowed to setgroups anyway. */ - if (!med->med_rmtclient && pud->pud_ngroups && - (setxid_perm & LUSTRE_SETGRP_PERM)) { - struct group_info *ginfo; - + if (!med->med_rmtclient && perm & CFS_SETGRP_PERM) { + if (pud->pud_ngroups) { /* setgroups for local client */ - ginfo = groups_alloc(pud->pud_ngroups); - if (!ginfo) { + ucred->mu_ginfo = groups_alloc(pud->pud_ngroups); + if (!ucred->mu_ginfo) { CERROR("failed to alloc %d groups\n", pud->pud_ngroups); GOTO(out, rc = -ENOMEM); } - groups_from_list(ginfo, pud->pud_groups); - groups_sort(ginfo); - ucred->mu_ginfo = ginfo; + + lustre_groups_from_list(ucred->mu_ginfo, + pud->pud_groups); + lustre_groups_sort(ucred->mu_ginfo); } else { ucred->mu_ginfo = NULL; } + } else { + ucred->mu_suppgids[0] = -1; + ucred->mu_suppgids[1] = -1; + ucred->mu_ginfo = NULL; + } - ucred->mu_identity = identity; + ucred->mu_uid = pud->pud_uid; + ucred->mu_gid = pud->pud_gid; + ucred->mu_fsuid = pud->pud_fsuid; + ucred->mu_fsgid = pud->pud_fsgid; + + /* XXX: need to process root_squash here. */ + mdt_root_squash(info); + + /* remove fs privilege for non-root user */ + if (ucred->mu_fsuid) + ucred->mu_cap = pud->pud_cap & ~CAP_FS_MASK; + else + ucred->mu_cap = pud->pud_cap; ucred->mu_valid = UCRED_NEW; EXIT; out: - if (rc && identity) - mdt_identity_put(mdt->mdt_identity_cache, identity); + if (rc) { + if (ucred->mu_ginfo) { + groups_free(ucred->mu_ginfo); + ucred->mu_ginfo = NULL; + } + if (ucred->mu_identity) { + mdt_identity_put(mdt->mdt_identity_cache, + ucred->mu_identity); + ucred->mu_identity = NULL; + } + } return rc; } @@ -438,20 +249,23 @@ int mdt_check_ucred(struct mdt_thread_info *info) struct mdt_device *mdt = info->mti_mdt; struct ptlrpc_user_desc *pud = req->rq_user_desc; struct md_ucred *ucred = mdt_ucred(info); - struct mdt_identity *identity; + struct md_identity *identity = NULL; lnet_nid_t peernid = req->rq_peer.nid; + __u32 perm = 0; + int setuid; + int setgid; + int rc = 0; ENTRY; if ((ucred->mu_valid == UCRED_OLD) || (ucred->mu_valid == UCRED_NEW)) RETURN(0); - if (!req->rq_user_desc) + if (!req->rq_auth_gss || req->rq_auth_usr_mdt || !req->rq_user_desc) RETURN(0); /* sanity check: if we use strong authentication, we expect the * uid which client claimed is true */ - if (req->rq_auth_gss) { if (med->med_rmtclient) { if (req->rq_auth_mapped_uid == INVALID_UID) { CWARN("remote user not mapped, deny access!\n"); @@ -462,11 +276,12 @@ int mdt_check_ucred(struct mdt_thread_info *info) RETURN(-EACCES); if (req->rq_auth_mapped_uid != pud->pud_uid) { - CERROR("remote client "LPU64": auth uid %u " + CERROR("remote client "LPU64": auth/mapped uid %u/%u " "while client claim %u:%u/%u:%u\n", - peernid, req->rq_auth_uid, pud->pud_uid, - pud->pud_gid, pud->pud_fsuid, - pud->pud_fsgid); + peernid, req->rq_auth_uid, + req->rq_auth_mapped_uid, + pud->pud_uid, pud->pud_gid, + pud->pud_fsuid, pud->pud_fsgid); RETURN(-EACCES); } } else { @@ -479,25 +294,122 @@ int mdt_check_ucred(struct mdt_thread_info *info) RETURN(-EACCES); } } - } if (is_identity_get_disabled(mdt->mdt_identity_cache)) { if (med->med_rmtclient) { - CERROR("remote client must run with " - "identity_get enabled!\n"); + CERROR("remote client must run with identity_get " + "enabled!\n"); RETURN(-EACCES); } - } else { + RETURN(0); + } + + identity = mdt_identity_get(mdt->mdt_identity_cache, pud->pud_uid); + if (!identity) { + CERROR("Deny access without identity: uid %d\n", pud->pud_uid); + RETURN(-EACCES); + } + + perm = mdt_identity_get_perm(identity, med->med_rmtclient, peernid); + /* find out the setuid/setgid attempt */ + setuid = (pud->pud_uid != pud->pud_fsuid); + setgid = (pud->pud_gid != pud->pud_fsgid || + pud->pud_gid != identity->mi_gid); + + /* check permission of setuid */ + if (setuid && !(perm & CFS_SETUID_PERM)) { + CWARN("mdt blocked setuid attempt (%u -> %u) from " + LPX64"\n", pud->pud_uid, pud->pud_fsuid, peernid); + GOTO(out, rc = -EACCES); + } + + /* check permission of setgid */ + if (setgid && !(perm & CFS_SETGID_PERM)) { + CWARN("mdt blocked setgid attempt (%u:%u/%u:%u -> %u) " + "from "LPX64"\n", pud->pud_uid, pud->pud_gid, + pud->pud_fsuid, pud->pud_fsgid, identity->mi_gid, + peernid); + GOTO(out, rc = -EACCES); + } + + EXIT; + +out: + mdt_identity_put(mdt->mdt_identity_cache, identity); + return rc; +} + +static int old_init_ucred(struct mdt_thread_info *info, + struct mdt_body *body) +{ + struct md_ucred *uc = mdt_ucred(info); + struct mdt_device *mdt = info->mti_mdt; + struct md_identity *identity = NULL; + + ENTRY; + + uc->mu_valid = UCRED_INVALID; + uc->mu_o_uid = uc->mu_uid = body->uid; + uc->mu_o_gid = uc->mu_gid = body->gid; + uc->mu_o_fsuid = uc->mu_fsuid = body->fsuid; + uc->mu_o_fsgid = uc->mu_fsgid = body->fsgid; + uc->mu_suppgids[0] = body->suppgid; + uc->mu_suppgids[1] = -1; + uc->mu_ginfo = NULL; + if (!is_identity_get_disabled(mdt->mdt_identity_cache)) { identity = mdt_identity_get(mdt->mdt_identity_cache, - pud->pud_uid); + uc->mu_fsuid); if (!identity) { CERROR("Deny access without identity: uid %d\n", - pud->pud_uid); + uc->mu_fsuid); RETURN(-EACCES); } + } + uc->mu_identity = identity; + + /* XXX: need to process root_squash here. */ + mdt_root_squash(info); + + /* remove fs privilege for non-root user */ + if (uc->mu_fsuid) + uc->mu_cap = body->capability & ~CAP_FS_MASK; + else + uc->mu_cap = body->capability; + uc->mu_valid = UCRED_OLD; + + RETURN(0); +} + +static int old_init_ucred_reint(struct mdt_thread_info *info) +{ + struct md_ucred *uc = mdt_ucred(info); + struct mdt_device *mdt = info->mti_mdt; + struct md_identity *identity = NULL; + + ENTRY; - mdt_identity_put(mdt->mdt_identity_cache, identity); + uc->mu_valid = UCRED_INVALID; + uc->mu_o_uid = uc->mu_o_fsuid = uc->mu_uid = uc->mu_fsuid; + uc->mu_o_gid = uc->mu_o_fsgid = uc->mu_gid = uc->mu_fsgid; + uc->mu_ginfo = NULL; + if (!is_identity_get_disabled(mdt->mdt_identity_cache)) { + identity = mdt_identity_get(mdt->mdt_identity_cache, + uc->mu_fsuid); + if (!identity) { + CERROR("Deny access without identity: uid %d\n", + uc->mu_fsuid); + RETURN(-EACCES); + } } + uc->mu_identity = identity; + + /* XXX: need to process root_squash here. */ + mdt_root_squash(info); + + /* remove fs privilege for non-root user */ + if (uc->mu_fsuid) + uc->mu_cap &= ~CAP_FS_MASK; + uc->mu_valid = UCRED_OLD; RETURN(0); } diff --git a/lustre/mdt/mdt_lproc.c b/lustre/mdt/mdt_lproc.c index e7565dd..3b2db54 100644 --- a/lustre/mdt/mdt_lproc.c +++ b/lustre/mdt/mdt_lproc.c @@ -227,9 +227,9 @@ static int lprocfs_wr_identity_info(struct file *file, const char *buffer, GOTO(out, rc = -EINVAL); } - if (sparam.idd_nperms > N_SETXID_PERMS_MAX) { + if (sparam.idd_nperms > N_PERMS_MAX) { CERROR("%s: perm count %d more than maximum %d\n", - obd->obd_name, sparam.idd_nperms, N_SETXID_PERMS_MAX); + obd->obd_name, sparam.idd_nperms, N_PERMS_MAX); GOTO(out, rc = -EINVAL); } @@ -268,301 +268,6 @@ out: return rc ?: count; } -static int lprocfs_rd_rmtacl_expire(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - struct obd_device *obd = data; - struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev); - - *eof = 1; - return snprintf(page, count, "%lu\n", - mdt->mdt_rmtacl_cache->uc_entry_expire / HZ); -} - -static int lprocfs_wr_rmtacl_expire(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - struct obd_device *obd = data; - struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev); - int rc, val; - - rc = lprocfs_write_helper(buffer, count, &val); - if (rc) - return rc; - - mdt->mdt_rmtacl_cache->uc_entry_expire = val * HZ; - return count; -} - -static int lprocfs_rd_rmtacl_acquire_expire(char *page, char **start, - off_t off, int count, int *eof, - void *data) -{ - struct obd_device *obd = data; - struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev); - - *eof = 1; - return snprintf(page, count, "%lu\n", - mdt->mdt_rmtacl_cache->uc_acquire_expire / HZ); -} - -static int lprocfs_wr_rmtacl_acquire_expire(struct file *file, - const char *buffer, - unsigned long count, - void *data) -{ - struct obd_device *obd = data; - struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev); - int rc, val; - - rc = lprocfs_write_helper(buffer, count, &val); - if (rc) - return rc; - - mdt->mdt_rmtacl_cache->uc_acquire_expire = val * HZ; - return count; -} - -static int lprocfs_rd_rmtacl_upcall(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - struct obd_device *obd = data; - struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev); - - *eof = 1; - return snprintf(page, count, "%s\n", - mdt->mdt_rmtacl_cache->uc_upcall); -} - -static int lprocfs_wr_rmtacl_upcall(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - struct obd_device *obd = data; - struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev); - struct upcall_cache *hash = mdt->mdt_rmtacl_cache; - char kernbuf[UC_CACHE_UPCALL_MAXPATH] = { '\0' }; - - if (count >= UC_CACHE_UPCALL_MAXPATH) { - CERROR("%s: remote ACL upcall too long\n", obd->obd_name); - return -EINVAL; - } - - if (copy_from_user(kernbuf, buffer, - min(count, UC_CACHE_UPCALL_MAXPATH - 1))) - return -EFAULT; - - /* Remove any extraneous bits from the upcall (e.g. linefeeds) */ - sscanf(kernbuf, "%s", hash->uc_upcall); - - if (strcmp(hash->uc_name, obd->obd_name) != 0) - CWARN("%s: write to upcall name %s\n", - obd->obd_name, hash->uc_upcall); - CWARN("%s: remote ACL upcall set to %s\n", obd->obd_name, hash->uc_upcall); - - return count; -} - -static int lprocfs_wr_rmtacl_info(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - struct obd_device *obd = data; - struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev); - struct rmtacl_downcall_data sparam, *param = &sparam; - int size = 0, rc = 0; - - if (count < sizeof(*param)) { - CERROR("%s: invalid data size %lu\n", obd->obd_name, count); - return count; - } - - if (copy_from_user(&sparam, buffer, sizeof(sparam))) { - CERROR("%s: bad remote acl data\n", obd->obd_name); - GOTO(out, rc = -EFAULT); - } - - if (sparam.add_magic != RMTACL_DOWNCALL_MAGIC) { - CERROR("%s: MDT remote acl downcall bad params\n", obd->obd_name); - GOTO(out, rc = -EINVAL); - } - - if (sparam.add_buflen) { - size = offsetof(struct rmtacl_downcall_data, - add_buf[sparam.add_buflen]); - OBD_ALLOC(param, size); - if (!param) { - CERROR("%s: fail to alloc %d bytes for ino "LPU64"\n", - obd->obd_name, size, sparam.add_key); - param = &sparam; - param->add_buflen = 0; - } else if (copy_from_user(param, buffer, size)) { - CERROR("%s: ino "LPU64" bad remote acl data\n", - obd->obd_name, sparam.add_key); - OBD_FREE(param, size); - param = &sparam; - param->add_buflen = 0; - } - } - - rc = upcall_cache_downcall(mdt->mdt_rmtacl_cache, 0, param->add_key, - param); - -out: - if (param && (param != &sparam)) - OBD_FREE(param, size); - - return rc ?: count; -} - -static int lprocfs_rd_rootsquash_uid(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - struct obd_device *obd = data; - struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev); - struct rootsquash_info *rsi = mdt->mdt_rootsquash_info; - - *eof = 1; - return snprintf(page, count, "%u\n", - rsi ? rsi->rsi_uid : 0); -} - -static int lprocfs_wr_rootsquash_uid(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - struct obd_device *obd = data; - struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev); - int val, rc; - - rc = lprocfs_write_helper(buffer, count, &val); - if (rc) - return rc; - - if (!mdt->mdt_rootsquash_info) - OBD_ALLOC_PTR(mdt->mdt_rootsquash_info); - if (!mdt->mdt_rootsquash_info) - return -ENOMEM; - - mdt->mdt_rootsquash_info->rsi_uid = val; - return count; -} - -static int lprocfs_rd_rootsquash_gid(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - struct obd_device *obd = data; - struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev); - struct rootsquash_info *rsi = mdt->mdt_rootsquash_info; - - *eof = 1; - return snprintf(page, count, "%u\n", - rsi ? rsi->rsi_gid : 0); -} - -static int lprocfs_wr_rootsquash_gid(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - struct obd_device *obd = data; - struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev); - int val, rc; - - rc = lprocfs_write_helper(buffer, count, &val); - if (rc) - return rc; - - if (!mdt->mdt_rootsquash_info) - OBD_ALLOC_PTR(mdt->mdt_rootsquash_info); - if (!mdt->mdt_rootsquash_info) - return -ENOMEM; - - mdt->mdt_rootsquash_info->rsi_gid = val; - return count; -} - -static int lprocfs_rd_nosquash_nids(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - struct obd_device *obd = data; - struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev); - struct rootsquash_info *rsi = mdt->mdt_rootsquash_info; - int i, ret; - - ret = snprintf(page, count, "rootsquash skip list:\n"); - for (i = 0; rsi && (i < rsi->rsi_n_nosquash_nids); i++) { - ret += snprintf(page + ret, count - ret, "%s\n", - libcfs_nid2str(rsi->rsi_nosquash_nids[i])); - } - - *eof = 1; - return ret; -} - -static inline void remove_newline(char *str) -{ - int len = strlen(str); - - if (str[len - 1] == '\n') - str[len - 1] = '\0'; -} - -/* XXX: This macro is copied from lnet/libcfs/nidstring.c */ -#define LNET_NIDSTR_SIZE 32 /* size of each one (see below for usage) */ - -static void do_process_nosquash_nids(struct mdt_device *m, char *buf) -{ - struct rootsquash_info *rsi = m->mdt_rootsquash_info; - char str[LNET_NIDSTR_SIZE], *end; - lnet_nid_t nid; - - LASSERT(rsi); - rsi->rsi_n_nosquash_nids = 0; - while (rsi->rsi_n_nosquash_nids < N_NOSQUASH_NIDS) { - end = strchr(buf, ','); - memset(str, 0, sizeof(str)); - if (end) - strncpy(str, buf, min_t(int, sizeof(str), end - buf)); - else - strncpy(str, buf, min_t(int, sizeof(str), strlen(buf))); - - if (!strcmp(str, "*")) { - nid = LNET_NID_ANY; - } else { - nid = libcfs_str2nid(str); - if (nid == LNET_NID_ANY) - goto ignore; - } - rsi->rsi_nosquash_nids[rsi->rsi_n_nosquash_nids++] = nid; -ignore: - if (!end || (*(end + 1) == 0)) - return; - buf = end + 1; - } -} - -static int lprocfs_wr_nosquash_nids(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - struct obd_device *obd = data; - struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev); - char skips[LNET_NIDSTR_SIZE * N_NOSQUASH_NIDS] = ""; - unsigned long size = sizeof(skips); - - if (count > size) { - CERROR("parameter exceeds max limit %lu\n", size); - return -EINVAL; - } - - if (copy_from_user(skips, buffer, min(size, count))) - return -EFAULT; - - if (!mdt->mdt_rootsquash_info) - OBD_ALLOC_PTR(mdt->mdt_rootsquash_info); - if (!mdt->mdt_rootsquash_info) - return -ENOMEM; - - remove_newline(skips); - do_process_nosquash_nids(mdt, skips); - return count; -} - /* for debug only */ static int lprocfs_rd_capa(char *page, char **start, off_t off, int count, int *eof, void *data) @@ -728,19 +433,6 @@ static struct lprocfs_vars lprocfs_mdt_obd_vars[] = { lprocfs_wr_identity_upcall, 0 }, { "identity_flush", 0, lprocfs_wr_identity_flush, 0 }, { "identity_info", 0, lprocfs_wr_identity_info, 0 }, - { "rmtacl_expire", lprocfs_rd_rmtacl_expire, - lprocfs_wr_rmtacl_expire, 0 }, - { "rmtacl_acquire_expire", lprocfs_rd_rmtacl_acquire_expire, - lprocfs_wr_rmtacl_acquire_expire, 0 }, - { "rmtacl_upcall", lprocfs_rd_rmtacl_upcall, - lprocfs_wr_rmtacl_upcall, 0 }, - { "rmtacl_info", 0, lprocfs_wr_rmtacl_info, 0 }, - { "rootsquash_uid", lprocfs_rd_rootsquash_uid, - lprocfs_wr_rootsquash_uid, 0 }, - { "rootsquash_gid", lprocfs_rd_rootsquash_gid, - lprocfs_wr_rootsquash_gid, 0 }, - { "nosquash_nids", lprocfs_rd_nosquash_nids, - lprocfs_wr_nosquash_nids, 0 }, { "capa", lprocfs_rd_capa, lprocfs_wr_capa, 0 }, { "capa_timeout", lprocfs_rd_capa_timeout, diff --git a/lustre/mdt/mdt_rmtacl.c b/lustre/mdt/mdt_rmtacl.c deleted file mode 100644 index 13fa70a..0000000 --- a/lustre/mdt/mdt_rmtacl.c +++ /dev/null @@ -1,260 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 2004-2006 Cluster File Systems, Inc. - * Author: Lai Siyao - * Author: Fan Yong - * - * This file is part of Lustre, http://www.lustre.org. - * - * Lustre is free 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. - * - * 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 - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Lustre; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef EXPORT_SYMTAB -#define EXPORT_SYMTAB -#endif -#define DEBUG_SUBSYSTEM S_MDS - -#ifndef AUTOCONF_INCLUDED -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mdt_internal.h" - -#define MAX_CMD_LEN 256 - -static __u64 rmtacl_key = 0; -static spinlock_t rmtacl_key_lock = SPIN_LOCK_UNLOCKED; - -/* - * For remote acl operation, do NOT cache! - * Use different key for each remote acl operation. - */ -static __u64 mdt_rmtacl_getkey(void) -{ - __u64 key; - - spin_lock(&rmtacl_key_lock); - key = ++rmtacl_key; - spin_unlock(&rmtacl_key_lock); - - return key; -} - -static void mdt_rmtacl_entry_init(struct upcall_cache_entry *entry, void *args) -{ - struct rmtacl_upcall_data *data = args; - struct mdt_rmtacl *acl = &entry->u.acl; - char *cmd; - - acl->ra_uid = data->aud_uid; - acl->ra_gid = data->aud_gid; - /* we use address of this cache entry as handle */ - acl->ra_handle = (__u32)entry; - OBD_ALLOC(cmd, strlen(data->aud_cmd) + 1); - if (!cmd) - return; /* upcall will fail later! */ - - strcpy(cmd, data->aud_cmd); - acl->ra_cmd = cmd; -} - -static void mdt_rmtacl_entry_free(struct upcall_cache *cache, - struct upcall_cache_entry *entry) -{ - struct mdt_rmtacl *acl = &entry->u.acl; - int len; - - if (acl->ra_cmd) { - len = strlen(acl->ra_cmd) + 1; - OBD_FREE(acl->ra_cmd, len); - } - - if (acl->ra_buf) { - len = strlen(acl->ra_buf) + 1; - OBD_FREE(acl->ra_buf, len); - } -} - -static int mdt_rmtacl_upcall_compare(struct upcall_cache *cache, - struct upcall_cache_entry *entry, - __u64 key, void *args) -{ - struct rmtacl_upcall_data *data = args; - - LASSERT(entry && data); - LASSERT(entry->u.acl.ra_cmd && data->aud_cmd); - return strncmp(entry->u.acl.ra_cmd, data->aud_cmd, MAX_CMD_LEN); -} - -static int mdt_rmtacl_downcall_compare(struct upcall_cache *cache, - struct upcall_cache_entry *entry, - __u64 key, void *args) -{ - struct rmtacl_downcall_data *data = args; - - return entry->u.acl.ra_handle - data->add_handle; -} - -static int mdt_rmtacl_do_upcall(struct upcall_cache *cache, - struct upcall_cache_entry *entry) -{ - struct mdt_rmtacl *acl = &entry->u.acl; - char uidstr[8] = ""; - char gidstr[8] = ""; - char handle[20] = ""; - char keystr[20] = ""; - char *argv[] = { - [0] = cache->uc_upcall, - [1] = uidstr, - [2] = gidstr, - [3] = cache->uc_name, - [4] = keystr, - [5] = handle, - [6] = acl->ra_cmd, - [7] = NULL - }; - char *envp[] = { - [0] = "HOME=/", - [1] = "PATH=/bin:/usr/bin:/sbin:/usr/sbin", - [2] = NULL - }; - int rc; - ENTRY; - - if (!acl->ra_cmd) - RETURN(-ENOMEM); - - snprintf(uidstr, sizeof(uidstr), "%u", acl->ra_uid); - snprintf(gidstr, sizeof(gidstr), "%u", acl->ra_gid); - snprintf(keystr, sizeof(keystr), LPU64, entry->ue_key); - snprintf(handle, sizeof(handle), "%u", acl->ra_handle); - - LASSERTF(strcmp(cache->uc_upcall, "NONE"), "no upcall set!"); - - CDEBUG(D_INFO, "%s: remote acl upcall %s %s %s %s %s %s %s\n", - cache->uc_name, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6]); - - rc = USERMODEHELPER(argv[0], argv, envp); - if (rc < 0) { - CERROR("%s: error invoking upcall %s %s %s %s %s %s %s: rc %d; " - "check /proc/fs/lustre/mdt/%s/rmtacl_upcall\n", - cache->uc_name, argv[0], argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6], rc, cache->uc_name); - } else { - CDEBUG(D_HA, "%s: invoked upcall %s %s %s %s %s %s %s\n", - cache->uc_name, argv[0], argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6]); - rc = 0; - } - RETURN(rc); -} - -static int mdt_rmtacl_parse_downcall(struct upcall_cache *cache, - struct upcall_cache_entry *entry, - void *args) -{ - struct mdt_rmtacl *acl = &entry->u.acl; - struct rmtacl_downcall_data *data; - char *buf; - int len; - ENTRY; - - data = (struct rmtacl_downcall_data *)args; - LASSERT(data); - - len = strlen(data->add_buf) + 1; - OBD_ALLOC(buf, len); - if (!buf) - RETURN(-ENOMEM); - - memcpy(buf, data->add_buf, len); - acl->ra_buf = buf; - - CDEBUG(D_OTHER, "parse mdt acl@%p: %s %s\n", - acl, acl->ra_cmd, acl->ra_buf); - - RETURN(0); -} - -struct upcall_cache_ops mdt_rmtacl_upcall_cache_ops = { - .init_entry = mdt_rmtacl_entry_init, - .free_entry = mdt_rmtacl_entry_free, - .upcall_compare = mdt_rmtacl_upcall_compare, - .downcall_compare = mdt_rmtacl_downcall_compare, - .do_upcall = mdt_rmtacl_do_upcall, - .parse_downcall = mdt_rmtacl_parse_downcall, -}; - -int mdt_rmtacl_upcall(struct mdt_thread_info *info, char *cmd, - struct lu_buf *buf) -{ - struct mdt_device *mdt = info->mti_mdt; - struct md_ucred *uc = mdt_ucred(info); - struct rmtacl_upcall_data data; - struct upcall_cache_entry *entry; - __u64 key; - int rc = 0; - ENTRY; - - data.aud_uid = uc->mu_fsuid; - data.aud_gid = uc->mu_fsgid; - data.aud_cmd = cmd; - - key = mdt_rmtacl_getkey(); - - entry = upcall_cache_get_entry(mdt->mdt_rmtacl_cache, key, &data); - if (IS_ERR(entry)) - GOTO(out, rc = PTR_ERR(entry)); - - if (buf->lb_len <= strlen(entry->u.acl.ra_buf)) - GOTO(out, rc = -EFAULT); - - memcpy(buf->lb_buf, entry->u.acl.ra_buf, strlen(entry->u.acl.ra_buf)); - /* remote acl operation expire at once! */ - UC_CACHE_SET_EXPIRED(entry); - upcall_cache_put_entry(mdt->mdt_rmtacl_cache, entry); - -out: - if (rc) - sprintf(buf->lb_buf, "server processing error: %d\n", rc); - RETURN(0); -} diff --git a/lustre/mdt/mdt_xattr.c b/lustre/mdt/mdt_xattr.c index 2d80821..b9682a6 100644 --- a/lustre/mdt/mdt_xattr.c +++ b/lustre/mdt/mdt_xattr.c @@ -68,9 +68,6 @@ static int mdt_getxattr_pack_reply(struct mdt_thread_info * info) !strncmp(xattr_name, user_string, sizeof(user_string) - 1)) RETURN(-EOPNOTSUPP); - if (!strcmp(xattr_name, XATTR_NAME_LUSTRE_ACL)) - size = RMTACL_SIZE_MAX; - else size = mo_xattr_get(info->mti_env, mdt_object_child(info->mti_object), &LU_BUF_NULL, xattr_name); @@ -108,32 +105,11 @@ static int mdt_getxattr_pack_reply(struct mdt_thread_info * info) RETURN(size); } -static int do_remote_getfacl(struct mdt_thread_info *info, struct lu_buf *buf) -{ - struct ptlrpc_request *req = mdt_info_req(info); - char *cmd; - int rc; - ENTRY; - - if (!buf->lb_buf || (buf->lb_len != RMTACL_SIZE_MAX)) - RETURN(-EINVAL); - - cmd = req_capsule_client_get(&info->mti_pill, &RMF_EADATA); - if (!cmd) { - CERROR("missing getfacl command!\n"); - RETURN(-EFAULT); - } - - rc = mdt_rmtacl_upcall(info, cmd, buf); - if (rc) - CERROR("remote acl upcall failed: %d\n", rc); - - lustre_shrink_reply(req, REPLY_REC_OFF + 1, strlen(buf->lb_buf) + 1, 0); - RETURN(rc ?: strlen(buf->lb_buf) + 1); -} - int mdt_getxattr(struct mdt_thread_info *info) { + struct ptlrpc_request *req = mdt_info_req(info); + struct mdt_export_data *med = mdt_req2med(req); + struct md_ucred *uc = mdt_ucred(info); struct mdt_body *reqbody; struct mdt_body *repbody = NULL; struct md_object *next; @@ -154,6 +130,23 @@ int mdt_getxattr(struct mdt_thread_info *info) if (rc) RETURN(err_serious(rc)); + next = mdt_object_child(info->mti_object); + + if (info->mti_body->valid & OBD_MD_FLRMTRGETFACL) { + __u32 perm = mdt_identity_get_perm(uc->mu_identity, + med->med_rmtclient, + req->rq_peer.nid); + + LASSERT(med->med_rmtclient); + if (!(perm & CFS_RMTACL_PERM)) + GOTO(out, rc = err_serious(-EPERM)); + + rc = mo_permission(info->mti_env, NULL, next, NULL, + MAY_RGETFACL); + if (rc) + GOTO(out, rc = err_serious(rc)); + } + easize = mdt_getxattr_pack_reply(info); if (easize < 0) GOTO(out, rc = err_serious(easize)); @@ -168,20 +161,36 @@ int mdt_getxattr(struct mdt_thread_info *info) buf = &info->mti_buf; buf->lb_buf = req_capsule_server_get(&info->mti_pill, &RMF_EADATA); buf->lb_len = easize; - next = mdt_object_child(info->mti_object); if (info->mti_body->valid & OBD_MD_FLXATTR) { + int flags = CFS_IC_NOTHING; char *xattr_name = req_capsule_client_get(&info->mti_pill, &RMF_NAME); CDEBUG(D_INODE, "getxattr %s\n", xattr_name); - if (!strcmp(xattr_name, XATTR_NAME_LUSTRE_ACL)) - rc = do_remote_getfacl(info, buf); - else rc = mo_xattr_get(info->mti_env, next, buf, xattr_name); - - if (rc < 0) + if (rc < 0) { CERROR("getxattr failed: %d\n", rc); + GOTO(out, rc); + } + + if (info->mti_body->valid & + (OBD_MD_FLRMTLSETFACL | OBD_MD_FLRMTLGETFACL)) + flags = CFS_IC_ALL; + else if (info->mti_body->valid & OBD_MD_FLRMTRGETFACL) + flags = CFS_IC_MAPPED; + + if (rc > 0 && flags != CFS_IC_NOTHING) { + int rc1; + + LASSERT(med->med_rmtclient); + rc1 = lustre_posix_acl_xattr_id2client(uc, + med->med_idmap, + (posix_acl_xattr_header *)(buf->lb_buf), + rc, flags); + if (unlikely(rc1 < 0)) + rc = rc1; + } } else if (info->mti_body->valid & OBD_MD_FLXATTRLS) { CDEBUG(D_INODE, "listxattr\n"); @@ -201,60 +210,58 @@ out: return rc; } -/* return EADATA length to the caller. negative value means error */ -static int mdt_setxattr_pack_reply(struct mdt_thread_info * info) -{ - struct req_capsule *pill = &info->mti_pill ; - __u64 valid = info->mti_body->valid; - int rc = 0, rc1; - - if ((valid & OBD_MD_FLXATTR) == OBD_MD_FLXATTR) { - char *xattr_name; - - xattr_name = req_capsule_client_get(pill, &RMF_NAME); - if (!xattr_name) - return -EFAULT; - - if (!strcmp(xattr_name, XATTR_NAME_LUSTRE_ACL)) - rc = RMTACL_SIZE_MAX; - } - - req_capsule_set_size(pill, &RMF_EADATA, RCL_SERVER, rc); - - rc1 = req_capsule_pack(pill); - - return rc = rc1 ? rc1 : rc; -} - -static int do_remote_setfacl(struct mdt_thread_info *info) +static int mdt_rmtlsetfacl(struct mdt_thread_info *info, char *xattr_name, + ext_acl_xattr_header *header, + posix_acl_xattr_header **out) { struct ptlrpc_request *req = mdt_info_req(info); + struct mdt_export_data *med = mdt_req2med(req); + struct md_ucred *uc = mdt_ucred(info); + struct md_object *next = mdt_object_child(info->mti_object); struct lu_buf *buf = &info->mti_buf; - char *cmd; int rc; ENTRY; - cmd = req_capsule_client_get(&info->mti_pill, &RMF_EADATA); - if (!cmd) { - CERROR("missing setfacl command!\n"); - RETURN(-EFAULT); + rc = lustre_ext_acl_xattr_id2server(uc, med->med_idmap, header); + if (rc) + RETURN(rc); + + rc = mo_xattr_get(info->mti_env, next, &LU_BUF_NULL, xattr_name); + if (rc == -ENODATA) + rc = 0; + else if (rc < 0) + RETURN(rc); + + buf->lb_len = rc; + if (buf->lb_len > 0) { + OBD_ALLOC(buf->lb_buf, buf->lb_len); + if (unlikely(buf->lb_buf == NULL)) + RETURN(-ENOMEM); + + rc = mo_xattr_get(info->mti_env, next, buf, xattr_name); + if (rc < 0) { + CERROR("getxattr failed: %d\n", rc); + GOTO(_out, rc); } + } else + buf->lb_buf = NULL; - buf->lb_buf = req_capsule_server_get(&info->mti_pill, &RMF_EADATA); - LASSERT(buf->lb_buf); - buf->lb_len = RMTACL_SIZE_MAX; + rc = lustre_acl_xattr_merge2posix((posix_acl_xattr_header *)(buf->lb_buf), + buf->lb_len, header, out); + EXIT; - rc = mdt_rmtacl_upcall(info, cmd, buf); - if (rc) - CERROR("remote acl upcall failed: %d\n", rc); +_out: + if (rc <= 0 && buf->lb_buf != NULL) + OBD_FREE(buf->lb_buf, buf->lb_len); - lustre_shrink_reply(req, REPLY_REC_OFF, strlen(buf->lb_buf) + 1, 0); - RETURN(rc); + return rc; } int mdt_setxattr(struct mdt_thread_info *info) { struct ptlrpc_request *req = mdt_info_req(info); + struct mdt_export_data *med = mdt_req2med(req); + struct md_ucred *uc = mdt_ucred(info); struct mdt_body *reqbody; const char user_string[] = "user."; const char trust_string[] = "trusted."; @@ -267,9 +274,10 @@ int mdt_setxattr(struct mdt_thread_info *info) struct lu_buf *buf = &info->mti_buf; __u64 valid = body->valid; char *xattr_name; - int xattr_len; + int xattr_len = 0; __u64 lockpart; int rc; + posix_acl_xattr_header *new_xattr = NULL; ENTRY; CDEBUG(D_INODE, "setxattr "DFID"\n", PFID(&body->fid1)); @@ -285,7 +293,17 @@ int mdt_setxattr(struct mdt_thread_info *info) if (rc) RETURN(err_serious(rc)); - rc = mdt_setxattr_pack_reply(info); + if (valid & OBD_MD_FLRMTRSETFACL) { + __u32 perm = mdt_identity_get_perm(uc->mu_identity, + med->med_rmtclient, + req->rq_peer.nid); + + LASSERT(med->med_rmtclient); + if (!(perm & CFS_RMTACL_PERM)) + GOTO(out, rc = err_serious(-EPERM)); + } + + rc = req_capsule_pack(pill); if (rc < 0) GOTO(out, rc = err_serious(rc)); @@ -297,12 +315,6 @@ int mdt_setxattr(struct mdt_thread_info *info) CDEBUG(D_INODE, "%s xattr %s\n", body->valid & OBD_MD_FLXATTR ? "set" : "remove", xattr_name); - if (((valid & OBD_MD_FLXATTR) == OBD_MD_FLXATTR) && - (!strcmp(xattr_name, XATTR_NAME_LUSTRE_ACL))) { - rc = do_remote_setfacl(info); - GOTO(out, rc); - } - if (strncmp(xattr_name, trust_string, sizeof(trust_string) - 1) == 0) { if (strcmp(xattr_name + 8, XATTR_NAME_LOV) == 0) GOTO(out, rc = -EACCES); @@ -335,6 +347,17 @@ int mdt_setxattr(struct mdt_thread_info *info) int flags = 0; xattr = req_capsule_client_get(pill, &RMF_EADATA); + if (valid & OBD_MD_FLRMTLSETFACL) { + LASSERT(med->med_rmtclient); + xattr_len = mdt_rmtlsetfacl(info, xattr_name, + (ext_acl_xattr_header *)xattr, + &new_xattr); + if (xattr_len < 0) + GOTO(out_unlock, rc = xattr_len); + + xattr = (char *)new_xattr; + } + if (body->flags & XATTR_REPLACE) flags |= LU_XATTR_REPLACE; @@ -356,6 +379,8 @@ int mdt_setxattr(struct mdt_thread_info *info) } EXIT; out_unlock: + if (unlikely(new_xattr != NULL)) + lustre_posix_acl_xattr_free(new_xattr, xattr_len); mdt_object_unlock(info, obj, lh, rc); out: mdt_exit_ucred(info); diff --git a/lustre/mgc/mgc_request.c b/lustre/mgc/mgc_request.c index 01d85bd..65c8610 100644 --- a/lustre/mgc/mgc_request.c +++ b/lustre/mgc/mgc_request.c @@ -317,7 +317,7 @@ static int mgc_requeue_add(struct config_llog_data *cld, int later) CDEBUG(D_INFO, "log %s: requeue (l=%d r=%d sp=%d st=%x)\n", cld->cld_logname, later, atomic_read(&cld->cld_refcount), cld->cld_stopping, rq_state); - + /* Hold lock for rq_state */ spin_lock(&config_list_lock); cld->cld_lostlock = 1; diff --git a/lustre/mgs/lproc_mgs.c b/lustre/mgs/lproc_mgs.c index 598ad31..e3d71ad 100644 --- a/lustre/mgs/lproc_mgs.c +++ b/lustre/mgs/lproc_mgs.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "mgs_internal.h" #ifdef LPROCFS @@ -88,9 +89,40 @@ int lproc_mgs_setup(struct obd_device *obd) return rc; } +static void seq_show_srpc_rule(struct seq_file *seq, const char *tgtname, + struct sptlrpc_rule_set *rset) +{ + struct sptlrpc_rule *r; + char dirbuf[10]; + char flvrbuf[40]; + char *net; + int i; + + for (i = 0; i < rset->srs_nrule; i++) { + r = &rset->srs_rules[i]; + + if (r->sr_netid == LNET_NIDNET(LNET_NID_ANY)) + net = "default"; + else + net = libcfs_net2str(r->sr_netid); + + if (r->sr_from == LUSTRE_SP_ANY && r->sr_to == LUSTRE_SP_ANY) + dirbuf[0] = '\0'; + else + snprintf(dirbuf, sizeof(dirbuf), ".%s2%s", + sptlrpc_part2name(r->sr_from), + sptlrpc_part2name(r->sr_to)); + + sptlrpc_flavor2name(&r->sr_flvr, flvrbuf, sizeof(flvrbuf)); + seq_printf(seq, "%s.srpc.flavor.%s%s=%s\n", tgtname, + net, dirbuf, flvrbuf); + } +} + static int mgs_live_seq_show(struct seq_file *seq, void *v) { - struct fs_db *fsdb = seq->private; + struct fs_db *fsdb = seq->private; + struct mgs_tgt_srpc_conf *srpc_tgt; int i; down(&fsdb->fsdb_sem); @@ -105,6 +137,18 @@ static int mgs_live_seq_show(struct seq_file *seq, void *v) if (test_bit(i, fsdb->fsdb_ost_index_map)) seq_printf(seq, "%s-OST%04x\n", fsdb->fsdb_name, i); + seq_printf(seq, "\nSecure RPC Config Rules:\n"); +#if 0 + seq_printf(seq, "%s.%s=%s\n", fsdb->fsdb_name, + PARAM_SRPC_UDESC, fsdb->fsdb_srpc_fl_udesc ? "yes" : "no"); +#endif + for (srpc_tgt = fsdb->fsdb_srpc_tgt; srpc_tgt; + srpc_tgt = srpc_tgt->mtsc_next) { + seq_show_srpc_rule(seq, srpc_tgt->mtsc_tgt, + &srpc_tgt->mtsc_rset); + } + seq_show_srpc_rule(seq, fsdb->fsdb_name, &fsdb->fsdb_srpc_gen); + up(&fsdb->fsdb_sem); return 0; } diff --git a/lustre/mgs/mgs_handler.c b/lustre/mgs/mgs_handler.c index 786ea2a..1efe1ab 100644 --- a/lustre/mgs/mgs_handler.c +++ b/lustre/mgs/mgs_handler.c @@ -65,6 +65,8 @@ static int mgs_connect(const struct lu_env *env, exp = class_conn2export(conn); LASSERT(exp); + exp->exp_flvr.sf_rpc = SPTLRPC_FLVR_NULL; + if (data != NULL) { data->ocd_connect_flags &= MGS_CONNECT_SUPPORTED; exp->exp_connect_flags = data->ocd_connect_flags; diff --git a/lustre/mgs/mgs_internal.h b/lustre/mgs/mgs_internal.h index 69acba9..5f0361f 100644 --- a/lustre/mgs/mgs_internal.h +++ b/lustre/mgs/mgs_internal.h @@ -23,6 +23,12 @@ int class_dentry_readdir(struct obd_device *obd, struct dentry *dir, struct vfsmount *inmnt, struct list_head *dentry_list); +struct mgs_tgt_srpc_conf { + struct mgs_tgt_srpc_conf *mtsc_next; + char *mtsc_tgt; + struct sptlrpc_rule_set mtsc_rset; +}; + #define INDEX_MAP_SIZE 8192 /* covers indicies to FFFF */ #define FSDB_LOG_EMPTY 0x0001 /* missing client log */ #define FSDB_OLDLOG14 0x0002 /* log starts in old (1.4) style */ @@ -43,6 +49,11 @@ struct fs_db { /* end COMPAT_146 */ __u32 fsdb_flags; __u32 fsdb_gen; + + /* in-memory copy of the srpc rules, guarded by fsdb_sem */ + struct sptlrpc_rule_set fsdb_srpc_gen; + struct mgs_tgt_srpc_conf *fsdb_srpc_tgt; + unsigned int fsdb_srpc_fl_udesc:1; }; int mgs_init_fsdb_list(struct obd_device *obd); diff --git a/lustre/mgs/mgs_llog.c b/lustre/mgs/mgs_llog.c index 7f5eb86..e942879 100644 --- a/lustre/mgs/mgs_llog.c +++ b/lustre/mgs/mgs_llog.c @@ -48,6 +48,13 @@ #include #include "mgs_internal.h" +static int mgs_get_fsdb_srpc_from_llog(struct obd_device *obd, + struct fs_db *fsdb); +static int mgs_get_srpc_conf_log(struct fs_db *fsdb, const char *tgt, + enum lustre_sec_part from, + enum lustre_sec_part to, + struct sptlrpc_conf_log *log); + /********************** Class functions ********************/ /* Caller must list_del and OBD_FREE each dentry from the list */ @@ -260,6 +267,26 @@ out_pop: RETURN(rc); } +static void mgs_free_fsdb_srpc(struct fs_db *fsdb) +{ + struct mgs_tgt_srpc_conf *tgtconf; + + /* free target-specific rules */ + while (fsdb->fsdb_srpc_tgt) { + tgtconf = fsdb->fsdb_srpc_tgt; + fsdb->fsdb_srpc_tgt = tgtconf->mtsc_next; + + LASSERT(tgtconf->mtsc_tgt); + + sptlrpc_rule_set_free(&tgtconf->mtsc_rset); + OBD_FREE(tgtconf->mtsc_tgt, strlen(tgtconf->mtsc_tgt) + 1); + OBD_FREE_PTR(tgtconf); + } + + /* free general rules */ + sptlrpc_rule_set_free(&fsdb->fsdb_srpc_gen); +} + static struct fs_db *mgs_find_fsdb(struct obd_device *obd, char *fsname) { struct mgs_obd *mgs = &obd->u.mgs; @@ -309,6 +336,7 @@ static struct fs_db *mgs_new_fsdb(struct obd_device *obd, char *fsname) if (rc) GOTO(err, rc); + fsdb->fsdb_srpc_fl_udesc = 1; sema_init(&fsdb->fsdb_sem, 1); list_add(&fsdb->fsdb_list, &mgs->mgs_fs_db_list); lproc_mgs_add_live(obd, fsdb); @@ -340,6 +368,7 @@ static void mgs_free_fsdb(struct obd_device *obd, struct fs_db *fsdb) name_destroy(&fsdb->fsdb_mdtlov); name_destroy(&fsdb->fsdb_mdtlmv); name_destroy(&fsdb->fsdb_mdc); + mgs_free_fsdb_srpc(fsdb); OBD_FREE_PTR(fsdb); } @@ -393,6 +422,14 @@ static int mgs_find_or_make_fsdb(struct obd_device *obd, char *name, return rc; } + /* populate srpc rules from params llog */ + rc = mgs_get_fsdb_srpc_from_llog(obd, fsdb); + if (rc) { + CERROR("Can't get db from params log %d\n", rc); + mgs_free_fsdb(obd, fsdb); + return rc; + } + *dbh = fsdb; return 0; @@ -712,17 +749,18 @@ static inline int record_setup(struct obd_device *obd, struct llog_handle *llh, return record_base(obd,llh,devname,0,LCFG_SETUP,s1,s2,s3,s4); } -static inline int record_sec_flavor(struct obd_device *obd, - struct llog_handle *llh, char *devname, - struct sec_flavor_config *conf) +static inline int record_sptlrpc_conf(struct obd_device *obd, + struct llog_handle *llh, + char *devname, + struct sptlrpc_conf_log *srpc_log) { struct lustre_cfg_bufs bufs; struct lustre_cfg *lcfg; int rc; lustre_cfg_bufs_reset(&bufs, devname); - lustre_cfg_bufs_set(&bufs, 1, conf, sizeof(*conf)); - lcfg = lustre_cfg_new(LCFG_SEC_FLAVOR, &bufs); + lustre_cfg_bufs_set(&bufs, 1, srpc_log, sizeof(*srpc_log)); + lcfg = lustre_cfg_new(LCFG_SPTLRPC_CONF, &bufs); rc = record_lcfg(obd, llh, lcfg); @@ -952,7 +990,9 @@ int mgs_write_log_direct_all(struct obd_device *obd, struct fs_db *fsdb, /* Could use fsdb index maps instead of directory listing */ list_for_each_entry_safe(dirent, n, &dentry_list, lld_list) { list_del(&dirent->lld_list); - if (strncmp(fsname, dirent->lld_name, len) == 0) { + /* don't write to sptlrpc rule log */ + if (strncmp(fsname, dirent->lld_name, len) == 0 && + strstr(dirent->lld_name, "-sptlrpc") == NULL) { CDEBUG(D_MGS, "Changing log %s\n", dirent->lld_name); /* Erase any old settings of this same parameter */ mgs_modify(obd, fsdb, mti, dirent->lld_name, devname, @@ -976,12 +1016,10 @@ struct temp_comp struct mgs_target_info *comp_mti; struct fs_db *comp_fsdb; struct obd_device *comp_obd; - struct sec_flavor_config comp_sec; }; static int mgs_write_log_mdc_to_mdt(struct obd_device *, struct fs_db *, - struct mgs_target_info *, - struct sec_flavor_config *, char *); + struct mgs_target_info *, char *); static int mgs_steal_llog_handler(struct llog_handle *llh, struct llog_rec_hdr *rec, @@ -993,7 +1031,6 @@ static int mgs_steal_llog_handler(struct llog_handle *llh, int cfg_len = rec->lrh_len; char *cfg_buf = (char*) (rec + 1); struct lustre_cfg *lcfg; - struct sec_flavor_config *sec_conf; int rc = 0; struct llog_handle *mdt_llh = NULL; static int got_an_osc_or_mdc = 0; @@ -1009,7 +1046,6 @@ static int mgs_steal_llog_handler(struct llog_handle *llh, tmti = ((struct temp_comp*)data)->comp_tmti; fsdb = ((struct temp_comp*)data)->comp_fsdb; obd = ((struct temp_comp*)data)->comp_obd; - sec_conf = &((struct temp_comp*)data)->comp_sec; if (rec->lrh_type != OBD_CFG_REC) { CERROR("unhandled lrh_type: %#x\n", rec->lrh_type); @@ -1087,10 +1123,9 @@ static int mgs_steal_llog_handler(struct llog_handle *llh, RETURN(rc); } - if (lcfg->lcfg_command == LCFG_SEC_FLAVOR) { - memcpy(sec_conf, lustre_cfg_buf(lcfg, 1), sizeof(*sec_conf)); + /* ignore client side sptlrpc_conf_log */ + if (lcfg->lcfg_command == LCFG_SPTLRPC_CONF) RETURN(rc); - } if (lcfg->lcfg_command == LCFG_ADD_MDC) { int index; @@ -1102,8 +1137,7 @@ static int mgs_steal_llog_handler(struct llog_handle *llh, strlen(mti->mti_fsname)); tmti->mti_stripe_index = index; - mgs_write_log_mdc_to_mdt(obd, fsdb, tmti, sec_conf, - mti->mti_svname); + mgs_write_log_mdc_to_mdt(obd, fsdb, tmti, mti->mti_svname); memset(tmti, 0, sizeof(*tmti)); RETURN(rc); } @@ -1283,37 +1317,12 @@ static int mgs_write_log_failnids(struct obd_device *obd, return rc; } -static -void extract_sec_flavor(char *params, char *key, char **ptr) -{ - char *val = NULL, *tail; - int len; - - *ptr = NULL; - - if (class_find_param(params, key, &val)) - return; - - tail = strchr(val, ' '); - if (tail == NULL) - len = strlen(val); - else - len = tail - val; - - OBD_ALLOC(*ptr, len + 1); - if (*ptr == NULL) - return; - - memcpy(*ptr, val, len); - (*ptr)[len] = '\0'; -} - static int mgs_write_log_mdc_to_lmv(struct obd_device *obd, struct fs_db *fsdb, struct mgs_target_info *mti, - struct sec_flavor_config *sec_conf, char *logname, char *lmvname) { struct llog_handle *llh = NULL; + struct sptlrpc_conf_log *srpc_log; char *mdcname, *nodeuuid, *mdcuuid, *lmvuuid; char index[5]; int i, rc; @@ -1327,6 +1336,16 @@ static int mgs_write_log_mdc_to_lmv(struct obd_device *obd, struct fs_db *fsdb, CDEBUG(D_MGS, "adding mdc for %s to log %s:lmv(%s)\n", mti->mti_svname, logname, lmvname); + srpc_log = sptlrpc_conf_log_alloc(); + if (IS_ERR(srpc_log)) + RETURN(PTR_ERR(srpc_log)); + srpc_log->scl_part = LUSTRE_SP_CLI; + + rc = mgs_get_srpc_conf_log(fsdb, mti->mti_svname, + LUSTRE_SP_CLI, LUSTRE_SP_MDT, srpc_log); + if (rc) + goto out_srpc; + name_create(&nodeuuid, libcfs_nid2str(mti->mti_nids[0]), ""); name_create(&mdcname, mti->mti_svname, "-mdc"); name_create(&mdcuuid, mdcname, "_UUID"); @@ -1345,7 +1364,7 @@ static int mgs_write_log_mdc_to_lmv(struct obd_device *obd, struct fs_db *fsdb, rc = record_attach(obd, llh, mdcname, LUSTRE_MDC_NAME, lmvuuid); rc = record_setup(obd, llh, mdcname, mti->mti_uuid, nodeuuid, 0, 0); - rc = record_sec_flavor(obd, llh, mdcname, sec_conf); + rc = record_sptlrpc_conf(obd, llh, mdcname, srpc_log); rc = mgs_write_log_failnids(obd, mti, llh, mdcname); snprintf(index, sizeof(index), "%d", mti->mti_stripe_index); rc = record_mdc_add(obd, llh, lmvname, mdcuuid, mti->mti_uuid, @@ -1358,16 +1377,17 @@ static int mgs_write_log_mdc_to_lmv(struct obd_device *obd, struct fs_db *fsdb, name_destroy(&mdcuuid); name_destroy(&mdcname); name_destroy(&nodeuuid); +out_srpc: + sptlrpc_conf_log_free(srpc_log); RETURN(rc); } /* add new mdc to already existent MDS */ static int mgs_write_log_mdc_to_mdt(struct obd_device *obd, struct fs_db *fsdb, - struct mgs_target_info *mti, - struct sec_flavor_config *sec_conf, - char *logname) + struct mgs_target_info *mti, char *logname) { struct llog_handle *llh = NULL; + struct sptlrpc_conf_log *srpc_log; char *nodeuuid, *mdcname, *mdcuuid, *mdtuuid; int idx = mti->mti_stripe_index; char index[9]; @@ -1381,6 +1401,16 @@ static int mgs_write_log_mdc_to_mdt(struct obd_device *obd, struct fs_db *fsdb, CDEBUG(D_MGS, "adding mdc index %d to %s\n", idx, logname); + srpc_log = sptlrpc_conf_log_alloc(); + if (IS_ERR(srpc_log)) + RETURN(PTR_ERR(srpc_log)); + srpc_log->scl_part = LUSTRE_SP_MDT; + + rc = mgs_get_srpc_conf_log(fsdb, mti->mti_svname, + LUSTRE_SP_MDT, LUSTRE_SP_MDT, srpc_log); + if (rc) + goto out_srpc; + name_create(&nodeuuid, libcfs_nid2str(mti->mti_nids[0]), ""); snprintf(index, sizeof(index), "-mdc%04x", idx); name_create(&mdcname, logname, index); @@ -1396,7 +1426,7 @@ static int mgs_write_log_mdc_to_mdt(struct obd_device *obd, struct fs_db *fsdb, } rc = record_attach(obd, llh, mdcname, LUSTRE_MDC_NAME, mdcuuid); rc = record_setup(obd, llh, mdcname, mti->mti_uuid, nodeuuid, 0, 0); - rc = record_sec_flavor(obd, llh, mdcname, sec_conf); + rc = record_sptlrpc_conf(obd, llh, mdcname, srpc_log); rc = mgs_write_log_failnids(obd, mti, llh, mdcname); snprintf(index, sizeof(index), "%d", idx); @@ -1409,6 +1439,8 @@ static int mgs_write_log_mdc_to_mdt(struct obd_device *obd, struct fs_db *fsdb, name_destroy(&mdcname); name_destroy(&nodeuuid); name_destroy(&mdtuuid); +out_srpc: + sptlrpc_conf_log_free(srpc_log); RETURN(rc); } @@ -1419,13 +1451,24 @@ static int mgs_write_log_mdt0(struct obd_device *obd, struct fs_db *fsdb, struct llog_handle *llh = NULL; char *uuid, *lovname; char mdt_index[5]; + struct sptlrpc_conf_log *srpc_log; char *ptr = mti->mti_params; int rc = 0, failout = 0; ENTRY; + srpc_log = sptlrpc_conf_log_alloc(); + if (IS_ERR(srpc_log)) + RETURN(PTR_ERR(srpc_log)); + srpc_log->scl_part = LUSTRE_SP_MDT; + + rc = mgs_get_srpc_conf_log(fsdb, mti->mti_svname, + LUSTRE_SP_ANY, LUSTRE_SP_MDT, srpc_log); + if (rc) + GOTO(out_srpc, rc); + OBD_ALLOC(uuid, sizeof(struct obd_uuid)); if (uuid == NULL) - RETURN(-ENOMEM); + GOTO(out_srpc, rc = -ENOMEM); if (class_find_param(ptr, PARAM_FAILMODE, &ptr) == 0) failout = (strncmp(ptr, "failout", 7) == 0); @@ -1448,11 +1491,14 @@ static int mgs_write_log_mdt0(struct obd_device *obd, struct fs_db *fsdb, rc = record_mount_opt(obd, llh, log, lovname, NULL); rc = record_setup(obd, llh, log, uuid, mdt_index, lovname, failout ? "n" : "f"); + rc = record_sptlrpc_conf(obd, llh, log, srpc_log); rc = record_marker(obd, llh, fsdb, CM_END, log, "add mdt"); rc = record_end_log(obd, &llh); out: name_destroy(&lovname); OBD_FREE(uuid, sizeof(struct obd_uuid)); +out_srpc: + sptlrpc_conf_log_free(srpc_log); RETURN(rc); } @@ -1460,10 +1506,9 @@ out: static int mgs_write_log_mdt(struct obd_device *obd, struct fs_db *fsdb, struct mgs_target_info *mti) { - char *cliname, *sec; struct llog_handle *llh = NULL; + char *cliname; struct temp_comp comp = { 0 }; - struct sec_flavor_config sec_conf_mdt, sec_conf_cli; char mdt_index[9]; int rc, i = 0; ENTRY; @@ -1492,19 +1537,6 @@ static int mgs_write_log_mdt(struct obd_device *obd, struct fs_db *fsdb, "%s_UUID", mti->mti_svname); } - /* security flavor */ - extract_sec_flavor(mti->mti_params, PARAM_SEC_RPC_MDT, &sec); - rc = sptlrpc_parse_flavor(LUSTRE_MDT, LUSTRE_MDT, sec, &sec_conf_mdt); - name_destroy(&sec); - if (rc) - RETURN(rc); - - extract_sec_flavor(mti->mti_params, PARAM_SEC_RPC_CLI, &sec); - rc = sptlrpc_parse_flavor(LUSTRE_CLI, LUSTRE_MDT, sec, &sec_conf_cli); - name_destroy(&sec); - if (rc) - RETURN(rc); - /* add mdt */ rc = mgs_write_log_mdt0(obd, fsdb, mti); @@ -1559,8 +1591,8 @@ static int mgs_write_log_mdt(struct obd_device *obd, struct fs_db *fsdb, rc = mgs_steal_llog_for_mdt_from_client(obd, cliname, &comp); - rc = mgs_write_log_mdc_to_lmv(obd, fsdb, mti, &sec_conf_cli, - cliname, fsdb->fsdb_clilmv); + rc = mgs_write_log_mdc_to_lmv(obd, fsdb, mti, cliname, + fsdb->fsdb_clilmv); /* add mountopts */ rc = record_start_log(obd, &llh, cliname); if (rc) @@ -1586,8 +1618,7 @@ out: sprintf(mdt_index,"-MDT%04x",i); name_create(&mdtname, mti->mti_fsname, mdt_index); - rc = mgs_write_log_mdc_to_mdt(obd, fsdb, mti, - &sec_conf_mdt, mdtname); + rc = mgs_write_log_mdc_to_mdt(obd, fsdb, mti, mdtname); name_destroy(&mdtname); } } @@ -1599,10 +1630,10 @@ out: static int mgs_write_log_osc_to_lov(struct obd_device *obd, struct fs_db *fsdb, struct mgs_target_info *mti, char *logname, char *suffix, char *lovname, - struct sec_flavor_config *sec_conf, - int flags) + enum lustre_sec_part sec_part, int flags) { struct llog_handle *llh = NULL; + struct sptlrpc_conf_log *srpc_log; char *nodeuuid, *oscname, *oscuuid, *lovuuid, *svname; char index[5]; int i, rc; @@ -1611,6 +1642,16 @@ static int mgs_write_log_osc_to_lov(struct obd_device *obd, struct fs_db *fsdb, CDEBUG(D_INFO, "adding osc for %s to log %s\n", mti->mti_svname, logname); + srpc_log = sptlrpc_conf_log_alloc(); + if (IS_ERR(srpc_log)) + RETURN(PTR_ERR(srpc_log)); + srpc_log->scl_part = sec_part; + + rc = mgs_get_srpc_conf_log(fsdb, mti->mti_svname, + sec_part, LUSTRE_SP_OST, srpc_log); + if (rc) + goto out_srpc; + if (mgs_log_is_empty(obd, logname)) { /* The first item in the log must be the lov, so we have somewhere to add our osc. */ @@ -1647,7 +1688,7 @@ static int mgs_write_log_osc_to_lov(struct obd_device *obd, struct fs_db *fsdb, } rc = record_attach(obd, llh, oscname, LUSTRE_OSC_NAME, lovuuid); rc = record_setup(obd, llh, oscname, mti->mti_uuid, nodeuuid, 0, 0); - rc = record_sec_flavor(obd, llh, oscname, sec_conf); + rc = record_sptlrpc_conf(obd, llh, oscname, srpc_log); rc = mgs_write_log_failnids(obd, mti, llh, oscname); snprintf(index, sizeof(index), "%d", mti->mti_stripe_index); rc = record_lov_add(obd, llh, lovname, mti->mti_uuid, index, "1"); @@ -1660,6 +1701,8 @@ out: name_destroy(&oscname); name_destroy(&svname); name_destroy(&nodeuuid); +out_srpc: + sptlrpc_conf_log_free(srpc_log); RETURN(rc); } @@ -1667,10 +1710,10 @@ static int mgs_write_log_ost(struct obd_device *obd, struct fs_db *fsdb, struct mgs_target_info *mti) { struct llog_handle *llh = NULL; - char *logname, *lovname, *sec; + struct sptlrpc_conf_log *srpc_log; + char *logname, *lovname; char mdt_index[9]; char *ptr = mti->mti_params; - struct sec_flavor_config sec_conf_mdt, sec_conf_cli; int rc, flags = 0, failout = 0, i; ENTRY; @@ -1689,18 +1732,15 @@ static int mgs_write_log_ost(struct obd_device *obd, struct fs_db *fsdb, RETURN(-EALREADY); } - /* security flavors */ - extract_sec_flavor(mti->mti_params, PARAM_SEC_RPC_MDT, &sec); - rc = sptlrpc_parse_flavor(LUSTRE_MDT, LUSTRE_OST, sec, &sec_conf_mdt); - name_destroy(&sec); - if (rc) - RETURN(rc); + srpc_log = sptlrpc_conf_log_alloc(); + if (IS_ERR(srpc_log)) + RETURN(PTR_ERR(srpc_log)); + srpc_log->scl_part = LUSTRE_SP_OST; - extract_sec_flavor(mti->mti_params, PARAM_SEC_RPC_CLI, &sec); - rc = sptlrpc_parse_flavor(LUSTRE_CLI, LUSTRE_OST, sec, &sec_conf_cli); - name_destroy(&sec); + rc = mgs_get_srpc_conf_log(fsdb, mti->mti_svname, + LUSTRE_SP_ANY, LUSTRE_SP_OST, srpc_log); if (rc) - RETURN(rc); + goto out_srpc; /* attach obdfilter ost1 ost1_UUID @@ -1721,6 +1761,7 @@ static int mgs_write_log_ost(struct obd_device *obd, struct fs_db *fsdb, rc = record_setup(obd, llh, mti->mti_svname, "dev"/*ignored*/, "type"/*ignored*/, failout ? "n" : "f", 0/*options*/); + rc = record_sptlrpc_conf(obd, llh, mti->mti_svname, srpc_log); rc = record_marker(obd, llh, fsdb, CM_END, mti->mti_svname, "add ost"); rc = record_end_log(obd, &llh); @@ -1751,7 +1792,7 @@ static int mgs_write_log_ost(struct obd_device *obd, struct fs_db *fsdb, name_create(&lovname, logname, "-mdtlov"); mgs_write_log_osc_to_lov(obd, fsdb, mti, logname, mdt_index, lovname, - &sec_conf_mdt, flags); + LUSTRE_SP_MDT, flags); name_destroy(&logname); name_destroy(&lovname); } @@ -1760,9 +1801,10 @@ static int mgs_write_log_ost(struct obd_device *obd, struct fs_db *fsdb, /* Append ost info to the client log */ name_create(&logname, mti->mti_fsname, "-client"); mgs_write_log_osc_to_lov(obd, fsdb, mti, logname, "", - fsdb->fsdb_clilov, &sec_conf_cli, 0); + fsdb->fsdb_clilov, LUSTRE_SP_CLI, 0); name_destroy(&logname); - +out_srpc: + sptlrpc_conf_log_free(srpc_log); RETURN(rc); } @@ -1865,6 +1907,662 @@ static int mgs_wlp_lcfg(struct obd_device *obd, struct fs_db *fsdb, return rc; } +/* + * populate rules which applied to a target device + */ +static int mgs_get_srpc_conf_log(struct fs_db *fsdb, const char *tgt, + enum lustre_sec_part from, + enum lustre_sec_part to, + struct sptlrpc_conf_log *log) +{ + struct mgs_tgt_srpc_conf *tgtconf; + struct sptlrpc_rule_set *tgt_rset; + int found_tgt = 0, rc; + + for (tgtconf = fsdb->fsdb_srpc_tgt; tgtconf; + tgtconf = tgtconf->mtsc_next) { + if (!strcmp(tgt, tgtconf->mtsc_tgt)) { + found_tgt = 1; + break; + } + } + + if (found_tgt) + tgt_rset = &tgtconf->mtsc_rset; + else + tgt_rset = NULL; + + rc = sptlrpc_conf_log_populate(&fsdb->fsdb_srpc_gen, tgt_rset, + from, to, fsdb->fsdb_srpc_fl_udesc, log); + if (rc) + CERROR("failed to populate srpc log for %s: %d\n", tgt, rc); + + return rc; +} + +struct mgs_msl_data { + struct obd_device *mmd_obd; + struct fs_db *mmd_fsdb; + struct mgs_target_info *mmd_mti; + int mmd_skip; + int mmd_attached; + int mmd_server; + enum lustre_sec_part mmd_tgtpart; + char mmd_tgtname[MTI_NAME_MAXLEN]; +}; + +static void mgs_msl_data_cleanup(struct mgs_msl_data *mmd) +{ + mmd->mmd_attached = 0; + mmd->mmd_tgtname[0] = '\0'; +} + +static int mgs_msl_tgt_uuid2name(char *tgtname, char *tgtuuid) +{ + char *ptr; + + if (tgtuuid == NULL) { + CERROR("missing target UUID???\n"); + return -EINVAL; + } + + ptr = strstr(tgtuuid, "_UUID"); + if (ptr == NULL) { + CERROR("unrecognized UUID: %s\n", tgtuuid); + return -EINVAL; + } + + *ptr = '\0';; + strncpy(tgtname, tgtuuid, MTI_NAME_MAXLEN); + tgtname[MTI_NAME_MAXLEN - 1] = '\0'; + + return 0; +} + +static int mgs_modify_srpc_log_handler(struct llog_handle *llh, + struct llog_rec_hdr *rec, + void *data) +{ + struct mgs_msl_data *mmd = (struct mgs_msl_data *)data; + struct cfg_marker *marker; + struct lustre_cfg *lcfg = (struct lustre_cfg *)(rec + 1); + int cfg_len, rc; + ENTRY; + + if (rec->lrh_type != OBD_CFG_REC) { + CERROR("unhandled lrh_type: %#x\n", rec->lrh_type); + RETURN(-EINVAL); + } + + cfg_len = rec->lrh_len - sizeof(struct llog_rec_hdr) - + sizeof(struct llog_rec_tail); + + rc = lustre_cfg_sanity_check(lcfg, cfg_len); + if (rc) { + CERROR("Insane cfg\n"); + RETURN(rc); + } + + if (lcfg->lcfg_command == LCFG_MARKER) { + marker = lustre_cfg_buf(lcfg, 1); + + if (marker->cm_flags & CM_START && + marker->cm_flags & CM_SKIP) + mmd->mmd_skip = 1; + if (marker->cm_flags & CM_END) + mmd->mmd_skip = 0; + + RETURN(0); + } + + if (mmd->mmd_skip) + RETURN(0); + + switch (lcfg->lcfg_command) { + case LCFG_ATTACH: + mmd->mmd_attached = 1; + + if (!strcmp(lustre_cfg_string(lcfg, 1), LUSTRE_OST_NAME)) { + mmd->mmd_server = 1; + mmd->mmd_tgtpart = LUSTRE_SP_OST; + } else if (!strcmp(lustre_cfg_string(lcfg, 1), + LUSTRE_MDT_NAME)) { + mmd->mmd_server = 1; + mmd->mmd_tgtpart = LUSTRE_SP_MDT; + } else if (!strcmp(lustre_cfg_string(lcfg, 1), + LUSTRE_OSC_NAME)) { + mmd->mmd_server = 0; + mmd->mmd_tgtpart = LUSTRE_SP_OST; + } else if (!strcmp(lustre_cfg_string(lcfg, 1), + LUSTRE_MDC_NAME)) { + mmd->mmd_server = 0; + mmd->mmd_tgtpart = LUSTRE_SP_MDT; + } else { + mmd->mmd_attached = 0; + } + + if (mmd->mmd_attached && mmd->mmd_server) { + rc = mgs_msl_tgt_uuid2name(mmd->mmd_tgtname, + lustre_cfg_string(lcfg, 2)); + if (rc) { + mgs_msl_data_cleanup(mmd); + break; + } + } + + break; + case LCFG_SETUP: + if (!mmd->mmd_attached) + break; + + /* already got tgtname at LCFG_ATTACH */ + if (mmd->mmd_server) + break; + + rc = mgs_msl_tgt_uuid2name(mmd->mmd_tgtname, + lustre_cfg_string(lcfg, 1)); + if (rc) { + mgs_msl_data_cleanup(mmd); + break; + } + + break; + case LCFG_SPTLRPC_CONF: { + struct sptlrpc_conf_log *log; + enum lustre_sec_part from; + + if (!mmd->mmd_attached) + break; + + log = sptlrpc_conf_log_extract(lcfg); + if (log == NULL) { + CERROR("missing sptlrpc config log???\n"); + mgs_msl_data_cleanup(mmd); + break; + } + + if (mmd->mmd_server) + from = LUSTRE_SP_ANY; + else + from = log->scl_part; + + /* cleanup the old log */ + sptlrpc_conf_log_cleanup(log); + + /* populate new log */ + rc = mgs_get_srpc_conf_log(mmd->mmd_fsdb, mmd->mmd_tgtname, + from, mmd->mmd_tgtpart, log); + if (rc) { + mgs_msl_data_cleanup(mmd); + break; + } + + /* Overwrite the log */ + rec->lrh_len = cfg_len; + rc = llog_write_rec(llh, rec, NULL, 0, (void *)lcfg, + rec->lrh_index); + if (rc) + CERROR("overwrite sptlrpc conf log failed: %d\n", rc); + + /* append new one */ + rc = record_marker(mmd->mmd_obd, llh, mmd->mmd_fsdb, CM_START, + mmd->mmd_mti->mti_svname, "sptlrpc config"); + rc = record_sptlrpc_conf(mmd->mmd_obd, llh, + lustre_cfg_string(lcfg, 0), log); + rc = record_marker(mmd->mmd_obd, llh, mmd->mmd_fsdb, CM_END, + mmd->mmd_mti->mti_svname, "sptlrpc config"); + + mgs_msl_data_cleanup(mmd); + break; + } + default: + /* ignore all others */ + break; + } + + RETURN(rc); +} + +static int mgs_modify_srpc_log(struct obd_device *obd, + struct fs_db *fsdb, + struct mgs_target_info *mti, + char *logname) +{ + struct llog_handle *llh; + struct lvfs_run_ctxt saved; + struct mgs_msl_data *mmd; + int rc, rc2; + ENTRY; + + CDEBUG(D_MGS, "modify sptlrpc log for %s\n", logname); + + push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); + + rc = llog_create(llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT), + &llh, NULL, logname); + if (rc) + GOTO(out_pop, rc); + + rc = llog_init_handle(llh, LLOG_F_IS_PLAIN, NULL); + if (rc) + GOTO(out_close, rc); + + if (llog_get_size(llh) <= 1) + GOTO(out_close, rc = 0); + + OBD_ALLOC_PTR(mmd); + if (!mmd) + GOTO(out_close, rc = -ENOMEM); + + mmd->mmd_obd = obd; + mmd->mmd_fsdb = fsdb; + mmd->mmd_mti = mti; + + rc = llog_process(llh, mgs_modify_srpc_log_handler, (void *) mmd, NULL); + + OBD_FREE_PTR(mmd); + +out_close: + rc2 = llog_close(llh); + if (!rc) + rc = rc2; + +out_pop: + pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); + if (rc) + CERROR("modify sptlrpc log %s failed %d\n", logname, rc); + + RETURN(rc); +} + +/* + * for each of log, remove old conf at first + */ +static int mgs_modify_srpc_log_all(struct obd_device *obd, + struct fs_db *fsdb, + struct mgs_target_info *mti) +{ + char tgt_index[9]; + char *logname; + int i, rc = 0, rc2; + ENTRY; + + for (i = 0; i < INDEX_MAP_SIZE * 8; i++){ + if (test_bit(i, fsdb->fsdb_mdt_index_map)) { + sprintf(tgt_index,"-MDT%04x",i); + + name_create(&logname, mti->mti_fsname, tgt_index); + rc2 = mgs_modify(obd, fsdb, mti, logname, + mti->mti_fsname, "sptlrpc config", + CM_SKIP); + rc2 = mgs_modify_srpc_log(obd, fsdb, mti, logname); + name_destroy(&logname); + + if (rc2 && rc == 0) + rc = rc2; + } + } + + for (i = 0; i < INDEX_MAP_SIZE * 8; i++){ + if (test_bit(i, fsdb->fsdb_ost_index_map)) { + sprintf(tgt_index,"-OST%04x",i); + + name_create(&logname, mti->mti_fsname, tgt_index); + rc2 = mgs_modify(obd, fsdb, mti, logname, + mti->mti_fsname, "sptlrpc config", + CM_SKIP); + rc2 = mgs_modify_srpc_log(obd, fsdb, mti, logname); + name_destroy(&logname); + + if (rc2 && rc == 0) + rc = rc2; + } + } + + name_create(&logname, mti->mti_fsname, "-client"); + rc2 = mgs_modify(obd, fsdb, mti, logname, + mti->mti_fsname, "sptlrpc config", CM_SKIP); + rc2 = mgs_modify_srpc_log(obd, fsdb, mti, logname); + name_destroy(&logname); + + if (rc2 && rc == 0) + rc = rc2; + + RETURN(rc); +} + +static int mgs_srpc_set_param_disk(struct obd_device *obd, + struct fs_db *fsdb, + struct mgs_target_info *mti, + char *param) +{ + struct llog_handle *llh = NULL; + char *logname; + char *comment, *ptr; + struct lustre_cfg_bufs bufs; + struct lustre_cfg *lcfg; + int rc, len; + ENTRY; + + /* get comment */ + ptr = strchr(param, '='); + LASSERT(ptr); + len = ptr - param; + + OBD_ALLOC(comment, len + 1); + if (comment == NULL) + RETURN(-ENOMEM); + strncpy(comment, param, len); + comment[len] = '\0'; + + /* prepare lcfg */ + lustre_cfg_bufs_reset(&bufs, mti->mti_svname); + lustre_cfg_bufs_set_string(&bufs, 1, param); + lcfg = lustre_cfg_new(0, &bufs); + if (lcfg == NULL) + GOTO(out_comment, rc = -ENOMEM); + + /* construct log name */ + rc = name_create(&logname, mti->mti_fsname, "-sptlrpc"); + if (rc) + GOTO(out_lcfg, rc); + + if (mgs_log_is_empty(obd, logname)) { + rc = record_start_log(obd, &llh, logname); + record_end_log(obd, &llh); + if (rc) + GOTO(out, rc); + } + + /* obsolete old one */ + mgs_modify(obd, fsdb, mti, logname, mti->mti_svname, comment, CM_SKIP); + + /* write the new one */ + rc = mgs_write_log_direct(obd, fsdb, logname, lcfg, + mti->mti_svname, comment); + if (rc) + CERROR("err %d writing log %s\n", rc, logname); + +out: + name_destroy(&logname); +out_lcfg: + lustre_cfg_free(lcfg); +out_comment: + OBD_FREE(comment, len + 1); + RETURN(rc); +} + +static int mgs_srpc_set_param_udesc_mem(struct fs_db *fsdb, + char *param) +{ + char *ptr; + + /* disable the adjustable udesc parameter for now, i.e. use default + * setting that client always ship udesc to MDT if possible. to enable + * it simply remove the following line */ + goto error_out; + + ptr = strchr(param, '='); + if (ptr == NULL) + goto error_out; + *ptr++ = '\0'; + + if (strcmp(param, PARAM_SRPC_UDESC)) + goto error_out; + + if (strcmp(ptr, "yes") == 0) { + fsdb->fsdb_srpc_fl_udesc = 1; + CWARN("Enable user descriptor shipping from client to MDT\n"); + } else if (strcmp(ptr, "no") == 0) { + fsdb->fsdb_srpc_fl_udesc = 0; + CWARN("Disable user descriptor shipping from client to MDT\n"); + } else { + *(ptr - 1) = '='; + goto error_out; + } + return 0; + +error_out: + CERROR("Invalid param: %s\n", param); + return -EINVAL; +} + +static int mgs_srpc_set_param_mem(struct fs_db *fsdb, + const char *svname, + char *param) +{ + struct sptlrpc_rule rule; + struct sptlrpc_rule_set *rset; + int rc; + ENTRY; + + if (strncmp(param, PARAM_SRPC, sizeof(PARAM_SRPC) - 1) != 0) { + CERROR("Invalid sptlrpc parameter: %s\n", param); + RETURN(-EINVAL); + } + + if (strncmp(param, PARAM_SRPC_UDESC, + sizeof(PARAM_SRPC_UDESC) - 1) == 0) { + RETURN(mgs_srpc_set_param_udesc_mem(fsdb, param)); + } + + if (strncmp(param, PARAM_SRPC_FLVR, sizeof(PARAM_SRPC_FLVR) - 1) != 0) { + CERROR("Invalid sptlrpc flavor parameter: %s\n", param); + RETURN(-EINVAL); + } + + param += sizeof(PARAM_SRPC_FLVR) - 1; + + rc = sptlrpc_parse_rule(param, &rule); + if (rc) + RETURN(rc); + + /* preapre room for this coming rule. svcname format should be: + * - fsname: general rule + * - fsname-tgtname: target-specific rule + */ + if (strchr(svname, '-')) { + struct mgs_tgt_srpc_conf *tgtconf; + int found = 0; + + for (tgtconf = fsdb->fsdb_srpc_tgt; tgtconf != NULL; + tgtconf = tgtconf->mtsc_next) { + if (!strcmp(tgtconf->mtsc_tgt, svname)) { + found = 1; + break; + } + } + + if (!found) { + int name_len; + + OBD_ALLOC_PTR(tgtconf); + if (tgtconf == NULL) + RETURN(-ENOMEM); + + name_len = strlen(svname); + + OBD_ALLOC(tgtconf->mtsc_tgt, name_len + 1); + if (tgtconf->mtsc_tgt == NULL) { + OBD_FREE_PTR(tgtconf); + RETURN(-ENOMEM); + } + memcpy(tgtconf->mtsc_tgt, svname, name_len); + + tgtconf->mtsc_next = fsdb->fsdb_srpc_tgt; + fsdb->fsdb_srpc_tgt = tgtconf; + } + + rset = &tgtconf->mtsc_rset; + } else { + rset = &fsdb->fsdb_srpc_gen; + } + + /* limit the maximum number of rules, but allow deletion in any case */ + if (rset->srs_nrule >= SPTLRPC_CONF_LOG_MAX / 2 && + rule.sr_flvr.sf_rpc != SPTLRPC_FLVR_INVALID) { + CERROR("too many (%d) rules already for %s\n", + rset->srs_nrule, svname); + RETURN(-E2BIG); + } + + rc = sptlrpc_rule_set_merge(rset, &rule, 1); + + RETURN(rc); +} + +static int mgs_srpc_set_param(struct obd_device *obd, + struct fs_db *fsdb, + struct mgs_target_info *mti, + char *param) +{ + char *copy; + int rc, copy_size; + ENTRY; + + /* keep a copy of original param, which could be destroied + * during parsing */ + copy_size = strlen(param) + 1; + OBD_ALLOC(copy, copy_size); + if (copy == NULL) + return -ENOMEM; + memcpy(copy, param, copy_size); + + rc = mgs_srpc_set_param_mem(fsdb, mti->mti_svname, param); + if (rc) + goto out_free; + + /* previous steps guaranteed the syntax is correct */ + rc = mgs_srpc_set_param_disk(obd, fsdb, mti, copy); + if (rc) + goto out_free; + + /* now apply the new rules to all existing config logs */ + rc = mgs_modify_srpc_log_all(obd, fsdb, mti); + +out_free: + OBD_FREE(copy, copy_size); + RETURN(rc); +} + +struct mgs_srpc_read_data { + struct fs_db *msrd_fsdb; + int msrd_skip; +}; + +static int mgs_srpc_read_handler(struct llog_handle *llh, + struct llog_rec_hdr *rec, + void *data) +{ + struct mgs_srpc_read_data *msrd = (struct mgs_srpc_read_data *) data; + struct cfg_marker *marker; + struct lustre_cfg *lcfg = (struct lustre_cfg *)(rec + 1); + char *svname, *param; + int cfg_len, rc; + ENTRY; + + if (rec->lrh_type != OBD_CFG_REC) { + CERROR("unhandled lrh_type: %#x\n", rec->lrh_type); + RETURN(-EINVAL); + } + + cfg_len = rec->lrh_len - sizeof(struct llog_rec_hdr) - + sizeof(struct llog_rec_tail); + + rc = lustre_cfg_sanity_check(lcfg, cfg_len); + if (rc) { + CERROR("Insane cfg\n"); + RETURN(rc); + } + + if (lcfg->lcfg_command == LCFG_MARKER) { + marker = lustre_cfg_buf(lcfg, 1); + + if (marker->cm_flags & CM_START && + marker->cm_flags & CM_SKIP) + msrd->msrd_skip = 1; + if (marker->cm_flags & CM_END) + msrd->msrd_skip = 0; + + RETURN(0); + } + + if (msrd->msrd_skip) + RETURN(0); + + if (lcfg->lcfg_command != 0) { + CERROR("invalid command (%x)\n", lcfg->lcfg_command); + RETURN(0); + } + + svname = lustre_cfg_string(lcfg, 0); + if (svname == NULL) { + CERROR("svname is empty\n"); + RETURN(0); + } + + param = lustre_cfg_string(lcfg, 1); + if (param == NULL) { + CERROR("param is empty\n"); + RETURN(0); + } + + rc = mgs_srpc_set_param_mem(msrd->msrd_fsdb, svname, param); + if (rc) + CERROR("read sptlrpc record error (%d): %s\n", rc, param); + + RETURN(0); +} + +static int mgs_get_fsdb_srpc_from_llog(struct obd_device *obd, + struct fs_db *fsdb) +{ + struct llog_handle *llh = NULL; + struct lvfs_run_ctxt saved; + char *logname; + struct mgs_srpc_read_data msrd; + int rc; + ENTRY; + + /* construct log name */ + rc = name_create(&logname, fsdb->fsdb_name, "-sptlrpc"); + if (rc) + RETURN(rc); + + if (mgs_log_is_empty(obd, logname)) + GOTO(out, rc = 0); + + push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); + + rc = llog_create(llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT), + &llh, NULL, logname); + if (rc) + GOTO(out_pop, rc); + + rc = llog_init_handle(llh, LLOG_F_IS_PLAIN, NULL); + if (rc) + GOTO(out_close, rc); + + if (llog_get_size(llh) <= 1) + GOTO(out_close, rc = 0); + + msrd.msrd_fsdb = fsdb; + msrd.msrd_skip = 0; + + rc = llog_process(llh, mgs_srpc_read_handler, (void *) &msrd, NULL); + +out_close: + llog_close(llh); +out_pop: + pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); +out: + name_destroy(&logname); + + if (rc) + CERROR("failed to read sptlrpc config database: %d\n", rc); + RETURN(rc); +} + static int mgs_write_log_params(struct obd_device *obd, struct fs_db *fsdb, struct mgs_target_info *mti) { @@ -1908,10 +2606,11 @@ static int mgs_write_log_params(struct obd_device *obd, struct fs_db *fsdb, } GOTO(end_while, rc); } - /* Processed in mgs_write_log_mdt/mgs_write_log_ost */ - if (class_match_param(ptr, PARAM_SEC_RPC_MDT, NULL) == 0 || - class_match_param(ptr, PARAM_SEC_RPC_CLI, NULL) == 0) + + if (class_match_param(ptr, PARAM_SRPC, NULL) == 0) { + rc = mgs_srpc_set_param(obd, fsdb, mti, ptr); GOTO(end_while, rc); + } if (class_match_param(ptr, PARAM_FAILNODE, NULL) == 0) { /* Add a failover nidlist */ diff --git a/lustre/obdclass/Makefile.in b/lustre/obdclass/Makefile.in index 11f93a0..eb16d75 100644 --- a/lustre/obdclass/Makefile.in +++ b/lustre/obdclass/Makefile.in @@ -25,6 +25,7 @@ obdclass-all-objs += debug.o genops.o uuid.o llog_ioctl.o obdclass-all-objs += lprocfs_status.o lustre_handles.o lustre_peer.o obdclass-all-objs += statfs_pack.o obdo.o obd_config.o obd_mount.o mea.o obdclass-all-objs += lu_object.o dt_object.o hash.o capa.o lu_time.o +obdclass-all-objs += acl.o idmap.o obdclass-objs := $(obdclass-linux-objs) $(obdclass-all-objs) diff --git a/lustre/obdclass/acl.c b/lustre/obdclass/acl.c new file mode 100644 index 0000000..d358f54 --- /dev/null +++ b/lustre/obdclass/acl.c @@ -0,0 +1,832 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * lustre/obdclass/acl.c + * Lustre Access Control List. + * Author: Fan Yong + * + * Copyright (c) 2004-2007 Cluster File Systems, Inc. + * + * This file is part of Lustre, http://www.lustre.org. + * + * Lustre is free 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. + * + * 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 + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Lustre; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef EXPORT_SYMTAB +# define EXPORT_SYMTAB +#endif + +#define DEBUG_SUBSYSTEM S_SEC + +#include +#include +#include + +#ifdef CONFIG_FS_POSIX_ACL + +#define CFS_ACL_XATTR_VERSION POSIX_ACL_XATTR_VERSION + +enum { + ES_UNK = 0, /* unknown stat */ + ES_UNC = 1, /* ACL entry is not changed */ + ES_MOD = 2, /* ACL entry is modified */ + ES_ADD = 3, /* ACL entry is added */ + ES_DEL = 4 /* ACL entry is deleted */ +}; + +static inline void lustre_ext_acl_le_to_cpu(ext_acl_xattr_entry *d, + ext_acl_xattr_entry *s) +{ + d->e_tag = le16_to_cpu(s->e_tag); + d->e_perm = le16_to_cpu(s->e_perm); + d->e_id = le32_to_cpu(s->e_id); + d->e_stat = le32_to_cpu(s->e_stat); +} + +static inline void lustre_ext_acl_cpu_to_le(ext_acl_xattr_entry *d, + ext_acl_xattr_entry *s) +{ + d->e_tag = cpu_to_le16(s->e_tag); + d->e_perm = cpu_to_le16(s->e_perm); + d->e_id = cpu_to_le32(s->e_id); + d->e_stat = cpu_to_le32(s->e_stat); +} + +static inline void lustre_posix_acl_le_to_cpu(posix_acl_xattr_entry *d, + posix_acl_xattr_entry *s) +{ + d->e_tag = le16_to_cpu(s->e_tag); + d->e_perm = le16_to_cpu(s->e_perm); + d->e_id = le32_to_cpu(s->e_id); +} + +static inline void lustre_posix_acl_cpu_to_le(posix_acl_xattr_entry *d, + posix_acl_xattr_entry *s) +{ + d->e_tag = cpu_to_le16(s->e_tag); + d->e_perm = cpu_to_le16(s->e_perm); + d->e_id = cpu_to_le32(s->e_id); +} + +/* + * Check permission based on POSIX ACL. + */ +int lustre_posix_acl_permission(struct md_ucred *mu, struct lu_attr *la, + int want, posix_acl_xattr_entry *entry, + int count) +{ + posix_acl_xattr_entry *pa, *pe, *mask_obj; + posix_acl_xattr_entry ae, me; + int found = 0; + + if (count <= 0) + return -EACCES; + + for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) { + lustre_posix_acl_le_to_cpu(&ae, pa); + switch (ae.e_tag) { + case ACL_USER_OBJ: + /* (May have been checked already) */ + if (la->la_uid == mu->mu_fsuid) + goto check_perm; + break; + case ACL_USER: + if (ae.e_id == mu->mu_fsuid) + goto mask; + break; + case ACL_GROUP_OBJ: + if (lustre_in_group_p(mu, la->la_gid)) { + found = 1; + if ((ae.e_perm & want) == want) + goto mask; + } + break; + case ACL_GROUP: + if (lustre_in_group_p(mu, ae.e_id)) { + found = 1; + if ((ae.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++) { + lustre_posix_acl_le_to_cpu(&me, mask_obj); + if (me.e_tag == ACL_MASK) { + if ((ae.e_perm & me.e_perm & want) == want) + return 0; + + return -EACCES; + } + } + +check_perm: + if ((ae.e_perm & want) == want) + return 0; + + return -EACCES; +} +EXPORT_SYMBOL(lustre_posix_acl_permission); + +/* + * Modify the ACL for the chmod. + */ +int lustre_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; + + for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) { + switch (le16_to_cpu(pa->e_tag)) { + case ACL_USER_OBJ: + pa->e_perm = cpu_to_le16((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 = cpu_to_le16(mode & S_IRWXO); + break; + default: + return -EIO; + } + } + + if (mask_obj) { + mask_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3); + } else { + if (!group_obj) + return -EIO; + group_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3); + } + + return 0; +} +EXPORT_SYMBOL(lustre_posix_acl_chmod_masq); + +/* + * Modify acl when creating a new object. + */ +int lustre_posix_acl_create_masq(posix_acl_xattr_entry *entry, __u32 *pmode, + int count) +{ + posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe; + posix_acl_xattr_entry ae; + __u32 mode = *pmode; + int not_equiv = 0; + + for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) { + lustre_posix_acl_le_to_cpu(&ae, pa); + switch (ae.e_tag) { + case ACL_USER_OBJ: + ae.e_perm &= (mode >> 6) | ~S_IRWXO; + pa->e_perm = cpu_to_le16(ae.e_perm); + mode &= (ae.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: + ae.e_perm &= mode | ~S_IRWXO; + pa->e_perm = cpu_to_le16(ae.e_perm); + mode &= ae.e_perm | ~S_IRWXO; + break; + case ACL_MASK: + mask_obj = pa; + not_equiv = 1; + break; + default: + return -EIO; + } + } + + if (mask_obj) { + ae.e_perm = le16_to_cpu(mask_obj->e_perm) & + ((mode >> 3) | ~S_IRWXO); + mode &= (ae.e_perm << 3) | ~S_IRWXG; + mask_obj->e_perm = cpu_to_le16(ae.e_perm); + } else { + if (!group_obj) + return -EIO; + ae.e_perm = le16_to_cpu(group_obj->e_perm) & + ((mode >> 3) | ~S_IRWXO); + mode &= (ae.e_perm << 3) | ~S_IRWXG; + group_obj->e_perm = cpu_to_le16(ae.e_perm); + } + + *pmode = (*pmode & ~S_IRWXUGO) | mode; + return not_equiv; +} +EXPORT_SYMBOL(lustre_posix_acl_create_masq); + +/* if "new_count == 0", then "new = {a_version, NULL}", NOT NULL. */ +static int lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header **header, + int old_count, int new_count) +{ + int old_size = CFS_ACL_XATTR_SIZE(old_count, posix_acl_xattr); + int new_size = CFS_ACL_XATTR_SIZE(new_count, posix_acl_xattr); + posix_acl_xattr_header *new; + + if (unlikely(old_count <= new_count)) + return old_size; + + OBD_ALLOC(new, new_size); + if (unlikely(new == NULL)) + return -ENOMEM; + + memcpy(new, *header, new_size); + OBD_FREE(*header, old_size); + *header = new; + return new_size; +} + +/* if "new_count == 0", then "new = {0, NULL}", NOT NULL. */ +static int lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header **header, + int old_count) +{ + int ext_count = le32_to_cpu((*header)->a_count); + int ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr); + int old_size = CFS_ACL_XATTR_SIZE(old_count, ext_acl_xattr); + ext_acl_xattr_header *new; + + if (unlikely(old_count <= ext_count)) + return 0; + + OBD_ALLOC(new, ext_size); + if (unlikely(new == NULL)) + return -ENOMEM; + + memcpy(new, *header, ext_size); + OBD_FREE(*header, old_size); + *header = new; + return 0; +} + +/* + * Generate new extended ACL based on the posix ACL. + */ +ext_acl_xattr_header * +lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size) +{ + int count, i, esize; + ext_acl_xattr_header *new; + ENTRY; + + if (unlikely(size < 0)) + RETURN(ERR_PTR(-EINVAL)); + else if (!size) + count = 0; + else + count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr); + esize = CFS_ACL_XATTR_SIZE(count, ext_acl_xattr); + OBD_ALLOC(new, esize); + if (unlikely(new == NULL)) + RETURN(ERR_PTR(-ENOMEM)); + + new->a_count = cpu_to_le32(count); + for (i = 0; i < count; i++) { + new->a_entries[i].e_tag = header->a_entries[i].e_tag; + new->a_entries[i].e_perm = header->a_entries[i].e_perm; + new->a_entries[i].e_id = header->a_entries[i].e_id; + new->a_entries[i].e_stat = cpu_to_le32(ES_UNK); + } + + RETURN(new); +} +EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext); + +/* + * Filter out the "nobody" entries in the posix ACL. + */ +int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, int size, + posix_acl_xattr_header **out) +{ + int count, i, j, rc = 0; + __u32 id; + posix_acl_xattr_header *new; + ENTRY; + + if (unlikely(size < 0)) + RETURN(-EINVAL); + else if (!size) + RETURN(0); + + OBD_ALLOC(new, size); + if (unlikely(new == NULL)) + RETURN(-ENOMEM); + + new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION); + count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr); + for (i = 0, j = 0; i < count; i++) { + id = le32_to_cpu(header->a_entries[i].e_id); + switch (le16_to_cpu(header->a_entries[i].e_tag)) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + if (id != ACL_UNDEFINED_ID) + GOTO(_out, rc = -EIO); + + memcpy(&new->a_entries[j++], &header->a_entries[i], + sizeof(posix_acl_xattr_entry)); + break; + case ACL_USER: + if (id != NOBODY_UID) + memcpy(&new->a_entries[j++], + &header->a_entries[i], + sizeof(posix_acl_xattr_entry)); + break; + case ACL_GROUP: + if (id != NOBODY_GID) + memcpy(&new->a_entries[j++], + &header->a_entries[i], + sizeof(posix_acl_xattr_entry)); + break; + default: + GOTO(_out, rc = -EIO); + } + } + + /* free unused space. */ + rc = lustre_posix_acl_xattr_reduce_space(&new, count, j); + if (rc >= 0) { + size = rc; + *out = new; + rc = 0; + } + EXIT; + +_out: + if (rc) { + OBD_FREE(new, size); + size = rc; + } + return size; +} +EXPORT_SYMBOL(lustre_posix_acl_xattr_filter); + +/* + * Convert server-side uid/gid in the posix ACL items to the client-side ones. + * convert rule: + * @CFS_IC_NOTHING + * nothing to be converted. + * @CFS_IC_ALL + * mapped ids are converted to client-side ones, + * unmapped ones are converted to "nobody". + * @CFS_IC_MAPPED + * only mapped ids are converted to "nobody". + * @CFS_IC_UNMAPPED + * only unmapped ids are converted to "nobody". + */ +int lustre_posix_acl_xattr_id2client(struct md_ucred *mu, + struct lustre_idmap_table *t, + posix_acl_xattr_header *header, + int size, int flags) +{ + int count, i; + __u32 id; + ENTRY; + + if (unlikely(size < 0)) + RETURN(-EINVAL); + else if (!size) + RETURN(0); + + if (unlikely(flags == CFS_IC_NOTHING)) + RETURN(0); + + count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr); + for (i = 0; i < count; i++) { + id = le32_to_cpu(header->a_entries[i].e_id); + switch (le16_to_cpu(header->a_entries[i].e_tag)) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + if (id != ACL_UNDEFINED_ID) + RETURN(-EIO); + break; + case ACL_USER: + id = lustre_idmap_lookup_uid(mu, t, 1, id); + if (flags == CFS_IC_ALL) { + if (id == CFS_IDMAP_NOTFOUND) + id = NOBODY_UID; + header->a_entries[i].e_id = cpu_to_le32(id); + } else if (flags == CFS_IC_MAPPED) { + if (id != CFS_IDMAP_NOTFOUND) + header->a_entries[i].e_id = + cpu_to_le32(NOBODY_UID); + } else if (flags == CFS_IC_UNMAPPED) { + if (id == CFS_IDMAP_NOTFOUND) + header->a_entries[i].e_id = + cpu_to_le32(NOBODY_UID); + } + break; + case ACL_GROUP: + id = lustre_idmap_lookup_gid(mu, t, 1, id); + if (flags == CFS_IC_ALL) { + if (id == CFS_IDMAP_NOTFOUND) + id = NOBODY_GID; + header->a_entries[i].e_id = cpu_to_le32(id); + } else if (flags == CFS_IC_MAPPED) { + if (id != CFS_IDMAP_NOTFOUND) + header->a_entries[i].e_id = + cpu_to_le32(NOBODY_GID); + } else if (flags == CFS_IC_UNMAPPED) { + if (id == CFS_IDMAP_NOTFOUND) + header->a_entries[i].e_id = + cpu_to_le32(NOBODY_GID); + } + break; + default: + RETURN(-EIO); + } + } + RETURN(0); +} +EXPORT_SYMBOL(lustre_posix_acl_xattr_id2client); + +/* + * Release the posix ACL space. + */ +void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size) +{ + OBD_FREE(header, size); +} +EXPORT_SYMBOL(lustre_posix_acl_xattr_free); + +/* + * Converts client-side uid/gid in the extended ACL items to server-side ones. + * convert rule: + * mapped ids are converted to server-side ones, + * unmapped ones cause "EPERM" error. + */ +int lustre_ext_acl_xattr_id2server(struct md_ucred *mu, + struct lustre_idmap_table *t, + ext_acl_xattr_header *header) + +{ + int i, count = le32_to_cpu(header->a_count); + __u32 id; + ENTRY; + + for (i = 0; i < count; i++) { + id = le32_to_cpu(header->a_entries[i].e_id); + switch (le16_to_cpu(header->a_entries[i].e_tag)) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + if (id != ACL_UNDEFINED_ID) + RETURN(-EIO); + break; + case ACL_USER: + id = lustre_idmap_lookup_uid(mu, t, 0, id); + if (id == CFS_IDMAP_NOTFOUND) + RETURN(-EPERM); + else + header->a_entries[i].e_id = cpu_to_le32(id); + break; + case ACL_GROUP: + id = lustre_idmap_lookup_gid(mu, t, 0, id); + if (id == CFS_IDMAP_NOTFOUND) + RETURN(-EPERM); + else + header->a_entries[i].e_id = cpu_to_le32(id); + break; + default: + RETURN(-EIO); + } + } + RETURN(0); +} +EXPORT_SYMBOL(lustre_ext_acl_xattr_id2server); + +/* + * Release the extended ACL space. + */ +void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header) +{ + OBD_FREE(header, CFS_ACL_XATTR_SIZE(le32_to_cpu(header->a_count), \ + ext_acl_xattr)); +} +EXPORT_SYMBOL(lustre_ext_acl_xattr_free); + +static ext_acl_xattr_entry * +lustre_ext_acl_xattr_search(ext_acl_xattr_header *header, + posix_acl_xattr_entry *entry, int *pos) +{ + int once, start, end, i, j, count = le32_to_cpu(header->a_count); + + once = 0; + start = *pos; + end = count; + +again: + for (i = start; i < end; i++) { + if (header->a_entries[i].e_tag == entry->e_tag && + header->a_entries[i].e_id == entry->e_id) { + j = i; + if (++i >= count) + i = 0; + *pos = i; + return &header->a_entries[j]; + } + } + + if (!once) { + once = 1; + start = 0; + end = *pos; + goto again; + } + + return NULL; +} + +/* + * Merge the posix ACL and the extended ACL into new posix ACL. + */ +int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size, + ext_acl_xattr_header *ext_header, + posix_acl_xattr_header **out) +{ + int posix_count, posix_size, i, j; + int ext_count = le32_to_cpu(ext_header->a_count), pos = 0, rc = 0; + posix_acl_xattr_entry pe = {ACL_MASK, 0, ACL_UNDEFINED_ID}; + posix_acl_xattr_header *new; + ext_acl_xattr_entry *ee, ae; + ENTRY; + + lustre_posix_acl_cpu_to_le(&pe, &pe); + ee = lustre_ext_acl_xattr_search(ext_header, &pe, &pos); + if (ee == NULL || le32_to_cpu(ee->e_stat) == ES_DEL) { + /* there are only base ACL entries at most. */ + posix_count = 3; + posix_size = CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr); + OBD_ALLOC(new, posix_size); + if (unlikely(new == NULL)) + RETURN(-ENOMEM); + + new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION); + for (i = 0, j = 0; i < ext_count; i++) { + lustre_ext_acl_le_to_cpu(&ae, + &ext_header->a_entries[i]); + switch (ae.e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_OTHER: + if (ae.e_id != ACL_UNDEFINED_ID) + GOTO(_out, rc = -EIO); + + if (ae.e_stat != ES_DEL) { + new->a_entries[j].e_tag = + ext_header->a_entries[i].e_tag; + new->a_entries[j].e_perm = + ext_header->a_entries[i].e_perm; + new->a_entries[j++].e_id = + ext_header->a_entries[i].e_id; + } + break; + case ACL_MASK: + case ACL_USER: + case ACL_GROUP: + if (ae.e_stat == ES_DEL) + break; + default: + GOTO(_out, rc = -EIO); + } + } + } else { + /* maybe there are valid ACL_USER or ACL_GROUP entries in the + * original server-side ACL, they are regarded as ES_UNC stat.*/ + int ori_posix_count; + + if (unlikely(size < 0)) + RETURN(-EINVAL); + else if (!size) + ori_posix_count = 0; + else + ori_posix_count = + CFS_ACL_XATTR_COUNT(size, posix_acl_xattr); + posix_count = ori_posix_count + ext_count; + posix_size = + CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr); + OBD_ALLOC(new, posix_size); + if (unlikely(new == NULL)) + RETURN(-ENOMEM); + + new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION); + /* 1. process the unchanged ACL entries + * in the original server-side ACL. */ + pos = 0; + for (i = 0, j = 0; i < ori_posix_count; i++) { + ee = lustre_ext_acl_xattr_search(ext_header, + &posix_header->a_entries[i], &pos); + if (ee == NULL) + memcpy(&new->a_entries[j++], + &posix_header->a_entries[i], + sizeof(posix_acl_xattr_entry)); + } + + /* 2. process the non-deleted entries + * from client-side extended ACL. */ + for (i = 0; i < ext_count; i++) { + if (le16_to_cpu(ext_header->a_entries[i].e_stat) != + ES_DEL) { + new->a_entries[j].e_tag = + ext_header->a_entries[i].e_tag; + new->a_entries[j].e_perm = + ext_header->a_entries[i].e_perm; + new->a_entries[j++].e_id = + ext_header->a_entries[i].e_id; + } + } + } + + /* free unused space. */ + rc = lustre_posix_acl_xattr_reduce_space(&new, posix_count, j); + if (rc >= 0) { + posix_size = rc; + *out = new; + rc = 0; + } + EXIT; + +_out: + if (rc) { + OBD_FREE(new, posix_size); + posix_size = rc; + } + return posix_size; +} +EXPORT_SYMBOL(lustre_acl_xattr_merge2posix); + +/* + * Merge the posix ACL and the extended ACL into new extended ACL. + */ +ext_acl_xattr_header * +lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size, + ext_acl_xattr_header *ext_header) +{ + int ori_ext_count, posix_count, ext_count, ext_size; + int i, j, pos = 0, rc = 0; + posix_acl_xattr_entry pae; + ext_acl_xattr_header *new; + ext_acl_xattr_entry *ee, eae; + ENTRY; + + if (unlikely(size < 0)) + RETURN(ERR_PTR(-EINVAL)); + else if (!size) + posix_count = 0; + else + posix_count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr); + ori_ext_count = le32_to_cpu(ext_header->a_count); + ext_count = posix_count + ori_ext_count; + ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr); + + OBD_ALLOC(new, ext_size); + if (unlikely(new == NULL)) + RETURN(ERR_PTR(-ENOMEM)); + + for (i = 0, j = 0; i < posix_count; i++) { + lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]); + switch (pae.e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + if (pae.e_id != ACL_UNDEFINED_ID) + GOTO(out, rc = -EIO); + case ACL_USER: + /* ignore "nobody" entry. */ + if (pae.e_id == NOBODY_UID) + break; + + new->a_entries[j].e_tag = + posix_header->a_entries[i].e_tag; + new->a_entries[j].e_perm = + posix_header->a_entries[i].e_perm; + new->a_entries[j].e_id = + posix_header->a_entries[i].e_id; + ee = lustre_ext_acl_xattr_search(ext_header, + &posix_header->a_entries[i], &pos); + if (ee) { + if (posix_header->a_entries[i].e_perm != + ee->e_perm) + /* entry modified. */ + ee->e_perm = + new->a_entries[j++].e_stat = + cpu_to_le32(ES_MOD); + else + /* entry unchanged. */ + ee->e_perm = + new->a_entries[j++].e_stat = + cpu_to_le32(ES_UNC); + } else { + /* new entry. */ + new->a_entries[j++].e_stat = + cpu_to_le32(ES_ADD); + } + break; + case ACL_GROUP: + /* ignore "nobody" entry. */ + if (pae.e_id == NOBODY_GID) + break; + new->a_entries[j].e_tag = + posix_header->a_entries[i].e_tag; + new->a_entries[j].e_perm = + posix_header->a_entries[i].e_perm; + new->a_entries[j].e_id = + posix_header->a_entries[i].e_id; + ee = lustre_ext_acl_xattr_search(ext_header, + &posix_header->a_entries[i], &pos); + if (ee) { + if (posix_header->a_entries[i].e_perm != + ee->e_perm) + /* entry modified. */ + ee->e_perm = + new->a_entries[j++].e_stat = + cpu_to_le32(ES_MOD); + else + /* entry unchanged. */ + ee->e_perm = + new->a_entries[j++].e_stat = + cpu_to_le32(ES_UNC); + } else { + /* new entry. */ + new->a_entries[j++].e_stat = + cpu_to_le32(ES_ADD); + } + break; + default: + GOTO(out, rc = -EIO); + } + } + + /* process deleted entries. */ + for (i = 0; i < ori_ext_count; i++) { + lustre_ext_acl_le_to_cpu(&eae, &ext_header->a_entries[i]); + if (eae.e_stat == ES_UNK) { + /* ignore "nobody" entry. */ + if ((eae.e_tag == ACL_USER && eae.e_id == NOBODY_UID) || + (eae.e_tag == ACL_GROUP && eae.e_id == NOBODY_GID)) + continue; + + new->a_entries[j].e_tag = + ext_header->a_entries[i].e_tag; + new->a_entries[j].e_perm = + ext_header->a_entries[i].e_perm; + new->a_entries[j].e_id = ext_header->a_entries[i].e_id; + new->a_entries[j++].e_stat = cpu_to_le32(ES_DEL); + } + } + + new->a_count = cpu_to_le32(j); + /* free unused space. */ + rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count); + EXIT; + +out: + if (rc) { + OBD_FREE(new, ext_size); + new = ERR_PTR(rc); + } + return new; +} +EXPORT_SYMBOL(lustre_acl_xattr_merge2ext); + +#endif diff --git a/lustre/obdclass/genops.c b/lustre/obdclass/genops.c index ab15541..25d12e4 100644 --- a/lustre/obdclass/genops.c +++ b/lustre/obdclass/genops.c @@ -713,6 +713,8 @@ struct obd_export *class_new_export(struct obd_device *obd, INIT_HLIST_NODE(&export->exp_uuid_hash); INIT_HLIST_NODE(&export->exp_nid_hash); + export->exp_sp_peer = LUSTRE_SP_ANY; + export->exp_flvr.sf_rpc = SPTLRPC_FLVR_INVALID; export->exp_client_uuid = *cluuid; obd_init_export(export); @@ -848,6 +850,7 @@ struct obd_import *class_new_import(struct obd_device *obd) imp->imp_last_success_conn = 0; imp->imp_state = LUSTRE_IMP_NEW; imp->imp_obd = class_incref(obd); + sema_init(&imp->imp_sec_mutex, 1); cfs_waitq_init(&imp->imp_recovery_waitq); atomic_set(&imp->imp_refcount, 2); diff --git a/lustre/obdclass/idmap.c b/lustre/obdclass/idmap.c new file mode 100644 index 0000000..9f85b98 --- /dev/null +++ b/lustre/obdclass/idmap.c @@ -0,0 +1,458 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * lustre/obdclass/idmap.c + * Lustre user identity mapping. + * Author: Fan Yong + * + * Copyright (C) 2004-2007 Cluster File Systems, Inc. + * + * + * This file is part of Lustre, http://www.lustre.org. + * + * Lustre is free 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. + * + * 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 + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Lustre; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef EXPORT_SYMTAB +# define EXPORT_SYMTAB +#endif + +#define DEBUG_SUBSYSTEM S_SEC + +#include +#include + +#define lustre_get_group_info(group_info) do { \ + atomic_inc(&(group_info)->usage); \ +} while (0) + +#define lustre_put_group_info(group_info) do { \ + if (atomic_dec_and_test(&(group_info)->usage)) \ + groups_free(group_info); \ +} while (0) + +/* + * groups_search() is copied from linux kernel! + * A simple bsearch. + */ +static int lustre_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 - CFS_GROUP_AT(group_info, mid); + + if (cmp > 0) + left = mid + 1; + else if (cmp < 0) + right = mid; + else + return 1; + } + return 0; +} + +void lustre_groups_from_list(struct group_info *ginfo, gid_t *glist) +{ + int i; + int count = ginfo->ngroups; + + /* fill group_info from gid array */ + for (i = 0; i < ginfo->nblocks && count > 0; i++) { + int cp_count = min(CFS_NGROUPS_PER_BLOCK, count); + int off = i * CFS_NGROUPS_PER_BLOCK; + int len = cp_count * sizeof(*glist); + + memcpy(ginfo->blocks[i], glist + off, len); + count -= cp_count; + } +} +EXPORT_SYMBOL(lustre_groups_from_list); + +/* groups_sort() is copied from linux kernel! */ +/* a simple shell-metzner sort */ +void lustre_groups_sort(struct group_info *group_info) +{ + int base, max, stride; + int gidsetsize = group_info->ngroups; + + for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1) + ; /* nothing */ + stride /= 3; + + while (stride) { + max = gidsetsize - stride; + for (base = 0; base < max; base++) { + int left = base; + int right = left + stride; + gid_t tmp = CFS_GROUP_AT(group_info, right); + + while (left >= 0 && + CFS_GROUP_AT(group_info, left) > tmp) { + CFS_GROUP_AT(group_info, right) = + CFS_GROUP_AT(group_info, left); + right = left; + left -= stride; + } + CFS_GROUP_AT(group_info, right) = tmp; + } + stride /= 3; + } +} +EXPORT_SYMBOL(lustre_groups_sort); + +int lustre_in_group_p(struct md_ucred *mu, gid_t grp) +{ + int rc = 1; + + if (grp != mu->mu_fsgid) { + struct group_info *group_info = NULL; + + if (mu->mu_ginfo || !mu->mu_identity || + mu->mu_valid == UCRED_OLD) + if (grp == mu->mu_suppgids[0] || + grp == mu->mu_suppgids[1]) + return 1; + + if (mu->mu_ginfo) + group_info = mu->mu_ginfo; + else if (mu->mu_identity) + group_info = mu->mu_identity->mi_ginfo; + + if (!group_info) + return 0; + + lustre_get_group_info(group_info); + rc = lustre_groups_search(group_info, grp); + lustre_put_group_info(group_info); + } + return rc; +} +EXPORT_SYMBOL(lustre_in_group_p); + +struct lustre_idmap_entry { + struct list_head lie_rmt_uid_hash; /* hashed as lie_rmt_uid; */ + struct list_head lie_lcl_uid_hash; /* hashed as lie_lcl_uid; */ + struct list_head lie_rmt_gid_hash; /* hashed as lie_rmt_gid; */ + struct list_head lie_lcl_gid_hash; /* hashed as lie_lcl_gid; */ + uid_t lie_rmt_uid; /* remote uid */ + uid_t lie_lcl_uid; /* local uid */ + gid_t lie_rmt_gid; /* remote gid */ + gid_t lie_lcl_gid; /* local gid */ +}; + +static inline __u32 lustre_idmap_hashfunc(__u32 id) +{ + return id & (CFS_IDMAP_HASHSIZE - 1); +} + +static +struct lustre_idmap_entry *idmap_entry_alloc(uid_t rmt_uid, uid_t lcl_uid, + gid_t rmt_gid, gid_t lcl_gid) +{ + struct lustre_idmap_entry *e; + + OBD_ALLOC_PTR(e); + if (e == NULL) + return NULL; + + INIT_LIST_HEAD(&e->lie_rmt_uid_hash); + INIT_LIST_HEAD(&e->lie_lcl_uid_hash); + INIT_LIST_HEAD(&e->lie_rmt_gid_hash); + INIT_LIST_HEAD(&e->lie_lcl_gid_hash); + e->lie_rmt_uid = rmt_uid; + e->lie_lcl_uid = lcl_uid; + e->lie_rmt_gid = rmt_gid; + e->lie_lcl_gid = lcl_gid; + + return e; +} + +static void idmap_entry_free(struct lustre_idmap_entry *e) +{ + if (!list_empty(&e->lie_rmt_uid_hash)) + list_del(&e->lie_rmt_uid_hash); + if (!list_empty(&e->lie_lcl_uid_hash)) + list_del(&e->lie_lcl_uid_hash); + if (!list_empty(&e->lie_rmt_gid_hash)) + list_del(&e->lie_rmt_gid_hash); + if (!list_empty(&e->lie_lcl_gid_hash)) + list_del(&e->lie_lcl_gid_hash); + OBD_FREE_PTR(e); +} + +/* + * return value + * NULL: not found entry + * ERR_PTR(-EACCES): found 1(remote):N(local) mapped entry + * others: found normal entry + */ +static +struct lustre_idmap_entry *idmap_search_entry(struct lustre_idmap_table *t, + uid_t rmt_uid, uid_t lcl_uid, + gid_t rmt_gid, gid_t lcl_gid) +{ + struct list_head *head; + struct lustre_idmap_entry *e; + + head = &t->lit_idmaps[RMT_UIDMAP_IDX][lustre_idmap_hashfunc(rmt_uid)]; + list_for_each_entry(e, head, lie_rmt_uid_hash) + if (e->lie_rmt_uid == rmt_uid) { + if (e->lie_lcl_uid == lcl_uid) { + if (e->lie_rmt_gid == rmt_gid && + e->lie_lcl_gid == lcl_gid) + /* must be quaternion match */ + return e; + } else { + /* 1:N uid mapping */ + CERROR("rmt uid %u already be mapped to %u" + " (new %u)\n", e->lie_rmt_uid, + e->lie_lcl_uid, lcl_uid); + return ERR_PTR(-EACCES); + } + } + + head = &t->lit_idmaps[RMT_GIDMAP_IDX][lustre_idmap_hashfunc(rmt_gid)]; + list_for_each_entry(e, head, lie_rmt_gid_hash) + if (e->lie_rmt_gid == rmt_gid) { + if (e->lie_lcl_gid == lcl_gid) { + if (unlikely(e->lie_rmt_uid == rmt_uid && + e->lie_lcl_uid == lcl_uid)) + /* after uid mapping search above, + * we should never come here */ + LBUG(); + } else { + /* 1:N gid mapping */ + CERROR("rmt gid %u already be mapped to %u" + " (new %u)\n", e->lie_rmt_gid, + e->lie_lcl_gid, lcl_gid); + return ERR_PTR(-EACCES); + } + } + + return NULL; +} + +static __u32 idmap_lookup_uid(struct list_head *hash, int reverse, __u32 uid) +{ + struct list_head *head = &hash[lustre_idmap_hashfunc(uid)]; + struct lustre_idmap_entry *e; + + if (!reverse) { + list_for_each_entry(e, head, lie_rmt_uid_hash) + if (e->lie_rmt_uid == uid) + return e->lie_lcl_uid; + } else { + list_for_each_entry(e, head, lie_lcl_uid_hash) + if (e->lie_lcl_uid == uid) + return e->lie_rmt_uid; + } + + return CFS_IDMAP_NOTFOUND; +} + +static __u32 idmap_lookup_gid(struct list_head *hash, int reverse, __u32 gid) +{ + struct list_head *head = &hash[lustre_idmap_hashfunc(gid)]; + struct lustre_idmap_entry *e; + + if (!reverse) { + list_for_each_entry(e, head, lie_rmt_gid_hash) + if (e->lie_rmt_gid == gid) + return e->lie_lcl_gid; + } else { + list_for_each_entry(e, head, lie_lcl_gid_hash) + if (e->lie_lcl_gid == gid) + return e->lie_rmt_gid; + } + + return CFS_IDMAP_NOTFOUND; +} + +int lustre_idmap_add(struct lustre_idmap_table *t, + uid_t ruid, uid_t luid, + gid_t rgid, gid_t lgid) +{ + struct lustre_idmap_entry *e0, *e1; + + LASSERT(t); + + spin_lock(&t->lit_lock); + e0 = idmap_search_entry(t, ruid, luid, rgid, lgid); + spin_unlock(&t->lit_lock); + if (!e0) { + e0 = idmap_entry_alloc(ruid, luid, rgid, lgid); + if (!e0) + return -ENOMEM; + + spin_lock(&t->lit_lock); + e1 = idmap_search_entry(t, ruid, luid, rgid, lgid); + if (e1 == NULL) { + list_add_tail(&e0->lie_rmt_uid_hash, + &t->lit_idmaps[RMT_UIDMAP_IDX] + [lustre_idmap_hashfunc(ruid)]); + list_add_tail(&e0->lie_lcl_uid_hash, + &t->lit_idmaps[LCL_UIDMAP_IDX] + [lustre_idmap_hashfunc(luid)]); + list_add_tail(&e0->lie_rmt_gid_hash, + &t->lit_idmaps[RMT_GIDMAP_IDX] + [lustre_idmap_hashfunc(rgid)]); + list_add_tail(&e0->lie_lcl_gid_hash, + &t->lit_idmaps[LCL_GIDMAP_IDX] + [lustre_idmap_hashfunc(lgid)]); + } + spin_unlock(&t->lit_lock); + if (e1 != NULL) { + idmap_entry_free(e0); + if (IS_ERR(e1)) + return PTR_ERR(e1); + } + } else if (IS_ERR(e0)) { + return PTR_ERR(e0); + } + + return 0; +} +EXPORT_SYMBOL(lustre_idmap_add); + +int lustre_idmap_del(struct lustre_idmap_table *t, + uid_t ruid, uid_t luid, + gid_t rgid, gid_t lgid) +{ + struct lustre_idmap_entry *e; + int rc = 0; + + LASSERT(t); + + spin_lock(&t->lit_lock); + e = idmap_search_entry(t, ruid, luid, rgid, lgid); + if (IS_ERR(e)) + rc = PTR_ERR(e); + else if (e) + idmap_entry_free(e); + spin_unlock(&t->lit_lock); + + return rc; +} +EXPORT_SYMBOL(lustre_idmap_del); + +int lustre_idmap_lookup_uid(struct md_ucred *mu, + struct lustre_idmap_table *t, + int reverse, uid_t uid) +{ + struct list_head *hash; + + if (mu && (mu->mu_valid == UCRED_OLD || mu->mu_valid == UCRED_NEW)) { + if (!reverse) { + if (uid == mu->mu_o_uid) + return mu->mu_uid; + else if (uid == mu->mu_o_fsuid) + return mu->mu_fsuid; + } else { + if (uid == mu->mu_uid) + return mu->mu_o_uid; + else if (uid == mu->mu_fsuid) + return mu->mu_o_fsuid; + } + } + + if (t == NULL) + return CFS_IDMAP_NOTFOUND; + + hash = t->lit_idmaps[reverse ? LCL_UIDMAP_IDX : RMT_UIDMAP_IDX]; + + spin_lock(&t->lit_lock); + uid = idmap_lookup_uid(hash, reverse, uid); + spin_unlock(&t->lit_lock); + + return uid; +} +EXPORT_SYMBOL(lustre_idmap_lookup_uid); + +int lustre_idmap_lookup_gid(struct md_ucred *mu, struct lustre_idmap_table *t, + int reverse, gid_t gid) +{ + struct list_head *hash; + + if (mu && (mu->mu_valid == UCRED_OLD || mu->mu_valid == UCRED_NEW)) { + if (!reverse) { + if (gid == mu->mu_o_gid) + return mu->mu_gid; + else if (gid == mu->mu_o_fsgid) + return mu->mu_fsgid; + } else { + if (gid == mu->mu_gid) + return mu->mu_o_gid; + else if (gid == mu->mu_fsgid) + return mu->mu_o_fsgid; + } + } + + if (t == NULL) + return CFS_IDMAP_NOTFOUND; + + hash = t->lit_idmaps[reverse ? LCL_GIDMAP_IDX : RMT_GIDMAP_IDX]; + + spin_lock(&t->lit_lock); + gid = idmap_lookup_gid(hash, reverse, gid); + spin_unlock(&t->lit_lock); + + return gid; +} +EXPORT_SYMBOL(lustre_idmap_lookup_gid); + +struct lustre_idmap_table *lustre_idmap_init(void) +{ + struct lustre_idmap_table *t; + int i, j; + + OBD_ALLOC_PTR(t); + if(unlikely(t == NULL)) + return (ERR_PTR(-ENOMEM)); + + spin_lock_init(&t->lit_lock); + for (i = 0; i < ARRAY_SIZE(t->lit_idmaps); i++) + for (j = 0; j < ARRAY_SIZE(t->lit_idmaps[i]); j++) + INIT_LIST_HEAD(&t->lit_idmaps[i][j]); + + return t; +} +EXPORT_SYMBOL(lustre_idmap_init); + +void lustre_idmap_fini(struct lustre_idmap_table *t) +{ + struct list_head *list; + struct lustre_idmap_entry *e; + int i; + LASSERT(t); + + list = t->lit_idmaps[RMT_UIDMAP_IDX]; + spin_lock(&t->lit_lock); + for (i = 0; i < CFS_IDMAP_HASHSIZE; i++) + while (!list_empty(&list[i])) { + e = list_entry(list[i].next, struct lustre_idmap_entry, + lie_rmt_uid_hash); + idmap_entry_free(e); + } + spin_unlock(&t->lit_lock); + + OBD_FREE_PTR(t); +} +EXPORT_SYMBOL(lustre_idmap_fini); diff --git a/lustre/obdclass/obd_config.c b/lustre/obdclass/obd_config.c index 3c0da53..646e7fe 100644 --- a/lustre/obdclass/obd_config.c +++ b/lustre/obdclass/obd_config.c @@ -574,36 +574,6 @@ int class_del_conn(struct obd_device *obd, struct lustre_cfg *lcfg) RETURN(rc); } -int class_sec_flavor(struct obd_device *obd, struct lustre_cfg *lcfg) -{ - struct sec_flavor_config *conf; - ENTRY; - - if (strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) && - strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME)) { - CERROR("Can't set security flavor on obd %s\n", - obd->obd_type->typ_name); - RETURN(-EINVAL); - } - - if (LUSTRE_CFG_BUFLEN(lcfg, 1) != sizeof(*conf)) { - CERROR("invalid data\n"); - RETURN(-EINVAL); - } - - conf = &obd->u.cli.cl_sec_conf; - memcpy(conf, lustre_cfg_buf(lcfg, 1), sizeof(*conf)); - -#ifdef __BIG_ENDIAN - __swab32s(&conf->sfc_rpc_flavor); - __swab32s(&conf->sfc_bulk_csum); - __swab32s(&conf->sfc_bulk_priv); - __swab32s(&conf->sfc_flags); -#endif - - RETURN(0); -} - CFS_LIST_HEAD(lustre_profile_list); struct lustre_profile *class_get_profile(const char * prof) @@ -829,10 +799,6 @@ int class_process_config(struct lustre_cfg *lcfg) err = class_del_conn(obd, lcfg); GOTO(out, err = 0); } - case LCFG_SEC_FLAVOR: { - err = class_sec_flavor(obd, lcfg); - GOTO(out, err = 0); - } default: { err = obd_process_config(obd, sizeof(*lcfg), lcfg); GOTO(out, err); diff --git a/lustre/obdclass/obd_mount.c b/lustre/obdclass/obd_mount.c index a09dc36..9af2524 100644 --- a/lustre/obdclass/obd_mount.c +++ b/lustre/obdclass/obd_mount.c @@ -893,81 +893,10 @@ int server_mti_print(char *title, struct mgs_target_info *mti) return(0); } -static -int mti_set_sec_opts(struct mgs_target_info *mti, struct lustre_mount_data *lmd) -{ - char *s1, *s2; - - if (lmd->lmd_sec_mdt == NULL && lmd->lmd_sec_cli == NULL) { - /* just let on-disk params do its work. but we have an - * assumption that any changes of on-disk data by tune2fs - * should lead to server rewrite log. - */ - return 0; - } - - /* filter out existing sec options */ - s1 = mti->mti_params; - while (*s1) { - int clear; - - while (*s1 == ' ') - s1++; - - if (strncmp(s1, PARAM_SEC_RPC_MDT, - sizeof(PARAM_SEC_RPC_MDT) - 1) == 0 || - strncmp(s1, PARAM_SEC_RPC_CLI, - sizeof(PARAM_SEC_RPC_CLI) - 1) == 0) - clear = 1; - else - clear = 0; - - s2 = strchr(s1, ' '); - if (s2 == NULL) { - if (clear) - *s1 = '\0'; - break; - } - s2++; - if (clear) - memmove(s1, s2, strlen(s2) + 1); - else - s1 = s2; - } - - /* append sec options from lmd */ - /* FIXME add flag LDD_F_UPDATE after mountconf start supporting - * log updating. - */ - if (lmd->lmd_sec_mdt) { - if (strlen(mti->mti_params) + strlen(lmd->lmd_sec_mdt) + - sizeof(PARAM_SEC_RPC_MDT) + 1 >= sizeof(mti->mti_params)) { - CERROR("security params too big for mti\n"); - return -ENOMEM; - } - strcat(mti->mti_params, " "PARAM_SEC_RPC_MDT); - strcat(mti->mti_params, lmd->lmd_sec_mdt); - //mti->mti_flags |= LDD_F_UPDATE; - } - if (lmd->lmd_sec_cli) { - if (strlen(mti->mti_params) + strlen(lmd->lmd_sec_cli) + - sizeof(PARAM_SEC_RPC_CLI) + 2 > sizeof(mti->mti_params)) { - CERROR("security params too big for mti\n"); - return -ENOMEM; - } - strcat(mti->mti_params, " "PARAM_SEC_RPC_CLI); - strcat(mti->mti_params, lmd->lmd_sec_cli); - //mti->mti_flags |= LDD_F_UPDATE; - } - - return 0; -} - static int server_sb2mti(struct super_block *sb, struct mgs_target_info *mti) { struct lustre_sb_info *lsi = s2lsi(sb); struct lustre_disk_data *ldd = lsi->lsi_ldd; - struct lustre_mount_data *lmd = lsi->lsi_lmd; lnet_process_id_t id; int i = 0; ENTRY; @@ -1003,8 +932,7 @@ static int server_sb2mti(struct super_block *sb, struct mgs_target_info *mti) RETURN(-ENOMEM); } memcpy(mti->mti_params, ldd->ldd_params, sizeof(mti->mti_params)); - - RETURN(mti_set_sec_opts(mti, lmd)); + RETURN(0); } /* Register an old or new target with the MGS. If needed MGS will construct @@ -1221,8 +1149,6 @@ struct lustre_sb_info *lustre_init_lsi(struct super_block *sb) /* Default umount style */ lsi->lsi_flags = LSI_UMOUNT_FAILOVER; - lsi->lsi_lmd->lmd_nllu = NOBODY_UID; - lsi->lsi_lmd->lmd_nllg = NOBODY_GID; RETURN(lsi); } @@ -1249,12 +1175,6 @@ static int lustre_free_lsi(struct super_block *sb) if (lsi->lsi_lmd->lmd_profile != NULL) OBD_FREE(lsi->lsi_lmd->lmd_profile, strlen(lsi->lsi_lmd->lmd_profile) + 1); - if (lsi->lsi_lmd->lmd_sec_mdt != NULL) - OBD_FREE(lsi->lsi_lmd->lmd_sec_mdt, - strlen(lsi->lsi_lmd->lmd_sec_mdt) + 1); - if (lsi->lsi_lmd->lmd_sec_cli != NULL) - OBD_FREE(lsi->lsi_lmd->lmd_sec_cli, - strlen(lsi->lsi_lmd->lmd_sec_cli) + 1); if (lsi->lsi_lmd->lmd_opts != NULL) OBD_FREE(lsi->lsi_lmd->lmd_opts, strlen(lsi->lsi_lmd->lmd_opts) + 1); @@ -1743,10 +1663,6 @@ static void lmd_print(struct lustre_mount_data *lmd) PRINT_CMD(PRINT_MASK, "profile: %s\n", lmd->lmd_profile); PRINT_CMD(PRINT_MASK, "device: %s\n", lmd->lmd_dev); PRINT_CMD(PRINT_MASK, "flags: %x\n", lmd->lmd_flags); - if (lmd->lmd_sec_mdt) - PRINT_CMD(PRINT_MASK, "sec_mdt: %s\n", lmd->lmd_sec_mdt); - if (lmd->lmd_sec_cli) - PRINT_CMD(PRINT_MASK, "sec_cli: %s\n", lmd->lmd_sec_cli); if (lmd->lmd_opts) PRINT_CMD(PRINT_MASK, "options: %s\n", lmd->lmd_opts); for (i = 0; i < lmd->lmd_exclude_count; i++) { @@ -1837,66 +1753,6 @@ static int lmd_make_exclusion(struct lustre_mount_data *lmd, char *ptr) RETURN(rc); } -static -int lmd_set_sec_opts(char **set, char *opts, int length) -{ - if (*set) - OBD_FREE(*set, strlen(*set) + 1); - - OBD_ALLOC(*set, length + 1); - if (*set == NULL) - return -ENOMEM; - - memcpy(*set, opts, length); - (*set)[length] = '\0'; - - return 0; -} - -static -int lmd_parse_sec_opts(struct lustre_mount_data *lmd, char *ptr) -{ - char *tail; - char **set = NULL; - int length; - - /* check peer name */ - if (strncmp(ptr, "sec_mdt=", 8) == 0) { - set = &lmd->lmd_sec_mdt; - ptr += 8; - } else if (strncmp(ptr, "sec_cli=", 8) == 0) { - set = &lmd->lmd_sec_cli; - ptr += 8; - } else if (strncmp(ptr, "sec=", 4) == 0) { - /* leave 'set' be null */ - ptr += 4; - } else { - CERROR("invalid security options: %s\n", ptr); - return -EINVAL; - } - - tail = strchr(ptr, ','); - if (tail == NULL) - length = strlen(ptr); - else - length = tail - ptr; - - if (set) { - if (lmd_set_sec_opts(set, ptr, length)) - return -EINVAL; - } else { - if (lmd->lmd_sec_mdt == NULL && - lmd_set_sec_opts(&lmd->lmd_sec_mdt, ptr, length)) - return -EINVAL; - - if (lmd->lmd_sec_cli == NULL && - lmd_set_sec_opts(&lmd->lmd_sec_cli, ptr, length)) - return -EINVAL; - } - - return 0; -} - /* mount -v -t lustre uml1:uml2:/lustre-client /mnt/lustre */ static int lmd_parse(char *options, struct lustre_mount_data *lmd) { @@ -1947,17 +1803,6 @@ static int lmd_parse(char *options, struct lustre_mount_data *lmd) if (rc) goto invalid; clear++; - } else if (strncmp(s1, "nllu=", 5) == 0) { - lmd->lmd_nllu = simple_strtoul(s1 + 5, NULL, 10); - clear++; - } else if (strncmp(s1, "nllg=", 5) == 0) { - lmd->lmd_nllg = simple_strtoul(s1 + 5, NULL, 10); - clear++; - } else if (strncmp(s1, "sec", 3) == 0) { - rc = lmd_parse_sec_opts(lmd, s1); - if (rc) - goto invalid; - clear++; } /* Linux 2.4 doesn't pass the device, so we stuck it at the end of the options. */ diff --git a/lustre/obdfilter/filter.c b/lustre/obdfilter/filter.c index a99a422..457447a 100644 --- a/lustre/obdfilter/filter.c +++ b/lustre/obdfilter/filter.c @@ -1941,6 +1941,9 @@ int filter_common_setup(struct obd_device *obd, struct lustre_cfg* lcfg, INIT_LIST_HEAD(&filter->fo_llog_list); spin_lock_init(&filter->fo_llog_list_lock); + filter->fo_sptlrpc_lock = RW_LOCK_UNLOCKED; + sptlrpc_rule_set_init(&filter->fo_sptlrpc_rset); + filter->fo_fl_oss_capa = 0; INIT_LIST_HEAD(&filter->fo_capa_keys); filter->fo_capa_hash = init_capa_hash(); @@ -2335,6 +2338,8 @@ static int filter_cleanup(struct obd_device *obd) ldlm_namespace_free(obd->obd_namespace, obd->obd_force); + sptlrpc_rule_set_free(&filter->fo_sptlrpc_rset); + if (obd->u.obt.obt_sb == NULL) RETURN(0); @@ -2428,7 +2433,8 @@ static int filter_connect_internal(struct obd_export *exp, RETURN(0); } -static int filter_reconnect(struct obd_export *exp, struct obd_device *obd, +static int filter_reconnect(const struct lu_env *env, + struct obd_export *exp, struct obd_device *obd, struct obd_uuid *cluuid, struct obd_connect_data *data) { @@ -4011,9 +4017,43 @@ static int filter_process_config(struct obd_device *obd, obd_count len, struct lprocfs_static_vars lvars; int rc = 0; - lprocfs_filter_init_vars(&lvars); + switch (lcfg->lcfg_command) { + case LCFG_SPTLRPC_CONF: { + struct filter_obd *filter = &obd->u.filter; + struct sptlrpc_conf_log *log; + struct sptlrpc_rule_set tmp_rset; + + log = sptlrpc_conf_log_extract(lcfg); + if (IS_ERR(log)) { + rc = PTR_ERR(log); + break; + } + + sptlrpc_rule_set_init(&tmp_rset); + + rc = sptlrpc_rule_set_from_log(&tmp_rset, log); + if (rc) { + CERROR("obd %s: failed get sptlrpc rules: %d\n", + obd->obd_name, rc); + break; + } + + write_lock(&filter->fo_sptlrpc_lock); + sptlrpc_rule_set_free(&filter->fo_sptlrpc_rset); + filter->fo_sptlrpc_rset = tmp_rset; + write_unlock(&filter->fo_sptlrpc_lock); + + sptlrpc_target_update_exp_flavor(obd, &tmp_rset); + break; + } + default: + lprocfs_filter_init_vars(&lvars); + + rc = class_process_proc_param(PARAM_OST, lvars.obd_vars, + lcfg, obd); + break; + } - rc = class_process_proc_param(PARAM_OST, lvars.obd_vars, lcfg, obd); return rc; } diff --git a/lustre/osc/lproc_osc.c b/lustre/osc/lproc_osc.c index a011bdf..7980fd2 100644 --- a/lustre/osc/lproc_osc.c +++ b/lustre/osc/lproc_osc.c @@ -353,7 +353,6 @@ static struct lprocfs_vars lprocfs_osc_obd_vars[] = { { "prealloc_next_id", osc_rd_prealloc_next_id, 0, 0 }, { "prealloc_last_id", osc_rd_prealloc_last_id, 0, 0 }, { "checksums", osc_rd_checksum, osc_wr_checksum, 0 }, - { "sptlrpc", sptlrpc_lprocfs_rd, 0, 0 }, { "resend_count", osc_rd_resend_count, osc_wr_resend_count, 0}, { 0 } }; diff --git a/lustre/osc/osc_request.c b/lustre/osc/osc_request.c index 68686a1..1ee17bd 100644 --- a/lustre/osc/osc_request.c +++ b/lustre/osc/osc_request.c @@ -1085,7 +1085,8 @@ static int osc_brw_prep_request(int cmd, struct client_obd *cli,struct obdo *oa, /* size[REQ_REC_OFF] still sizeof (*body) */ if (opc == OST_WRITE) { - if (unlikely(cli->cl_checksum)) { + if (unlikely(cli->cl_checksum) && + req->rq_flvr.sf_bulk_csum == BULK_CSUM_ALG_NULL) { body->oa.o_valid |= OBD_MD_FLCKSUM; body->oa.o_cksum = osc_checksum_bulk(requested_nob, page_count, pga, @@ -1104,7 +1105,8 @@ static int osc_brw_prep_request(int cmd, struct client_obd *cli,struct obdo *oa, size[REPLY_REC_OFF + 1] = sizeof(__u32) * niocount; ptlrpc_req_set_repsize(req, 3, size); } else { - if (unlikely(cli->cl_checksum)) + if (unlikely(cli->cl_checksum) && + req->rq_flvr.sf_bulk_csum == BULK_CSUM_ALG_NULL) body->oa.o_valid |= OBD_MD_FLCKSUM; /* 1 RC for the whole I/O */ ptlrpc_req_set_repsize(req, 2, size); @@ -3560,7 +3562,8 @@ static int osc_llog_finish(struct obd_device *obd, int count) RETURN(rc); } -static int osc_reconnect(struct obd_export *exp, struct obd_device *obd, +static int osc_reconnect(const struct lu_env *env, + struct obd_export *exp, struct obd_device *obd, struct obd_uuid *cluuid, struct obd_connect_data *data) { @@ -3698,6 +3701,7 @@ int osc_setup(struct obd_device *obd, struct lustre_cfg *lcfg) lprocfs_osc_init_vars(&lvars); if (lprocfs_obd_setup(obd, lvars.obd_vars) == 0) { lproc_osc_attach_seqstat(obd); + sptlrpc_lprocfs_cliobd_attach(obd); ptlrpc_lprocfs_register_obd(obd); } @@ -3790,7 +3794,16 @@ static int osc_process_config(struct obd_device *obd, obd_count len, void *buf) lprocfs_osc_init_vars(&lvars); - rc = class_process_proc_param(PARAM_OSC, lvars.obd_vars, lcfg, obd); + switch (lcfg->lcfg_command) { + case LCFG_SPTLRPC_CONF: + rc = sptlrpc_cliobd_process_config(obd, lcfg); + break; + default: + rc = class_process_proc_param(PARAM_OSC, lvars.obd_vars, + lcfg, obd); + break; + } + return(rc); } diff --git a/lustre/ost/ost_handler.c b/lustre/ost/ost_handler.c index 2bc96b3..6ea1654 100644 --- a/lustre/ost/ost_handler.c +++ b/lustre/ost/ost_handler.c @@ -1112,10 +1112,8 @@ static int ost_brw_write(struct ptlrpc_request *req, struct obd_trans_info *oti) } no_reply = rc != 0; - if (rc == 0) { - /* let client retry if unwrap failed */ - rc = sptlrpc_svc_unwrap_bulk(req, desc); - } + if (rc == 0) + sptlrpc_svc_unwrap_bulk(req, desc); repbody = lustre_msg_buf(req->rq_repmsg, REPLY_REC_OFF, sizeof(*repbody)); @@ -1352,6 +1350,44 @@ static int ost_llog_handle_connect(struct obd_export *exp, RETURN(rc); } +static int filter_export_check_flavor(struct filter_obd *filter, + struct obd_export *exp, + struct ptlrpc_request *req) +{ + int rc = 0; + + /* FIXME + * this should be done in filter_connect()/filter_reconnect(), but + * we can't obtain information like NID, which stored in incoming + * request, thus can't decide what flavor to use. so we do it here. + * + * This hack should be removed after the OST stack be rewritten, just + * like what we are doing in mdt_obd_connect()/mdt_obd_reconnect(). + */ + if (exp->exp_flvr.sf_rpc != SPTLRPC_FLVR_INVALID) + return 0; + + CDEBUG(D_SEC, "from %s\n", sptlrpc_part2name(req->rq_sp_from)); + spin_lock(&exp->exp_lock); + exp->exp_sp_peer = req->rq_sp_from; + + read_lock(&filter->fo_sptlrpc_lock); + sptlrpc_rule_set_choose(&filter->fo_sptlrpc_rset, exp->exp_sp_peer, + req->rq_peer.nid, &exp->exp_flvr); + read_unlock(&filter->fo_sptlrpc_lock); + + if (exp->exp_flvr.sf_rpc != req->rq_flvr.sf_rpc) { + CERROR("invalid rpc flavor %x, expect %x, from %s\n", + req->rq_flvr.sf_rpc, exp->exp_flvr.sf_rpc, + libcfs_nid2str(req->rq_peer.nid)); + exp->exp_flvr.sf_rpc = SPTLRPC_FLVR_INVALID; + rc = -EACCES; + } + + spin_unlock(&exp->exp_lock); + + return rc; +} static int ost_filter_recovery_request(struct ptlrpc_request *req, struct obd_device *obd, int *process) @@ -1508,8 +1544,14 @@ int ost_handle(struct ptlrpc_request *req) if (OBD_FAIL_CHECK(OBD_FAIL_OST_CONNECT_NET)) RETURN(0); rc = target_handle_connect(req); - if (!rc) - obd = req->rq_export->exp_obd; + if (!rc) { + struct obd_export *exp = req->rq_export; + + obd = exp->exp_obd; + + rc = filter_export_check_flavor(&obd->u.filter, + exp, req); + } break; } case OST_DISCONNECT: diff --git a/lustre/ptlrpc/Makefile.in b/lustre/ptlrpc/Makefile.in index 381a77c..caab57d 100644 --- a/lustre/ptlrpc/Makefile.in +++ b/lustre/ptlrpc/Makefile.in @@ -14,7 +14,8 @@ ptlrpc_objs := client.o recover.o connection.o niobuf.o pack_generic.o ptlrpc_objs += events.o ptlrpc_module.o service.o pinger.o recov_thread.o ptlrpc_objs += llog_net.o llog_client.o llog_server.o import.o ptlrpcd.o ptlrpc_objs += pers.o lproc_ptlrpc.o wiretest.o layout.o -ptlrpc_objs += sec.o sec_bulk.o sec_gc.o sec_null.o sec_plain.o sec_lproc.o +ptlrpc_objs += sec.o sec_bulk.o sec_gc.o sec_config.o sec_lproc.o +ptlrpc_objs += sec_null.o sec_plain.o ptlrpc-objs := $(ldlm_objs) $(ptlrpc_objs) diff --git a/lustre/ptlrpc/autoMakefile.am b/lustre/ptlrpc/autoMakefile.am index e098d92..7d4754e 100644 --- a/lustre/ptlrpc/autoMakefile.am +++ b/lustre/ptlrpc/autoMakefile.am @@ -19,8 +19,8 @@ LDLM_COMM_SOURCES= $(top_srcdir)/lustre/ldlm/l_lock.c \ COMMON_SOURCES = client.c recover.c connection.c niobuf.c pack_generic.c \ events.c ptlrpc_module.c service.c pinger.c recov_thread.c llog_net.c \ llog_client.c llog_server.c import.c ptlrpcd.c pers.c wiretest.c \ - ptlrpc_internal.h layout.c sec.c sec_bulk.c sec_gc.c sec_null.c \ - sec_plain.c sec_lproc.c lproc_ptlrpc.c $(LDLM_COMM_SOURCES) + ptlrpc_internal.h layout.c sec.c sec_bulk.c sec_gc.c sec_config.c \ + sec_lproc.c sec_null.c sec_plain.c lproc_ptlrpc.c $(LDLM_COMM_SOURCES) if LIBLUSTRE @@ -60,6 +60,10 @@ ptlrpc_SOURCES := \ service.c \ wiretest.c \ sec.c \ + sec_bulk.c \ + sec_gc.c \ + sec_config.c \ + sec_lproc.c \ sec_null.c \ sec_plain.c \ $(LDLM_COMM_SOURCES) diff --git a/lustre/ptlrpc/gss/autoMakefile.am b/lustre/ptlrpc/gss/autoMakefile.am index 3f9be08..12c2547 100644 --- a/lustre/ptlrpc/gss/autoMakefile.am +++ b/lustre/ptlrpc/gss/autoMakefile.am @@ -10,6 +10,5 @@ if MODULES modulefs_DATA = ptlrpc_gss$(KMODEXT) endif # MODULES -DIST_SOURCES = $(ptlrpc_gss-objs:.o=.c) gss_api.h gss_asn1.h gss_err.h \ - gss_internal.h gss_krb5.h +DIST_SOURCES = *.c *.h MOSTLYCLEANFILES := @MOSTLYCLEANFILES@ diff --git a/lustre/ptlrpc/gss/gss_api.h b/lustre/ptlrpc/gss/gss_api.h index cf31747..d38e4d2 100644 --- a/lustre/ptlrpc/gss/gss_api.h +++ b/lustre/ptlrpc/gss/gss_api.h @@ -67,6 +67,7 @@ __u32 lgss_unwrap( rawobj_t *out_msg); __u32 lgss_plain_encrypt( struct gss_ctx *ctx, + int decrypt, int length, void *in_buf, void *out_buf); @@ -128,6 +129,7 @@ struct gss_api_ops { rawobj_t *out_msg); __u32 (*gss_plain_encrypt)( struct gss_ctx *ctx, + int decrypt, int length, void *in_buf, void *out_buf); diff --git a/lustre/ptlrpc/gss/gss_bulk.c b/lustre/ptlrpc/gss/gss_bulk.c index 7d4864c..9f829ad 100644 --- a/lustre/ptlrpc/gss/gss_bulk.c +++ b/lustre/ptlrpc/gss/gss_bulk.c @@ -57,6 +57,7 @@ int do_bulk_privacy(struct gss_ctx *gctx, { struct crypto_tfm *tfm; struct scatterlist sg, sg2, *sgd; + unsigned int blksize; int i, rc; __u8 local_iv[sizeof(bsd->bsd_iv)]; @@ -68,12 +69,6 @@ int do_bulk_privacy(struct gss_ctx *gctx, if (alg == BULK_PRIV_ALG_NULL) return 0; - if (encrypt) - get_random_bytes(bsd->bsd_iv, sizeof(bsd->bsd_iv)); - - /* compute the secret iv */ - lgss_plain_encrypt(gctx, sizeof(local_iv), bsd->bsd_iv, local_iv); - tfm = crypto_alloc_tfm(sptlrpc_bulk_priv_alg2name(alg), sptlrpc_bulk_priv_alg2flags(alg)); if (tfm == NULL) { @@ -82,12 +77,25 @@ int do_bulk_privacy(struct gss_ctx *gctx, return -ENOMEM; } + blksize = crypto_tfm_alg_blocksize(tfm); + LASSERT(blksize <= sizeof(local_iv)); + + if (encrypt) + get_random_bytes(bsd->bsd_iv, sizeof(bsd->bsd_iv)); + + /* compute the secret iv */ + rc = lgss_plain_encrypt(gctx, 0, + sizeof(local_iv), bsd->bsd_iv, local_iv); + if (rc) { + CERROR("failed to compute secret iv: %d\n", rc); + goto out; + } + rc = crypto_cipher_setkey(tfm, local_iv, sizeof(local_iv)); if (rc) { CERROR("Failed to set key for TFM %s: %d\n", sptlrpc_bulk_priv_alg2name(alg), rc); - crypto_free_tfm(tfm); - return rc; + goto out; } for (i = 0; i < desc->bd_iov_count; i++) { @@ -119,12 +127,12 @@ int do_bulk_privacy(struct gss_ctx *gctx, */ } - crypto_free_tfm(tfm); - if (encrypt) bsd->bsd_priv_alg = alg; - return 0; +out: + crypto_free_tfm(tfm); + return rc; } int gss_cli_ctx_wrap_bulk(struct ptlrpc_cli_ctx *ctx, @@ -134,14 +142,13 @@ int gss_cli_ctx_wrap_bulk(struct ptlrpc_cli_ctx *ctx, struct gss_cli_ctx *gctx; struct lustre_msg *msg; struct ptlrpc_bulk_sec_desc *bsdr; - struct sec_flavor_config *conf; int offset, rc; ENTRY; - LASSERT(SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)); + LASSERT(req->rq_pack_bulk); LASSERT(req->rq_bulk_read || req->rq_bulk_write); - switch (SEC_FLAVOR_SVC(req->rq_sec_flavor)) { + switch (RPC_FLVR_SVC(req->rq_flvr.sf_rpc)) { case SPTLRPC_SVC_NULL: LASSERT(req->rq_reqbuf->lm_bufcount >= 3); msg = req->rq_reqbuf; @@ -163,23 +170,22 @@ int gss_cli_ctx_wrap_bulk(struct ptlrpc_cli_ctx *ctx, } /* make checksum */ - conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf; - rc = bulk_csum_cli_request(desc, req->rq_bulk_read, conf->sfc_bulk_csum, - msg, offset); + rc = bulk_csum_cli_request(desc, req->rq_bulk_read, + req->rq_flvr.sf_bulk_csum, msg, offset); if (rc) { CERROR("client bulk %s: failed to generate checksum: %d\n", req->rq_bulk_read ? "read" : "write", rc); RETURN(rc); } - if (conf->sfc_bulk_priv == BULK_PRIV_ALG_NULL) + if (req->rq_flvr.sf_bulk_priv == BULK_PRIV_ALG_NULL) RETURN(0); /* previous bulk_csum_cli_request() has verified bsdr is good */ bsdr = lustre_msg_buf(msg, offset, 0); if (req->rq_bulk_read) { - bsdr->bsd_priv_alg = conf->sfc_bulk_priv; + bsdr->bsd_priv_alg = req->rq_flvr.sf_bulk_priv; RETURN(0); } @@ -194,7 +200,7 @@ int gss_cli_ctx_wrap_bulk(struct ptlrpc_cli_ctx *ctx, LASSERT(gctx->gc_mechctx); rc = do_bulk_privacy(gctx->gc_mechctx, desc, 1, - conf->sfc_bulk_priv, bsdr); + req->rq_flvr.sf_bulk_priv, bsdr); if (rc) CERROR("bulk write: client failed to encrypt pages\n"); @@ -211,10 +217,10 @@ int gss_cli_ctx_unwrap_bulk(struct ptlrpc_cli_ctx *ctx, int roff, voff, rc; ENTRY; - LASSERT(SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)); + LASSERT(req->rq_pack_bulk); LASSERT(req->rq_bulk_read || req->rq_bulk_write); - switch (SEC_FLAVOR_SVC(req->rq_sec_flavor)) { + switch (RPC_FLVR_SVC(req->rq_flvr.sf_rpc)) { case SPTLRPC_SVC_NULL: vmsg = req->rq_repbuf; voff = vmsg->lm_bufcount - 1; @@ -286,6 +292,7 @@ int gss_svc_unwrap_bulk(struct ptlrpc_request *req, ENTRY; LASSERT(req->rq_svc_ctx); + LASSERT(req->rq_pack_bulk); LASSERT(req->rq_bulk_write); grctx = gss_svc_ctx2reqctx(req->rq_svc_ctx); @@ -322,6 +329,7 @@ int gss_svc_wrap_bulk(struct ptlrpc_request *req, ENTRY; LASSERT(req->rq_svc_ctx); + LASSERT(req->rq_pack_bulk); LASSERT(req->rq_bulk_read); grctx = gss_svc_ctx2reqctx(req->rq_svc_ctx); diff --git a/lustre/ptlrpc/gss/gss_cli_upcall.c b/lustre/ptlrpc/gss/gss_cli_upcall.c index fed7c48..610c108 100644 --- a/lustre/ptlrpc/gss/gss_cli_upcall.c +++ b/lustre/ptlrpc/gss/gss_cli_upcall.c @@ -72,6 +72,8 @@ int ctx_init_pack_request(struct obd_import *imp, rawobj_t obj; LASSERT(msg->lm_bufcount <= 4); + LASSERT(req->rq_cli_ctx); + LASSERT(req->rq_cli_ctx->cc_sec); /* gss hdr */ ghdr = lustre_msg_buf(msg, 0, sizeof(*ghdr)); @@ -83,7 +85,9 @@ int ctx_init_pack_request(struct obd_import *imp, ghdr->gh_handle.len = 0; /* fix the user desc */ - if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) { + if (req->rq_pack_udesc) { + ghdr->gh_flags |= LUSTRE_GSS_PACK_USER; + pud = lustre_msg_buf(msg, offset, sizeof(*pud)); LASSERT(pud); pud->pud_uid = pud->pud_fsuid = uid; @@ -96,6 +100,7 @@ int ctx_init_pack_request(struct obd_import *imp, /* security payload */ p = lustre_msg_buf(msg, offset, 0); size = msg->lm_buflens[offset]; + LASSERT(p); /* 1. lustre svc type */ LASSERT(size > 4); @@ -110,7 +115,7 @@ int ctx_init_pack_request(struct obd_import *imp, /* 3. reverse context handle. actually only needed by root user, * but we send it anyway. */ - gsec = container_of(imp->imp_sec, struct gss_sec, gs_base); + gsec = sec2gsec(req->rq_cli_ctx->cc_sec); obj.len = sizeof(gsec->gs_rvs_hdl); obj.data = (__u8 *) &gsec->gs_rvs_hdl; if (rawobj_serialize(&obj, &p, &size)) @@ -205,6 +210,7 @@ int ctx_init_parse_reply(struct lustre_msg *msg, /* XXX move to where lgssd could see */ struct lgssd_ioctl_param { int version; /* in */ + int secid; /* in */ char *uuid; /* in */ int lustre_svc; /* in */ uid_t uid; /* in */ @@ -269,6 +275,14 @@ int gss_do_ctx_init_rpc(__user char *buffer, unsigned long count) goto out_copy; } + if (req->rq_cli_ctx->cc_sec->ps_id != param.secid) { + CWARN("original secid %d, now has changed to %d, " + "cancel this negotiation\n", param.secid, + req->rq_cli_ctx->cc_sec->ps_id); + param.status = -EINVAL; + goto out_copy; + } + /* get token */ rc = ctx_init_pack_request(imp, req, param.lustre_svc, @@ -340,10 +354,11 @@ int gss_do_ctx_fini_rpc(struct gss_cli_ctx *gctx) might_sleep(); - CDEBUG(D_SEC, "%s ctx %p(%u->%s)\n", - sec_is_reverse(ctx->cc_sec) ? - "server finishing reverse" : "client finishing forward", - ctx, ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec)); + CWARN("%s ctx %p idx "LPX64" (%u->%s)\n", + sec_is_reverse(ctx->cc_sec) ? + "server finishing reverse" : "client finishing forward", + ctx, gss_handle_to_u64(&gctx->gc_handle), + ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec)); gctx->gc_proc = PTLRPC_GSS_PROC_DESTROY; @@ -356,7 +371,7 @@ int gss_do_ctx_fini_rpc(struct gss_cli_ctx *gctx) } /* fix the user desc */ - if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) { + if (req->rq_pack_udesc) { /* we rely the fact that this request is in AUTH mode, * and user_desc at offset 2. */ pud = lustre_msg_buf(req->rq_reqbuf, 2, sizeof(*pud)); diff --git a/lustre/ptlrpc/gss/gss_internal.h b/lustre/ptlrpc/gss/gss_internal.h index 67083c1..6e98242 100644 --- a/lustre/ptlrpc/gss/gss_internal.h +++ b/lustre/ptlrpc/gss/gss_internal.h @@ -36,6 +36,7 @@ typedef struct rawobj_buf_s { __u8 *buf; } rawobj_buf_t; +int rawobj_empty(rawobj_t *obj); int rawobj_alloc(rawobj_t *obj, char *buf, int len); void rawobj_free(rawobj_t *obj); int rawobj_equal(rawobj_t *a, rawobj_t *b); @@ -109,6 +110,11 @@ enum ptlrpc_gss_tgt { LUSTRE_GSS_TGT_MGS = 2, }; +enum ptlrpc_gss_header_flags { + LUSTRE_GSS_PACK_BULK = 1, + LUSTRE_GSS_PACK_USER = 2, +}; + static inline __u32 import_to_gss_svc(struct obd_import *imp) { @@ -126,7 +132,9 @@ __u32 import_to_gss_svc(struct obd_import *imp) * following 3 header must have the same size and offset */ struct gss_header { - __u32 gh_version; /* gss version */ + __u8 gh_version; /* gss version */ + __u8 gh_sp; /* sec part */ + __u16 gh_pad0; __u32 gh_flags; /* wrap flags */ __u32 gh_proc; /* proc */ __u32 gh_seq; /* sequence */ @@ -138,7 +146,9 @@ struct gss_header { }; struct gss_rep_header { - __u32 gh_version; + __u8 gh_version; + __u8 gh_sp; + __u16 gh_pad0; __u32 gh_flags; __u32 gh_proc; __u32 gh_major; @@ -150,7 +160,9 @@ struct gss_rep_header { }; struct gss_err_header { - __u32 gh_version; + __u8 gh_version; + __u8 gh_sp; + __u16 gh_pad0; __u32 gh_flags; __u32 gh_proc; __u32 gh_major; @@ -166,6 +178,7 @@ struct gss_err_header { * used later by server. */ struct gss_wire_ctx { + __u32 gw_flags; __u32 gw_proc; __u32 gw_seq; __u32 gw_svc; @@ -177,6 +190,13 @@ struct gss_wire_ctx { PTLRPC_GSS_MAX_HANDLE_SIZE) +static inline __u64 gss_handle_to_u64(rawobj_t *handle) +{ + if (handle->len != PTLRPC_GSS_MAX_HANDLE_SIZE) + return -1; + return *((__u64 *) handle->data); +} + #define GSS_SEQ_WIN (2048) #define GSS_SEQ_WIN_MAIN GSS_SEQ_WIN #define GSS_SEQ_WIN_BACK (128) @@ -200,15 +220,17 @@ struct gss_svc_seq_data { }; struct gss_svc_ctx { - unsigned int gsc_usr_root:1, - gsc_usr_mds:1, - gsc_remote:1; + struct gss_ctx *gsc_mechctx; + struct gss_svc_seq_data gsc_seqdata; + rawobj_t gsc_rvs_hdl; + __u32 gsc_rvs_seq; uid_t gsc_uid; gid_t gsc_gid; uid_t gsc_mapped_uid; - rawobj_t gsc_rvs_hdl; - struct gss_svc_seq_data gsc_seqdata; - struct gss_ctx *gsc_mechctx; + unsigned int gsc_usr_root:1, + gsc_usr_mds:1, + gsc_remote:1, + gsc_reverse:1; }; struct gss_svc_reqctx { @@ -242,6 +264,8 @@ struct gss_cli_ctx { atomic_t gc_seq; rawobj_t gc_handle; struct gss_ctx *gc_mechctx; + /* handle for the buddy svc ctx */ + rawobj_t gc_svc_handle; }; struct gss_cli_ctx_keyring { @@ -271,10 +295,6 @@ struct gss_sec_pipefs { struct gss_sec_keyring { struct gss_sec gsk_base; /* - * unique sec_id. - */ - int gsk_id; - /* * all contexts listed here. access is protected by sec spinlock. */ struct hlist_head gsk_clist; @@ -337,6 +357,13 @@ struct gss_svc_reqctx *gss_svc_ctx2reqctx(struct ptlrpc_svc_ctx *ctx) return container_of(ctx, struct gss_svc_reqctx, src_base); } +static inline +struct gss_svc_ctx *gss_svc_ctx2gssctx(struct ptlrpc_svc_ctx *ctx) +{ + LASSERT(ctx); + return gss_svc_ctx2reqctx(ctx)->src_ctx; +} + /* sec_gss.c */ int gss_cli_ctx_match(struct ptlrpc_cli_ctx *ctx, struct vfs_cred *vcred); int gss_cli_ctx_display(struct ptlrpc_cli_ctx *ctx, char *buf, int bufsize); @@ -381,9 +408,9 @@ int gss_sec_create_common(struct gss_sec *gsec, struct ptlrpc_sec_policy *policy, struct obd_import *imp, struct ptlrpc_svc_ctx *ctx, - __u32 flavor, - unsigned long flags); + struct sptlrpc_flavor *sf); void gss_sec_destroy_common(struct gss_sec *gsec); +void gss_sec_kill(struct ptlrpc_sec *sec); int gss_cli_ctx_init_common(struct ptlrpc_sec *sec, struct ptlrpc_cli_ctx *ctx, @@ -395,7 +422,6 @@ int gss_cli_ctx_fini_common(struct ptlrpc_sec *sec, void gss_cli_ctx_flags2str(unsigned long flags, char *buf, int bufsize); /* gss_keyring.c */ -extern struct ptlrpc_sec_policy gss_policy_keyring; int __init gss_init_keyring(void); void __exit gss_exit_keyring(void); @@ -438,6 +464,9 @@ __u64 gss_get_next_ctx_index(void); int gss_svc_upcall_install_rvs_ctx(struct obd_import *imp, struct gss_sec *gsec, struct gss_cli_ctx *gctx); +int gss_svc_upcall_expire_rvs_ctx(rawobj_t *handle); +int gss_svc_upcall_dup_handle(rawobj_t *handle, struct gss_svc_ctx *ctx); +int gss_svc_upcall_update_sequence(rawobj_t *handle, __u32 seq); int gss_svc_upcall_handle_init(struct ptlrpc_request *req, struct gss_svc_reqctx *grctx, struct gss_wire_ctx *gw, diff --git a/lustre/ptlrpc/gss/gss_keyring.c b/lustre/ptlrpc/gss/gss_keyring.c index ca5d529..f469791 100644 --- a/lustre/ptlrpc/gss/gss_keyring.c +++ b/lustre/ptlrpc/gss/gss_keyring.c @@ -59,6 +59,10 @@ static struct key_type gss_key_type; static int sec_install_rctx_kr(struct ptlrpc_sec *sec, struct ptlrpc_svc_ctx *svc_ctx); +#ifndef task_aux +#define task_aux(tsk) (tsk) +#endif + /* * the timeout is only for the case that upcall child process die abnormally. * in any other cases it should finally update kernel key. so we set this @@ -213,37 +217,44 @@ static void ctx_destroy_kr(struct ptlrpc_cli_ctx *ctx) { struct ptlrpc_sec *sec = ctx->cc_sec; struct gss_cli_ctx_keyring *gctx_kr = ctx2gctx_keyring(ctx); - int rc; CDEBUG(D_SEC, "destroying ctx %p\n", ctx); /* at this time the association with key has been broken. */ LASSERT(sec); + LASSERT(atomic_read(&sec->ps_refcount) > 0); + LASSERT(atomic_read(&sec->ps_nctx) > 0); LASSERT(test_bit(PTLRPC_CTX_CACHED_BIT, &ctx->cc_flags) == 0); LASSERT(gctx_kr->gck_key == NULL); ctx_clear_timer_kr(ctx); LASSERT(gctx_kr->gck_timer == NULL); - rc = gss_cli_ctx_fini_common(sec, ctx); - if (rc < 0) + if (gss_cli_ctx_fini_common(sec, ctx)) return; OBD_FREE_PTR(gctx_kr); - if (rc > 0) { - CWARN("released the last ctx, proceed to destroy sec %s@%p\n", - sec->ps_policy->sp_name, sec); - sptlrpc_sec_destroy(sec); + atomic_dec(&sec->ps_nctx); + sptlrpc_sec_put(sec); +} + +static void ctx_release_kr(struct ptlrpc_cli_ctx *ctx, int sync) +{ + if (sync) { + ctx_destroy_kr(ctx); + } else { + atomic_inc(&ctx->cc_refcount); + sptlrpc_gc_add_ctx(ctx); } } -static void ctx_put_kr(struct ptlrpc_cli_ctx *ctx) +static void ctx_put_kr(struct ptlrpc_cli_ctx *ctx, int sync) { LASSERT(atomic_read(&ctx->cc_refcount) > 0); if (atomic_dec_and_test(&ctx->cc_refcount)) - ctx_destroy_kr(ctx); + ctx_release_kr(ctx, sync); } /* @@ -272,8 +283,7 @@ static inline void spin_unlock_if(spinlock_t *lock, int condition) spin_unlock(lock); } -static -void ctx_enlist_kr(struct ptlrpc_cli_ctx *ctx, int is_root, int locked) +static void ctx_enlist_kr(struct ptlrpc_cli_ctx *ctx, int is_root, int locked) { struct ptlrpc_sec *sec = ctx->cc_sec; struct gss_sec_keyring *gsec_kr = sec2gsec_keyring(sec); @@ -299,8 +309,7 @@ void ctx_enlist_kr(struct ptlrpc_cli_ctx *ctx, int is_root, int locked) * * return non-zero if we indeed unlist this ctx. */ -static -int ctx_unlist_kr(struct ptlrpc_cli_ctx *ctx, int locked) +static int ctx_unlist_kr(struct ptlrpc_cli_ctx *ctx, int locked) { struct ptlrpc_sec *sec = ctx->cc_sec; struct gss_sec_keyring *gsec_kr = sec2gsec_keyring(sec); @@ -326,8 +335,7 @@ int ctx_unlist_kr(struct ptlrpc_cli_ctx *ctx, int locked) * bind a key with a ctx together. * caller must hold write lock of the key, as well as ref on key & ctx. */ -static -void bind_key_ctx(struct key *key, struct ptlrpc_cli_ctx *ctx) +static void bind_key_ctx(struct key *key, struct ptlrpc_cli_ctx *ctx) { LASSERT(atomic_read(&ctx->cc_refcount) > 0); LASSERT(atomic_read(&key->usage) > 0); @@ -345,8 +353,7 @@ void bind_key_ctx(struct key *key, struct ptlrpc_cli_ctx *ctx) * unbind a key and a ctx. * caller must hold write lock, as well as a ref of the key. */ -static -void unbind_key_ctx(struct key *key, struct ptlrpc_cli_ctx *ctx) +static void unbind_key_ctx(struct key *key, struct ptlrpc_cli_ctx *ctx) { LASSERT(key->payload.data == ctx); LASSERT(test_bit(PTLRPC_CTX_CACHED_BIT, &ctx->cc_flags) == 0); @@ -360,7 +367,7 @@ void unbind_key_ctx(struct key *key, struct ptlrpc_cli_ctx *ctx) /* once ctx get split from key, the timer is meaningless */ ctx_clear_timer_kr(ctx); - ctx_put_kr(ctx); + ctx_put_kr(ctx, 1); key_put(key); } @@ -434,7 +441,7 @@ static void dispose_ctx_list_kr(struct hlist_head *freelist) sptlrpc_cli_ctx_wakeup(ctx); unbind_ctx_kr(ctx); - ctx_put_kr(ctx); + ctx_put_kr(ctx, 0); } } @@ -522,7 +529,7 @@ void rvs_sec_install_root_ctx_kr(struct ptlrpc_sec *sec, static void construct_key_desc(void *buf, int bufsize, struct ptlrpc_sec *sec, uid_t uid) { - snprintf(buf, bufsize, "%d@%x", uid, sec2gsec_keyring(sec)->gsk_id); + snprintf(buf, bufsize, "%d@%x", uid, sec->ps_id); ((char *)buf)[bufsize - 1] = '\0'; } @@ -530,13 +537,10 @@ static void construct_key_desc(void *buf, int bufsize, * sec apis * ****************************************/ -static atomic_t gss_sec_id_kr = ATOMIC_INIT(0); - static struct ptlrpc_sec * gss_sec_create_kr(struct obd_import *imp, - struct ptlrpc_svc_ctx *ctx, - __u32 flavor, - unsigned long flags) + struct ptlrpc_svc_ctx *svcctx, + struct sptlrpc_flavor *sf) { struct gss_sec_keyring *gsec_kr; ENTRY; @@ -545,7 +549,6 @@ struct ptlrpc_sec * gss_sec_create_kr(struct obd_import *imp, if (gsec_kr == NULL) RETURN(NULL); - gsec_kr->gsk_id = atomic_inc_return(&gss_sec_id_kr); CFS_INIT_HLIST_HEAD(&gsec_kr->gsk_clist); gsec_kr->gsk_root_ctx = NULL; mutex_init(&gsec_kr->gsk_root_uc_lock); @@ -554,14 +557,13 @@ struct ptlrpc_sec * gss_sec_create_kr(struct obd_import *imp, #endif if (gss_sec_create_common(&gsec_kr->gsk_base, &gss_policy_keyring, - imp, ctx, flavor, flags)) + imp, svcctx, sf)) goto err_free; - if (ctx != NULL) { - if (sec_install_rctx_kr(&gsec_kr->gsk_base.gs_base, ctx)) { - gss_sec_destroy_common(&gsec_kr->gsk_base); - goto err_free; - } + if (svcctx != NULL && + sec_install_rctx_kr(&gsec_kr->gsk_base.gs_base, svcctx)) { + gss_sec_destroy_common(&gsec_kr->gsk_base); + goto err_free; } RETURN(&gsec_kr->gsk_base.gs_base); @@ -587,16 +589,14 @@ void gss_sec_destroy_kr(struct ptlrpc_sec *sec) OBD_FREE(gsec_kr, sizeof(*gsec_kr)); } -static -int user_is_root(struct ptlrpc_sec *sec, struct vfs_cred *vcred) +static inline int user_is_root(struct ptlrpc_sec *sec, struct vfs_cred *vcred) { - if (sec->ps_flags & PTLRPC_SEC_FL_ROOTONLY) + /* except the ROOTONLY flag, treat it as root user only if real uid + * is 0, euid/fsuid being 0 are handled as setuid scenarios */ + if (sec_is_rootonly(sec) || (vcred->vc_uid == 0)) return 1; - - /* FIXME - * more precisely deal with setuid. maybe add more infomation - * into vfs_cred ?? */ - return (vcred->vc_uid == 0); + else + return 0; } /* @@ -654,7 +654,7 @@ struct ptlrpc_cli_ctx * gss_sec_lookup_ctx_kr(struct ptlrpc_sec *sec, struct key *key; char desc[24]; char *coinfo; - const int coinfo_size = sizeof(struct obd_uuid) + 64; + int coinfo_size; char *co_flags = ""; ENTRY; @@ -691,15 +691,29 @@ struct ptlrpc_cli_ctx * gss_sec_lookup_ctx_kr(struct ptlrpc_sec *sec, co_flags = "r"; } + /* in case of setuid, key will be constructed as owner of fsuid/fsgid, + * but we do authentication based on real uid/gid. the key permission + * bits will be exactly as POS_ALL, so only processes who subscribed + * this key could have the access, although the quota might be counted + * on others (fsuid/fsgid). + * + * keyring will use fsuid/fsgid as upcall parameters, so we have to + * encode real uid/gid into callout info. + */ + construct_key_desc(desc, sizeof(desc), sec, vcred->vc_uid); - /* callout info: mech:flags:svc_type:peer_nid:target_uuid */ + /* callout info format: + * secid:mech:uid:gid:flags:svc_type:peer_nid:target_uuid + */ + coinfo_size = sizeof(struct obd_uuid) + MAX_OBD_NAME + 64; OBD_ALLOC(coinfo, coinfo_size); if (coinfo == NULL) goto out; - snprintf(coinfo, coinfo_size, "%s:%s:%d:"LPX64":%s", - sec2gsec(sec)->gs_mech->gm_name, + snprintf(coinfo, coinfo_size, "%d:%s:%u:%u:%s:%d:"LPX64":%s", + sec->ps_id, sec2gsec(sec)->gs_mech->gm_name, + vcred->vc_uid, vcred->vc_gid, co_flags, import_to_gss_svc(imp), imp->imp_connection->c_peer.nid, imp->imp_obd->obd_name); @@ -769,14 +783,9 @@ void gss_sec_release_ctx_kr(struct ptlrpc_sec *sec, struct ptlrpc_cli_ctx *ctx, int sync) { + LASSERT(atomic_read(&sec->ps_refcount) > 0); LASSERT(atomic_read(&ctx->cc_refcount) == 0); - - if (sync) { - ctx_destroy_kr(ctx); - } else { - atomic_inc(&ctx->cc_refcount); - sptlrpc_gc_add_ctx(ctx); - } + ctx_release_kr(ctx, sync); } /* @@ -865,13 +874,12 @@ void flush_spec_ctx_cache_kr(struct ptlrpc_sec *sec, atomic_inc(&ctx->cc_refcount); - if (ctx_unlist_kr(ctx, 1)) + if (ctx_unlist_kr(ctx, 1)) { hlist_add_head(&ctx->cc_cache, &freelist); - else { + } else { LASSERT(atomic_read(&ctx->cc_refcount) >= 2); atomic_dec(&ctx->cc_refcount); } - } spin_unlock(&sec->ps_lock); @@ -886,8 +894,8 @@ int gss_sec_flush_ctx_cache_kr(struct ptlrpc_sec *sec, { ENTRY; - CDEBUG(D_SEC, "sec %p(%d, busy %d), uid %d, grace %d, force %d\n", - sec, atomic_read(&sec->ps_refcount), atomic_read(&sec->ps_busy), + CDEBUG(D_SEC, "sec %p(%d, nctx %d), uid %d, grace %d, force %d\n", + sec, atomic_read(&sec->ps_refcount), atomic_read(&sec->ps_nctx), uid, grace, force); if (uid != -1 && uid != 0) @@ -932,25 +940,21 @@ void gss_sec_gc_ctx_kr(struct ptlrpc_sec *sec) } static -int gss_sec_display_kr(struct ptlrpc_sec *sec, char *buf, int bufsize) +int gss_sec_display_kr(struct ptlrpc_sec *sec, struct seq_file *seq) { struct gss_sec_keyring *gsec_kr = sec2gsec_keyring(sec); struct hlist_node *pos, *next; struct ptlrpc_cli_ctx *ctx; - int written = 0; + struct gss_cli_ctx *gctx; + time_t now = cfs_time_current_sec(); ENTRY; - written = snprintf(buf, bufsize, "context list ===>\n"); - bufsize -= written; - buf += written; - spin_lock(&sec->ps_lock); hlist_for_each_entry_safe(ctx, pos, next, &gsec_kr->gsk_clist, cc_cache) { - struct gss_cli_ctx *gctx; struct key *key; char flags_str[40]; - int len; + char mech[40]; gctx = ctx2gctx(ctx); key = ctx2gctx_keyring(ctx)->gck_key; @@ -958,40 +962,31 @@ int gss_sec_display_kr(struct ptlrpc_sec *sec, char *buf, int bufsize) gss_cli_ctx_flags2str(ctx->cc_flags, flags_str, sizeof(flags_str)); - len = snprintf(buf, bufsize, "%p(%d): uid %u, exp %ld(%ld)s, " - "fl %s, seq %d, win %u, key %08x(%d), ", - ctx, atomic_read(&ctx->cc_refcount), - ctx->cc_vcred.vc_uid, - ctx->cc_expire, - ctx->cc_expire - cfs_time_current_sec(), - flags_str, - atomic_read(&gctx->gc_seq), - gctx->gc_win, - key ? key->serial : 0, - key ? atomic_read(&key->usage) : 0); - - written += len; - buf += len; - bufsize -= len; - - if (bufsize <= 0) - break; - if (gctx->gc_mechctx) - len = lgss_display(gctx->gc_mechctx, buf, bufsize); + lgss_display(gctx->gc_mechctx, mech, sizeof(mech)); else - len = snprintf(buf, bufsize, "mech N/A\n"); - - written += len; - buf += len; - bufsize -= len; - - if (bufsize <= 0) - break; + snprintf(mech, sizeof(mech), "N/A"); + mech[sizeof(mech) - 1] = '\0'; + + seq_printf(seq, "%p: uid %u, ref %d, expire %ld(%+ld), fl %s, " + "seq %d, win %u, key %08x(ref %d), " + "hdl "LPX64":"LPX64", mech: %s\n", + ctx, ctx->cc_vcred.vc_uid, + atomic_read(&ctx->cc_refcount), + ctx->cc_expire, + ctx->cc_expire ? ctx->cc_expire - now : 0, + flags_str, + atomic_read(&gctx->gc_seq), + gctx->gc_win, + key ? key->serial : 0, + key ? atomic_read(&key->usage) : 0, + gss_handle_to_u64(&gctx->gc_handle), + gss_handle_to_u64(&gctx->gc_svc_handle), + mech); } spin_unlock(&sec->ps_lock); - RETURN(written); + RETURN(0); } /**************************************** @@ -1063,13 +1058,13 @@ int sec_install_rctx_kr(struct ptlrpc_sec *sec, if (rc) { CERROR("failed copy reverse cli ctx: %d\n", rc); - ctx_put_kr(cli_ctx); + ctx_put_kr(cli_ctx, 1); return rc; } rvs_sec_install_root_ctx_kr(sec, cli_ctx, NULL); - ctx_put_kr(cli_ctx); + ctx_put_kr(cli_ctx, 1); return 0; } @@ -1123,7 +1118,7 @@ int sec_install_rctx_kr(struct ptlrpc_sec *sec, rvs_sec_install_root_ctx_kr(sec, cli_ctx, key); - ctx_put_kr(cli_ctx); + ctx_put_kr(cli_ctx, 1); up_write(&key->sem); rc = 0; @@ -1133,7 +1128,7 @@ out: return rc; err_put: - ctx_put_kr(cli_ctx); + ctx_put_kr(cli_ctx, 1); err_up: up_write(&key->sem); err_revoke: @@ -1157,9 +1152,16 @@ static int gss_svc_install_rctx_kr(struct obd_import *imp, struct ptlrpc_svc_ctx *svc_ctx) { - LASSERT(imp->imp_sec); + struct ptlrpc_sec *sec; + int rc; - return sec_install_rctx_kr(imp->imp_sec, svc_ctx); + sec = sptlrpc_import_sec_ref(imp); + LASSERT(sec); + + rc = sec_install_rctx_kr(sec, svc_ctx); + sptlrpc_sec_put(sec); + + return rc; } /**************************************** @@ -1169,6 +1171,7 @@ int gss_svc_install_rctx_kr(struct obd_import *imp, static int gss_kt_instantiate(struct key *key, const void *data, size_t datalen) { + int rc; ENTRY; if (data != NULL || datalen != 0) { @@ -1181,8 +1184,26 @@ int gss_kt_instantiate(struct key *key, const void *data, size_t datalen) RETURN(-EINVAL); } - /* XXX */ - key->perm |= KEY_POS_ALL | KEY_USR_ALL; + /* link the key to session keyring, so following context negotiation + * rpc fired from user space could find this key. This will be unlinked + * automatically when upcall processes die. + * + * we can't do this through keyctl from userspace, because the upcall + * might be neither possessor nor owner of the key (setuid). + * + * the session keyring is created upon upcall, and don't change all + * the way until upcall finished, so rcu lock is not needed here. + */ + LASSERT(cfs_current()->signal->session_keyring); + + rc = key_link(cfs_current()->signal->session_keyring, key); + if (unlikely(rc)) { + CERROR("failed to link key %08x to keyring %08x: %d\n", + key->serial, + cfs_current()->signal->session_keyring->serial, rc); + RETURN(rc); + } + CDEBUG(D_SEC, "key %p instantiated, ctx %p\n", key, key->payload.data); RETURN(0); } @@ -1365,6 +1386,7 @@ static struct ptlrpc_ctx_ops gss_keyring_ctxops = { static struct ptlrpc_sec_cops gss_sec_keyring_cops = { .create_sec = gss_sec_create_kr, .destroy_sec = gss_sec_destroy_kr, + .kill_sec = gss_sec_kill, .lookup_ctx = gss_sec_lookup_ctx_kr, .release_ctx = gss_sec_release_ctx_kr, .flush_ctx_cache = gss_sec_flush_ctx_cache_kr, diff --git a/lustre/ptlrpc/gss/gss_krb5_mech.c b/lustre/ptlrpc/gss/gss_krb5_mech.c index 50dcace..c2e068a 100644 --- a/lustre/ptlrpc/gss/gss_krb5_mech.c +++ b/lustre/ptlrpc/gss/gss_krb5_mech.c @@ -1167,6 +1167,7 @@ out_free: static __u32 gss_plain_encrypt_kerberos(struct gss_ctx *ctx, + int decrypt, int length, void *in_buf, void *out_buf) @@ -1174,7 +1175,7 @@ __u32 gss_plain_encrypt_kerberos(struct gss_ctx *ctx, struct krb5_ctx *kctx = ctx->internal_ctx_id; __u32 rc; - rc = krb5_encrypt(kctx->kc_keye.kb_tfm, 0, + rc = krb5_encrypt(kctx->kc_keye.kb_tfm, decrypt, NULL, in_buf, out_buf, length); if (rc) CERROR("plain encrypt error: %d\n", rc); @@ -1189,7 +1190,7 @@ int gss_display_kerberos(struct gss_ctx *ctx, struct krb5_ctx *kctx = ctx->internal_ctx_id; int written; - written = snprintf(buf, bufsize, "mech: krb5 (%s)\n", + written = snprintf(buf, bufsize, "krb5 (%s)", enctype2str(kctx->kc_enctype)); return written; } diff --git a/lustre/ptlrpc/gss/gss_mech_switch.c b/lustre/ptlrpc/gss/gss_mech_switch.c index 6e6386f..9b2965d 100644 --- a/lustre/ptlrpc/gss/gss_mech_switch.c +++ b/lustre/ptlrpc/gss/gss_mech_switch.c @@ -290,6 +290,7 @@ __u32 lgss_unwrap(struct gss_ctx *context_handle, __u32 lgss_plain_encrypt(struct gss_ctx *ctx, + int decrypt, int length, void *in_buf, void *out_buf) @@ -300,7 +301,7 @@ __u32 lgss_plain_encrypt(struct gss_ctx *ctx, LASSERT(ctx->mech_type->gm_ops->gss_plain_encrypt); return ctx->mech_type->gm_ops - ->gss_plain_encrypt(ctx, length, in_buf, out_buf); + ->gss_plain_encrypt(ctx, decrypt, length, in_buf, out_buf); } /* gss_delete_sec_context: free all resources associated with context_handle. diff --git a/lustre/ptlrpc/gss/gss_pipefs.c b/lustre/ptlrpc/gss/gss_pipefs.c index d0a3456..53caace 100644 --- a/lustre/ptlrpc/gss/gss_pipefs.c +++ b/lustre/ptlrpc/gss/gss_pipefs.c @@ -120,19 +120,14 @@ static void ctx_destroy_pf(struct ptlrpc_sec *sec, struct ptlrpc_cli_ctx *ctx) { struct gss_cli_ctx *gctx = ctx2gctx(ctx); - int rc; - rc = gss_cli_ctx_fini_common(sec, ctx); - if (rc < 0) + if (gss_cli_ctx_fini_common(sec, ctx)) return; OBD_FREE_PTR(gctx); - if (rc > 0) { - CWARN("released the last ctx, proceed to destroy sec %s@%p\n", - sec->ps_policy->sp_name, sec); - sptlrpc_sec_destroy(sec); - } + atomic_dec(&sec->ps_nctx); + sptlrpc_sec_put(sec); } static @@ -292,7 +287,6 @@ void gss_sec_ctx_replace_pf(struct gss_sec *gsec, } ctx_enhash_pf(new, &gsec_pf->gsp_chash[hash]); - atomic_inc(&gsec->gs_base.ps_busy); spin_unlock(&gsec->gs_base.ps_lock); @@ -353,8 +347,7 @@ void gss_ctx_cache_gc_pf(struct gss_sec_pipefs *gsec_pf, static struct ptlrpc_sec* gss_sec_create_pf(struct obd_import *imp, struct ptlrpc_svc_ctx *ctx, - __u32 flavor, - unsigned long flags) + struct sptlrpc_flavor *sf) { struct gss_sec_pipefs *gsec_pf; int alloc_size, hash_size, i; @@ -362,7 +355,8 @@ struct ptlrpc_sec* gss_sec_create_pf(struct obd_import *imp, #define GSS_SEC_PIPEFS_CTX_HASH_SIZE (32) - if (ctx || flags & (PTLRPC_SEC_FL_ROOTONLY | PTLRPC_SEC_FL_REVERSE)) + if (ctx || + sf->sf_flags & (PTLRPC_SEC_FL_ROOTONLY | PTLRPC_SEC_FL_REVERSE)) hash_size = 1; else hash_size = GSS_SEC_PIPEFS_CTX_HASH_SIZE; @@ -379,7 +373,7 @@ struct ptlrpc_sec* gss_sec_create_pf(struct obd_import *imp, CFS_INIT_HLIST_HEAD(&gsec_pf->gsp_chash[i]); if (gss_sec_create_common(&gsec_pf->gsp_base, &gss_policy_pipefs, - imp, ctx, flavor, flags)) + imp, ctx, sf)) goto err_free; if (ctx == NULL) { @@ -609,13 +603,15 @@ static int gss_svc_install_rctx_pf(struct obd_import *imp, struct ptlrpc_svc_ctx *ctx) { - struct gss_sec *gsec; + struct ptlrpc_sec *sec; + int rc; - LASSERT(imp->imp_sec); - LASSERT(ctx); + sec = sptlrpc_import_sec_ref(imp); + LASSERT(sec); + rc = gss_install_rvs_cli_ctx_pf(sec2gsec(sec), ctx); - gsec = container_of(imp->imp_sec, struct gss_sec, gs_base); - return gss_install_rvs_cli_ctx_pf(gsec, ctx); + sptlrpc_sec_put(sec); + return rc; } /**************************************** @@ -1154,6 +1150,7 @@ static struct ptlrpc_ctx_ops gss_pipefs_ctxops = { static struct ptlrpc_sec_cops gss_sec_pipefs_cops = { .create_sec = gss_sec_create_pf, .destroy_sec = gss_sec_destroy_pf, + .kill_sec = gss_sec_kill, .lookup_ctx = gss_sec_lookup_ctx_pf, .release_ctx = gss_sec_release_ctx_pf, .flush_ctx_cache = gss_sec_flush_ctx_cache_pf, diff --git a/lustre/ptlrpc/gss/gss_rawobj.c b/lustre/ptlrpc/gss/gss_rawobj.c index 75343c9..5765f41 100644 --- a/lustre/ptlrpc/gss/gss_rawobj.c +++ b/lustre/ptlrpc/gss/gss_rawobj.c @@ -34,6 +34,12 @@ #include "gss_internal.h" +int rawobj_empty(rawobj_t *obj) +{ + LASSERT(equi(obj->len, obj->data)); + return (obj->len == 0); +} + int rawobj_alloc(rawobj_t *obj, char *buf, int len) { LASSERT(obj); diff --git a/lustre/ptlrpc/gss/gss_svc_upcall.c b/lustre/ptlrpc/gss/gss_svc_upcall.c index 76c6b4d..72438ae 100644 --- a/lustre/ptlrpc/gss/gss_svc_upcall.c +++ b/lustre/ptlrpc/gss/gss_svc_upcall.c @@ -54,12 +54,11 @@ #include #include #include +#include #else #include #endif -#include - #include #include #include @@ -88,8 +87,7 @@ __u64 gss_get_next_ctx_index(void) return idx; } -static inline -unsigned long hash_mem(char *buf, int length, int bits) +static inline unsigned long hash_mem(char *buf, int length, int bits) { unsigned long hash = 0; unsigned long l = 0; @@ -135,8 +133,7 @@ static struct cache_head *rsi_table[RSI_HASHMAX]; static struct cache_detail rsi_cache; static struct rsi *rsi_lookup(struct rsi *item, int set); -static -void rsi_free(struct rsi *rsi) +static void rsi_free(struct rsi *rsi) { rawobj_free(&rsi->in_handle); rawobj_free(&rsi->in_token); @@ -144,8 +141,7 @@ void rsi_free(struct rsi *rsi) rawobj_free(&rsi->out_token); } -static -void rsi_put(struct cache_head *item, struct cache_detail *cd) +static void rsi_put(struct cache_head *item, struct cache_detail *cd) { struct rsi *rsi = container_of(item, struct rsi, h); @@ -158,8 +154,7 @@ void rsi_put(struct cache_head *item, struct cache_detail *cd) } } -static inline -int rsi_hash(struct rsi *item) +static inline int rsi_hash(struct rsi *item) { return hash_mem((char *)item->in_handle.data, item->in_handle.len, RSI_HASHBITS) ^ @@ -167,15 +162,13 @@ int rsi_hash(struct rsi *item) RSI_HASHBITS); } -static inline -int rsi_match(struct rsi *item, struct rsi *tmp) +static inline int rsi_match(struct rsi *item, struct rsi *tmp) { return (rawobj_equal(&item->in_handle, &tmp->in_handle) && rawobj_equal(&item->in_token, &tmp->in_token)); } -static -void rsi_request(struct cache_detail *cd, +static void rsi_request(struct cache_detail *cd, struct cache_head *h, char **bpp, int *blen) { @@ -195,8 +188,7 @@ void rsi_request(struct cache_detail *cd, (*bpp)[-1] = '\n'; } -static inline -void rsi_init(struct rsi *new, struct rsi *item) +static inline void rsi_init(struct rsi *new, struct rsi *item) { new->out_handle = RAWOBJ_EMPTY; new->out_token = RAWOBJ_EMPTY; @@ -211,8 +203,7 @@ void rsi_init(struct rsi *new, struct rsi *item) init_waitqueue_head(&new->waitq); } -static inline -void rsi_update(struct rsi *new, struct rsi *item) +static inline void rsi_update(struct rsi *new, struct rsi *item) { LASSERT(new->out_handle.len == 0); LASSERT(new->out_token.len == 0); @@ -226,8 +217,7 @@ void rsi_update(struct rsi *new, struct rsi *item) new->minor_status = item->minor_status; } -static -int rsi_parse(struct cache_detail *cd, char *mesg, int mlen) +static int rsi_parse(struct cache_detail *cd, char *mesg, int mlen) { char *buf = mesg; char *ep; @@ -343,16 +333,14 @@ static struct cache_head *rsc_table[RSC_HASHMAX]; static struct cache_detail rsc_cache; static struct rsc *rsc_lookup(struct rsc *item, int set); -static -void rsc_free(struct rsc *rsci) +static void rsc_free(struct rsc *rsci) { rawobj_free(&rsci->handle); rawobj_free(&rsci->ctx.gsc_rvs_hdl); lgss_delete_sec_context(&rsci->ctx.gsc_mechctx); } -static -void rsc_put(struct cache_head *item, struct cache_detail *cd) +static void rsc_put(struct cache_head *item, struct cache_detail *cd) { struct rsc *rsci = container_of(item, struct rsc, h); @@ -365,21 +353,18 @@ void rsc_put(struct cache_head *item, struct cache_detail *cd) } } -static inline -int rsc_hash(struct rsc *rsci) +static inline int rsc_hash(struct rsc *rsci) { return hash_mem((char *)rsci->handle.data, rsci->handle.len, RSC_HASHBITS); } -static inline -int rsc_match(struct rsc *new, struct rsc *tmp) +static inline int rsc_match(struct rsc *new, struct rsc *tmp) { return rawobj_equal(&new->handle, &tmp->handle); } -static inline -void rsc_init(struct rsc *new, struct rsc *tmp) +static inline void rsc_init(struct rsc *new, struct rsc *tmp) { new->handle = tmp->handle; tmp->handle = RAWOBJ_EMPTY; @@ -389,8 +374,7 @@ void rsc_init(struct rsc *new, struct rsc *tmp) new->ctx.gsc_rvs_hdl = RAWOBJ_EMPTY; } -static inline -void rsc_update(struct rsc *new, struct rsc *tmp) +static inline void rsc_update(struct rsc *new, struct rsc *tmp) { new->ctx = tmp->ctx; tmp->ctx.gsc_rvs_hdl = RAWOBJ_EMPTY; @@ -400,8 +384,7 @@ void rsc_update(struct rsc *new, struct rsc *tmp) spin_lock_init(&new->ctx.gsc_seqdata.ssd_lock); } -static -int rsc_parse(struct cache_detail *cd, char *mesg, int mlen) +static int rsc_parse(struct cache_detail *cd, char *mesg, int mlen) { char *buf = mesg; int len, rv, tmp_int; @@ -527,8 +510,7 @@ out: typedef int rsc_entry_match(struct rsc *rscp, long data); -static -void rsc_flush(rsc_entry_match *match, long data) +static void rsc_flush(rsc_entry_match *match, long data) { struct cache_head **ch; struct rsc *rscp; @@ -558,22 +540,19 @@ void rsc_flush(rsc_entry_match *match, long data) EXIT; } -static -int match_uid(struct rsc *rscp, long uid) +static int match_uid(struct rsc *rscp, long uid) { if ((int) uid == -1) return 1; return ((int) rscp->ctx.gsc_uid == (int) uid); } -static -int match_target(struct rsc *rscp, long target) +static int match_target(struct rsc *rscp, long target) { return (rscp->target == (struct obd_device *) target); } -static inline -void rsc_flush_uid(int uid) +static inline void rsc_flush_uid(int uid) { if (uid == -1) CWARN("flush all gss contexts...\n"); @@ -581,8 +560,7 @@ void rsc_flush_uid(int uid) rsc_flush(match_uid, (long) uid); } -static inline -void rsc_flush_target(struct obd_device *target) +static inline void rsc_flush_target(struct obd_device *target) { rsc_flush(match_target, (long) target); } @@ -603,8 +581,7 @@ static struct cache_detail rsc_cache = { static DefineSimpleCacheLookup(rsc, 0); -static -struct rsc *gss_svc_searchbyctx(rawobj_t *handle) +static struct rsc *gss_svc_searchbyctx(rawobj_t *handle) { struct rsc rsci; struct rsc *found; @@ -658,17 +635,63 @@ int gss_svc_upcall_install_rvs_ctx(struct obd_import *imp, rscp = rsc_lookup(&rsci, 1); rsc_free(&rsci); - if (rscp) - rsc_put(&rscp->h, &rsc_cache); + if (rscp) { + /* FIXME */ + rscp->ctx.gsc_usr_root = 1; + rscp->ctx.gsc_usr_mds= 1; + rscp->ctx.gsc_reverse = 1; + + rawobj_dup(&gctx->gc_svc_handle, &rscp->handle); - CDEBUG(D_SEC, "client installed reverse svc ctx to %s: idx "LPX64"\n", - imp->imp_obd->u.cli.cl_target_uuid.uuid, gsec->gs_rvs_hdl); + CWARN("create reverse svc ctx %p to %s: idx "LPX64"\n", + &rscp->ctx, obd2cli_tgt(imp->imp_obd), + gsec->gs_rvs_hdl); + + rsc_put(&rscp->h, &rsc_cache); + } RETURN(0); } -static -struct cache_deferred_req* cache_upcall_defer(struct cache_req *req) +int gss_svc_upcall_expire_rvs_ctx(rawobj_t *handle) +{ + const cfs_time_t expire = 20; + struct rsc *rscp; + + rscp = gss_svc_searchbyctx(handle); + if (rscp) { + CDEBUG(D_SEC, "reverse svcctx %p (rsc %p) expire soon\n", + &rscp->ctx, rscp); + + rscp->h.expiry_time = cfs_time_current_sec() + expire; + rsc_put(&rscp->h, &rsc_cache); + } + return 0; +} + +int gss_svc_upcall_dup_handle(rawobj_t *handle, struct gss_svc_ctx *ctx) +{ + struct rsc *rscp = container_of(ctx, struct rsc, ctx); + + return rawobj_dup(handle, &rscp->handle); +} + +int gss_svc_upcall_update_sequence(rawobj_t *handle, __u32 seq) +{ + struct rsc *rscp; + + rscp = gss_svc_searchbyctx(handle); + if (rscp) { + CDEBUG(D_SEC, "reverse svcctx %p (rsc %p) update seq to %u\n", + &rscp->ctx, rscp, seq + 1); + + rscp->ctx.gsc_rvs_seq = seq + 1; + rsc_put(&rscp->h, &rsc_cache); + } + return 0; +} + +static struct cache_deferred_req* cache_upcall_defer(struct cache_req *req) { return NULL; } @@ -844,6 +867,9 @@ out: /* if anything went wrong, we don't keep the context too */ if (rc != SECSVC_OK) set_bit(CACHE_NEGATIVE, &rsci->h.flags); + else + CDEBUG(D_SEC, "create rsc with idx "LPX64"\n", + gss_handle_to_u64(&rsci->handle)); rsc_put(&rsci->h, &rsc_cache); } @@ -857,7 +883,8 @@ struct gss_svc_ctx *gss_svc_upcall_get_ctx(struct ptlrpc_request *req, rsc = gss_svc_searchbyctx(&gw->gw_handle); if (!rsc) { - CWARN("Invalid gss context handle from %s\n", + CWARN("Invalid gss ctx idx "LPX64" from %s\n", + gss_handle_to_u64(&gw->gw_handle), libcfs_nid2str(req->rq_peer.nid)); return NULL; } @@ -876,7 +903,10 @@ void gss_svc_upcall_destroy_ctx(struct gss_svc_ctx *ctx) { struct rsc *rsc = container_of(ctx, struct rsc, ctx); + /* can't be found */ set_bit(CACHE_NEGATIVE, &rsc->h.flags); + /* to be removed at next scan */ + rsc->h.expiry_time = 1; } int __init gss_init_svc_upcall(void) diff --git a/lustre/ptlrpc/gss/sec_gss.c b/lustre/ptlrpc/gss/sec_gss.c index 1337b8e..8f19122 100644 --- a/lustre/ptlrpc/gss/sec_gss.c +++ b/lustre/ptlrpc/gss/sec_gss.c @@ -94,14 +94,11 @@ static inline int msg_last_seglen(struct lustre_msg *msg) static void gss_header_swabber(struct gss_header *ghdr) { - __swab32s(&ghdr->gh_version); __swab32s(&ghdr->gh_flags); __swab32s(&ghdr->gh_proc); __swab32s(&ghdr->gh_seq); __swab32s(&ghdr->gh_svc); __swab32s(&ghdr->gh_pad1); - __swab32s(&ghdr->gh_pad2); - __swab32s(&ghdr->gh_pad3); __swab32s(&ghdr->gh_handle.len); } @@ -167,11 +164,11 @@ int gss_estimate_payload(struct gss_ctx *mechctx, int msgsize, int privacy) /* * return signature size, otherwise < 0 to indicate error */ -static -int gss_sign_msg(struct lustre_msg *msg, - struct gss_ctx *mechctx, - __u32 proc, __u32 seq, __u32 svc, - rawobj_t *handle) +static int gss_sign_msg(struct lustre_msg *msg, + struct gss_ctx *mechctx, + enum lustre_sec_part sp, + __u32 flags, __u32 proc, __u32 seq, __u32 svc, + rawobj_t *handle) { struct gss_header *ghdr; rawobj_t text[3], mic; @@ -186,7 +183,8 @@ int gss_sign_msg(struct lustre_msg *msg, ghdr = lustre_msg_buf(msg, 0, 0); ghdr->gh_version = PTLRPC_GSS_VERSION; - ghdr->gh_flags = 0; + ghdr->gh_sp = (__u8) sp; + ghdr->gh_flags = flags; ghdr->gh_proc = proc; ghdr->gh_seq = seq; ghdr->gh_svc = svc; @@ -329,26 +327,18 @@ int cli_ctx_expire(struct ptlrpc_cli_ctx *ctx) LASSERT(atomic_read(&ctx->cc_refcount)); if (!test_and_set_bit(PTLRPC_CTX_DEAD_BIT, &ctx->cc_flags)) { - cfs_time_t now; - if (!ctx->cc_early_expire) clear_bit(PTLRPC_CTX_UPTODATE_BIT, &ctx->cc_flags); - now = cfs_time_current_sec(); - if (ctx->cc_expire && cfs_time_aftereq(now, ctx->cc_expire)) - CWARN("ctx %p(%u->%s): get expired (%lds exceeds)\n", - ctx, ctx->cc_vcred.vc_uid, - sec2target_str(ctx->cc_sec), - cfs_time_sub(now, ctx->cc_expire)); - else - CWARN("ctx %p(%u->%s): force to die (%lds remains)\n", - ctx, ctx->cc_vcred.vc_uid, - sec2target_str(ctx->cc_sec), - ctx->cc_expire == 0 ? 0 : - cfs_time_sub(ctx->cc_expire, now)); + CWARN("ctx %p(%u->%s) get expired: %lu(%+lds)\n", + ctx, ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec), + ctx->cc_expire, + ctx->cc_expire == 0 ? 0 : + cfs_time_sub(ctx->cc_expire, cfs_time_current_sec())); return 1; } + return 0; } @@ -385,7 +375,7 @@ void gss_cli_ctx_uptodate(struct gss_cli_ctx *gctx) } ctx->cc_expire = gss_round_ctx_expiry(ctx_expiry, - ctx->cc_sec->ps_flags); + ctx->cc_sec->ps_flvr.sf_flags); /* At this point this ctx might have been marked as dead by * someone else, in which case nobody will make further use @@ -393,33 +383,46 @@ void gss_cli_ctx_uptodate(struct gss_cli_ctx *gctx) * destroying server side context when it be destroied. */ set_bit(PTLRPC_CTX_UPTODATE_BIT, &ctx->cc_flags); - if (sec_is_reverse(ctx->cc_sec)) - CDEBUG(D_SEC, "server installed reverse ctx %p, " - "will expire at %lu(%lds lifetime)\n", - ctx, ctx->cc_expire, - ctx->cc_expire - cfs_time_current_sec()); - else - CWARN("client refreshed ctx %p(%u->%s), will expire at " - "%lu(%lds lifetime)\n", ctx, ctx->cc_vcred.vc_uid, - sec2target_str(ctx->cc_sec), ctx->cc_expire, - ctx->cc_expire - cfs_time_current_sec()); + if (sec_is_reverse(ctx->cc_sec)) { + CWARN("server installed reverse ctx %p idx "LPX64", " + "expiry %lu(%+lds)\n", ctx, + gss_handle_to_u64(&gctx->gc_handle), + ctx->cc_expire, ctx->cc_expire - cfs_time_current_sec()); + } else { + CWARN("client refreshed ctx %p idx "LPX64" (%u->%s), " + "expiry %lu(%+lds)\n", ctx, + gss_handle_to_u64(&gctx->gc_handle), + ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec), + ctx->cc_expire, ctx->cc_expire - cfs_time_current_sec()); - /* install reverse svc ctx, but only for forward connection - * and root context */ - if (!sec_is_reverse(ctx->cc_sec) && ctx->cc_vcred.vc_uid == 0) { - gss_sec_install_rctx(ctx->cc_sec->ps_import, - ctx->cc_sec, ctx); + /* install reverse svc ctx for root context */ + if (ctx->cc_vcred.vc_uid == 0) + gss_sec_install_rctx(ctx->cc_sec->ps_import, + ctx->cc_sec, ctx); } } -static -void gss_cli_ctx_finalize(struct gss_cli_ctx *gctx) +static void gss_cli_ctx_finalize(struct gss_cli_ctx *gctx) { + LASSERT(gctx->gc_base.cc_sec); + if (gctx->gc_mechctx) { lgss_delete_sec_context(&gctx->gc_mechctx); gctx->gc_mechctx = NULL; } + if (!rawobj_empty(&gctx->gc_svc_handle)) { + /* forward ctx: mark buddy reverse svcctx soon-expire. + * reverse ctx: update current seq to buddy svcctx. */ + if (!sec_is_reverse(gctx->gc_base.cc_sec)) + gss_svc_upcall_expire_rvs_ctx(&gctx->gc_svc_handle); + else + gss_svc_upcall_update_sequence(&gctx->gc_svc_handle, + (__u32) atomic_read(&gctx->gc_seq)); + + rawobj_free(&gctx->gc_svc_handle); + } + rawobj_free(&gctx->gc_handle); } @@ -612,8 +615,8 @@ void gss_cli_ctx_flags2str(unsigned long flags, char *buf, int bufsize) int gss_cli_ctx_sign(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req) { - struct gss_cli_ctx *gctx; - __u32 seq, svc; + struct gss_cli_ctx *gctx = ctx2gctx(ctx); + __u32 flags = 0, seq, svc; int rc; ENTRY; @@ -625,13 +628,18 @@ int gss_cli_ctx_sign(struct ptlrpc_cli_ctx *ctx, if (req->rq_ctx_init) RETURN(0); - gctx = container_of(ctx, struct gss_cli_ctx, gc_base); - svc = SEC_FLAVOR_SVC(req->rq_sec_flavor); + svc = RPC_FLVR_SVC(req->rq_flvr.sf_rpc); + if (req->rq_pack_bulk) + flags |= LUSTRE_GSS_PACK_BULK; + if (req->rq_pack_udesc) + flags |= LUSTRE_GSS_PACK_USER; + redo: seq = atomic_inc_return(&gctx->gc_seq); rc = gss_sign_msg(req->rq_reqbuf, gctx->gc_mechctx, - gctx->gc_proc, seq, svc, + ctx->cc_sec->ps_part, + flags, gctx->gc_proc, seq, svc, &gctx->gc_handle); if (rc < 0) RETURN(rc); @@ -688,6 +696,7 @@ int gss_cli_ctx_handle_err_notify(struct ptlrpc_cli_ctx *ctx, } else if (sec_is_reverse(ctx->cc_sec)) { CWARN("reverse server respond error (%08x/%08x)\n", errhdr->gh_major, errhdr->gh_minor); + sptlrpc_cli_ctx_expire(ctx); rc = -EINVAL; } else if (errhdr->gh_major == GSS_S_NO_CONTEXT || errhdr->gh_major == GSS_S_BAD_SIG) { @@ -763,6 +772,13 @@ int gss_cli_ctx_verify(struct ptlrpc_cli_ctx *ctx, switch (ghdr->gh_proc) { case PTLRPC_GSS_PROC_DATA: + if (!equi(req->rq_pack_bulk == 1, + ghdr->gh_flags & LUSTRE_GSS_PACK_BULK)) { + CERROR("%s bulk flag in reply\n", + req->rq_pack_bulk ? "missing" : "unexpected"); + RETURN(-EPROTO); + } + if (ghdr->gh_seq != reqhdr->gh_seq) { CERROR("seqnum %u mismatch, expect %u\n", ghdr->gh_seq, reqhdr->gh_seq); @@ -785,7 +801,7 @@ int gss_cli_ctx_verify(struct ptlrpc_cli_ctx *ctx, req->rq_repmsg = lustre_msg_buf(msg, 1, 0); req->rq_replen = msg->lm_buflens[1]; - if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) { + if (req->rq_pack_bulk) { if (msg->lm_bufcount < 4) { CERROR("Invalid reply bufcount %u\n", msg->lm_bufcount); @@ -847,17 +863,22 @@ int gss_cli_ctx_seal(struct ptlrpc_cli_ctx *ctx, } lustre_init_msg_v2(req->rq_reqbuf, 3, buflens, NULL); - req->rq_reqbuf->lm_secflvr = req->rq_sec_flavor; + req->rq_reqbuf->lm_secflvr = req->rq_flvr.sf_rpc; /* gss header */ ghdr = lustre_msg_buf(req->rq_reqbuf, 0, 0); ghdr->gh_version = PTLRPC_GSS_VERSION; + ghdr->gh_sp = (__u8) ctx->cc_sec->ps_part; ghdr->gh_flags = 0; ghdr->gh_proc = gctx->gc_proc; ghdr->gh_seq = atomic_inc_return(&gctx->gc_seq); ghdr->gh_svc = SPTLRPC_SVC_PRIV; ghdr->gh_handle.len = gctx->gc_handle.len; memcpy(ghdr->gh_handle.data, gctx->gc_handle.data, gctx->gc_handle.len); + if (req->rq_pack_bulk) + ghdr->gh_flags |= LUSTRE_GSS_PACK_BULK; + if (req->rq_pack_udesc) + ghdr->gh_flags |= LUSTRE_GSS_PACK_USER; redo: /* header signature */ @@ -948,6 +969,13 @@ int gss_cli_ctx_unseal(struct ptlrpc_cli_ctx *ctx, switch (ghdr->gh_proc) { case PTLRPC_GSS_PROC_DATA: + if (!equi(req->rq_pack_bulk == 1, + ghdr->gh_flags & LUSTRE_GSS_PACK_BULK)) { + CERROR("%s bulk flag in reply\n", + req->rq_pack_bulk ? "missing" : "unexpected"); + RETURN(-EPROTO); + } + if (lustre_msg_swabbed(req->rq_repbuf)) gss_header_swabber(ghdr); @@ -969,7 +997,7 @@ int gss_cli_ctx_unseal(struct ptlrpc_cli_ctx *ctx, RETURN(-EPROTO); } - if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) { + if (req->rq_pack_bulk) { if (req->rq_repbuf->lm_bufcount < 2) { CERROR("Too few request buffer segments %d\n", req->rq_repbuf->lm_bufcount); @@ -1016,18 +1044,18 @@ int gss_install_rvs_svc_ctx(struct obd_import *imp, int gss_sec_create_common(struct gss_sec *gsec, struct ptlrpc_sec_policy *policy, struct obd_import *imp, - struct ptlrpc_svc_ctx *ctx, - __u32 flavor, - unsigned long flags) + struct ptlrpc_svc_ctx *svcctx, + struct sptlrpc_flavor *sf) { struct ptlrpc_sec *sec; LASSERT(imp); - LASSERT(SEC_FLAVOR_POLICY(flavor) == SPTLRPC_POLICY_GSS); + LASSERT(RPC_FLVR_POLICY(sf->sf_rpc) == SPTLRPC_POLICY_GSS); - gsec->gs_mech = lgss_subflavor_to_mech(SEC_FLAVOR_SUB(flavor)); + gsec->gs_mech = lgss_subflavor_to_mech(RPC_FLVR_SUB(sf->sf_rpc)); if (!gsec->gs_mech) { - CERROR("gss backend 0x%x not found\n", SEC_FLAVOR_SUB(flavor)); + CERROR("gss backend 0x%x not found\n", + RPC_FLVR_SUB(sf->sf_rpc)); return -EOPNOTSUPP; } @@ -1037,29 +1065,28 @@ int gss_sec_create_common(struct gss_sec *gsec, /* initialize upper ptlrpc_sec */ sec = &gsec->gs_base; sec->ps_policy = policy; - sec->ps_flavor = flavor; - sec->ps_flags = flags; + atomic_set(&sec->ps_refcount, 0); + atomic_set(&sec->ps_nctx, 0); + sec->ps_id = sptlrpc_get_next_secid(); + sec->ps_flvr = *sf; sec->ps_import = class_import_get(imp); sec->ps_lock = SPIN_LOCK_UNLOCKED; - atomic_set(&sec->ps_busy, 0); CFS_INIT_LIST_HEAD(&sec->ps_gc_list); - if (!ctx) { + if (!svcctx) { sec->ps_gc_interval = GSS_GC_INTERVAL; - sec->ps_gc_next = cfs_time_current_sec() + sec->ps_gc_interval; } else { LASSERT(sec_is_reverse(sec)); /* never do gc on reverse sec */ sec->ps_gc_interval = 0; - sec->ps_gc_next = 0; } - if (SEC_FLAVOR_SVC(flavor) == SPTLRPC_SVC_PRIV && - flags & PTLRPC_SEC_FL_BULK) + if (sec->ps_flvr.sf_bulk_priv != BULK_PRIV_ALG_NULL && + sec->ps_flvr.sf_flags & PTLRPC_SEC_FL_BULK) sptlrpc_enc_pool_add_user(); - CDEBUG(D_SEC, "create %s%s@%p\n", (ctx ? "reverse " : ""), + CDEBUG(D_SEC, "create %s%s@%p\n", (svcctx ? "reverse " : ""), policy->sp_name, gsec); return 0; } @@ -1071,7 +1098,7 @@ void gss_sec_destroy_common(struct gss_sec *gsec) LASSERT(sec->ps_import); LASSERT(atomic_read(&sec->ps_refcount) == 0); - LASSERT(atomic_read(&sec->ps_busy) == 0); + LASSERT(atomic_read(&sec->ps_nctx) == 0); if (gsec->gs_mech) { lgss_mech_put(gsec->gs_mech); @@ -1080,13 +1107,18 @@ void gss_sec_destroy_common(struct gss_sec *gsec) class_import_put(sec->ps_import); - if (SEC_FLAVOR_SVC(sec->ps_flavor) == SPTLRPC_SVC_PRIV && - sec->ps_flags & PTLRPC_SEC_FL_BULK) + if (sec->ps_flvr.sf_bulk_priv != BULK_PRIV_ALG_NULL && + sec->ps_flvr.sf_flags & PTLRPC_SEC_FL_BULK) sptlrpc_enc_pool_del_user(); EXIT; } +void gss_sec_kill(struct ptlrpc_sec *sec) +{ + sec->ps_dying = 1; +} + int gss_cli_ctx_init_common(struct ptlrpc_sec *sec, struct ptlrpc_cli_ctx *ctx, struct ptlrpc_ctx_ops *ctxops, @@ -1108,8 +1140,10 @@ int gss_cli_ctx_init_common(struct ptlrpc_sec *sec, CFS_INIT_LIST_HEAD(&ctx->cc_req_list); CFS_INIT_LIST_HEAD(&ctx->cc_gc_chain); - /* take a ref on belonging sec */ - atomic_inc(&sec->ps_busy); + /* take a ref on belonging sec, balanced in ctx destroying */ + atomic_inc(&sec->ps_refcount); + /* statistic only */ + atomic_inc(&sec->ps_nctx); CDEBUG(D_SEC, "%s@%p: create ctx %p(%u->%s)\n", sec->ps_policy->sp_name, ctx->cc_sec, @@ -1118,19 +1152,18 @@ int gss_cli_ctx_init_common(struct ptlrpc_sec *sec, } /* - * return: - * -1: the destroy has been taken care of by someone else - * 0: proceed to destroy the ctx - * 1: busy count dropped to 0, proceed to destroy ctx and sec + * return value: + * 1: the context has been taken care of by someone else + * 0: proceed to really destroy the context locally */ int gss_cli_ctx_fini_common(struct ptlrpc_sec *sec, struct ptlrpc_cli_ctx *ctx) { struct gss_cli_ctx *gctx = ctx2gctx(ctx); - LASSERT(ctx->cc_sec == sec); + LASSERT(atomic_read(&sec->ps_nctx) > 0); LASSERT(atomic_read(&ctx->cc_refcount) == 0); - LASSERT(atomic_read(&sec->ps_busy) > 0); + LASSERT(ctx->cc_sec == sec); if (gctx->gc_mechctx) { /* the final context fini rpc will use this ctx too, and it's @@ -1143,22 +1176,17 @@ int gss_cli_ctx_fini_common(struct ptlrpc_sec *sec, gss_cli_ctx_finalize(gctx); if (!atomic_dec_and_test(&ctx->cc_refcount)) - return -1; + return 1; } if (sec_is_reverse(sec)) - CDEBUG(D_SEC, "reverse sec %p: destroy ctx %p\n", - ctx->cc_sec, ctx); + CWARN("reverse sec %p: destroy ctx %p\n", + ctx->cc_sec, ctx); else CWARN("%s@%p: destroy ctx %p(%u->%s)\n", sec->ps_policy->sp_name, ctx->cc_sec, ctx, ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec)); - if (atomic_dec_and_test(&sec->ps_busy)) { - LASSERT(atomic_read(&sec->ps_refcount) == 0); - return 1; - } - return 0; } @@ -1167,7 +1195,6 @@ int gss_alloc_reqbuf_intg(struct ptlrpc_sec *sec, struct ptlrpc_request *req, int svc, int msgsize) { - struct sec_flavor_config *conf; int bufsize, txtsize; int buflens[5], bufcnt = 2; ENTRY; @@ -1194,17 +1221,17 @@ int gss_alloc_reqbuf_intg(struct ptlrpc_sec *sec, if (svc == SPTLRPC_SVC_INTG) txtsize += buflens[1]; - if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) { + if (req->rq_pack_udesc) { buflens[bufcnt] = sptlrpc_current_user_desc_size(); if (svc == SPTLRPC_SVC_INTG) txtsize += buflens[bufcnt]; bufcnt++; } - if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) { - conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf; - buflens[bufcnt] = bulk_sec_desc_size(conf->sfc_bulk_csum, 1, - req->rq_bulk_read); + if (req->rq_pack_bulk) { + buflens[bufcnt] = bulk_sec_desc_size( + req->rq_flvr.sf_bulk_csum, 1, + req->rq_bulk_read); if (svc == SPTLRPC_SVC_INTG) txtsize += buflens[bufcnt]; bufcnt++; @@ -1232,13 +1259,13 @@ int gss_alloc_reqbuf_intg(struct ptlrpc_sec *sec, } lustre_init_msg_v2(req->rq_reqbuf, bufcnt, buflens, NULL); - req->rq_reqbuf->lm_secflvr = req->rq_sec_flavor; + req->rq_reqbuf->lm_secflvr = req->rq_flvr.sf_rpc; req->rq_reqmsg = lustre_msg_buf(req->rq_reqbuf, 1, msgsize); LASSERT(req->rq_reqmsg); /* pack user desc here, later we might leave current user's process */ - if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) + if (req->rq_pack_udesc) sptlrpc_pack_user_desc(req->rq_reqbuf, 2); RETURN(0); @@ -1249,7 +1276,6 @@ int gss_alloc_reqbuf_priv(struct ptlrpc_sec *sec, struct ptlrpc_request *req, int msgsize) { - struct sec_flavor_config *conf; int ibuflens[3], ibufcnt; int buflens[3]; int clearsize, wiresize; @@ -1267,13 +1293,13 @@ int gss_alloc_reqbuf_priv(struct ptlrpc_sec *sec, ibufcnt = 1; ibuflens[0] = msgsize; - if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) + if (req->rq_pack_udesc) ibuflens[ibufcnt++] = sptlrpc_current_user_desc_size(); - if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) { - conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf; - ibuflens[ibufcnt++] = bulk_sec_desc_size(conf->sfc_bulk_csum, 1, - req->rq_bulk_read); - } + if (req->rq_pack_bulk) + ibuflens[ibufcnt++] = bulk_sec_desc_size( + req->rq_flvr.sf_bulk_csum, 1, + req->rq_bulk_read); + clearsize = lustre_msg_size_v2(ibufcnt, ibuflens); /* to allow append padding during encryption */ clearsize += GSS_MAX_CIPHER_BLOCK; @@ -1321,7 +1347,7 @@ int gss_alloc_reqbuf_priv(struct ptlrpc_sec *sec, lustre_init_msg_v2(req->rq_clrbuf, ibufcnt, ibuflens, NULL); req->rq_reqmsg = lustre_msg_buf(req->rq_clrbuf, 0, msgsize); - if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) + if (req->rq_pack_udesc) sptlrpc_pack_user_desc(req->rq_clrbuf, 1); RETURN(0); @@ -1335,9 +1361,9 @@ int gss_alloc_reqbuf(struct ptlrpc_sec *sec, struct ptlrpc_request *req, int msgsize) { - int svc = SEC_FLAVOR_SVC(req->rq_sec_flavor); + int svc = RPC_FLVR_SVC(req->rq_flvr.sf_rpc); - LASSERT(!SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor) || + LASSERT(!req->rq_pack_bulk || (req->rq_bulk_read || req->rq_bulk_write)); switch (svc) { @@ -1348,7 +1374,7 @@ int gss_alloc_reqbuf(struct ptlrpc_sec *sec, case SPTLRPC_SVC_PRIV: return gss_alloc_reqbuf_priv(sec, req, msgsize); default: - LASSERTF(0, "bad flavor %x\n", req->rq_sec_flavor); + LASSERTF(0, "bad rpc flavor %x\n", req->rq_flvr.sf_rpc); return 0; } } @@ -1360,7 +1386,7 @@ void gss_free_reqbuf(struct ptlrpc_sec *sec, ENTRY; LASSERT(!req->rq_pool || req->rq_reqbuf); - privacy = SEC_FLAVOR_SVC(req->rq_sec_flavor) == SPTLRPC_SVC_PRIV; + privacy = RPC_FLVR_SVC(req->rq_flvr.sf_rpc) == SPTLRPC_SVC_PRIV; if (!req->rq_clrbuf) goto release_reqbuf; @@ -1381,11 +1407,15 @@ void gss_free_reqbuf(struct ptlrpc_sec *sec, release_reqbuf: if (!req->rq_pool && req->rq_reqbuf) { + LASSERT(req->rq_reqbuf_len); + OBD_FREE(req->rq_reqbuf, req->rq_reqbuf_len); req->rq_reqbuf = NULL; req->rq_reqbuf_len = 0; } + req->rq_reqmsg = NULL; + EXIT; } @@ -1406,7 +1436,6 @@ int gss_alloc_repbuf_intg(struct ptlrpc_sec *sec, struct ptlrpc_request *req, int svc, int msgsize) { - struct sec_flavor_config *conf; int txtsize; int buflens[4], bufcnt = 2; @@ -1431,10 +1460,10 @@ int gss_alloc_repbuf_intg(struct ptlrpc_sec *sec, if (svc == SPTLRPC_SVC_INTG) txtsize += buflens[1]; - if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) { - conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf; - buflens[bufcnt] = bulk_sec_desc_size(conf->sfc_bulk_csum, 0, - req->rq_bulk_read); + if (req->rq_pack_bulk) { + buflens[bufcnt] = bulk_sec_desc_size( + req->rq_flvr.sf_bulk_csum, 0, + req->rq_bulk_read); if (svc == SPTLRPC_SVC_INTG) txtsize += buflens[bufcnt]; bufcnt++; @@ -1453,7 +1482,6 @@ int gss_alloc_repbuf_priv(struct ptlrpc_sec *sec, struct ptlrpc_request *req, int msgsize) { - struct sec_flavor_config *conf; int txtsize; int buflens[3], bufcnt; @@ -1465,10 +1493,9 @@ int gss_alloc_repbuf_priv(struct ptlrpc_sec *sec, bufcnt = 1; buflens[0] = msgsize; - if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) { - conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf; + if (req->rq_pack_bulk) { buflens[bufcnt++] = bulk_sec_desc_size( - conf->sfc_bulk_csum, 0, + req->rq_flvr.sf_bulk_csum, 0, req->rq_bulk_read); } txtsize = lustre_msg_size_v2(bufcnt, buflens); @@ -1492,10 +1519,10 @@ int gss_alloc_repbuf(struct ptlrpc_sec *sec, struct ptlrpc_request *req, int msgsize) { - int svc = SEC_FLAVOR_SVC(req->rq_sec_flavor); + int svc = RPC_FLVR_SVC(req->rq_flvr.sf_rpc); ENTRY; - LASSERT(!SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor) || + LASSERT(!req->rq_pack_bulk || (req->rq_bulk_read || req->rq_bulk_write)); switch (svc) { @@ -1506,7 +1533,7 @@ int gss_alloc_repbuf(struct ptlrpc_sec *sec, case SPTLRPC_SVC_PRIV: return gss_alloc_repbuf_priv(sec, req, msgsize); default: - LASSERTF(0, "bad flavor %x\n", req->rq_sec_flavor); + LASSERTF(0, "bad rpc flavor %x\n", req->rq_flvr.sf_rpc); return 0; } } @@ -1517,6 +1544,8 @@ void gss_free_repbuf(struct ptlrpc_sec *sec, OBD_FREE(req->rq_repbuf, req->rq_repbuf_len); req->rq_repbuf = NULL; req->rq_repbuf_len = 0; + + req->rq_repmsg = NULL; } static int get_enlarged_msgsize(struct lustre_msg *msg, @@ -1726,7 +1755,7 @@ int gss_enlarge_reqbuf(struct ptlrpc_sec *sec, struct ptlrpc_request *req, int segment, int newsize) { - int svc = SEC_FLAVOR_SVC(req->rq_sec_flavor); + int svc = RPC_FLVR_SVC(req->rq_flvr.sf_rpc); LASSERT(!req->rq_ctx_init && !req->rq_ctx_fini); @@ -1738,7 +1767,7 @@ int gss_enlarge_reqbuf(struct ptlrpc_sec *sec, case SPTLRPC_SVC_PRIV: return gss_enlarge_reqbuf_priv(sec, req, segment, newsize); default: - LASSERTF(0, "bad flavor %x\n", req->rq_sec_flavor); + LASSERTF(0, "bad rpc flavor %x\n", req->rq_flvr.sf_rpc); return 0; } } @@ -1800,8 +1829,9 @@ static int gss_svc_sign(struct ptlrpc_request *req, struct ptlrpc_reply_state *rs, struct gss_svc_reqctx *grctx, - int svc) + __u32 svc) { + __u32 flags = 0; int rc; ENTRY; @@ -1811,9 +1841,12 @@ int gss_svc_sign(struct ptlrpc_request *req, if (req->rq_replen != rs->rs_repbuf->lm_buflens[1]) lustre_shrink_msg(rs->rs_repbuf, 1, req->rq_replen, 1); + if (req->rq_pack_bulk) + flags |= LUSTRE_GSS_PACK_BULK; + rc = gss_sign_msg(rs->rs_repbuf, grctx->src_ctx->gsc_mechctx, - PTLRPC_GSS_PROC_DATA, grctx->src_wirectx.gw_seq, - svc, NULL); + LUSTRE_SP_ANY, flags, PTLRPC_GSS_PROC_DATA, + grctx->src_wirectx.gw_seq, svc, NULL); if (rc < 0) RETURN(rc); @@ -1880,6 +1913,11 @@ int gss_svc_handle_init(struct ptlrpc_request *req, req->rq_ctx_init = 1; + if (gw->gw_flags & LUSTRE_GSS_PACK_BULK) { + CERROR("unexpected bulk flag\n"); + RETURN(SECSVC_DROP); + } + if (gw->gw_proc == PTLRPC_GSS_PROC_INIT && gw->gw_handle.len != 0) { CERROR("proc %u: invalid handle length %u\n", gw->gw_proc, gw->gw_handle.len); @@ -1915,7 +1953,7 @@ int gss_svc_handle_init(struct ptlrpc_request *req, uuid = (struct obd_uuid *) uuid_obj.data; target = class_uuid2obd(uuid); if (!target || target->obd_stopping || !target->obd_set_up) { - CERROR("target '%s' is not available for context init (%s)", + CERROR("target '%s' is not available for context init (%s)\n", uuid->uuid, target == NULL ? "no target" : (target->obd_stopping ? "stopping" : "not set up")); RETURN(SECSVC_DROP); @@ -1939,14 +1977,15 @@ int gss_svc_handle_init(struct ptlrpc_request *req, RETURN(rc); if (grctx->src_ctx->gsc_usr_mds || grctx->src_ctx->gsc_usr_root) - CWARN("user from %s authenticated as %s\n", - libcfs_nid2str(req->rq_peer.nid), + CWARN("create svc ctx %p: user from %s authenticated as %s\n", + grctx->src_ctx, libcfs_nid2str(req->rq_peer.nid), grctx->src_ctx->gsc_usr_mds ? "mds" : "root"); else - CWARN("accept user %u from %s\n", grctx->src_ctx->gsc_uid, + CWARN("create svc ctx %p: accept user %u from %s\n", + grctx->src_ctx, grctx->src_ctx->gsc_uid, libcfs_nid2str(req->rq_peer.nid)); - if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) { + if (gw->gw_flags & LUSTRE_GSS_PACK_USER) { if (reqbuf->lm_bufcount < 4) { CERROR("missing user descriptor\n"); RETURN(SECSVC_DROP); @@ -1955,6 +1994,8 @@ int gss_svc_handle_init(struct ptlrpc_request *req, CERROR("Mal-formed user descriptor\n"); RETURN(SECSVC_DROP); } + + req->rq_pack_udesc = 1; req->rq_user_desc = lustre_msg_buf(reqbuf, 2, 0); } @@ -1998,7 +2039,8 @@ int gss_svc_verify_request(struct ptlrpc_request *req, if (*major != GSS_S_COMPLETE) RETURN(-EACCES); - if (gss_check_seq_num(&gctx->gsc_seqdata, gw->gw_seq, 1)) { + if (gctx->gsc_reverse == 0 && + gss_check_seq_num(&gctx->gsc_seqdata, gw->gw_seq, 1)) { CERROR("phase 1+: discard replayed req: seq %u\n", gw->gw_seq); *major = GSS_S_DUPLICATE_TOKEN; RETURN(-EACCES); @@ -2006,7 +2048,7 @@ int gss_svc_verify_request(struct ptlrpc_request *req, verified: /* user descriptor */ - if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) { + if (gw->gw_flags & LUSTRE_GSS_PACK_USER) { if (msg->lm_bufcount < (offset + 1)) { CERROR("no user desc included\n"); RETURN(-EINVAL); @@ -2017,12 +2059,13 @@ verified: RETURN(-EINVAL); } + req->rq_pack_udesc = 1; req->rq_user_desc = lustre_msg_buf(msg, offset, 0); offset++; } /* check bulk cksum data */ - if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) { + if (gw->gw_flags & LUSTRE_GSS_PACK_BULK) { if (msg->lm_bufcount < (offset + 1)) { CERROR("no bulk checksum included\n"); RETURN(-EINVAL); @@ -2031,6 +2074,7 @@ verified: if (bulk_sec_desc_unpack(msg, offset)) RETURN(-EINVAL); + req->rq_pack_bulk = 1; grctx->src_reqbsd = lustre_msg_buf(msg, offset, 0); grctx->src_reqbsd_size = lustre_msg_buflen(msg, offset); } @@ -2079,7 +2123,7 @@ int gss_svc_unseal_request(struct ptlrpc_request *req, RETURN(-EINVAL); } - if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) { + if (gw->gw_flags & LUSTRE_GSS_PACK_USER) { if (msg->lm_bufcount < offset + 1) { CERROR("no user descriptor included\n"); RETURN(-EINVAL); @@ -2090,11 +2134,12 @@ int gss_svc_unseal_request(struct ptlrpc_request *req, RETURN(-EINVAL); } + req->rq_pack_udesc = 1; req->rq_user_desc = lustre_msg_buf(msg, offset, 0); offset++; } - if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) { + if (gw->gw_flags & LUSTRE_GSS_PACK_BULK) { if (msg->lm_bufcount < offset + 1) { CERROR("no bulk checksum included\n"); RETURN(-EINVAL); @@ -2103,6 +2148,7 @@ int gss_svc_unseal_request(struct ptlrpc_request *req, if (bulk_sec_desc_unpack(msg, offset)) RETURN(-EINVAL); + req->rq_pack_bulk = 1; grctx->src_reqbsd = lustre_msg_buf(msg, offset, 0); grctx->src_reqbsd_size = lustre_msg_buflen(msg, offset); } @@ -2170,7 +2216,7 @@ int gss_svc_handle_destroy(struct ptlrpc_request *req, grctx->src_ctx = gss_svc_upcall_get_ctx(req, gw); if (!grctx->src_ctx) { - CWARN("invalid gss context handle for destroy.\n"); + CDEBUG(D_SEC, "invalid gss context handle for destroy.\n"); RETURN(SECSVC_DROP); } @@ -2182,12 +2228,13 @@ int gss_svc_handle_destroy(struct ptlrpc_request *req, if (gss_svc_verify_request(req, grctx, gw, &major)) RETURN(SECSVC_DROP); - CWARN("destroy svc ctx %p(%u->%s)\n", grctx->src_ctx, - grctx->src_ctx->gsc_uid, libcfs_nid2str(req->rq_peer.nid)); + CWARN("destroy svc ctx %p idx "LPX64" (%u->%s)\n", + grctx->src_ctx, gss_handle_to_u64(&gw->gw_handle), + grctx->src_ctx->gsc_uid, libcfs_nid2str(req->rq_peer.nid)); gss_svc_upcall_destroy_ctx(grctx->src_ctx); - if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) { + if (gw->gw_flags & LUSTRE_GSS_PACK_USER) { if (req->rq_reqbuf->lm_bufcount < 4) { CERROR("missing user descriptor, ignore it\n"); RETURN(SECSVC_OK); @@ -2196,6 +2243,8 @@ int gss_svc_handle_destroy(struct ptlrpc_request *req, CERROR("Mal-formed user descriptor, ignore it\n"); RETURN(SECSVC_OK); } + + req->rq_pack_udesc = 1; req->rq_user_desc = lustre_msg_buf(req->rq_reqbuf, 2, 0); } @@ -2231,6 +2280,8 @@ int gss_svc_accept(struct ptlrpc_sec_policy *policy, struct ptlrpc_request *req) RETURN(SECSVC_DROP); } + req->rq_sp_from = ghdr->gh_sp; + /* alloc grctx data */ OBD_ALLOC_PTR(grctx); if (!grctx) { @@ -2243,6 +2294,7 @@ int gss_svc_accept(struct ptlrpc_sec_policy *policy, struct ptlrpc_request *req) gw = &grctx->src_wirectx; /* save wire context */ + gw->gw_flags = ghdr->gh_flags; gw->gw_proc = ghdr->gh_proc; gw->gw_seq = ghdr->gh_seq; gw->gw_svc = ghdr->gh_svc; @@ -2331,13 +2383,12 @@ int gss_svc_alloc_rs(struct ptlrpc_request *req, int msglen) LASSERT(msglen % 8 == 0); - if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor) && - !req->rq_bulk_read && !req->rq_bulk_write) { + if (req->rq_pack_bulk && !req->rq_bulk_read && !req->rq_bulk_write) { CERROR("client request bulk sec on non-bulk rpc\n"); RETURN(-EPROTO); } - svc = SEC_FLAVOR_SVC(req->rq_sec_flavor); + svc = RPC_FLVR_SVC(req->rq_flvr.sf_rpc); grctx = gss_svc_ctx2reqctx(req->rq_svc_ctx); if (gss_svc_reqctx_is_special(grctx)) @@ -2350,7 +2401,7 @@ int gss_svc_alloc_rs(struct ptlrpc_request *req, int msglen) ibufcnt = 1; ibuflens[0] = msglen; - if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) { + if (req->rq_pack_bulk) { LASSERT(grctx->src_reqbsd); bsd_off = ibufcnt; @@ -2376,7 +2427,7 @@ int gss_svc_alloc_rs(struct ptlrpc_request *req, int msglen) if (svc == SPTLRPC_SVC_INTG) txtsize += buflens[1]; - if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) { + if (req->rq_pack_bulk) { LASSERT(grctx->src_reqbsd); bsd_off = bufcnt; @@ -2418,7 +2469,7 @@ int gss_svc_alloc_rs(struct ptlrpc_request *req, int msglen) rs->rs_msg = lustre_msg_buf(rs->rs_repbuf, 0, msglen); } else { lustre_init_msg_v2(rs->rs_repbuf, bufcnt, buflens, NULL); - rs->rs_repbuf->lm_secflvr = req->rq_sec_flavor; + rs->rs_repbuf->lm_secflvr = req->rq_flvr.sf_rpc; rs->rs_msg = lustre_msg_buf(rs->rs_repbuf, 1, 0); } @@ -2492,7 +2543,7 @@ int gss_svc_seal(struct ptlrpc_request *req, LASSERT(lustre_msg_size_v2(3, buflens) <= rs->rs_repbuf_len); lustre_init_msg_v2(rs->rs_repbuf, 3, buflens, NULL); - rs->rs_repbuf->lm_secflvr = req->rq_sec_flavor; + rs->rs_repbuf->lm_secflvr = req->rq_flvr.sf_rpc; /* gss header */ ghdr = lustre_msg_buf(rs->rs_repbuf, 0, 0); @@ -2502,6 +2553,8 @@ int gss_svc_seal(struct ptlrpc_request *req, ghdr->gh_seq = grctx->src_wirectx.gw_seq; ghdr->gh_svc = SPTLRPC_SVC_PRIV; ghdr->gh_handle.len = 0; + if (req->rq_pack_bulk) + ghdr->gh_flags |= LUSTRE_GSS_PACK_BULK; /* header signature */ msgobj.len = rs->rs_repbuf->lm_buflens[0]; @@ -2601,33 +2654,53 @@ int gss_copy_rvc_cli_ctx(struct ptlrpc_cli_ctx *cli_ctx, struct ptlrpc_svc_ctx *svc_ctx) { struct gss_cli_ctx *cli_gctx = ctx2gctx(cli_ctx); - struct gss_svc_reqctx *grctx; + struct gss_svc_ctx *svc_gctx = gss_svc_ctx2gssctx(svc_ctx); struct gss_ctx *mechctx = NULL; + LASSERT(cli_gctx); + LASSERT(svc_gctx && svc_gctx->gsc_mechctx); + cli_gctx->gc_proc = PTLRPC_GSS_PROC_DATA; cli_gctx->gc_win = GSS_SEQ_WIN; - atomic_set(&cli_gctx->gc_seq, 0); - grctx = container_of(svc_ctx, struct gss_svc_reqctx, src_base); - LASSERT(grctx->src_ctx); - LASSERT(grctx->src_ctx->gsc_mechctx); + /* The problem is the reverse ctx might get lost in some recovery + * situations, and the same svc_ctx will be used to re-create it. + * if there's callback be sentout before that, new reverse ctx start + * with sequence 0 will lead to future callback rpc be treated as + * replay. + * + * each reverse root ctx will record its latest sequence number on its + * buddy svcctx before be destroied, so here we continue use it. + */ + atomic_set(&cli_gctx->gc_seq, svc_gctx->gsc_rvs_seq); + + if (gss_svc_upcall_dup_handle(&cli_gctx->gc_svc_handle, svc_gctx)) { + CERROR("failed to dup svc handle\n"); + goto err_out; + } - if (lgss_copy_reverse_context(grctx->src_ctx->gsc_mechctx, &mechctx) != + if (lgss_copy_reverse_context(svc_gctx->gsc_mechctx, &mechctx) != GSS_S_COMPLETE) { CERROR("failed to copy mech context\n"); - return -ENOMEM; + goto err_svc_handle; } - if (rawobj_dup(&cli_gctx->gc_handle, &grctx->src_ctx->gsc_rvs_hdl)) { + if (rawobj_dup(&cli_gctx->gc_handle, &svc_gctx->gsc_rvs_hdl)) { CERROR("failed to dup reverse handle\n"); - lgss_delete_sec_context(&mechctx); - return -ENOMEM; + goto err_ctx; } cli_gctx->gc_mechctx = mechctx; gss_cli_ctx_uptodate(cli_gctx); return 0; + +err_ctx: + lgss_delete_sec_context(&mechctx); +err_svc_handle: + rawobj_free(&cli_gctx->gc_svc_handle); +err_out: + return -ENOMEM; } int __init sptlrpc_gss_init(void) diff --git a/lustre/ptlrpc/import.c b/lustre/ptlrpc/import.c index a854214..e282302 100644 --- a/lustre/ptlrpc/import.c +++ b/lustre/ptlrpc/import.c @@ -445,10 +445,14 @@ int ptlrpc_connect_import(struct obd_import *imp, char *new_uuid) } } + rc = sptlrpc_import_sec_adapt(imp, NULL, 0); + if (rc) + GOTO(out, rc); + /* Reset connect flags to the originally requested flags, in case * the server is updated on-the-fly we will get the new features. */ imp->imp_connect_data.ocd_connect_flags = imp->imp_connect_flags_orig; - rc = obd_reconnect(imp->imp_obd->obd_self_export, obd, + rc = obd_reconnect(NULL, imp->imp_obd->obd_self_export, obd, &obd->obd_uuid, &imp->imp_connect_data); if (rc) GOTO(out, rc); @@ -805,7 +809,7 @@ out: struct obd_connect_data *ocd; /* reply message might not be ready */ - if (request->rq_repmsg != NULL) + if (request->rq_repmsg == NULL) RETURN(-EPROTO); ocd = lustre_swab_repbuf(request, REPLY_REC_OFF, diff --git a/lustre/ptlrpc/layout.c b/lustre/ptlrpc/layout.c index e223d5f..05295b8 100644 --- a/lustre/ptlrpc/layout.c +++ b/lustre/ptlrpc/layout.c @@ -330,8 +330,7 @@ static const struct req_msg_field *mds_setxattr_client[] = { }; static const struct req_msg_field *mds_setxattr_server[] = { - &RMF_PTLRPC_BODY, - &RMF_EADATA + &RMF_PTLRPC_BODY }; static const struct req_msg_field *mds_getattr_server[] = { diff --git a/lustre/ptlrpc/niobuf.c b/lustre/ptlrpc/niobuf.c index 7d92ba6..0965e4e 100644 --- a/lustre/ptlrpc/niobuf.c +++ b/lustre/ptlrpc/niobuf.c @@ -310,12 +310,13 @@ int ptlrpc_send_reply (struct ptlrpc_request *req, int may_be_difficult) int rc; /* We must already have a reply buffer (only ptlrpc_error() may be - * called without one). The reply generated by security layer (e.g. + * called without one). The reply generated by sptlrpc layer (e.g. * error notify, etc.) might have NULL rq->reqmsg; Otherwise we must * have a request buffer which is either the actual (swabbed) incoming * request, or a saved copy if this is a req saved in * target_queue_final_reply(). */ + LASSERT (req->rq_no_reply == 0); LASSERT (req->rq_reqbuf != NULL); LASSERT (rs != NULL); LASSERT (may_be_difficult || !rs->rs_difficult); @@ -375,7 +376,10 @@ out: int ptlrpc_reply (struct ptlrpc_request *req) { - return (ptlrpc_send_reply (req, 0)); + if (req->rq_no_reply) + return 0; + else + return (ptlrpc_send_reply(req, 0)); } int ptlrpc_error(struct ptlrpc_request *req) @@ -383,6 +387,9 @@ int ptlrpc_error(struct ptlrpc_request *req) int rc; ENTRY; + if (req->rq_no_reply) + RETURN(0); + if (!req->rq_repmsg) { rc = lustre_pack_reply(req, 1, NULL, NULL); if (rc) diff --git a/lustre/ptlrpc/pack_generic.c b/lustre/ptlrpc/pack_generic.c index 146dd55..c59a312 100644 --- a/lustre/ptlrpc/pack_generic.c +++ b/lustre/ptlrpc/pack_generic.c @@ -254,12 +254,8 @@ int lustre_pack_request(struct ptlrpc_request *req, __u32 magic, int count, LASSERT(count > 0); LASSERT(lens[MSG_PTLRPC_BODY_OFF] == sizeof(struct ptlrpc_body)); - /* if we choose policy other than null, we have also choosed - * to use new message format. - */ - if (magic == LUSTRE_MSG_MAGIC_V1 && - req->rq_sec_flavor != SPTLRPC_FLVR_NULL) - magic = LUSTRE_MSG_MAGIC_V2; + /* only use new format, we don't need to be compatible with 1.4 */ + magic = LUSTRE_MSG_MAGIC_V2; switch (magic) { case LUSTRE_MSG_MAGIC_V1: diff --git a/lustre/ptlrpc/ptlrpc_internal.h b/lustre/ptlrpc/ptlrpc_internal.h index efa11e5..4d80f48 100644 --- a/lustre/ptlrpc/ptlrpc_internal.h +++ b/lustre/ptlrpc/ptlrpc_internal.h @@ -190,7 +190,6 @@ int sptlrpc_enc_pool_init(void); void sptlrpc_enc_pool_fini(void); int sptlrpc_proc_read_enc_pool(char *page, char **start, off_t off, int count, int *eof, void *data); -const char * sptlrpc_bulk_csum_alg2name(__u32 csum_alg); /* sec_lproc.c */ int sptlrpc_lproc_init(void); diff --git a/lustre/ptlrpc/sec.c b/lustre/ptlrpc/sec.c index 7511b94..059c3f3 100644 --- a/lustre/ptlrpc/sec.c +++ b/lustre/ptlrpc/sec.c @@ -1,7 +1,8 @@ /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * - * Copyright (C) 2004-2006 Cluster File Systems, Inc. + * Copyright (C) 2004-2007 Cluster File Systems, Inc. + * Author: Eric Mei * * This file is part of Lustre, http://www.lustre.org. * @@ -54,7 +55,7 @@ static struct ptlrpc_sec_policy *policies[SPTLRPC_POLICY_MAX] = { int sptlrpc_register_policy(struct ptlrpc_sec_policy *policy) { - __u32 number = policy->sp_policy; + __u16 number = policy->sp_policy; LASSERT(policy->sp_name); LASSERT(policy->sp_cops); @@ -78,7 +79,7 @@ EXPORT_SYMBOL(sptlrpc_register_policy); int sptlrpc_unregister_policy(struct ptlrpc_sec_policy *policy) { - __u32 number = policy->sp_policy; + __u16 number = policy->sp_policy; LASSERT(number < SPTLRPC_POLICY_MAX); @@ -99,21 +100,17 @@ int sptlrpc_unregister_policy(struct ptlrpc_sec_policy *policy) EXPORT_SYMBOL(sptlrpc_unregister_policy); static -struct ptlrpc_sec_policy * sptlrpc_flavor2policy(ptlrpc_sec_flavor_t flavor) +struct ptlrpc_sec_policy * sptlrpc_rpcflavor2policy(__u16 flavor) { -#ifdef CONFIG_KMOD static DECLARE_MUTEX(load_mutex); -#endif - static atomic_t loaded = ATOMIC_INIT(0); - struct ptlrpc_sec_policy *policy; - __u32 number = SEC_FLAVOR_POLICY(flavor), flag = 0; + static atomic_t loaded = ATOMIC_INIT(0); + struct ptlrpc_sec_policy *policy; + __u16 number = RPC_FLVR_POLICY(flavor), flag = 0; if (number >= SPTLRPC_POLICY_MAX) return NULL; -#ifdef CONFIG_KMOD again: -#endif read_lock(&policy_lock); policy = policies[number]; if (policy && !try_module_get(policy->sp_owner)) @@ -122,18 +119,15 @@ again: flag = atomic_read(&loaded); read_unlock(&policy_lock); -#ifdef CONFIG_KMOD /* if failure, try to load gss module, once */ - if (unlikely(policy == NULL) && - flag == 0 && - (number == SPTLRPC_POLICY_GSS || - number == SPTLRPC_POLICY_GSS_PIPEFS)) { + if (unlikely(policy == NULL) && flag == 0 && + number == SPTLRPC_POLICY_GSS) { mutex_down(&load_mutex); if (atomic_read(&loaded) == 0) { if (request_module("ptlrpc_gss") != 0) CERROR("Unable to load module ptlrpc_gss\n"); else - CWARN("module ptlrpc_gss loaded\n"); + CWARN("module ptlrpc_gss loaded on demand\n"); atomic_set(&loaded, 1); } @@ -141,12 +135,11 @@ again: goto again; } -#endif return policy; } -ptlrpc_sec_flavor_t sptlrpc_name2flavor(const char *name) +__u16 sptlrpc_name2rpcflavor(const char *name) { if (!strcmp(name, "null")) return SPTLRPC_FLVR_NULL; @@ -161,9 +154,9 @@ ptlrpc_sec_flavor_t sptlrpc_name2flavor(const char *name) return SPTLRPC_FLVR_INVALID; } -EXPORT_SYMBOL(sptlrpc_name2flavor); +EXPORT_SYMBOL(sptlrpc_name2rpcflavor); -char *sptlrpc_flavor2name(ptlrpc_sec_flavor_t flavor) +const char *sptlrpc_rpcflavor2name(__u16 flavor) { switch (flavor) { case SPTLRPC_FLVR_NULL: @@ -179,11 +172,30 @@ char *sptlrpc_flavor2name(ptlrpc_sec_flavor_t flavor) case SPTLRPC_FLVR_KRB5P: return "krb5p"; default: - CERROR("invalid flavor 0x%x(p%u,s%u,v%u)\n", flavor, - SEC_FLAVOR_POLICY(flavor), SEC_FLAVOR_MECH(flavor), - SEC_FLAVOR_SVC(flavor)); + CERROR("invalid rpc flavor 0x%x(p%u,s%u,v%u)\n", flavor, + RPC_FLVR_POLICY(flavor), RPC_FLVR_MECH(flavor), + RPC_FLVR_SVC(flavor)); } - return "UNKNOWN"; + return "unknown"; +} +EXPORT_SYMBOL(sptlrpc_rpcflavor2name); + +int sptlrpc_flavor2name(struct sptlrpc_flavor *sf, char *buf, int bufsize) +{ + char *bulk; + + if (sf->sf_bulk_priv != BULK_PRIV_ALG_NULL) + bulk = "bulkp"; + else if (sf->sf_bulk_csum != BULK_CSUM_ALG_NULL) + bulk = "bulki"; + else + bulk = "bulkn"; + + snprintf(buf, bufsize, "%s-%s:%s/%s", + sptlrpc_rpcflavor2name(sf->sf_rpc), bulk, + sptlrpc_bulk_csum_alg2name(sf->sf_bulk_csum), + sptlrpc_bulk_priv_alg2name(sf->sf_bulk_priv)); + return 0; } EXPORT_SYMBOL(sptlrpc_flavor2name); @@ -200,10 +212,11 @@ struct ptlrpc_cli_ctx *get_my_ctx(struct ptlrpc_sec *sec) LASSERT(sec); LASSERT(sec->ps_policy->sp_cops->lookup_ctx); - if (sec->ps_flags & (PTLRPC_SEC_FL_REVERSE | PTLRPC_SEC_FL_ROOTONLY)) { + if (sec->ps_flvr.sf_flags & (PTLRPC_SEC_FL_REVERSE | + PTLRPC_SEC_FL_ROOTONLY)) { vcred.vc_uid = 0; vcred.vc_gid = 0; - if (sec->ps_flags & PTLRPC_SEC_FL_REVERSE) { + if (sec->ps_flvr.sf_flags & PTLRPC_SEC_FL_REVERSE) { create = 0; remove_dead = 0; } @@ -272,21 +285,56 @@ int sptlrpc_cli_ctx_display(struct ptlrpc_cli_ctx *ctx, char *buf, int bufsize) return ctx->cc_ops->display(ctx, buf, bufsize); } +static int sptlrpc_import_sec_check_expire(struct obd_import *imp) +{ + int adapt = 0; + + spin_lock(&imp->imp_lock); + if (imp->imp_sec_expire && + imp->imp_sec_expire < cfs_time_current_sec()) { + adapt = 1; + imp->imp_sec_expire = 0; + } + spin_unlock(&imp->imp_lock); + + if (!adapt) + return 0; + + CDEBUG(D_SEC, "found delayed sec adapt expired, do it now\n"); + return sptlrpc_import_sec_adapt(imp, NULL, 0); +} + int sptlrpc_req_get_ctx(struct ptlrpc_request *req) { struct obd_import *imp = req->rq_import; + struct ptlrpc_sec *sec; + int rc; ENTRY; LASSERT(!req->rq_cli_ctx); LASSERT(imp); - if (imp->imp_sec == NULL) { - CERROR("import %p (%s) with no sec pointer\n", + if (unlikely(imp->imp_sec_expire)) { + rc = sptlrpc_import_sec_check_expire(imp); + if (rc) + RETURN(rc); + } + + sec = sptlrpc_import_sec_ref(imp); + if (sec == NULL) { + CERROR("import %p (%s) with no ptlrpc_sec\n", imp, ptlrpc_import_state_name(imp->imp_state)); RETURN(-EACCES); } - req->rq_cli_ctx = get_my_ctx(imp->imp_sec); + if (unlikely(sec->ps_dying)) { + CERROR("attempt to use dying sec %p\n", sec); + return -EACCES; + } + + req->rq_cli_ctx = get_my_ctx(sec); + + sptlrpc_sec_put(sec); if (!req->rq_cli_ctx) { CERROR("req %p: fail to get context\n", req); @@ -321,35 +369,115 @@ void sptlrpc_req_put_ctx(struct ptlrpc_request *req, int sync) EXIT; } +static +int sptlrpc_req_ctx_switch(struct ptlrpc_request *req, + struct ptlrpc_cli_ctx *oldctx, + struct ptlrpc_cli_ctx *newctx) +{ + struct sptlrpc_flavor old_flvr; + char *reqmsg; + int reqmsg_size; + int rc; + + if (likely(oldctx->cc_sec == newctx->cc_sec)) + return 0; + + LASSERT(req->rq_reqmsg); + LASSERT(req->rq_reqlen); + LASSERT(req->rq_replen); + + CWARN("req %p: switch ctx %p -> %p, switch sec %p(%s) -> %p(%s)\n", + req, oldctx, newctx, + oldctx->cc_sec, oldctx->cc_sec->ps_policy->sp_name, + newctx->cc_sec, newctx->cc_sec->ps_policy->sp_name); + + /* save flavor */ + old_flvr = req->rq_flvr; + + /* save request message */ + reqmsg_size = req->rq_reqlen; + OBD_ALLOC(reqmsg, reqmsg_size); + if (reqmsg == NULL) + return -ENOMEM; + memcpy(reqmsg, req->rq_reqmsg, reqmsg_size); + + /* release old req/rep buf */ + req->rq_cli_ctx = oldctx; + sptlrpc_cli_free_reqbuf(req); + sptlrpc_cli_free_repbuf(req); + req->rq_cli_ctx = newctx; + + /* recalculate the flavor */ + sptlrpc_req_set_flavor(req, 0); + + /* alloc new request buffer + * we don't need to alloc reply buffer here, leave it to the + * rest procedure of ptlrpc + */ + rc = sptlrpc_cli_alloc_reqbuf(req, reqmsg_size); + if (!rc) { + LASSERT(req->rq_reqmsg); + memcpy(req->rq_reqmsg, reqmsg, reqmsg_size); + } else { + CWARN("failed to alloc reqbuf: %d\n", rc); + req->rq_flvr = old_flvr; + } + + OBD_FREE(reqmsg, reqmsg_size); + return rc; +} + /* - * request must have a context. if failed to get new context, - * just restore the old one + * request must have a context. in any case of failure, restore the + * restore the old one. a request must have a ctx. */ int sptlrpc_req_replace_dead_ctx(struct ptlrpc_request *req) { - struct ptlrpc_cli_ctx *ctx = req->rq_cli_ctx; - int rc; + struct ptlrpc_cli_ctx *oldctx = req->rq_cli_ctx; + struct ptlrpc_cli_ctx *newctx; + int rc; ENTRY; - LASSERT(ctx); - LASSERT(test_bit(PTLRPC_CTX_DEAD_BIT, &ctx->cc_flags)); - - /* make sure not on context waiting list */ - spin_lock(&ctx->cc_lock); - list_del_init(&req->rq_ctx_chain); - spin_unlock(&ctx->cc_lock); + LASSERT(oldctx); + LASSERT(test_bit(PTLRPC_CTX_DEAD_BIT, &oldctx->cc_flags)); - sptlrpc_cli_ctx_get(ctx); + sptlrpc_cli_ctx_get(oldctx); sptlrpc_req_put_ctx(req, 0); + rc = sptlrpc_req_get_ctx(req); - if (!rc) { - LASSERT(req->rq_cli_ctx); - sptlrpc_cli_ctx_put(ctx, 1); - } else { + if (unlikely(rc)) { LASSERT(!req->rq_cli_ctx); - req->rq_cli_ctx = ctx; + + /* restore old ctx */ + req->rq_cli_ctx = oldctx; + RETURN(rc); } - RETURN(rc); + + newctx = req->rq_cli_ctx; + LASSERT(newctx); + + if (unlikely(newctx == oldctx)) { + /* + * still get the old ctx, usually means system busy + */ + CWARN("ctx (%p, fl %lx) doesn't switch, relax a little bit\n", + newctx, newctx->cc_flags); + + schedule_timeout(HZ); + } else { + rc = sptlrpc_req_ctx_switch(req, oldctx, newctx); + if (rc) { + /* restore old ctx */ + sptlrpc_req_put_ctx(req, 0); + req->rq_cli_ctx = oldctx; + RETURN(rc); + } + + LASSERT(req->rq_cli_ctx == newctx); + } + + sptlrpc_cli_ctx_put(oldctx, 1); + RETURN(0); } EXPORT_SYMBOL(sptlrpc_req_replace_dead_ctx); @@ -422,6 +550,12 @@ int sptlrpc_req_refresh_ctx(struct ptlrpc_request *req, long timeout) LASSERT(ctx); + /* + * during the process a request's context might change type even + * (e.g. from gss ctx to plain ctx), so each loop we need to re-check + * everything + */ +again: /* skip special ctxs */ if (cli_ctx_is_eternal(ctx) || req->rq_ctx_init || req->rq_ctx_fini) RETURN(0); @@ -432,7 +566,6 @@ int sptlrpc_req_refresh_ctx(struct ptlrpc_request *req, long timeout) } LASSERT(test_bit(PTLRPC_CTX_NEW_BIT, &ctx->cc_flags) == 0); -again: LASSERT(ctx->cc_ops->validate); if (ctx->cc_ops->validate(ctx) == 0) { req_off_ctx_list(req, ctx); @@ -477,32 +610,21 @@ again: } if (unlikely(test_bit(PTLRPC_CTX_DEAD_BIT, &ctx->cc_flags))) { - /* don't have to, but we don't want to release it too soon */ - sptlrpc_cli_ctx_get(ctx); - rc = sptlrpc_req_replace_dead_ctx(req); if (rc) { LASSERT(ctx == req->rq_cli_ctx); - CERROR("req %p: failed to replace dead ctx %p\n", - req, ctx); + CERROR("req %p: failed to replace dead ctx %p: %d\n", + req, ctx, rc); req->rq_err = 1; LASSERT(list_empty(&req->rq_ctx_chain)); - sptlrpc_cli_ctx_put(ctx, 1); - RETURN(-ENOMEM); + RETURN(rc); } - /* FIXME - * if ctx didn't really switch, might be cpu tight or sth, - * we just relax a little bit. - */ - if (ctx == req->rq_cli_ctx) - schedule(); - - CWARN("req %p: replace dead ctx %p(%u->%s) => %p\n", - req, ctx, ctx->cc_vcred.vc_uid, - sec2target_str(ctx->cc_sec), req->rq_cli_ctx); + CWARN("req %p: replace dead ctx %p => ctx %p (%u->%s)\n", + req, ctx, req->rq_cli_ctx, + req->rq_cli_ctx->cc_vcred.vc_uid, + sec2target_str(req->rq_cli_ctx->cc_sec)); - sptlrpc_cli_ctx_put(ctx, 1); ctx = req->rq_cli_ctx; LASSERT(list_empty(&req->rq_ctx_chain)); @@ -534,12 +656,14 @@ again: ctx_refresh_interrupt, req); rc = l_wait_event(req->rq_reply_waitq, ctx_check_refresh(ctx), &lwi); - /* five cases we are here: - * 1. successfully refreshed; - * 2. someone else mark this ctx dead by force; - * 3. interruptted; - * 4. timedout, and we don't want recover from the failure; - * 5. timedout, and waked up upon recovery finished; + /* following cases we could be here: + * - successfully refreshed; + * - interruptted; + * - timedout, and we don't want recover from the failure; + * - timedout, and waked up upon recovery finished; + * - someone else mark this ctx dead by force; + * - someone invalidate the req and call wake_client_req(), + * e.g. ptlrpc_abort_inflight(); */ if (!cli_ctx_is_refreshed(ctx)) { /* timed out or interruptted */ @@ -552,12 +676,16 @@ again: goto again; } +/* + * Note this could be called in two situations: + * - new request from ptlrpc_pre_req(), with proper @opcode + * - old request which changed ctx in the middle, with @opcode == 0 + */ void sptlrpc_req_set_flavor(struct ptlrpc_request *req, int opcode) { - struct sec_flavor_config *conf; + struct ptlrpc_sec *sec; LASSERT(req->rq_import); - LASSERT(req->rq_import->imp_sec); LASSERT(req->rq_cli_ctx); LASSERT(req->rq_cli_ctx->cc_sec); LASSERT(req->rq_bulk_read == 0 || req->rq_bulk_write == 0); @@ -576,44 +704,45 @@ void sptlrpc_req_set_flavor(struct ptlrpc_request *req, int opcode) case SEC_CTX_FINI: req->rq_ctx_fini = 1; break; + case 0: + /* init/fini rpc won't be resend, so can't be here */ + LASSERT(req->rq_ctx_init == 0); + LASSERT(req->rq_ctx_fini == 0); + + /* cleanup flags, which should be recalculated */ + req->rq_pack_udesc = 0; + req->rq_pack_bulk = 0; + break; } - req->rq_sec_flavor = req->rq_cli_ctx->cc_sec->ps_flavor; + sec = req->rq_cli_ctx->cc_sec; + + spin_lock(&sec->ps_lock); + req->rq_flvr = sec->ps_flvr; + spin_unlock(&sec->ps_lock); /* force SVC_NULL for context initiation rpc, SVC_INTG for context - * destruction rpc - */ - if (unlikely(req->rq_ctx_init)) { - req->rq_sec_flavor = SEC_MAKE_RPC_FLAVOR( - SEC_FLAVOR_POLICY(req->rq_sec_flavor), - SEC_FLAVOR_MECH(req->rq_sec_flavor), - SPTLRPC_SVC_NULL); - } else if (unlikely(req->rq_ctx_fini)) { - req->rq_sec_flavor = SEC_MAKE_RPC_FLAVOR( - SEC_FLAVOR_POLICY(req->rq_sec_flavor), - SEC_FLAVOR_MECH(req->rq_sec_flavor), - SPTLRPC_SVC_INTG); - } - - conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf; - - /* user descriptor flag, except ROOTONLY which don't need, and - * null security which can't - */ - if ((conf->sfc_flags & PTLRPC_SEC_FL_ROOTONLY) == 0 && - req->rq_sec_flavor != SPTLRPC_FLVR_NULL) - req->rq_sec_flavor |= SEC_FLAVOR_FL_USER; + * destruction rpc */ + if (unlikely(req->rq_ctx_init)) + rpc_flvr_set_svc(&req->rq_flvr.sf_rpc, SPTLRPC_SVC_NULL); + else if (unlikely(req->rq_ctx_fini)) + rpc_flvr_set_svc(&req->rq_flvr.sf_rpc, SPTLRPC_SVC_INTG); + + /* user descriptor flag, null security can't do it anyway */ + if ((sec->ps_flvr.sf_flags & PTLRPC_SEC_FL_UDESC) && + (req->rq_flvr.sf_rpc != SPTLRPC_FLVR_NULL)) + req->rq_pack_udesc = 1; /* bulk security flag */ if ((req->rq_bulk_read || req->rq_bulk_write) && - (conf->sfc_bulk_priv != BULK_PRIV_ALG_NULL || - conf->sfc_bulk_csum != BULK_CSUM_ALG_NULL)) - req->rq_sec_flavor |= SEC_FLAVOR_FL_BULK; + (req->rq_flvr.sf_bulk_priv != BULK_PRIV_ALG_NULL || + req->rq_flvr.sf_bulk_csum != BULK_CSUM_ALG_NULL)) + req->rq_pack_bulk = 1; } void sptlrpc_request_out_callback(struct ptlrpc_request *req) { - if (SEC_FLAVOR_SVC(req->rq_sec_flavor) != SPTLRPC_SVC_PRIV) + if (RPC_FLVR_SVC(req->rq_flvr.sf_rpc) != SPTLRPC_SVC_PRIV) return; LASSERT(req->rq_clrbuf); @@ -632,6 +761,7 @@ void sptlrpc_request_out_callback(struct ptlrpc_request *req) */ int sptlrpc_import_check_ctx(struct obd_import *imp) { + struct ptlrpc_sec *sec; struct ptlrpc_cli_ctx *ctx; struct ptlrpc_request *req = NULL; int rc; @@ -639,7 +769,10 @@ int sptlrpc_import_check_ctx(struct obd_import *imp) might_sleep(); - ctx = get_my_ctx(imp->imp_sec); + sec = sptlrpc_import_sec_ref(imp); + ctx = get_my_ctx(sec); + sptlrpc_sec_put(sec); + if (!ctx) RETURN(1); @@ -687,7 +820,7 @@ int sptlrpc_cli_wrap_request(struct ptlrpc_request *req) RETURN(rc); } - switch (SEC_FLAVOR_SVC(req->rq_sec_flavor)) { + switch (RPC_FLVR_SVC(req->rq_flvr.sf_rpc)) { case SPTLRPC_SVC_NULL: case SPTLRPC_SVC_AUTH: case SPTLRPC_SVC_INTG: @@ -717,7 +850,7 @@ int sptlrpc_cli_wrap_request(struct ptlrpc_request *req) int sptlrpc_cli_unwrap_reply(struct ptlrpc_request *req) { struct ptlrpc_cli_ctx *ctx = req->rq_cli_ctx; - int rc; + int rc; ENTRY; LASSERT(ctx); @@ -733,38 +866,45 @@ int sptlrpc_cli_unwrap_reply(struct ptlrpc_request *req) RETURN(-EPROTO); } + if (req->rq_repbuf->lm_magic == LUSTRE_MSG_MAGIC_V1 || req->rq_repbuf->lm_magic == LUSTRE_MSG_MAGIC_V1_SWABBED) { - /* it's must be null flavor, so our requets also should be - * in null flavor */ - if (SEC_FLAVOR_POLICY(req->rq_sec_flavor) != + /* + * v1 message, it's must be null flavor, so our requets also + * should be in null flavor + */ + if (RPC_FLVR_POLICY(req->rq_flvr.sf_rpc) != SPTLRPC_POLICY_NULL) { - CERROR("request flavor is %x but reply with null\n", - req->rq_sec_flavor); + CERROR("request was %s but reply with null\n", + sptlrpc_rpcflavor2name(req->rq_flvr.sf_rpc)); RETURN(-EPROTO); } } else { - /* v2 message... */ - ptlrpc_sec_flavor_t tmpf = req->rq_repbuf->lm_secflvr; + /* + * v2 message, check request/reply policy match + */ + __u16 rpc_flvr = WIRE_FLVR_RPC(req->rq_repbuf->lm_secflvr); if (req->rq_repbuf->lm_magic == LUSTRE_MSG_MAGIC_V2_SWABBED) - __swab32s(&tmpf); + __swab16s(&rpc_flvr); - if (SEC_FLAVOR_POLICY(tmpf) != - SEC_FLAVOR_POLICY(req->rq_sec_flavor)) { - CERROR("request policy %u while reply with %d\n", - SEC_FLAVOR_POLICY(req->rq_sec_flavor), - SEC_FLAVOR_POLICY(tmpf)); + if (RPC_FLVR_POLICY(rpc_flvr) != + RPC_FLVR_POLICY(req->rq_flvr.sf_rpc)) { + CERROR("request policy was %u while reply with %u\n", + RPC_FLVR_POLICY(req->rq_flvr.sf_rpc), + RPC_FLVR_POLICY(rpc_flvr)); RETURN(-EPROTO); } - if ((SEC_FLAVOR_POLICY(req->rq_sec_flavor) != - SPTLRPC_POLICY_NULL) && + /* do nothing if it's null policy; otherwise unpack the + * wrapper message + */ + if (RPC_FLVR_POLICY(rpc_flvr) != SPTLRPC_POLICY_NULL && lustre_unpack_msg(req->rq_repbuf, req->rq_nob_received)) RETURN(-EPROTO); } - switch (SEC_FLAVOR_SVC(req->rq_sec_flavor)) { + switch (RPC_FLVR_SVC(req->rq_flvr.sf_rpc)) { case SPTLRPC_SVC_NULL: case SPTLRPC_SVC_AUTH: case SPTLRPC_SVC_INTG: @@ -784,16 +924,41 @@ int sptlrpc_cli_unwrap_reply(struct ptlrpc_request *req) } /************************************************** + * sec ID * + **************************************************/ + +/* + * "fixed" sec (e.g. null) use sec_id < 0 + */ +static atomic_t sptlrpc_sec_id = ATOMIC_INIT(1); + +int sptlrpc_get_next_secid(void) +{ + return atomic_inc_return(&sptlrpc_sec_id); +} +EXPORT_SYMBOL(sptlrpc_get_next_secid); + +/************************************************** * client side high-level security APIs * **************************************************/ -static -void sec_cop_destroy_sec(struct ptlrpc_sec *sec) +static int sec_cop_flush_ctx_cache(struct ptlrpc_sec *sec, uid_t uid, + int grace, int force) +{ + struct ptlrpc_sec_policy *policy = sec->ps_policy; + + LASSERT(policy->sp_cops); + LASSERT(policy->sp_cops->flush_ctx_cache); + + return policy->sp_cops->flush_ctx_cache(sec, uid, grace, force); +} + +static void sec_cop_destroy_sec(struct ptlrpc_sec *sec) { struct ptlrpc_sec_policy *policy = sec->ps_policy; LASSERT(atomic_read(&sec->ps_refcount) == 0); - LASSERT(atomic_read(&sec->ps_busy) == 0); + LASSERT(atomic_read(&sec->ps_nctx) == 0); LASSERT(policy->sp_cops->destroy_sec); CDEBUG(D_SEC, "%s@%p: being destroied\n", sec->ps_policy->sp_name, sec); @@ -802,156 +967,316 @@ void sec_cop_destroy_sec(struct ptlrpc_sec *sec) sptlrpc_policy_put(policy); } -static -int sec_cop_flush_ctx_cache(struct ptlrpc_sec *sec, uid_t uid, - int grace, int force) +void sptlrpc_sec_destroy(struct ptlrpc_sec *sec) { - struct ptlrpc_sec_policy *policy = sec->ps_policy; + sec_cop_destroy_sec(sec); +} +EXPORT_SYMBOL(sptlrpc_sec_destroy); - LASSERT(policy->sp_cops); - LASSERT(policy->sp_cops->flush_ctx_cache); +static void sptlrpc_sec_kill(struct ptlrpc_sec *sec) +{ + LASSERT(atomic_read(&sec->ps_refcount) > 0); - return policy->sp_cops->flush_ctx_cache(sec, uid, grace, force); + if (sec->ps_policy->sp_cops->kill_sec) { + sec->ps_policy->sp_cops->kill_sec(sec); + + sec_cop_flush_ctx_cache(sec, -1, 1, 1); + } } -void sptlrpc_sec_destroy(struct ptlrpc_sec *sec) +struct ptlrpc_sec *sptlrpc_sec_get(struct ptlrpc_sec *sec) { - sec_cop_destroy_sec(sec); + if (sec) { + LASSERT(atomic_read(&sec->ps_refcount) > 0); + atomic_inc(&sec->ps_refcount); + } + + return sec; } -EXPORT_SYMBOL(sptlrpc_sec_destroy); +EXPORT_SYMBOL(sptlrpc_sec_get); + +void sptlrpc_sec_put(struct ptlrpc_sec *sec) +{ + if (sec) { + LASSERT(atomic_read(&sec->ps_refcount) > 0); + + if (atomic_dec_and_test(&sec->ps_refcount)) { + LASSERT(atomic_read(&sec->ps_nctx) == 0); + + sptlrpc_gc_del_sec(sec); + sec_cop_destroy_sec(sec); + } + } +} +EXPORT_SYMBOL(sptlrpc_sec_put); /* - * let policy module to determine whether take refrence of - * import or not. + * it's policy module responsible for taking refrence of import */ static -struct ptlrpc_sec * import_create_sec(struct obd_import *imp, - struct ptlrpc_svc_ctx *ctx, - __u32 flavor, - unsigned long flags) +struct ptlrpc_sec * sptlrpc_sec_create(struct obd_import *imp, + struct ptlrpc_svc_ctx *svc_ctx, + struct sptlrpc_flavor *sf, + enum lustre_sec_part sp) { struct ptlrpc_sec_policy *policy; - struct ptlrpc_sec *sec; + struct ptlrpc_sec *sec; ENTRY; - flavor = SEC_FLAVOR_RPC(flavor); - - if (ctx) { + if (svc_ctx) { LASSERT(imp->imp_dlm_fake == 1); CDEBUG(D_SEC, "%s %s: reverse sec using flavor %s\n", imp->imp_obd->obd_type->typ_name, imp->imp_obd->obd_name, - sptlrpc_flavor2name(flavor)); + sptlrpc_rpcflavor2name(sf->sf_rpc)); - policy = sptlrpc_policy_get(ctx->sc_policy); - flags |= PTLRPC_SEC_FL_REVERSE | PTLRPC_SEC_FL_ROOTONLY; + policy = sptlrpc_policy_get(svc_ctx->sc_policy); + sf->sf_flags |= PTLRPC_SEC_FL_REVERSE | PTLRPC_SEC_FL_ROOTONLY; } else { LASSERT(imp->imp_dlm_fake == 0); CDEBUG(D_SEC, "%s %s: select security flavor %s\n", imp->imp_obd->obd_type->typ_name, imp->imp_obd->obd_name, - sptlrpc_flavor2name(flavor)); + sptlrpc_rpcflavor2name(sf->sf_rpc)); - policy = sptlrpc_flavor2policy(flavor); + policy = sptlrpc_rpcflavor2policy(sf->sf_rpc); if (!policy) { - CERROR("invalid flavor 0x%x\n", flavor); + CERROR("invalid flavor 0x%x\n", sf->sf_rpc); RETURN(NULL); } } - sec = policy->sp_cops->create_sec(imp, ctx, flavor, flags); + sec = policy->sp_cops->create_sec(imp, svc_ctx, sf); if (sec) { atomic_inc(&sec->ps_refcount); - /* take 1 busy count on behalf of sec itself, - * balanced in sptlrpc_set_put() - */ - atomic_inc(&sec->ps_busy); + sec->ps_part = sp; if (sec->ps_gc_interval && policy->sp_cops->gc_ctx) sptlrpc_gc_add_sec(sec); - } else + } else { sptlrpc_policy_put(policy); + } RETURN(sec); } -int sptlrpc_import_get_sec(struct obd_import *imp, - struct ptlrpc_svc_ctx *ctx, - __u32 flavor, - unsigned long flags) +struct ptlrpc_sec *sptlrpc_import_sec_ref(struct obd_import *imp) { - might_sleep(); + struct ptlrpc_sec *sec; - /* old sec might be still there in reconnecting */ - if (imp->imp_sec) - return 0; + spin_lock(&imp->imp_lock); + sec = sptlrpc_sec_get(imp->imp_sec); + spin_unlock(&imp->imp_lock); - imp->imp_sec = import_create_sec(imp, ctx, flavor, flags); - if (!imp->imp_sec) - return -EINVAL; + return sec; +} +EXPORT_SYMBOL(sptlrpc_import_sec_ref); - return 0; +static void sptlrpc_import_sec_install(struct obd_import *imp, + struct ptlrpc_sec *sec) +{ + struct ptlrpc_sec *old_sec; + + LASSERT(atomic_read(&sec->ps_refcount) > 0); + + spin_lock(&imp->imp_lock); + old_sec = imp->imp_sec; + imp->imp_sec = sec; + spin_unlock(&imp->imp_lock); + + if (old_sec) { + sptlrpc_sec_kill(old_sec); + + /* balance the ref taken by this import */ + sptlrpc_sec_put(old_sec); + } +} + +static void sptlrpc_import_sec_adapt_inplace(struct obd_import *imp, + struct ptlrpc_sec *sec, + struct sptlrpc_flavor *sf) +{ + if (sf->sf_bulk_priv != sec->ps_flvr.sf_bulk_priv || + sf->sf_bulk_csum != sec->ps_flvr.sf_bulk_csum) { + CWARN("imp %p (%s->%s): changing bulk flavor %s/%s -> %s/%s\n", + imp, imp->imp_obd->obd_name, + obd_uuid2str(&imp->imp_connection->c_remote_uuid), + sptlrpc_bulk_priv_alg2name(sec->ps_flvr.sf_bulk_priv), + sptlrpc_bulk_csum_alg2name(sec->ps_flvr.sf_bulk_csum), + sptlrpc_bulk_priv_alg2name(sf->sf_bulk_priv), + sptlrpc_bulk_csum_alg2name(sf->sf_bulk_csum)); + + spin_lock(&sec->ps_lock); + sec->ps_flvr.sf_bulk_priv = sf->sf_bulk_priv; + sec->ps_flvr.sf_bulk_csum = sf->sf_bulk_csum; + spin_unlock(&sec->ps_lock); + } + + if (!equi(sf->sf_flags & PTLRPC_SEC_FL_UDESC, + sec->ps_flvr.sf_flags & PTLRPC_SEC_FL_UDESC)) { + CWARN("imp %p (%s->%s): %s shipping user descriptor\n", + imp, imp->imp_obd->obd_name, + obd_uuid2str(&imp->imp_connection->c_remote_uuid), + (sf->sf_flags & PTLRPC_SEC_FL_UDESC) ? "start" : "stop"); + + spin_lock(&sec->ps_lock); + sec->ps_flvr.sf_flags &= ~PTLRPC_SEC_FL_UDESC; + sec->ps_flvr.sf_flags |= sf->sf_flags & PTLRPC_SEC_FL_UDESC; + spin_unlock(&sec->ps_lock); + } } -void sptlrpc_import_put_sec(struct obd_import *imp) +/* + * for normal import, @svc_ctx should be NULL and @rpc_flavor is ignored; + * for reverse import, @svc_ctx and @rpc_flavor is from incoming request. + */ +int sptlrpc_import_sec_adapt(struct obd_import *imp, + struct ptlrpc_svc_ctx *svc_ctx, + __u16 rpc_flavor) { - struct ptlrpc_sec *sec; - struct ptlrpc_sec_policy *policy; + struct ptlrpc_connection *conn; + struct sptlrpc_flavor sf; + struct ptlrpc_sec *sec, *newsec; + enum lustre_sec_part sp; + int rc; - might_sleep(); + if (imp == NULL) + return 0; - if (imp->imp_sec == NULL) - return; + conn = imp->imp_connection; - sec = imp->imp_sec; - policy = sec->ps_policy; + if (svc_ctx == NULL) { + /* normal import, determine flavor from rule set */ + sptlrpc_rule_set_choose(&imp->imp_obd->u.cli.cl_sptlrpc_rset, + LUSTRE_SP_ANY, conn->c_self, &sf); - if (atomic_dec_and_test(&sec->ps_refcount)) { - sec_cop_flush_ctx_cache(sec, -1, 1, 1); - sptlrpc_gc_del_sec(sec); + sp = imp->imp_obd->u.cli.cl_sec_part; + } else { + /* reverse import, determine flavor from incoming reqeust */ + sf.sf_rpc = rpc_flavor; + sf.sf_bulk_priv = BULK_PRIV_ALG_NULL; + sf.sf_bulk_csum = BULK_CSUM_ALG_NULL; + sf.sf_flags = PTLRPC_SEC_FL_REVERSE | PTLRPC_SEC_FL_ROOTONLY; - if (atomic_dec_and_test(&sec->ps_busy)) - sec_cop_destroy_sec(sec); - else { - CWARN("delay destroying busy sec %s %p\n", - policy->sp_name, sec); + sp = sptlrpc_target_sec_part(imp->imp_obd); + } + + sec = sptlrpc_import_sec_ref(imp); + if (sec) { + if (svc_ctx == NULL) { + /* normal import, only check rpc flavor, if just bulk + * flavor or flags changed, we can handle it on the fly + * without switching sec. */ + if (sf.sf_rpc == sec->ps_flvr.sf_rpc) { + sptlrpc_import_sec_adapt_inplace(imp, sec, &sf); + + rc = 0; + goto out; + } + } else { + /* reverse import, do not compare bulk flavor */ + if (sf.sf_rpc == sec->ps_flvr.sf_rpc) { + rc = 0; + goto out; + } } + + CWARN("%simport %p (%s%s%s): changing flavor " + "(%s, %s/%s) -> (%s, %s/%s)\n", + svc_ctx ? "reverse " : "", + imp, imp->imp_obd->obd_name, + svc_ctx == NULL ? "->" : "<-", + obd_uuid2str(&conn->c_remote_uuid), + sptlrpc_rpcflavor2name(sec->ps_flvr.sf_rpc), + sptlrpc_bulk_csum_alg2name(sec->ps_flvr.sf_bulk_csum), + sptlrpc_bulk_priv_alg2name(sec->ps_flvr.sf_bulk_priv), + sptlrpc_rpcflavor2name(sf.sf_rpc), + sptlrpc_bulk_csum_alg2name(sf.sf_bulk_csum), + sptlrpc_bulk_priv_alg2name(sf.sf_bulk_priv)); } else { - sptlrpc_policy_put(policy); + CWARN("%simport %p (%s%s%s) netid %x: " + "select initial flavor (%s, %s/%s)\n", + svc_ctx == NULL ? "" : "reverse ", + imp, imp->imp_obd->obd_name, + svc_ctx == NULL ? "->" : "<-", + obd_uuid2str(&conn->c_remote_uuid), + LNET_NIDNET(conn->c_self), + sptlrpc_rpcflavor2name(sf.sf_rpc), + sptlrpc_bulk_csum_alg2name(sf.sf_bulk_csum), + sptlrpc_bulk_priv_alg2name(sf.sf_bulk_priv)); + } + + mutex_down(&imp->imp_sec_mutex); + + newsec = sptlrpc_sec_create(imp, svc_ctx, &sf, sp); + if (newsec) { + sptlrpc_import_sec_install(imp, newsec); + rc = 0; + } else { + CERROR("%simport %p (%s): failed to create new sec\n", + svc_ctx == NULL ? "" : "reverse ", + imp, obd_uuid2str(&conn->c_remote_uuid)); + rc = -EPERM; } - imp->imp_sec = NULL; + mutex_up(&imp->imp_sec_mutex); + +out: + sptlrpc_sec_put(sec); + return 0; } -void sptlrpc_import_flush_root_ctx(struct obd_import *imp) +void sptlrpc_import_sec_put(struct obd_import *imp) { - if (imp == NULL || imp->imp_sec == NULL) + if (imp->imp_sec) { + sptlrpc_sec_kill(imp->imp_sec); + + sptlrpc_sec_put(imp->imp_sec); + imp->imp_sec = NULL; + } +} + +static void import_flush_ctx_common(struct obd_import *imp, + uid_t uid, int grace, int force) +{ + struct ptlrpc_sec *sec; + + if (imp == NULL) + return; + + sec = sptlrpc_import_sec_ref(imp); + if (sec == NULL) return; + sec_cop_flush_ctx_cache(sec, uid, grace, force); + sptlrpc_sec_put(sec); +} + +void sptlrpc_import_inval_all_ctx(struct obd_import *imp) +{ + /* use grace == 0 */ + import_flush_ctx_common(imp, -1, 0, 1); +} + +void sptlrpc_import_flush_root_ctx(struct obd_import *imp) +{ /* it's important to use grace mode, see explain in - * sptlrpc_req_refresh_ctx() - */ - sec_cop_flush_ctx_cache(imp->imp_sec, 0, 1, 1); + * sptlrpc_req_refresh_ctx() */ + import_flush_ctx_common(imp, 0, 1, 1); } void sptlrpc_import_flush_my_ctx(struct obd_import *imp) { - if (imp == NULL || imp->imp_sec == NULL) - return; - - sec_cop_flush_ctx_cache(imp->imp_sec, cfs_current()->uid, 1, 1); + import_flush_ctx_common(imp, cfs_current()->uid, 1, 1); } EXPORT_SYMBOL(sptlrpc_import_flush_my_ctx); void sptlrpc_import_flush_all_ctx(struct obd_import *imp) { - if (imp == NULL || imp->imp_sec == NULL) - return; - - sec_cop_flush_ctx_cache(imp->imp_sec, -1, 1, 1); + import_flush_ctx_common(imp, -1, 1, 1); } EXPORT_SYMBOL(sptlrpc_import_flush_all_ctx); @@ -994,7 +1319,9 @@ void sptlrpc_cli_free_reqbuf(struct ptlrpc_request *req) LASSERT(atomic_read(&ctx->cc_refcount)); LASSERT(ctx->cc_sec); LASSERT(ctx->cc_sec->ps_policy); - LASSERT(req->rq_reqbuf || req->rq_clrbuf); + + if (req->rq_reqbuf == NULL && req->rq_clrbuf == NULL) + return; policy = ctx->cc_sec->ps_policy; policy->sp_cops->free_reqbuf(ctx->cc_sec, req); @@ -1101,7 +1428,10 @@ void sptlrpc_cli_free_repbuf(struct ptlrpc_request *req) LASSERT(atomic_read(&ctx->cc_refcount)); LASSERT(ctx->cc_sec); LASSERT(ctx->cc_sec->ps_policy); - LASSERT(req->rq_repbuf); + + if (req->rq_repbuf == NULL) + return; + LASSERT(req->rq_repbuf_len); policy = ctx->cc_sec->ps_policy; policy->sp_cops->free_repbuf(ctx->cc_sec, req); @@ -1132,19 +1462,259 @@ int sptlrpc_svc_install_rvs_ctx(struct obd_import *imp, * server side security * ****************************************/ +static int flavor_allowed(struct sptlrpc_flavor *exp, + struct ptlrpc_request *req) +{ + struct sptlrpc_flavor *flvr = &req->rq_flvr; + + if (exp->sf_rpc == flvr->sf_rpc) + return 1; + + if ((req->rq_ctx_init || req->rq_ctx_fini) && + RPC_FLVR_POLICY(exp->sf_rpc) == RPC_FLVR_POLICY(flvr->sf_rpc) && + RPC_FLVR_MECH(exp->sf_rpc) == RPC_FLVR_MECH(flvr->sf_rpc)) + return 1; + + return 0; +} + +#define EXP_FLVR_UPDATE_EXPIRE (OBD_TIMEOUT_DEFAULT + 10) + int sptlrpc_target_export_check(struct obd_export *exp, struct ptlrpc_request *req) { - if (!req->rq_auth_gss || - (!req->rq_auth_usr_root && !req->rq_auth_usr_mdt)) + struct sptlrpc_flavor flavor; + + if (exp == NULL) return 0; - if (!req->rq_ctx_init) + /* client side export has no imp_reverse, skip + * FIXME maybe we should check flavor this as well??? */ + if (exp->exp_imp_reverse == NULL) return 0; - LASSERT(exp->exp_imp_reverse); - sptlrpc_svc_install_rvs_ctx(exp->exp_imp_reverse, req->rq_svc_ctx); - return 0; + /* don't care about ctx fini rpc */ + if (req->rq_ctx_fini) + return 0; + + spin_lock(&exp->exp_lock); + + /* if flavor just changed (exp->exp_flvr_changed != 0), we wait for + * the first req with the new flavor, then treat it as current flavor, + * adapt reverse sec according to it. + * note the first rpc with new flavor might not be with root ctx, in + * which case delay the sec_adapt by leaving exp_flvr_adapt == 1. */ + if (unlikely(exp->exp_flvr_changed) && + flavor_allowed(&exp->exp_flvr_old[1], req)) { + /* make the new flavor as "current", and old ones as + * about-to-expire */ + CDEBUG(D_SEC, "exp %p: just changed: %x->%x\n", exp, + exp->exp_flvr.sf_rpc, exp->exp_flvr_old[1].sf_rpc); + flavor = exp->exp_flvr_old[1]; + exp->exp_flvr_old[1] = exp->exp_flvr_old[0]; + exp->exp_flvr_expire[1] = exp->exp_flvr_expire[0]; + exp->exp_flvr_old[0] = exp->exp_flvr; + exp->exp_flvr_expire[0] = cfs_time_current_sec() + + EXP_FLVR_UPDATE_EXPIRE; + exp->exp_flvr = flavor; + + /* flavor change finished */ + exp->exp_flvr_changed = 0; + LASSERT(exp->exp_flvr_adapt == 1); + + /* if it's gss, we only interested in root ctx init */ + if (req->rq_auth_gss && + !(req->rq_ctx_init && (req->rq_auth_usr_root || + req->rq_auth_usr_mdt))) { + spin_unlock(&exp->exp_lock); + CDEBUG(D_SEC, "is good but not root(%d:%d:%d:%d)\n", + req->rq_auth_gss, req->rq_ctx_init, + req->rq_auth_usr_root, req->rq_auth_usr_mdt); + return 0; + } + + exp->exp_flvr_adapt = 0; + spin_unlock(&exp->exp_lock); + + return sptlrpc_import_sec_adapt(exp->exp_imp_reverse, + req->rq_svc_ctx, flavor.sf_rpc); + } + + /* if it equals to the current flavor, we accept it, but need to + * dealing with reverse sec/ctx */ + if (likely(flavor_allowed(&exp->exp_flvr, req))) { + /* most cases should return here, we only interested in + * gss root ctx init */ + if (!req->rq_auth_gss || !req->rq_ctx_init || + (!req->rq_auth_usr_root && !req->rq_auth_usr_mdt)) { + spin_unlock(&exp->exp_lock); + return 0; + } + + if (exp->exp_flvr_adapt) { + exp->exp_flvr_adapt = 0; + CDEBUG(D_SEC, "exp %p (%x|%x|%x): do delayed adapt\n", + exp, exp->exp_flvr.sf_rpc, + exp->exp_flvr_old[0].sf_rpc, + exp->exp_flvr_old[1].sf_rpc); + flavor = exp->exp_flvr; + spin_unlock(&exp->exp_lock); + + return sptlrpc_import_sec_adapt(exp->exp_imp_reverse, + req->rq_svc_ctx, + flavor.sf_rpc); + } else { + CDEBUG(D_SEC, "exp %p (%x|%x|%x): is current flavor, " + "install rvs ctx\n", exp, exp->exp_flvr.sf_rpc, + exp->exp_flvr_old[0].sf_rpc, + exp->exp_flvr_old[1].sf_rpc); + spin_unlock(&exp->exp_lock); + + return sptlrpc_svc_install_rvs_ctx(exp->exp_imp_reverse, + req->rq_svc_ctx); + } + } + + if (exp->exp_flvr_expire[0]) { + if (exp->exp_flvr_expire[0] >= cfs_time_current_sec()) { + if (flavor_allowed(&exp->exp_flvr_old[0], req)) { + CDEBUG(D_SEC, "exp %p (%x|%x|%x): match the " + "middle one (%lu)\n", exp, + exp->exp_flvr.sf_rpc, + exp->exp_flvr_old[0].sf_rpc, + exp->exp_flvr_old[1].sf_rpc, + exp->exp_flvr_expire[0] - + cfs_time_current_sec()); + spin_unlock(&exp->exp_lock); + return 0; + } + } else { + CDEBUG(D_SEC, "mark middle expired\n"); + exp->exp_flvr_expire[0] = 0; + } + CDEBUG(D_SEC, "exp %p (%x|%x|%x): %x not match middle\n", exp, + exp->exp_flvr.sf_rpc, + exp->exp_flvr_old[0].sf_rpc, exp->exp_flvr_old[1].sf_rpc, + req->rq_flvr.sf_rpc); + } + + /* now it doesn't match the current flavor, the only chance we can + * accept it is match the old flavors which is not expired. */ + if (exp->exp_flvr_changed == 0 && exp->exp_flvr_expire[1]) { + if (exp->exp_flvr_expire[1] >= cfs_time_current_sec()) { + if (flavor_allowed(&exp->exp_flvr_old[1], req)) { + CDEBUG(D_SEC, "exp %p (%x|%x|%x): match the " + "oldest one (%lu)\n", exp, + exp->exp_flvr.sf_rpc, + exp->exp_flvr_old[0].sf_rpc, + exp->exp_flvr_old[1].sf_rpc, + exp->exp_flvr_expire[1] - + cfs_time_current_sec()); + spin_unlock(&exp->exp_lock); + return 0; + } + } else { + CDEBUG(D_SEC, "mark oldest expired\n"); + exp->exp_flvr_expire[1] = 0; + } + CDEBUG(D_SEC, "exp %p (%x|%x|%x): %x not match found\n", + exp, exp->exp_flvr.sf_rpc, + exp->exp_flvr_old[0].sf_rpc, exp->exp_flvr_old[1].sf_rpc, + req->rq_flvr.sf_rpc); + } else { + CDEBUG(D_SEC, "exp %p (%x|%x|%x): skip the last one\n", + exp, exp->exp_flvr.sf_rpc, exp->exp_flvr_old[0].sf_rpc, + exp->exp_flvr_old[1].sf_rpc); + } + + spin_unlock(&exp->exp_lock); + + CWARN("req %p: (%u|%u|%u|%u|%u) with unauthorized flavor %x\n", + req, req->rq_auth_gss, req->rq_ctx_init, req->rq_ctx_fini, + req->rq_auth_usr_root, req->rq_auth_usr_mdt, req->rq_flvr.sf_rpc); + return -EACCES; +} + +void sptlrpc_target_update_exp_flavor(struct obd_device *obd, + struct sptlrpc_rule_set *rset) +{ + struct obd_export *exp; + struct sptlrpc_flavor new_flvr; + + LASSERT(obd); + + spin_lock(&obd->obd_dev_lock); + + list_for_each_entry(exp, &obd->obd_exports, exp_obd_chain) { + if (exp->exp_connection == NULL) + continue; + + /* note if this export had just been updated flavor + * (exp_flvr_changed == 1), this will override the + * previous one. */ + spin_lock(&exp->exp_lock); + sptlrpc_rule_set_choose(rset, exp->exp_sp_peer, + exp->exp_connection->c_peer.nid, + &new_flvr); + if (exp->exp_flvr_changed || + memcmp(&new_flvr, &exp->exp_flvr, sizeof(new_flvr))) { + exp->exp_flvr_old[1] = new_flvr; + exp->exp_flvr_expire[1] = 0; + exp->exp_flvr_changed = 1; + exp->exp_flvr_adapt = 1; + CDEBUG(D_SEC, "exp %p (%s): updated flavor %x->%x\n", + exp, sptlrpc_part2name(exp->exp_sp_peer), + exp->exp_flvr.sf_rpc, + exp->exp_flvr_old[1].sf_rpc); + } + spin_unlock(&exp->exp_lock); + } + + spin_unlock(&obd->obd_dev_lock); +} +EXPORT_SYMBOL(sptlrpc_target_update_exp_flavor); + +static int sptlrpc_svc_check_from(struct ptlrpc_request *req, int svc_rc) +{ + if (svc_rc == SECSVC_DROP) + return SECSVC_DROP; + + switch (req->rq_sp_from) { + case LUSTRE_SP_CLI: + case LUSTRE_SP_MDT: + case LUSTRE_SP_OST: + case LUSTRE_SP_MGS: + case LUSTRE_SP_ANY: + break; + default: + DEBUG_REQ(D_ERROR, req, "invalid source %u", req->rq_sp_from); + return SECSVC_DROP; + } + + if (!req->rq_auth_gss) + return svc_rc; + + if (unlikely(req->rq_sp_from == LUSTRE_SP_ANY)) { + CERROR("not specific part\n"); + return SECSVC_DROP; + } + + /* from MDT, must be authenticated as MDT */ + if (unlikely(req->rq_sp_from == LUSTRE_SP_MDT && + !req->rq_auth_usr_mdt)) { + DEBUG_REQ(D_ERROR, req, "fake source MDT"); + return SECSVC_DROP; + } + + /* from OST, must be callback to MDT and CLI, the reverse sec + * was from mdt/root keytab, so it should be MDT or root FIXME */ + if (unlikely(req->rq_sp_from == LUSTRE_SP_OST && + !req->rq_auth_usr_mdt && !req->rq_auth_usr_root)) { + DEBUG_REQ(D_ERROR, req, "fake source OST"); + return SECSVC_DROP; + } + + return svc_rc; } int sptlrpc_svc_unwrap_request(struct ptlrpc_request *req) @@ -1158,10 +1728,10 @@ int sptlrpc_svc_unwrap_request(struct ptlrpc_request *req) LASSERT(req->rq_reqmsg == NULL); LASSERT(req->rq_repmsg == NULL); - /* - * in any case we avoid to call unpack_msg() for request of null flavor - * which will later be done by ptlrpc_server_handle_request(). - */ + req->rq_sp_from = LUSTRE_SP_ANY; + req->rq_auth_uid = INVALID_UID; + req->rq_auth_mapped_uid = INVALID_UID; + if (req->rq_reqdata_len < sizeof(struct lustre_msg)) { CERROR("request size %d too small\n", req->rq_reqdata_len); RETURN(SECSVC_DROP); @@ -1169,22 +1739,30 @@ int sptlrpc_svc_unwrap_request(struct ptlrpc_request *req) if (msg->lm_magic == LUSTRE_MSG_MAGIC_V1 || msg->lm_magic == LUSTRE_MSG_MAGIC_V1_SWABBED) { - req->rq_sec_flavor = SPTLRPC_FLVR_NULL; + /* + * v1 message, treat as to be null + */ + req->rq_flvr.sf_rpc = SPTLRPC_FLVR_NULL; } else { - req->rq_sec_flavor = msg->lm_secflvr; - - if (msg->lm_magic == LUSTRE_MSG_MAGIC_V2_SWABBED) - __swab32s(&req->rq_sec_flavor); - - if ((SEC_FLAVOR_POLICY(req->rq_sec_flavor) != + /* + * v2 message. + */ + if (msg->lm_magic == LUSTRE_MSG_MAGIC_V2) + req->rq_flvr.sf_rpc = WIRE_FLVR_RPC(msg->lm_secflvr); + else + req->rq_flvr.sf_rpc = WIRE_FLVR_RPC( + __swab32(msg->lm_secflvr)); + + /* unpack the wrapper message if the policy is not null */ + if ((RPC_FLVR_POLICY(req->rq_flvr.sf_rpc) != SPTLRPC_POLICY_NULL) && lustre_unpack_msg(msg, req->rq_reqdata_len)) RETURN(SECSVC_DROP); } - policy = sptlrpc_flavor2policy(req->rq_sec_flavor); + policy = sptlrpc_rpcflavor2policy(req->rq_flvr.sf_rpc); if (!policy) { - CERROR("unsupported security flavor %x\n", req->rq_sec_flavor); + CERROR("unsupported rpc flavor %x\n", req->rq_flvr.sf_rpc); RETURN(SECSVC_DROP); } @@ -1194,6 +1772,9 @@ int sptlrpc_svc_unwrap_request(struct ptlrpc_request *req) LASSERT(req->rq_reqmsg || rc != SECSVC_OK); sptlrpc_policy_put(policy); + /* sanity check for the request source */ + rc = sptlrpc_svc_check_from(req, rc); + /* FIXME move to proper place */ if (rc == SECSVC_OK) { __u32 opc = lustre_msg_get_opc(req->rq_reqmsg); @@ -1329,7 +1910,7 @@ int sptlrpc_cli_wrap_bulk(struct ptlrpc_request *req, { struct ptlrpc_cli_ctx *ctx; - if (!SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) + if (!req->rq_pack_bulk) return 0; LASSERT(req->rq_bulk_read || req->rq_bulk_write); @@ -1376,7 +1957,7 @@ int sptlrpc_cli_unwrap_bulk_read(struct ptlrpc_request *req, struct ptlrpc_cli_ctx *ctx; int rc = 0; - if (!SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) + if (!req->rq_pack_bulk) return 0; LASSERT(req->rq_bulk_read && !req->rq_bulk_write); @@ -1404,7 +1985,7 @@ int sptlrpc_cli_unwrap_bulk_write(struct ptlrpc_request *req, { struct ptlrpc_cli_ctx *ctx; - if (!SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) + if (!req->rq_pack_bulk) return 0; LASSERT(!req->rq_bulk_read && req->rq_bulk_write); @@ -1422,7 +2003,7 @@ int sptlrpc_svc_wrap_bulk(struct ptlrpc_request *req, { struct ptlrpc_svc_ctx *ctx; - if (!SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) + if (!req->rq_pack_bulk) return 0; LASSERT(req->rq_bulk_read || req->rq_bulk_write); @@ -1440,7 +2021,7 @@ int sptlrpc_svc_unwrap_bulk(struct ptlrpc_request *req, { struct ptlrpc_svc_ctx *ctx; - if (!SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) + if (!req->rq_pack_bulk) return 0; LASSERT(req->rq_bulk_read || req->rq_bulk_write); @@ -1540,225 +2121,6 @@ int sptlrpc_unpack_user_desc(struct lustre_msg *msg, int offset) EXPORT_SYMBOL(sptlrpc_unpack_user_desc); /**************************************** - * user supplied flavor string parsing * - ****************************************/ - -static -int get_default_flavor(enum lustre_part to_part, struct sec_flavor_config *conf) -{ - conf->sfc_bulk_priv = BULK_PRIV_ALG_NULL; - conf->sfc_bulk_csum = BULK_CSUM_ALG_NULL; - conf->sfc_flags = 0; - - switch (to_part) { - case LUSTRE_MDT: - conf->sfc_rpc_flavor = SPTLRPC_FLVR_PLAIN; - return 0; - case LUSTRE_OST: - conf->sfc_rpc_flavor = SPTLRPC_FLVR_NULL; - return 0; - default: - CERROR("Unknown to lustre part %d, apply defaults\n", to_part); - conf->sfc_rpc_flavor = SPTLRPC_FLVR_NULL; - return -EINVAL; - } -} - -static -void get_flavor_by_rpc(__u32 rpc_flavor, struct sec_flavor_config *conf) -{ - conf->sfc_rpc_flavor = rpc_flavor; - conf->sfc_bulk_priv = BULK_PRIV_ALG_NULL; - conf->sfc_bulk_csum = BULK_CSUM_ALG_NULL; - conf->sfc_flags = 0; - - switch (rpc_flavor) { - case SPTLRPC_FLVR_NULL: - case SPTLRPC_FLVR_PLAIN: - case SPTLRPC_FLVR_KRB5N: - case SPTLRPC_FLVR_KRB5A: - break; - case SPTLRPC_FLVR_KRB5P: - conf->sfc_bulk_priv = BULK_PRIV_ALG_ARC4; - /* fall through */ - case SPTLRPC_FLVR_KRB5I: - conf->sfc_bulk_csum = BULK_CSUM_ALG_SHA1; - break; - default: - LBUG(); - } -} - -static -void get_flavor_by_rpc_bulk(__u32 rpc_flavor, int bulk_priv, - struct sec_flavor_config *conf) -{ - if (bulk_priv) - conf->sfc_bulk_priv = BULK_PRIV_ALG_ARC4; - else - conf->sfc_bulk_priv = BULK_PRIV_ALG_NULL; - - switch (rpc_flavor) { - case SPTLRPC_FLVR_PLAIN: - conf->sfc_bulk_csum = BULK_CSUM_ALG_MD5; - break; - case SPTLRPC_FLVR_KRB5N: - case SPTLRPC_FLVR_KRB5A: - case SPTLRPC_FLVR_KRB5I: - case SPTLRPC_FLVR_KRB5P: - conf->sfc_bulk_csum = BULK_CSUM_ALG_SHA1; - break; - default: - LBUG(); - } -} - -static __u32 __flavors[] = { - SPTLRPC_FLVR_NULL, - SPTLRPC_FLVR_PLAIN, - SPTLRPC_FLVR_KRB5N, - SPTLRPC_FLVR_KRB5A, - SPTLRPC_FLVR_KRB5I, - SPTLRPC_FLVR_KRB5P, -}; - -#define __nflavors (sizeof(__flavors)/sizeof(__u32)) - -/* - * flavor string format: rpc[-bulk{n|i|p}[:cksum/enc]] - * for examples: - * null - * plain-bulki - * krb5p-bulkn - * krb5i-bulkp - * krb5i-bulkp:sha512/arc4 - */ -int sptlrpc_parse_flavor(enum lustre_part from_part, enum lustre_part to_part, - char *str, struct sec_flavor_config *conf) -{ - char *f, *bulk, *alg, *enc; - char buf[64]; - int i, bulk_priv; - ENTRY; - - if (str == NULL) { - if (get_default_flavor(to_part, conf)) - return -EINVAL; - goto set_flags; - } - - for (i = 0; i < __nflavors; i++) { - f = sptlrpc_flavor2name(__flavors[i]); - if (strncmp(str, f, strlen(f)) == 0) - break; - } - - if (i >= __nflavors) - GOTO(invalid, -EINVAL); - - /* prepare local buffer thus we can modify it as we want */ - strncpy(buf, str, 64); - buf[64 - 1] = '\0'; - - /* find bulk string */ - bulk = strchr(buf, '-'); - if (bulk) - *bulk++ = '\0'; - - /* now the first part must equal to rpc flavor name */ - if (strcmp(buf, f) != 0) - GOTO(invalid, -EINVAL); - - get_flavor_by_rpc(__flavors[i], conf); - - if (bulk == NULL) - goto set_flags; - - /* null flavor should not have any suffix */ - if (__flavors[i] == SPTLRPC_FLVR_NULL) - GOTO(invalid, -EINVAL); - - /* find bulk algorithm string */ - alg = strchr(bulk, ':'); - if (alg) - *alg++ = '\0'; - - /* verify bulk section */ - if (strcmp(bulk, "bulkn") == 0) { - conf->sfc_bulk_csum = BULK_CSUM_ALG_NULL; - conf->sfc_bulk_priv = BULK_PRIV_ALG_NULL; - goto set_flags; - } - - if (strcmp(bulk, "bulki") == 0) - bulk_priv = 0; - else if (strcmp(bulk, "bulkp") == 0) - bulk_priv = 1; - else - GOTO(invalid, -EINVAL); - - /* plain policy dosen't support bulk encryption */ - if (bulk_priv && __flavors[i] == SPTLRPC_FLVR_PLAIN) - GOTO(invalid, -EINVAL); - - get_flavor_by_rpc_bulk(__flavors[i], bulk_priv, conf); - - if (alg == NULL) - goto set_flags; - - /* find encryption algorithm string */ - enc = strchr(alg, '/'); - if (enc) - *enc++ = '\0'; - - /* bulk combination sanity check */ - if ((bulk_priv && enc == NULL) || (bulk_priv == 0 && enc)) - GOTO(invalid, -EINVAL); - - /* checksum algorithm */ - for (i = 0; i < BULK_CSUM_ALG_MAX; i++) { - if (strcmp(alg, sptlrpc_bulk_csum_alg2name(i)) == 0) { - conf->sfc_bulk_csum = i; - break; - } - } - if (i >= BULK_CSUM_ALG_MAX) - GOTO(invalid, -EINVAL); - - /* privacy algorithm */ - if (enc) { - if (strcmp(enc, "arc4") != 0) - GOTO(invalid, -EINVAL); - conf->sfc_bulk_priv = BULK_PRIV_ALG_ARC4; - } - -set_flags: - /* * set ROOTONLY flag: - * - to OST - * - from MDT to MDT - * * set BULK flag for: - * - from CLI to OST - */ - if (to_part == LUSTRE_OST || - (from_part == LUSTRE_MDT && to_part == LUSTRE_MDT)) - conf->sfc_flags |= PTLRPC_SEC_FL_ROOTONLY; - if (from_part == LUSTRE_CLI && to_part == LUSTRE_OST) - conf->sfc_flags |= PTLRPC_SEC_FL_BULK; - -#ifdef __BIG_ENDIAN - __swab32s(&conf->sfc_rpc_flavor); - __swab32s(&conf->sfc_bulk_csum); - __swab32s(&conf->sfc_bulk_priv); - __swab32s(&conf->sfc_flags); -#endif - return 0; -invalid: - CERROR("invalid flavor string: %s\n", str); - return -EINVAL; -} -EXPORT_SYMBOL(sptlrpc_parse_flavor); - -/**************************************** * misc helpers * ****************************************/ diff --git a/lustre/ptlrpc/sec_bulk.c b/lustre/ptlrpc/sec_bulk.c index 6620bd0..5740220 100644 --- a/lustre/ptlrpc/sec_bulk.c +++ b/lustre/ptlrpc/sec_bulk.c @@ -1,7 +1,7 @@ /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * - * Copyright (C) 2006 Cluster File Systems, Inc. + * Copyright (C) 2006-2007 Cluster File Systems, Inc. * Author: Eric Mei * * This file is part of Lustre, http://www.lustre.org. @@ -52,49 +52,73 @@ #define PTRS_PER_PAGE (CFS_PAGE_SIZE / sizeof(void *)) #define PAGES_PER_POOL (PTRS_PER_PAGE) +#define IDLE_IDX_MAX (100) +#define IDLE_IDX_WEIGHT (3) + +#define CACHE_QUIESCENCE_PERIOD (20) + static struct ptlrpc_enc_page_pool { /* * constants */ unsigned long epp_max_pages; /* maximum pages can hold, const */ unsigned int epp_max_pools; /* number of pools, const */ - /* - * users of the pools. the capacity grow as more user added, - * but doesn't shrink when users gone -- just current policy. - * during failover there might be user add/remove activities. - */ - atomic_t epp_users; /* shared by how many users (osc) */ - atomic_t epp_users_gone; /* users removed */ + /* * wait queue in case of not enough free pages. */ cfs_waitq_t epp_waitq; /* waiting threads */ unsigned int epp_waitqlen; /* wait queue length */ unsigned long epp_pages_short; /* # of pages wanted of in-q users */ - unsigned long epp_adding:1, /* during adding pages */ - epp_full:1; /* pools are all full */ + unsigned int epp_growing:1; /* during adding pages */ + + /* + * indicating how idle the pools are, from 0 to MAX_IDLE_IDX + * this is counted based on each time when getting pages from + * the pools, not based on time. which means in case that system + * is idled for a while but the idle_idx might still be low if no + * activities happened in the pools. + */ + unsigned long epp_idle_idx; + + /* last shrink time due to mem tight */ + long epp_last_shrink; + long epp_last_access; + /* * in-pool pages bookkeeping */ spinlock_t epp_lock; /* protect following fields */ unsigned long epp_total_pages; /* total pages in pools */ unsigned long epp_free_pages; /* current pages available */ + /* * statistics */ - unsigned int epp_st_adds; - unsigned int epp_st_failadds; /* # of add pages failures */ - unsigned long epp_st_reqs; /* # of get_pages requests */ - unsigned long epp_st_missings; /* # of cache missing */ - unsigned long epp_st_lowfree; /* lowest free pages ever reached */ - unsigned long epp_st_max_wqlen;/* highest waitqueue length ever */ - cfs_time_t epp_st_max_wait; /* in jeffies */ + unsigned int epp_st_grows; /* # of grows */ + unsigned int epp_st_grow_fails; /* # of add pages failures */ + unsigned int epp_st_shrinks; /* # of shrinks */ + unsigned long epp_st_access; /* # of access */ + unsigned long epp_st_missings; /* # of cache missing */ + unsigned long epp_st_lowfree; /* lowest free pages reached */ + unsigned long epp_st_max_wqlen; /* highest waitqueue length */ + cfs_time_t epp_st_max_wait; /* in jeffies */ /* * pointers to pools */ cfs_page_t ***epp_pools; } page_pools; +/* + * memory shrinker + */ +const int pools_shrinker_seeks = DEFAULT_SEEKS; +static struct shrinker *pools_shrinker = NULL; + + +/* + * /proc/fs/lustre/sptlrpc/encrypt_page_pools + */ int sptlrpc_proc_read_enc_pool(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -107,42 +131,118 @@ int sptlrpc_proc_read_enc_pool(char *page, char **start, off_t off, int count, "pages per pool: %lu\n" "max pages: %lu\n" "max pools: %u\n" - "users: %d - %d\n" - "current waitqueue len: %u\n" - "current pages in short: %lu\n" "total pages: %lu\n" "total free: %lu\n" - "add page times: %u\n" - "add page failed times: %u\n" - "total requests: %lu\n" + "idle index: %lu/100\n" + "last shrink: %lds\n" + "last access: %lds\n" + "grows: %u\n" + "grows failure: %u\n" + "shrinks: %u\n" + "cache access: %lu\n" "cache missing: %lu\n" - "lowest free pages: %lu\n" + "low free mark: %lu\n" "max waitqueue depth: %lu\n" - "max wait time: "CFS_TIME_T"\n" + "max wait time: "CFS_TIME_T"/%u\n" , num_physpages, PAGES_PER_POOL, page_pools.epp_max_pages, page_pools.epp_max_pools, - atomic_read(&page_pools.epp_users), - atomic_read(&page_pools.epp_users_gone), - page_pools.epp_waitqlen, - page_pools.epp_pages_short, page_pools.epp_total_pages, page_pools.epp_free_pages, - page_pools.epp_st_adds, - page_pools.epp_st_failadds, - page_pools.epp_st_reqs, + page_pools.epp_idle_idx, + cfs_time_current_sec() - page_pools.epp_last_shrink, + cfs_time_current_sec() - page_pools.epp_last_access, + page_pools.epp_st_grows, + page_pools.epp_st_grow_fails, + page_pools.epp_st_shrinks, + page_pools.epp_st_access, page_pools.epp_st_missings, page_pools.epp_st_lowfree, page_pools.epp_st_max_wqlen, - page_pools.epp_st_max_wait + page_pools.epp_st_max_wait, HZ ); spin_unlock(&page_pools.epp_lock); return rc; } +static void enc_pools_release_free_pages(long npages) +{ + int p_idx, g_idx; + + LASSERT(npages <= page_pools.epp_free_pages); + + p_idx = (page_pools.epp_free_pages - 1) / PAGES_PER_POOL; + g_idx = (page_pools.epp_free_pages - 1) % PAGES_PER_POOL; + LASSERT(page_pools.epp_pools[p_idx]); + + page_pools.epp_free_pages -= npages; + page_pools.epp_total_pages -= npages; + + while (npages-- > 0) { + LASSERT(page_pools.epp_pools[p_idx][g_idx] != NULL); + + cfs_free_page(page_pools.epp_pools[p_idx][g_idx]); + page_pools.epp_pools[p_idx][g_idx] = NULL; + + if (g_idx-- == 0) { + p_idx--; + g_idx = PAGES_PER_POOL - 1; + + LASSERT(page_pools.epp_pools[p_idx]); + } + } +} + +/* + * could be called frequently for query (@nr_to_scan == 0) + */ +static int enc_pools_shrink(int nr_to_scan, unsigned int gfp_mask) +{ + unsigned long ret; + + spin_lock(&page_pools.epp_lock); + + if (nr_to_scan) { + if (nr_to_scan > page_pools.epp_free_pages) + nr_to_scan = page_pools.epp_free_pages; + + enc_pools_release_free_pages(nr_to_scan); + CDEBUG(D_SEC, "released %d pages, %ld left\n", + nr_to_scan, page_pools.epp_free_pages); + + page_pools.epp_st_shrinks++; + page_pools.epp_last_shrink = cfs_time_current_sec(); + } + + /* + * try to keep at least PTLRPC_MAX_BRW_PAGES pages in the pool + */ + if (page_pools.epp_free_pages <= PTLRPC_MAX_BRW_PAGES) { + ret = 0; + goto out_unlock; + } + + /* + * if no pool access for a long time, we consider it's fully idle + */ + if (cfs_time_current_sec() - page_pools.epp_last_access > + CACHE_QUIESCENCE_PERIOD) + page_pools.epp_idle_idx = IDLE_IDX_MAX; + + LASSERT(page_pools.epp_idle_idx <= IDLE_IDX_MAX); + ret = (page_pools.epp_free_pages * page_pools.epp_idle_idx / + IDLE_IDX_MAX); + if (page_pools.epp_free_pages - ret < PTLRPC_MAX_BRW_PAGES) + ret = page_pools.epp_free_pages - PTLRPC_MAX_BRW_PAGES; + +out_unlock: + spin_unlock(&page_pools.epp_lock); + return ret; +} + static inline int npages_to_npools(unsigned long npages) { @@ -152,7 +252,7 @@ int npages_to_npools(unsigned long npages) /* * return how many pages cleaned up. */ -static unsigned long enc_cleanup_pools(cfs_page_t ***pools, int npools) +static unsigned long enc_pools_cleanup(cfs_page_t ***pools, int npools) { unsigned long cleaned = 0; int i, j; @@ -180,7 +280,7 @@ static unsigned long enc_cleanup_pools(cfs_page_t ***pools, int npools) * we have options to avoid most memory copy with some tricks. but we choose * the simplest way to avoid complexity. It's not frequently called. */ -static void enc_insert_pool(cfs_page_t ***pools, int npools, int npages) +static void enc_pools_insert(cfs_page_t ***pools, int npools, int npages) { int freeslot; int op_idx, np_idx, og_idx, ng_idx; @@ -251,9 +351,6 @@ static void enc_insert_pool(cfs_page_t ***pools, int npools, int npages) page_pools.epp_free_pages += npages; page_pools.epp_st_lowfree = page_pools.epp_free_pages; - if (page_pools.epp_total_pages == page_pools.epp_max_pages) - page_pools.epp_full = 1; - CDEBUG(D_SEC, "add %d pages to total %lu\n", npages, page_pools.epp_total_pages); @@ -267,16 +364,16 @@ static int enc_pools_add_pages(int npages) int npools, alloced = 0; int i, j, rc = -ENOMEM; + if (npages < PTLRPC_MAX_BRW_PAGES) + npages = PTLRPC_MAX_BRW_PAGES; + down(&sem_add_pages); - if (npages > page_pools.epp_max_pages - page_pools.epp_total_pages) + if (npages + page_pools.epp_total_pages > page_pools.epp_max_pages) npages = page_pools.epp_max_pages - page_pools.epp_total_pages; - if (npages == 0) { - rc = 0; - goto out; - } + LASSERT(npages > 0); - page_pools.epp_st_adds++; + page_pools.epp_st_grows++; npools = npages_to_npools(npages); OBD_ALLOC(pools, npools * sizeof(*pools)); @@ -298,64 +395,59 @@ static int enc_pools_add_pages(int npages) } } - enc_insert_pool(pools, npools, npages); - CDEBUG(D_SEC, "add %d pages into enc page pools\n", npages); + enc_pools_insert(pools, npools, npages); + CDEBUG(D_SEC, "added %d pages into pools\n", npages); rc = 0; out_pools: - enc_cleanup_pools(pools, npools); + enc_pools_cleanup(pools, npools); OBD_FREE(pools, npools * sizeof(*pools)); out: if (rc) { - page_pools.epp_st_failadds++; - CERROR("Failed to pre-allocate %d enc pages\n", npages); + page_pools.epp_st_grow_fails++; + CERROR("Failed to allocate %d enc pages\n", npages); } up(&sem_add_pages); return rc; } -/* - * both "max bulk rpcs inflight" and "lnet MTU" are tunable, we use the - * default fixed value initially. - */ -int sptlrpc_enc_pool_add_user(void) +static inline void enc_pools_wakeup(void) { - int page_plus = PTLRPC_MAX_BRW_PAGES * OSC_MAX_RIF_DEFAULT; - int users, users_gone, shift, rc; + if (unlikely(page_pools.epp_waitqlen)) { + LASSERT(page_pools.epp_waitqlen > 0); + LASSERT(cfs_waitq_active(&page_pools.epp_waitq)); + cfs_waitq_broadcast(&page_pools.epp_waitq); + } +} - LASSERT(!in_interrupt()); - LASSERT(atomic_read(&page_pools.epp_users) >= 0); +static int enc_pools_should_grow(int page_needed, long now) +{ + /* don't grow if someone else is growing the pools right now, + * or the pools has reached its full capacity + */ + if (page_pools.epp_growing || + page_pools.epp_total_pages == page_pools.epp_max_pages) + return 0; - users_gone = atomic_dec_return(&page_pools.epp_users_gone); - if (users_gone >= 0) { - CWARN("%d users gone, skip\n", users_gone + 1); + /* if total pages is not enough, we need to grow */ + if (page_pools.epp_total_pages < page_needed) + return 1; + + /* if we just did a shrink due to memory tight, we'd better + * wait a while to grow again. + */ + if (now - page_pools.epp_last_shrink < 2) return 0; - } - atomic_inc(&page_pools.epp_users_gone); /* - * prepare full pages for first 2 users; 1/2 for next 2 users; - * 1/4 for next 4 users; 1/8 for next 8 users; 1/16 for next 16 users; - * ... + * here we perhaps need consider other factors like wait queue + * length, idle index, etc. ? */ - users = atomic_add_return(1, &page_pools.epp_users); - shift = fls(users - 1); - shift = shift > 1 ? shift - 1 : 0; - page_plus = page_plus >> shift; - page_plus = page_plus > 2 ? page_plus : 2; - rc = enc_pools_add_pages(page_plus); - return 0; -} -EXPORT_SYMBOL(sptlrpc_enc_pool_add_user); - -int sptlrpc_enc_pool_del_user(void) -{ - atomic_inc(&page_pools.epp_users_gone); - return 0; + /* grow the pools in any other cases */ + return 1; } -EXPORT_SYMBOL(sptlrpc_enc_pool_del_user); /* * we allocate the requested pages atomically. @@ -363,12 +455,14 @@ EXPORT_SYMBOL(sptlrpc_enc_pool_del_user); int sptlrpc_enc_pool_get_pages(struct ptlrpc_bulk_desc *desc) { cfs_waitlink_t waitlink; - cfs_time_t tick1 = 0, tick2; + unsigned long this_idle = -1; + cfs_time_t tick = 0; + long now; int p_idx, g_idx; int i; LASSERT(desc->bd_max_iov > 0); - LASSERT(desc->bd_max_iov <= page_pools.epp_total_pages); + LASSERT(desc->bd_max_iov <= page_pools.epp_max_pages); /* resent bulk, enc pages might have been allocated previously */ if (desc->bd_enc_pages != NULL) @@ -380,57 +474,56 @@ int sptlrpc_enc_pool_get_pages(struct ptlrpc_bulk_desc *desc) return -ENOMEM; spin_lock(&page_pools.epp_lock); -again: - page_pools.epp_st_reqs++; + page_pools.epp_st_access++; +again: if (unlikely(page_pools.epp_free_pages < desc->bd_max_iov)) { - if (tick1 == 0) - tick1 = cfs_time_current(); + if (tick == 0) + tick = cfs_time_current(); + + now = cfs_time_current_sec(); page_pools.epp_st_missings++; page_pools.epp_pages_short += desc->bd_max_iov; - if (++page_pools.epp_waitqlen > page_pools.epp_st_max_wqlen) - page_pools.epp_st_max_wqlen = page_pools.epp_waitqlen; - - /* we just wait if someone else is adding more pages, or - * wait queue length is not deep enough. otherwise try to - * add more pages in the pools. - * - * FIXME the policy of detecting resource tight & growing pool - * need to be reconsidered. */ - if (page_pools.epp_adding || page_pools.epp_waitqlen < 2 || - page_pools.epp_full) { - set_current_state(TASK_UNINTERRUPTIBLE); - cfs_waitlink_init(&waitlink); - cfs_waitq_add(&page_pools.epp_waitq, &waitlink); + if (enc_pools_should_grow(desc->bd_max_iov, now)) { + page_pools.epp_growing = 1; spin_unlock(&page_pools.epp_lock); - cfs_schedule(); + enc_pools_add_pages(page_pools.epp_pages_short / 2); spin_lock(&page_pools.epp_lock); + + page_pools.epp_growing = 0; } else { - page_pools.epp_adding = 1; + if (++page_pools.epp_waitqlen > + page_pools.epp_st_max_wqlen) + page_pools.epp_st_max_wqlen = + page_pools.epp_waitqlen; + + set_current_state(TASK_UNINTERRUPTIBLE); + cfs_waitlink_init(&waitlink); + cfs_waitq_add(&page_pools.epp_waitq, &waitlink); spin_unlock(&page_pools.epp_lock); - enc_pools_add_pages(page_pools.epp_pages_short / 2); + cfs_schedule(); spin_lock(&page_pools.epp_lock); - page_pools.epp_adding = 0; + LASSERT(page_pools.epp_waitqlen > 0); + page_pools.epp_waitqlen--; } LASSERT(page_pools.epp_pages_short >= desc->bd_max_iov); - LASSERT(page_pools.epp_waitqlen > 0); page_pools.epp_pages_short -= desc->bd_max_iov; - page_pools.epp_waitqlen--; + this_idle = 0; goto again; } /* record max wait time */ - if (unlikely(tick1 != 0)) { - tick2 = cfs_time_current(); - if (tick2 - tick1 > page_pools.epp_st_max_wait) - page_pools.epp_st_max_wait = tick2 - tick1; + if (unlikely(tick != 0)) { + tick = cfs_time_current() - tick; + if (tick > page_pools.epp_st_max_wait) + page_pools.epp_st_max_wait = tick; } /* proceed with rest of allocation */ @@ -453,6 +546,19 @@ again: if (page_pools.epp_free_pages < page_pools.epp_st_lowfree) page_pools.epp_st_lowfree = page_pools.epp_free_pages; + /* + * new idle index = (old * weight + new) / (weight + 1) + */ + if (this_idle == -1) { + this_idle = page_pools.epp_free_pages * IDLE_IDX_MAX / + page_pools.epp_total_pages; + } + page_pools.epp_idle_idx = (page_pools.epp_idle_idx * IDLE_IDX_WEIGHT + + this_idle) / + (IDLE_IDX_WEIGHT + 1); + + page_pools.epp_last_access = cfs_time_current_sec(); + spin_unlock(&page_pools.epp_lock); return 0; } @@ -492,11 +598,7 @@ void sptlrpc_enc_pool_put_pages(struct ptlrpc_bulk_desc *desc) page_pools.epp_free_pages += desc->bd_max_iov; - if (unlikely(page_pools.epp_waitqlen)) { - LASSERT(page_pools.epp_waitqlen > 0); - LASSERT(cfs_waitq_active(&page_pools.epp_waitq)); - cfs_waitq_broadcast(&page_pools.epp_waitq); - } + enc_pools_wakeup(); spin_unlock(&page_pools.epp_lock); @@ -506,39 +608,103 @@ void sptlrpc_enc_pool_put_pages(struct ptlrpc_bulk_desc *desc) } EXPORT_SYMBOL(sptlrpc_enc_pool_put_pages); +/* + * we don't do much stuff for add_user/del_user anymore, except adding some + * initial pages in add_user() if current pools are empty, rest would be + * handled by the pools's self-adaption. + */ +int sptlrpc_enc_pool_add_user(void) +{ + int need_grow = 0; + + spin_lock(&page_pools.epp_lock); + if (page_pools.epp_growing == 0 && page_pools.epp_total_pages == 0) { + page_pools.epp_growing = 1; + need_grow = 1; + } + spin_unlock(&page_pools.epp_lock); + + if (need_grow) { + enc_pools_add_pages(PTLRPC_MAX_BRW_PAGES); + + spin_lock(&page_pools.epp_lock); + page_pools.epp_growing = 0; + enc_pools_wakeup(); + spin_unlock(&page_pools.epp_lock); + } + return 0; +} +EXPORT_SYMBOL(sptlrpc_enc_pool_add_user); + +int sptlrpc_enc_pool_del_user(void) +{ + return 0; +} +EXPORT_SYMBOL(sptlrpc_enc_pool_del_user); + +static inline void enc_pools_alloc(void) +{ + LASSERT(page_pools.epp_max_pools); + /* + * on system with huge memory but small page size, this might lead to + * high-order allocation. but it's not common, and we suppose memory + * be not too much fragmented at module loading time. + */ + OBD_ALLOC(page_pools.epp_pools, + page_pools.epp_max_pools * sizeof(*page_pools.epp_pools)); +} + +static inline void enc_pools_free(void) +{ + LASSERT(page_pools.epp_max_pools); + LASSERT(page_pools.epp_pools); + + OBD_FREE(page_pools.epp_pools, + page_pools.epp_max_pools * sizeof(*page_pools.epp_pools)); +} + int sptlrpc_enc_pool_init(void) { - /* constants */ - page_pools.epp_max_pages = num_physpages / 4; + /* + * maximum capacity is 1/8 of total physical memory. + * is the 1/8 a good number? + */ + page_pools.epp_max_pages = num_physpages / 8; page_pools.epp_max_pools = npages_to_npools(page_pools.epp_max_pages); - atomic_set(&page_pools.epp_users, 0); - atomic_set(&page_pools.epp_users_gone, 0); - cfs_waitq_init(&page_pools.epp_waitq); page_pools.epp_waitqlen = 0; page_pools.epp_pages_short = 0; - page_pools.epp_adding = 0; - page_pools.epp_full = 0; + page_pools.epp_growing = 0; + + page_pools.epp_idle_idx = 0; + page_pools.epp_last_shrink = cfs_time_current_sec(); + page_pools.epp_last_access = cfs_time_current_sec(); spin_lock_init(&page_pools.epp_lock); page_pools.epp_total_pages = 0; page_pools.epp_free_pages = 0; - page_pools.epp_st_adds = 0; - page_pools.epp_st_failadds = 0; - page_pools.epp_st_reqs = 0; + page_pools.epp_st_grows = 0; + page_pools.epp_st_grow_fails = 0; + page_pools.epp_st_shrinks = 0; + page_pools.epp_st_access = 0; page_pools.epp_st_missings = 0; page_pools.epp_st_lowfree = 0; page_pools.epp_st_max_wqlen = 0; page_pools.epp_st_max_wait = 0; - OBD_ALLOC(page_pools.epp_pools, - page_pools.epp_max_pools * sizeof(*page_pools.epp_pools)); + enc_pools_alloc(); if (page_pools.epp_pools == NULL) return -ENOMEM; + pools_shrinker = set_shrinker(pools_shrinker_seeks, enc_pools_shrink); + if (pools_shrinker == NULL) { + enc_pools_free(); + return -ENOMEM; + } + return 0; } @@ -546,15 +712,17 @@ void sptlrpc_enc_pool_fini(void) { unsigned long cleaned, npools; + LASSERT(pools_shrinker); LASSERT(page_pools.epp_pools); LASSERT(page_pools.epp_total_pages == page_pools.epp_free_pages); + remove_shrinker(pools_shrinker); + npools = npages_to_npools(page_pools.epp_total_pages); - cleaned = enc_cleanup_pools(page_pools.epp_pools, npools); + cleaned = enc_pools_cleanup(page_pools.epp_pools, npools); LASSERT(cleaned == page_pools.epp_total_pages); - OBD_FREE(page_pools.epp_pools, - page_pools.epp_max_pools * sizeof(*page_pools.epp_pools)); + enc_pools_free(); } #else /* !__KERNEL__ */ @@ -596,15 +764,15 @@ static struct { [BULK_CSUM_ALG_SHA512] = { "sha512", 64 }, }; -const char * sptlrpc_bulk_csum_alg2name(__u32 csum_alg) +const char * sptlrpc_bulk_csum_alg2name(__u8 csum_alg) { if (csum_alg < BULK_CSUM_ALG_MAX) return csum_types[csum_alg].name; - return "unknown_cksum"; + return "unknown"; } EXPORT_SYMBOL(sptlrpc_bulk_csum_alg2name); -int bulk_sec_desc_size(__u32 csum_alg, int request, int read) +int bulk_sec_desc_size(__u8 csum_alg, int request, int read) { int size = sizeof(struct ptlrpc_bulk_sec_desc); @@ -631,9 +799,7 @@ int bulk_sec_desc_unpack(struct lustre_msg *msg, int offset) if (lustre_msg_swabbed(msg)) { __swab32s(&bsd->bsd_version); - __swab32s(&bsd->bsd_pad); - __swab32s(&bsd->bsd_csum_alg); - __swab32s(&bsd->bsd_priv_alg); + __swab16s(&bsd->bsd_pad); } if (bsd->bsd_version != 0) { @@ -852,14 +1018,19 @@ int bulk_csum_cli_request(struct ptlrpc_bulk_desc *desc, int read, LASSERT(rsize >= sizeof(*bsdr)); LASSERT(alg < BULK_CSUM_ALG_MAX); - if (read) + if (read) { bsdr->bsd_csum_alg = alg; - else { + } else { rc = generate_bulk_csum(desc, alg, bsdr, rsize); - if (rc) { - CERROR("client bulk write: failed to perform " + if (rc) + CERROR("bulk write: client failed to compute " "checksum: %d\n", rc); - } + + /* For sending we only compute the wrong checksum instead + * of corrupting the data so it is still correct on a redo */ + if (rc == 0 && OBD_FAIL_CHECK(OBD_FAIL_OSC_CHECKSUM_SEND) && + bsdr->bsd_csum_alg != BULK_CSUM_ALG_NULL) + bsdr->bsd_csum[0] ^= 0x1; } return rc; @@ -919,7 +1090,7 @@ int bulk_csum_cli_reply(struct ptlrpc_bulk_desc *desc, int read, if (!memcmp(cli, srv, csum_size)) { /* checksum confirmed */ CDEBUG(D_SEC, "bulk write checksum (%s) confirmed\n", - csum_types[bsdr->bsd_csum_alg].name); + csum_types[bsdr->bsd_csum_alg].name); return 0; } @@ -953,6 +1124,29 @@ int bulk_csum_cli_reply(struct ptlrpc_bulk_desc *desc, int read, } EXPORT_SYMBOL(bulk_csum_cli_reply); +#ifdef __KERNEL__ +static void corrupt_bulk_data(struct ptlrpc_bulk_desc *desc) +{ + char *ptr; + unsigned int off, i; + + for (i = 0; i < desc->bd_iov_count; i++) { + if (desc->bd_iov[i].kiov_len == 0) + continue; + + ptr = cfs_kmap(desc->bd_iov[i].kiov_page); + off = desc->bd_iov[i].kiov_offset & ~CFS_PAGE_MASK; + ptr[off] ^= 0x1; + cfs_kunmap(desc->bd_iov[i].kiov_page); + return; + } +} +#else +static void corrupt_bulk_data(struct ptlrpc_bulk_desc *desc) +{ +} +#endif /* __KERNEL__ */ + int bulk_csum_svc(struct ptlrpc_bulk_desc *desc, int read, struct ptlrpc_bulk_sec_desc *bsdv, int vsize, struct ptlrpc_bulk_sec_desc *bsdr, int rsize) @@ -969,8 +1163,14 @@ int bulk_csum_svc(struct ptlrpc_bulk_desc *desc, int read, CERROR("bulk read: server failed to generate %s " "checksum: %d\n", csum_types[bsdv->bsd_csum_alg].name, rc); - } else + + /* corrupt the data after we compute the checksum, to + * simulate an OST->client data error */ + if (rc == 0 && OBD_FAIL_CHECK(OBD_FAIL_OSC_CHECKSUM_RECEIVE)) + corrupt_bulk_data(desc); + } else { rc = verify_bulk_csum(desc, 0, bsdv, vsize, bsdr, rsize); + } return rc; } @@ -992,15 +1192,15 @@ static struct { [BULK_PRIV_ALG_ARC4] = { "arc4", 0 }, }; -const char * sptlrpc_bulk_priv_alg2name(__u32 priv_alg) +const char * sptlrpc_bulk_priv_alg2name(__u8 priv_alg) { if (priv_alg < BULK_PRIV_ALG_MAX) return priv_types[priv_alg].name; - return "unknown_priv"; + return "unknown"; } EXPORT_SYMBOL(sptlrpc_bulk_priv_alg2name); -__u32 sptlrpc_bulk_priv_alg2flags(__u32 priv_alg) +__u32 sptlrpc_bulk_priv_alg2flags(__u8 priv_alg) { if (priv_alg < BULK_PRIV_ALG_MAX) return priv_types[priv_alg].flags; diff --git a/lustre/ptlrpc/sec_config.c b/lustre/ptlrpc/sec_config.c new file mode 100644 index 0000000..3534ba2 --- /dev/null +++ b/lustre/ptlrpc/sec_config.c @@ -0,0 +1,796 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * Copyright (C) 2007 Cluster File Systems, Inc. + * + * This file is part of Lustre, http://www.lustre.org. + * + * Lustre is free 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. + * + * 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 + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Lustre; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#endif +#define DEBUG_SUBSYSTEM S_SEC + +#include +#ifndef __KERNEL__ +#include +#include +#else +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "ptlrpc_internal.h" + +const char *sptlrpc_part2name(enum lustre_sec_part part) +{ + switch (part) { + case LUSTRE_SP_CLI: + return "cli"; + case LUSTRE_SP_MDT: + return "mdt"; + case LUSTRE_SP_OST: + return "ost"; + case LUSTRE_SP_MGS: + return "mgs"; + case LUSTRE_SP_ANY: + return "any"; + default: + return "err"; + } +} +EXPORT_SYMBOL(sptlrpc_part2name); + +enum lustre_sec_part sptlrpc_target_sec_part(struct obd_device *obd) +{ + const char *type = obd->obd_type->typ_name; + + if (!strcmp(type, LUSTRE_MDT_NAME)) + return LUSTRE_SP_MDT; + if (!strcmp(type, LUSTRE_OST_NAME)) + return LUSTRE_SP_OST; + if (!strcmp(type, LUSTRE_MGS_NAME)) + return LUSTRE_SP_MGS; + + CERROR("unknown target %p(%s)\n", obd, type); + return LUSTRE_SP_ANY; +} +EXPORT_SYMBOL(sptlrpc_target_sec_part); + +/**************************************** + * user supplied flavor string parsing * + ****************************************/ + +typedef enum { + BULK_TYPE_N = 0, + BULK_TYPE_I = 1, + BULK_TYPE_P = 2 +} bulk_type_t; + +static void get_default_flavor(struct sptlrpc_flavor *sf) +{ + sf->sf_rpc = SPTLRPC_FLVR_NULL; + sf->sf_bulk_priv = BULK_PRIV_ALG_NULL; + sf->sf_bulk_csum = BULK_CSUM_ALG_NULL; + sf->sf_flags = 0; +} + +static void get_flavor_by_rpc(struct sptlrpc_rule *rule, __u16 rpc_flavor) +{ + get_default_flavor(&rule->sr_flvr); + + rule->sr_flvr.sf_rpc = rpc_flavor; + + switch (rpc_flavor) { + case SPTLRPC_FLVR_NULL: + case SPTLRPC_FLVR_PLAIN: + case SPTLRPC_FLVR_KRB5N: + case SPTLRPC_FLVR_KRB5A: + break; + case SPTLRPC_FLVR_KRB5P: + rule->sr_flvr.sf_bulk_priv = BULK_PRIV_ALG_ARC4; + /* fall through */ + case SPTLRPC_FLVR_KRB5I: + rule->sr_flvr.sf_bulk_csum = BULK_CSUM_ALG_SHA1; + break; + default: + LBUG(); + } +} + +static void get_flavor_by_bulk(struct sptlrpc_rule *rule, bulk_type_t bulk_type) +{ + switch (bulk_type) { + case BULK_TYPE_N: + rule->sr_flvr.sf_bulk_csum = BULK_CSUM_ALG_NULL; + rule->sr_flvr.sf_bulk_priv = BULK_PRIV_ALG_NULL; + break; + case BULK_TYPE_I: + rule->sr_flvr.sf_bulk_csum = BULK_CSUM_ALG_SHA1; + rule->sr_flvr.sf_bulk_priv = BULK_PRIV_ALG_NULL; + break; + case BULK_TYPE_P: + rule->sr_flvr.sf_bulk_csum = BULK_CSUM_ALG_SHA1; + rule->sr_flvr.sf_bulk_priv = BULK_PRIV_ALG_ARC4; + break; + default: + LBUG(); + } +} + +static __u16 __flavors[] = { + SPTLRPC_FLVR_NULL, + SPTLRPC_FLVR_PLAIN, + SPTLRPC_FLVR_KRB5N, + SPTLRPC_FLVR_KRB5A, + SPTLRPC_FLVR_KRB5I, + SPTLRPC_FLVR_KRB5P, +}; + +#define __nflavors ARRAY_SIZE(__flavors) + +/* + * flavor string format: rpc[-bulk{n|i|p}[:cksum/enc]] + * for examples: + * null + * plain-bulki + * krb5p-bulkn + * krb5i-bulkp + * krb5i-bulkp:sha512/arc4 + */ +static int parse_flavor(char *str, struct sptlrpc_rule *rule) +{ + const char *f; + char *bulk, *alg, *enc; + char buf[64]; + bulk_type_t bulk_type; + __u8 i; + ENTRY; + + if (str == NULL || str[0] == '\0') { + rule->sr_flvr.sf_rpc = SPTLRPC_FLVR_INVALID; + goto out; + } + + for (i = 0; i < __nflavors; i++) { + f = sptlrpc_rpcflavor2name(__flavors[i]); + if (strncmp(str, f, strlen(f)) == 0) + break; + } + + if (i >= __nflavors) + GOTO(invalid, -EINVAL); + + /* prepare local buffer thus we can modify it as we want */ + strncpy(buf, str, 64); + buf[64 - 1] = '\0'; + + /* find bulk string */ + bulk = strchr(buf, '-'); + if (bulk) + *bulk++ = '\0'; + + /* now the first part must equal to rpc flavor name */ + if (strcmp(buf, f) != 0) + GOTO(invalid, -EINVAL); + + get_flavor_by_rpc(rule, __flavors[i]); + + if (bulk == NULL) + goto out; + + /* find bulk algorithm string */ + alg = strchr(bulk, ':'); + if (alg) + *alg++ = '\0'; + + /* verify bulk section */ + if (strcmp(bulk, "bulkn") == 0) { + rule->sr_flvr.sf_bulk_csum = BULK_CSUM_ALG_NULL; + rule->sr_flvr.sf_bulk_priv = BULK_PRIV_ALG_NULL; + bulk_type = BULK_TYPE_N; + } else if (strcmp(bulk, "bulki") == 0) + bulk_type = BULK_TYPE_I; + else if (strcmp(bulk, "bulkp") == 0) + bulk_type = BULK_TYPE_P; + else + GOTO(invalid, -EINVAL); + + /* null flavor don't support bulk i/p */ + if (__flavors[i] == SPTLRPC_FLVR_NULL && bulk_type != BULK_TYPE_N) + GOTO(invalid, -EINVAL); + + /* plain policy dosen't support bulk p */ + if (__flavors[i] == SPTLRPC_FLVR_PLAIN && bulk_type == BULK_TYPE_P) + GOTO(invalid, -EINVAL); + + get_flavor_by_bulk(rule, bulk_type); + + if (alg == NULL) + goto out; + + /* find encryption algorithm string */ + enc = strchr(alg, '/'); + if (enc) + *enc++ = '\0'; + + /* checksum algorithm */ + for (i = 0; i < BULK_CSUM_ALG_MAX; i++) { + if (strcmp(alg, sptlrpc_bulk_csum_alg2name(i)) == 0) { + rule->sr_flvr.sf_bulk_csum = i; + break; + } + } + if (i >= BULK_CSUM_ALG_MAX) + GOTO(invalid, -EINVAL); + + /* privacy algorithm */ + if (enc) { + for (i = 0; i < BULK_PRIV_ALG_MAX; i++) { + if (strcmp(enc, sptlrpc_bulk_priv_alg2name(i)) == 0) { + rule->sr_flvr.sf_bulk_priv = i; + break; + } + } + if (i >= BULK_PRIV_ALG_MAX) + GOTO(invalid, -EINVAL); + } + + /* + * bulk combination sanity checks + */ + if (bulk_type == BULK_TYPE_P && + rule->sr_flvr.sf_bulk_priv == BULK_PRIV_ALG_NULL) + GOTO(invalid, -EINVAL); + + if (bulk_type == BULK_TYPE_I && + (rule->sr_flvr.sf_bulk_csum == BULK_CSUM_ALG_NULL || + rule->sr_flvr.sf_bulk_priv != BULK_PRIV_ALG_NULL)) + GOTO(invalid, -EINVAL); + + if (bulk_type == BULK_TYPE_N && + (rule->sr_flvr.sf_bulk_csum != BULK_CSUM_ALG_NULL || + rule->sr_flvr.sf_bulk_priv != BULK_PRIV_ALG_NULL)) + GOTO(invalid, -EINVAL); + +out: + return 0; +invalid: + CERROR("invalid flavor string: %s\n", str); + return -EINVAL; +} + +/**************************************** + * configure rules * + ****************************************/ + +static void sptlrpc_rule_init(struct sptlrpc_rule *rule) +{ + rule->sr_netid = LNET_NIDNET(LNET_NID_ANY); + rule->sr_from = LUSTRE_SP_ANY; + rule->sr_to = LUSTRE_SP_ANY; + rule->sr_padding = 0; + + get_default_flavor(&rule->sr_flvr); +} + +/* + * format: network[.direction]=flavor + */ +int sptlrpc_parse_rule(char *param, struct sptlrpc_rule *rule) +{ + char *flavor, *dir; + int rc; + + sptlrpc_rule_init(rule); + + flavor = strchr(param, '='); + if (flavor == NULL) { + CERROR("invalid param, no '='\n"); + RETURN(-EINVAL); + } + *flavor++ = '\0'; + + dir = strchr(param, '.'); + if (dir) + *dir++ = '\0'; + + /* 1.1 network */ + if (strcmp(param, "default")) { + rule->sr_netid = libcfs_str2net(param); + if (rule->sr_netid == LNET_NIDNET(LNET_NID_ANY)) { + CERROR("invalid network name: %s\n", param); + RETURN(-EINVAL); + } + } + + /* 1.2 direction */ + if (dir) { + if (!strcmp(dir, "mdt2ost")) { + rule->sr_from = LUSTRE_SP_MDT; + rule->sr_to = LUSTRE_SP_OST; + } else if (!strcmp(dir, "mdt2mdt")) { + rule->sr_from = LUSTRE_SP_MDT; + rule->sr_to = LUSTRE_SP_MDT; + } else if (!strcmp(dir, "cli2ost")) { + rule->sr_from = LUSTRE_SP_CLI; + rule->sr_to = LUSTRE_SP_OST; + } else if (!strcmp(dir, "cli2mdt")) { + rule->sr_from = LUSTRE_SP_CLI; + rule->sr_to = LUSTRE_SP_MDT; + } else { + CERROR("invalid rule dir segment: %s\n", dir); + RETURN(-EINVAL); + } + } + + /* 2.1 flavor */ + rc = parse_flavor(flavor, rule); + if (rc) + RETURN(-EINVAL); + + RETURN(0); +} +EXPORT_SYMBOL(sptlrpc_parse_rule); + +void sptlrpc_rule_set_free(struct sptlrpc_rule_set *rset) +{ + LASSERT(rset->srs_nslot || + (rset->srs_nrule == 0 && rset->srs_rules == NULL)); + + if (rset->srs_nslot) { + OBD_FREE(rset->srs_rules, + rset->srs_nslot * sizeof(*rset->srs_rules)); + sptlrpc_rule_set_init(rset); + } +} +EXPORT_SYMBOL(sptlrpc_rule_set_free); + +/* + * return 0 if the rule set could accomodate one more rule. + * if @expand != 0, the rule set might be expanded. + */ +int sptlrpc_rule_set_expand(struct sptlrpc_rule_set *rset, int expand) +{ + struct sptlrpc_rule *rules; + int nslot; + + if (rset->srs_nrule < rset->srs_nslot) + return 0; + + if (expand == 0) + return -E2BIG; + + if (rset->srs_nslot == 0) + nslot = 8; + else + nslot = rset->srs_nslot + 8; + + /* better use realloc() if available */ + OBD_ALLOC(rules, nslot * sizeof(*rset->srs_rules)); + if (rules == NULL) + return -ENOMEM; + + memcpy(rules, rset->srs_rules, + rset->srs_nrule * sizeof(*rset->srs_rules)); + + if (rset->srs_rules) + OBD_FREE(rset->srs_rules, + rset->srs_nslot * sizeof(*rset->srs_rules)); + + rset->srs_rules = rules; + rset->srs_nslot = nslot; + return 0; +} +EXPORT_SYMBOL(sptlrpc_rule_set_expand); + +static inline int rule_spec_dir(struct sptlrpc_rule *rule) +{ + return (rule->sr_from != LUSTRE_SP_ANY || + rule->sr_to != LUSTRE_SP_ANY); +} +static inline int rule_spec_net(struct sptlrpc_rule *rule) +{ + return (rule->sr_netid != LNET_NIDNET(LNET_NID_ANY)); +} +static inline int rule_match_dir(struct sptlrpc_rule *r1, + struct sptlrpc_rule *r2) +{ + return (r1->sr_from == r2->sr_from && r1->sr_to == r2->sr_to); +} +static inline int rule_match_net(struct sptlrpc_rule *r1, + struct sptlrpc_rule *r2) +{ + return (r1->sr_netid == r2->sr_netid); +} + +/* + * merge @rule into @rset. + * if @expand != 0 then @rset slots might be expanded. + */ +int sptlrpc_rule_set_merge(struct sptlrpc_rule_set *rset, + struct sptlrpc_rule *rule, + int expand) +{ + struct sptlrpc_rule *p = rset->srs_rules; + int spec_dir, spec_net; + int rc, n, match = 0; + + spec_net = rule_spec_net(rule); + spec_dir = rule_spec_dir(rule); + + for (n = 0; n < rset->srs_nrule; n++) { + p = &rset->srs_rules[n]; + + /* test network match, if failed: + * - spec rule: skip rules which is also spec rule match, until + * we hit a wild rule, which means no more chance + * - wild rule: skip until reach the one which is also wild + * and matches + */ + if (!rule_match_net(p, rule)) { + if (spec_net) { + if (rule_spec_net(p)) + continue; + else + break; + } else { + continue; + } + } + + /* test dir match, same logic as net matching */ + if (!rule_match_dir(p, rule)) { + if (spec_dir) { + if (rule_spec_dir(p)) + continue; + else + break; + } else { + continue; + } + } + + /* find a match */ + match = 1; + break; + } + + if (match) { + LASSERT(n >= 0 && n < rset->srs_nrule); + + if (rule->sr_flvr.sf_rpc == SPTLRPC_FLVR_INVALID) { + /* remove this rule */ + if (n < rset->srs_nrule - 1) + memmove(&rset->srs_rules[n], + &rset->srs_rules[n + 1], + (rset->srs_nrule - n - 1) * + sizeof(*rule)); + rset->srs_nrule--; + } else { + /* override the rule */ + memcpy(&rset->srs_rules[n], rule, sizeof(*rule)); + } + } else { + LASSERT(n >= 0 && n <= rset->srs_nrule); + + if (rule->sr_flvr.sf_rpc != SPTLRPC_FLVR_INVALID) { + rc = sptlrpc_rule_set_expand(rset, expand); + if (rc) + return rc; + + if (n < rset->srs_nrule) + memmove(&rset->srs_rules[n + 1], + &rset->srs_rules[n], + (rset->srs_nrule - n) * sizeof(*rule)); + memcpy(&rset->srs_rules[n], rule, sizeof(*rule)); + rset->srs_nrule++; + } else { + CWARN("ignore the unmatched deletion\n"); + } + } + + return 0; +} +EXPORT_SYMBOL(sptlrpc_rule_set_merge); + +int sptlrpc_rule_set_from_log(struct sptlrpc_rule_set *rset, + struct sptlrpc_conf_log *log) +{ + LASSERT(rset); + LASSERT(log); + + sptlrpc_rule_set_free(rset); + + if (log->scl_nrule == 0) + return 0; + + OBD_ALLOC(rset->srs_rules, log->scl_nrule * sizeof(*log->scl_rules)); + if (!rset->srs_rules) + return -ENOMEM; + + memcpy(rset->srs_rules, log->scl_rules, + log->scl_nrule * sizeof(*log->scl_rules)); + rset->srs_nslot = rset->srs_nrule = log->scl_nrule; + return 0; +} +EXPORT_SYMBOL(sptlrpc_rule_set_from_log); + +/* + * according to NID/from choose a flavor from rule set. + */ +void sptlrpc_rule_set_choose(struct sptlrpc_rule_set *rset, + enum lustre_sec_part from, + lnet_nid_t nid, + struct sptlrpc_flavor *sf) +{ + struct sptlrpc_rule *r; + int n; + + for (n = 0; n < rset->srs_nrule; n++) { + r = &rset->srs_rules[n]; + + if (LNET_NIDNET(nid) != LNET_NIDNET(LNET_NID_ANY) && + r->sr_netid != LNET_NIDNET(LNET_NID_ANY) && + LNET_NIDNET(nid) != r->sr_netid) + continue; + + if (from != LUSTRE_SP_ANY && r->sr_from != LUSTRE_SP_ANY && + from != r->sr_from) + continue; + + *sf = r->sr_flvr; + return; + } + + /* no match found, set as default flavor */ + get_default_flavor(sf); +} +EXPORT_SYMBOL(sptlrpc_rule_set_choose); + +void sptlrpc_rule_set_dump(struct sptlrpc_rule_set *rset) +{ + struct sptlrpc_rule *r; + int n; + + for (n = 0; n < rset->srs_nrule; n++) { + r = &rset->srs_rules[n]; + CWARN("<%02d> from %x to %x, net %x, rpc %x\n", n, + r->sr_from, r->sr_to, r->sr_netid, r->sr_flvr.sf_rpc); + } +} +EXPORT_SYMBOL(sptlrpc_rule_set_dump); + +/**************************************** + * sptlrpc config log * + ****************************************/ + +struct sptlrpc_conf_log *sptlrpc_conf_log_alloc(void) +{ + struct sptlrpc_conf_log *log; + + OBD_ALLOC_PTR(log); + if (log == NULL) + return ERR_PTR(-ENOMEM); + + log->scl_max = SPTLRPC_CONF_LOG_MAX; + return log; +} +EXPORT_SYMBOL(sptlrpc_conf_log_alloc); + +void sptlrpc_conf_log_free(struct sptlrpc_conf_log *log) +{ + LASSERT(log->scl_max == SPTLRPC_CONF_LOG_MAX); + OBD_FREE_PTR(log); +} +EXPORT_SYMBOL(sptlrpc_conf_log_free); + +static __u32 get_log_rule_flags(enum lustre_sec_part from, + enum lustre_sec_part to, + unsigned int fl_udesc) +{ + /* MDT->MDT; MDT->OST */ + if (from == LUSTRE_SP_MDT) + return PTLRPC_SEC_FL_ROOTONLY; + /* CLI->OST */ + if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_OST) + return PTLRPC_SEC_FL_ROOTONLY | PTLRPC_SEC_FL_BULK; + /* CLI->MDT */ + if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_MDT) + if (fl_udesc) + return PTLRPC_SEC_FL_UDESC; + + return 0; +} + +/* + * generate config log: merge general and target rules, which + * match @from @to + */ +int sptlrpc_conf_log_populate(struct sptlrpc_rule_set *gen, + struct sptlrpc_rule_set *tgt, + enum lustre_sec_part from, + enum lustre_sec_part to, + unsigned int fl_udesc, + struct sptlrpc_conf_log *log) +{ + struct sptlrpc_rule_set *src[2] = { gen, tgt }; + struct sptlrpc_rule_set dst; + struct sptlrpc_rule *rule; + __u32 flags; + int i, n, rc; + + LASSERT(log); + + dst.srs_nslot = log->scl_max; + dst.srs_nrule = 0; + dst.srs_rules = log->scl_rules; + + /* merge general rules firstly, then target-specific rules */ + for (i = 0; i < 2; i++) { + if (src[i] == NULL) + continue; + + for (n = 0; n < src[i]->srs_nrule; n++) { + rule = &src[i]->srs_rules[n]; + + if (from != LUSTRE_SP_ANY && + rule->sr_from != LUSTRE_SP_ANY && + rule->sr_from != from) + continue; + if (to != LUSTRE_SP_ANY && + rule->sr_to != LUSTRE_SP_ANY && + rule->sr_to != to) + continue; + + rc = sptlrpc_rule_set_merge(&dst, rule, 0); + if (rc) { + CERROR("can't merge: %d\n", rc); + return rc; + } + } + } + + log->scl_nrule = dst.srs_nrule; + + /* set flags for each rule */ + flags = get_log_rule_flags(from, to, fl_udesc); + + for (i = 0; i < log->scl_nrule; i++) { + log->scl_rules[i].sr_flvr.sf_flags = flags; + + /* also clear the from/to fields which don't need to be known + * accordingly. @from == ANY means this log is for target, + * otherwise for client. */ + if (from != LUSTRE_SP_ANY) + log->scl_rules[i].sr_from = LUSTRE_SP_ANY; + log->scl_rules[i].sr_to = LUSTRE_SP_ANY; + } + + return 0; +} +EXPORT_SYMBOL(sptlrpc_conf_log_populate); + +/* + * extract config log from @lcfg + */ +struct sptlrpc_conf_log *sptlrpc_conf_log_extract(struct lustre_cfg *lcfg) +{ + struct sptlrpc_conf_log *log; + struct sptlrpc_rule *r; + int i; + ENTRY; + + log = lustre_cfg_buf(lcfg, 1); + if (log == NULL) { + CERROR("no sptlrpc config data\n"); + RETURN(ERR_PTR(-EINVAL)); + } + + if (lcfg->lcfg_version == __swab32(LUSTRE_CFG_VERSION)) { + __swab32s(&log->scl_max); + __swab32s(&log->scl_nrule); + } + + if (LUSTRE_CFG_BUFLEN(lcfg, 1) < + log->scl_max * sizeof(log->scl_rules[0])) { + CERROR("mal-formed config log\n"); + RETURN(ERR_PTR(-EINVAL)); + } + + if (lcfg->lcfg_version == __swab32(LUSTRE_CFG_VERSION)) { + for (i = 0; i < log->scl_nrule; i++) { + r = &log->scl_rules[i]; + __swab32s(&r->sr_netid); + __swab16s(&r->sr_flvr.sf_rpc); + __swab32s(&r->sr_flvr.sf_flags); + } + } + + RETURN(log); +} +EXPORT_SYMBOL(sptlrpc_conf_log_extract); + +void sptlrpc_conf_log_cleanup(struct sptlrpc_conf_log *log) +{ + log->scl_nrule = 0; + memset(log->scl_rules, 0, sizeof(log->scl_rules)); +} +EXPORT_SYMBOL(sptlrpc_conf_log_cleanup); + +void sptlrpc_conf_log_dump(struct sptlrpc_conf_log *log) +{ + struct sptlrpc_rule *r; + int n; + + CWARN("max %u, rule# %u part %u\n", + log->scl_max, log->scl_nrule, log->scl_part); + + for (n = 0; n < log->scl_nrule; n++) { + r = &log->scl_rules[n]; + CWARN("<%02d> %x -> %x, net %x, rpc %x\n", n, + r->sr_from, r->sr_to, r->sr_netid, r->sr_flvr.sf_rpc); + } +} +EXPORT_SYMBOL(sptlrpc_conf_log_dump); + +/* + * caller should guarantee that no concurrent calls to this function + */ +#define SEC_ADAPT_DELAY (10) + +int sptlrpc_cliobd_process_config(struct obd_device *obd, + struct lustre_cfg *lcfg) +{ + struct sptlrpc_conf_log *log; + struct obd_import *imp; + int rc; + + log = sptlrpc_conf_log_extract(lcfg); + if (IS_ERR(log)) { + CERROR("extract log error: %ld\n", PTR_ERR(log)); + return PTR_ERR(log); + } + + obd->u.cli.cl_sec_part = log->scl_part; + + rc = sptlrpc_rule_set_from_log(&obd->u.cli.cl_sptlrpc_rset, log); + if (rc) { + CERROR("failed create rule set: %d\n", rc); + return rc; + } + + imp = obd->u.cli.cl_import; + if (imp == NULL) + return 0; + + /* even if imp_sec_expire is already set, we'll override it to a + * newer (later) time */ + spin_lock(&imp->imp_lock); + if (imp->imp_sec) + imp->imp_sec_expire = cfs_time_current_sec() + SEC_ADAPT_DELAY; + spin_unlock(&imp->imp_lock); + return 0; +} +EXPORT_SYMBOL(sptlrpc_cliobd_process_config); diff --git a/lustre/ptlrpc/sec_gc.c b/lustre/ptlrpc/sec_gc.c index 96ce6ef..930a7dc 100644 --- a/lustre/ptlrpc/sec_gc.c +++ b/lustre/ptlrpc/sec_gc.c @@ -27,6 +27,8 @@ #ifndef __KERNEL__ #include +#else +#include #endif #include @@ -51,11 +53,11 @@ static atomic_t sec_gc_wait_del = ATOMIC_INIT(0); void sptlrpc_gc_add_sec(struct ptlrpc_sec *sec) { - if (!list_empty(&sec->ps_gc_list)) { - CERROR("sec %p(%s) already in gc list\n", - sec, sec->ps_policy->sp_name); - return; - } + LASSERT(sec->ps_policy->sp_cops->gc_ctx); + LASSERT(sec->ps_gc_interval > 0); + LASSERT(list_empty(&sec->ps_gc_list)); + + sec->ps_gc_next = cfs_time_current_sec() + sec->ps_gc_interval; spin_lock(&sec_gc_list_lock); list_add_tail(&sec_gc_list, &sec->ps_gc_list); @@ -72,14 +74,17 @@ void sptlrpc_gc_del_sec(struct ptlrpc_sec *sec) might_sleep(); + /* signal before list_del to make iteration in gc thread safe */ + atomic_inc(&sec_gc_wait_del); + spin_lock(&sec_gc_list_lock); list_del_init(&sec->ps_gc_list); spin_unlock(&sec_gc_list_lock); /* barrier */ - atomic_inc(&sec_gc_wait_del); mutex_down(&sec_gc_mutex); mutex_up(&sec_gc_mutex); + atomic_dec(&sec_gc_wait_del); CDEBUG(D_SEC, "del sec %p(%s)\n", sec, sec->ps_policy->sp_name); @@ -127,7 +132,7 @@ static void sec_process_ctx_list(void) static void sec_do_gc(struct ptlrpc_sec *sec) { - cfs_time_t now = cfs_time_current_sec(); + LASSERT(sec->ps_policy->sp_cops->gc_ctx); if (unlikely(sec->ps_gc_next == 0)) { CWARN("sec %p(%s) has 0 gc time\n", @@ -135,19 +140,13 @@ static void sec_do_gc(struct ptlrpc_sec *sec) return; } - if (unlikely(sec->ps_policy->sp_cops->gc_ctx == NULL)) { - CWARN("sec %p(%s) is not prepared for gc\n", - sec, sec->ps_policy->sp_name); - return; - } - CDEBUG(D_SEC, "check on sec %p(%s)\n", sec, sec->ps_policy->sp_name); - if (time_after(sec->ps_gc_next, now)) + if (cfs_time_after(sec->ps_gc_next, cfs_time_current_sec())) return; sec->ps_policy->sp_cops->gc_ctx(sec); - sec->ps_gc_next = now + sec->ps_gc_interval; + sec->ps_gc_next = cfs_time_current_sec() + sec->ps_gc_interval; } static int sec_gc_main(void *arg) @@ -155,24 +154,30 @@ static int sec_gc_main(void *arg) struct ptlrpc_thread *thread = (struct ptlrpc_thread *) arg; struct l_wait_info lwi; - cfs_daemonize("sptlrpc_ctx_gc"); + cfs_daemonize("sptlrpc_gc"); /* Record that the thread is running */ thread->t_flags = SVC_RUNNING; cfs_waitq_signal(&thread->t_ctl_waitq); while (1) { - struct ptlrpc_sec *sec, *next; + struct ptlrpc_sec *sec; thread->t_flags &= ~SVC_SIGNAL; sec_process_ctx_list(); again: + /* go through sec list do gc. + * FIXME here we iterate through the whole list each time which + * is not optimal. we perhaps want to use balanced binary tree + * to trace each sec as order of expiry time. + * another issue here is we wakeup as fixed interval instead of + * according to each sec's expiry time */ mutex_down(&sec_gc_mutex); - list_for_each_entry_safe(sec, next, &sec_gc_list, ps_gc_list) { + list_for_each_entry(sec, &sec_gc_list, ps_gc_list) { /* if someone is waiting to be deleted, let it * proceed as soon as possible. */ if (atomic_read(&sec_gc_wait_del)) { - CWARN("deletion pending, retry\n"); + CWARN("deletion pending, start over\n"); mutex_up(&sec_gc_mutex); goto again; } @@ -181,6 +186,9 @@ again: } mutex_up(&sec_gc_mutex); + /* check ctx list again before sleep */ + sec_process_ctx_list(); + lwi = LWI_TIMEOUT(SEC_GC_INTERVAL * HZ, NULL, NULL); l_wait_event(thread->t_ctl_waitq, thread->t_flags & (SVC_STOPPING | SVC_SIGNAL), diff --git a/lustre/ptlrpc/sec_lproc.c b/lustre/ptlrpc/sec_lproc.c index df81d9c..115eae6 100644 --- a/lustre/ptlrpc/sec_lproc.c +++ b/lustre/ptlrpc/sec_lproc.c @@ -56,6 +56,8 @@ void sec_flags2str(unsigned long flags, char *buf, int bufsize) strncat(buf, "reverse,", bufsize); if (flags & PTLRPC_SEC_FL_ROOTONLY) strncat(buf, "rootonly,", bufsize); + if (flags & PTLRPC_SEC_FL_UDESC) + strncat(buf, "udesc,", bufsize); if (flags & PTLRPC_SEC_FL_BULK) strncat(buf, "bulk,", bufsize); if (buf[0] == '\0') @@ -65,64 +67,102 @@ void sec_flags2str(unsigned long flags, char *buf, int bufsize) } -int sptlrpc_lprocfs_rd(char *page, char **start, off_t off, int count, - int *eof, void *data) +static int sptlrpc_info_lprocfs_seq_show(struct seq_file *seq, void *v) { - struct obd_device *obd = data; - struct sec_flavor_config *conf = &obd->u.cli.cl_sec_conf; - struct ptlrpc_sec *sec = NULL; - char flags_str[32]; - int written; - - if (obd == NULL) - return 0; - - LASSERT(strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME) == 0 || - strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) == 0 || - strcmp(obd->obd_type->typ_name, LUSTRE_MGC_NAME) == 0); - LASSERT(conf->sfc_bulk_csum < BULK_CSUM_ALG_MAX); - LASSERT(conf->sfc_bulk_priv < BULK_PRIV_ALG_MAX); - - if (obd->u.cli.cl_import) - sec = obd->u.cli.cl_import->imp_sec; - - if (sec == NULL) { - written = snprintf(page, count, "\n"); + struct obd_device *dev = seq->private; + struct client_obd *cli = &dev->u.cli; + struct ptlrpc_sec *sec = NULL; + char flags_str[32]; + + LASSERT(strcmp(dev->obd_type->typ_name, LUSTRE_OSC_NAME) == 0 || + strcmp(dev->obd_type->typ_name, LUSTRE_MDC_NAME) == 0 || + strcmp(dev->obd_type->typ_name, LUSTRE_MGC_NAME) == 0); + + if (cli->cl_import) + sec = sptlrpc_import_sec_ref(cli->cl_import); + if (sec == NULL) goto out; + + sec_flags2str(sec->ps_flvr.sf_flags, flags_str, sizeof(flags_str)); + + seq_printf(seq, "rpc flavor: %s\n", + sptlrpc_rpcflavor2name(sec->ps_flvr.sf_rpc)); + seq_printf(seq, "bulk flavor: %s/%s\n", + sptlrpc_bulk_csum_alg2name(sec->ps_flvr.sf_bulk_csum), + sptlrpc_bulk_priv_alg2name(sec->ps_flvr.sf_bulk_priv)); + seq_printf(seq, "flags: %s\n", flags_str); + seq_printf(seq, "id: %d\n", sec->ps_id); + seq_printf(seq, "refcount: %d\n", atomic_read(&sec->ps_refcount)); + seq_printf(seq, "nctx: %d\n", atomic_read(&sec->ps_nctx)); + seq_printf(seq, "gc internal %ld\n", sec->ps_gc_interval); + seq_printf(seq, "gc next %ld\n", + sec->ps_gc_interval ? + sec->ps_gc_next - cfs_time_current_sec() : 0); + + sptlrpc_sec_put(sec); +out: + return 0; +} +LPROC_SEQ_FOPS_RO(sptlrpc_info_lprocfs); + +static int sptlrpc_ctxs_lprocfs_seq_show(struct seq_file *seq, void *v) +{ + struct obd_device *dev = seq->private; + struct client_obd *cli = &dev->u.cli; + struct ptlrpc_sec *sec = NULL; + + LASSERT(strcmp(dev->obd_type->typ_name, LUSTRE_OSC_NAME) == 0 || + strcmp(dev->obd_type->typ_name, LUSTRE_MDC_NAME) == 0 || + strcmp(dev->obd_type->typ_name, LUSTRE_MGC_NAME) == 0); + + if (cli->cl_import) + sec = sptlrpc_import_sec_ref(cli->cl_import); + if (sec == NULL) + goto out; + + if (sec->ps_policy->sp_cops->display) + sec->ps_policy->sp_cops->display(sec, seq); + + sptlrpc_sec_put(sec); +out: + return 0; +} +LPROC_SEQ_FOPS_RO(sptlrpc_ctxs_lprocfs); + +int sptlrpc_lprocfs_cliobd_attach(struct obd_device *dev) +{ + int rc; + + if (strcmp(dev->obd_type->typ_name, LUSTRE_OSC_NAME) != 0 && + strcmp(dev->obd_type->typ_name, LUSTRE_MDC_NAME) != 0 && + strcmp(dev->obd_type->typ_name, LUSTRE_MGC_NAME) != 0) { + CERROR("can't register lproc for obd type %s\n", + dev->obd_type->typ_name); + return -EINVAL; } - sec_flags2str(sec->ps_flags, flags_str, sizeof(flags_str)); - - written = snprintf(page, count, - "rpc msg flavor: %s\n" - "bulk checksum: %s\n" - "bulk encrypt: %s\n" - "flags: %s\n" - "ctx cache busy %d\n" - "gc interval %lu\n" - "gc next %ld\n", - sptlrpc_flavor2name(sec->ps_flavor), - sptlrpc_bulk_csum_alg2name(conf->sfc_bulk_csum), - sptlrpc_bulk_priv_alg2name(conf->sfc_bulk_priv), - flags_str, - atomic_read(&sec->ps_busy), - sec->ps_gc_interval, - sec->ps_gc_interval ? - sec->ps_gc_next - cfs_time_current_sec() : 0 - ); - - if (sec->ps_policy->sp_cops->display) { - written += sec->ps_policy->sp_cops->display( - sec, page + written, count - written); + rc = lprocfs_obd_seq_create(dev, "srpc.info", 0444, + &sptlrpc_info_lprocfs_fops, dev); + if (rc) { + CERROR("create proc entry srpc.info for %s: %d\n", + dev->obd_name, rc); + return rc; } -out: - return written; + rc = lprocfs_obd_seq_create(dev, "srpc.contexts", 0444, + &sptlrpc_ctxs_lprocfs_fops, dev); + if (rc) { + CERROR("create proc entry srpc.contexts for %s: %d\n", + dev->obd_name, rc); + return rc; + } + + return 0; } -EXPORT_SYMBOL(sptlrpc_lprocfs_rd); +EXPORT_SYMBOL(sptlrpc_lprocfs_cliobd_attach); static struct lprocfs_vars sptlrpc_lprocfs_vars[] = { - { "enc_pool", sptlrpc_proc_read_enc_pool, NULL, NULL }, + { "encrypt_page_pools", sptlrpc_proc_read_enc_pool, NULL, NULL }, { NULL } }; @@ -152,6 +192,11 @@ void sptlrpc_lproc_fini(void) #else /* !__KERNEL__ */ +int sptlrpc_lprocfs_cliobd_attach(struct obd_device *dev) +{ + return 0; +} + int sptlrpc_lproc_init(void) { return 0; diff --git a/lustre/ptlrpc/sec_null.c b/lustre/ptlrpc/sec_null.c index 2c86055..dddf7e2 100644 --- a/lustre/ptlrpc/sec_null.c +++ b/lustre/ptlrpc/sec_null.c @@ -39,6 +39,29 @@ static struct ptlrpc_sec null_sec; static struct ptlrpc_cli_ctx null_cli_ctx; static struct ptlrpc_svc_ctx null_svc_ctx; +/* + * null sec temporarily use the third byte of lm_secflvr to identify + * the source sec part. + */ +static inline +void null_encode_sec_part(struct lustre_msg *msg, enum lustre_sec_part sp) +{ + msg->lm_secflvr |= (((__u32) sp) & 0xFF) << 16; +} + +static inline +enum lustre_sec_part null_decode_sec_part(struct lustre_msg *msg) +{ + switch (msg->lm_magic) { + case LUSTRE_MSG_MAGIC_V2: + return (msg->lm_secflvr >> 16) & 0xFF; + case LUSTRE_MSG_MAGIC_V2_SWABBED: + return (msg->lm_secflvr >> 8) & 0xFF; + default: + return LUSTRE_SP_ANY; + } +} + static int null_ctx_refresh(struct ptlrpc_cli_ctx *ctx) { @@ -50,8 +73,15 @@ int null_ctx_refresh(struct ptlrpc_cli_ctx *ctx) static int null_ctx_sign(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req) { - if (req->rq_reqbuf->lm_magic != LUSTRE_MSG_MAGIC_V1) + if (req->rq_reqbuf->lm_magic != LUSTRE_MSG_MAGIC_V1) { req->rq_reqbuf->lm_secflvr = SPTLRPC_FLVR_NULL; + + if (!req->rq_import->imp_dlm_fake) { + struct obd_device *obd = req->rq_import->imp_obd; + null_encode_sec_part(req->rq_reqbuf, + obd->u.cli.cl_sec_part); + } + } req->rq_reqdata_len = req->rq_reqlen; return 0; } @@ -76,12 +106,23 @@ static struct ptlrpc_svc_ctx null_svc_ctx = { }; static -struct ptlrpc_sec* null_create_sec(struct obd_import *imp, - struct ptlrpc_svc_ctx *ctx, - __u32 flavor, - unsigned long flags) +struct ptlrpc_sec *null_create_sec(struct obd_import *imp, + struct ptlrpc_svc_ctx *svc_ctx, + struct sptlrpc_flavor *sf) { - LASSERT(SEC_FLAVOR_POLICY(flavor) == SPTLRPC_POLICY_NULL); + LASSERT(RPC_FLVR_POLICY(sf->sf_rpc) == SPTLRPC_POLICY_NULL); + + if (sf->sf_bulk_priv != BULK_PRIV_ALG_NULL || + sf->sf_bulk_csum != BULK_CSUM_ALG_NULL) { + CERROR("null sec don't support bulk algorithm: %u/%u\n", + sf->sf_bulk_priv, sf->sf_bulk_csum); + return NULL; + } + + /* general layer has take a module reference for us, because we never + * really destroy the sec, simply release the reference here. + */ + sptlrpc_policy_put(&null_policy); return &null_sec; } @@ -138,16 +179,18 @@ void null_free_reqbuf(struct ptlrpc_sec *sec, { if (!req->rq_pool) { LASSERTF(req->rq_reqmsg == req->rq_reqbuf, - "reqmsg %p is not reqbuf %p in null sec\n", - req->rq_reqmsg, req->rq_reqbuf); + "req %p: reqmsg %p is not reqbuf %p in null sec\n", + req, req->rq_reqmsg, req->rq_reqbuf); LASSERTF(req->rq_reqbuf_len >= req->rq_reqlen, - "reqlen %d should smaller than buflen %d\n", - req->rq_reqlen, req->rq_reqbuf_len); + "req %p: reqlen %d should smaller than buflen %d\n", + req, req->rq_reqlen, req->rq_reqbuf_len); OBD_FREE(req->rq_reqbuf, req->rq_reqbuf_len); req->rq_reqmsg = req->rq_reqbuf = NULL; req->rq_reqbuf_len = 0; } + + req->rq_reqmsg = NULL; } static @@ -172,6 +215,8 @@ void null_free_repbuf(struct ptlrpc_sec *sec, OBD_FREE(req->rq_repbuf, req->rq_repbuf_len); req->rq_repbuf = NULL; req->rq_repbuf_len = 0; + + req->rq_repmsg = NULL; } static @@ -220,13 +265,15 @@ int null_enlarge_reqbuf(struct ptlrpc_sec *sec, static int null_accept(struct ptlrpc_request *req) { - LASSERT(SEC_FLAVOR_POLICY(req->rq_sec_flavor) == SPTLRPC_POLICY_NULL); + LASSERT(RPC_FLVR_POLICY(req->rq_flvr.sf_rpc) == SPTLRPC_POLICY_NULL); - if (SEC_FLAVOR_RPC(req->rq_sec_flavor) != SPTLRPC_FLVR_NULL) { - CERROR("Invalid flavor 0x%x\n", req->rq_sec_flavor); + if (req->rq_flvr.sf_rpc != SPTLRPC_FLVR_NULL) { + CERROR("Invalid rpc flavor 0x%x\n", req->rq_flvr.sf_rpc); return SECSVC_DROP; } + req->rq_sp_from = null_decode_sec_part(req->rq_reqbuf); + req->rq_reqmsg = req->rq_reqbuf; req->rq_reqlen = req->rq_reqdata_len; @@ -324,11 +371,16 @@ void null_init_internal(void) null_sec.ps_policy = &null_policy; atomic_set(&null_sec.ps_refcount, 1); /* always busy */ + null_sec.ps_id = -1; null_sec.ps_import = NULL; - null_sec.ps_flavor = SPTLRPC_FLVR_NULL; - null_sec.ps_flags = 0; + null_sec.ps_flvr.sf_rpc = SPTLRPC_FLVR_NULL; + null_sec.ps_flvr.sf_bulk_priv = BULK_PRIV_ALG_NULL; + null_sec.ps_flvr.sf_bulk_csum = BULK_CSUM_ALG_NULL; + null_sec.ps_flvr.sf_flags = 0; + null_sec.ps_part = LUSTRE_SP_ANY; + null_sec.ps_dying = 0; spin_lock_init(&null_sec.ps_lock); - atomic_set(&null_sec.ps_busy, 1); /* for "null_cli_ctx" */ + atomic_set(&null_sec.ps_nctx, 1); /* for "null_cli_ctx" */ INIT_LIST_HEAD(&null_sec.ps_gc_list); null_sec.ps_gc_interval = 0; null_sec.ps_gc_next = 0; diff --git a/lustre/ptlrpc/sec_plain.c b/lustre/ptlrpc/sec_plain.c index e15a69e..5c75f66 100644 --- a/lustre/ptlrpc/sec_plain.c +++ b/lustre/ptlrpc/sec_plain.c @@ -1,7 +1,7 @@ /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * - * Copyright (C) 2006 Cluster File Systems, Inc. + * Copyright (C) 2006-2007 Cluster File Systems, Inc. * Author: Eric Mei * * This file is part of Lustre, http://www.lustre.org. @@ -34,12 +34,61 @@ #include #include +struct plain_sec { + struct ptlrpc_sec pls_base; + rwlock_t pls_lock; + struct ptlrpc_cli_ctx *pls_ctx; +}; + +static inline struct plain_sec *sec2plsec(struct ptlrpc_sec *sec) +{ + return container_of(sec, struct plain_sec, pls_base); +} + static struct ptlrpc_sec_policy plain_policy; static struct ptlrpc_ctx_ops plain_ctx_ops; -static struct ptlrpc_sec plain_sec; -static struct ptlrpc_cli_ctx plain_cli_ctx; static struct ptlrpc_svc_ctx plain_svc_ctx; +/* + * flavor flags (maximum 8 flags) + */ +#define PLAIN_WFLVR_FLAGS_OFFSET (12) +#define PLAIN_WFLVR_FLAG_BULK (1 << (0 + PLAIN_WFLVR_FLAGS_OFFSET)) +#define PLAIN_WFLVR_FLAG_USER (1 << (1 + PLAIN_WFLVR_FLAGS_OFFSET)) + +#define PLAIN_WFLVR_HAS_BULK(wflvr) \ + (((wflvr) & PLAIN_WFLVR_FLAG_BULK) != 0) +#define PLAIN_WFLVR_HAS_USER(wflvr) \ + (((wflvr) & PLAIN_WFLVR_FLAG_USER) != 0) + +#define PLAIN_WFLVR_TO_RPC(wflvr) \ + ((wflvr) & ((1 << PLAIN_WFLVR_FLAGS_OFFSET) - 1)) + +/* + * similar to null sec, temporarily use the third byte of lm_secflvr to identify + * the source sec part. + */ +static inline +void plain_encode_sec_part(struct lustre_msg *msg, enum lustre_sec_part sp) +{ + msg->lm_secflvr |= (((__u32) sp) & 0xFF) << 16; +} + +static inline +enum lustre_sec_part plain_decode_sec_part(struct lustre_msg *msg) +{ + return (msg->lm_secflvr >> 16) & 0xFF; +} + +/* + * for simplicity, plain policy rpc use fixed layout. + */ +#define PLAIN_PACK_SEGMENTS (3) + +#define PLAIN_PACK_MSG_OFF (0) +#define PLAIN_PACK_USER_OFF (1) +#define PLAIN_PACK_BULK_OFF (2) + /**************************************** * cli_ctx apis * ****************************************/ @@ -53,12 +102,25 @@ int plain_ctx_refresh(struct ptlrpc_cli_ctx *ctx) } static +int plain_ctx_validate(struct ptlrpc_cli_ctx *ctx) +{ + return 0; +} + +static int plain_ctx_sign(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req) { struct lustre_msg_v2 *msg = req->rq_reqbuf; ENTRY; - msg->lm_secflvr = req->rq_sec_flavor; + msg->lm_secflvr = req->rq_flvr.sf_rpc; + if (req->rq_pack_bulk) + msg->lm_secflvr |= PLAIN_WFLVR_FLAG_BULK; + if (req->rq_pack_udesc) + msg->lm_secflvr |= PLAIN_WFLVR_FLAG_USER; + + plain_encode_sec_part(msg, ctx->cc_sec->ps_part); + req->rq_reqdata_len = lustre_msg_size_v2(msg->lm_bufcount, msg->lm_buflens); RETURN(0); @@ -68,23 +130,37 @@ static int plain_ctx_verify(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req) { struct lustre_msg *msg = req->rq_repbuf; + __u16 wflvr; ENTRY; - if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) { - if (msg->lm_bufcount != 2) { - CERROR("Protocol error: invalid buf count %d\n", - msg->lm_bufcount); - RETURN(-EPROTO); - } + if (msg->lm_bufcount != PLAIN_PACK_SEGMENTS) { + CERROR("unexpected reply buf count %u\n", msg->lm_bufcount); + RETURN(-EPROTO); + } - if (bulk_sec_desc_unpack(msg, 1)) { - CERROR("Mal-formed bulk checksum reply\n"); - RETURN(-EINVAL); - } + wflvr = WIRE_FLVR_RPC(msg->lm_secflvr); + + /* expect no user desc in reply */ + if (PLAIN_WFLVR_HAS_USER(wflvr)) { + CERROR("Unexpected udesc flag in reply\n"); + RETURN(-EPROTO); + } + + /* whether we sent with bulk or not, we expect the same in reply */ + if (!equi(req->rq_pack_bulk == 1, PLAIN_WFLVR_HAS_BULK(wflvr))) { + CERROR("%s bulk checksum in reply\n", + req->rq_pack_bulk ? "Missing" : "Unexpected"); + RETURN(-EPROTO); } - req->rq_repmsg = lustre_msg_buf(msg, 0, 0); - req->rq_replen = msg->lm_buflens[0]; + if (req->rq_pack_bulk && + bulk_sec_desc_unpack(msg, PLAIN_PACK_BULK_OFF)) { + CERROR("Mal-formed bulk checksum reply\n"); + RETURN(-EINVAL); + } + + req->rq_repmsg = lustre_msg_buf(msg, PLAIN_PACK_MSG_OFF, 0); + req->rq_replen = msg->lm_buflens[PLAIN_PACK_MSG_OFF]; RETURN(0); } @@ -93,17 +169,13 @@ int plain_cli_wrap_bulk(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req, struct ptlrpc_bulk_desc *desc) { - struct sec_flavor_config *conf; - - LASSERT(req->rq_import); - LASSERT(SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)); - LASSERT(req->rq_reqbuf->lm_bufcount >= 2); + LASSERT(req->rq_pack_bulk); + LASSERT(req->rq_reqbuf->lm_bufcount == PLAIN_PACK_SEGMENTS); - conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf; return bulk_csum_cli_request(desc, req->rq_bulk_read, - conf->sfc_bulk_csum, + req->rq_flvr.sf_bulk_csum, req->rq_reqbuf, - req->rq_reqbuf->lm_bufcount - 1); + PLAIN_PACK_BULK_OFF); } static @@ -111,15 +183,13 @@ int plain_cli_unwrap_bulk(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req, struct ptlrpc_bulk_desc *desc) { - LASSERT(SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)); - LASSERT(req->rq_reqbuf->lm_bufcount >= 2); - LASSERT(req->rq_repbuf->lm_bufcount >= 2); + LASSERT(req->rq_pack_bulk); + LASSERT(req->rq_reqbuf->lm_bufcount == PLAIN_PACK_SEGMENTS); + LASSERT(req->rq_repbuf->lm_bufcount == PLAIN_PACK_SEGMENTS); return bulk_csum_cli_reply(desc, req->rq_bulk_read, - req->rq_reqbuf, - req->rq_reqbuf->lm_bufcount - 1, - req->rq_repbuf, - req->rq_repbuf->lm_bufcount - 1); + req->rq_reqbuf, PLAIN_PACK_BULK_OFF, + req->rq_repbuf, PLAIN_PACK_BULK_OFF); } /**************************************** @@ -127,40 +197,178 @@ int plain_cli_unwrap_bulk(struct ptlrpc_cli_ctx *ctx, ****************************************/ static -struct ptlrpc_sec* plain_create_sec(struct obd_import *imp, - struct ptlrpc_svc_ctx *ctx, - __u32 flavor, - unsigned long flags) +struct ptlrpc_cli_ctx *plain_sec_install_ctx(struct plain_sec *plsec) { - ENTRY; - LASSERT(SEC_FLAVOR_POLICY(flavor) == SPTLRPC_POLICY_PLAIN); - RETURN(&plain_sec); + struct ptlrpc_cli_ctx *ctx, *ctx_new; + + OBD_ALLOC_PTR(ctx_new); + + write_lock(&plsec->pls_lock); + + ctx = plsec->pls_ctx; + if (ctx) { + atomic_inc(&ctx->cc_refcount); + + if (ctx_new) + OBD_FREE_PTR(ctx_new); + } else if (ctx_new) { + ctx = ctx_new; + + atomic_set(&ctx->cc_refcount, 1); /* for cache */ + ctx->cc_sec = &plsec->pls_base; + ctx->cc_ops = &plain_ctx_ops; + ctx->cc_expire = 0; + ctx->cc_flags = PTLRPC_CTX_CACHED | PTLRPC_CTX_UPTODATE; + ctx->cc_vcred.vc_uid = 0; + spin_lock_init(&ctx->cc_lock); + INIT_LIST_HEAD(&ctx->cc_req_list); + INIT_LIST_HEAD(&ctx->cc_gc_chain); + + plsec->pls_ctx = ctx; + atomic_inc(&plsec->pls_base.ps_nctx); + atomic_inc(&plsec->pls_base.ps_refcount); + + atomic_inc(&ctx->cc_refcount); /* for caller */ + } + + write_unlock(&plsec->pls_lock); + + return ctx; } static void plain_destroy_sec(struct ptlrpc_sec *sec) { + struct plain_sec *plsec = sec2plsec(sec); ENTRY; - LASSERT(sec == &plain_sec); + + LASSERT(sec->ps_policy == &plain_policy); + LASSERT(sec->ps_import); + LASSERT(atomic_read(&sec->ps_refcount) == 0); + LASSERT(atomic_read(&sec->ps_nctx) == 0); + LASSERT(plsec->pls_ctx == NULL); + + class_import_put(sec->ps_import); + + OBD_FREE_PTR(plsec); EXIT; } static +void plain_kill_sec(struct ptlrpc_sec *sec) +{ + sec->ps_dying = 1; +} + +static +struct ptlrpc_sec *plain_create_sec(struct obd_import *imp, + struct ptlrpc_svc_ctx *svc_ctx, + struct sptlrpc_flavor *sf) +{ + struct plain_sec *plsec; + struct ptlrpc_sec *sec; + struct ptlrpc_cli_ctx *ctx; + ENTRY; + + LASSERT(RPC_FLVR_POLICY(sf->sf_rpc) == SPTLRPC_POLICY_PLAIN); + + if (sf->sf_bulk_priv != BULK_PRIV_ALG_NULL) { + CERROR("plain policy don't support bulk encryption: %u\n", + sf->sf_bulk_priv); + RETURN(NULL); + } + + OBD_ALLOC_PTR(plsec); + if (plsec == NULL) + RETURN(NULL); + + /* + * initialize plain_sec + */ + plsec->pls_lock = RW_LOCK_UNLOCKED; + plsec->pls_ctx = NULL; + + sec = &plsec->pls_base; + sec->ps_policy = &plain_policy; + atomic_set(&sec->ps_refcount, 0); + atomic_set(&sec->ps_nctx, 0); + sec->ps_id = sptlrpc_get_next_secid(); + sec->ps_import = class_import_get(imp); + sec->ps_flvr = *sf; + sec->ps_lock = SPIN_LOCK_UNLOCKED; + INIT_LIST_HEAD(&sec->ps_gc_list); + sec->ps_gc_interval = 0; + sec->ps_gc_next = 0; + + /* install ctx immediately if this is a reverse sec */ + if (svc_ctx) { + ctx = plain_sec_install_ctx(plsec); + if (ctx == NULL) { + plain_destroy_sec(sec); + RETURN(NULL); + } + sptlrpc_cli_ctx_put(ctx, 1); + } + + RETURN(sec); +} + +static struct ptlrpc_cli_ctx *plain_lookup_ctx(struct ptlrpc_sec *sec, struct vfs_cred *vcred, int create, int remove_dead) { + struct plain_sec *plsec = sec2plsec(sec); + struct ptlrpc_cli_ctx *ctx; ENTRY; - atomic_inc(&plain_cli_ctx.cc_refcount); - RETURN(&plain_cli_ctx); + + read_lock(&plsec->pls_lock); + ctx = plsec->pls_ctx; + if (ctx) + atomic_inc(&ctx->cc_refcount); + read_unlock(&plsec->pls_lock); + + if (unlikely(ctx == NULL)) + ctx = plain_sec_install_ctx(plsec); + + RETURN(ctx); +} + +static +void plain_release_ctx(struct ptlrpc_sec *sec, + struct ptlrpc_cli_ctx *ctx, int sync) +{ + LASSERT(atomic_read(&sec->ps_refcount) > 0); + LASSERT(atomic_read(&sec->ps_nctx) > 0); + LASSERT(atomic_read(&ctx->cc_refcount) == 0); + LASSERT(ctx->cc_sec == sec); + + OBD_FREE_PTR(ctx); + + atomic_dec(&sec->ps_nctx); + sptlrpc_sec_put(sec); } static int plain_flush_ctx_cache(struct ptlrpc_sec *sec, - uid_t uid, - int grace, int force) + uid_t uid, int grace, int force) { - return 0; + struct plain_sec *plsec = sec2plsec(sec); + struct ptlrpc_cli_ctx *ctx; + ENTRY; + + /* do nothing unless caller want to flush for 'all' */ + if (uid != -1) + RETURN(0); + + write_lock(&plsec->pls_lock); + ctx = plsec->pls_ctx; + plsec->pls_ctx = NULL; + write_unlock(&plsec->pls_lock); + + if (ctx) + sptlrpc_cli_ctx_put(ctx, 1); + RETURN(0); } static @@ -168,24 +376,24 @@ int plain_alloc_reqbuf(struct ptlrpc_sec *sec, struct ptlrpc_request *req, int msgsize) { - struct sec_flavor_config *conf; - int bufcnt = 1, buflens[2], alloc_len; + int buflens[PLAIN_PACK_SEGMENTS] = { 0, }; + int alloc_len; ENTRY; - buflens[0] = msgsize; + buflens[PLAIN_PACK_MSG_OFF] = msgsize; - if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) - buflens[bufcnt++] = sptlrpc_current_user_desc_size(); + if (req->rq_pack_udesc) + buflens[PLAIN_PACK_USER_OFF] = sptlrpc_current_user_desc_size(); - if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) { + if (req->rq_pack_bulk) { LASSERT(req->rq_bulk_read || req->rq_bulk_write); - conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf; - buflens[bufcnt++] = bulk_sec_desc_size(conf->sfc_bulk_csum, 1, - req->rq_bulk_read); + buflens[PLAIN_PACK_BULK_OFF] = bulk_sec_desc_size( + req->rq_flvr.sf_bulk_csum, 1, + req->rq_bulk_read); } - alloc_len = lustre_msg_size_v2(bufcnt, buflens); + alloc_len = lustre_msg_size_v2(PLAIN_PACK_SEGMENTS, buflens); if (!req->rq_reqbuf) { LASSERT(!req->rq_pool); @@ -202,11 +410,11 @@ int plain_alloc_reqbuf(struct ptlrpc_sec *sec, memset(req->rq_reqbuf, 0, alloc_len); } - lustre_init_msg_v2(req->rq_reqbuf, bufcnt, buflens, NULL); + lustre_init_msg_v2(req->rq_reqbuf, PLAIN_PACK_SEGMENTS, buflens, NULL); req->rq_reqmsg = lustre_msg_buf_v2(req->rq_reqbuf, 0, 0); - if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) - sptlrpc_pack_user_desc(req->rq_reqbuf, 1); + if (req->rq_pack_udesc) + sptlrpc_pack_user_desc(req->rq_reqbuf, PLAIN_PACK_USER_OFF); RETURN(0); } @@ -221,6 +429,8 @@ void plain_free_reqbuf(struct ptlrpc_sec *sec, req->rq_reqbuf = NULL; req->rq_reqbuf_len = 0; } + + req->rq_reqmsg = NULL; EXIT; } @@ -229,21 +439,21 @@ int plain_alloc_repbuf(struct ptlrpc_sec *sec, struct ptlrpc_request *req, int msgsize) { - struct sec_flavor_config *conf; - int bufcnt = 1, buflens[2], alloc_len; + int buflens[PLAIN_PACK_SEGMENTS] = { 0, }; + int alloc_len; ENTRY; - buflens[0] = msgsize; + buflens[PLAIN_PACK_MSG_OFF] = msgsize; - if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) { + if (req->rq_pack_bulk) { LASSERT(req->rq_bulk_read || req->rq_bulk_write); - conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf; - buflens[bufcnt++] = bulk_sec_desc_size(conf->sfc_bulk_csum, 0, - req->rq_bulk_read); + buflens[PLAIN_PACK_BULK_OFF] = bulk_sec_desc_size( + req->rq_flvr.sf_bulk_csum, 0, + req->rq_bulk_read); } - alloc_len = lustre_msg_size_v2(bufcnt, buflens); + alloc_len = lustre_msg_size_v2(PLAIN_PACK_SEGMENTS, buflens); alloc_len = size_roundup_power2(alloc_len); OBD_ALLOC(req->rq_repbuf, alloc_len); @@ -262,6 +472,8 @@ void plain_free_repbuf(struct ptlrpc_sec *sec, OBD_FREE(req->rq_repbuf, req->rq_repbuf_len); req->rq_repbuf = NULL; req->rq_repbuf_len = 0; + + req->rq_repmsg = NULL; EXIT; } @@ -275,10 +487,10 @@ int plain_enlarge_reqbuf(struct ptlrpc_sec *sec, int newmsg_size, newbuf_size; ENTRY; - /* embedded msg always at seg 0 */ LASSERT(req->rq_reqbuf); LASSERT(req->rq_reqbuf_len >= req->rq_reqlen); - LASSERT(lustre_msg_buf(req->rq_reqbuf, 0, 0) == req->rq_reqmsg); + LASSERT(lustre_msg_buf(req->rq_reqbuf, PLAIN_PACK_MSG_OFF, 0) == + req->rq_reqmsg); /* compute new embedded msg size. */ oldsize = req->rq_reqmsg->lm_buflens[segment]; @@ -288,11 +500,11 @@ int plain_enlarge_reqbuf(struct ptlrpc_sec *sec, req->rq_reqmsg->lm_buflens[segment] = oldsize; /* compute new wrapper msg size. */ - oldsize = req->rq_reqbuf->lm_buflens[0]; - req->rq_reqbuf->lm_buflens[0] = newmsg_size; + oldsize = req->rq_reqbuf->lm_buflens[PLAIN_PACK_MSG_OFF]; + req->rq_reqbuf->lm_buflens[PLAIN_PACK_MSG_OFF] = newmsg_size; newbuf_size = lustre_msg_size_v2(req->rq_reqbuf->lm_bufcount, req->rq_reqbuf->lm_buflens); - req->rq_reqbuf->lm_buflens[0] = oldsize; + req->rq_reqbuf->lm_buflens[PLAIN_PACK_MSG_OFF] = oldsize; /* request from pool should always have enough buffer */ LASSERT(!req->rq_pool || req->rq_reqbuf_len >= newbuf_size); @@ -309,10 +521,12 @@ int plain_enlarge_reqbuf(struct ptlrpc_sec *sec, OBD_FREE(req->rq_reqbuf, req->rq_reqbuf_len); req->rq_reqbuf = newbuf; req->rq_reqbuf_len = newbuf_size; - req->rq_reqmsg = lustre_msg_buf(req->rq_reqbuf, 0, 0); + req->rq_reqmsg = lustre_msg_buf(req->rq_reqbuf, + PLAIN_PACK_MSG_OFF, 0); } - _sptlrpc_enlarge_msg_inplace(req->rq_reqbuf, 0, newmsg_size); + _sptlrpc_enlarge_msg_inplace(req->rq_reqbuf, PLAIN_PACK_MSG_OFF, + newmsg_size); _sptlrpc_enlarge_msg_inplace(req->rq_reqmsg, segment, newsize); req->rq_reqlen = newmsg_size; @@ -332,46 +546,43 @@ static int plain_accept(struct ptlrpc_request *req) { struct lustre_msg *msg = req->rq_reqbuf; - int bufcnt = 1; ENTRY; - LASSERT(SEC_FLAVOR_POLICY(req->rq_sec_flavor) == SPTLRPC_POLICY_PLAIN); + LASSERT(RPC_FLVR_POLICY(req->rq_flvr.sf_rpc) == SPTLRPC_POLICY_PLAIN); - if (SEC_FLAVOR_RPC(req->rq_sec_flavor) != SPTLRPC_FLVR_PLAIN) { - CERROR("Invalid flavor 0x%x\n", req->rq_sec_flavor); - return SECSVC_DROP; + if (msg->lm_bufcount < PLAIN_PACK_SEGMENTS) { + CERROR("unexpected request buf count %u\n", msg->lm_bufcount); + RETURN(SECSVC_DROP); } - if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) { - if (msg->lm_bufcount < ++bufcnt) { - CERROR("Protocal error: too small buf count %d\n", - msg->lm_bufcount); - RETURN(SECSVC_DROP); - } + if (req->rq_flvr.sf_rpc != SPTLRPC_FLVR_PLAIN) { + CERROR("Invalid rpc flavor %x\n", req->rq_flvr.sf_rpc); + RETURN(SECSVC_DROP); + } + + req->rq_sp_from = plain_decode_sec_part(msg); - if (sptlrpc_unpack_user_desc(msg, bufcnt - 1)) { + if (PLAIN_WFLVR_HAS_USER(msg->lm_secflvr)) { + if (sptlrpc_unpack_user_desc(msg, PLAIN_PACK_USER_OFF)) { CERROR("Mal-formed user descriptor\n"); RETURN(SECSVC_DROP); } - req->rq_user_desc = lustre_msg_buf(msg, bufcnt - 1, 0); + req->rq_pack_udesc = 1; + req->rq_user_desc = lustre_msg_buf(msg, PLAIN_PACK_USER_OFF, 0); } - if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) { - if (msg->lm_bufcount != ++bufcnt) { - CERROR("Protocal error: invalid buf count %d\n", - msg->lm_bufcount); - RETURN(SECSVC_DROP); - } - - if (bulk_sec_desc_unpack(msg, bufcnt - 1)) { + if (PLAIN_WFLVR_HAS_BULK(msg->lm_secflvr)) { + if (bulk_sec_desc_unpack(msg, PLAIN_PACK_BULK_OFF)) { CERROR("Mal-formed bulk checksum request\n"); RETURN(SECSVC_DROP); } + + req->rq_pack_bulk = 1; } - req->rq_reqmsg = lustre_msg_buf(msg, 0, 0); - req->rq_reqlen = msg->lm_buflens[0]; + req->rq_reqmsg = lustre_msg_buf(msg, PLAIN_PACK_MSG_OFF, 0); + req->rq_reqlen = msg->lm_buflens[PLAIN_PACK_MSG_OFF]; req->rq_svc_ctx = &plain_svc_ctx; atomic_inc(&req->rq_svc_ctx->sc_refcount); @@ -382,26 +593,26 @@ int plain_accept(struct ptlrpc_request *req) static int plain_alloc_rs(struct ptlrpc_request *req, int msgsize) { - struct ptlrpc_reply_state *rs; + struct ptlrpc_reply_state *rs; struct ptlrpc_bulk_sec_desc *bsd; - int bufcnt = 1, buflens[2]; - int rs_size = sizeof(*rs); + int buflens[PLAIN_PACK_SEGMENTS] = { 0, }; + int rs_size = sizeof(*rs); ENTRY; LASSERT(msgsize % 8 == 0); - buflens[0] = msgsize; - if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor) && - (req->rq_bulk_read || req->rq_bulk_write)) { + buflens[PLAIN_PACK_MSG_OFF] = msgsize; + + if (req->rq_pack_bulk && (req->rq_bulk_read || req->rq_bulk_write)) { bsd = lustre_msg_buf(req->rq_reqbuf, - req->rq_reqbuf->lm_bufcount - 1, - sizeof(*bsd)); + PLAIN_PACK_BULK_OFF, sizeof(*bsd)); LASSERT(bsd); - buflens[bufcnt++] = bulk_sec_desc_size(bsd->bsd_csum_alg, 0, - req->rq_bulk_read); + buflens[PLAIN_PACK_BULK_OFF] = bulk_sec_desc_size( + bsd->bsd_csum_alg, 0, + req->rq_bulk_read); } - rs_size += lustre_msg_size_v2(bufcnt, buflens); + rs_size += lustre_msg_size_v2(PLAIN_PACK_SEGMENTS, buflens); rs = req->rq_reply_state; @@ -421,8 +632,8 @@ int plain_alloc_rs(struct ptlrpc_request *req, int msgsize) rs->rs_repbuf = (struct lustre_msg *) (rs + 1); rs->rs_repbuf_len = rs_size - sizeof(*rs); - lustre_init_msg_v2(rs->rs_repbuf, bufcnt, buflens, NULL); - rs->rs_msg = lustre_msg_buf_v2(rs->rs_repbuf, 0, 0); + lustre_init_msg_v2(rs->rs_repbuf, PLAIN_PACK_SEGMENTS, buflens, NULL); + rs->rs_msg = lustre_msg_buf_v2(rs->rs_repbuf, PLAIN_PACK_MSG_OFF, 0); req->rq_reply_state = rs; RETURN(0); @@ -452,12 +663,16 @@ int plain_authorize(struct ptlrpc_request *req) LASSERT(rs); LASSERT(msg); - if (req->rq_replen != msg->lm_buflens[0]) - len = lustre_shrink_msg(msg, 0, req->rq_replen, 1); + if (req->rq_replen != msg->lm_buflens[PLAIN_PACK_MSG_OFF]) + len = lustre_shrink_msg(msg, PLAIN_PACK_MSG_OFF, + req->rq_replen, 1); else len = lustre_msg_size_v2(msg->lm_bufcount, msg->lm_buflens); - msg->lm_secflvr = req->rq_sec_flavor; + msg->lm_secflvr = req->rq_flvr.sf_rpc; + if (req->rq_pack_bulk) + msg->lm_secflvr |= PLAIN_WFLVR_FLAG_BULK; + rs->rs_repdata_len = len; RETURN(0); } @@ -467,18 +682,21 @@ int plain_svc_unwrap_bulk(struct ptlrpc_request *req, struct ptlrpc_bulk_desc *desc) { struct ptlrpc_reply_state *rs = req->rq_reply_state; - int voff, roff; LASSERT(rs); - - voff = req->rq_reqbuf->lm_bufcount - 1; - roff = rs->rs_repbuf->lm_bufcount - 1; + LASSERT(req->rq_pack_bulk); + LASSERT(req->rq_reqbuf->lm_bufcount >= PLAIN_PACK_SEGMENTS); + LASSERT(rs->rs_repbuf->lm_bufcount == PLAIN_PACK_SEGMENTS); return bulk_csum_svc(desc, req->rq_bulk_read, - lustre_msg_buf(req->rq_reqbuf, voff, 0), - lustre_msg_buflen(req->rq_reqbuf, voff), - lustre_msg_buf(rs->rs_repbuf, roff, 0), - lustre_msg_buflen(rs->rs_repbuf, roff)); + lustre_msg_buf(req->rq_reqbuf, + PLAIN_PACK_BULK_OFF, 0), + lustre_msg_buflen(req->rq_reqbuf, + PLAIN_PACK_BULK_OFF), + lustre_msg_buf(rs->rs_repbuf, + PLAIN_PACK_BULK_OFF, 0), + lustre_msg_buflen(rs->rs_repbuf, + PLAIN_PACK_BULK_OFF)); } static @@ -486,22 +704,26 @@ int plain_svc_wrap_bulk(struct ptlrpc_request *req, struct ptlrpc_bulk_desc *desc) { struct ptlrpc_reply_state *rs = req->rq_reply_state; - int voff, roff; LASSERT(rs); - - voff = req->rq_reqbuf->lm_bufcount - 1; - roff = rs->rs_repbuf->lm_bufcount - 1; + LASSERT(req->rq_pack_bulk); + LASSERT(req->rq_reqbuf->lm_bufcount >= PLAIN_PACK_SEGMENTS); + LASSERT(rs->rs_repbuf->lm_bufcount == PLAIN_PACK_SEGMENTS); return bulk_csum_svc(desc, req->rq_bulk_read, - lustre_msg_buf(req->rq_reqbuf, voff, 0), - lustre_msg_buflen(req->rq_reqbuf, voff), - lustre_msg_buf(rs->rs_repbuf, roff, 0), - lustre_msg_buflen(rs->rs_repbuf, roff)); + lustre_msg_buf(req->rq_reqbuf, + PLAIN_PACK_BULK_OFF, 0), + lustre_msg_buflen(req->rq_reqbuf, + PLAIN_PACK_BULK_OFF), + lustre_msg_buf(rs->rs_repbuf, + PLAIN_PACK_BULK_OFF, 0), + lustre_msg_buflen(rs->rs_repbuf, + PLAIN_PACK_BULK_OFF)); } static struct ptlrpc_ctx_ops plain_ctx_ops = { .refresh = plain_ctx_refresh, + .validate = plain_ctx_validate, .sign = plain_ctx_sign, .verify = plain_ctx_verify, .wrap_bulk = plain_cli_wrap_bulk, @@ -511,7 +733,9 @@ static struct ptlrpc_ctx_ops plain_ctx_ops = { static struct ptlrpc_sec_cops plain_sec_cops = { .create_sec = plain_create_sec, .destroy_sec = plain_destroy_sec, + .kill_sec = plain_kill_sec, .lookup_ctx = plain_lookup_ctx, + .release_ctx = plain_release_ctx, .flush_ctx_cache = plain_flush_ctx_cache, .alloc_reqbuf = plain_alloc_reqbuf, .alloc_repbuf = plain_alloc_repbuf, @@ -531,50 +755,19 @@ static struct ptlrpc_sec_sops plain_sec_sops = { static struct ptlrpc_sec_policy plain_policy = { .sp_owner = THIS_MODULE, - .sp_name = "sec.plain", + .sp_name = "plain", .sp_policy = SPTLRPC_POLICY_PLAIN, .sp_cops = &plain_sec_cops, .sp_sops = &plain_sec_sops, }; -static -void plain_init_internal(void) -{ - static HLIST_HEAD(__list); - - plain_sec.ps_policy = &plain_policy; - atomic_set(&plain_sec.ps_refcount, 1); /* always busy */ - plain_sec.ps_import = NULL; - plain_sec.ps_flavor = SPTLRPC_FLVR_PLAIN; - plain_sec.ps_flags = 0; - spin_lock_init(&plain_sec.ps_lock); - atomic_set(&plain_sec.ps_busy, 1); /* for "plain_cli_ctx" */ - CFS_INIT_LIST_HEAD(&plain_sec.ps_gc_list); - plain_sec.ps_gc_interval = 0; - plain_sec.ps_gc_next = 0; - - hlist_add_head(&plain_cli_ctx.cc_cache, &__list); - atomic_set(&plain_cli_ctx.cc_refcount, 1); /* for hash */ - plain_cli_ctx.cc_sec = &plain_sec; - plain_cli_ctx.cc_ops = &plain_ctx_ops; - plain_cli_ctx.cc_expire = 0; - plain_cli_ctx.cc_flags = PTLRPC_CTX_CACHED | PTLRPC_CTX_ETERNAL | - PTLRPC_CTX_UPTODATE; - plain_cli_ctx.cc_vcred.vc_uid = 0; - spin_lock_init(&plain_cli_ctx.cc_lock); - CFS_INIT_LIST_HEAD(&plain_cli_ctx.cc_req_list); - CFS_INIT_LIST_HEAD(&plain_cli_ctx.cc_gc_chain); -} - int sptlrpc_plain_init(void) { int rc; - plain_init_internal(); - rc = sptlrpc_register_policy(&plain_policy); if (rc) - CERROR("failed to register sec.plain: %d\n", rc); + CERROR("failed to register: %d\n", rc); return rc; } @@ -585,5 +778,5 @@ void sptlrpc_plain_fini(void) rc = sptlrpc_unregister_policy(&plain_policy); if (rc) - CERROR("cannot unregister sec.plain: %d\n", rc); + CERROR("cannot unregister: %d\n", rc); } diff --git a/lustre/ptlrpc/service.c b/lustre/ptlrpc/service.c index dc1106e..1e6a812 100644 --- a/lustre/ptlrpc/service.c +++ b/lustre/ptlrpc/service.c @@ -591,9 +591,6 @@ ptlrpc_server_handle_request(struct ptlrpc_service *svc, } /* go through security check/transform */ - request->rq_auth_uid = INVALID_UID; - request->rq_auth_mapped_uid = INVALID_UID; - rc = sptlrpc_svc_unwrap_request(request); switch (rc) { case SECSVC_OK: @@ -674,7 +671,7 @@ ptlrpc_server_handle_request(struct ptlrpc_service *svc, rc = sptlrpc_target_export_check(request->rq_export, request); if (unlikely(rc)) { DEBUG_REQ(D_ERROR, request, - "DROPPING req with illeagle security flavor"); + "DROPPING req with illegal security flavor,"); goto put_conn; } diff --git a/lustre/tests/Makefile.am b/lustre/tests/Makefile.am index 2d16b87..b14261f 100644 --- a/lustre/tests/Makefile.am +++ b/lustre/tests/Makefile.am @@ -12,10 +12,15 @@ noinst_SCRIPTS += conf-sanity.sh insanity.sh lfscktest.sh oos.sh oos2.sh noinst_SCRIPTS += llog-test.sh recovery-small.sh replay-dual.sh sanity-quota.sh noinst_SCRIPTS += replay-ost-single.sh replay-single.sh run-llog.sh sanityN.sh noinst_SCRIPTS += lockorder.sh socketclient socketserver sanity-sec.sh +noinst_SCRIPTS += sanity-gss.sh krb5_login.sh nobase_noinst_SCRIPTS = cfg/insanity-local.sh cfg/insanity-ltest.sh nobase_noinst_SCRIPTS += cfg/local.sh acl/make-tree acl/run +nobase_noinst_SCRIPTS += rmtacl/make-tree rmtacl/run nobase_noinst_DATA = acl/cp.test acl/getfacl-noacl.test acl/inheritance.test nobase_noinst_DATA += acl/misc.test acl/permissions.test acl/setfacl.test +nobase_noinst_DATA += rmtacl/misc.test rmtacl/permissions.test +nobase_noinst_DATA += rmtacl/setfacl.test rmtacl/cp.test +nobase_noinst_DATA += rmtacl/getfacl-noacl.test rmtacl/inheritance.test EXTRA_DIST = $(noinst_SCRIPTS) $(noinst_DATA) \ $(nobase_noinst_SCRIPTS) $(nobase_noinst_DATA) diff --git a/lustre/tests/acceptance-small.sh b/lustre/tests/acceptance-small.sh index c5b6b40..4c27f95 100755 --- a/lustre/tests/acceptance-small.sh +++ b/lustre/tests/acceptance-small.sh @@ -25,7 +25,7 @@ fi [ "$DEBUG_OFF" ] || DEBUG_OFF="eval sysctl -w lnet.debug=\"$DEBUG_LVL\"" [ "$DEBUG_ON" ] || DEBUG_ON="eval sysctl -w lnet.debug=0x33f0484" -export TESTSUITE_LIST="RUNTESTS SANITY DBENCH BONNIE IOZONE FSX SANITYN LFSCK LIBLUSTRE REPLAY_SINGLE CONF_SANITY RECOVERY_SMALL REPLAY_OST_SINGLE REPLAY_DUAL INSANITY SANITY_QUOTA" +export TESTSUITE_LIST="RUNTESTS SANITY DBENCH BONNIE IOZONE FSX SANITYN LFSCK LIBLUSTRE REPLAY_SINGLE CONF_SANITY RECOVERY_SMALL REPLAY_OST_SINGLE REPLAY_DUAL INSANITY SANITY_QUOTA SANITY_SEC" if [ "$SLOW" = "no" ]; then # 5 min @@ -52,6 +52,11 @@ LUSTRE=${LUSTRE:-`dirname $0`/..} . $LUSTRE/tests/test-framework.sh init_test_env $@ +if $GSS; then + # liblustre doesn't support GSS + export LIBLUSTRE=no +fi + SETUP=${SETUP:-setupall} FORMAT=${FORMAT:-formatall} CLEANUP=${CLEANUP:-stopall} @@ -311,6 +316,10 @@ if [ "$SANITY_QUOTA" != "no" ]; then SANITY_QUOTA="done" fi +if [ "$SANITY_SEC" != "no" ]; then + title sanity-sec + bash sanity-sec.sh +fi RC=$? title FINISHED diff --git a/lustre/tests/conf-sanity.sh b/lustre/tests/conf-sanity.sh index fd4de0e..dbd9b6b 100644 --- a/lustre/tests/conf-sanity.sh +++ b/lustre/tests/conf-sanity.sh @@ -174,7 +174,7 @@ fi gen_config -init_krb5_env +init_gss test_0() { setup @@ -1493,7 +1493,7 @@ run_test 38 "MDS recreates missing lov_objid file from OST data" umount_client $MOUNT cleanup_nocli -cleanup_krb5_env +cleanup_gss equals_msg `basename $0`: test complete [ -f "$TESTSUITELOG" ] && cat $TESTSUITELOG || true diff --git a/lustre/tests/krb5_login.sh b/lustre/tests/krb5_login.sh index e80ae7c2..b2a4205 100755 --- a/lustre/tests/krb5_login.sh +++ b/lustre/tests/krb5_login.sh @@ -7,11 +7,7 @@ if [ $UID -eq 0 ]; then exit 0 fi -if [ -z "$KRB5DIR" ]; then - KRB5DIR=/usr/kerberos -fi - -$KRB5DIR/bin/klist -5 -s +klist -5 -s invalid=$? if [ $invalid -eq 0 ]; then @@ -20,7 +16,7 @@ fi echo "***** refresh Kerberos V5 TGT for uid $UID *****" if [ -z "$GSS_PASS" ]; then - $KRB5DIR/bin/kinit + kinit else expect < -rw-rw-r--+ + + $ lfs cp f g + $ lfs ls -l g | awk -- '{ print $1 }' + > -rw-r--r-- + + $ rm g + $ lfs cp -p f g + $ lfs ls -l f | awk -- '{ print $1 }' + > -rw-rw-r--+ + + $ mkdir h + $ echo blubb > h/x + $ lfs cp -rp h i + $ cat i/x + > blubb + + $ rm -r i + +Use to be "$lfs lsetfacl -R -m u:bin:rwX h", but RHEL4 uncorrectly set the x flag, +so we change to the following test + + $ lfs lsetfacl -R -m u:bin:rwx h + $ lfs lgetfacl --omit-header h/x + > user::rw- + > user:bin:rwx + > group::r-- + > mask::rwx + > other::r-- + > + + $ lfs cp -rp h i + $ lfs lgetfacl --omit-header i/x + > user::rw- + > user:bin:rwx + > group::r-- + > mask::rwx + > other::r-- + > + + $ cd .. + $ rm -r d diff --git a/lustre/tests/rmtacl/getfacl-noacl.test b/lustre/tests/rmtacl/getfacl-noacl.test new file mode 100644 index 0000000..8f1f69a --- /dev/null +++ b/lustre/tests/rmtacl/getfacl-noacl.test @@ -0,0 +1,59 @@ +Getfacl utility option parsing tests. This test can be run on a +filesystem with or without ACL support. + + $ mkdir test + $ cd test + $ umask 027 + $ touch x + $ lfs lgetfacl --omit-header x + > user::rw- + > group::r-- + > other::--- + > + + $ lfs lgetfacl --omit-header --access x + > user::rw- + > group::r-- + > other::--- + > + + $ lfs lgetfacl --omit-header -d x + $ lfs lgetfacl --omit-header -d . + $ lfs lgetfacl --omit-header -d / + > getfacl: Removing leading '/' from absolute path names + + $ lfs lgetfacl --skip-base x + $ lfs lgetfacl --omit-header --all-effective x + > user::rw- + > group::r-- + > other::--- + > + + $ lfs lgetfacl --omit-header --no-effective x + > user::rw- + > group::r-- + > other::--- + > + + $ mkdir d + $ touch d/y + $ ln -s d l +The result of "lfs lgetfacl -dR . | grep file | sort" is related with +the dentry item order in parent directory. Such order depends on +FS implementation. Fix with -P (--physical) option. +# $ lfs lgetfacl -dR . | grep file | sort + $ lfs lgetfacl -dRP . | grep file | sort + > # file: . + > # file: d + > # file: d/y + > # file: x + + $ ln -s l ll + $ lfs lgetfacl -dLR ll | grep file | sort + > # file: ll + > # file: ll/y + + $ rm l ll x + $ rm -rf d + $ cd .. + $ rmdir test diff --git a/lustre/tests/rmtacl/inheritance.test b/lustre/tests/rmtacl/inheritance.test new file mode 100644 index 0000000..40d25cb --- /dev/null +++ b/lustre/tests/rmtacl/inheritance.test @@ -0,0 +1,131 @@ +ACL inheritance test. Run these tests on a filesystem with ACL support. + + + $ id -u + > 0 + + $ mkdir d + $ lfs lsetfacl -d -m group:bin:r-x d + $ lfs lgetfacl d + > # file: d + > # owner: root + > # group: root + > user::rwx + > group::r-x + > other::r-x + > default:user::rwx + > default:group::r-x + > default:group:bin:r-x + > default:mask::r-x + > default:other::r-x + > + + $ mkdir d/subdir + $ lfs lgetfacl d/subdir + > # file: d/subdir + > # owner: root + > # group: root + > user::rwx + > group::r-x + > group:bin:r-x + > mask::r-x + > other::r-x + > default:user::rwx + > default:group::r-x + > default:group:bin:r-x + > default:mask::r-x + > default:other::r-x + > + + $ touch d/f + $ lfs ls -l d/f | awk -- '{ print $1 }' + > -rw-r--r--+ + $ lfs lgetfacl d/f + > # file: d/f + > # owner: root + > # group: root + > user::rw- + > group::r-x #effective:r-- + > group:bin:r-x #effective:r-- + > mask::r-- + > other::r-- + > + + $ su bin + $ echo i >> d/f + > d/f: Permission denied + +Changed by CFS: (1). reduce the tree level to 2 (for shortening +time of local tests). (2). add one more lfs lgetfacl test since dir +might be distributed around MDS's. + + $ su + $ rm d/f + $ rmdir d/subdir + $ mv d tree + $ ./make-tree + $ lfs lgetfacl tree/dir0/dir5/file4 + > # file: tree/dir0/dir5/file4 + > # owner: root + > # group: root + > user::rw- + > group::r-x #effective:r-- + > group:bin:r-x #effective:r-- + > mask::r-- + > other::r-- + > + $ lfs lgetfacl tree/dir0/dir6/file4 + > # file: tree/dir0/dir6/file4 + > # owner: root + > # group: root + > user::rw- + > group::r-x #effective:r-- + > group:bin:r-x #effective:r-- + > mask::r-- + > other::r-- + > + $ echo i >> tree/dir6/dir2/file2 + $ echo i > tree/dir1/f + $ lfs ls -l tree/dir1/f | awk -- '{ print $1 }' + > -rw-r--r--+ +in following item, the error message is dependant on distributions. +success on FC3, but not on FC2 and SLES3 etc. comment out by CFS. +# $ su bin +# $ echo i > tree/dir6/dir2/f +# > tree/dir6/dir2/f: No such file or directory +# $ su + + $ rm -rf tree + + +Original scripts, comment out by CFS. +# +# $ su +# $ rm d/f +# $ rmdir d/subdir +# $ mv d tree +# $ ./make-tree +# $ lfs lgetfacl tree/dir0/dir5/dir7/file4 +# > # file: tree/dir0/dir5/dir7/file4 +# > # owner: root +# > # group: root +# > user::rw- +# > group::r-x #effective:r-- +# > group:bin:r-x #effective:r-- +# > mask::r-- +# > other::r-- +# > +# $ echo i >> tree/dir6/dir2/dir1/file2 +# $ echo i > tree/dir1/f +# $ lfs ls -l tree/dir1/f | awk -- '{ print $1 }' +# > -rw-r--r--+ +# $ su bin +# $ echo i > tree/dir6/dir2/f +# > tree/dir6/dir2/f: No such file or directory +# $ su +# +# $ rm -rf tree + + + + diff --git a/lustre/tests/rmtacl/make-tree b/lustre/tests/rmtacl/make-tree new file mode 100755 index 0000000..6ade51d --- /dev/null +++ b/lustre/tests/rmtacl/make-tree @@ -0,0 +1,45 @@ +#!/bin/sh + +# reduce LEVELS from 3 => 2 by CFS +LEVELS=2 ; [ -z "$1" ] || LEVELS=$1 +DIRS=10 ; [ -z "$2" ] || DIRS=$2 +FILES=10 ; [ -z "$2" ] || FILES=$3 +NUMBER_OF_ACLS=50 ; [ -z "$3" ] || NUMBER_OF_ACLS=$4 + +function random_dir() { + mkdir -p $1 + #lfs lsetfacl -s "u::rwx,u:$[($RANDOM % $NUMBER_OF_ACLS)+1000]:rwx,g::rx,o:-" $1 +} + +function random_file() { + touch $1 + #lfs lsetfacl -s "u::rw,u:$[($RANDOM % $NUMBER_OF_ACLS)+1000]:rw,g::r,o:-" $1 +} + +function create () { + local LEVEL=$1 + if [ $LEVEL -eq 0 ]; then + local I=0 + while [ $I -lt $FILES ]; do + random_file file$I + I=$[$I+1] + done + else + local I=0 + while [ $I -lt $DIRS ]; do + random_dir dir$I + cd dir$I + create $[$LEVEL-1] + cd .. + I=$[$I+1] + done + fi + return +} + +mkdir -p tree +cd tree +create $LEVELS +cd .. +exit 0 + diff --git a/lustre/tests/rmtacl/misc.test b/lustre/tests/rmtacl/misc.test new file mode 100644 index 0000000..aa7d7bd --- /dev/null +++ b/lustre/tests/rmtacl/misc.test @@ -0,0 +1,426 @@ +Pretty comprehensive ACL tests. + +This must be run on a filesystem with ACL support. Also, you will need +two dummy users (bin and daemon) and a dummy group (daemon). + + $ umask 027 + $ touch f + +Only change a base ACL: + $ lfs lsetfacl -m u::r f + $ lfs lsetfacl -m u::rw,u:bin:rw f + $ lfs ls -dl f | awk '{print $1}' + > -rw-rw----+ + + $ lfs lgetfacl --omit-header f + > user::rw- + > user:bin:rw- + > group::r-- + > mask::rw- + > other::--- + > + + $ rm f + $ umask 022 + $ touch f + $ lfs lsetfacl -m u:bin:rw f + $ lfs ls -dl f | awk '{print $1}' + > -rw-rw-r--+ + + $ lfs lgetfacl --omit-header f + > user::rw- + > user:bin:rw- + > group::r-- + > mask::rw- + > other::r-- + > + + $rm f + $ umask 027 + $ mkdir d + $ lfs lsetfacl -m u:bin:rwx d + $ lfs ls -dl d | awk '{print $1}' + > drwxrwx---+ + + $ lfs lgetfacl --omit-header d + > user::rwx + > user:bin:rwx + > group::r-x + > mask::rwx + > other::--- + > + + $ rmdir d + $ umask 022 + $ mkdir d + $ lfs lsetfacl -m u:bin:rwx d + $ lfs ls -dl d | awk '{print $1}' + > drwxrwxr-x+ + + $ lfs lgetfacl --omit-header d + > user::rwx + > user:bin:rwx + > group::r-x + > mask::rwx + > other::r-x + > + + $ rmdir d + + +Multiple users + + $ umask 022 + $ touch f + $ lfs lsetfacl -m u:bin:rw,u:daemon:r f + $ lfs ls -dl f | awk '{print $1}' + > -rw-rw-r--+ + + $ lfs lgetfacl --omit-header f + > user::rw- + > user:bin:rw- + > user:daemon:r-- + > group::r-- + > mask::rw- + > other::r-- + > + +Multiple groups + + $ lfs lsetfacl -m g:users:rw,g:daemon:r f + $ lfs ls -dl f | awk '{print $1}' + > -rw-rw-r--+ + + $ lfs lgetfacl --omit-header f + > user::rw- + > user:bin:rw- + > user:daemon:r-- + > group::r-- + > group:daemon:r-- + > group:users:rw- + > mask::rw- + > other::r-- + > + +Remove one group + + $ lfs lsetfacl -x g:users f + $ lfs ls -dl f | awk '{print $1}' + > -rw-rw-r--+ + + $ lfs lgetfacl --omit-header f + > user::rw- + > user:bin:rw- + > user:daemon:r-- + > group::r-- + > group:daemon:r-- + > mask::rw- + > other::r-- + > + +Remove one user + + $ lfs lsetfacl -x u:daemon f + $ lfs ls -dl f | awk '{print $1}' + > -rw-rw-r--+ + + $ lfs lgetfacl --omit-header f + > user::rw- + > user:bin:rw- + > group::r-- + > group:daemon:r-- + > mask::rw- + > other::r-- + > + + $ rm f + +Default ACL + + $ umask 027 + $ mkdir d + $ lfs lsetfacl -m u:bin:rwx,u:daemon:rw,d:u:bin:rwx,d:m:rx d + $ lfs ls -dl d | awk '{print $1}' + > drwxrwx---+ + + $ lfs lgetfacl --omit-header d + > user::rwx + > user:bin:rwx + > user:daemon:rw- + > group::r-x + > mask::rwx + > other::--- + > default:user::rwx + > default:user:bin:rwx #effective:r-x + > default:group::r-x + > default:mask::r-x + > default:other::--- + > + +Umask now ignored? + + $ umask 027 + $ touch d/f + $ lfs ls -dl d/f | awk '{print $1}' + > -rw-r-----+ + + $ lfs lgetfacl --omit-header d/f + > user::rw- + > user:bin:rwx #effective:r-- + > group::r-x #effective:r-- + > mask::r-- + > other::--- + > + + $ rm d/f + $ umask 022 + $ touch d/f + $ lfs ls -dl d/f | awk '{print $1}' + > -rw-r-----+ + + $ lfs lgetfacl --omit-header d/f + > user::rw- + > user:bin:rwx #effective:r-- + > group::r-x #effective:r-- + > mask::r-- + > other::--- + > + + $ rm d/f + +Default ACL copying + + $ umask 000 + $ mkdir d/d + $ lfs ls -dl d/d | awk '{print $1}' + > drwxr-x---+ + + $ lfs lgetfacl --omit-header d/d + > user::rwx + > user:bin:rwx #effective:r-x + > group::r-x + > mask::r-x + > other::--- + > default:user::rwx + > default:user:bin:rwx #effective:r-x + > default:group::r-x + > default:mask::r-x + > default:other::--- + > + + $ rmdir d/d + $ umask 022 + $ mkdir d/d + $ lfs ls -dl d/d | awk '{print $1}' + > drwxr-x---+ + + $ lfs lgetfacl --omit-header d/d + > user::rwx + > user:bin:rwx #effective:r-x + > group::r-x + > mask::r-x + > other::--- + > default:user::rwx + > default:user:bin:rwx #effective:r-x + > default:group::r-x + > default:mask::r-x + > default:other::--- + > + +Add some users and groups + + $ lfs lsetfacl -nm u:daemon:rx,d:u:daemon:rx,g:users:rx,g:daemon:rwx d/d + $ lfs ls -dl d/d | awk '{print $1}' + > drwxr-x---+ + + $ lfs lgetfacl --omit-header d/d + > user::rwx + > user:bin:rwx #effective:r-x + > user:daemon:r-x + > group::r-x + > group:daemon:rwx #effective:r-x + > group:users:r-x + > mask::r-x + > other::--- + > default:user::rwx + > default:user:bin:rwx #effective:r-x + > default:user:daemon:r-x + > default:group::r-x + > default:mask::r-x + > default:other::--- + > + +Symlink in directory with default ACL? + + $ ln -s d d/l + $ lfs ls -dl d/l | awk '{print $1}' + > lrwxrwxrwx + + $ lfs ls -dl -L d/l | awk '{print $1}' + > drwxr-x---+ + + $ lfs lgetfacl --omit-header d/l + > user::rwx + > user:bin:rwx #effective:r-x + > user:daemon:r-x + > group::r-x + > group:daemon:rwx #effective:r-x + > group:users:r-x + > mask::r-x + > other::--- + > default:user::rwx + > default:user:bin:rwx #effective:r-x + > default:user:daemon:r-x + > default:group::r-x + > default:mask::r-x + > default:other::--- + > + + $ rm d/l + +Does mask manipulation work? + + $ lfs lsetfacl -m g:daemon:rx,u:bin:rx d/d + $ lfs ls -dl d/d | awk '{print $1}' + > drwxr-x---+ + + $ lfs lgetfacl --omit-header d/d + > user::rwx + > user:bin:r-x + > user:daemon:r-x + > group::r-x + > group:daemon:r-x + > group:users:r-x + > mask::r-x + > other::--- + > default:user::rwx + > default:user:bin:rwx #effective:r-x + > default:user:daemon:r-x + > default:group::r-x + > default:mask::r-x + > default:other::--- + > + + $ lfs lsetfacl -m d:u:bin:rwx d/d + $ lfs ls -dl d/d | awk '{print $1}' + > drwxr-x---+ + + $ lfs lgetfacl --omit-header d/d + > user::rwx + > user:bin:r-x + > user:daemon:r-x + > group::r-x + > group:daemon:r-x + > group:users:r-x + > mask::r-x + > other::--- + > default:user::rwx + > default:user:bin:rwx + > default:user:daemon:r-x + > default:group::r-x + > default:mask::rwx + > default:other::--- + > + + $ rmdir d/d + +Remove the default ACL + + $ lfs lsetfacl -k d + $ lfs ls -dl d | awk '{print $1}' + > drwxrwx---+ + + $ lfs lgetfacl --omit-header d + > user::rwx + > user:bin:rwx + > user:daemon:rw- + > group::r-x + > mask::rwx + > other::--- + > + +Reset to base entries + + $ lfs lsetfacl -b d + $ lfs ls -dl d | awk '{print $1}' + > drwxr-x--- + + $ lfs lgetfacl --omit-header d + > user::rwx + > group::r-x + > other::--- + > + +Now, chmod should change the group_obj entry + + $ chmod 775 d + $ lfs ls -dl d | awk '{print $1}' + > drwxrwxr-x + + $ lfs lgetfacl --omit-header d + > user::rwx + > group::rwx + > other::r-x + > + + $ rmdir d + $ umask 002 + $ mkdir d + $ lfs lsetfacl -m u:daemon:rwx,u:bin:rx,d:u:daemon:rwx,d:u:bin:rx d + $ lfs ls -dl d | awk '{print $1}' + > drwxrwxr-x+ + + $ lfs lgetfacl --omit-header d + > user::rwx + > user:bin:r-x + > user:daemon:rwx + > group::rwx + > mask::rwx + > other::r-x + > default:user::rwx + > default:user:bin:r-x + > default:user:daemon:rwx + > default:group::rwx + > default:mask::rwx + > default:other::r-x + > + + $ chmod 750 d + $ lfs ls -dl d | awk '{print $1}' + > drwxr-x---+ + + $ lfs lgetfacl --omit-header d + > user::rwx + > user:bin:r-x + > user:daemon:rwx #effective:r-x + > group::rwx #effective:r-x + > mask::r-x + > other::--- + > default:user::rwx + > default:user:bin:r-x + > default:user:daemon:rwx + > default:group::rwx + > default:mask::rwx + > default:other::r-x + > + + $ chmod 750 d + $ lfs ls -dl d | awk '{print $1}' + > drwxr-x---+ + + $ lfs lgetfacl --omit-header d + > user::rwx + > user:bin:r-x + > user:daemon:rwx #effective:r-x + > group::rwx #effective:r-x + > mask::r-x + > other::--- + > default:user::rwx + > default:user:bin:r-x + > default:user:daemon:rwx + > default:group::rwx + > default:mask::rwx + > default:other::r-x + > + + $ rmdir d diff --git a/lustre/tests/rmtacl/permissions.test b/lustre/tests/rmtacl/permissions.test new file mode 100644 index 0000000..b7cb587 --- /dev/null +++ b/lustre/tests/rmtacl/permissions.test @@ -0,0 +1,284 @@ +This script tests if file permissions are properly checked with and +without ACLs. The script must be run as root to allow switching users. +The following users are required. They must be a member in the groups +listed in parentheses. + + bin (bin) + daemon (bin, daemon) + + +Cry immediately if we are not running as root. + + $ id -u + > 0 + + +First, set up a temporary directory and create a regular file with +defined permissions. + + $ mkdir d + $ cd d + $ umask 027 + $ touch f + $ lfs ls -l f | awk -- '{ print $1, $3, $4 }' + > -rw-r----- root root + + +Make sure root has access to the file. Verify that user daemon does not +have access to the file owned by root. + + $ echo root > f + + $ su daemon + $ echo daemon >> f + > f: Permission denied + + $ su + + +Now, change the ownership of the file to bin:bin and verify that this +gives user bin write access. + + $ chown bin:bin f + $ lfs ls -l f | awk -- '{ print $1, $3, $4 }' + > -rw-r----- bin bin + $ su bin + $ echo bin >> f + + +User daemon is a member in the owning group, which has only read access. +Verify this. + + $ su daemon + $ cat f + > root + > bin + + $ echo daemon >> f + > f: Permission denied + + +Now, add an ACL entry for user daemon that grants him rw- access. File +owners and users capable of CAP_FOWNER are allowed to change ACLs. + + $ su bin + $ lfs lsetfacl -m u:daemon:rw f + $ lfs lgetfacl --omit-header f + > user::rw- + > user:daemon:rw- + > group::r-- + > mask::rw- + > other::--- + > + + +Verify that the additional ACL entry grants user daemon write access. + + $ su daemon + $ echo daemon >> f + $ cat f + > root + > bin + > daemon + + +Remove write access from the group class permission bits, and +verify that this masks daemon's write permission. + + $ su bin + $ chmod g-w f + $ lfs lgetfacl --omit-header f + > user::rw- + > user:daemon:rw- #effective:r-- + > group::r-- + > mask::r-- + > other::--- + > + + $ su daemon + $ echo daemon >> f + > f: Permission denied + + +Add an entry for group daemon with rw- access, and change the +permissions for user daemon to r--. Also change the others permissions t +rw-. The user entry should take precedence, so daemon should be denied +access. + + $ su bin + $ lfs lsetfacl -m u:daemon:r,g:daemon:rw-,o::rw- f + + $ su daemon + $ echo daemon >> f + > f: Permission denied + + +Remove the entry for user daemon. The group daemon permissions should +now give user daemon rw- access. + + $ su bin + $ lfs lsetfacl -x u:daemon f + + $ su daemon + $ echo daemon2 >> f + $ cat f + > root + > bin + > daemon + > daemon2 + + +Set the group daemon permissions to r-- and verify that after than, user +daemon does not have write access anymore. + + $ su bin + $ lfs lsetfacl -m g:daemon:r f + + $ su daemon + $ echo daemon3 >> f + > f: Permission denied + + +Now, remove the group daemon entry. Because user daemon is a member in +the owning group, he should still have no write access. + + $ su bin + $ lfs lsetfacl -x g:daemon f + + $ su daemon + $ echo daemon4 >> f + > f: Permission denied + + +Change the owning group. The other permissions should now grant user +daemon write access. + + $ su + $ chgrp root f + + $ su daemon + $ echo daemon5 >> f + $ cat f + > root + > bin + > daemon + > daemon2 + > daemon5 + + +Verify that permissions in separate matching ACL entries do not +accumulate. + + $ su + $ lfs lsetfacl -m g:bin:r,g:daemon:w f + + $ su daemon + $ : < f # open for reading + $ : > f # open for writing + $ : <> f # open for read-write + > f: Permission denied + + +Test if directories can have ACLs. We assume that only one access check +algorithm is used for all file types the file system, so these tests +only need to verify that ACL permissions make a difference. + + $ su + $ mkdir -m 750 e + $ touch e/h + + $ su bin + $ shopt -s nullglob ; echo e/* + > + + $ echo i > e/i + > e/i: Permission denied + + $ su + $ lfs lsetfacl -m u:bin:rx e + + $ su bin + $ echo e/* + > e/h +following 2 lines seems not valid, which also failed on ext3 in FC3 enviroment, +although it pass in FC2. commented out by CFS (agreed with HP) +Replaced "echo" with "touch" can resolve such problem. +# $ echo i > e/i +# > e/i: Permission denied + $ touch e/i + > touch: cannot touch `e/i': Permission denied + + $ su + $ lfs lsetfacl -m u:bin:rwx e + + $ su bin + $ echo i > e/i + + +Test if symlinks are properly followed. + + $ su + $ touch g + $ ln -s g l + $ lfs lsetfacl -m u:bin:rw l + $ lfs ls -l g | awk -- '{ print $1, $3, $4 }' + > -rw-rw----+ root root + + +Test if ACLs are effective for block and character special files, fifos, +sockets. This is done by creating special files locally. The devices do +not need to exist: The access check is earlier in the code path than the +test if the device exists. + + + $ mknod -m 0660 hdt b 91 64 # /dev/hdt + $ mknod -m 0660 null c 1 3 # /dev/null + $ mkfifo -m 0660 fifo + + $ su bin + $ : < hdt + > hdt: Permission denied + $ : < null + > null: Permission denied + $ : < fifo + > fifo: Permission denied + + $ su + $ lfs lsetfacl -m u:bin:rw hdt null fifo + + $ su bin + $ : < hdt + > hdt: No such device or address + $ : < null + $ ( echo blah > fifo & ) ; cat fifo + > blah + + +Test if CAP_FOWNER is properly honored for directories. This addresses a +specific bug in XFS 1.2, which does not grant root access to files in +directories if the file has an ACL and only CAP_FOWNER would grant them. + + $ su + $ mkdir -m 600 x + $ chown daemon:daemon x + $ echo j > x/j + $ lfs ls -l x/j | awk -- '{ print $1, $3, $4 }' + > -rw-r----- root root + + $ lfs lsetfacl -m u:daemon:r x + + $ lfs ls -l x/j | awk -- '{ print $1, $3, $4 }' + > -rw-r----- root root + (With the bug this gives: `ls: x/j: Permission denied'.) + + $ echo k > x/k + (With the bug this gives: `x/k: Permission denied'.) + + $ chmod 750 x + + +Clean up. + + $ su + $ cd .. + $ rm -rf d diff --git a/lustre/tests/rmtacl/run b/lustre/tests/rmtacl/run new file mode 100755 index 0000000..cfc8c05 --- /dev/null +++ b/lustre/tests/rmtacl/run @@ -0,0 +1,275 @@ +#!/usr/bin/perl -w -U + +# +# Possible improvements: +# +# - distinguish stdout and stderr output +# - add environment variable like assignments +# - run up to a specific line +# - resume at a specific line +# + +use strict; +use FileHandle; +use Getopt::Std; +use POSIX qw(isatty setuid); +use vars qw($opt_v); + +no warnings qw(taint); + +getopts('v'); + +my ($OK, $FAILED) = ("ok", "failed"); +if (isatty(fileno(STDOUT))) { + $OK = "\033[32m" . $OK . "\033[m"; + $FAILED = "\033[31m\033[1m" . $FAILED . "\033[m"; +} + +sub exec_test($$); +sub process_test($$$$); + +my ($prog, $in, $out) = ([], [], []); +my $line_number = 0; +my $prog_line; +my ($tests, $failed) = (0,0); + +for (;;) { + my $line = <>; $line_number++; + if (defined $line) { + # Substitute %VAR and %{VAR} with environment variables. + $line =~ s[%(?:(\w+)|\{(\w+)\})][$ENV{"$1$2"}]eg; + } + if (defined $line) { + if ($line =~ s/^\s*< ?//) { + push @$in, $line; + } elsif ($line =~ s/^\s*> ?//) { + push @$out, $line; + } else { + process_test($prog, $prog_line, $in, $out); + + $prog = []; + $prog_line = 0; + } + if ($line =~ s/^\s*\$ ?//) { + $line =~ s/\s+#.*//; # remove comments here... + $prog = [ map { s/\\(.)/$1/g; $_ } split /(? @$result) ? @$out : @$result; + for (my $n=0; $n < $nmax; $n++) { + if (!defined($out->[$n]) || !defined($result->[$n]) || + $out->[$n] ne $result->[$n]) { + $good = 0; + } + } + $tests++; + $failed++ unless $good; + print $good ? $OK : $FAILED, "\n"; + if (!$good) { + for (my $n=0; $n < $nmax; $n++) { + my $l = defined($out->[$n]) ? $out->[$n] : "~"; + chomp $l; + my $r = defined($result->[$n]) ? $result->[$n] : "~"; + chomp $r; + print sprintf("%-37s %s %-39s\n", $l, $l eq $r ? "|" : "?", $r); + } + } elsif ($opt_v) { + print join('', @$result); + } +} + + +sub su($) { + my ($user) = @_; + + $user ||= "root"; + + my ($login, $pass, $uid, $gid) = getpwnam($user) + or return [ "su: user $user does not exist\n" ]; + my @groups = (); + my $fh = new FileHandle("/etc/group") + or return [ "opening /etc/group: $!\n" ]; + while (<$fh>) { + chomp; + my ($group, $passwd, $gid, $users) = split /:/; + foreach my $u (split /,/, $users) { + push @groups, $gid + if ($user eq $u); + } + } + $fh->close; + + my $groups = join(" ", ($gid, $gid, @groups)); + #print STDERR "[[$groups]]\n"; + $! = 0; # reset errno + $> = 0; + $( = $gid; + $) = $groups; + if ($!) { + return [ "su: $!\n" ]; + } + if ($uid != 0) { + $> = $uid; + #$< = $uid; + if ($!) { + return [ "su: $prog->[1]: $!\n" ]; + } + } + #print STDERR "[($>,$<)($(,$))]"; + return []; +} + + +sub sg($) { + my ($group) = @_; + + my $gid = getgrnam($group) + or return [ "sg: group $group does not exist\n" ]; + my %groups = map { $_ eq $gid ? () : ($_ => 1) } (split /\s/, $)); + + #print STDERR "<<", join("/", keys %groups), ">>\n"; + my $groups = join(" ", ($gid, $gid, keys %groups)); + #print STDERR "[[$groups]]\n"; + $! = 0; # reset errno + if ($> != 0) { + my $uid = $>; + $> = 0; + $( = $gid; + $) = $groups; + $> = $uid; + } else { + $( = $gid; + $) = $groups; + } + if ($!) { + return [ "sg: $!\n" ]; + } + print STDERR "[($>,$<)($(,$))]"; + return []; +} + + +sub exec_test($$) { + my ($prog, $in) = @_; + local (*IN, *IN_DUP, *IN2, *OUT_DUP, *OUT, *OUT2); + my $needs_shell = (join('', @$prog) =~ /[][|<>"'`\$\*\?]/); + + if ($prog->[0] eq "umask") { + umask oct $prog->[1]; + return []; + } elsif ($prog->[0] eq "cd") { + if (!chdir $prog->[1]) { + return [ "chdir: $prog->[1]: $!\n" ]; + } + return []; + } elsif ($prog->[0] eq "su") { + return su($prog->[1]); + } elsif ($prog->[0] eq "sg") { + return sg($prog->[1]); + } + + pipe *IN2, *OUT + or die "Can't create pipe for reading: $!"; + open *IN_DUP, "<&STDIN" + or *IN_DUP = undef; + open *STDIN, "<&IN2" + or die "Can't duplicate pipe for reading: $!"; + close *IN2; + + open *OUT_DUP, ">&STDOUT" + or die "Can't duplicate STDOUT: $!"; + pipe *IN, *OUT2 + or die "Can't create pipe for writing: $!"; + open *STDOUT, ">&OUT2" + or die "Can't duplicate pipe for writing: $!"; + close *OUT2; + + *STDOUT->autoflush(); + *OUT->autoflush(); + + if (fork()) { + # Server + if (*IN_DUP) { + open *STDIN, "<&IN_DUP" + or die "Can't duplicate STDIN: $!"; + close *IN_DUP + or die "Can't close STDIN duplicate: $!"; + } + open *STDOUT, ">&OUT_DUP" + or die "Can't duplicate STDOUT: $!"; + close *OUT_DUP + or die "Can't close STDOUT duplicate: $!"; + + foreach my $line (@$in) { + #print "> $line"; + print OUT $line; + } + close *OUT + or die "Can't close pipe for writing: $!"; + + my $result = []; + while () { + #print "< $_"; + if ($needs_shell) { + s#^/bin/sh: line \d+: ##; + s#^/bin/sh: ##; # temporarily added by ericm + } + push @$result, $_; + } + return $result; + } else { + # Client + $< = $>; + close IN + or die "Can't close read end for input pipe: $!"; + close OUT + or die "Can't close write end for output pipe: $!"; + close OUT_DUP + or die "Can't close STDOUT duplicate: $!"; + local *ERR_DUP; + open ERR_DUP, ">&STDERR" + or die "Can't duplicate STDERR: $!"; + open STDERR, ">&STDOUT" + or die "Can't join STDOUT and STDERR: $!"; + + if ($needs_shell) { + exec ('/bin/sh', '-c', join(" ", @$prog)); + } else { + exec @$prog; + } + print STDERR $prog->[0], ": $!\n"; + exit; + } +} + diff --git a/lustre/tests/rmtacl/setfacl.test b/lustre/tests/rmtacl/setfacl.test new file mode 100644 index 0000000..14c473a --- /dev/null +++ b/lustre/tests/rmtacl/setfacl.test @@ -0,0 +1,144 @@ +Setfacl utility tests. Run these tests on a filesystem with ACL support. + + $ mkdir d + $ chown bin:bin d + $ cd d + + $ su bin + $ sg bin + $ umask 027 + $ touch g + $ lfs ls -dl g | awk '{print $1}' + > -rw-r----- + + $ lfs lsetfacl -m m:- g + $ lfs ls -dl g | awk '{print $1}' + > -rw-------+ + + $ lfs lgetfacl g + > # file: g + > # owner: bin + > # group: bin + > user::rw- + > group::r-- #effective:--- + > mask::--- + > other::--- + > + + $ lfs lsetfacl -x m g + $ lfs lgetfacl g + > # file: g + > # owner: bin + > # group: bin + > user::rw- + > group::r-- + > other::--- + > + + $ lfs lsetfacl -m u:daemon:rw g + $ lfs lgetfacl g + > # file: g + > # owner: bin + > # group: bin + > user::rw- + > user:daemon:rw- + > group::r-- + > mask::rw- + > other::--- + > + + $ lfs lsetfacl -m u::rwx,g::r-x,o:- g + $ lfs lgetfacl g + > # file: g + > # owner: bin + > # group: bin + > user::rwx + > user:daemon:rw- + > group::r-x + > mask::rwx + > other::--- + > + + $ lfs lsetfacl -m u::rwx,g::r-x,o:-,m:- g + $ lfs lgetfacl g + > # file: g + > # owner: bin + > # group: bin + > user::rwx + > user:daemon:rw- #effective:--- + > group::r-x #effective:--- + > mask::--- + > other::--- + > + + $ lfs lsetfacl -m u::rwx,g::r-x,o:-,u:root:-,m:- g + $ lfs lgetfacl g + > # file: g + > # owner: bin + > # group: bin + > user::rwx + > user:root:--- + > user:daemon:rw- #effective:--- + > group::r-x #effective:--- + > mask::--- + > other::--- + > + + $ lfs lsetfacl -m u::rwx,g::r-x,o:-,u:root:-,m:- g + $ lfs lgetfacl g + > # file: g + > # owner: bin + > # group: bin + > user::rwx + > user:root:--- + > user:daemon:rw- #effective:--- + > group::r-x #effective:--- + > mask::--- + > other::--- + > + + $ lfs lsetfacl -m u::rwx,g::r-x,o:-,u:root:- g + $ lfs lgetfacl g + > # file: g + > # owner: bin + > # group: bin + > user::rwx + > user:root:--- + > user:daemon:rw- + > group::r-x + > mask::rwx + > other::--- + > + + $ lfs lsetfacl --test -x u: g + > setfacl: g: Malformed access ACL `user:root:---,user:daemon:rw-,group::r-x,mask::rwx,other::---': Missing or wrong entry at entry 1 + + $ lfs lsetfacl --test -x u:x + > setfacl: Option -x: Invalid argument near character 3 + + $ lfs lsetfacl -m d:u:root:rwx g + > setfacl: g: Only directories can have default ACLs + + $ lfs lsetfacl -x m g + > setfacl: g: Malformed access ACL `user::rwx,user:root:---,user:daemon:rw-,group::r-x,other::---': Missing or wrong entry at entry 5 + lfs lsetfacl --test -m d:u:daemon:rwx lfs lsetfacl + lfs lsetfacl --test -n -m d:u:daemon:rwx lfs lsetfacl + +Check if the mask is properly recalculated + + $ mkdir d + $ lfs lsetfacl --test -m u::rwx,u:bin:rwx,g::r-x,o::--- d + > d: u::rwx,u:bin:rwx,g::r-x,m::rwx,o::---,* + + $ lfs lsetfacl --test -m u::rwx,u:bin:rwx,g::r-x,m::---,o::--- d + > d: u::rwx,u:bin:rwx,g::r-x,m::---,o::---,* + + $ lfs lsetfacl --test -d -m u::rwx,u:bin:rwx,g::r-x,o::--- d + > d: *,d:u::rwx,d:u:bin:rwx,d:g::r-x,d:m::rwx,d:o::--- + + $ lfs lsetfacl --test -d -m u::rwx,u:bin:rwx,g::r-x,m::---,o::--- d + > d: *,d:u::rwx,d:u:bin:rwx,d:g::r-x,d:m::---,d:o::--- + + $ su + $ cd .. + $ rm -r d diff --git a/lustre/tests/sanity-gss.sh b/lustre/tests/sanity-gss.sh index 4e3111a..69d23c7 100644 --- a/lustre/tests/sanity-gss.sh +++ b/lustre/tests/sanity-gss.sh @@ -9,15 +9,12 @@ set -e ONLY=${ONLY:-"$*"} # bug number for skipped test: -ALWAYS_EXCEPT=${ALWAYS_EXCEPT:-""} +ALWAYS_EXCEPT=${ALWAYS_EXCEPT:-"$SANITY_GSS_EXCEPT"} # UPDATE THE COMMENT ABOVE WITH BUG NUMBERS WHEN CHANGING ALWAYS_EXCEPT! -if [ "x$GSS_PIPEFS" != "xy" ]; then - ALWAYS_EXCEPT="$ALWAYS_EXCEPT 4" -fi -[ "$SLOW" = "no" ] && EXCEPT="$EXCEPT" +[ "$SLOW" = "no" ] && EXCEPT_SLOW="100 101" -# Tests that fail on uml, maybe elsewhere, FIXME +# Tests that fail on uml CPU=`awk '/model/ {print $4}' /proc/cpuinfo` [ "$CPU" = "UML" ] && EXCEPT="$EXCEPT" @@ -28,17 +25,16 @@ esac SRCDIR=`dirname $0` export PATH=$PWD/$SRCDIR:$SRCDIR:$SRCDIR/../utils:$SRCDIR/../utils/gss:$PATH:/sbin +export NAME=${NAME:-local} +SAVE_PWD=$PWD -TMP=${TMP:-/tmp} +CLEANUP=${CLEANUP:-""} +SETUP=${SETUP:-""} -CHECKSTAT=${CHECKSTAT:-"checkstat -v"} -CREATETEST=${CREATETEST:-createtest} -LFS=${LFS:-lfs} -LCTL=${LCTL:-lctl} -MEMHOG=${MEMHOG:-memhog} -DIRECTIO=${DIRECTIO:-directio} -ACCEPTOR_PORT=${ACCEPTOR_PORT:-988} -UMOUNT=${UMOUNT:-"umount -d"} +LUSTRE=${LUSTRE:-`dirname $0`/..} +. $LUSTRE/tests/test-framework.sh +init_test_env $@ +. ${CONFIG:=$LUSTRE/tests/cfg/$NAME.sh} if [ $UID -ne 0 ]; then echo "Warning: running as non-root uid $UID" @@ -49,96 +45,315 @@ else RUNAS=${RUNAS:-"runas -u $RUNAS_ID"} # $RUNAS_ID may get set incorrectly somewhere else - if [ $RUNAS_ID -eq 0 ]; then - echo "Error: \$RUNAS_ID set to 0, but \$UID is also 0!" - exit 1 - fi + [ $RUNAS_ID -eq 0 ] && error "\$RUNAS_ID set to 0, but \$UID is also 0!" fi -SANITYLOG=${SANITYLOG:-/tmp/sanity-gss.log} - -export NAME=${NAME:-local} - -SAVE_PWD=$PWD - -export SEC=${SEC:-krb5p} -export KRB5_CCACHE_DIR=/tmp -export KRB5_CRED=$KRB5_CCACHE_DIR/krb5cc_$RUNAS_ID -export KRB5_CRED_SAVE=$KRB5_CCACHE_DIR/krb5cc.sanity.save +# remove $SEC, we'd like to control everything by ourselves +unset SEC # -# check pre-set $SEC +# global variables of this sanity # -case "x$SEC" in - xkrb5*) - echo "Using ptlrpc security flavor $SEC" - ;; - *) - echo "SEC=$SEC is invalid, it has to be gss/krb5 flavor" - exit 1 - ;; -esac +KRB5_CCACHE_DIR=/tmp +KRB5_CRED=$KRB5_CCACHE_DIR/krb5cc_$RUNAS_ID +KRB5_CRED_SAVE=$KRB5_CCACHE_DIR/krb5cc.sanity.save +CLICOUNT=2 +cnt_mdt2ost=0 +cnt_mdt2mdt=0 +cnt_cli2ost=0 +cnt_cli2mdt=0 +cnt_all2ost=0 +cnt_all2mdt=0 +cnt_all2all=0 +DBENCH_PID=0 +PROC_CLI="srpc.info" + +# set manually +GSS=true +GSS_KRB5=true + +# we want double mount +MOUNT_2=${MOUNT_2:-"yes"} +cleanup_and_setup_lustre + +rm -rf $DIR/${TESTSUITE}/[df][0-9]* +rm -rf $DIR/[df][0-9]* + +check_runas_id $RUNAS_ID $RUNAS -LUSTRE=${LUSTRE:-`dirname $0`/..} -. $LUSTRE/tests/test-framework.sh -init_test_env $@ -. ${CONFIG:=$LUSTRE/tests/cfg/local.sh} +build_test_filter prepare_krb5_creds() { - rm -f $CRED_SAVE + rm -f $KRB5_CRED_SAVE $RUNAS krb5_login.sh || exit 1 [ -f $KRB5_CRED ] || exit 2 cp $KRB5_CRED $KRB5_CRED_SAVE } -cleanup() { - echo -n "cln.." - cleanupall ${FORCE} $* || { echo "FAILed to clean up"; exit 20; } +combination() +{ + local M=$1 + local N=$2 + local R=1 + + if [ $M -lt $N ]; then + R=0 + else + N=$((N + 1)) + while [ $N -le $M ]; do + R=$((R * N)) + N=$((N + 1)) + done + fi + + echo $R + return 0 } -CLEANUP=${CLEANUP:-:} -setup() { - echo -n "mnt.." - load_modules - setupall || exit 10 - echo "done" +calc_connection_cnt() { + # MDT->MDT = 2 * C(M, 2) + # MDT->OST = M * O + # CLI->OST = C * O + # CLI->MDT = C * M + comb_m2=$(combination $MDSCOUNT 2) + + cnt_mdt2mdt=$((comb_m2 * 2)) + cnt_mdt2ost=$((MDSCOUNT * OSTCOUNT)) + cnt_cli2ost=$((CLICOUNT * OSTCOUNT)) + cnt_cli2mdt=$((CLICOUNT * MDSCOUNT)) + cnt_all2ost=$((cnt_mdt2ost + cnt_cli2ost)) + cnt_all2mdt=$((cnt_mdt2mdt + cnt_cli2mdt)) + cnt_all2all=$((cnt_mdt2ost + cnt_mdt2mdt + cnt_cli2ost + cnt_cli2mdt)) } -SETUP=${SETUP:-:} -trace() { - log "STARTING: $*" - strace -o $TMP/$1.strace -ttt $* - RC=$? - log "FINISHED: $*: rc $RC" - return 1 +set_rule() +{ + local tgt=$1 + local net=$2 + local dir=$3 + local flavor=$4 + local cmd="$tgt.srpc.flavor" + + if [ $net == "any" ]; then + net="default" + fi + cmd="$cmd.$net" + + if [ $dir != "any" ]; then + cmd="$cmd.$dir" + fi + + cmd="$cmd=$flavor" + log "Setting sptlrpc rule: $cmd" + do_facet mgs "$LCTL conf_param $cmd" +} + +count_flvr() +{ + output=$1 + flavor=$2 + + echo "$output" | grep rpc | grep $flavor | wc -l } -TRACE=${TRACE:-""} -check_kernel_version() { - VERSION_FILE=$LPROC/kernel_version - WANT_VER=$1 - [ ! -f $VERSION_FILE ] && echo "can't find kernel version" && return 1 - GOT_VER=`cat $VERSION_FILE` - [ $GOT_VER -ge $WANT_VER ] && return 0 - log "test needs at least kernel version $WANT_VER, running $GOT_VER" +flvr_cnt_cli2mdt() +{ + local flavor=$1 + + output=`do_facet client cat $LPROC/mdc/*-MDT*-mdc-*/$PROC_CLI 2>/dev/null` + count_flvr "$output" $flavor +} + +flvr_cnt_cli2ost() +{ + local flavor=$1 + + output=`do_facet client cat $LPROC/osc/*OST*-osc-[^M][^D][^T]*/$PROC_CLI 2>/dev/null` + count_flvr "$output" $flavor +} + +flvr_cnt_mdt2mdt() +{ + local flavor=$1 + local cnt=0 + + if [ $MDSCOUNT -le 1 ]; then + echo 0 + return + fi + + for num in `seq $MDSCOUNT`; do + output=`do_facet mds$num cat $LPROC/mdc/*-MDT*-mdc[0-9]*/$PROC_CLI 2>/dev/null` + tmpcnt=`count_flvr "$output" $flavor` + cnt=$((cnt + tmpcnt)) + done + echo $cnt; +} + +flvr_cnt_mdt2ost() +{ + local flavor=$1 + local cnt=0 + + for num in `seq $MDSCOUNT`; do + output=`do_facet mds$num cat $LPROC/osc/*OST*-osc-MDT*/$PROC_CLI 2>/dev/null` + tmpcnt=`count_flvr "$output" $flavor` + cnt=$((cnt + tmpcnt)) + done + echo $cnt; +} + +do_check_flavor() +{ + local dir=$1 # from to + local flavor=$2 # flavor expected + local res=0 + + if [ $dir == "cli2mdt" ]; then + res=`flvr_cnt_cli2mdt $flavor` + elif [ $dir == "cli2ost" ]; then + res=`flvr_cnt_cli2ost $flavor` + elif [ $dir == "mdt2mdt" ]; then + res=`flvr_cnt_mdt2mdt $flavor` + elif [ $dir == "mdt2ost" ]; then + res=`flvr_cnt_mdt2ost $flavor` + elif [ $dir == "all2ost" ]; then + res1=`flvr_cnt_mdt2ost $flavor` + res2=`flvr_cnt_cli2ost $flavor` + res=$((res1 + res2)) + elif [ $dir == "all2mdt" ]; then + res1=`flvr_cnt_mdt2mdt $flavor` + res2=`flvr_cnt_cli2mdt $flavor` + res=$((res1 + res2)) + elif [ $dir == "all2all" ]; then + res1=`flvr_cnt_mdt2ost $flavor` + res2=`flvr_cnt_cli2ost $flavor` + res3=`flvr_cnt_mdt2mdt $flavor` + res4=`flvr_cnt_cli2mdt $flavor` + res=$((res1 + res2 + res3 + res4)) + fi + + echo $res +} + +wait_flavor() +{ + local dir=$1 # from to + local flavor=$2 # flavor expected + local expect=$3 # number expected + local res=0 + + for ((i=0;i<20;i++)); do + echo -n "checking..." + res=$(do_check_flavor $dir $flavor) + if [ $res -eq $expect ]; then + echo "found $res $flavor connections of $dir, OK" + return 0 + else + echo "found $res $flavor connections of $dir, not ready ($expect)" + sleep 4 + fi + done + + echo "Error checking $flavor of $dir: expect $expect, actual $res" return 1 } -_basetest() { - echo $* +restore_to_default_flavor() +{ + local proc=$LPROC/mgs/MGS/live/$FSNAME + + echo "restoring to default flavor..." + + nrule=`do_facet mgs cat $proc 2>/dev/null | grep "$FSNAME.srpc.flavor." | wc -l` + + # remove all existing rules if any + if [ $nrule -ne 0 ]; then + echo "remove existing $nrule rules" + for rule in `do_facet mgs cat $proc 2>/dev/null | grep "$FSNAME.srpc.flavor."`; do + spec=`echo $rule | awk -F = '{print $1}'` + do_facet mgs "$LCTL conf_param $spec=" + done + fi + + # verify no rules left + nrule=`do_facet mgs cat $proc 2>/dev/null | grep "$FSNAME.srpc.flavor." | wc -l` + [ $nrule -ne 0 ] && error "still $nrule rules left" + + # wait for default flavor to be applied + # currently default flavor for all connections are 'null' + wait_flavor all2all null $cnt_all2all + echo "now at default flavor settings" } -[ "$SANITYLOG" ] && rm -f $SANITYLOG || true +set_flavor_all() +{ + local flavor=$1 + echo "setting all flavor to $flavor" -prepare_krb5_creds -build_test_filter -umask 077 + res=$(do_check_flavor all2all $flavor) + if [ $res -eq $cnt_all2all ]; then + echo "already have total $res $flavor connections" + return + fi -# setup filesystem -formatall -setupall -chmod a+rwx $MOUNT + echo "found $res $flavor out of total $cnt_all2all connections" + restore_to_default_flavor + + set_rule $FSNAME any any $flavor + wait_flavor all2all $flavor $cnt_all2all +} + +start_dbench() +{ + NPROC=`cat /proc/cpuinfo 2>/dev/null | grep ^processor | wc -l` + [ $NPROC -lt 2 ] && NPROC=2 + sh rundbench $NPROC 1>/dev/null & + DBENCH_PID=$! + sleep 2 + + num=`ps --no-headers -p $DBENCH_PID 2>/dev/null | wc -l` + if [ $num -ne 1 ]; then + error "failed to start dbench $NPROC" + else + echo "started dbench with $NPROC processes at background" + fi + + return 0 +} + +check_dbench() +{ + num=`ps --no-headers -p $DBENCH_PID 2>/dev/null | wc -l` + if [ $num -eq 0 ]; then + echo "dbench $DBENCH_PID already finished" + wait $DBENCH_PID || error "dbench $PID exit with error" + start_dbench + elif [ $num -ne 1 ]; then + killall -9 dbench + error "found $num instance of pid $DBENCH_PID ???" + fi + + return 0 +} + +stop_dbench() +{ + for ((;;)); do + killall dbench 2>/dev/null + num=`ps --no-headers -p $DBENCH_PID | wc -l` + if [ $num -eq 0 ]; then + echo "dbench finished" + break + fi + echo "dbench $DBENCH_PID is still running, waiting 2s..." + sleep 2 + done + + wait $DBENCH_PID || true + sync || true +} restore_krb5_cred() { cp $KRB5_CRED_SAVE $KRB5_CRED @@ -146,37 +361,102 @@ restore_krb5_cred() { chmod 0600 $KRB5_CRED } +check_multiple_gss_daemons() { + local facet=$1 + local gssd=$2 + local gssd_name=`basename $gssd` + + for ((i=0;i<10;i++)); do + do_facet $facet "$gssd -v &" + done + + # wait daemons entering "stable" status + sleep 5 + + num=`do_facet $facet ps -o cmd -C $gssd_name | grep $gssd_name | wc -l` + echo "$num instance(s) of $gssd_name are running" + + if [ $num -ne 1 ]; then + error "$gssd_name not unique" + fi +} + +prepare_krb5_creds +calc_connection_cnt +umask 077 + +test_0() { + local my_facet=mds + + echo "bring up gss daemons..." + start_gss_daemons + + echo "check with someone already running..." + check_multiple_gss_daemons $my_facet $LSVCGSSD + if $GSS_PIPEFS; then + check_multiple_gss_daemons $my_facet $LGSSD + fi + + echo "check with someone run & finished..." + do_facet $my_facet killall -q -2 lgssd lsvcgssd || true + sleep 5 # wait fully exit + check_multiple_gss_daemons $my_facet $LSVCGSSD + if $GSS_PIPEFS; then + check_multiple_gss_daemons $my_facet $LGSSD + fi + + echo "check refresh..." + do_facet $my_facet killall -q -2 lgssd lsvcgssd || true + sleep 5 # wait fully exit + do_facet $my_facet ipcrm -S 0x3b92d473 + check_multiple_gss_daemons $my_facet $LSVCGSSD + if $GSS_PIPEFS; then + do_facet $my_facet ipcrm -S 0x3a92d473 + check_multiple_gss_daemons $my_facet $LGSSD + fi +} +run_test 0 "start multiple gss daemons" + +set_flavor_all krb5p + test_1() { + local file=$DIR/$tfile + + chmod 0777 $DIR || error "chmod $DIR failed" # access w/o cred $RUNAS kdestroy - $RUNAS touch $MOUNT/f1 && error "unexpected success" + $RUNAS touch $file && error "unexpected success" # access w/ cred restore_krb5_cred - $RUNAS touch $MOUNT/f1 || error "should not fail" - [ -f $MOUNT/f1 ] || error "$MOUNT/f1 not found" + $RUNAS touch $file || error "should not fail" + [ -f $file ] || error "$file not found" } run_test 1 "access with or without krb5 credential" test_2() { + local file1=$DIR/$tfile-1 + local file2=$DIR/$tfile-2 + + chmod 0777 $DIR || error "chmod $DIR failed" # current access should be ok - $RUNAS touch $MOUNT/f2_1 || error "can't touch $MOUNT/f2_1" - [ -f $MOUNT/f2_1 ] || error "$MOUNT/f2_1 not found" + $RUNAS touch $file1 || error "can't touch $file1" + [ -f $file1 ] || error "$file1 not found" # cleanup all cred/ctx and touch $RUNAS kdestroy $RUNAS $LFS flushctx || error "can't flush ctx" - $RUNAS touch $MOUNT/f2_2 && error "unexpected success" + $RUNAS touch $file2 && error "unexpected success" # restore and touch restore_krb5_cred - $RUNAS touch $MOUNT/f2_2 || error "should not fail" - [ -f $MOUNT/f2_2 ] || error "$MOUNT/f2_2 not found" + $RUNAS touch $file2 || error "should not fail" + [ -f $file2 ] || error "$file2 not found" } run_test 2 "lfs flushctx" test_3() { - local file=$MOUNT/f3 + local file=$DIR/$tfile # create file echo "aaaaaaaaaaaaaaaaa" > $file @@ -215,9 +495,12 @@ test_3() { run_test 3 "local cache under DLM lock" test_4() { - local file1=$MOUNT/f4_1 - local file2=$MOUNT/f4_2 + local file1=$DIR/$tfile-1 + local file2=$DIR/$tfile-2 + ! $GSS_PIPEFS && skip "pipefs not used" && return + + chmod 0777 $DIR || error "chmod $DIR failed" # current access should be ok $RUNAS touch $file1 || error "can't touch $file1" [ -f $file1 ] || error "$file1 not found" @@ -246,10 +529,11 @@ test_4() { run_test 4 "lgssd dead, operations should wait timeout and fail" test_5() { - local file1=$MOUNT/f5_1 - local file2=$MOUNT/f5_2 - local wait_time=`expr $TIMEOUT + $TIMEOUT` + local file1=$DIR/$tfile-1 + local file2=$DIR/$tfile-2 + local wait_time=$((TIMEOUT + TIMEOUT / 2)) + chmod 0777 $DIR || error "chmod $DIR failed" # current access should be ok $RUNAS touch $file1 || error "can't touch $file1" [ -f $file1 ] || error "$file1 not found" @@ -282,26 +566,15 @@ test_5() { run_test 5 "lsvcgssd dead, operations lead to recovery" test_6() { - NPROC=`cat /proc/cpuinfo 2>/dev/null | grep ^processor | wc -l` - [ $NPROC -ne 0 ] || NPROC=2 - - echo "starting dbench $NPROC" - sh rundbench $NPROC & - RUNPID=$! - - for ((n=0;;n++)); do - sleep 2 - num=`ps --no-headers -p $RUNPID | wc -l` - [ $num -ne 0 ] || break - echo "flush ctx ..." - $LFS flushctx - done - wait $RUNPID || error "dbench detect error" + mkdir $DIR/d6 || error "mkdir $DIR/d6 failed" + cp -a /etc/* $DIR/d6/ || error "cp failed" + ls -l $DIR/d6/* > /dev/null || error "ls failed" + rm -rf $DIR2/d6/* || error "rm failed" } -run_test 6 "recoverable from losing context" +run_test 6 "test basic DLM callback works" test_7() { - local tdir=$MOUNT/dir7 + local tdir=$DIR/d7 local num_osts # @@ -333,74 +606,298 @@ test_7() { } run_test 7 "exercise enlarge_reqbuf()" -check_multiple_gss_daemons() { - local facet=$1 - local gssd=$2 - local gssd_name=`basename $gssd` +test_90() { + if [ "$SLOW" = "no" ]; then + total=10 + else + total=60 + fi - for ((i=0;i<10;i++)); do - do_facet $facet "$gssd -v &" + start_dbench + + for ((n=0;n<$total;n++)); do + sleep 2 + check_dbench + echo "flush ctx ($n/$total) ..." + $LFS flushctx done + check_dbench + stop_dbench +} +run_test 90 "recoverable from losing contexts under load" - # wait daemons entering "stable" status - sleep 5 +test_99() { + local nrule_old=0 + local nrule_new=0 + local max=32 - num=`do_facet $facet ps -o cmd -C $gssd_name | grep $gssd_name | wc -l` - echo "$num instance(s) of $gssd_name are running" + # + # general rules + # + nrule_old=`do_facet mgs cat $LPROC/mgs/MGS/live/$FSNAME 2>/dev/null \ + | grep "$FSNAME.srpc.flavor." | wc -l` + echo "original general rules: $nrule_old" - if [ $num -ne 1 ]; then - error "$gssd_name not unique" + for ((i = $nrule_old; i < $max; i++)); do + set_rule $FSNAME elan$i any krb5n || error "set rule $i" + done + set_rule $FSNAME elan100 any krb5n && error "set $max rule should fail" + for ((i = $nrule_old; i < $max; i++)); do + set_rule $FSNAME elan$i any || error "remove rule $i" + done + + nrule_new=`do_facet mgs cat $LPROC/mgs/MGS/live/$FSNAME 2>/dev/null \ + | grep "$FSNAME.srpc.flavor." | wc -l` + if [ $nrule_new != $nrule_old ]; then + error "general rule: $nrule_new != $nrule_old" fi + + # + # target-specific rules + # + nrule_old=`do_facet mgs cat $LPROC/mgs/MGS/live/$FSNAME 2>/dev/null \ + | grep "$FSNAME-MDT0000.srpc.flavor." | wc -l` + echo "original target rules: $nrule_old" + + for ((i = $nrule_old; i < $max; i++)); do + set_rule $FSNAME-MDT0000 elan$i any krb5i || error "set rule $i" + done + set_rule $FSNAME-MDT0000 elan100 any krb5i && error "set $max rule should fail" + for ((i = $nrule_old; i < $max; i++)); do + set_rule $FSNAME-MDT0000 elan$i any || error "remove rule $i" + done + + nrule_new=`do_facet mgs cat $LPROC/mgs/MGS/live/$FSNAME 2>/dev/null \ + | grep "$FSNAME-MDT0000.srpc.flavor." | wc -l` + if [ $nrule_new != $nrule_old ]; then + error "general rule: $nrule_new != $nrule_old" + fi +} +run_test 99 "maximum sptlrpc rules limitation" + +error_dbench() +{ + local err_str=$1 + + killall -9 dbench + sleep 1 + + error $err_str } test_100() { - local facet=mds + # started from default flavors + restore_to_default_flavor - # cleanup everything at first - cleanupall + # running dbench background + start_dbench - echo "bring up gss daemons..." - start_gss_daemons + # + # all: null -> krb5n -> krb5a -> krb5i -> krb5p -> plain + # + set_rule $FSNAME any any krb5n + wait_flavor all2all krb5n $cnt_all2all || error_dbench "1" + check_dbench - echo "check with someone already running..." - check_multiple_gss_daemons $facet $LSVCGSSD - if [ "x$GSS_PIPEFS" == "xy" ]; then - check_multiple_gss_daemons $facet $LGSSD - fi + set_rule $FSNAME any any krb5a + wait_flavor all2all krb5a $cnt_all2all || error_dbench "2" + check_dbench - echo "check with someone run & finished..." - do_facet $facet killall -q -2 lgssd lsvcgssd || true - sleep 5 # wait fully exit - check_multiple_gss_daemons $facet $LSVCGSSD - if [ "x$GSS_PIPEFS" == "xy" ]; then - check_multiple_gss_daemons $facet $LGSSD - fi + set_rule $FSNAME any any krb5i + wait_flavor all2all krb5i $cnt_all2all || error_dbench "3" + check_dbench - echo "check refresh..." - do_facet $facet killall -q -2 lgssd lsvcgssd || true - sleep 5 # wait fully exit - do_facet $facet ipcrm -S 0x3b92d473 - check_multiple_gss_daemons $facet $LSVCGSSD - if [ "x$GSS_PIPEFS" == "xy" ]; then - do_facet $facet ipcrm -S 0x3a92d473 - check_multiple_gss_daemons $facet $LGSSD + set_rule $FSNAME any any krb5p + wait_flavor all2all krb5p $cnt_all2all || error_dbench "4" + check_dbench + + set_rule $FSNAME any any plain + wait_flavor all2all plain $cnt_all2all || error_dbench "5" + check_dbench + + # + # M - M: krb5a + # C - M: krb5i + # M - O: krb5p + # C - O: krb5n + # + set_rule $FSNAME any mdt2mdt krb5a + wait_flavor mdt2mdt krb5a $cnt_mdt2mdt || error_dbench "6" + check_dbench + + set_rule $FSNAME any cli2mdt krb5i + wait_flavor cli2mdt krb5i $cnt_cli2mdt || error_dbench "7" + check_dbench + + set_rule $FSNAME any mdt2ost krb5p + wait_flavor mdt2ost krb5p $cnt_mdt2ost || error_dbench "8" + check_dbench + + set_rule $FSNAME any cli2ost krb5n + wait_flavor cli2ost krb5n $cnt_cli2ost || error_dbench "9" + check_dbench + + # + # * - MDT0: krb5p + # * - OST0: krb5i + # + # nothing should be changed because they are override by above dir rules + # + set_rule $FSNAME-MDT0000 any any krb5p + set_rule $FSNAME-OST0000 any any krb5i + wait_flavor mdt2mdt krb5a $cnt_mdt2mdt || error_dbench "10" + wait_flavor cli2mdt krb5i $cnt_cli2mdt || error_dbench "11" + check_dbench + wait_flavor mdt2ost krb5p $cnt_mdt2ost || error_dbench "12" + wait_flavor cli2ost krb5n $cnt_cli2ost || error_dbench "13" + + # + # delete all dir-specific rules + # + set_rule $FSNAME any mdt2mdt + set_rule $FSNAME any cli2mdt + set_rule $FSNAME any mdt2ost + set_rule $FSNAME any cli2ost + wait_flavor mdt2mdt krb5p $((MDSCOUNT - 1)) || error_dbench "14" + wait_flavor cli2mdt krb5p $CLICOUNT || error_dbench "15" + check_dbench + wait_flavor mdt2ost krb5i $MDSCOUNT || error_dbench "16" + wait_flavor cli2ost krb5i $CLICOUNT || error_dbench "17" + check_dbench + + # + # remove: + # * - MDT0: krb5p + # * - OST0: krb5i + # + set_rule $FSNAME-MDT0000 any any + set_rule $FSNAME-OST0000 any any || error_dbench "18" + wait_flavor all2all plain $cnt_all2all || error_dbench "19" + check_dbench + + stop_dbench +} +run_test 100 "change security flavor on the fly under load" + +switch_sec_test() +{ + local count=$1 + local flavor0=$2 + local flavor1=$3 + local flavor2=$4 + local df_pid=0 + local wait_time=$((TIMEOUT + TIMEOUT / 4)) + local num + + # + # stop gss daemon, then switch to flavor1 (which should be a gss flavor), + # and run a 'df' which should hanging, wait the request timeout and + # resend, then switch the flavor to another one. To exercise the code of + # switching ctx/sec for a resend request. + # + echo ">>>>>>>>>>>>>>> Testing $flavor0 -> $flavor1 -> $flavor2..." + + echo "(0) set base flavor $flavor0" + set_rule $FSNAME any cli2mdt $flavor0 + wait_flavor cli2mdt $flavor0 $count + df $MOUNT + if [ $? -ne 0 ]; then + error "initial df failed" fi stop_gss_daemons + sleep 1 + + echo "(1) $flavor0 -> $flavor1" + set_rule $FSNAME any cli2mdt $flavor1 + wait_flavor cli2mdt $flavor1 $count + df $MOUNT & + df_pid=$! + sleep 1 + + echo "waiting $wait_time seconds for df ($df_pid)" + sleep $wait_time + num=`ps --no-headers -p $df_pid 2>/dev/null | wc -l` + [ $num -eq 1 ] || error "df already ended ($num)" + echo "process $df_pid is still hanging there... OK" + + echo "(2) set end flavor $flavor2" + set_rule $FSNAME any cli2mdt $flavor2 + wait_flavor cli2mdt $flavor2 $count + start_gss_daemons + wait $df_pid || error "df returned error" } -run_test 100 "start multiple gss daemons" -TMPDIR=$OLDTMPDIR -TMP=$OLDTMP -HOME=$OLDHOME +test_101() +{ + # started from default flavors + restore_to_default_flavor + + switch_sec_test $cnt_cli2mdt null krb5n null + switch_sec_test $cnt_cli2mdt null krb5a null + switch_sec_test $cnt_cli2mdt null krb5i null + switch_sec_test $cnt_cli2mdt null krb5p null + switch_sec_test $cnt_cli2mdt null krb5i plain + switch_sec_test $cnt_cli2mdt plain krb5p plain + switch_sec_test $cnt_cli2mdt plain krb5n krb5a + switch_sec_test $cnt_cli2mdt krb5a krb5i krb5p + switch_sec_test $cnt_cli2mdt krb5p krb5a krb5n + switch_sec_test $cnt_cli2mdt krb5n krb5p krb5i +} +run_test 101 "switch ctx as well as sec for resending request" -log "cleanup: ======================================================" -if [ "`mount | grep ^$NAME`" ]; then - rm -rf $DIR/[Rdfs][1-9]* -fi +error_102() +{ + local err_str=$1 -cleanupall -f || error "cleanup failed" + killall -9 dbench + sleep 1 + error $err_str +} + +test_102() { + # started from default flavors + restore_to_default_flavor + + # run dbench background + start_dbench + + echo "Testing null->krb5n->krb5a->krb5i->krb5p->plain->null" + set_rule $FSNAME any any krb5n + set_rule $FSNAME any any krb5a + set_rule $FSNAME any any krb5i + set_rule $FSNAME any any krb5p + set_rule $FSNAME any any plain + set_rule $FSNAME any any null + + check_dbench + wait_flavor all2all null $cnt_all2all || error_dbench "1" + check_dbench + + echo "waiting for 15s and check again" + sleep 15 + check_dbench + + echo "Testing null->krb5i->null->krb5i->null..." + for ((i=0; i<10; i++)); do + set_rule $FSNAME any any krb5i + set_rule $FSNAME any any null + done + set_rule $FSNAME any any krb5i + + check_dbench + wait_flavor all2all krb5i $cnt_all2all || error_dbench "2" + check_dbench + + echo "waiting for 15s and check again" + sleep 15 + check_dbench + + stop_dbench +} +run_test 102 "survive from insanely fast flavor switch" -echo '=========================== finished ===============================' -[ -f "$SANITYLOG" ] && cat $SANITYLOG && exit 1 || true +equals_msg `basename $0`: test complete, cleaning up +check_and_cleanup_lustre +[ -f "$TESTSUITELOG" ] && cat $TESTSUITELOG || true diff --git a/lustre/tests/sanity-sec.sh b/lustre/tests/sanity-sec.sh index d68531d..a348768 100644 --- a/lustre/tests/sanity-sec.sh +++ b/lustre/tests/sanity-sec.sh @@ -1,108 +1,57 @@ #!/bin/bash # -# Run select tests by setting SEC_ONLY, or as arguments to the script. -# Skip specific tests by setting SEC_EXCEPT. +# Run select tests by setting ONLY, or as arguments to the script. +# Skip specific tests by setting EXCEPT. # set -e +ONLY=${ONLY:-"$*"} +[ "$EXCEPT" ] && echo "Skipping tests: `echo $EXCEPT`" + SRCDIR=`dirname $0` export PATH=$PWD/$SRCDIR:$SRCDIR:$PWD/$SRCDIR/../utils:$PATH:/sbin +export NAME=${NAME:-local} + +LUSTRE=${LUSTRE:-`dirname $0`/..} +. $LUSTRE/tests/test-framework.sh +init_test_env $@ +. ${CONFIG:=$LUSTRE/tests/cfg/$NAME.sh} + +RUNAS=${RUNAS:-"$LUSTRE/tests/runas"} +WTL=${WTL:-"$LUSTRE/tests/write_time_limit"} -SEC_ONLY=${SEC_ONLY:-"$*"} -[ "$SEC_EXCEPT" ] && echo "Skipping tests: `echo $SEC_EXCEPT`" - -TMP=${TMP:-/tmp} -LFS=${LFS:-lfs} -LCTL=${LCTL:-lctl} -RUNAS=${RUNAS:-runas} -WTL=${WTL:-write_time_limit} - -LPROC=/proc/fs/lustre -ENABLE_IDENTITY=/usr/sbin/l_getidentity -DISABLE_IDENTITY=NONE -LUSTRE_CONF_DIR=/etc/lustre -PERM_CONF=$LUSTRE_CONF_DIR/perm.conf -LDLM_LPROC=$LPROC/ldlm +PERM_CONF=/etc/lustre/perm.conf LLITE_LPROC=$LPROC/llite MDC_LPROC=$LPROC/mdc MDT_LPROC=$LPROC/mdt OST_LPROC=$LPROC/obdfilter -sec_log() { - echo "$*" - $LCTL mark "$*" 2> /dev/null || true -} - -SANITYSECLOG=${SANITYSECLOG:-/tmp/sanity-sec.log} -[ "$SANITYSECLOG" ] && rm -f $SANITYSECLOG || true - -sec_error() { - sec_log "FAIL: $TESTNAME $@" - if [ "$SANITYSECLOG" ]; then - echo "FAIL: $TESTNAME $@" >> $SANITYSECLOG - else - exit 1 - fi -} - -sec_pass() { - echo PASS $@ -} - -sec_skip () { - sec_log "$0: SKIP: $TESTNAME $@" - [ "$SANITYSECLOG" ] && echo "$0: SKIP: $TESTNAME $@" >> $SANITYSECLOG -} - -ID1=500 -ID2=501 +SANITYSECLOG=${TESTSUITELOG:-$TMP/$(basename $0 .sh).log} +FAIL_ON_ERROR=false +ID0=${ID0:-500} +ID1=${ID1:-501} +USER0=`cat /etc/passwd|grep :$ID0:$ID0:|cut -d: -f1` USER1=`cat /etc/passwd|grep :$ID1:$ID1:|cut -d: -f1` -USER2=`cat /etc/passwd|grep :$ID2:$ID2:|cut -d: -f1` -if [ -z "$USER1" ]; then - echo "===== Please add user1 (uid=$ID1 gid=$ID1)! Skip sanity-sec =====" - sec_error "===== Please add user1 (uid=$ID1 gid=$ID1)! =====" - exit 0 -fi +[ -z "$USER0" ] && \ + echo "Please add user0 (uid=$ID0 gid=$ID0)! Skip sanity-sec" && exit 0 -if [ -z "$USER2" ]; then - echo "===== Please add user2 (uid=$ID2 gid=$ID2)! Skip sanity-sec =====" - sec_error "===== Please add user2 (uid=$ID2 gid=$ID2)! =====" - exit 0 -fi +[ -z "$USER1" ] && \ + echo "Please add user1 (uid=$ID1 gid=$ID1)! Skip sanity-sec" && exit 0 -export NAME=${NAME:-local} - -LUSTRE=${LUSTRE:-`dirname $0`/..} -. $LUSTRE/tests/test-framework.sh -init_test_env $@ -. ${CONFIG:=$LUSTRE/tests/cfg/$NAME.sh} - -mounted_lustre_filesystems() { - awk '($3 ~ "lustre" && $1 ~ ":") { print $2 }' /proc/mounts -} - -MOUNTED="`mounted_lustre_filesystems`" -if [ -z "$MOUNTED" ]; then - formatall - setupall - MOUNTED="`mounted_lustre_filesystems`" - [ -z "$MOUNTED" ] && sec_error "NAME=$NAME not mounted" - S_MOUNTED=yes -fi - -[ `echo $MOUNT | wc -w` -gt 1 ] && sec_error "NAME=$NAME mounted more than once" +check_and_setup_lustre DIR=${DIR:-$MOUNT} -[ -z "`echo $DIR | grep $MOUNT`" ] && echo "$DIR not in $MOUNT" && \ - sec_cleanup && exit 99 +[ -z "`echo $DIR | grep $MOUNT`" ] && \ + error "$DIR not in $MOUNT" && sec_cleanup && exit 1 -[ `ls -l $LDLM_LPROC/namespaces 2>/dev/null | grep *-mdc-* | wc -l` -gt 1 ] \ - && echo "skip multi-MDS test" && sec_cleanup && exit 0 +[ `echo $MOUNT | wc -w` -gt 1 ] && \ + echo "NAME=$MOUNT mounted more than once" && sec_cleanup && exit 0 -OST_COUNT=$(ls -l $LDLM_LPROC/namespaces 2>/dev/null | grep osc | grep -v MDT | wc -l) +[ $MDSCOUNT -gt 1 ] && \ + echo "skip multi-MDS test" && sec_cleanup && exit 0 # for GSS_SUP GSS_REF=$(lsmod | grep ^ptlrpc_gss | awk '{print $3}') @@ -114,24 +63,9 @@ else echo "without GSS support" fi -# for MDT_TYPE -MDT_REF=$(lsmod | grep ^mdt | awk '{print $3}') -if [ ! -z "$MDT_REF" -a "$MDT_REF" != "0" ]; then - MDT_TYPE="local" - echo "local mdt" -else - MDT_TYPE="remote" - echo "remote mdt" -fi - -MDT="`do_facet $SINGLEMDS ls -l $MDT_LPROC/ | grep MDT | awk '{print $9}'`" +MDT="`do_facet $SINGLEMDS \"ls -l $MDT_LPROC/ 2>/dev/null\" | grep MDT | awk '{print $9}'`" if [ ! -z "$MDT" ]; then - IDENTITY_UPCALL=$MDT_LPROC/$MDT/identity_upcall - IDENTITY_UPCALL_BAK="`more $IDENTITY_UPCALL`" IDENTITY_FLUSH=$MDT_LPROC/$MDT/identity_flush - ROOTSQUASH_UID=$MDT_LPROC/$MDT/rootsquash_uid - ROOTSQUASH_GID=$MDT_LPROC/$MDT/rootsquash_gid - NOSQUASH_NIDS=$MDT_LPROC/$MDT/nosquash_nids MDSCAPA=$MDT_LPROC/$MDT/capa CAPA_TIMEOUT=$MDT_LPROC/$MDT/capa_timeout fi @@ -147,62 +81,6 @@ fi SAVE_PWD=$PWD -sec_run_one() { - BEFORE=`date +%s` - sec_log "== test $1 $2= `date +%H:%M:%S` ($BEFORE)" - export TESTNAME=test_$1 - test_$1 || sec_error "exit with rc=$?" - unset TESTNAME - sec_pass "($((`date +%s` - $BEFORE))s)" -} - -build_test_filter() { - for O in $SEC_ONLY; do - eval SEC_ONLY_${O}=true - done - for E in $SEC_EXCEPT; do - eval SEC_EXCEPT_${E}=true - done -} - -_basetest() { - echo $* -} - -basetest() { - IFS=abcdefghijklmnopqrstuvwxyz _basetest $1 -} - -sec_run_test() { - base=`basetest $1` - if [ "$SEC_ONLY" ]; then - testname=SEC_ONLY_$1 - if [ ${!testname}x != x ]; then - sec_run_one $1 "$2" - return $? - fi - testname=SEC_ONLY_$base - if [ ${!testname}x != x ]; then - sec_run_one $1 "$2" - return $? - fi - echo -n "." - return 0 - fi - testname=SEC_EXCEPT_$1 - if [ ${!testname}x != x ]; then - echo "skipping excluded test $1" - return 0 - fi - testname=SEC_EXCEPT_$base - if [ ${!testname}x != x ]; then - echo "skipping excluded test $1 (base $base)" - return 0 - fi - sec_run_one $1 "$2" - return $? -} - build_test_filter sec_login() { @@ -210,169 +88,165 @@ sec_login() { local group=$2 if ! $RUNAS -u $user krb5_login.sh; then - echo "$user login kerberos failed." + error "$user login kerberos failed." exit 1 fi - if ! $RUNAS -u $user -g $group ls $DIR > /dev/null; then + if ! $RUNAS -u $user -g $group ls $DIR > /dev/null 2>&1; then $RUNAS -u $user lfs flushctx -k $RUNAS -u $user krb5_login.sh - if ! $RUNAS -u $user -g $group ls $DIR > /dev/null; then - echo "init $user $group failed." + if ! $RUNAS -u $user -g $group ls $DIR > /dev/null 2>&1; then + error "init $user $group failed." exit 2 fi fi } -setup() { - if [ ! -z "$MDT" ]; then - do_facet $SINGLEMDS echo $ENABLE_IDENTITY > $IDENTITY_UPCALL - do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH +declare -a identity_old + +sec_setup() { + for num in `seq $MDSCOUNT`; do + switch_identity $num true || identity_old[$num]=$? + done + + if ! $RUNAS -u $ID0 ls $DIR > /dev/null 2>&1; then + sec_login $USER0 $USER0 fi if ! $RUNAS -u $ID1 ls $DIR > /dev/null 2>&1; then sec_login $USER1 $USER1 fi - - if ! $RUNAS -u $ID2 ls $DIR > /dev/null 2>&1; then - sec_login $USER2 $USER2 - fi } -setup +sec_setup # run as different user test_0() { rm -rf $DIR/d0 mkdir $DIR/d0 - chown $USER1 $DIR/d0 || sec_error - $RUNAS -u $ID1 ls $DIR || sec_error - $RUNAS -u $ID1 touch $DIR/f0 && sec_error - $RUNAS -u $ID1 touch $DIR/d0/f1 || sec_error - $RUNAS -u $ID2 touch $DIR/d0/f2 && sec_error - touch $DIR/d0/f3 || sec_error - chown root $DIR/d0 - chgrp $USER1 $DIR/d0 - chmod 775 $DIR/d0 - $RUNAS -u $ID1 touch $DIR/d0/f4 || sec_error - $RUNAS -u $ID2 touch $DIR/d0/f5 && sec_error - touch $DIR/d0/f6 || sec_error + chown $USER0 $DIR/d0 || error "chown (1)" + $RUNAS -u $ID0 ls $DIR || error "ls (2)" + $RUNAS -u $ID0 touch $DIR/f0 && error "touch (3)" + $RUNAS -u $ID0 touch $DIR/d0/f1 || error "touch (4)" + $RUNAS -u $ID1 touch $DIR/d0/f2 && error "touch (5)" + touch $DIR/d0/f3 || error "touch (6)" + chown root $DIR/d0 || error "chown (7)" + chgrp $USER0 $DIR/d0 || error "chgrp (8)" + chmod 775 $DIR/d0 || error "chmod (9)" + $RUNAS -u $ID0 touch $DIR/d0/f4 || error "touch (10)" + $RUNAS -u $ID1 touch $DIR/d0/f5 && error "touch (11)" + touch $DIR/d0/f6 || error "touch (12)" rm -rf $DIR/d0 } -sec_run_test 0 "uid permission =============================" +run_test 0 "uid permission =============================" # setuid/gid test_1() { - [ $GSS_SUP = 0 ] && sec_skip "without GSS support." && return - [ -z "$MDT" ] && sec_skip "do not support do_facet operations." && return + [ $GSS_SUP = 0 ] && skip "without GSS support." && return + [ -z "$MDT" ] && skip "do not support do_facet operations." && return + [ "$CLIENT_TYPE" = "remote" ] && \ + skip "test_1 for local client only" && return - do_facet $SINGLEMDS rm -f $PERM_CONF - do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH + do_facet $SINGLEMDS "rm -f $PERM_CONF" + do_facet $SINGLEMDS "echo -1 > $IDENTITY_FLUSH" rm -rf $DIR/d1 mkdir $DIR/d1 - chown $USER1 $DIR/d1 || sec_error - $RUNAS -u $ID2 -v $ID1 touch $DIR/d1/f0 && sec_error - do_facet $SINGLEMDS echo "\* $ID2 setuid" > $PERM_CONF - echo "enable uid $ID2 setuid" - do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH - $RUNAS -u $ID2 -v $ID1 touch $DIR/d1/f1 || sec_error - - chown root $DIR/d1 - chgrp $USER1 $DIR/d1 - chmod 770 $DIR/d1 - $RUNAS -u $ID2 -g $ID2 touch $DIR/d1/f2 && sec_error - $RUNAS -u $ID2 -g $ID2 -j $ID1 touch $DIR/d1/f3 && sec_error - do_facet $SINGLEMDS echo "\* $ID2 setuid,setgid" > $PERM_CONF - echo "enable uid $ID2 setuid,setgid" - do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH - $RUNAS -u $ID2 -g $ID2 -j $ID1 touch $DIR/d1/f4 || sec_error - $RUNAS -u $ID2 -v $ID1 -g $ID2 -j $ID1 touch $DIR/d1/f5 || sec_error + chown $USER0 $DIR/d1 || error "chown (1)" + $RUNAS -u $ID1 -v $ID0 touch $DIR/d1/f0 && error "touch (2)" + do_facet $SINGLEMDS "echo '* $ID1 setuid' > $PERM_CONF" + echo "enable uid $ID1 setuid" + do_facet $SINGLEMDS "echo -1 > $IDENTITY_FLUSH" + $RUNAS -u $ID1 -v $ID0 touch $DIR/d1/f1 || error "touch (3)" + + chown root $DIR/d1 || error "chown (4)" + chgrp $USER0 $DIR/d1 || error "chgrp (5)" + chmod 770 $DIR/d1 || error "chmod (6)" + $RUNAS -u $ID1 -g $ID1 touch $DIR/d1/f2 && error "touch (7)" + $RUNAS -u $ID1 -g $ID1 -j $ID0 touch $DIR/d1/f3 && error "touch (8)" + do_facet $SINGLEMDS "echo '* $ID1 setuid,setgid' > $PERM_CONF" + echo "enable uid $ID1 setuid,setgid" + do_facet $SINGLEMDS "echo -1 > $IDENTITY_FLUSH" + $RUNAS -u $ID1 -g $ID1 -j $ID0 touch $DIR/d1/f4 || error "touch (9)" + $RUNAS -u $ID1 -v $ID0 -g $ID1 -j $ID0 touch $DIR/d1/f5 || error "touch (10)" rm -rf $DIR/d1 - do_facet $SINGLEMDS rm -f $PERM_CONF - do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH + do_facet $SINGLEMDS "rm -f $PERM_CONF" + do_facet $SINGLEMDS "echo -1 > $IDENTITY_FLUSH" +} +run_test 1 "setuid/gid =============================" + +run_rmtacl_subtest() { + $SAVE_PWD/rmtacl/run $SAVE_PWD/rmtacl/$1.test + return $? } -sec_run_test 1 "setuid/gid =============================" # remote_acl # for remote client only test_2 () { [ "$CLIENT_TYPE" = "local" ] && \ - sec_skip "remote_acl for remote client only" && return + skip "remote_acl for remote client only" && return [ -z "$(grep ^acl $MDC_LPROC/*-mdc-*/connect_flags)" ] && \ - sec_skip "must have acl enabled" && return + skip "must have acl enabled" && return [ -z "$(which setfacl 2>/dev/null)" ] && \ - sec_skip "could not find setfacl" && return - [ "$UID" != 0 ] && sec_skip "must run as root" && return - - rm -rf $DIR/d2 - mkdir $DIR/d2 - chmod 755 $DIR/d2 - echo xxx > $DIR/d2/f0 - chmod 644 $DIR/d2/f0 - - $LFS getfacl $DIR/d2/f0 || sec_error - $RUNAS -u $ID1 cat $DIR/d2/f0 || sec_error - $RUNAS -u $ID1 touch $DIR/d2/f0 && sec_error - - $LFS setfacl -m u:$USER1:w $DIR/d2/f0 || sec_error - $LFS getfacl $DIR/d2/f0 || sec_error - echo "set user $USER1 write permission on file $DIR/d2/f0" - $RUNAS -u $ID1 touch $DIR/d2/f0 || sec_error - $RUNAS -u $ID1 cat $DIR/d2/f0 && sec_error - - rm -rf $DIR/d2 + skip "could not find setfacl" && return + [ "$UID" != 0 ] && skip "must run as root" && return + + sec_login root root + sec_login bin bin + sec_login daemon daemon + sec_login games users + + SAVE_UMASK=`umask` + umask 0022 + cd $DIR + + if [ ! -z "$MDT" ]; then + do_facet $SINGLEMDS "echo '* 0 rmtacl' > $PERM_CONF" + do_facet $SINGLEMDS "echo -1 > $IDENTITY_FLUSH" + fi + + if lfs rgetfacl $DIR; then + echo "performing cp ..." + run_rmtacl_subtest cp || error "cp" + else + echo "server doesn't permit current user 'lfs r{s,g}etfacl', skip cp test." + fi + echo "performing getfacl-noacl..." + run_rmtacl_subtest getfacl-noacl || error "getfacl-noacl" + echo "performing misc..." + run_rmtacl_subtest misc || error "misc" + echo "performing permissions..." + run_rmtacl_subtest permissions || error "permissions" + echo "performing setfacl..." + run_rmtacl_subtest setfacl || error "setfacl" + + # inheritance test got from HP + echo "performing inheritance..." + cp $SAVE_PWD/rmtacl/make-tree . + chmod +x make-tree + run_rmtacl_subtest inheritance || error "inheritance" + rm -f make-tree + + if [ ! -z "$MDT" ]; then + do_facet $SINGLEMDS "rm -f $PERM_CONF" + do_facet $SINGLEMDS "echo -1 > $IDENTITY_FLUSH" + fi + + cd $SAVE_PWD + umask $SAVE_UMASK } -sec_run_test 2 "rmtacl =============================" +run_test 2 "rmtacl =============================" # rootsquash -# for remote mdt only +# root_squash will be redesigned in Lustre 1.7 test_3() { - [ $GSS_SUP = 0 ] && sec_skip "without GSS support." && return - [ -z "$MDT" ] && sec_skip "do not support do_facet operations." && return - [ "$MDT_TYPE" = "local" ] && sec_skip "rootsquash for remote mdt only" && return - - do_facet $SINGLEMDS echo "-\*" > $NOSQUASH_NIDS - do_facet $SINGLEMDS echo 0 > $ROOTSQUASH_UID - do_facet $SINGLEMDS echo 0 > $ROOTSQUASH_GID - - rm -rf $DIR/d3 - mkdir $DIR/d3 - chown $USER1 $DIR/d3 - chmod 700 $DIR/d3 - do_facet $SINGLEMDS echo $ID1 > $ROOTSQUASH_UID - echo "set rootsquash uid = $ID1" - touch $DIR/f3_0 && sec_error - touch $DIR/d3/f3_1 || sec_error - - do_facet $SINGLEMDS echo 0 > $ROOTSQUASH_UID - echo "disable rootsquash" - chown root $DIR/d3 - chgrp $USER2 $DIR/d3 - chmod 770 $DIR/d3 - - do_facet $SINGLEMDS echo $ID1 > $ROOTSQUASH_UID - echo "set rootsquash uid = $ID1" - touch $DIR/d3/f3_2 && sec_error - do_facet $SINGLEMDS echo $ID2 > $ROOTSQUASH_GID - echo "set rootsquash gid = $ID2" - touch $DIR/d3/f3_3 || sec_error - - do_facet $SINGLEMDS echo "+\*" > $NOSQUASH_NIDS - echo "add host in rootsquash skip list" - touch $DIR/f3_4 || sec_error - - do_facet $SINGLEMDS echo 0 > $ROOTSQUASH_UID - do_facet $SINGLEMDS echo 0 > $ROOTSQUASH_GID - do_facet $SINGLEMDS echo "-\*" > $NOSQUASH_NIDS - rm -rf $DIR/d3 - rm -f $DIR/f3_? + skip "root_squash will be redesigned in Lustre 1.7" && return } -sec_run_test 3 "rootsquash =============================" +run_test 3 "rootsquash =============================" # bug 3285 - supplementary group should always succeed. # NB: the supplementary groups are set for local client only, @@ -382,29 +256,29 @@ test_4() { rm -rf $DIR/d4 mkdir $DIR/d4 chmod 771 $DIR/d4 - chgrp $ID1 $DIR/d4 - $RUNAS -u $ID1 ls $DIR/d4 || sec_error "setgroups(1) failed" + chgrp $ID0 $DIR/d4 + $RUNAS -u $ID0 ls $DIR/d4 || error "setgroups (1)" if [ "$CLIENT_TYPE" != "remote" ]; then if [ ! -z "$MDT" ]; then - do_facet $SINGLEMDS echo "\* $ID2 setgrp" > $PERM_CONF - do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH + do_facet $SINGLEMDS "echo '* $ID1 setgrp' > $PERM_CONF" + do_facet $SINGLEMDS "echo -1 > $IDENTITY_FLUSH" fi - $RUNAS -u $ID2 -G1,2,$ID1 ls $DIR/d4 || sec_error "setgroups(2) failed" + $RUNAS -u $ID1 -G1,2,$ID0 ls $DIR/d4 || error "setgroups (2)" if [ ! -z "$MDT" ]; then - do_facet $SINGLEMDS rm -f $PERM_CONF - do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH + do_facet $SINGLEMDS "rm -f $PERM_CONF" + do_facet $SINGLEMDS "echo -1 > $IDENTITY_FLUSH" fi fi - $RUNAS -u $ID2 -G1,2 ls $DIR/d4 && sec_error "setgroups(3) failed" + $RUNAS -u $ID1 -G1,2 ls $DIR/d4 && error "setgroups (3)" rm -rf $DIR/d4 } -sec_run_test 4 "set supplementary group ===============" +run_test 4 "set supplementary group ===============" mds_capability_timeout() { [ $# -lt 1 ] && echo "Miss mds capability timeout value" && return 1 echo "Set mds capability timeout as $1 seconds" - do_facet $SINGLEMDS echo $1 > $CAPA_TIMEOUT + do_facet $SINGLEMDS "echo $1 > $CAPA_TIMEOUT" return 0 } @@ -417,7 +291,7 @@ mds_capability_switch() { *) echo "Invalid mds capability switch value" && return 2;; esac - do_facet $SINGLEMDS echo $1 > $MDSCAPA + do_facet $SINGLEMDS "echo $1 > $MDSCAPA" return 0 } @@ -430,12 +304,10 @@ oss_capability_switch() { *) echo "Invalid oss capability switch value" && return 2;; esac - i=0; - while [ $i -lt $OST_COUNT ]; do - j=$i; - i=`expr $i + 1` - OST="`do_facet ost$i ls -l $OST_LPROC/ | grep OST | awk '{print $9}' | grep $j$`" - do_facet ost$i echo $1 > $OST_LPROC/$OST/capa + for i in `seq $OSTCOUNT`; do + local j=`expr $i - 1` + local OST="`do_facet ost$i \"ls -l $OST_LPROC/\" | grep OST | awk '{print $9}' | grep $j$`" + do_facet ost$i "echo $1 > $OST_LPROC/$OST/capa" done return 0 } @@ -475,13 +347,25 @@ turn_capability_off() { test_5() { local file=$DIR/f5 - [ -z "$MDT" ] && sec_skip "do not support do_facet operations." && return + [ -z "$MDT" ] && skip "do not support do_facet operations." && return turn_capability_off + if [ $? != 0 ]; then + error "turn_capability_off" + return 1 + fi rm -f $file # Disable proc variable - mds_capability_switch 0 || return 1 - oss_capability_switch 1 || return 2 + mds_capability_switch 0 + if [ $? != 0 ]; then + error "mds_capability_switch 0" + return 2 + fi + oss_capability_switch 1 + if [ $? != 0 ]; then + error "oss_capability_switch 1" + return 3 + fi # proc variable disabled -- access to the objects in the filesystem # is not allowed @@ -489,11 +373,15 @@ test_5() { "-- access to the objects in the filesystem is denied." $WTL $file 30 if [ $? == 0 ]; then - echo "Write worked well even though secrets not supplied." - return 3 + error "Write worked well even though secrets not supplied." + return 4 fi - turn_capability_on || return 4 + turn_capability_on + if [ $? != 0 ]; then + error "turn_capability_on" + return 4 + fi sleep 5 # proc variable enabled, secrets supplied -- write should work now @@ -501,14 +389,18 @@ test_5() { "-- write should work now)." $WTL $file 30 if [ $? != 0 ]; then - echo "Write failed even though secrets supplied." + error "Write failed even though secrets supplied." return 5 fi turn_capability_off + if [ $? != 0 ]; then + error "turn_capability_off" + return 7 + fi rm -f $file } -sec_run_test 5 "capa secrets =========================" +run_test 5 "capa secrets =========================" # Expiry: A test program is performing I/O on a file. It has credential # with an expiry half a minute later. While the program is running the @@ -517,51 +409,76 @@ sec_run_test 5 "capa secrets =========================" test_6() { local file=$DIR/f6 - [ -z "$MDT" ] && sec_skip "do not support do_facet operations." && return + [ -z "$MDT" ] && skip "do not support do_facet operations." && return turn_capability_off + if [ $? != 0 ]; then + error "turn_capability_off" + return 1 + fi rm -f $file - turn_capability_on 30 || return 1 + turn_capability_on 30 + if [ $? != 0 ]; then + error "turn_capability_on 30" + return 2 + fi # Token expiry - $WTL $file 60 || return 2 + $WTL $file 60 + if [ $? != 0 ]; then + error "$WTL $file 60" + return 3 + fi # Reset MDS capability timeout - mds_capability_timeout 30 || exit 3 + mds_capability_timeout 30 + if [ $? != 0 ]; then + error "mds_capability_timeout 30" + return 4 + fi $WTL $file 60 & local PID=$! sleep 5 # To disable automatic renew, only need turn capa off on MDS. - mds_capability_switch 0 || return 4 + mds_capability_switch 0 + if [ $? != 0 ]; then + error "mds_capability_switch 0" + return 5 + fi echo "We expect I/O failure." wait $PID if [ $? == 0 ]; then echo "no I/O failure got." - return 5 + return 6 fi turn_capability_off + if [ $? != 0 ]; then + error "turn_capability_off" + return 7 + fi rm -f $file } -sec_run_test 6 "capa expiry =========================" +run_test 6 "capa expiry =========================" log "cleanup: ======================================================" -unsetup() { - if [ ! -z "$MDT" ]; then - do_facet $SINGLEMDS echo $IDENTITY_UPCALL_BAK > $IDENTITY_UPCALL - do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH - fi +sec_unsetup() { + for num in `seq $MDSCOUNT`; do + if [ "${identity_old[$num]}" = 1 ]; then + switch_identity $num false || identity_old[$num]=$? + fi + done + $RUNAS -u $ID0 ls $DIR $RUNAS -u $ID1 ls $DIR - $RUNAS -u $ID2 ls $DIR } -unsetup +sec_unsetup sec_cleanup() { - if [ "$S_MOUNTED" = "yes" ]; then - cleanupall -f || sec_error "cleanup failed" + if [ "$I_MOUNTED" = "yes" ]; then + cleanupall -f || error "sec_cleanup" fi } sec_cleanup diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index a29a855..fd9c990 100644 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -830,7 +830,7 @@ test_27c() { [ `$GETSTRIPE $DIR/d27/f01 | grep -A 10 obdidx | wc -l` -eq 4 ] || error "two-stripe file doesn't have two stripes" pass - log "== test_27d: write to two stripe file file f01 ================" + log "== test_27c: write to two stripe file file f01 ================" dd if=/dev/zero of=$DIR/d27/f01 bs=4k count=4 || error "dd failed" } run_test 27c "create two stripe file f01 =======================" @@ -2921,12 +2921,6 @@ test_66() { } run_test 66 "update inode blocks count on client ===============" -test_67() { - [ ! -f sanity-sec.sh ] && skip "missing subtest sanity-sec.sh" && return - sh sanity-sec.sh -} -run_test 67 "security test =====================================" - LLOOP= cleanup_68() { trap 0 @@ -3274,6 +3268,13 @@ run_test 76 "destroy duplicate inodes in client inode cache ====" export ORIG_CSUM="" set_checksums() { + # Note: in sptlrpc modes which enable its own bulk checksum, the + # original crc32_le bulk checksum will be automatically disabled, + # and the OBD_FAIL_OSC_CHECKSUM_SEND/OBD_FAIL_OSC_CHECKSUM_RECEIVE + # will be checked by sptlrpc code against sptlrpc bulk checksum. + # In this case set_checksums() will not be no-op, because sptlrpc + # bulk checksum will be enabled all through the test. + [ "$ORIG_CSUM" ] || ORIG_CSUM=`cat $LPROC/osc/*/checksums | head -n1` for f in $LPROC/osc/*/checksums; do echo $1 >> $f @@ -3872,6 +3873,12 @@ test_103 () { [ -z "$(which setfacl 2>/dev/null)" ] && skip "could not find setfacl" && return $GSS && skip "could not run under gss" && return + declare -a identity_old + + for num in `seq $MDSCOUNT`; do + switch_identity $num true || identity_old[$num]=$? + done + SAVE_UMASK=`umask` umask 0022 cd $DIR @@ -3882,9 +3889,8 @@ test_103 () { run_acl_subtest getfacl-noacl || error echo "performing misc..." run_acl_subtest misc || error -# XXX add back permission test when we support supplementary groups. -# echo "performing permissions..." -# run_acl_subtest permissions || error + echo "performing permissions..." + run_acl_subtest permissions || error echo "performing setfacl..." run_acl_subtest setfacl || error @@ -3897,6 +3903,12 @@ test_103 () { cd $SAVE_PWD umask $SAVE_UMASK + + for num in `seq $MDSCOUNT`; do + if [ "${identity_old[$num]}" = 1 ]; then + switch_identity $num false || identity_old[$num]=$? + fi + done } run_test 103 "acl test =========================================" diff --git a/lustre/tests/test-framework.sh b/lustre/tests/test-framework.sh index 2633f1a..d7fafbe 100644 --- a/lustre/tests/test-framework.sh +++ b/lustre/tests/test-framework.sh @@ -13,6 +13,7 @@ export CATASTROPHE=${CATASTROPHE:-/proc/sys/lnet/catastrophe} export GSS=false export GSS_KRB5=false export GSS_PIPEFS=false +export IDENTITY_UPCALL=false #export PDSH="pdsh -S -Rssh -w" # eg, assert_env LUSTRE MDSNODES OSTNODES CLIENTS @@ -77,10 +78,17 @@ init_test_env() { export PATH=:$PATH:$LUSTRE/utils:$LUSTRE/utils/gss:$LUSTRE/tests export LCTL=${LCTL:-"$LUSTRE/utils/lctl"} - export LFS=${LFS:-"$LUSTRE/utils/lfs"} [ ! -f "$LCTL" ] && export LCTL=$(which lctl) export LFS=${LFS:-"$LUSTRE/utils/lfs"} [ ! -f "$LFS" ] && export LFS=$(which lfs) + export L_GETIDENTITY=${L_GETIDENTITY:-"$LUSTRE/utils/l_getidentity"} + if [ ! -f "$L_GETIDENTITY" ]; then + if `which l_getidentity > /dev/null 2>&1`; then + export L_GETIDENTITY=$(which l_getidentity) + else + export L_GETIDENTITY=NONE + fi + fi export MKFS=${MKFS:-"$LUSTRE/utils/mkfs.lustre"} [ ! -f "$MKFS" ] && export MKFS=$(which mkfs.lustre) export TUNEFS=${TUNEFS:-"$LUSTRE/utils/tunefs.lustre"} @@ -90,7 +98,10 @@ init_test_env() { export NAME=${NAME:-local} export LPROC=/proc/fs/lustre export LGSSD=${LGSSD:-"$LUSTRE/utils/gss/lgssd"} + [ "$GSS_PIPEFS" = "true" ] && [ ! -f "$LGSSD" ] && \ + export LGSSD=$(which lgssd) export LSVCGSSD=${LSVCGSSD:-"$LUSTRE/utils/gss/lsvcgssd"} + [ ! -f "$LSVCGSSD" ] && export LSVCGSSD=$(which lsvcgssd) export KRB5DIR=${KRB5DIR:-"/usr/kerberos"} export DIR2 @@ -106,6 +117,15 @@ init_test_env() { ;; esac + case "x$ID" in + xtrue) + IDENTITY_UPCALL=true + ;; + xfalse) + IDENTITY_UPCALL=false + ;; + esac + # Paths on remote nodes, if different export RLUSTRE=${RLUSTRE:-$LUSTRE} export RPWD=${RPWD:-$PWD} @@ -339,18 +359,13 @@ stop_gss_daemons() { send_sigint client lgssd } -init_krb5_env() { - if [ ! -z $SEC ]; then - MDS_MOUNT_OPTS=$MDS_MOUNT_OPTS,sec=$SEC - OST_MOUNT_OPTS=$OST_MOUNT_OPTS,sec=$SEC - fi - +init_gss() { if $GSS; then start_gss_daemons fi } -cleanup_krb5_env() { +cleanup_gss() { if $GSS; then stop_gss_daemons # maybe cleanup credential cache? @@ -847,7 +862,7 @@ stopall() { cleanupall() { stopall $* unload_modules - cleanup_krb5_env + cleanup_gss } mdsmkfsopts() @@ -859,6 +874,11 @@ mdsmkfsopts() formatall() { [ "$FSTYPE" ] && FSTYPE_OPT="--backfstype $FSTYPE" + if [ ! -z $SEC ]; then + MDS_MKFS_OPTS="$MDS_MKFS_OPTS --param srpc.flavor.default=$SEC" + OST_MKFS_OPTS="$OST_MKFS_OPTS --param srpc.flavor.default=$SEC" + fi + stopall # We need ldiskfs here, may as well load them all load_modules @@ -887,9 +907,40 @@ mount_client() { grep " $1 " /proc/mounts || zconf_mount `hostname` $* } +# return value: +# 0: success, the old identity set already. +# 1: success, the old identity does not set. +# 2: fail. +switch_identity() { + local num=$1 + local switch=$2 + local j=`expr $num - 1` + local MDT="`do_facet mds$num ls -l $LPROC/mdt/ 2>/dev/null | grep MDT | awk '{print $9}' | grep $j$`" + + if [ -z "$MDT" ]; then + return 2 + fi + + local old="`do_facet mds$num cat $LPROC/mdt/$MDT/identity_upcall`" + + if [ $switch ]; then + do_facet mds$num "echo \"$L_GETIDENTITY\" > $LPROC/mdt/$MDT/identity_upcall" + else + do_facet mds$num "echo \"NONE\" > $LPROC/mdt/$MDT/identity_upcall" + fi + + do_facet mds$num "echo \"-1\" > $LPROC/mdt/$MDT/identity_flush" + + if [ $old = "NONE" ]; then + return 1 + else + return 0 + fi +} + setupall() { load_modules - init_krb5_env + init_gss if [ -z "$CLIENTONLY" ]; then echo "Setup mdts, osts" for num in `seq $MDSCOUNT`; do @@ -897,6 +948,7 @@ setupall() { echo $REFORMAT | grep -q "reformat" \ || do_facet mds$num "$TUNEFS --writeconf $DEVNAME" start mds$num $DEVNAME $MDS_MOUNT_OPTS + switch_identity $num $IDENTITY_UPCALL done for num in `seq $OSTCOUNT`; do DEVNAME=$(ostdevname $num) diff --git a/lustre/utils/Makefile.am b/lustre/utils/Makefile.am index a7ee8f4..f0339d6 100644 --- a/lustre/utils/Makefile.am +++ b/lustre/utils/Makefile.am @@ -19,7 +19,7 @@ noinst_PROGRAMS = wirecheck wiretest obdio obdbarrier # mount only finds helpers in /sbin rootsbin_PROGRAMS = mount.lustre sbin_PROGRAMS = mkfs.lustre tunefs.lustre lctl \ - l_getidentity l_facl llverfs llverdev \ + l_getidentity llverfs llverdev \ llog_reader lr_reader if LIBPTHREAD sbin_PROGRAMS += loadgen @@ -97,10 +97,6 @@ l_getidentity_SOURCES = l_getidentity.c l_getidentity_LDADD := $(LIBPTLCTL) l_getidentity_DEPENDENCIES := $(LIBPTLCTL) -l_facl_SOURCES = l_facl.c -l_facl_LDADD := liblustreapi.a -l_facl_DEPENDENCIES := liblustreapi.a - EXTRA_DIST = $(sbin_scripts) $(bin_scripts) # NOTE: this should only be run on i386. diff --git a/lustre/utils/gss/lgss_keyring.c b/lustre/utils/gss/lgss_keyring.c index cf267ad..840e14c 100644 --- a/lustre/utils/gss/lgss_keyring.c +++ b/lustre/utils/gss/lgss_keyring.c @@ -53,6 +53,8 @@ static char *g_service = NULL; */ struct lgss_nego_data { uint32_t lnd_established:1; + + int lnd_secid; uint32_t lnd_uid; uint32_t lnd_lsvc; char *lnd_uuid; @@ -82,8 +84,11 @@ struct lgss_init_res { struct keyring_upcall_param { uint32_t kup_ver; + uint32_t kup_secid; uint32_t kup_uid; + uint32_t kup_fsuid; uint32_t kup_gid; + uint32_t kup_fsgid; uint32_t kup_svc; uint64_t kup_nid; char kup_tgt[64]; @@ -118,6 +123,7 @@ int do_nego_rpc(struct lgss_nego_data *lnd, } param.version = GSSD_INTERFACE_VERSION; + param.secid = lnd->lnd_secid; param.uuid = lnd->lnd_uuid; param.lustre_svc = lnd->lnd_lsvc; param.uid = lnd->lnd_uid; @@ -184,7 +190,7 @@ int do_nego_rpc(struct lgss_nego_data *lnd, /* * if return error, the lnd_rpc_err or lnd_gss_err is set. */ -int lgssc_negotiation(struct lgss_nego_data *lnd) +static int lgssc_negotiation(struct lgss_nego_data *lnd) { struct lgss_init_res gr; gss_buffer_desc *recv_tokenp, send_token; @@ -289,15 +295,16 @@ int lgssc_negotiation(struct lgss_nego_data *lnd) /* * if return error, the lnd_rpc_err or lnd_gss_err is set. */ -int lgssc_init_nego_data(struct lgss_nego_data *lnd, - struct keyring_upcall_param *kup, - lgss_mech_t mech) +static int lgssc_init_nego_data(struct lgss_nego_data *lnd, + struct keyring_upcall_param *kup, + lgss_mech_t mech) { gss_buffer_desc sname; OM_uint32 maj_stat, min_stat; memset(lnd, 0, sizeof(*lnd)); + lnd->lnd_secid = kup->kup_secid; lnd->lnd_uid = kup->kup_uid; lnd->lnd_lsvc = kup->kup_svc; lnd->lnd_uuid = kup->kup_tgt; @@ -443,10 +450,10 @@ out: } /* - * note we can't assume authority in child process + * note we inherited assumed authority from parent process */ -int lgssc_kr_negotiate(key_serial_t keyid, struct lgss_cred *cred, - struct keyring_upcall_param *kup) +static int lgssc_kr_negotiate(key_serial_t keyid, struct lgss_cred *cred, + struct keyring_upcall_param *kup) { struct lgss_nego_data lnd; gss_buffer_desc token = GSS_C_EMPTY_BUFFER; @@ -454,47 +461,28 @@ int lgssc_kr_negotiate(key_serial_t keyid, struct lgss_cred *cred, int rc = -1; logmsg(LL_TRACE, "child start on behalf of key %08x: " - "cred %p, uid %u, svc %u, nid %Lx\n", keyid, cred, - cred->lc_uid, cred->lc_tgt_svc, cred->lc_tgt_nid); - - if (kup->kup_gid != 0 && setregid(kup->kup_gid, kup->kup_gid)) { - logmsg(LL_WARN, "key %08x, failed set gids to %u: %s\n", - keyid, kup->kup_gid, strerror(errno)); - } - - if (kup->kup_uid != 0 && setreuid(kup->kup_uid, kup->kup_uid)) { - logmsg(LL_WARN, "key %08x, failed set uids to %u: %s\n", - keyid, kup->kup_uid, strerror(errno)); - } - - /* - * link to session keyring, allow the key to be found. - */ - if (keyctl_link(keyid, KEY_SPEC_SESSION_KEYRING)) { - logmsg(LL_ERR, "key %08x, failed to link to session " - "keyring: %s\n", keyid, strerror(errno)); - error_kernel_key(keyid, -EACCES, 0); - goto out_cred; - } + "cred %p, uid %u, svc %u, nid %Lx, uids: %u:%u/%u:%u\n", + keyid, cred, cred->lc_uid, cred->lc_tgt_svc, cred->lc_tgt_nid, + kup->kup_uid, kup->kup_gid, kup->kup_fsuid, kup->kup_fsgid); if (lgss_get_service_str(&g_service, kup->kup_svc, kup->kup_nid)) { logmsg(LL_ERR, "key %08x: failed to construct service " "string\n", keyid); error_kernel_key(keyid, -EACCES, 0); - goto out_unlink; + goto out_cred; } if (lgss_using_cred(cred)) { logmsg(LL_ERR, "key %08x: can't using cred\n", keyid); error_kernel_key(keyid, -EACCES, 0); - goto out_unlink; + goto out_cred; } if (lgssc_init_nego_data(&lnd, kup, cred->lc_mech->lmt_mech_n)) { logmsg(LL_ERR, "key %08x: failed to initialize " "negotiation data\n", keyid); error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err); - goto out_unlink; + goto out_cred; } rc = lgssc_negotiation(&lnd); @@ -524,12 +512,6 @@ out: lgssc_fini_nego_data(&lnd); -out_unlink: - if (keyctl_unlink(keyid, KEY_SPEC_SESSION_KEYRING)) { - logmsg(LL_WARN, "failed to unlink key %08x: %s\n", - keyid, strerror(errno)); - } - out_cred: lgss_release_cred(cred); return rc; @@ -537,21 +519,24 @@ out_cred: /* * call out info format: s[:s]... - * [0]: mech_name (string) - * [1]: flags (chars) FMT: r-root; m-mds - * [2]: lustre_svc (uint) - * [3]: target_nid (uint64) - * [4]: target_uuid (string) + * [0]: secid (uint) + * [1]: mech_name (string) + * [2]: uid (uint) + * [3]: gid (uint) + * [4]: flags (chars) FMT: r-root; m-mds + * [5]: lustre_svc (uint) + * [6]: target_nid (uint64) + * [7]: target_uuid (string) */ -static -int parse_callout_info(const char *coinfo, - struct keyring_upcall_param *uparam) +static int parse_callout_info(const char *coinfo, + struct keyring_upcall_param *uparam) { - char buf[1024]; - char *string = buf; - int length, i; - char *data[5]; - char *pos; + const int nargs = 8; + char buf[1024]; + char *string = buf; + int length, i; + char *data[nargs]; + char *pos; length = strlen(coinfo) + 1; if (length > 1024) { @@ -560,7 +545,7 @@ int parse_callout_info(const char *coinfo, } memcpy(buf, coinfo, length); - for (i = 0; i < 4; i++) { + for (i = 0; i < nargs - 1; i++) { pos = strchr(string, ':'); if (pos == NULL) { logmsg(LL_ERR, "short of components\n"); @@ -573,22 +558,28 @@ int parse_callout_info(const char *coinfo, } data[i] = string; - logmsg(LL_TRACE, "components: %s,%s,%s,%s,%s\n", - data[0], data[1], data[2], data[3], data[4], data[5]); + logmsg(LL_TRACE, "components: %s,%s,%s,%s,%s,%s,%s,%s\n", + data[0], data[1], data[2], data[3], data[4], data[5], + data[6], data[7]); - strncpy(uparam->kup_mech, data[0], sizeof(uparam->kup_mech)); - if (strchr(data[1], 'r')) + uparam->kup_secid = strtol(data[0], NULL, 0); + strncpy(uparam->kup_mech, data[1], sizeof(uparam->kup_mech)); + uparam->kup_uid = strtol(data[2], NULL, 0); + uparam->kup_gid = strtol(data[3], NULL, 0); + if (strchr(data[4], 'r')) uparam->kup_is_root = 1; - if (strchr(data[1], 'm')) + if (strchr(data[4], 'm')) uparam->kup_is_mds = 1; - uparam->kup_svc = strtol(data[2], NULL, 0); - uparam->kup_nid = strtoll(data[3], NULL, 0); - strncpy(uparam->kup_tgt, data[4], sizeof(uparam->kup_tgt)); - - logmsg(LL_DEBUG, "parse call out info: mech %s, is_root %d, " - "is_mds %d, svc %d, nid 0x%Lx, tgt %s\n", - uparam->kup_mech, uparam->kup_is_root, uparam->kup_is_mds, - uparam->kup_svc, uparam->kup_nid, uparam->kup_tgt); + uparam->kup_svc = strtol(data[5], NULL, 0); + uparam->kup_nid = strtoll(data[6], NULL, 0); + strncpy(uparam->kup_tgt, data[7], sizeof(uparam->kup_tgt)); + + logmsg(LL_DEBUG, "parse call out info: secid %d, mech %s, ugid %u:%u " + "is_root %d, is_mds %d, svc %d, nid 0x%Lx, tgt %s\n", + uparam->kup_secid, uparam->kup_mech, + uparam->kup_uid, uparam->kup_gid, + uparam->kup_is_root, uparam->kup_is_mds, uparam->kup_svc, + uparam->kup_nid, uparam->kup_tgt); return 0; } @@ -625,8 +616,8 @@ int main(int argc, char *argv[]) return 1; } - logmsg(LL_INFO, "key %s, desc %s, uid %s, sring %s, coinfo %s\n", - argv[2], argv[4], argv[6], argv[10], argv[5]); + logmsg(LL_INFO, "key %s, desc %s, ugid %s:%s, sring %s, coinfo %s\n", + argv[2], argv[4], argv[6], argv[7], argv[10], argv[5]); memset(&uparam, 0, sizeof(uparam)); @@ -640,11 +631,16 @@ int main(int argc, char *argv[]) return 1; } - if (sscanf(argv[6], "%d", &uparam.kup_uid) != 1) { + if (sscanf(argv[6], "%d", &uparam.kup_fsuid) != 1) { logmsg(LL_ERR, "can't extract UID: %s\n", argv[6]); return 1; } + if (sscanf(argv[7], "%d", &uparam.kup_fsgid) != 1) { + logmsg(LL_ERR, "can't extract GID: %s\n", argv[7]); + return 1; + } + if (sscanf(argv[10], "%d", &sring) != 1) { logmsg(LL_ERR, "can't extract session keyring: %s\n", argv[10]); return 1; @@ -692,11 +688,16 @@ int main(int argc, char *argv[]) return 1; } - /* - * pre initialize the key + /* pre initialize the key. note the keyring linked to is actually of the + * original requesting process, not _this_ upcall process. if it's for + * root user, don't link to any keyrings because we want fully control + * on it, and share it among all root sessions; otherswise link to + * session keyring. */ - inst_keyring = (cred->lc_fl_root || cred->lc_fl_mds) ? - 0 : KEY_SPEC_SESSION_KEYRING; + if (cred->lc_fl_root || cred->lc_fl_mds) + inst_keyring = 0; + else + inst_keyring = KEY_SPEC_SESSION_KEYRING; if (keyctl_instantiate(keyid, NULL, 0, inst_keyring)) { logmsg(LL_ERR, "instantiate key %08x: %s\n", diff --git a/lustre/utils/gss/lgss_krb5_utils.c b/lustre/utils/gss/lgss_krb5_utils.c index 0a4d44d..7ebbfd2 100644 --- a/lustre/utils/gss/lgss_krb5_utils.c +++ b/lustre/utils/gss/lgss_krb5_utils.c @@ -232,9 +232,9 @@ int princ_is_local_realm(krb5_context ctx, krb5_principal princ) } static -int svc_princ_is_local_host(krb5_context ctx, - krb5_principal princ, - loglevel_t loglevel) +int svc_princ_verify_host(krb5_context ctx, + krb5_principal princ, + loglevel_t loglevel) { struct utsname utsbuf; struct hostent *host; @@ -297,17 +297,24 @@ int lkrb5_cc_check_tgt_princ(krb5_context ctx, return -1; } - /* if it's mds service principal, check hostname */ + /* if it's mds service principal, or lustre_root principal + * with host part, verify the hostname. + * note we allow lustre_root without host part */ if (lgss_krb5_strcmp(krb5_princ_name(ctx, princ), LGSS_SVC_MDS_STR) == 0) { - if (svc_princ_is_local_host(ctx, princ, LL_WARN)) { - logmsg(LL_WARN, "mds service principal not belongs " + if (svc_princ_verify_host(ctx, princ, LL_WARN)) { + logmsg(LL_WARN, "mds service principal doesn't belong " "to this node\n"); return -1; } } else if (lgss_krb5_strcmp(krb5_princ_name(ctx, princ), - LGSS_USR_ROOT_STR)) { - /* do nothing */ + LGSS_USR_ROOT_STR) == 0) { + if (krb5_princ_component(ctx, princ, 1) != NULL && + svc_princ_verify_host(ctx, princ, LL_WARN)) { + logmsg(LL_WARN, "lustre_root principal doesn't belong " + "to this node\n"); + return -1; + } } else { logmsg(LL_WARN, "unexpected krb5 cc principal name %.*s\n", krb5_princ_name(ctx, princ)->length, @@ -556,8 +563,9 @@ int lkrb5_refresh_root_tgt_cc(krb5_context ctx, krb5_keytab kt; krb5_keytab_entry kte; krb5_kt_cursor cursor; - krb5_principal princ = NULL; + krb5_principal princ = NULL, princ2; krb5_error_code code; + int general_root = 0; int rc = -1; /* prepare parsing the keytab file */ @@ -592,32 +600,59 @@ int lkrb5_refresh_root_tgt_cc(krb5_context ctx, if (!princ_is_local_realm(ctx, kte.principal)) continue; - /* lustre_root@realm */ + /* lustre_root[/host]@realm */ if (lgss_krb5_strcmp(krb5_princ_name(ctx, kte.principal), LGSS_USR_ROOT_STR) == 0) { - if (princ != NULL) { - logmsg(LL_WARN, "already picked one? " - "how could it possible???\n"); - continue; + int tmp_general_root = 0; + + if (krb5_princ_component(ctx, kte.principal,1) == NULL){ + if (princ != NULL) { + logmsg(LL_TRACE, "lustre_root: " + "already picked one, skip\n"); + continue; + } + + tmp_general_root = 1; + } else { + if (svc_princ_verify_host(ctx, kte.principal, + LL_TRACE)) { + logmsg(LL_TRACE, "lustre_root: " + "doesn't belong to this node\n"); + continue; + } + + if (princ != NULL && !general_root) { + logmsg(LL_TRACE, "lustre_root: already " + "have a host-specific one, " + "skip\n"); + continue; + } } - code = krb5_copy_principal(ctx, kte.principal, &princ); - if (code) + code = krb5_copy_principal(ctx, kte.principal, &princ2); + if (code) { logmsg(LL_ERR, "copy lustre_root princ: %s\n", krb5_err_msg(code)); + continue; + } + + if (princ != NULL) { + logmsg(LL_TRACE, "release a lustre_root one\n"); + krb5_free_principal(ctx, princ); + } + princ = princ2; + general_root = tmp_general_root; continue; } /* lustre_mds/host@realm */ if (lgss_krb5_strcmp(krb5_princ_name(ctx, kte.principal), LGSS_SVC_MDS_STR) == 0) { - krb5_principal princ2; - - if (svc_princ_is_local_host(ctx, kte.principal, - LL_TRACE)) { + if (svc_princ_verify_host(ctx, kte.principal, + LL_TRACE)) { logmsg(LL_TRACE, "mds service principal: " - "not belongs to this node\n"); + "doesn't belong to this node\n"); continue; } diff --git a/lustre/utils/gss/lsupport.c b/lustre/utils/gss/lsupport.c index a5f0146..b629cb6 100644 --- a/lustre/utils/gss/lsupport.c +++ b/lustre/utils/gss/lsupport.c @@ -586,7 +586,7 @@ libcfs_str2nid(char *str) #define MAX_LINE_LEN 256 struct user_map_item { - char *principal; /* NULL means match all, will cause multi->single mapped, FORBID */ + char *principal; /* NULL means match all */ lnet_nid_t nid; uid_t uid; }; @@ -604,7 +604,9 @@ void cleanup_mapping(void) { if (mapping.items) { for (; mapping.nitems > 0; mapping.nitems--) - free(mapping.items[mapping.nitems - 1].principal); + if (mapping.items[mapping.nitems-1].principal) + free(mapping.items[mapping.nitems-1].principal); + free(mapping.items); mapping.items = NULL; } @@ -630,7 +632,8 @@ static int grow_mapping(int nitems) } if (mapping.items) { - memcpy(new, mapping.items, mapping.nitems * sizeof(struct user_map_item)); + memcpy(new, mapping.items, + mapping.nitems * sizeof(struct user_map_item)); free(mapping.items); } mapping.items = new; @@ -690,8 +693,7 @@ static int read_mapping_db(void) } if (!strcmp(princ, "*")) { - printerr(0, "NOT permit \"*\" princ, it will cause multi->single mapped\n"); - continue; + name = NULL; } else { name = strdup(princ); if (!name) { @@ -706,6 +708,7 @@ static int read_mapping_db(void) nid = libcfs_str2nid(nid_str); if (nid == LNET_NID_ANY) { printerr(0, "fail to parse nid %s\n", nid_str); + if (name) free(name); continue; } @@ -714,6 +717,7 @@ static int read_mapping_db(void) dest_uid = parse_uid(dest); if (dest_uid == -1) { printerr(0, "no valid user: %s\n", dest); + if (name) free(name); continue; } @@ -721,6 +725,7 @@ static int read_mapping_db(void) if (grow_mapping(mapping.nitems + 1)) { printerr(0, "fail to grow mapping to %d\n", mapping.nitems + 1); + if (name) free(name); fclose(f); return -1; @@ -780,7 +785,7 @@ int lookup_mapping(char *princ, lnet_nid_t nid, uid_t *uid) if (entry->nid != LNET_NID_ANY && entry->nid != nid) continue; - if (!strcasecmp(entry->principal, princ)) { + if (!entry->principal || !strcasecmp(entry->principal, princ)) { printerr(1, "found mapping: %s ==> %d\n", princ, entry->uid); *uid = entry->uid; diff --git a/lustre/utils/gss/lsupport.h b/lustre/utils/gss/lsupport.h index 6739804..6748ecd 100644 --- a/lustre/utils/gss/lsupport.h +++ b/lustre/utils/gss/lsupport.h @@ -36,6 +36,7 @@ struct lgssd_upcall_data { struct lgssd_ioctl_param { int version; /* in */ + int secid; /* in */ char *uuid; /* in */ int lustre_svc; /* in */ uid_t uid; /* in */ diff --git a/lustre/utils/gss/nfs-utils-1.0.11-lustre.diff b/lustre/utils/gss/nfs-utils-1.0.11-lustre.diff index 46efbcf..e0f551b 100644 --- a/lustre/utils/gss/nfs-utils-1.0.11-lustre.diff +++ b/lustre/utils/gss/nfs-utils-1.0.11-lustre.diff @@ -1,6 +1,6 @@ -diff -Nrup nfs-utils-1.0.11/configure.in nfs-utils-1.0.11.lustre/configure.in ---- nfs-utils-1.0.11/configure.in 2007-02-21 21:50:03.000000000 -0700 -+++ nfs-utils-1.0.11.lustre/configure.in 2007-06-29 12:29:20.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/configure.in nfs-utils-1.0.11/configure.in +--- nfs-utils-1.0.11.lustre/configure.in 2007-02-21 21:50:03.000000000 -0700 ++++ nfs-utils-1.0.11/configure.in 2008-01-02 18:10:29.000000000 -0700 @@ -18,61 +18,14 @@ AC_ARG_WITH(release, RELEASE=$withval, RELEASE=1) @@ -191,9 +191,9 @@ diff -Nrup nfs-utils-1.0.11/configure.in nfs-utils-1.0.11.lustre/configure.in + utils/gssd/Makefile]) AC_OUTPUT -diff -Nrup nfs-utils-1.0.11/Makefile.am nfs-utils-1.0.11.lustre/Makefile.am ---- nfs-utils-1.0.11/Makefile.am 2007-02-21 21:50:03.000000000 -0700 -+++ nfs-utils-1.0.11.lustre/Makefile.am 2007-06-29 12:29:20.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/Makefile.am nfs-utils-1.0.11/Makefile.am +--- nfs-utils-1.0.11.lustre/Makefile.am 2007-02-21 21:50:03.000000000 -0700 ++++ nfs-utils-1.0.11/Makefile.am 2008-01-02 18:10:29.000000000 -0700 @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in @@ -202,9 +202,9 @@ diff -Nrup nfs-utils-1.0.11/Makefile.am nfs-utils-1.0.11.lustre/Makefile.am MAINTAINERCLEANFILES = Makefile.in -diff -Nrup nfs-utils-1.0.11/utils/gssd/cacheio.c nfs-utils-1.0.11.lustre/utils/gssd/cacheio.c ---- nfs-utils-1.0.11/utils/gssd/cacheio.c 2007-02-21 21:50:03.000000000 -0700 -+++ nfs-utils-1.0.11.lustre/utils/gssd/cacheio.c 2007-06-29 12:32:27.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/cacheio.c nfs-utils-1.0.11/utils/gssd/cacheio.c +--- nfs-utils-1.0.11.lustre/utils/gssd/cacheio.c 2007-02-21 21:50:03.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/cacheio.c 2008-01-02 18:11:38.000000000 -0700 @@ -240,7 +240,8 @@ int qword_get(char **bpp, char *dest, in return -1; while (*bp == ' ') bp++; @@ -215,9 +215,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/cacheio.c nfs-utils-1.0.11.lustre/utils/g return len; } -diff -Nrup nfs-utils-1.0.11/utils/gssd/context.c nfs-utils-1.0.11.lustre/utils/gssd/context.c ---- nfs-utils-1.0.11/utils/gssd/context.c 2007-02-21 21:50:03.000000000 -0700 -+++ nfs-utils-1.0.11.lustre/utils/gssd/context.c 2007-06-29 12:32:28.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/context.c nfs-utils-1.0.11/utils/gssd/context.c +--- nfs-utils-1.0.11.lustre/utils/gssd/context.c 2007-02-21 21:50:03.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/context.c 2008-01-02 18:11:38.000000000 -0700 @@ -33,11 +33,14 @@ #include #include @@ -238,9 +238,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/context.c nfs-utils-1.0.11.lustre/utils/g #include "context.h" int -diff -Nrup nfs-utils-1.0.11/utils/gssd/context.h nfs-utils-1.0.11.lustre/utils/gssd/context.h ---- nfs-utils-1.0.11/utils/gssd/context.h 2007-06-29 12:28:01.000000000 -0600 -+++ nfs-utils-1.0.11.lustre/utils/gssd/context.h 2007-06-29 12:32:29.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/context.h nfs-utils-1.0.11/utils/gssd/context.h +--- nfs-utils-1.0.11.lustre/utils/gssd/context.h 2008-01-02 17:22:48.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/context.h 2008-01-02 18:11:38.000000000 -0700 @@ -31,8 +31,6 @@ #ifndef _CONTEXT_H_ #define _CONTEXT_H_ @@ -250,9 +250,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/context.h nfs-utils-1.0.11.lustre/utils/g /* Hopefully big enough to hold any serialized context */ #define MAX_CTX_LEN 4096 -diff -Nrup nfs-utils-1.0.11/utils/gssd/context_heimdal.c nfs-utils-1.0.11.lustre/utils/gssd/context_heimdal.c ---- nfs-utils-1.0.11/utils/gssd/context_heimdal.c 2007-02-21 21:50:03.000000000 -0700 -+++ nfs-utils-1.0.11.lustre/utils/gssd/context_heimdal.c 2007-06-29 12:32:29.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/context_heimdal.c nfs-utils-1.0.11/utils/gssd/context_heimdal.c +--- nfs-utils-1.0.11.lustre/utils/gssd/context_heimdal.c 2007-02-21 21:50:03.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/context_heimdal.c 2008-01-02 18:11:38.000000000 -0700 @@ -43,8 +43,13 @@ #ifdef HAVE_COM_ERR_H #include @@ -269,9 +269,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/context_heimdal.c nfs-utils-1.0.11.lustre #include "write_bytes.h" int write_heimdal_keyblock(char **p, char *end, krb5_keyblock *key) -diff -Nrup nfs-utils-1.0.11/utils/gssd/context_lucid.c nfs-utils-1.0.11.lustre/utils/gssd/context_lucid.c ---- nfs-utils-1.0.11/utils/gssd/context_lucid.c 2007-06-29 12:28:01.000000000 -0600 -+++ nfs-utils-1.0.11.lustre/utils/gssd/context_lucid.c 2007-06-29 12:32:30.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/context_lucid.c nfs-utils-1.0.11/utils/gssd/context_lucid.c +--- nfs-utils-1.0.11.lustre/utils/gssd/context_lucid.c 2008-01-02 17:22:48.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/context_lucid.c 2008-01-02 18:11:38.000000000 -0700 @@ -41,11 +41,7 @@ #include #include @@ -410,10 +410,10 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/context_lucid.c nfs-utils-1.0.11.lustre/u maj_stat = gss_export_lucid_sec_context(&min_stat, &ctx, 1, &return_ctx); if (maj_stat != GSS_S_COMPLETE) { -diff -Nrup nfs-utils-1.0.11/utils/gssd/context_mit.c nfs-utils-1.0.11.lustre/utils/gssd/context_mit.c ---- nfs-utils-1.0.11/utils/gssd/context_mit.c 2007-06-29 12:28:01.000000000 -0600 -+++ nfs-utils-1.0.11.lustre/utils/gssd/context_mit.c 2007-06-29 12:32:30.000000000 -0600 -@@ -39,10 +39,14 @@ +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/context_mit.c nfs-utils-1.0.11/utils/gssd/context_mit.c +--- nfs-utils-1.0.11.lustre/utils/gssd/context_mit.c 2008-01-02 17:22:48.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/context_mit.c 2008-01-02 18:11:38.000000000 -0700 +@@ -39,10 +39,15 @@ #include #include #include @@ -424,6 +424,7 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/context_mit.c nfs-utils-1.0.11.lustre/uti + +#ifdef _NEW_BUILD_ +# include "lgss_utils.h" ++# include "write_bytes.h" +#else +# include "gss_util.h" +# include "gss_oids.h" @@ -432,7 +433,7 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/context_mit.c nfs-utils-1.0.11.lustre/uti #include "context.h" #include -@@ -333,12 +337,7 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss +@@ -333,12 +338,7 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss * keydata-2; ( Ki (Kseq for DES3) ) * keydata-3; ( Kc (derived checksum key) ) */ @@ -446,9 +447,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/context_mit.c nfs-utils-1.0.11.lustre/uti if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err; /* Only applicable flag for this is initiator */ -diff -Nrup nfs-utils-1.0.11/utils/gssd/context_spkm3.c nfs-utils-1.0.11.lustre/utils/gssd/context_spkm3.c ---- nfs-utils-1.0.11/utils/gssd/context_spkm3.c 2007-02-21 21:50:03.000000000 -0700 -+++ nfs-utils-1.0.11.lustre/utils/gssd/context_spkm3.c 2007-06-29 12:32:31.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/context_spkm3.c nfs-utils-1.0.11/utils/gssd/context_spkm3.c +--- nfs-utils-1.0.11.lustre/utils/gssd/context_spkm3.c 2007-02-21 21:50:03.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/context_spkm3.c 2008-01-02 18:11:38.000000000 -0700 @@ -33,8 +33,6 @@ #include #include @@ -458,9 +459,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/context_spkm3.c nfs-utils-1.0.11.lustre/u #include "gss_util.h" #include "gss_oids.h" #include "err_util.h" -diff -Nrup nfs-utils-1.0.11/utils/gssd/err_util.c nfs-utils-1.0.11.lustre/utils/gssd/err_util.c ---- nfs-utils-1.0.11/utils/gssd/err_util.c 2007-02-21 21:50:03.000000000 -0700 -+++ nfs-utils-1.0.11.lustre/utils/gssd/err_util.c 2007-06-29 12:32:31.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/err_util.c nfs-utils-1.0.11/utils/gssd/err_util.c +--- nfs-utils-1.0.11.lustre/utils/gssd/err_util.c 2007-02-21 21:50:03.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/err_util.c 2008-01-02 18:11:38.000000000 -0700 @@ -32,6 +32,8 @@ #include #include @@ -511,9 +512,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/err_util.c nfs-utils-1.0.11.lustre/utils/ + } +} + -diff -Nrup nfs-utils-1.0.11/utils/gssd/err_util.h nfs-utils-1.0.11.lustre/utils/gssd/err_util.h ---- nfs-utils-1.0.11/utils/gssd/err_util.h 2007-02-21 21:50:03.000000000 -0700 -+++ nfs-utils-1.0.11.lustre/utils/gssd/err_util.h 2007-06-29 12:32:32.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/err_util.h nfs-utils-1.0.11/utils/gssd/err_util.h +--- nfs-utils-1.0.11.lustre/utils/gssd/err_util.h 2007-02-21 21:50:03.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/err_util.h 2008-01-02 18:11:38.000000000 -0700 @@ -33,5 +33,6 @@ void initerr(char *progname, int verbosity, int fg); @@ -521,9 +522,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/err_util.h nfs-utils-1.0.11.lustre/utils/ +void print_hexl(int pri, unsigned char *cp, int length); #endif /* _ERR_UTIL_H_ */ -diff -Nrup nfs-utils-1.0.11/utils/gssd/gss_clnt_send_err.c nfs-utils-1.0.11.lustre/utils/gssd/gss_clnt_send_err.c ---- nfs-utils-1.0.11/utils/gssd/gss_clnt_send_err.c 2007-02-21 21:50:03.000000000 -0700 -+++ nfs-utils-1.0.11.lustre/utils/gssd/gss_clnt_send_err.c 2007-06-29 12:29:20.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gss_clnt_send_err.c nfs-utils-1.0.11/utils/gssd/gss_clnt_send_err.c +--- nfs-utils-1.0.11.lustre/utils/gssd/gss_clnt_send_err.c 2007-02-21 21:50:03.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/gss_clnt_send_err.c 2008-01-02 18:10:29.000000000 -0700 @@ -47,6 +47,7 @@ #include "gssd.h" #include "write_bytes.h" @@ -537,9 +538,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/gss_clnt_send_err.c nfs-utils-1.0.11.lust exit(0); } +#endif -diff -Nrup nfs-utils-1.0.11/utils/gssd/gssd.c nfs-utils-1.0.11.lustre/utils/gssd/gssd.c ---- nfs-utils-1.0.11/utils/gssd/gssd.c 2007-06-29 12:28:01.000000000 -0600 -+++ nfs-utils-1.0.11.lustre/utils/gssd/gssd.c 2007-06-29 12:32:36.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gssd.c nfs-utils-1.0.11/utils/gssd/gssd.c +--- nfs-utils-1.0.11.lustre/utils/gssd/gssd.c 2008-01-02 17:22:48.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/gssd.c 2008-01-02 18:11:38.000000000 -0700 @@ -38,9 +38,12 @@ #include "config.h" @@ -766,9 +767,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/gssd.c nfs-utils-1.0.11.lustre/utils/gssd + printerr(0, "lgssd exiting\n"); + return 0; } -diff -Nrup nfs-utils-1.0.11/utils/gssd/gssd.h nfs-utils-1.0.11.lustre/utils/gssd/gssd.h ---- nfs-utils-1.0.11/utils/gssd/gssd.h 2007-06-29 12:28:01.000000000 -0600 -+++ nfs-utils-1.0.11.lustre/utils/gssd/gssd.h 2007-06-29 12:32:37.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gssd.h nfs-utils-1.0.11/utils/gssd/gssd.h +--- nfs-utils-1.0.11.lustre/utils/gssd/gssd.h 2008-01-02 17:22:48.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/gssd.h 2008-01-02 18:11:38.000000000 -0700 @@ -48,8 +48,13 @@ #define GSSD_DEFAULT_CRED_PREFIX "krb5cc_" #define GSSD_DEFAULT_MACHINE_CRED_SUFFIX "machine" @@ -824,10 +825,21 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/gssd.h nfs-utils-1.0.11.lustre/utils/gssd +void lgssd_mutex_put(int semid); #endif /* _RPC_GSSD_H_ */ -diff -Nrup nfs-utils-1.0.11/utils/gssd/gssd_main_loop.c nfs-utils-1.0.11.lustre/utils/gssd/gssd_main_loop.c ---- nfs-utils-1.0.11/utils/gssd/gssd_main_loop.c 2007-06-29 12:28:01.000000000 -0600 -+++ nfs-utils-1.0.11.lustre/utils/gssd/gssd_main_loop.c 2007-06-29 12:32:38.000000000 -0600 -@@ -94,11 +94,13 @@ scan_poll_results(int ret) +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gssd_main_loop.c nfs-utils-1.0.11/utils/gssd/gssd_main_loop.c +--- nfs-utils-1.0.11.lustre/utils/gssd/gssd_main_loop.c 2008-01-02 17:22:48.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/gssd_main_loop.c 2008-01-02 18:11:38.000000000 -0700 +@@ -44,6 +44,10 @@ + #include + #include + #include ++/* For time() */ ++#include ++/* For waitpid() */ ++#include + + #include "gssd.h" + #include "err_util.h" +@@ -94,11 +98,13 @@ scan_poll_results(int ret) }; void @@ -842,7 +854,7 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/gssd_main_loop.c nfs-utils-1.0.11.lustre/ /* Taken from linux/Documentation/dnotify.txt: */ dn_act.sa_sigaction = dir_notify_handler; -@@ -106,10 +108,10 @@ gssd_run() +@@ -106,10 +112,10 @@ gssd_run() dn_act.sa_flags = SA_SIGINFO; sigaction(DNOTIFY_SIGNAL, &dn_act, NULL); @@ -856,7 +868,7 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/gssd_main_loop.c nfs-utils-1.0.11.lustre/ } fcntl(fd, F_SETSIG, DNOTIFY_SIGNAL); fcntl(fd, F_NOTIFY, DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT); -@@ -119,12 +121,30 @@ gssd_run() +@@ -119,12 +125,30 @@ gssd_run() while (1) { while (dir_changed) { dir_changed = 0; @@ -888,7 +900,7 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/gssd_main_loop.c nfs-utils-1.0.11.lustre/ /* race condition here: dir_changed could be set before we * enter the poll, and we'd never notice if it weren't for the * timeout. */ -@@ -139,6 +159,7 @@ gssd_run() +@@ -139,6 +163,7 @@ gssd_run() scan_poll_results(ret); } } @@ -896,9 +908,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/gssd_main_loop.c nfs-utils-1.0.11.lustre/ close(fd); return; } -diff -Nrup nfs-utils-1.0.11/utils/gssd/gssd_proc.c nfs-utils-1.0.11.lustre/utils/gssd/gssd_proc.c ---- nfs-utils-1.0.11/utils/gssd/gssd_proc.c 2007-06-29 12:28:01.000000000 -0600 -+++ nfs-utils-1.0.11.lustre/utils/gssd/gssd_proc.c 2007-06-29 12:32:38.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gssd_proc.c nfs-utils-1.0.11/utils/gssd/gssd_proc.c +--- nfs-utils-1.0.11.lustre/utils/gssd/gssd_proc.c 2008-01-02 17:22:48.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/gssd_proc.c 2008-01-02 18:11:38.000000000 -0700 @@ -43,7 +43,6 @@ #endif #include "config.h" @@ -1700,9 +1712,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/gssd_proc.c nfs-utils-1.0.11.lustre/utils goto out; +#endif } -diff -Nrup nfs-utils-1.0.11/utils/gssd/gss_util.c nfs-utils-1.0.11.lustre/utils/gssd/gss_util.c ---- nfs-utils-1.0.11/utils/gssd/gss_util.c 2007-02-21 21:50:03.000000000 -0700 -+++ nfs-utils-1.0.11.lustre/utils/gssd/gss_util.c 2007-06-29 12:32:40.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gss_util.c nfs-utils-1.0.11/utils/gssd/gss_util.c +--- nfs-utils-1.0.11.lustre/utils/gssd/gss_util.c 2007-02-21 21:50:03.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/gss_util.c 2008-01-02 18:11:38.000000000 -0700 @@ -87,9 +87,16 @@ #ifdef HAVE_COM_ERR_H #include @@ -1916,9 +1928,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/gss_util.c nfs-utils-1.0.11.lustre/utils/ + return retval; +} + -diff -Nrup nfs-utils-1.0.11/utils/gssd/gss_util.h nfs-utils-1.0.11.lustre/utils/gssd/gss_util.h ---- nfs-utils-1.0.11/utils/gssd/gss_util.h 2007-02-21 21:50:03.000000000 -0700 -+++ nfs-utils-1.0.11.lustre/utils/gssd/gss_util.h 2007-06-29 12:32:41.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gss_util.h nfs-utils-1.0.11/utils/gssd/gss_util.h +--- nfs-utils-1.0.11.lustre/utils/gssd/gss_util.h 2007-02-21 21:50:03.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/gss_util.h 2008-01-02 18:11:38.000000000 -0700 @@ -32,14 +32,14 @@ #define _GSS_UTIL_H_ @@ -1936,9 +1948,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/gss_util.h nfs-utils-1.0.11.lustre/utils/ +int gssd_get_local_realm(void); #endif /* _GSS_UTIL_H_ */ -diff -Nrup nfs-utils-1.0.11/utils/gssd/krb5_util.c nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.c ---- nfs-utils-1.0.11/utils/gssd/krb5_util.c 2007-06-29 12:28:01.000000000 -0600 -+++ nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.c 2007-06-29 12:32:42.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.c nfs-utils-1.0.11/utils/gssd/krb5_util.c +--- nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.c 2008-01-02 17:22:48.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/krb5_util.c 2008-01-02 18:11:38.000000000 -0700 @@ -99,12 +99,15 @@ #include #include @@ -2404,9 +2416,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/krb5_util.c nfs-utils-1.0.11.lustre/utils } } +#endif -diff -Nrup nfs-utils-1.0.11/utils/gssd/krb5_util.h nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.h ---- nfs-utils-1.0.11/utils/gssd/krb5_util.h 2007-06-29 12:28:01.000000000 -0600 -+++ nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.h 2007-06-29 12:32:42.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.h nfs-utils-1.0.11/utils/gssd/krb5_util.h +--- nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.h 2008-01-02 17:22:48.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/krb5_util.h 2008-01-02 18:11:38.000000000 -0700 @@ -10,6 +10,8 @@ struct gssd_k5_kt_princ { struct gssd_k5_kt_princ *next; @@ -2425,893 +2437,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/krb5_util.h nfs-utils-1.0.11.lustre/utils -#endif - #endif /* KRB5_UTIL_H */ -diff -Nrup nfs-utils-1.0.11/utils/gssd/lsupport.c nfs-utils-1.0.11.lustre/utils/gssd/lsupport.c ---- nfs-utils-1.0.11/utils/gssd/lsupport.c 1969-12-31 17:00:00.000000000 -0700 -+++ nfs-utils-1.0.11.lustre/utils/gssd/lsupport.c 2007-06-29 12:32:43.000000000 -0600 -@@ -0,0 +1,787 @@ -+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- -+ * vim:expandtab:shiftwidth=8:tabstop=8: -+ * -+ * Copyright (c) 2005 Cluster File Systems, Inc. -+ * -+ * This file is part of Lustre, http://www.lustre.org. -+ * -+ * Lustre is free 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. -+ * -+ * 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 -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with Lustre; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#ifndef _GNU_SOURCE -+#define _GNU_SOURCE -+#endif -+#include "config.h" -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#ifdef HAVE_GETHOSTBYNAME -+# include -+#endif -+ -+#ifdef _NEW_BUILD_ -+# include "lgss_utils.h" -+#else -+# include "err_util.h" -+# include "gssd.h" -+#endif -+#include "lsupport.h" -+ -+/**************************************** -+ * exclusive startup * -+ ****************************************/ -+ -+static struct __sem_s { -+ char *name; -+ key_t sem_key; -+ int sem_id; -+} sems[2] = { -+ [GSSD_CLI] = { "client", 0x3a92d473, 0 }, -+ [GSSD_SVC] = { "server", 0x3b92d473, 0 }, -+}; -+ -+void gssd_init_unique(int type) -+{ -+ struct __sem_s *sem = &sems[type]; -+ struct sembuf sembuf; -+ -+ assert(type == GSSD_CLI || type == GSSD_SVC); -+ -+again: -+ sem->sem_id = semget(sem->sem_key, 1, IPC_CREAT | IPC_EXCL | 0700); -+ if (sem->sem_id == -1) { -+ if (errno != EEXIST) { -+ printerr(0, "Create sem: %s\n", strerror(errno)); -+ exit(-1); -+ } -+ -+ /* already exist. Note there's still a small window racing -+ * with other processes, due to the stupid semaphore semantics. -+ */ -+ sem->sem_id = semget(sem->sem_key, 0, 0700); -+ if (sem->sem_id == -1) { -+ if (errno == ENOENT) { -+ printerr(0, "another instance just exit, " -+ "try again\n"); -+ goto again; -+ } -+ -+ printerr(0, "Obtain sem: %s\n", strerror(errno)); -+ exit(-1); -+ } -+ } else { -+ int val = 1; -+ -+ if (semctl(sem->sem_id, 0, SETVAL, val) == -1) { -+ printerr(0, "Initialize sem: %s\n", -+ strerror(errno)); -+ exit(-1); -+ } -+ } -+ -+ sembuf.sem_num = 0; -+ sembuf.sem_op = -1; -+ sembuf.sem_flg = IPC_NOWAIT | SEM_UNDO; -+ -+ if (semop(sem->sem_id, &sembuf, 1) != 0) { -+ if (errno == EAGAIN) { -+ printerr(0, "Another instance is running, exit\n"); -+ exit(0); -+ } -+ printerr(0, "Grab sem: %s\n", strerror(errno)); -+ exit(0); -+ } -+ -+ printerr(2, "Successfully created %s global identity\n", sem->name); -+} -+ -+void gssd_exit_unique(int type) -+{ -+ assert(type == GSSD_CLI || type == GSSD_SVC); -+ -+ /* -+ * do nothing. we can't remove the sem here, otherwise the race -+ * window would be much bigger. So it's sad we have to leave the -+ * sem in the system forever. -+ */ -+} -+ -+/**************************************** -+ * client side resolvation: * -+ * lnd/netid/nid => hostname * -+ ****************************************/ -+ -+char gethostname_ex[PATH_MAX] = GSSD_DEFAULT_GETHOSTNAME_EX; -+ -+typedef int lnd_nid2hostname_t(char *lnd, uint32_t net, uint32_t addr, -+ char *buf, int buflen); -+ -+/* FIXME what about IPv6? */ -+static -+int ipv4_nid2hostname(char *lnd, uint32_t net, uint32_t addr, -+ char *buf, int buflen) -+{ -+ struct hostent *ent; -+ -+ addr = htonl(addr); -+ ent = gethostbyaddr(&addr, sizeof(addr), AF_INET); -+ if (!ent) { -+ printerr(0, "%s: can't resolve 0x%x\n", lnd, addr); -+ return -1; -+ } -+ if (strlen(ent->h_name) >= buflen) { -+ printerr(0, "%s: name too long: %s\n", lnd, ent->h_name); -+ return -1; -+ } -+ strcpy(buf, ent->h_name); -+ -+ printerr(2, "%s: net 0x%x, addr 0x%x => %s\n", -+ lnd, net, addr, buf); -+ return 0; -+} -+ -+static -+int lolnd_nid2hostname(char *lnd, uint32_t net, uint32_t addr, -+ char *buf, int buflen) -+{ -+ struct utsname uts; -+ struct hostent *ent; -+ -+ if (addr) { -+ printerr(0, "%s: addr is 0x%x, we expect 0\n", lnd, addr); -+ return -1; -+ } -+ -+ if (uname(&uts)) { -+ printerr(0, "%s: failed obtain local machine name\n", lnd); -+ return -1; -+ } -+ -+ ent = gethostbyname(uts.nodename); -+ if (!ent) { -+ printerr(0, "%s: failed obtain canonical name of %s\n", -+ lnd, uts.nodename); -+ return -1; -+ } -+ -+ if (strlen(ent->h_name) >= buflen) { -+ printerr(0, "%s: name too long: %s\n", lnd, ent->h_name); -+ return -1; -+ } -+ strcpy(buf, ent->h_name); -+ -+ printerr(3, "%s: addr 0x%x => %s\n", lnd, addr, buf); -+ return 0; -+} -+ -+static int is_space(char c) -+{ -+ return (c == ' ' || c == '\t' || c == '\n'); -+} -+ -+static -+int external_nid2hostname(char *lnd, uint32_t net, uint32_t addr, -+ char *namebuf, int namebuflen) -+{ -+ const int bufsize = PATH_MAX + 256; -+ char buf[bufsize], *head, *tail; -+ FILE *fghn; -+ -+ sprintf(buf, "%s %s 0x%x 0x%x", gethostname_ex, lnd, net, addr); -+ printerr(2, "cmd: %s\n", buf); -+ -+ fghn = popen(buf, "r"); -+ if (fghn == NULL) { -+ printerr(0, "failed to call %s\n", gethostname_ex); -+ return -1; -+ } -+ -+ head = fgets(buf, bufsize, fghn); -+ if (head == NULL) { -+ printerr(0, "can't read from %s\n", gethostname_ex); -+ return -1; -+ } -+ if (pclose(fghn) == -1) -+ printerr(1, "pclose failed, continue\n"); -+ -+ /* trim head/tail space */ -+ while (is_space(*head)) -+ head++; -+ -+ tail = head + strlen(head); -+ if (tail <= head) { -+ printerr(0, "no output from %s\n", gethostname_ex); -+ return -1; -+ } -+ while (is_space(*(tail - 1))) -+ tail--; -+ if (tail <= head) { -+ printerr(0, "output are all space from %s\n", gethostname_ex); -+ return -1; -+ } -+ *tail = '\0'; -+ -+ /* start with '@' means error msg */ -+ if (head[0] == '@') { -+ printerr(0, "error from %s: %s\n", gethostname_ex, &head[1]); -+ return -1; -+ } -+ -+ if (tail - head > namebuflen) { -+ printerr(0, "external hostname too long: %s\n", head); -+ return -1; -+ } -+ -+ printerr(2, "%s: net 0x%x, addr 0x%x => %s\n", -+ lnd, net, addr, head); -+ strcpy(namebuf, head); -+ return 0; -+} -+ -+static struct { -+ char *name; -+ lnd_nid2hostname_t *nid2name; -+} converter[LND_ENUM_END_MARKER] = { -+ {"UNUSED0", NULL}, -+ [QSWLND] = { "QSWLND", external_nid2hostname}, -+ [SOCKLND] = { "SOCKLND", ipv4_nid2hostname }, -+ [GMLND] = { "GMLND", external_nid2hostname}, -+ [PTLLND] = { "PTLLND", external_nid2hostname }, -+ [O2IBLND] = { "O2IBLND", ipv4_nid2hostname }, -+ [CIBLND] = { "CIBLND", external_nid2hostname }, -+ [OPENIBLND] = { "OPENIBLND",external_nid2hostname }, -+ [IIBLND] = { "IIBLND", external_nid2hostname }, -+ [LOLND] = { "LOLND", lolnd_nid2hostname }, -+ [RALND] = { "RALND", external_nid2hostname }, -+ [VIBLND] = { "VIBLND", external_nid2hostname }, -+}; -+ -+int lnet_nid2hostname(lnet_nid_t nid, char *buf, int buflen) -+{ -+ uint32_t lnd, net, addr; -+ -+ addr = LNET_NIDADDR(nid); -+ net = LNET_NIDNET(nid); -+ lnd = LNET_NETTYP(net); -+ -+ if (lnd >= LND_ENUM_END_MARKER) { -+ printerr(0, "ERROR: Unrecognized LND %u\n", lnd); -+ return -1; -+ } -+ -+ if (converter[lnd].nid2name == NULL) { -+ printerr(0, "ERROR: %s converter not ready\n", -+ converter[lnd].name); -+ return -1; -+ } -+ -+ return converter[lnd].nid2name(converter[lnd].name, net, addr, -+ buf, buflen); -+} -+ -+ -+/**************************************** -+ * lnet support routine * -+ * (from lnet/libcfs/nidstrings.c * -+ ****************************************/ -+ -+#define LNET_NIDSTR_SIZE 32 /* size of each one (see below for usage) */ -+ -+static int libcfs_lo_str2addr(char *str, int nob, uint32_t *addr); -+static void libcfs_ip_addr2str(uint32_t addr, char *str); -+static int libcfs_ip_str2addr(char *str, int nob, uint32_t *addr); -+static void libcfs_decnum_addr2str(uint32_t addr, char *str); -+static void libcfs_hexnum_addr2str(uint32_t addr, char *str); -+static int libcfs_num_str2addr(char *str, int nob, uint32_t *addr); -+ -+struct netstrfns { -+ int nf_type; -+ char *nf_name; -+ char *nf_modname; -+ void (*nf_addr2str)(uint32_t addr, char *str); -+ int (*nf_str2addr)(char *str, int nob, uint32_t *addr); -+}; -+ -+static struct netstrfns libcfs_netstrfns[] = { -+ {/* .nf_type */ LOLND, -+ /* .nf_name */ "lo", -+ /* .nf_modname */ "klolnd", -+ /* .nf_addr2str */ libcfs_decnum_addr2str, -+ /* .nf_str2addr */ libcfs_lo_str2addr}, -+ {/* .nf_type */ SOCKLND, -+ /* .nf_name */ "tcp", -+ /* .nf_modname */ "ksocklnd", -+ /* .nf_addr2str */ libcfs_ip_addr2str, -+ /* .nf_str2addr */ libcfs_ip_str2addr}, -+ {/* .nf_type */ O2IBLND, -+ /* .nf_name */ "o2ib", -+ /* .nf_modname */ "ko2iblnd", -+ /* .nf_addr2str */ libcfs_ip_addr2str, -+ /* .nf_str2addr */ libcfs_ip_str2addr}, -+ {/* .nf_type */ CIBLND, -+ /* .nf_name */ "cib", -+ /* .nf_modname */ "kciblnd", -+ /* .nf_addr2str */ libcfs_ip_addr2str, -+ /* .nf_str2addr */ libcfs_ip_str2addr}, -+ {/* .nf_type */ OPENIBLND, -+ /* .nf_name */ "openib", -+ /* .nf_modname */ "kopeniblnd", -+ /* .nf_addr2str */ libcfs_ip_addr2str, -+ /* .nf_str2addr */ libcfs_ip_str2addr}, -+ {/* .nf_type */ IIBLND, -+ /* .nf_name */ "iib", -+ /* .nf_modname */ "kiiblnd", -+ /* .nf_addr2str */ libcfs_ip_addr2str, -+ /* .nf_str2addr */ libcfs_ip_str2addr}, -+ {/* .nf_type */ VIBLND, -+ /* .nf_name */ "vib", -+ /* .nf_modname */ "kviblnd", -+ /* .nf_addr2str */ libcfs_ip_addr2str, -+ /* .nf_str2addr */ libcfs_ip_str2addr}, -+ {/* .nf_type */ RALND, -+ /* .nf_name */ "ra", -+ /* .nf_modname */ "kralnd", -+ /* .nf_addr2str */ libcfs_ip_addr2str, -+ /* .nf_str2addr */ libcfs_ip_str2addr}, -+ {/* .nf_type */ QSWLND, -+ /* .nf_name */ "elan", -+ /* .nf_modname */ "kqswlnd", -+ /* .nf_addr2str */ libcfs_decnum_addr2str, -+ /* .nf_str2addr */ libcfs_num_str2addr}, -+ {/* .nf_type */ GMLND, -+ /* .nf_name */ "gm", -+ /* .nf_modname */ "kgmlnd", -+ /* .nf_addr2str */ libcfs_hexnum_addr2str, -+ /* .nf_str2addr */ libcfs_num_str2addr}, -+ {/* .nf_type */ PTLLND, -+ /* .nf_name */ "ptl", -+ /* .nf_modname */ "kptllnd", -+ /* .nf_addr2str */ libcfs_decnum_addr2str, -+ /* .nf_str2addr */ libcfs_num_str2addr}, -+ /* placeholder for net0 alias. It MUST BE THE LAST ENTRY */ -+ {/* .nf_type */ -1}, -+}; -+ -+const int libcfs_nnetstrfns = sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]); -+ -+static int -+libcfs_lo_str2addr(char *str, int nob, uint32_t *addr) -+{ -+ *addr = 0; -+ return 1; -+} -+ -+static void -+libcfs_ip_addr2str(uint32_t addr, char *str) -+{ -+ snprintf(str, LNET_NIDSTR_SIZE, "%u.%u.%u.%u", -+ (addr >> 24) & 0xff, (addr >> 16) & 0xff, -+ (addr >> 8) & 0xff, addr & 0xff); -+} -+ -+/* CAVEAT EMPTOR XscanfX -+ * I use "%n" at the end of a sscanf format to detect trailing junk. However -+ * sscanf may return immediately if it sees the terminating '0' in a string, so -+ * I initialise the %n variable to the expected length. If sscanf sets it; -+ * fine, if it doesn't, then the scan ended at the end of the string, which is -+ * fine too :) */ -+ -+static int -+libcfs_ip_str2addr(char *str, int nob, uint32_t *addr) -+{ -+ int a; -+ int b; -+ int c; -+ int d; -+ int n = nob; /* XscanfX */ -+ -+ /* numeric IP? */ -+ if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 && -+ n == nob && -+ (a & ~0xff) == 0 && (b & ~0xff) == 0 && -+ (c & ~0xff) == 0 && (d & ~0xff) == 0) { -+ *addr = ((a<<24)|(b<<16)|(c<<8)|d); -+ return 1; -+ } -+ -+#ifdef HAVE_GETHOSTBYNAME -+ /* known hostname? */ -+ if (('a' <= str[0] && str[0] <= 'z') || -+ ('A' <= str[0] && str[0] <= 'Z')) { -+ char *tmp; -+ -+ tmp = malloc(nob + 1); -+ if (tmp != NULL) { -+ struct hostent *he; -+ -+ memcpy(tmp, str, nob); -+ tmp[nob] = 0; -+ -+ he = gethostbyname(tmp); -+ -+ free(tmp); -+ tmp = NULL; -+ -+ if (he != NULL) { -+ uint32_t ip = *(uint32_t *)he->h_addr; -+ -+ *addr = ntohl(ip); -+ return 1; -+ } -+ } -+ } -+#endif -+ return 0; -+} -+ -+static void -+libcfs_decnum_addr2str(uint32_t addr, char *str) -+{ -+ snprintf(str, LNET_NIDSTR_SIZE, "%u", addr); -+} -+ -+static void -+libcfs_hexnum_addr2str(uint32_t addr, char *str) -+{ -+ snprintf(str, LNET_NIDSTR_SIZE, "0x%x", addr); -+} -+ -+static int -+libcfs_num_str2addr(char *str, int nob, uint32_t *addr) -+{ -+ int n; -+ -+ n = nob; -+ if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob) -+ return 1; -+ -+ n = nob; -+ if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob) -+ return 1; -+ -+ n = nob; -+ if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob) -+ return 1; -+ -+ return 0; -+} -+ -+static struct netstrfns * -+libcfs_lnd2netstrfns(int lnd) -+{ -+ int i; -+ -+ if (lnd >= 0) -+ for (i = 0; i < libcfs_nnetstrfns; i++) -+ if (lnd == libcfs_netstrfns[i].nf_type) -+ return &libcfs_netstrfns[i]; -+ -+ return NULL; -+} -+ -+static struct netstrfns * -+libcfs_str2net_internal(char *str, uint32_t *net) -+{ -+ struct netstrfns *nf; -+ int nob; -+ int netnum; -+ int i; -+ -+ for (i = 0; i < libcfs_nnetstrfns; i++) { -+ nf = &libcfs_netstrfns[i]; -+ if (nf->nf_type >= 0 && -+ !strncmp(str, nf->nf_name, strlen(nf->nf_name))) -+ break; -+ } -+ -+ if (i == libcfs_nnetstrfns) -+ return NULL; -+ -+ nob = strlen(nf->nf_name); -+ -+ if (strlen(str) == (unsigned int)nob) { -+ netnum = 0; -+ } else { -+ if (nf->nf_type == LOLND) /* net number not allowed */ -+ return NULL; -+ -+ str += nob; -+ i = strlen(str); -+ if (sscanf(str, "%u%n", &netnum, &i) < 1 || -+ i != (int)strlen(str)) -+ return NULL; -+ } -+ -+ *net = LNET_MKNET(nf->nf_type, netnum); -+ return nf; -+} -+ -+lnet_nid_t -+libcfs_str2nid(char *str) -+{ -+ char *sep = strchr(str, '@'); -+ struct netstrfns *nf; -+ uint32_t net; -+ uint32_t addr; -+ -+ if (sep != NULL) { -+ nf = libcfs_str2net_internal(sep + 1, &net); -+ if (nf == NULL) -+ return LNET_NID_ANY; -+ } else { -+ sep = str + strlen(str); -+ net = LNET_MKNET(SOCKLND, 0); -+ nf = libcfs_lnd2netstrfns(SOCKLND); -+ if (!nf) -+ return LNET_NID_ANY; -+ } -+ -+ if (!nf->nf_str2addr(str, sep - str, &addr)) -+ return LNET_NID_ANY; -+ -+ return LNET_MKNID(net, addr); -+} -+ -+/**************************************** -+ * user mapping database handling * -+ * (very rudiment) * -+ ****************************************/ -+ -+#define MAPPING_GROW_SIZE 512 -+#define MAX_LINE_LEN 256 -+ -+struct user_map_item { -+ char *principal; /* NULL means match all, will cause multi->single mapped, FORBID */ -+ lnet_nid_t nid; -+ uid_t uid; -+}; -+ -+struct user_mapping { -+ int nitems; -+ struct user_map_item *items; -+}; -+ -+static struct user_mapping mapping = {0, NULL}; -+/* FIXME to be finished: monitor change of mapping database */ -+static int mapping_mtime = 0; -+ -+void cleanup_mapping(void) -+{ -+ if (mapping.items) { -+ for (; mapping.nitems > 0; mapping.nitems--) -+ free(mapping.items[mapping.nitems - 1].principal); -+ free(mapping.items); -+ mapping.items = NULL; -+ } -+} -+ -+static int grow_mapping(int nitems) -+{ -+ struct user_map_item *new; -+ int oldsize, newsize; -+ -+ oldsize = (mapping.nitems * sizeof(struct user_map_item) + -+ MAPPING_GROW_SIZE - 1) / MAPPING_GROW_SIZE; -+ newsize = (nitems * sizeof(struct user_map_item) + -+ MAPPING_GROW_SIZE - 1) / MAPPING_GROW_SIZE; -+ while (newsize <= oldsize) -+ return 0; -+ -+ newsize *= MAPPING_GROW_SIZE; -+ new = malloc(newsize); -+ if (!new) { -+ printerr(0, "can't alloc mapping size %d\n", newsize); -+ return -1; -+ } -+ -+ if (mapping.items) { -+ memcpy(new, mapping.items, mapping.nitems * sizeof(struct user_map_item)); -+ free(mapping.items); -+ } -+ mapping.items = new; -+ return 0; -+} -+ -+uid_t parse_uid(char *uidstr) -+{ -+ struct passwd *pw; -+ char *p = NULL; -+ long uid; -+ -+ pw = getpwnam(uidstr); -+ if (pw) -+ return pw->pw_uid; -+ -+ uid = strtol(uidstr, &p, 0); -+ if (*p == '\0') -+ return (uid_t) uid; -+ -+ return -1; -+} -+ -+static int read_mapping_db(void) -+{ -+ char princ[MAX_LINE_LEN]; -+ char nid_str[MAX_LINE_LEN]; -+ char dest[MAX_LINE_LEN]; -+ char linebuf[MAX_LINE_LEN]; -+ char *line; -+ lnet_nid_t nid; -+ uid_t dest_uid; -+ FILE *f; -+ -+ /* cleanup old mappings */ -+ cleanup_mapping(); -+ -+ f = fopen(MAPPING_DATABASE_FILE, "r"); -+ if (!f) { -+ printerr(0, "can't open mapping database: %s\n", -+ MAPPING_DATABASE_FILE); -+ return -1; -+ } -+ -+ while ((line = fgets(linebuf, MAX_LINE_LEN, f)) != NULL) { -+ char *name; -+ -+ if (strlen(line) >= MAX_LINE_LEN) { -+ printerr(0, "invalid mapping db: line too long (%d)\n", -+ strlen(line)); -+ continue; -+ } -+ -+ if (sscanf(line, "%s %s %s", princ, nid_str, dest) != 3) { -+ printerr(0, "mapping db: syntax error\n"); -+ continue; -+ } -+ -+ if (!strcmp(princ, "*")) { -+ printerr(0, "NOT permit \"*\" princ, it will cause multi->single mapped\n"); -+ continue; -+ } else { -+ name = strdup(princ); -+ if (!name) { -+ printerr(0, "fail to dup str %s\n", princ); -+ continue; -+ } -+ } -+ -+ if (!strcmp(nid_str, "*")) { -+ nid = LNET_NID_ANY; -+ } else { -+ nid = libcfs_str2nid(nid_str); -+ if (nid == LNET_NID_ANY) { -+ printerr(0, "fail to parse nid %s\n", nid_str); -+ free(name); -+ continue; -+ } -+ } -+ -+ dest_uid = parse_uid(dest); -+ if (dest_uid == -1) { -+ printerr(0, "no valid user: %s\n", dest); -+ free(name); -+ continue; -+ } -+ -+ if (grow_mapping(mapping.nitems + 1)) { -+ printerr(0, "fail to grow mapping to %d\n", -+ mapping.nitems + 1); -+ free(name); -+ fclose(f); -+ return -1; -+ } -+ -+ mapping.items[mapping.nitems].principal = name; -+ mapping.items[mapping.nitems].nid = nid; -+ mapping.items[mapping.nitems].uid = dest_uid; -+ mapping.nitems++; -+ printerr(1, "add mapping: %s(%s/0x%llx) ==> %d\n", -+ name, nid_str, nid, dest_uid); -+ } -+ -+ fclose(f); -+ return 0; -+} -+ -+static inline int mapping_changed(void) -+{ -+ struct stat st; -+ -+ if (stat(MAPPING_DATABASE_FILE, &st) == -1) { -+ /* stat failed, treat it like doesn't exist or be removed */ -+ if (mapping_mtime == 0) { -+ return 0; -+ } else { -+ printerr(0, "Warning: stat %s failed: %s\n", -+ MAPPING_DATABASE_FILE, strerror(errno)); -+ -+ mapping_mtime = 0; -+ return 1; -+ } -+ } -+ -+ if (st.st_mtime != mapping_mtime) { -+ mapping_mtime = st.st_mtime; -+ return 1; -+ } -+ -+ return 0; -+} -+ -+int lookup_mapping(char *princ, lnet_nid_t nid, uid_t *uid) -+{ -+ int n; -+ -+ *uid = -1; -+ -+ /* FIXME race condition here */ -+ if (mapping_changed()) { -+ if (read_mapping_db()) -+ printerr(0, "all remote users will be denied\n"); -+ } -+ -+ for (n = 0; n < mapping.nitems; n++) { -+ struct user_map_item *entry = &mapping.items[n]; -+ -+ if (entry->nid != LNET_NID_ANY && entry->nid != nid) -+ continue; -+ if (!strcasecmp(entry->principal, princ)) { -+ printerr(1, "found mapping: %s ==> %d\n", -+ princ, entry->uid); -+ *uid = entry->uid; -+ return 0; -+ } -+ } -+ -+ printerr(2, "no mapping for %s/%#Lx\n", princ, nid); -+ return -1; -+} -diff -Nrup nfs-utils-1.0.11/utils/gssd/lsupport.h nfs-utils-1.0.11.lustre/utils/gssd/lsupport.h ---- nfs-utils-1.0.11/utils/gssd/lsupport.h 1969-12-31 17:00:00.000000000 -0700 -+++ nfs-utils-1.0.11.lustre/utils/gssd/lsupport.h 2007-06-29 12:32:43.000000000 -0600 -@@ -0,0 +1,89 @@ -+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- -+ * vim:expandtab:shiftwidth=8:tabstop=8: -+ */ -+ -+#ifndef __LIBCFS_H__ -+#define __LIBCFS_H__ -+ -+#include -+#include -+ -+#define GSSD_CLI (0) -+#define GSSD_SVC (1) -+ -+void gssd_init_unique(int type); -+void gssd_exit_unique(int type); -+ -+/* -+ * copied from lustre source -+ */ -+ -+#define LUSTRE_GSS_SVC_MDS 0 -+#define LUSTRE_GSS_SVC_OSS 1 -+ -+struct lgssd_upcall_data { -+ uint32_t seq; -+ uint32_t uid; -+ uint32_t gid; -+ uint32_t svc; -+ uint64_t nid; -+ char obd[64]; -+}; -+ -+#define GSSD_INTERFACE_VERSION (1) -+ -+struct lgssd_ioctl_param { -+ int version; /* in */ -+ char *uuid; /* in */ -+ int lustre_svc; /* in */ -+ uid_t uid; /* in */ -+ gid_t gid; /* in */ -+ long send_token_size;/* in */ -+ char *send_token; /* in */ -+ long reply_buf_size; /* in */ -+ char *reply_buf; /* in */ -+ long status; /* out */ -+ long reply_length; /* out */ -+}; -+ -+#define GSSD_DEFAULT_GETHOSTNAME_EX "/etc/lustre/nid2hostname" -+#define MAPPING_DATABASE_FILE "/etc/lustre/idmap.conf" -+ -+typedef uint64_t lnet_nid_t; -+typedef uint32_t lnet_netid_t; -+ -+#define LNET_NID_ANY ((lnet_nid_t) -1) -+#define LNET_PID_ANY ((lnet_pid_t) -1) -+ -+enum { -+ /* Only add to these values (i.e. don't ever change or redefine them): -+ * network addresses depend on them... */ -+ QSWLND = 1, -+ SOCKLND = 2, -+ GMLND = 3, -+ PTLLND = 4, -+ O2IBLND = 5, -+ CIBLND = 6, -+ OPENIBLND = 7, -+ IIBLND = 8, -+ LOLND = 9, -+ RALND = 10, -+ VIBLND = 11, -+ LND_ENUM_END_MARKER -+}; -+ -+int lnet_nid2hostname(lnet_nid_t nid, char *buf, int buflen); -+void cleanup_mapping(void); -+int lookup_mapping(char *princ, uint64_t nid, uid_t *uid); -+lnet_nid_t libcfs_str2nid(char *str); -+ -+/* how an LNET NID encodes net:address */ -+#define LNET_NIDADDR(nid) ((uint32_t)((nid) & 0xffffffff)) -+#define LNET_NIDNET(nid) ((uint32_t)(((nid) >> 32)) & 0xffffffff) -+#define LNET_MKNID(net,addr) ((((uint64_t)(net))<<32)|((uint64_t)(addr))) -+/* how net encodes type:number */ -+#define LNET_NETNUM(net) ((net) & 0xffff) -+#define LNET_NETTYP(net) (((net) >> 16) & 0xffff) -+#define LNET_MKNET(typ,num) ((((uint32_t)(typ))<<16)|((uint32_t)(num))) -+ -+#endif /* __LIBCFS_H__ */ -diff -Nrup nfs-utils-1.0.11/utils/gssd/Makefile.am nfs-utils-1.0.11.lustre/utils/gssd/Makefile.am ---- nfs-utils-1.0.11/utils/gssd/Makefile.am 2007-02-21 21:50:03.000000000 -0700 -+++ nfs-utils-1.0.11.lustre/utils/gssd/Makefile.am 2007-06-29 12:29:20.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/Makefile.am nfs-utils-1.0.11/utils/gssd/Makefile.am +--- nfs-utils-1.0.11.lustre/utils/gssd/Makefile.am 2007-02-21 21:50:03.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/Makefile.am 2008-01-02 18:10:29.000000000 -0700 @@ -1,17 +1,11 @@ ## Process this file with automake to produce Makefile.in @@ -3417,9 +2545,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/Makefile.am nfs-utils-1.0.11.lustre/utils - rm -f $(RPCPREFIX)$$inst ; \ - done) - -diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd.c nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.c ---- nfs-utils-1.0.11/utils/gssd/svcgssd.c 2007-02-21 21:50:03.000000000 -0700 -+++ nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.c 2007-06-29 12:32:44.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.c nfs-utils-1.0.11/utils/gssd/svcgssd.c +--- nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.c 2007-02-21 21:50:03.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/svcgssd.c 2008-01-02 18:11:38.000000000 -0700 @@ -43,7 +43,6 @@ #include #include @@ -3583,9 +2711,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd.c nfs-utils-1.0.11.lustre/utils/g printerr(0, "gssd_run returned!\n"); abort(); } -diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd.h nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.h ---- nfs-utils-1.0.11/utils/gssd/svcgssd.h 2007-02-21 21:50:03.000000000 -0700 -+++ nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.h 2007-06-29 12:32:45.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.h nfs-utils-1.0.11/utils/gssd/svcgssd.h +--- nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.h 2007-02-21 21:50:03.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/svcgssd.h 2008-01-02 18:11:38.000000000 -0700 @@ -35,9 +35,20 @@ #include #include @@ -3610,10 +2738,16 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd.h nfs-utils-1.0.11.lustre/utils/g +#define LUSTRE_ROOT_NAMELEN 11 #endif /* _RPC_SVCGSSD_H_ */ -diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd_main_loop.c nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_main_loop.c ---- nfs-utils-1.0.11/utils/gssd/svcgssd_main_loop.c 2007-02-21 21:50:03.000000000 -0700 -+++ nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_main_loop.c 2007-06-29 12:32:45.000000000 -0600 -@@ -46,46 +46,66 @@ +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_main_loop.c nfs-utils-1.0.11/utils/gssd/svcgssd_main_loop.c +--- nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_main_loop.c 2007-02-21 21:50:03.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/svcgssd_main_loop.c 2008-01-02 18:11:38.000000000 -0700 +@@ -42,50 +42,72 @@ + #include + #include + #include ++/* For nanosleep() */ ++#include + #include "svcgssd.h" #include "err_util.h" @@ -3701,9 +2835,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd_main_loop.c nfs-utils-1.0.11.lust } } } -diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_proc.c ---- nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c 2007-02-21 21:50:03.000000000 -0700 -+++ nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_proc.c 2007-06-29 12:32:46.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_proc.c nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c +--- nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_proc.c 2007-02-21 21:50:03.000000000 -0700 ++++ nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c 2008-01-02 18:11:38.000000000 -0700 @@ -35,7 +35,6 @@ #include @@ -3814,7 +2948,7 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c nfs-utils-1.0.11.lustre/ut void print_hexl(int pri, unsigned char *cp, int length) { -@@ -286,12 +293,121 @@ print_hexl(int pri, unsigned char *cp, i +@@ -286,12 +293,149 @@ print_hexl(int pri, unsigned char *cp, i printerr(pri,"\n"); } } @@ -3827,7 +2961,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c nfs-utils-1.0.11.lustre/ut +{ + u_int32_t maj_stat, min_stat; + gss_buffer_desc name; -+ char *sname, *realm, *slash; ++ char *sname, *host, *realm; ++ const int namebuf_size = 512; ++ char namebuf[namebuf_size]; + int res = -1; + gss_OID name_type = GSS_C_NO_OID; + struct passwd *pw; @@ -3849,7 +2985,6 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c nfs-utils-1.0.11.lustre/ut + return -1; + } + memcpy(sname, name.value, name.length); -+ printerr(1, "authenticated %s from %016llx\n", sname, nid); + gss_release_buffer(&min_stat, &name); + + if (lustre_svc == LUSTRE_GSS_SVC_MDS) @@ -3858,64 +2993,91 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c nfs-utils-1.0.11.lustre/ut + cred->cr_mapped_uid = -1; + + realm = strchr(sname, '@'); -+ if (!realm) { -+ printerr(0, "WARNNING: principal %s contains no realm name\n", -+ sname); -+ cred->cr_remote = (mds_local_realm != NULL); -+ } else { ++ if (realm) + *realm++ = '\0'; -+ if (!mds_local_realm) -+ cred->cr_remote = 1; -+ else -+ cred->cr_remote = -+ (strcasecmp(mds_local_realm, realm) != 0); -+ } + -+ if (cred->cr_remote) { -+ if (cred->cr_mapped_uid != -1) -+ res = 0; -+ else if (lustre_svc == LUSTRE_GSS_SVC_OSS && -+ strcmp(sname, "lustre_root") == 0) -+ res = 0; -+ else -+ printerr(0, "principal %s is remote without mapping\n", -+ sname); ++ host = strchr(sname, '/'); ++ if (host) ++ *host++ = '\0'; ++ ++ if (strcmp(sname, GSSD_SERVICE_OSS) == 0) { ++ printerr(0, "forbid "GSSD_SERVICE_OSS" as user name\n"); + goto out_free; -+ } ++ } ++ ++ /* 1. check host part */ ++ if (host) { ++ if (lnet_nid2hostname(nid, namebuf, namebuf_size)) { ++ printerr(0, "ERROR: failed to resolve hostname for " ++ "%s/%s@%s from %016llx\n", ++ sname, host, realm, nid); ++ goto out_free; ++ } ++ ++ if (strcasecmp(host, namebuf)) { ++ printerr(0, "ERROR: %s/%s@s claimed hostname doesn't " ++ "match %s, nid %016llx\n", sname, host, realm, ++ namebuf, nid); ++ goto out_free; ++ } ++ } else { ++ if (!strcmp(sname, GSSD_SERVICE_MDS)) { ++ printerr(0, "ERROR: "GSSD_SERVICE_MDS"@%s from %016llx " ++ "doesn't bind with hostname\n", ++ realm ? realm : "", nid); ++ goto out_free; ++ } ++ } ++ ++ /* 2. check realm */ ++ if (!realm) { ++ /* just deny it ++ cred->cr_remote = (mds_local_realm != NULL); ++ */ ++ printerr(0, "ERROR: %s%s%s have no realm name\n", ++ sname, host ? "/" : "", host ? "host" : ""); ++ goto out_free; ++ } ++ ++ if (!mds_local_realm || strcasecmp(mds_local_realm, realm)) { ++ cred->cr_remote = 1; + -+ slash = strchr(sname, '/'); -+ if (slash) -+ *slash = '\0'; ++ if (cred->cr_mapped_uid == -1) ++ printerr(0, "ERROR: %s from %016llx is remote but " ++ "without mapping\n", sname, nid); ++ /* mapped, skip user checking */ ++ goto out_free; ++ } + ++ /* 3. check user */ + if (!(pw = getpwnam(sname))) { -+ /* If client use machine credential, we map it to root, which -+ * will subject to further mapping by root-squash in kernel. -+ * -+ * MDS service keytab is treated as special user, also mapped -+ * to root. OSS service keytab can't be used as a user. -+ */ ++ /* map lustre_root/lustre_mds to root user, which is subject ++ * to further mapping by root-squash in kernel. */ + if (!strcmp(sname, LUSTRE_ROOT_NAME)) { -+ printerr(2, "lustre_root principal, resolve to uid 0\n"); + cred->cr_uid = 0; + cred->cr_usr_root = 1; + } else if (!strcmp(sname, GSSD_SERVICE_MDS)) { -+ printerr(2, "mds service principal, resolve to uid 0\n"); + cred->cr_uid = 0; + cred->cr_usr_mds = 1; + } else { -+ cred->cr_uid = -1; + if (cred->cr_mapped_uid == -1) { -+ printerr(0, "invalid user %s\n", sname); ++ printerr(0, "ERROR: invalid user, %s/%s@%s " ++ "from %016llx\n", sname, host, ++ realm, nid); + goto out_free; + } -+ printerr(2, "user %s mapped to %u\n", -+ sname, cred->cr_mapped_uid); + } ++ printerr(2, "user %s from %016llx is mapped to %u\n", ++ sname, nid, cred->cr_mapped_uid); + } else { ++ /* note: a mapped local user will go to here too */ + cred->cr_uid = pw->pw_uid; + printerr(2, "%s resolve to uid %u\n", sname, cred->cr_uid); + } + ++ printerr(1, "%s: authenticated %s%s%s@%s from %016llx\n", ++ lustre_svc_name[lustre_svc], sname, ++ host ? "/" : "", host ? host : "", realm, nid); + res = 0; +out_free: + free(sname); @@ -3940,7 +3102,7 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c nfs-utils-1.0.11.lustre/ut char in_tok_buf[TOKEN_BUF_SIZE]; char in_handle_buf[15]; char out_handle_buf[15]; -@@ -303,10 +419,13 @@ handle_nullreq(FILE *f) { +@@ -303,10 +447,13 @@ handle_nullreq(FILE *f) { ignore_out_tok = {.value = NULL}, /* XXX isn't there a define for this?: */ null_token = {.value = NULL}; @@ -3954,7 +3116,7 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c nfs-utils-1.0.11.lustre/ut u_int32_t maj_stat = GSS_S_FAILURE, min_stat = 0; u_int32_t ignore_min_stat; struct svc_cred cred; -@@ -314,25 +433,31 @@ handle_nullreq(FILE *f) { +@@ -314,25 +461,31 @@ handle_nullreq(FILE *f) { static int lbuflen = 0; static char *cp; @@ -3973,7 +3135,7 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c nfs-utils-1.0.11.lustre/ut + qword_get(&cp, (char *) &lustre_svc, sizeof(lustre_svc)); + qword_get(&cp, (char *) &nid, sizeof(nid)); + qword_get(&cp, (char *) &handle_seq, sizeof(handle_seq)); -+ printerr(1, "handling req: svc %u, nid %016llx, idx %llx\n", ++ printerr(2, "handling req: svc %u, nid %016llx, idx %llx\n", + lustre_svc, nid, handle_seq); + in_handle.length = (size_t) qword_get(&cp, in_handle.value, @@ -3992,7 +3154,7 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c nfs-utils-1.0.11.lustre/ut if (in_tok.length < 0) { printerr(0, "WARNING: handle_nullreq: " -@@ -352,7 +477,13 @@ handle_nullreq(FILE *f) { +@@ -352,7 +505,13 @@ handle_nullreq(FILE *f) { memcpy(&ctx, in_handle.value, in_handle.length); } @@ -4007,7 +3169,7 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c nfs-utils-1.0.11.lustre/ut &in_tok, GSS_C_NO_CHANNEL_BINDINGS, &client_name, &mech, &out_tok, &ret_flags, NULL, NULL); -@@ -370,7 +501,8 @@ handle_nullreq(FILE *f) { +@@ -370,7 +529,8 @@ handle_nullreq(FILE *f) { maj_stat, min_stat, mech); goto out_err; } @@ -4017,7 +3179,7 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c nfs-utils-1.0.11.lustre/ut /* get_ids() prints error msg */ maj_stat = GSS_S_BAD_NAME; /* XXX ? */ gss_release_name(&ignore_min_stat, &client_name); -@@ -378,10 +510,8 @@ handle_nullreq(FILE *f) { +@@ -378,10 +538,8 @@ handle_nullreq(FILE *f) { } gss_release_name(&ignore_min_stat, &client_name); @@ -4028,7 +3190,7 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c nfs-utils-1.0.11.lustre/ut out_handle.length = sizeof(handle_seq); memcpy(out_handle.value, &handle_seq, sizeof(handle_seq)); -@@ -405,8 +535,7 @@ out: +@@ -405,8 +563,7 @@ out: free(ctx_token.value); if (out_tok.value != NULL) gss_release_buffer(&ignore_min_stat, &out_tok); @@ -4038,9 +3200,9 @@ diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c nfs-utils-1.0.11.lustre/ut out_err: if (ctx != GSS_C_NO_CONTEXT) -diff -Nrup nfs-utils-1.0.11/utils/Makefile.am nfs-utils-1.0.11.lustre/utils/Makefile.am ---- nfs-utils-1.0.11/utils/Makefile.am 2007-02-21 21:50:03.000000000 -0700 -+++ nfs-utils-1.0.11.lustre/utils/Makefile.am 2007-06-29 12:29:20.000000000 -0600 +diff -Nrup nfs-utils-1.0.11.lustre/utils/Makefile.am nfs-utils-1.0.11/utils/Makefile.am +--- nfs-utils-1.0.11.lustre/utils/Makefile.am 2007-02-21 21:50:03.000000000 -0700 ++++ nfs-utils-1.0.11/utils/Makefile.am 2008-01-02 18:10:29.000000000 -0700 @@ -2,30 +2,6 @@ OPTDIRS = diff --git a/lustre/utils/gss/svcgssd_proc.c b/lustre/utils/gss/svcgssd_proc.c index 745268a..280aa2e 100644 --- a/lustre/utils/gss/svcgssd_proc.c +++ b/lustre/utils/gss/svcgssd_proc.c @@ -301,7 +301,9 @@ get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred, { u_int32_t maj_stat, min_stat; gss_buffer_desc name; - char *sname, *realm, *slash; + char *sname, *host, *realm; + const int namebuf_size = 512; + char namebuf[namebuf_size]; int res = -1; gss_OID name_type = GSS_C_NO_OID; struct passwd *pw; @@ -323,8 +325,6 @@ get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred, return -1; } memcpy(sname, name.value, name.length); - printerr(1, "%s: authenticated %s from %016llx\n", - lustre_svc_name[lustre_svc], sname, nid); gss_release_buffer(&min_stat, &name); if (lustre_svc == LUSTRE_GSS_SVC_MDS) @@ -333,64 +333,91 @@ get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred, cred->cr_mapped_uid = -1; realm = strchr(sname, '@'); - if (!realm) { - printerr(0, "WARNNING: principal %s contains no realm name\n", - sname); - cred->cr_remote = (mds_local_realm != NULL); - } else { + if (realm) *realm++ = '\0'; - if (!mds_local_realm) - cred->cr_remote = 1; - else - cred->cr_remote = - (strcasecmp(mds_local_realm, realm) != 0); - } - if (cred->cr_remote) { - if (cred->cr_mapped_uid != -1) - res = 0; - else if (lustre_svc == LUSTRE_GSS_SVC_OSS && - strcmp(sname, "lustre_root") == 0) - res = 0; - else - printerr(0, "principal %s is remote without mapping\n", - sname); + host = strchr(sname, '/'); + if (host) + *host++ = '\0'; + + if (strcmp(sname, GSSD_SERVICE_OSS) == 0) { + printerr(0, "forbid "GSSD_SERVICE_OSS" as user name\n"); goto out_free; - } + } + + /* 1. check host part */ + if (host) { + if (lnet_nid2hostname(nid, namebuf, namebuf_size)) { + printerr(0, "ERROR: failed to resolve hostname for " + "%s/%s@%s from %016llx\n", + sname, host, realm, nid); + goto out_free; + } + + if (strcasecmp(host, namebuf)) { + printerr(0, "ERROR: %s/%s@s claimed hostname doesn't " + "match %s, nid %016llx\n", sname, host, realm, + namebuf, nid); + goto out_free; + } + } else { + if (!strcmp(sname, GSSD_SERVICE_MDS)) { + printerr(0, "ERROR: "GSSD_SERVICE_MDS"@%s from %016llx " + "doesn't bind with hostname\n", + realm ? realm : "", nid); + goto out_free; + } + } - slash = strchr(sname, '/'); - if (slash) - *slash = '\0'; + /* 2. check realm */ + if (!realm) { + /* just deny it + cred->cr_remote = (mds_local_realm != NULL); + */ + printerr(0, "ERROR: %s%s%s have no realm name\n", + sname, host ? "/" : "", host ? "host" : ""); + goto out_free; + } + + if (!mds_local_realm || strcasecmp(mds_local_realm, realm)) { + cred->cr_remote = 1; + + if (cred->cr_mapped_uid == -1) + printerr(0, "ERROR: %s from %016llx is remote but " + "without mapping\n", sname, nid); + /* mapped, skip user checking */ + goto out_free; + } + /* 3. check user */ if (!(pw = getpwnam(sname))) { - /* If client use machine credential, we map it to root, which - * will subject to further mapping by root-squash in kernel. - * - * MDS service keytab is treated as special user, also mapped - * to root. OSS service keytab can't be used as a user. - */ + /* map lustre_root/lustre_mds to root user, which is subject + * to further mapping by root-squash in kernel. */ if (!strcmp(sname, LUSTRE_ROOT_NAME)) { - printerr(2, "lustre_root principal, resolve to uid 0\n"); cred->cr_uid = 0; cred->cr_usr_root = 1; } else if (!strcmp(sname, GSSD_SERVICE_MDS)) { - printerr(2, "mds service principal, resolve to uid 0\n"); cred->cr_uid = 0; cred->cr_usr_mds = 1; } else { - cred->cr_uid = -1; if (cred->cr_mapped_uid == -1) { - printerr(0, "invalid user %s\n", sname); + printerr(0, "ERROR: invalid user, %s/%s@%s " + "from %016llx\n", sname, host, + realm, nid); goto out_free; } - printerr(2, "user %s mapped to %u\n", - sname, cred->cr_mapped_uid); } + printerr(2, "user %s from %016llx is mapped to %u\n", + sname, nid, cred->cr_mapped_uid); } else { + /* note: a mapped local user will go to here too */ cred->cr_uid = pw->pw_uid; printerr(2, "%s resolve to uid %u\n", sname, cred->cr_uid); } + printerr(1, "%s: authenticated %s%s%s@%s from %016llx\n", + lustre_svc_name[lustre_svc], sname, + host ? "/" : "", host ? host : "", realm, nid); res = 0; out_free: free(sname); diff --git a/lustre/utils/l_facl.c b/lustre/utils/l_facl.c deleted file mode 100644 index d9eaa2c..0000000 --- a/lustre/utils/l_facl.c +++ /dev/null @@ -1,268 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 2004-2006 Cluster File Systems, Inc. - * - * This file is part of Lustre, http://www.lustre.org. - * - * Lustre is free 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. - * - * 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 - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Lustre; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "obdctl.h" - -static char *progname; - -static void usage(void) -{ - fprintf(stderr, - "\nusage: %s {uid} {gid} {mdtname} {key} {handle} {cmd}\n" - "Normally invoked as an upcall from Lustre, set via:\n" - " /proc/fs/lustre/mdt/{mdtname}/rmtacl_upcall\n", - progname); -} - -static inline void show_result(struct rmtacl_downcall_data *data) -{ - fprintf(stdout, "buflen %d\n\n%s\n", data->add_buflen, data->add_buf); -} - -#define MDS_ERR "server processing error" - -static void errlog(char *buf, const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - vsprintf(buf, fmt, args); - va_end(args); -} - -static char *get_lustre_mount(void) -{ - FILE *fp; - struct mntent *mnt; - static char mntpath[PATH_MAX] = ""; - - fp = setmntent(MOUNTED, "r"); - if (fp == NULL) { - fprintf(stderr, "setmntent %s failed: %s\n", - MOUNTED, strerror(errno)); - return NULL; - } - - while (1) { - mnt = getmntent(fp); - if (!mnt) - break; - - if (!llapi_is_lustre_mnttype(mnt->mnt_type)) - continue; - - /* - * XXX: The fsname can be configed by user, it should pass into as a parameter. - * Since we only need one client on mdt node for remote set{get}facl, it is - * unnecessary to do the accurate match for fsname, but match ":/" temporary. - */ - //if (strstr(mnt->mnt_fsname, ":/lustre")) { - /* save the mountpoint dir part */ - strncpy(mntpath, mnt->mnt_dir, sizeof(mntpath)); - endmntent(fp); - return mntpath; - //} - } - endmntent(fp); - - return NULL; -} - -int main(int argc, char **argv) -{ - struct rmtacl_downcall_data *data; - char procname[1024], *buf, *mntpath; - int out_pipe[2], err_pipe[2], pid, size, buflen, fd, rc; - - progname = basename(argv[0]); - - if (argc != 7) { - usage(); - return 1; - } - - size = offsetof(struct rmtacl_downcall_data, add_buf[RMTACL_SIZE_MAX]); - data = malloc(size); - if (!data) { - fprintf(stderr, "malloc %d failed\n", size); - return 1; - } - memset(data, 0, size); - data->add_magic = RMTACL_DOWNCALL_MAGIC; - data->add_key = strtoll(argv[4], NULL, 10); - data->add_handle = strtoul(argv[5], NULL, 10); - buf = data->add_buf; - - mntpath = get_lustre_mount(); - if (!mntpath) { - errlog(buf, MDS_ERR"(no lustre mounted on MDS)\n"); - goto downcall; - } - - /* create pipe */ - if (pipe(out_pipe) < 0 || pipe(err_pipe) < 0) { - errlog(buf, MDS_ERR"(pipe failed): %s\n", strerror(errno)); - goto downcall; - } - - if ((pid = fork()) < 0) { - errlog(buf, MDS_ERR"(fork failed): %s\n", strerror(errno)); - goto downcall; - } else if (pid == 0) { - uid_t uid; - gid_t gid; - - close(out_pipe[0]); - if (out_pipe[1] != STDOUT_FILENO) { - dup2(out_pipe[1], STDOUT_FILENO); - close(out_pipe[1]); - } - close(err_pipe[0]); - if (err_pipe[1] != STDERR_FILENO) { - dup2(err_pipe[1], STDERR_FILENO); - close(err_pipe[1]); - } - close(STDIN_FILENO); - - if (chdir(mntpath) < 0) { - fprintf(stderr, "chdir %s failed: %s\n", - mntpath, strerror(errno)); - return 1; - } - - gid = (gid_t)atoi(argv[2]); - if (gid) { - if (setgid(gid) == -1) { - fprintf(stderr, "setgid %u failed: %s\n", - gid, strerror(errno)); - return 1; - } - } - - uid = (uid_t)atoi(argv[1]); - if (uid) { - if (setuid(uid) == -1) { - fprintf(stderr, "setuid %u failed: %s\n", - uid, strerror(errno)); - return 1; - } - } - - execl("/bin/sh", "sh", "-c", argv[6], NULL); - fprintf(stderr, "execl %s failed: %s\n", - argv[6], strerror(errno)); - - return 1; - } - - /* parent process handling */ - close(out_pipe[1]); - close(err_pipe[1]); - - buflen = 0; - while (1) { - rc = read(out_pipe[0], buf + buflen, RMTACL_SIZE_MAX - buflen); - if (rc < 0) { - errlog(buf, MDS_ERR"(read failed): %s\n", - strerror(errno)); - break; - } - if (rc == 0) - break; - buflen += rc; - if (buflen >= RMTACL_SIZE_MAX) - break; - } - - if (buflen != 0) { - wait(&rc); - goto downcall; - } - - while (1) { - rc = read(err_pipe[0], buf + buflen, RMTACL_SIZE_MAX - buflen); - if (rc < 0) { - errlog(buf, MDS_ERR"(read failed): %s\n", - strerror(errno)); - break; - } - if (rc == 0) - break; - buflen += rc; - if (buflen >= RMTACL_SIZE_MAX) - break; - } - - wait(&rc); - -downcall: - buf[RMTACL_SIZE_MAX - 1] = 0; - data->add_buflen = strlen(buf) + 1; - if (getenv("L_FACL_TEST")) { - show_result(data); - free(data); - return 0; - } - - snprintf(procname, sizeof(procname), - "/proc/fs/lustre/mdt/%s/rmtacl_info", argv[3]); - fd = open(procname, O_WRONLY); - if (fd < 0) { - fprintf(stderr, "open %s failed: %s\n", - procname, strerror(errno)); - free(data); - return 1; - } - - buflen = offsetof(struct rmtacl_downcall_data, - add_buf[data->add_buflen]); - rc = write(fd, data, buflen); - close(fd); - if (rc != buflen) { - fprintf(stderr, "write %s len %d return %d: %s\n", - procname, buflen, rc, strerror(errno)); - free(data); - return 1; - } - - free(data); - return 0; -} diff --git a/lustre/utils/l_getidentity.c b/lustre/utils/l_getidentity.c index c37057b..65e9f0b 100644 --- a/lustre/utils/l_getidentity.c +++ b/lustre/utils/l_getidentity.c @@ -39,17 +39,17 @@ #include #include -#define SETXID_PATHNAME "/etc/lustre/setxid.conf" +#define PERM_PATHNAME "/etc/lustre/perm.conf" /* - * setxid permission file format is like this: + * permission file format is like this: * {nid} {uid} {perms} * * '*' nid means any nid * '*' uid means any uid * the valid values for perms are: - * setuid/setgid/setgrp -- enable corresponding perm - * nosetuid/nosetgid/nosetgrp -- disable corresponding perm + * setuid/setgid/setgrp/rmtacl -- enable corresponding perm + * nosetuid/nosetgid/nosetgrp/normtacl -- disable corresponding perm * they can be listed together, seperated by ',', * when perm and noperm are in the same line (item), noperm is preferential, * when they are in different lines (items), the latter is preferential, @@ -174,27 +174,29 @@ static inline int match_uid(uid_t uid, const char *str) typedef struct { char *name; __u32 bit; -} setxid_perm_type_t; +} perm_type_t; -static setxid_perm_type_t setxid_perm_types[] = { - { "setuid", LUSTRE_SETUID_PERM }, - { "setgid", LUSTRE_SETGID_PERM }, - { "setgrp", LUSTRE_SETGRP_PERM }, +static perm_type_t perm_types[] = { + { "setuid", CFS_SETUID_PERM }, + { "setgid", CFS_SETGID_PERM }, + { "setgrp", CFS_SETGRP_PERM }, + { "rmtacl", CFS_RMTACL_PERM }, { 0 } }; -static setxid_perm_type_t setxid_noperm_types[] = { - { "nosetuid", LUSTRE_SETUID_PERM }, - { "nosetgid", LUSTRE_SETGID_PERM }, - { "nosetgrp", LUSTRE_SETGRP_PERM }, +static perm_type_t noperm_types[] = { + { "nosetuid", CFS_SETUID_PERM }, + { "nosetgid", CFS_SETGID_PERM }, + { "nosetgrp", CFS_SETGRP_PERM }, + { "normtacl", CFS_RMTACL_PERM }, { 0 } }; -int parse_setxid_perm(__u32 *perm, __u32 *noperm, char *str) +int parse_perm(__u32 *perm, __u32 *noperm, char *str) { char *start, *end; char name[64]; - setxid_perm_type_t *pt; + perm_type_t *pt; *perm = 0; *noperm = 0; @@ -207,7 +209,7 @@ int parse_setxid_perm(__u32 *perm, __u32 *noperm, char *str) if (start >= end) break; strncpy(name, start, end - start); - for (pt = setxid_perm_types; pt->name; pt++) { + for (pt = perm_types; pt->name; pt++) { if (!strcasecmp(name, pt->name)) { *perm |= pt->bit; break; @@ -215,7 +217,7 @@ int parse_setxid_perm(__u32 *perm, __u32 *noperm, char *str) } if (!pt->name) { - for (pt = setxid_noperm_types; pt->name; pt++) { + for (pt = noperm_types; pt->name; pt++) { if (!strcasecmp(name, pt->name)) { *noperm |= pt->bit; break; @@ -233,16 +235,16 @@ int parse_setxid_perm(__u32 *perm, __u32 *noperm, char *str) return 0; } -int parse_setxid_perm_line(struct identity_downcall_data *data, char *line) +int parse_perm_line(struct identity_downcall_data *data, char *line) { char uid_str[256], nid_str[256], perm_str[256]; lnet_nid_t nid; __u32 perm, noperm; int rc, i; - if (data->idd_nperms >= N_SETXID_PERMS_MAX) { - errlog("setxid permission count %d > max %d\n", - data->idd_nperms, N_SETXID_PERMS_MAX); + if (data->idd_nperms >= N_PERMS_MAX) { + errlog("permission count %d > max %d\n", + data->idd_nperms, N_PERMS_MAX); return -1; } @@ -265,7 +267,7 @@ int parse_setxid_perm_line(struct identity_downcall_data *data, char *line) } } - if (parse_setxid_perm(&perm, &noperm, perm_str)) { + if (parse_perm(&perm, &noperm, perm_str)) { errlog("invalid perm %s\n", perm_str); return -1; } @@ -324,7 +326,7 @@ int parse_setxid_perm_line(struct identity_downcall_data *data, char *line) return 0; } -int get_setxid_perms(FILE *fp, struct identity_downcall_data *data) +int get_perms(FILE *fp, struct identity_downcall_data *data) { char line[1024]; @@ -332,7 +334,7 @@ int get_setxid_perms(FILE *fp, struct identity_downcall_data *data) if (comment_line(line)) continue; - if (parse_setxid_perm_line(data, line)) { + if (parse_perm_line(data, line)) { errlog("parse line %s failed!\n", line); return -1; } @@ -355,10 +357,10 @@ static void show_result(struct identity_downcall_data *data) for (i = 0; i < data->idd_ngroups; i++) printf("%s%u", i > 0 ? "," : "", data->idd_groups[i]); printf("\n"); - printf("setxid permissions:\n" + printf("permissions:\n" " nid\t\t\tperm\n"); for (i = 0; i < data->idd_nperms; i++) { - struct setxid_perm_downcall_data *pdd; + struct perm_downcall_data *pdd; pdd = &data->idd_perms[i]; @@ -406,13 +408,13 @@ int main(int argc, char **argv) goto downcall; /* read permission database */ - perms_fp = fopen(SETXID_PATHNAME, "r"); + perms_fp = fopen(PERM_PATHNAME, "r"); if (perms_fp) { - get_setxid_perms(perms_fp, data); + get_perms(perms_fp, data); fclose(perms_fp); } else if (errno != ENOENT) { errlog("open %s failed: %s\n", - SETXID_PATHNAME, strerror(errno)); + PERM_PATHNAME, strerror(errno)); } downcall: diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index 4c7a99e..8d8d0d8 100644 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -71,8 +71,12 @@ static int lfs_quota(int argc, char **argv); #endif static int lfs_flushctx(int argc, char **argv); static int lfs_join(int argc, char **argv); -static int lfs_getfacl(int argc, char **argv); -static int lfs_setfacl(int argc, char **argv); +static int lfs_lsetfacl(int argc, char **argv); +static int lfs_lgetfacl(int argc, char **argv); +static int lfs_rsetfacl(int argc, char **argv); +static int lfs_rgetfacl(int argc, char **argv); +static int lfs_cp(int argc, char **argv); +static int lfs_ls(int argc, char **argv); /* all avaialable commands */ command_t cmdlist[] = { @@ -143,12 +147,24 @@ command_t cmdlist[] = { #endif {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n" "usage: flushctx [-k] [mountpoint...]"}, - {"getfacl", lfs_getfacl, 0, - "Get file access control list in remote client.\n" - "usage: getfacl [-dRLPvh] file"}, - {"setfacl", lfs_setfacl, 0, - "Set file access control list in remote client.\n" - "usage: setfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file"}, + {"lsetfacl", lfs_lsetfacl, 0, + "Remote user setfacl for user/group on the same remote client.\n" + "usage: lsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."}, + {"lgetfacl", lfs_lgetfacl, 0, + "Remote user getfacl for user/group on the same remote client.\n" + "usage: lgetfacl [-dRLPvh] file ..."}, + {"rsetfacl", lfs_rsetfacl, 0, + "Remote user setfacl for user/group on other clients.\n" + "usage: rsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."}, + {"rgetfacl", lfs_rgetfacl, 0, + "Remote user getfacl for user/group on other clients.\n" + "usage: rgetfacl [-dRLPvh] file ..."}, + {"cp", lfs_cp, 0, + "Remote user copy files and directories.\n" + "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."}, + {"ls", lfs_ls, 0, + "Remote user list directory contents.\n" + "usage: ls [OPTION]... [FILE]..."}, {"help", Parser_help, 0, "help"}, {"exit", Parser_quit, 0, "quit"}, {"quit", Parser_quit, 0, "quit"}, @@ -1862,117 +1878,38 @@ static int lfs_flushctx(int argc, char **argv) return rc; } -/* - * We assume one and only one filename is supplied as the - * last parameter. - */ -static int acl_cmd_parse(int argc, char **argv, char *fname, char *cmd) +static int lfs_lsetfacl(int argc, char **argv) { - char *dname, *rpath = NULL; - char path[PATH_MAX], cwd[PATH_MAX]; - FILE *fp; - struct mntent *mnt; - int i; - - if (argc < 2) - return -1; - - /* FIXME the premise is there is no sub-mounted filesystems under this - * mounted lustre tree. */ - strncpy(fname, argv[argc - 1], PATH_MAX); - - /* get path prefix */ - dname = dirname(fname); - - /* try to resolve the pathname into relative to the root of the mounted - * lustre filesystem. - */ - if (getcwd(cwd, sizeof(cwd)) == NULL) { - fprintf(stderr, "getcwd %s failed: %s\n", cwd, strerror(errno)); - return -1; - } - - if (chdir(dname) == -1) { - fprintf(stderr, "chdir to %s failed: %s\n", - dname, strerror(errno)); - return -1; - } - - if (getcwd(path, sizeof(path)) == NULL) { - fprintf(stderr, "getcwd %s: %s\n", path, strerror(errno)); - return -1; - } - - if (chdir(cwd) == -1) { - fprintf(stderr, "chdir back to %s: %s\n", - cwd, strerror(errno)); - return -1; - } - - strncat(path, "/", PATH_MAX); - strncpy(fname, argv[argc - 1], PATH_MAX); - strncat(path, basename(fname), PATH_MAX); - - fp = setmntent(MOUNTED, "r"); - if (fp == NULL) { - fprintf(stderr, "setmntent %s failed: %s\n", - MOUNTED, strerror(errno)); - return -1; - } - - while (1) { - mnt = getmntent(fp); - if (!mnt) - break; - - if (!llapi_is_lustre_mnttype(mnt->mnt_type)) - continue; - - if (!strncmp(mnt->mnt_dir, path, strlen(mnt->mnt_dir))) { - rpath = path + strlen(mnt->mnt_dir); - break; - } - } - endmntent(fp); - - /* remove char '/' from rpath to be a relative path */ - while (rpath && *rpath == '/') rpath++; - - if (!rpath) { - fprintf(stderr, - "%s: file %s doesn't belong to a lustre file system!\n", - argv[0], argv[argc - 1]); - return -1; - } - - for (i = 0; i < argc - 1; i++) { - strncat(cmd, argv[i], PATH_MAX); - strncat(cmd, " ", PATH_MAX); - } - strncat(cmd, *rpath ? rpath : ".", PATH_MAX); - strncpy(fname, argv[argc - 1], sizeof(fname)); - - return 0; + argv[0]++; + return(llapi_lsetfacl(argc, argv)); } -static int lfs_getfacl(int argc, char **argv) +static int lfs_lgetfacl(int argc, char **argv) { - char fname[PATH_MAX] = "", cmd[PATH_MAX] = ""; - - if (acl_cmd_parse(argc, argv, fname, cmd)) - return CMD_HELP; + argv[0]++; + return(llapi_lgetfacl(argc, argv)); +} - return llapi_getfacl(fname, cmd); +static int lfs_rsetfacl(int argc, char **argv) +{ + argv[0]++; + return(llapi_rsetfacl(argc, argv)); } -static int lfs_setfacl(int argc, char **argv) +static int lfs_rgetfacl(int argc, char **argv) { - char fname[PATH_MAX] = "", cmd[PATH_MAX] = ""; + argv[0]++; + return(llapi_rgetfacl(argc, argv)); +} - if (acl_cmd_parse(argc, argv, fname, cmd)) - return CMD_HELP; +static int lfs_cp(int argc, char **argv) +{ + return(llapi_cp(argc, argv)); +} - return llapi_setfacl(fname, cmd); +static int lfs_ls(int argc, char **argv) +{ + return(llapi_ls(argc, argv)); } int main(int argc, char **argv) diff --git a/lustre/utils/liblustreapi.c b/lustre/utils/liblustreapi.c index 185be04..d43a7a2 100644 --- a/lustre/utils/liblustreapi.c +++ b/lustre/utils/liblustreapi.c @@ -1697,67 +1697,293 @@ out: return ret; } -int llapi_getfacl(char *fname, char *cmd) +#include +#include +#include +#include +#include +#include + +static int rmtacl_notify(int ops) { - struct rmtacl_ioctl_data data; - char out[RMTACL_SIZE_MAX] = ""; - int fd, rc; - - data.cmd = cmd; - data.cmd_len = strlen(cmd) + 1; - data.res = out; - data.res_len = sizeof(out); - - fd = open(fname, 0); - if (fd == -1) { - llapi_err(LLAPI_MSG_ERROR,"open %s failed", fname); + FILE *fp; + struct mntent *mnt; + int found = 0, fd, rc; + + fp = setmntent(MOUNTED, "r"); + if (fp == NULL) { + perror("setmntent"); return -1; } - rc = ioctl(fd, LL_IOC_GETFACL, &data); - close(fd); - if (errno == EBADE) { - llapi_err(LLAPI_MSG_ERROR, "Please use getfacl directly!"); - rc = 1; - } else if (rc) { - llapi_err(LLAPI_MSG_ERROR,"getfacl %s failed", fname); + while (1) { + mnt = getmntent(fp); + if (!mnt) + break; + + if (!llapi_is_lustre_mnt(mnt)) + continue; + + fd = open(mnt->mnt_dir, O_RDONLY | O_DIRECTORY); + if (fd < 0) { + perror("open"); + return -1; + } + + rc = ioctl(fd, LL_IOC_RMTACL, ops); + if (rc < 0) { + perror("ioctl"); + return -1; + } + + found++; + } + endmntent(fp); + return found; +} + +static char *next_token(char *p, int div) +{ + if (p == NULL) + return NULL; + + if (div) + while (*p && *p != ':' && !isspace(*p)) + p++; + else + while (*p == ':' || isspace(*p)) + p++; + + return *p ? p : NULL; +} + +static int rmtacl_name2id(char *name, int is_user) +{ + if (is_user) { + struct passwd *pw; + + if ((pw = getpwnam(name)) == NULL) + return INVALID_ID; + else + return (int)(pw->pw_uid); } else { - llapi_printf(LLAPI_MSG_NORMAL, "%s", out); + struct group *gr; + + if ((gr = getgrnam(name)) == NULL) + return INVALID_ID; + else + return (int)(gr->gr_gid); } +} - return rc; +static int isodigit(int c) +{ + return (c >= '0' && c <= '7') ? 1 : 0; +} + +/* + * Whether the name is just digits string (uid/gid) already or not. + * Return value: + * 1: str is id + * 0: str is not id + */ +static int str_is_id(char *str) +{ + if (str == NULL) + return 0; + + if (*str == '0') { + str++; + if (*str == 'x' || *str == 'X') { /* for Hex. */ + if (!isxdigit(*(++str))) + return 0; + + while (isxdigit(*(++str))); + } else if (isodigit(*str)) { /* for Oct. */ + while (isodigit(*(++str))); + } + } else if (isdigit(*str)) { /* for Dec. */ + while (isdigit(*(++str))); + } + + return (*str == 0) ? 1 : 0; } -int llapi_setfacl(char *fname, char *cmd) +typedef struct { + char *name; + int length; + int is_user; + int next_token; +} rmtacl_name_t; + +#define RMTACL_OPTNAME(name) name, sizeof(name) - 1 + +static rmtacl_name_t rmtacl_namelist[] = { + { RMTACL_OPTNAME("user:"), 1, 0 }, + { RMTACL_OPTNAME("group:"), 0, 0 }, + { RMTACL_OPTNAME("default:user:"), 1, 0 }, + { RMTACL_OPTNAME("default:group:"), 0, 0 }, + /* for --tabular option */ + { RMTACL_OPTNAME("user"), 1, 1 }, + { RMTACL_OPTNAME("group"), 0, 1 }, + { 0 } +}; + +static int rgetfacl_output(char *str) { - struct rmtacl_ioctl_data data; - char out[RMTACL_SIZE_MAX] = ""; - int fd, rc; - - data.cmd = cmd; - data.cmd_len = strlen(cmd) + 1; - data.res = out; - data.res_len = sizeof(out); - - fd = open(fname, 0); - if (fd == -1) { - llapi_err(LLAPI_MSG_ERROR,"open %s failed", fname); + char *start = NULL, *end = NULL; + int is_user = 0, n, id; + char c; + rmtacl_name_t *rn; + + if (str == NULL) return -1; + + for (rn = rmtacl_namelist; rn->name; rn++) { + if(strncmp(str, rn->name, rn->length) == 0) { + if (!rn->next_token) + start = str + rn->length; + else + start = next_token(str + rn->length, 0); + is_user = rn->is_user; + break; + } } - rc = ioctl(fd, LL_IOC_SETFACL, &data); - close(fd); - if (errno == EBADE) { - llapi_err(LLAPI_MSG_ERROR, "Please use setfacl directly!"); - rc = 1; - } else if (errno == EOPNOTSUPP) { - llapi_err(LLAPI_MSG_ERROR, "setfacl: %s: %s", fname); - rc = 1; - } else if (rc) { - llapi_err(LLAPI_MSG_ERROR,"setfacl %s failed", fname); + end = next_token(start, 1); + if (end == NULL || start == end) { + n = printf("%s", str); + return n; + } + + c = *end; + *end = 0; + id = rmtacl_name2id(start, is_user); + if (id == INVALID_ID) { + if (str_is_id(start)) { + *end = c; + n = printf("%s", str); + } else + return -1; + } else if ((id == NOBODY_UID && is_user) || + (id == NOBODY_GID && !is_user)) { + *end = c; + n = printf("%s", str); } else { - llapi_printf(LLAPI_MSG_NORMAL, "%s", out); + *end = c; + *start = 0; + n = printf("%s%d%s", str, id, end); } + return n; +} - return rc; +static int child_status(int status) +{ + return WIFEXITED(status) ? WEXITSTATUS(status) : -1; +} + +static int do_rmtacl(int argc, char *argv[], int ops, int (output_func)(char *)) +{ + pid_t pid = 0; + int fd[2], status; + FILE *fp; + char buf[PIPE_BUF]; + + if (output_func) { + if (pipe(fd) < 0) { + perror("pipe"); + return -1; + } + + if ((pid = fork()) < 0) { + perror("pipe"); + close(fd[0]); + close(fd[1]); + return -1; + } else if (!pid) { + /* child process redirects its output. */ + close(fd[0]); + close(1); + if (dup2(fd[1], 1) < 0) { + perror("dup2"); + close(fd[1]); + return -1; + } + } else { + close(fd[1]); + } + } + + if (!pid) { + status = rmtacl_notify(ops); + if (status < 0) + return -1; + + exit(execvp(argv[0], argv)); + } + + /* the following is parent process */ + if ((fp = fdopen(fd[0], "r")) == NULL) { + perror("fdopen"); + kill(pid, SIGKILL); + close(fd[0]); + return -1; + } + + while (fgets(buf, PIPE_BUF, fp) != NULL) { + if (output_func(buf) < 0) + fprintf(stderr, "WARNING: unexpected error!\n[%s]\n", + buf); + } + fclose(fp); + close(fd[0]); + + if (waitpid(pid, &status, 0) < 0) { + perror("waitpid"); + return -1; + } + + return child_status(status); +} + +int llapi_lsetfacl(int argc, char *argv[]) +{ + return do_rmtacl(argc, argv, RMT_LSETFACL, NULL); +} + +int llapi_lgetfacl(int argc, char *argv[]) +{ + return do_rmtacl(argc, argv, RMT_LGETFACL, NULL); +} + +int llapi_rsetfacl(int argc, char *argv[]) +{ + return do_rmtacl(argc, argv, RMT_RSETFACL, NULL); +} + +int llapi_rgetfacl(int argc, char *argv[]) +{ + return do_rmtacl(argc, argv, RMT_RGETFACL, rgetfacl_output); +} + +int llapi_cp(int argc, char *argv[]) +{ + int rc; + + rc = rmtacl_notify(RMT_RSETFACL); + if (rc < 0) + return -1; + + exit(execvp(argv[0], argv)); +} + +int llapi_ls(int argc, char *argv[]) +{ + int rc; + + rc = rmtacl_notify(RMT_LGETFACL); + if (rc < 0) + return -1; + + exit(execvp(argv[0], argv)); } diff --git a/lustre/utils/module_setup.sh b/lustre/utils/module_setup.sh index 8597bcd..b0db190 100755 --- a/lustre/utils/module_setup.sh +++ b/lustre/utils/module_setup.sh @@ -63,7 +63,7 @@ depmod -A -e echo "Copying mount from local build dir to "$MDIR cp -u ../utils/mount.lustre /sbin/. cp -u ../utils/l_getidentity /usr/sbin/. -cp -u ../utils/l_facl /usr/sbin/. +cp -u ../utils/lfs /usr/sbin/. MP="/sbin/modprobe" MPI="$MP --ignore-install"