Whamcloud - gitweb
LU-17015 gss: support large kerberos token for rpc sec init 24/52224/28
authorSebastien Buisson <sbuisson@ddn.com>
Thu, 7 Sep 2023 07:28:45 +0000 (09:28 +0200)
committerOleg Drokin <green@whamcloud.com>
Wed, 25 Oct 2023 18:07:26 +0000 (18:07 +0000)
If the current Kerberos setup is using large token, like when PAC
feature is enabled for Kerberos, authentication can fail due to server
side unable to exchange token between kernel and userspace.
This limitation is inherent to the sunrpc cache mechanism, that can
only handle tokens up to PAGE_SIZE.

For RPC sec init phase, use Lustre's upcall cache mechanism
instead of deprecated kernel's sunrpc cache. The upcall calls a new
userspace command 'l_getauth', that fowards the sec init request to
the lsvcgssd daemon via Unix domain sockets.

Test-Parameters: kerberos=true testlist=sanity-krb5
Change-Id: I709cd79894a5a13fc4cdfab2109c86f2230db3b8
Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/52224
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Aurelien Degremont <adegremont@nvidia.com>
26 files changed:
libcfs/libcfs/crypto/fname.c
libcfs/libcfs/crypto/llcrypt_private.h
lustre/include/lustre_sec.h
lustre/include/uapi/linux/lustre/lgss.h
lustre/include/uapi/linux/lustre/lustre_disk.h
lustre/include/uapi/linux/lustre/lustre_idl.h
lustre/include/upcall_cache.h
lustre/obdclass/Makefile.in
lustre/obdclass/upcall_cache.c
lustre/ptlrpc/gss/gss_api.h
lustre/ptlrpc/gss/gss_internal.h
lustre/ptlrpc/gss/gss_svc_upcall.c
lustre/ptlrpc/gss/lproc_gss.c
lustre/ptlrpc/wiretest.c
lustre/tests/sanity-sec.sh
lustre/tests/test-framework.sh
lustre/utils/gss/.gitignore
lustre/utils/gss/Makefile.am
lustre/utils/gss/l_getauth.c [new file with mode: 0644]
lustre/utils/gss/lsupport.h
lustre/utils/gss/svcgssd.c
lustre/utils/gss/svcgssd.h
lustre/utils/gss/svcgssd_main_loop.c
lustre/utils/gss/svcgssd_proc.c
lustre/utils/wirecheck.c
lustre/utils/wiretest.c

index 65b6b42..91a2159 100644 (file)
@@ -207,9 +207,6 @@ static inline int llcrypt_base64_decode(const char *src, int len, u8 *dst)
  * This base64 encoding is RFC 4648 compliant base64-url encoding.
  */
 
-static const char base64url_table[] =
-       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
-
 #define LLCRYPT_BASE64URL_CHARS(nbytes)        DIV_ROUND_UP((nbytes) * 4, 3)
 
 /**
index 06eafaf..14d494e 100644 (file)
@@ -18,6 +18,7 @@
 #include <libcfs/crypto/llcrypt.h>
 #include <crypto/hash.h>
 #include <lustre_disk.h>
+#include <uapi/linux/lustre/lgss.h>
 
 #ifndef CRYPTO_TFM_REQ_FORBID_WEAK_KEYS
 #define CRYPTO_TFM_REQ_FORBID_WEAK_KEYS CRYPTO_TFM_REQ_WEAK_KEY
index c6e5202..e51e631 100644 (file)
@@ -1154,12 +1154,49 @@ void sptlrpc_target_update_exp_flavor(struct obd_device *obd,
                                       struct sptlrpc_rule_set *rset);
 
 /*
- * reverse context
+ * context and reverse context
  */
+#define GSS_SEQ_WIN                    (2048)
+#define GSS_SEQ_WIN_MAIN               GSS_SEQ_WIN
+#define GSS_SEQ_WIN_BACK               (128)
+#define GSS_SEQ_REPACK_THRESHOLD       (GSS_SEQ_WIN_MAIN / 2 + \
+                                        GSS_SEQ_WIN_MAIN / 4)
+
+struct gss_svc_seq_data {
+       spinlock_t              ssd_lock;
+       /*
+        * highest sequence number seen so far, for main and back window
+        */
+       __u32                   ssd_max_main;
+       __u32                   ssd_max_back;
+       /*
+        * main and back window
+        * for i such that ssd_max - GSS_SEQ_WIN < i <= ssd_max, the i-th bit
+        * of ssd_win is nonzero iff sequence number i has been seen already.
+        */
+       unsigned long           ssd_win_main[GSS_SEQ_WIN_MAIN/BITS_PER_LONG];
+       unsigned long           ssd_win_back[GSS_SEQ_WIN_BACK/BITS_PER_LONG];
+};
+
+struct gss_svc_ctx {
+       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;
+       unsigned int            gsc_usr_root:1,
+                               gsc_usr_mds:1,
+                               gsc_usr_oss:1,
+                               gsc_remote:1,
+                               gsc_reverse:1;
+};
+
 int sptlrpc_svc_install_rvs_ctx(struct obd_import *imp,
-                                struct ptlrpc_svc_ctx *ctx);
+                               struct ptlrpc_svc_ctx *ctx);
 int sptlrpc_cli_install_rvs_ctx(struct obd_import *imp,
-                                struct ptlrpc_cli_ctx *ctx);
+                               struct ptlrpc_cli_ctx *ctx);
 
 /* bulk security api */
 int sptlrpc_enc_pool_add_user(void);
index 52c67fe..8386fec 100644 (file)
 #ifndef _LGSS_H
 #define _LGSS_H
 
+#ifndef __KERNEL__
+# define __USE_ISOC99  1
+# include <stdio.h> /* snprintf() */
+# include <stdlib.h> /* abs() */
+# include <inttypes.h> /* PRIu64 */
+# include <ctype.h> /* isascii() */
+# define __USE_GNU      1
+# define __USE_XOPEN2K8  1
+#else
+#include <linux/ctype.h>
+#define PRIu64 "llu"
+#define PRIx64 "llx"
+#endif /* !__KERNEL__ */
+
 #include <linux/types.h>
+#include <linux/string.h>
+#include <linux/unistd.h>
 
 /*
  * sparse kernel source annotations
@@ -55,4 +71,434 @@ struct lgssd_ioctl_param {
        __u64 reply_length;
 };
 
+#define GSS_SOCKET_PATH        "/tmp/svcgssd.socket"
+#define RSI_DOWNCALL_MAGIC     0x6d6dd62a
+#define RSI_DOWNCALL_PATH      "sptlrpc/gss/rsi_info"
+#define RSI_CACHE_NAME         "rsicache"
+
+struct rsi_downcall_data {
+       __u32     sid_magic;
+       __u32     sid_err;
+       __u32     sid_hash;
+       __u32     sid_maj_stat;
+       __u32     sid_min_stat;
+       __u32     sid_len;
+       __s64     sid_offset;
+       /* sid_val contains in_handle, in_token,
+        * out_handle, out_token
+        */
+       char      sid_val[0];
+};
+
+/*
+ * gss_string_write() - write some string
+ *
+ * If string is empty, write single digit 0.
+ * Pad with a trailing space.
+ */
+static inline void gss_string_write(char **dst, int *dstlen, const char *src)
+{
+       char *cp = *dst;
+       int ret;
+
+       if (*dstlen < 0)
+               return;
+
+       if (!strlen(src))
+               ret = snprintf(cp, *dstlen, "0");
+       else
+               ret = snprintf(cp, *dstlen, "%s", src);
+       if (ret >= *dstlen) {
+               cp += *dstlen;
+               *dstlen = -1;
+       } else {
+               cp[ret] = ' ';
+               cp += ret + 1;
+               *dstlen -= ret + 1;
+       }
+       *dst = cp;
+}
+
+/*
+ * gss_u64_write() - write some u64
+ */
+static inline void gss_u64_write_string(char **dst, int *dstlen, uint64_t n)
+{
+       char *cp = *dst;
+       int ret;
+
+       if (*dstlen < 0)
+               return;
+
+       ret = snprintf(cp, *dstlen, "%"PRIu64, n);
+       if (ret >= *dstlen) {
+               cp += *dstlen;
+               *dstlen = -1;
+       } else {
+               cp[ret] = ' ';
+               cp += ret + 1;
+               *dstlen -= ret + 1;
+       }
+       *dst = cp;
+}
+
+/*
+ * gss_u64_write_hex() - write some u64 in hex
+ */
+static inline void gss_u64_write_hex_string(char **dst, int *dstlen, uint64_t n)
+{
+       char *cp = *dst;
+       int ret;
+
+       if (*dstlen < 0)
+               return;
+
+       ret = snprintf(cp, *dstlen, "0x%"PRIx64, n);
+       if (ret >= *dstlen) {
+               cp += *dstlen;
+               *dstlen = -1;
+       } else {
+               cp[ret] = ' ';
+               cp += ret + 1;
+               *dstlen -= ret + 1;
+       }
+       *dst = cp;
+}
+
+/*
+ * gss_buffer_write() - write some buffer
+ */
+static inline void gss_buffer_write(char **dst, int *dstlen,
+                                   const __u8 *src, int srclen)
+{
+       char *cp = *dst;
+       int len = *dstlen;
+       __u32 *p;
+
+       if (len < 0)
+               return;
+
+       if (len < sizeof(__u32)) {
+               len = -1;
+               goto out;
+       }
+
+       /* write size of data */
+       p = (__u32 *)cp;
+       *p = srclen;
+       cp += sizeof(__u32);
+       len -= sizeof(__u32);
+
+       if (!srclen)
+               goto out;
+
+       /* write data itself */
+       while (srclen && len) {
+               *cp++ = *src++;
+               len--;
+               srclen--;
+       }
+       if (!len && srclen)
+               len = -1;
+
+out:
+       *dst = cp;
+       *dstlen = len;
+}
+
+/*
+ * gss_u32_write() - write some u32
+ */
+static inline void gss_u32_write(char **dst, int *dstlen, __u32 val)
+{
+       char *cp = *dst;
+       int len = *dstlen;
+       __u32 *p;
+
+       if (len < 0)
+               return;
+
+       if (len < sizeof(__u32)) {
+               len = -1;
+               goto out;
+       }
+
+       p = (__u32 *)cp;
+       *p = val;
+       cp += sizeof(__u32);
+       len -= sizeof(__u32);
+
+out:
+       *dst = cp;
+       *dstlen = len;
+}
+
+static const char base64url_table[] =
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+#define BASE64URL_CHARS(nbytes) ((((nbytes) * 4) + 3 - 1) / 3)
+
+/*
+ * gss_base64url_encode() - base64url-encode some binary data
+ *
+ * Encode data using base64url encoding, i.e. the "Base 64 Encoding with URL
+ * and Filename Safe Alphabet" specified by RFC 4648.  '='-padding isn't used,
+ * as it's unneeded and not required by the RFC.
+ * Pad with a trailing space.
+ */
+static inline void gss_base64url_encode(char **dst, int *dstlen,
+                                       const __u8 *src, int srclen)
+{
+       char *cp = *dst;
+       int len = *dstlen;
+       __u32 ac = 0;
+       int bits = 0;
+       int i;
+
+       if (len < 0)
+               return;
+
+       if (!srclen)
+               return gss_string_write(dst, dstlen, "");
+
+       for (i = 0; i < srclen; i++) {
+               if (!len)
+                       break;
+               ac = (ac << 8) | src[i];
+               bits += 8;
+               do {
+                       bits -= 6;
+                       *cp++ = base64url_table[(ac >> bits) & 0x3f];
+                       len--;
+               } while (bits >= 6 && len > 0);
+       }
+       if (i < srclen) {
+               len = -1;
+               goto out;
+       }
+
+       if (bits) {
+               *cp++ = base64url_table[(ac << (6 - bits)) & 0x3f];
+               len--;
+       }
+
+       if (!len) {
+               len = -1;
+               goto out;
+       }
+       *cp++ = ' ';
+       len--;
+
+out:
+       *dst = cp;
+       *dstlen = len;
+}
+
+/*
+ * gss_base64url_decode() - base64url-decode a string
+ *
+ * Decode a string using base64url encoding, i.e. the "Base 64 Encoding with
+ * URL and Filename Safe Alphabet" specified by RFC 4648.  '='-padding isn't
+ * accepted, nor are non-encoding characters such as whitespace.
+ * String end is marked with a trailing space or '\n' or '\0'.
+ */
+static inline int gss_base64url_decode(char **src, char *dst, int destsize)
+{
+       int bits = 0, len = 0;
+       char *cp = *src, *p;
+       char *bp = dst;
+       __u32 ac = 0;
+
+       while (*cp == ' ')
+               cp++;
+
+       /* the single digit 0 is inserted if field is empty */
+       if (*cp == '0' &&
+           (*(cp + 1) == ' ' || *(cp + 1) == '\n' || *(cp + 1) == '\0')) {
+               cp++;
+               goto fini;
+       }
+
+       while (isascii(*cp)) {
+               if (*cp == ' ' || *cp == '\n' || *cp == '\0')
+                       break;
+
+               p = strchr(base64url_table, *cp);
+               if (len > destsize || p == NULL || *cp == '\0') {
+                       len = -1;
+                       goto out;
+               }
+
+               cp++;
+               ac = (ac << 6) | (p - base64url_table);
+               bits += 6;
+               if (bits >= 8) {
+                       bits -= 8;
+                       *bp++ = (__u8)(ac >> bits);
+                       len++;
+               }
+       }
+
+       if (!isascii(*cp) || (ac & ((1 << bits) - 1))) {
+               len = -1;
+               goto out;
+       }
+
+fini:
+       *src = cp;
+out:
+       return len;
+}
+
+/*
+ * gss_string_read() - read some string
+ *
+ * An empty string is represented with the single digit 0.
+ * String end is marked with a trailing space or '\n' or '\0'.
+ */
+static inline int gss_string_read(char **src, char *dst, int destsize,
+                                 int allowzero)
+{
+       char *cp = *src;
+       char *bp = dst;
+       int len = 0;
+
+       while (*cp == ' ')
+               cp++;
+
+       /* the single digit 0 is inserted if field is empty */
+       if (!allowzero && *cp == '0' &&
+           (*(cp + 1) == ' ' || *(cp + 1) == '\n')) {
+               cp++;
+               goto out;
+       }
+
+       while (isascii(*cp)) {
+               if (*cp == ' ' || *cp == '\n')
+                       break;
+
+               if (len >= destsize || *cp == '\0') {
+                       len = -1;
+                       goto out;
+               }
+
+               *(bp++) = *(cp++);
+               len++;
+       }
+
+       if (!isascii(*cp)) {
+               len = -1;
+               goto out;
+       }
+
+       *src = cp;
+
+out:
+       return len;
+}
+
+#ifndef __KERNEL__
+/*
+ * gss_u64_read() - read some u64
+ */
+static inline int gss_u64_read_string(char **src, __u64 *n)
+{
+       char buf[24];
+       char *ep;
+       int ret;
+
+       ret = gss_string_read(src, buf, sizeof(buf), 1);
+       if (ret < 0)
+               return ret;
+
+       buf[ret] = '\0';
+       *n = strtoull(buf, &ep, 0);
+       if (*ep)
+               return -1;
+
+       return 0;
+}
 #endif
+
+/*
+ * gss_buffer_read() - read some buffer
+ */
+static inline int gss_buffer_read(char **src, char *dst, int destsize)
+{
+       char *cp = *src;
+       char *bp = dst;
+       __u32 *p;
+       int len, size;
+
+       /* read data size */
+       p = (__u32 *)cp;
+       len = *p;
+       cp += sizeof(__u32);
+
+       if (len > destsize) {
+               len = -1;
+               goto out;
+       }
+
+       if (!len)
+               goto fini;
+
+       /* read data itself */
+       size = len;
+       while (size && destsize) {
+               *(bp++) = *(cp++);
+               destsize--;
+               size--;
+       }
+       if (!destsize && size)
+               len = -1;
+
+fini:
+       *src = cp;
+out:
+       return len;
+}
+
+/*
+ * gss_buffer_get() - get reference to gss buffer
+ */
+static inline int gss_buffer_get(char **src, __u32 *len, __u8 **data)
+{
+       char *cp = *src;
+       __u32 *p;
+
+       /* read data size */
+       p = (__u32 *)cp;
+       *len = *p;
+       cp += sizeof(__u32);
+
+       /* point to data buf */
+       if (!*len)
+               *data = NULL;
+       else
+               *data = (__u8 *)cp;
+
+       /* move forward */
+       cp += *len;
+
+       *src = cp;
+       return *len;
+}
+
+/*
+ * gss_u32_read() - read some u32
+ */
+static inline int gss_u32_read(char **src, __u32 *val)
+{
+       char *cp = *src;
+       __u32 *p;
+
+       p = (__u32 *)cp;
+       *val = *p;
+       cp += sizeof(__u32);
+
+       *src = cp;
+       return 0;
+}
+
+#endif /* _LGSS_H */
index a8c5c71..a097bcf 100644 (file)
@@ -255,8 +255,6 @@ enum nodemap_idx_type {
        NODEMAP_GLOBAL_IDX = 15,        /* stores nodemap activation status */
 };
 
-#define LUSTRE_NODEMAP_NAME_LENGTH     16
-
 /* lu_nodemap flags */
 enum nm_flag_bits {
        NM_FL_ALLOW_ROOT_ACCESS = 0x1,
index d2eb486..07fc673 100644 (file)
@@ -3725,6 +3725,8 @@ struct llog_update_record {
                                     SELINUX_POLICY_VER_LEN + \
                                     SELINUX_POLICY_HASH_LEN + 3)
 
+#define LUSTRE_NODEMAP_NAME_LENGTH     16
+
 /** enums containing the types of ids contained in a nodemap
  * kept so other modules (mgs, mdt, etc) can define the type
  * of search easily
index d411249..f333c0f 100644 (file)
@@ -34,6 +34,8 @@
 
 #include <libcfs/libcfs.h>
 #include <uapi/linux/lnet/lnet-types.h>
+#include <obd.h>
+#include <lustre_sec.h>
 
 /** \defgroup ucache ucache
  *
@@ -78,6 +80,19 @@ struct md_identity {
        struct md_perm            *mi_perms;
 };
 
+struct gss_rsi {
+       struct upcall_cache_entry *si_uc_entry;
+       lnet_nid_t                 si_nid4; /* FIXME Support larger NID */
+       char                       si_nm_name[LUSTRE_NODEMAP_NAME_LENGTH + 1];
+       __u32                      si_lustre_svc;
+       rawobj_t                   si_in_handle;
+       rawobj_t                   si_in_token;
+       rawobj_t                   si_out_handle;
+       rawobj_t                   si_out_token;
+       int                        si_major_status;
+       int                        si_minor_status;
+};
+
 struct upcall_cache_entry {
        struct list_head        ue_hash;
        uint64_t                ue_key;
@@ -88,6 +103,7 @@ struct upcall_cache_entry {
        time64_t                ue_expire;
        union {
                struct md_identity      identity;
+               struct gss_rsi          rsi;
        } u;
 };
 
index 5a4bb64..408db86 100644 (file)
@@ -19,14 +19,13 @@ obdclass-all-objs += lustre_handles.o lustre_peer.o local_storage.o
 obdclass-all-objs += statfs_pack.o obdo.o obd_config.o obd_mount.o obd_sysfs.o
 obdclass-all-objs += lu_object.o dt_object.o
 obdclass-all-objs += cl_object.o cl_page.o cl_lock.o cl_io.o lu_ref.o
-obdclass-all-objs += linkea.o
+obdclass-all-objs += linkea.o upcall_cache.o
 obdclass-all-objs += kernelcomm.o jobid.o
 obdclass-all-objs += integrity.o obd_cksum.o
 obdclass-all-objs += lu_tgt_descs.o lu_tgt_pool.o
 obdclass-all-objs += range_lock.o interval_tree.o
 
 @SERVER_TRUE@obdclass-all-objs += idmap.o
-@SERVER_TRUE@obdclass-all-objs += upcall_cache.o
 @SERVER_TRUE@obdclass-all-objs += lprocfs_jobstats.o
 @SERVER_TRUE@obdclass-all-objs += lprocfs_status_server.o
 @SERVER_TRUE@obdclass-all-objs += lu_ucred.o
@@ -43,7 +42,6 @@ EXTRA_DIST += cl_internal.h local_storage.h
 EXTRA_DIST += range_lock.c interval_tree.c
 
 @SERVER_FALSE@EXTRA_DIST += idmap.c
-@SERVER_FALSE@EXTRA_DIST += upcall_cache.c
 @SERVER_FALSE@EXTRA_DIST += lprocfs_jobstats.c
 @SERVER_FALSE@EXTRA_DIST += lprocfs_status_server.c
 @SERVER_FALSE@EXTRA_DIST += lu_ucred.c
index 014d9ae..ddd4d52 100644 (file)
@@ -370,7 +370,8 @@ int upcall_cache_downcall(struct upcall_cache *cache, __u32 err, __u64 key,
        if (rc)
                GOTO(out, rc);
 
-       entry->ue_expire = ktime_get_seconds() + cache->uc_entry_expire;
+       if (!entry->ue_expire)
+               entry->ue_expire = ktime_get_seconds() + cache->uc_entry_expire;
        UC_CACHE_SET_VALID(entry);
        CDEBUG(D_OTHER, "%s: created upcall cache entry %p for key %llu\n",
               cache->uc_name, entry, entry->ue_key);
index aa48101..c1c26a3 100644 (file)
@@ -19,6 +19,8 @@
 #ifndef __PTLRPC_GSS_GSS_API_H_
 #define __PTLRPC_GSS_GSS_API_H_
 
+#include <uapi/linux/lustre/lgss.h>
+
 struct gss_api_mech;
 
 typedef int (*digest_hash)(
index fc37409..abc511d 100644 (file)
@@ -14,6 +14,7 @@
 #include <crypto/hash.h>
 #include <libcfs/libcfs_crypto.h>
 #include <lustre_sec.h>
+#include <upcall_cache.h>
 
 /*
  * rawobj stuff
@@ -139,43 +140,6 @@ static inline __u64 gss_handle_to_u64(rawobj_t *handle)
         return *((__u64 *) handle->data);
 }
 
-#define GSS_SEQ_WIN                     (2048)
-#define GSS_SEQ_WIN_MAIN                GSS_SEQ_WIN
-#define GSS_SEQ_WIN_BACK                (128)
-#define GSS_SEQ_REPACK_THRESHOLD        (GSS_SEQ_WIN_MAIN / 2 + \
-                                         GSS_SEQ_WIN_MAIN / 4)
-
-struct gss_svc_seq_data {
-       spinlock_t              ssd_lock;
-        /*
-         * highest sequence number seen so far, for main and back window
-         */
-        __u32                   ssd_max_main;
-        __u32                   ssd_max_back;
-        /*
-         * main and back window
-         * for i such that ssd_max - GSS_SEQ_WIN < i <= ssd_max, the i-th bit
-         * of ssd_win is nonzero iff sequence number i has been seen already.
-         */
-        unsigned long           ssd_win_main[GSS_SEQ_WIN_MAIN/BITS_PER_LONG];
-        unsigned long           ssd_win_back[GSS_SEQ_WIN_BACK/BITS_PER_LONG];
-};
-
-struct gss_svc_ctx {
-        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;
-        unsigned int            gsc_usr_root:1,
-                                gsc_usr_mds:1,
-                                gsc_usr_oss:1,
-                                gsc_remote:1,
-                                gsc_reverse:1;
-};
-
 struct gss_svc_reqctx {
         struct ptlrpc_svc_ctx           src_base;
         /*
@@ -479,4 +443,13 @@ static inline unsigned int ll_read_key_usage(struct key *key)
 #endif
 }
 
+#define RSI_UPCALL_PATH "/usr/sbin/l_getauth"
+#define UC_RSICACHE_HASH_SIZE 64
+
+extern struct upcall_cache_ops rsi_upcall_cache_ops;
+extern struct upcall_cache *rsicache;
+struct gss_rsi *rsi_entry_get(struct upcall_cache *cache, struct gss_rsi *rsi);
+void rsi_entry_put(struct upcall_cache *cache, struct gss_rsi *rsi);
+void rsi_flush(struct upcall_cache *cache, int hash);
+
 #endif /* __PTLRPC_GSS_GSS_INTERNAL_H_ */
index ea94cb6..dbd9efd 100644 (file)
@@ -55,7 +55,9 @@
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/sunrpc/cache.h>
+#include <linux/binfmts.h>
 #include <net/sock.h>
+#include <linux/un.h>
 
 #include <obd.h>
 #include <obd_class.h>
@@ -113,14 +115,346 @@ static inline unsigned long hash_mem(char *buf, int length, int bits)
        return hash >> (BITS_PER_LONG - bits);
 }
 
+/* This is a little bit of a concern but we need to make our own hash64 function
+ * as the one from the kernel seems to be buggy by returning a u32:
+ * static __always_inline u32 hash_64_generic(u64 val, unsigned int bits)
+ */
+#if BITS_PER_LONG == 64
+static __always_inline __u64 gss_hash_64(__u64 val, unsigned int bits)
+{
+       __u64 hash = val;
+       /*  Sigh, gcc can't optimise this alone like it does for 32 bits. */
+       __u64 n = hash;
+
+       n <<= 18;
+       hash -= n;
+       n <<= 33;
+       hash -= n;
+       n <<= 3;
+       hash += n;
+       n <<= 3;
+       hash -= n;
+       n <<= 4;
+       hash += n;
+       n <<= 2;
+       hash += n;
+
+       /* High bits are more random, so use them. */
+       return hash >> (64 - bits);
+}
+
+static inline unsigned long hash_mem_64(char *buf, int length, int bits)
+{
+       unsigned long hash = 0;
+       unsigned long l = 0;
+       int len = 0;
+       unsigned char c;
+
+       do {
+               if (len == length) {
+                       c = (char) len;
+                       len = -1;
+               } else
+                       c = *buf++;
+
+               l = (l << 8) | c;
+               len++;
+
+               if ((len & (BITS_PER_LONG/8-1)) == 0)
+                       hash = gss_hash_64(hash^l, BITS_PER_LONG);
+       } while (len);
+
+       return hash >> (BITS_PER_LONG - bits);
+}
+#endif /* BITS_PER_LONG == 64 */
+
 /****************************************
- * rpc sec init (rsi) cache *
+ * rpc sec init (rsi) cache            *
  ****************************************/
 
 #define RSI_HASHBITS    (6)
 #define RSI_HASHMAX     (1 << RSI_HASHBITS)
 #define RSI_HASHMASK    (RSI_HASHMAX - 1)
 
+static void rsi_entry_init(struct upcall_cache_entry *entry,
+                          void *args)
+{
+       struct gss_rsi *rsi = &entry->u.rsi;
+       struct gss_rsi *tmp = args;
+
+       rsi->si_uc_entry = entry;
+       rawobj_dup(&rsi->si_in_handle, &tmp->si_in_handle);
+       rawobj_dup(&rsi->si_in_token, &tmp->si_in_token);
+       rsi->si_out_handle = RAWOBJ_EMPTY;
+       rsi->si_out_token = RAWOBJ_EMPTY;
+
+       rsi->si_lustre_svc = tmp->si_lustre_svc;
+       rsi->si_nid4 = tmp->si_nid4;
+       memcpy(rsi->si_nm_name, tmp->si_nm_name, sizeof(tmp->si_nm_name));
+}
+
+static void __rsi_free(struct gss_rsi *rsi)
+{
+       rawobj_free(&rsi->si_in_handle);
+       rawobj_free(&rsi->si_in_token);
+       rawobj_free(&rsi->si_out_handle);
+       rawobj_free(&rsi->si_out_token);
+}
+
+static void rsi_entry_free(struct upcall_cache *cache,
+                          struct upcall_cache_entry *entry)
+{
+       struct gss_rsi *rsi = &entry->u.rsi;
+
+       __rsi_free(rsi);
+}
+
+static inline int rsi_entry_hash(struct gss_rsi *rsi)
+{
+#if BITS_PER_LONG == 64
+       return hash_mem_64((char *)rsi->si_in_handle.data,
+                          rsi->si_in_handle.len, RSI_HASHBITS) ^
+               hash_mem_64((char *)rsi->si_in_token.data,
+                           rsi->si_in_token.len, RSI_HASHBITS);
+#else
+       return hash_mem((char *)rsi->si_in_handle.data, rsi->si_in_handle.len,
+                       RSI_HASHBITS) ^
+               hash_mem((char *)rsi->si_in_token.data, rsi->si_in_token.len,
+                        RSI_HASHBITS);
+#endif
+}
+
+static inline int __rsi_entry_match(rawobj_t *h1, rawobj_t *h2,
+                                   rawobj_t *t1, rawobj_t *t2)
+{
+       return !(rawobj_equal(h1, h2) && rawobj_equal(t1, t2));
+}
+
+static inline int rsi_entry_match(struct gss_rsi *rsi, struct gss_rsi *tmp)
+{
+       return __rsi_entry_match(&rsi->si_in_handle, &tmp->si_in_handle,
+                                &rsi->si_in_token, &tmp->si_in_token);
+}
+
+/* Returns 0 to tell this is a match */
+static inline int rsi_upcall_compare(struct upcall_cache *cache,
+                                    struct upcall_cache_entry *entry,
+                                    __u64 key, void *args)
+{
+       struct gss_rsi *rsi1 = &entry->u.rsi;
+       struct gss_rsi *rsi2 = args;
+
+       return rsi_entry_match(rsi1, rsi2);
+}
+
+/* See handle_channel_request() userspace for where the upcall data is read */
+static int rsi_do_upcall(struct upcall_cache *cache,
+                        struct upcall_cache_entry *entry)
+{
+       int size, len, *blen;
+       char *buffer, *bp, **bpp;
+       char *argv[] = {
+               [0] = cache->uc_upcall,
+               [1] = "-c",
+               [2] = cache->uc_name,
+               [3] = "-r",
+               [4] = NULL,
+               [5] = NULL
+       };
+       char *envp[] = {
+               [0] = "HOME=/",
+               [1] = "PATH=/sbin:/usr/sbin",
+               [2] = NULL
+       };
+       ktime_t start, end;
+       struct gss_rsi *rsi = &entry->u.rsi;
+       __u64 index = 0;
+       int rc;
+
+       ENTRY;
+       CDEBUG(D_SEC, "rsi upcall '%s' on '%s'\n",
+              cache->uc_upcall, cache->uc_name);
+
+       size = 24 + 1 + /* ue_key is uint64_t */
+               12 + 1 + /* si_lustre_svc is __u32*/
+               18 + 1 + /* si_nid4 is lnet_nid_t, hex with leading 0x */
+               18 + 1 + /* index is __u64, hex with leading 0x */
+               strlen(rsi->si_nm_name) + 1 +
+               BASE64URL_CHARS(rsi->si_in_handle.len) + 1 +
+               BASE64URL_CHARS(rsi->si_in_token.len) + 1 +
+               1 + 1; /* eol */
+       if (size > MAX_ARG_STRLEN)
+               RETURN(-E2BIG);
+       OBD_ALLOC_LARGE(buffer, size);
+       if (!buffer)
+               RETURN(-ENOMEM);
+
+       bp = buffer;
+       bpp = &bp;
+       len = size;
+       blen = &len;
+
+       /* if in_handle is null, provide kernel suggestion */
+       if (rsi->si_in_handle.len == 0)
+               index = gss_get_next_ctx_index();
+
+       /* entry->ue_key is put into args sent via upcall, so that it can be
+        * returned by userspace. This will help find cache entry at downcall,
+        * without unnecessary recomputation of the hash.
+        */
+       gss_u64_write_string(bpp, blen, entry->ue_key);
+       gss_u64_write_string(bpp, blen, rsi->si_lustre_svc);
+       gss_u64_write_hex_string(bpp, blen, rsi->si_nid4);
+       gss_u64_write_hex_string(bpp, blen, index);
+       gss_string_write(bpp, blen, (char *) rsi->si_nm_name);
+       gss_base64url_encode(bpp, blen, rsi->si_in_handle.data,
+                            rsi->si_in_handle.len);
+       gss_base64url_encode(bpp, blen, rsi->si_in_token.data,
+                            rsi->si_in_token.len);
+       (*bpp)[-1] = '\n';
+       (*bpp)[0] = '\0';
+
+       argv[4] = buffer;
+       down_read(&cache->uc_upcall_rwsem);
+       start = ktime_get();
+       rc = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
+       end = ktime_get();
+       up_read(&cache->uc_upcall_rwsem);
+       if (rc < 0) {
+               CERROR("%s: error invoking upcall %s %s (time %ldus): rc = %d\n",
+                      cache->uc_name, argv[0], argv[2],
+                      (long)ktime_us_delta(end, start), rc);
+       } else {
+               CDEBUG(D_SEC, "%s: invoked upcall %s %s (time %ldus)\n",
+                      cache->uc_name, argv[0], argv[2],
+                      (long)ktime_us_delta(end, start));
+               rc = 0;
+       }
+
+       OBD_FREE_LARGE(buffer, size);
+       RETURN(rc);
+}
+
+static inline int rsi_downcall_compare(struct upcall_cache *cache,
+                                      struct upcall_cache_entry *entry,
+                                      __u64 key, void *args)
+{
+       struct gss_rsi *rsi = &entry->u.rsi;
+       struct rsi_downcall_data *sid = args;
+       char *mesg = sid->sid_val;
+       rawobj_t handle, token;
+       char *p = mesg;
+       int len;
+
+       /* sid_val starts with handle and token */
+
+       /* First, handle */
+       len = gss_buffer_get(&mesg, &handle.len, &handle.data);
+       sid->sid_offset = mesg - p;
+       p = mesg;
+
+       /* Second, token */
+       len = gss_buffer_get(&mesg, &token.len, &token.data);
+       sid->sid_offset += mesg - p;
+
+       return __rsi_entry_match(&rsi->si_in_handle, &handle,
+                                &rsi->si_in_token, &token);
+}
+
+static int rsi_parse_downcall(struct upcall_cache *cache,
+                             struct upcall_cache_entry *entry,
+                             void *args)
+{
+       struct gss_rsi *rsi = &entry->u.rsi;
+       struct rsi_downcall_data *sid = args;
+       int mlen = sid->sid_len;
+       char *mesg = sid->sid_val + sid->sid_offset;
+       char *buf = sid->sid_val;
+       int status = -EINVAL;
+       int len;
+
+       ENTRY;
+
+       if (mlen <= 0)
+               goto out;
+
+       rsi->si_major_status = sid->sid_maj_stat;
+       rsi->si_minor_status = sid->sid_min_stat;
+
+       /* in_handle and in_token have already been consumed in
+        * rsi_downcall_compare(). sid_offset gives next field.
+        */
+
+       /* out_handle */
+       len = gss_buffer_read(&mesg, buf, mlen);
+       if (len < 0)
+               goto out;
+       if (rawobj_alloc(&rsi->si_out_handle, buf, len)) {
+               status = -ENOMEM;
+               goto out;
+       }
+
+       /* out_token */
+       len = gss_buffer_read(&mesg, buf, mlen);
+       if (len < 0)
+               goto out;
+       if (rawobj_alloc(&rsi->si_out_token, buf, len)) {
+               status = -ENOMEM;
+               goto out;
+       }
+
+       entry->ue_expire = 0;
+       status = 0;
+
+out:
+       CDEBUG(D_OTHER, "rsi parse %p: %d\n", rsi, status);
+       RETURN(status);
+}
+
+struct gss_rsi *rsi_entry_get(struct upcall_cache *cache, struct gss_rsi *rsi)
+{
+       struct upcall_cache_entry *entry;
+       int hash = rsi_entry_hash(rsi);
+
+       if (!cache)
+               return ERR_PTR(-ENOENT);
+
+       entry = upcall_cache_get_entry(cache, (__u64)hash, rsi);
+       if (unlikely(!entry))
+               return ERR_PTR(-ENOENT);
+       if (IS_ERR(entry))
+               return ERR_CAST(entry);
+
+       return &entry->u.rsi;
+}
+
+void rsi_entry_put(struct upcall_cache *cache, struct gss_rsi *rsi)
+{
+       if (!cache || !rsi)
+               return;
+
+       upcall_cache_put_entry(cache, rsi->si_uc_entry);
+}
+
+void rsi_flush(struct upcall_cache *cache, int hash)
+{
+       if (hash < 0)
+               upcall_cache_flush_idle(cache);
+       else
+               upcall_cache_flush_one(cache, (__u64)hash, NULL);
+}
+
+struct upcall_cache_ops rsi_upcall_cache_ops = {
+       .init_entry       = rsi_entry_init,
+       .free_entry       = rsi_entry_free,
+       .upcall_compare   = rsi_upcall_compare,
+       .downcall_compare = rsi_downcall_compare,
+       .do_upcall        = rsi_do_upcall,
+       .parse_downcall   = rsi_parse_downcall,
+};
+
+struct upcall_cache *rsicache;
+
 struct rsi {
        struct cache_head       h;
        __u32                   lustre_svc;
@@ -888,12 +1222,6 @@ int gss_svc_upcall_update_sequence(rawobj_t *handle, __u32 seq)
         return 0;
 }
 
-static struct cache_deferred_req* cache_upcall_defer(struct cache_req *req)
-{
-        return NULL;
-}
-static struct cache_req cache_upcall_chandle = { cache_upcall_defer };
-
 int gss_svc_upcall_handle_init(struct ptlrpc_request *req,
                               struct gss_svc_reqctx *grctx,
                               struct gss_wire_ctx *gw,
@@ -902,119 +1230,71 @@ int gss_svc_upcall_handle_init(struct ptlrpc_request *req,
                               rawobj_t *rvs_hdl,
                               rawobj_t *in_token)
 {
+       struct gss_rsi rsi = { 0 }, *rsip = NULL;
        struct ptlrpc_reply_state *rs;
-       struct rsc                *rsci = NULL;
-       struct rsi                *rsip = NULL, rsikey;
-       wait_queue_entry_t wait;
-       int                        replen = sizeof(struct ptlrpc_body);
-       struct gss_rep_header     *rephdr;
-       int                        first_check = 1;
-       int                        rc = SECSVC_DROP;
+       struct rsc *rsci = NULL;
+       int replen = sizeof(struct ptlrpc_body);
+       struct gss_rep_header *rephdr;
+       int rc = SECSVC_DROP, rc2;
 
        ENTRY;
-       memset(&rsikey, 0, sizeof(rsikey));
-       rsikey.lustre_svc = lustre_svc;
+
+       rsi.si_lustre_svc = lustre_svc;
        /* In case of MR, rq_peer is not the NID from which request is received,
         * but primary NID of peer.
         * So we need LNetPrimaryNID(rq_source) to match what the clients uses.
         */
        LNetPrimaryNID(&req->rq_source.nid);
-       rsikey.nid4 = lnet_nid_to_nid4(&req->rq_source.nid);
-       nodemap_test_nid(lnet_nid_to_nid4(&req->rq_peer.nid), rsikey.nm_name,
-                        sizeof(rsikey.nm_name));
-
-        /* duplicate context handle. for INIT it always 0 */
-        if (rawobj_dup(&rsikey.in_handle, &gw->gw_handle)) {
-                CERROR("fail to dup context handle\n");
-                GOTO(out, rc);
-        }
-
-        if (rawobj_dup(&rsikey.in_token, in_token)) {
-                CERROR("can't duplicate token\n");
-                rawobj_free(&rsikey.in_handle);
-                GOTO(out, rc);
-        }
-
-        rsip = rsi_lookup(&rsikey);
-        rsi_free(&rsikey);
-        if (!rsip) {
-                CERROR("error in rsi_lookup.\n");
-
-                if (!gss_pack_err_notify(req, GSS_S_FAILURE, 0))
-                        rc = SECSVC_COMPLETE;
-
-                GOTO(out, rc);
-        }
-
-       cache_get(&rsip->h); /* take an extra ref */
-       init_wait(&wait);
-       add_wait_queue(&rsip->waitq, &wait);
-
-cache_check:
-       /* Note each time cache_check() will drop a reference if return
-        * non-zero. We hold an extra reference on initial rsip, but must
-        * take care of following calls. */
-       rc = cache_check(&rsi_cache, &rsip->h, &cache_upcall_chandle);
-       switch (rc) {
-       case -ETIMEDOUT:
-       case -EAGAIN: {
-               int valid;
-
-               if (first_check) {
-                       first_check = 0;
-
-                       cache_read_lock(&rsi_cache);
-                       valid = test_bit(CACHE_VALID, &rsip->h.flags);
-                       if (valid == 0)
-                               set_current_state(TASK_INTERRUPTIBLE);
-                       cache_read_unlock(&rsi_cache);
-
-                       if (valid == 0) {
-                               unsigned long timeout;
-
-                               timeout = cfs_time_seconds(GSS_SVC_UPCALL_TIMEOUT);
-                               schedule_timeout(timeout);
-                       }
-                       cache_get(&rsip->h);
-                       goto cache_check;
-               }
-               CWARN("waited %ds timeout, drop\n", GSS_SVC_UPCALL_TIMEOUT);
-               break;
+       rsi.si_nid4 = lnet_nid_to_nid4(&req->rq_source.nid);
+       nodemap_test_nid(lnet_nid_to_nid4(&req->rq_peer.nid), rsi.si_nm_name,
+                        sizeof(rsi.si_nm_name));
+
+       /* Note that context handle is always 0 for for INIT. */
+       rc2 = rawobj_dup(&rsi.si_in_handle, &gw->gw_handle);
+       if (rc2) {
+               CERROR("%s: failed to duplicate context handle: rc = %d\n",
+                      target->obd_name, rc2);
+               GOTO(out, rc);
        }
-       case -ENOENT:
-               CDEBUG(D_SEC, "cache_check return ENOENT, drop\n");
-               break;
-       case 0:
-               /* if not the first check, we have to release the extra
-                * reference we just added on it. */
-               if (!first_check)
-                       cache_put(&rsip->h, &rsi_cache);
-               CDEBUG(D_SEC, "cache_check is good\n");
-               break;
+
+       rc2 = rawobj_dup(&rsi.si_in_token, in_token);
+       if (rc2) {
+               CERROR("%s: failed to duplicate token: rc = %d\n",
+                      target->obd_name, rc2);
+               rawobj_free(&rsi.si_in_handle);
+               GOTO(out, rc);
        }
 
-       remove_wait_queue(&rsip->waitq, &wait);
-       cache_put(&rsip->h, &rsi_cache);
+       rsip = rsi_entry_get(rsicache, &rsi);
+       __rsi_free(&rsi);
+       if (IS_ERR(rsip)) {
+               CERROR("%s: failed to get entry from rsi cache (nid %s): rc = %ld\n",
+                      target->obd_name,
+                      libcfs_nid2str(lnet_nid_to_nid4(&req->rq_source.nid)),
+                      PTR_ERR(rsip));
 
-       if (rc)
-               GOTO(out, rc = SECSVC_DROP);
+               if (!gss_pack_err_notify(req, GSS_S_FAILURE, 0))
+                       rc = SECSVC_COMPLETE;
 
-        rc = SECSVC_DROP;
-        rsci = gss_svc_searchbyctx(&rsip->out_handle);
-        if (!rsci) {
-                CERROR("authentication failed\n");
+               GOTO(out, rc);
+       }
 
+       rc = SECSVC_DROP;
+       rsci = gss_svc_searchbyctx(&rsip->si_out_handle);
+       if (!rsci) {
                /* gss mechanism returned major and minor code so we return
                 * those in error message */
-               if (!gss_pack_err_notify(req, rsip->major_status,
-                                        rsip->minor_status))
+               if (!gss_pack_err_notify(req, rsip->si_major_status,
+                                        rsip->si_minor_status))
                        rc = SECSVC_COMPLETE;
 
-                GOTO(out, rc);
-        } else {
-                cache_get(&rsci->h);
-                grctx->src_ctx = &rsci->ctx;
-        }
+               CERROR("%s: authentication failed: rc = %d\n",
+                      target->obd_name, rc);
+               GOTO(out, rc);
+       } else {
+               cache_get(&rsci->h);
+               grctx->src_ctx = &rsci->ctx;
+       }
 
        if (gw->gw_flags & LUSTRE_GSS_PACK_KCSUM) {
                grctx->src_ctx->gsc_mechctx->hash_func = gss_digest_hash;
@@ -1030,68 +1310,69 @@ cache_check:
                        gss_digest_hash_compat;
        }
 
-        if (rawobj_dup(&rsci->ctx.gsc_rvs_hdl, rvs_hdl)) {
-                CERROR("failed duplicate reverse handle\n");
-                GOTO(out, rc);
-        }
+       if (rawobj_dup(&rsci->ctx.gsc_rvs_hdl, rvs_hdl)) {
+               CERROR("%s: failed duplicate reverse handle\n",
+                      target->obd_name);
+               GOTO(out, rc);
+       }
 
-        rsci->target = target;
+       rsci->target = target;
 
-       CDEBUG(D_SEC, "server create rsc %p(%u->%s)\n",
-              rsci, rsci->ctx.gsc_uid, libcfs_nidstr(&req->rq_peer.nid));
+       CDEBUG(D_SEC, "%s: server create rsc %p(%u->%s)\n",
+              target->obd_name, rsci, rsci->ctx.gsc_uid,
+              libcfs_nidstr(&req->rq_peer.nid));
 
-        if (rsip->out_handle.len > PTLRPC_GSS_MAX_HANDLE_SIZE) {
-                CERROR("handle size %u too large\n", rsip->out_handle.len);
-                GOTO(out, rc = SECSVC_DROP);
-        }
+       if (rsip->si_out_handle.len > PTLRPC_GSS_MAX_HANDLE_SIZE) {
+               CERROR("%s: handle size %u too large\n",
+                      target->obd_name, rsip->si_out_handle.len);
+               GOTO(out, rc = SECSVC_DROP);
+       }
 
-        grctx->src_init = 1;
-       grctx->src_reserve_len = round_up(rsip->out_token.len, 4);
+       grctx->src_init = 1;
+       grctx->src_reserve_len = round_up(rsip->si_out_token.len, 4);
 
-        rc = lustre_pack_reply_v2(req, 1, &replen, NULL, 0);
-        if (rc) {
-                CERROR("failed to pack reply: %d\n", rc);
-                GOTO(out, rc = SECSVC_DROP);
-        }
+       rc = lustre_pack_reply_v2(req, 1, &replen, NULL, 0);
+       if (rc) {
+               CERROR("%s: failed to pack reply: rc = %d\n",
+                      target->obd_name, rc);
+               GOTO(out, rc = SECSVC_DROP);
+       }
 
-        rs = req->rq_reply_state;
-        LASSERT(rs->rs_repbuf->lm_bufcount == 3);
-        LASSERT(rs->rs_repbuf->lm_buflens[0] >=
-                sizeof(*rephdr) + rsip->out_handle.len);
-        LASSERT(rs->rs_repbuf->lm_buflens[2] >= rsip->out_token.len);
+       rs = req->rq_reply_state;
+       LASSERT(rs->rs_repbuf->lm_bufcount == 3);
+       LASSERT(rs->rs_repbuf->lm_buflens[0] >=
+               sizeof(*rephdr) + rsip->si_out_handle.len);
+       LASSERT(rs->rs_repbuf->lm_buflens[2] >= rsip->si_out_token.len);
 
-        rephdr = lustre_msg_buf(rs->rs_repbuf, 0, 0);
-        rephdr->gh_version = PTLRPC_GSS_VERSION;
-        rephdr->gh_flags = 0;
-        rephdr->gh_proc = PTLRPC_GSS_PROC_ERR;
-        rephdr->gh_major = rsip->major_status;
-        rephdr->gh_minor = rsip->minor_status;
-        rephdr->gh_seqwin = GSS_SEQ_WIN;
-        rephdr->gh_handle.len = rsip->out_handle.len;
-        memcpy(rephdr->gh_handle.data, rsip->out_handle.data,
-               rsip->out_handle.len);
+       rephdr = lustre_msg_buf(rs->rs_repbuf, 0, 0);
+       rephdr->gh_version = PTLRPC_GSS_VERSION;
+       rephdr->gh_flags = 0;
+       rephdr->gh_proc = PTLRPC_GSS_PROC_ERR;
+       rephdr->gh_major = rsip->si_major_status;
+       rephdr->gh_minor = rsip->si_minor_status;
+       rephdr->gh_seqwin = GSS_SEQ_WIN;
+       rephdr->gh_handle.len = rsip->si_out_handle.len;
+       memcpy(rephdr->gh_handle.data, rsip->si_out_handle.data,
+              rsip->si_out_handle.len);
 
-        memcpy(lustre_msg_buf(rs->rs_repbuf, 2, 0), rsip->out_token.data,
-               rsip->out_token.len);
+       memcpy(lustre_msg_buf(rs->rs_repbuf, 2, 0), rsip->si_out_token.data,
+              rsip->si_out_token.len);
 
-        rs->rs_repdata_len = lustre_shrink_msg(rs->rs_repbuf, 2,
-                                               rsip->out_token.len, 0);
+       rs->rs_repdata_len = lustre_shrink_msg(rs->rs_repbuf, 2,
+                                              rsip->si_out_token.len, 0);
 
-        rc = SECSVC_OK;
+       rc = SECSVC_OK;
 
 out:
-       /* it looks like here we should put rsip also, but this mess up
-        * with NFS cache mgmt code... FIXME
-        * something like:
-        * if (rsip)
-        *     rsi_put(&rsip->h, &rsi_cache); */
-
+       if (!IS_ERR_OR_NULL(rsip))
+               rsi_entry_put(rsicache, rsip);
        if (rsci) {
                /* 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 %#llx\n",
+                       CDEBUG(D_SEC, "%s: create rsc with idx %#llx\n",
+                              target->obd_name,
                               gss_handle_to_u64(&rsci->handle));
 
                COMPAT_RSC_PUT(&rsci->h, &rsc_cache);
@@ -1132,9 +1413,57 @@ void gss_svc_upcall_destroy_ctx(struct gss_svc_ctx *ctx)
         rsc->h.expiry_time = 1;
 }
 
+/* Wait for userspace daemon to open socket, approx 1.5 s.
+ * If socket is not open, upcall requests might fail.
+ */
+static int check_gssd_socket(void)
+{
+       struct sockaddr_un *sun;
+       struct socket *sock;
+       int tries = 0;
+       int err;
+
+#ifdef HAVE_SOCK_CREATE_KERN_USE_NET
+       err = sock_create_kern(current->nsproxy->net_ns,
+                              AF_UNIX, SOCK_STREAM, 0, &sock);
+#else
+       err = sock_create_kern(AF_UNIX, SOCK_STREAM, 0, &sock);
+#endif
+       if (err < 0) {
+               CDEBUG(D_SEC, "Failed to create socket: %d\n", err);
+               return err;
+       }
+
+       OBD_ALLOC(sun, sizeof(*sun));
+       if (!sun) {
+               sock_release(sock);
+               return -ENOMEM;
+       }
+       memset(sun, 0, sizeof(*sun));
+       sun->sun_family = AF_UNIX;
+       strncpy(sun->sun_path, GSS_SOCKET_PATH, sizeof(sun->sun_path));
+
+       /* Try to connect to the socket */
+       while (tries++ < 6) {
+               err = kernel_connect(sock, (struct sockaddr *)sun,
+                                    sizeof(*sun), 0);
+               if (!err)
+                       break;
+               schedule_timeout_uninterruptible(cfs_time_seconds(1) / 4);
+       }
+       if (err < 0)
+               CDEBUG(D_SEC, "Failed to connect to socket: %d\n", err);
+       else
+               kernel_sock_shutdown(sock, SHUT_RDWR);
+
+       sock_release(sock);
+       OBD_FREE(sun, sizeof(*sun));
+       return err;
+}
+
 int __init gss_init_svc_upcall(void)
 {
-       int     i, rc;
+       int rc;
 
        /*
         * this helps reducing context index confliction. after server reboot,
@@ -1145,16 +1474,16 @@ int __init gss_init_svc_upcall(void)
        get_random_bytes(&__ctx_index, sizeof(__ctx_index));
 
 #ifdef HAVE_CACHE_HEAD_HLIST
-       for (i = 0; i < rsi_cache.hash_size; i++)
-               INIT_HLIST_HEAD(&rsi_cache.hash_table[i]);
+       for (rc = 0; rc < rsi_cache.hash_size; rc++)
+               INIT_HLIST_HEAD(&rsi_cache.hash_table[rc]);
 #endif
        rc = cache_register_net(&rsi_cache, &init_net);
        if (rc != 0)
                return rc;
 
 #ifdef HAVE_CACHE_HEAD_HLIST
-       for (i = 0; i < rsc_cache.hash_size; i++)
-               INIT_HLIST_HEAD(&rsc_cache.hash_table[i]);
+       for (rc = 0; rc < rsc_cache.hash_size; rc++)
+               INIT_HLIST_HEAD(&rsc_cache.hash_table[rc]);
 #endif
        rc = cache_register_net(&rsc_cache, &init_net);
        if (rc != 0) {
@@ -1162,21 +1491,20 @@ int __init gss_init_svc_upcall(void)
                return rc;
        }
 
-       /* FIXME this looks stupid. we intend to give lsvcgssd a chance to open
-        * the init upcall channel, otherwise there's big chance that the first
-        * upcall issued before the channel be opened thus nfsv4 cache code will
-        * drop the request directly, thus lead to unnecessary recovery time.
-        * Here we wait at minimum 1.5 seconds.
-        */
-       for (i = 0; i < 6; i++) {
-               if (channel_users(&rsi_cache) > 0)
-                       break;
-               schedule_timeout_uninterruptible(cfs_time_seconds(1) / 4);
+       rsicache = upcall_cache_init(RSI_CACHE_NAME, RSI_UPCALL_PATH,
+                                    UC_RSICACHE_HASH_SIZE,
+                                    3600, /* entry expire: 1 h */
+                                    20, /* acquire expire: 20 s */
+                                    &rsi_upcall_cache_ops);
+       if (IS_ERR(rsicache)) {
+               rc = PTR_ERR(rsicache);
+               rsicache = NULL;
+               return rc;
        }
 
-       if (channel_users(&rsi_cache) == 0)
+       if (check_gssd_socket())
                CDEBUG(D_SEC,
-                      "Init channel is not opened by lsvcgssd, following request might be dropped until lsvcgssd is active\n");
+                      "Init channel not opened by lsvcgssd, GSS might not work on server side until daemon is active\n");
 
        return 0;
 }
@@ -1188,4 +1516,6 @@ void gss_exit_svc_upcall(void)
 
        cache_purge(&rsc_cache);
        cache_unregister_net(&rsc_cache, &init_net);
+
+       upcall_cache_cleanup(rsicache);
 }
index 185174a..de0e404 100644 (file)
@@ -181,6 +181,161 @@ static ssize_t sptlrpc_gss_check_upcall_ns_seq_write(struct file *file,
 LPROC_SEQ_FOPS(sptlrpc_gss_check_upcall_ns);
 #endif /* HAVE_GSS_KEYRING */
 
+static int rsi_upcall_seq_show(struct seq_file *m,
+                              void *data)
+{
+       down_read(&rsicache->uc_upcall_rwsem);
+       seq_printf(m, "%s\n", rsicache->uc_upcall);
+       up_read(&rsicache->uc_upcall_rwsem);
+
+       return 0;
+}
+
+static ssize_t rsi_upcall_seq_write(struct file *file,
+                                   const char __user *buffer,
+                                   size_t count, loff_t *off)
+{
+       int rc;
+
+       if (count >= UC_CACHE_UPCALL_MAXPATH) {
+               CERROR("%s: rsi upcall too long\n", rsicache->uc_name);
+               return -EINVAL;
+       }
+
+       /* Remove any extraneous bits from the upcall (e.g. linefeeds) */
+       down_write(&rsicache->uc_upcall_rwsem);
+       rc = sscanf(buffer, "%s", rsicache->uc_upcall);
+       up_write(&rsicache->uc_upcall_rwsem);
+
+       if (rc != 1) {
+               CERROR("%s: invalid rsi upcall provided\n", rsicache->uc_name);
+               return -EINVAL;
+       }
+
+       CDEBUG(D_CONFIG, "%s: rsi upcall set to %s\n", rsicache->uc_name,
+              rsicache->uc_upcall);
+
+       return count;
+}
+LPROC_SEQ_FOPS(rsi_upcall);
+
+static ssize_t lprocfs_rsi_flush_seq_write(struct file *file,
+                                          const char __user *buffer,
+                                          size_t count, void *data)
+{
+       int hash, rc;
+
+       rc = kstrtoint_from_user(buffer, count, 0, &hash);
+       if (rc)
+               return rc;
+
+       rsi_flush(rsicache, hash);
+       return count;
+}
+LPROC_SEQ_FOPS_WR_ONLY(gss, rsi_flush);
+
+static ssize_t lprocfs_rsi_info_seq_write(struct file *file,
+                                         const char __user *buffer,
+                                         size_t count, void *data)
+{
+       struct rsi_downcall_data *param;
+       int size = sizeof(*param), rc, checked = 0;
+
+again:
+       if (count < size) {
+               CERROR("%s: invalid data count = %lu, size = %d\n",
+                      rsicache->uc_name, (unsigned long)count, size);
+               return -EINVAL;
+       }
+
+       OBD_ALLOC_LARGE(param, size);
+       if (param == NULL)
+               return -ENOMEM;
+
+       if (copy_from_user(param, buffer, size)) {
+               CERROR("%s: bad rsi data\n", rsicache->uc_name);
+               GOTO(out, rc = -EFAULT);
+       }
+
+       if (checked == 0) {
+               checked = 1;
+               if (param->sid_magic != RSI_DOWNCALL_MAGIC) {
+                       CERROR("%s: rsi downcall bad params\n",
+                              rsicache->uc_name);
+                       GOTO(out, rc = -EINVAL);
+               }
+
+               rc = param->sid_len; /* save sid_len */
+               OBD_FREE_LARGE(param, size);
+               size = offsetof(struct rsi_downcall_data, sid_val[rc]);
+               goto again;
+       }
+
+       rc = upcall_cache_downcall(rsicache, param->sid_err,
+                                  param->sid_hash, param);
+
+out:
+       if (param != NULL)
+               OBD_FREE_LARGE(param, size);
+
+       return rc ? rc : count;
+}
+LPROC_SEQ_FOPS_WR_ONLY(gss, rsi_info);
+
+static int rsi_entry_expire_seq_show(struct seq_file *m,
+                                    void *data)
+{
+       seq_printf(m, "%lld\n", rsicache->uc_entry_expire);
+       return 0;
+}
+
+static ssize_t rsi_entry_expire_seq_write(struct file *file,
+                                         const char __user *buffer,
+                                         size_t count, loff_t *off)
+{
+       time64_t val;
+       int rc;
+
+       rc = kstrtoll_from_user(buffer, count, 10, &val);
+       if (rc)
+               return rc;
+
+       if (val < 0)
+               return -ERANGE;
+
+       rsicache->uc_entry_expire = val;
+
+       return count;
+}
+LPROC_SEQ_FOPS(rsi_entry_expire);
+
+static int rsi_acquire_expire_seq_show(struct seq_file *m,
+                                      void *data)
+{
+       seq_printf(m, "%lld\n", rsicache->uc_acquire_expire);
+       return 0;
+}
+
+static ssize_t rsi_acquire_expire_seq_write(struct file *file,
+                                           const char __user *buffer,
+                                           size_t count, loff_t *off)
+{
+       time64_t val;
+       int rc;
+
+       rc = kstrtoll_from_user(buffer, count, 10, &val);
+       if (rc)
+               return rc;
+
+       if (val < 0 || val > INT_MAX)
+               return -ERANGE;
+
+       rsicache->uc_acquire_expire = val;
+
+       return count;
+}
+LPROC_SEQ_FOPS(rsi_acquire_expire);
+
 static struct ldebugfs_vars gss_debugfs_vars[] = {
        { .name =       "replays",
          .fops =       &gss_proc_oos_fops      },
@@ -197,6 +352,16 @@ static struct lprocfs_vars gss_lprocfs_vars[] = {
        { .name =       "gss_check_upcall_ns",
          .fops =       &sptlrpc_gss_check_upcall_ns_fops },
 #endif
+       { .name =       "rsi_upcall",
+         .fops =       &rsi_upcall_fops },
+       { .name =       "rsi_flush",
+         .fops =       &gss_rsi_flush_fops },
+       { .name =       "rsi_info",
+         .fops =       &gss_rsi_info_fops },
+       { .name =       "rsi_entry_expire",
+         .fops =       &rsi_entry_expire_fops },
+       { .name =       "rsi_acquire_expire",
+         .fops =       &rsi_acquire_expire_fops },
        { NULL }
 };
 
index 5b5a1d5..1da31b5 100644 (file)
@@ -43,6 +43,7 @@
 #include <uapi/linux/lustre/lustre_access_log.h>
 #include <uapi/linux/lustre/lustre_lfsck_user.h>
 #include <uapi/linux/lustre/lustre_cfg.h>
+#include <uapi/linux/lustre/lgss.h>
 
 #include "ptlrpc_internal.h"
 
@@ -4390,6 +4391,42 @@ void lustre_assert_wire_constants(void)
                 (long long)(int)sizeof(((struct llog_changelog_user_rec *)0)->cur_tail));
 #endif /* HAVE_SERVER_SUPPORT */
 
+       /* Checks for struct rsi_downcall_data */
+       LASSERTF((int)sizeof(struct rsi_downcall_data) == 32, "found %lld\n",
+                (long long)(int)sizeof(struct rsi_downcall_data));
+       LASSERTF((int)offsetof(struct rsi_downcall_data, sid_magic) == 0, "found %lld\n",
+                (long long)(int)offsetof(struct rsi_downcall_data, sid_magic));
+       LASSERTF((int)sizeof(((struct rsi_downcall_data *)0)->sid_magic) == 4, "found %lld\n",
+                (long long)(int)sizeof(((struct rsi_downcall_data *)0)->sid_magic));
+       LASSERTF((int)offsetof(struct rsi_downcall_data, sid_err) == 4, "found %lld\n",
+                (long long)(int)offsetof(struct rsi_downcall_data, sid_err));
+       LASSERTF((int)sizeof(((struct rsi_downcall_data *)0)->sid_err) == 4, "found %lld\n",
+                (long long)(int)sizeof(((struct rsi_downcall_data *)0)->sid_err));
+       LASSERTF((int)offsetof(struct rsi_downcall_data, sid_hash) == 8, "found %lld\n",
+                (long long)(int)offsetof(struct rsi_downcall_data, sid_hash));
+       LASSERTF((int)sizeof(((struct rsi_downcall_data *)0)->sid_hash) == 4, "found %lld\n",
+                (long long)(int)sizeof(((struct rsi_downcall_data *)0)->sid_hash));
+       LASSERTF((int)offsetof(struct rsi_downcall_data, sid_maj_stat) == 12, "found %lld\n",
+                (long long)(int)offsetof(struct rsi_downcall_data, sid_maj_stat));
+       LASSERTF((int)sizeof(((struct rsi_downcall_data *)0)->sid_maj_stat) == 4, "found %lld\n",
+                (long long)(int)sizeof(((struct rsi_downcall_data *)0)->sid_maj_stat));
+       LASSERTF((int)offsetof(struct rsi_downcall_data, sid_min_stat) == 16, "found %lld\n",
+                (long long)(int)offsetof(struct rsi_downcall_data, sid_min_stat));
+       LASSERTF((int)sizeof(((struct rsi_downcall_data *)0)->sid_min_stat) == 4, "found %lld\n",
+                (long long)(int)sizeof(((struct rsi_downcall_data *)0)->sid_min_stat));
+       LASSERTF((int)offsetof(struct rsi_downcall_data, sid_len) == 20, "found %lld\n",
+                (long long)(int)offsetof(struct rsi_downcall_data, sid_len));
+       LASSERTF((int)sizeof(((struct rsi_downcall_data *)0)->sid_len) == 4, "found %lld\n",
+                (long long)(int)sizeof(((struct rsi_downcall_data *)0)->sid_len));
+       LASSERTF((int)offsetof(struct rsi_downcall_data, sid_offset) == 24, "found %lld\n",
+                (long long)(int)offsetof(struct rsi_downcall_data, sid_offset));
+       LASSERTF((int)sizeof(((struct rsi_downcall_data *)0)->sid_offset) == 8, "found %lld\n",
+                (long long)(int)sizeof(((struct rsi_downcall_data *)0)->sid_offset));
+       LASSERTF((int)offsetof(struct rsi_downcall_data, sid_val) == 32, "found %lld\n",
+                (long long)(int)offsetof(struct rsi_downcall_data, sid_val));
+       LASSERTF((int)sizeof(((struct rsi_downcall_data *)0)->sid_val) == 0, "found %lld\n",
+                (long long)(int)sizeof(((struct rsi_downcall_data *)0)->sid_val));
+
        /* Checks for struct llog_gen */
        LASSERTF((int)sizeof(struct llog_gen) == 16, "found %lld\n",
                 (long long)(int)sizeof(struct llog_gen));
index 3a27042..2f49e43 100755 (executable)
@@ -2365,6 +2365,10 @@ test_31() {
        [ -z "$LNETCTL" ] && skip "without lnetctl support." && return
        local_mode && skip "in local mode."
 
+       if $SHARED_KEY; then
+               skip "Conflicting test with SSK"
+       fi
+
        # save mds failover nids for restore at cleanup
        failover_mds1=$(do_facet mds1 $TUNEFS --dryrun $(mdsdevname 1))
        if [ -n "$failover_mds1" ]; then
@@ -2487,8 +2491,11 @@ cleanup_32() {
        set_rule _mgs any any null
 
        # stop gss daemon on MGS
-       if ! combined_mgs_mds ; then
-               send_sigint $mgs_HOST lsvcgssd
+       send_sigint $mgs_HOST lsvcgssd
+
+       # re-start gss daemon on MDS if necessary
+       if combined_mgs_mds ; then
+               start_gss_daemons $mds_HOST "$LSVCGSSD -vvv -s -m -o -z"
        fi
 
        # re-mount client
@@ -2519,11 +2526,15 @@ test_32() {
        umount_client $MOUNT || error "umount $MOUNT failed"
        fi
 
+       # kill daemon on MGS to start afresh
+       send_sigint $mgs_HOST lsvcgssd
+
        # start gss daemon on MGS
        if combined_mgs_mds ; then
-               send_sigint $mds_HOST lsvcgssd
+               start_gss_daemons $mgs_HOST "$LSVCGSSD -vvv -s -g -m -o -z"
+       else
+               start_gss_daemons $mgs_HOST "$LSVCGSSD -vvv -s -g"
        fi
-       start_gss_daemons $mgs_HOST "$LSVCGSSD -vvv -s -g"
 
        # add mgs key type and MGS NIDs in key on MGS
        do_nodes $mgs_HOST "$LGSS_SK -t mgs,server -g $MGSNID -m \
@@ -2602,8 +2613,11 @@ cleanup_33() {
        zconf_umount_clients ${clients_arr[0]} $MOUNT
 
        # stop gss daemon on MGS
-       if ! combined_mgs_mds ; then
-               send_sigint $mgs_HOST lsvcgssd
+       send_sigint $mgs_HOST lsvcgssd
+
+       # re-start gss daemon on MDS if necessary
+       if combined_mgs_mds ; then
+               start_gss_daemons $mds_HOST "$LSVCGSSD -vvv -s -m -o -z"
        fi
 
        # re-mount client
@@ -2634,11 +2648,15 @@ test_33() {
        umount_client $MOUNT || error "umount $MOUNT failed"
        fi
 
+       # kill daemon on MGS to start afresh
+       send_sigint $mgs_HOST lsvcgssd
+
        # start gss daemon on MGS
        if combined_mgs_mds ; then
-               send_sigint $mds_HOST lsvcgssd
+               start_gss_daemons $mgs_HOST "$LSVCGSSD -vvv -s -g -m -o -z"
+       else
+               start_gss_daemons $mgs_HOST "$LSVCGSSD -vvv -s -g"
        fi
-       start_gss_daemons $mgs_HOST "$LSVCGSSD -vvv -s -g"
 
        # add mgs key type and MGS NIDs in key on MGS
        do_nodes $mgs_HOST "$LGSS_SK -t mgs,server -g $MGSNID -m \
index 8d119bc..22e8615 100755 (executable)
@@ -352,6 +352,8 @@ init_test_env() {
        [ ! -f "$LSOM_SYNC" ] &&
                export LSOM_SYNC=$(which llsom_sync 2> /dev/null)
        [ -z "$LSOM_SYNC" ] && export LSOM_SYNC="/usr/sbin/llsom_sync"
+       export L_GETAUTH=${L_GETAUTH:-"$LUSTRE/utils/gss/l_getauth"}
+       [ ! -f "$L_GETAUTH" ] && export L_GETAUTH=$(which l_getauth 2> /dev/null)
        export LSVCGSSD=${LSVCGSSD:-"$LUSTRE/utils/gss/lsvcgssd"}
        [ ! -f "$LSVCGSSD" ] && export LSVCGSSD=$(which lsvcgssd 2> /dev/null)
        export KRB5DIR=${KRB5DIR:-"/usr/kerberos"}
@@ -960,12 +962,31 @@ fs_inode_ksize() {
 check_gss_daemon_nodes() {
        local list=$1
        local dname=$2
+       local loopmax=10
+       local loop
+       local node
+       local ret
 
        do_nodesv $list "num=\\\$(ps -o cmd -C $dname | grep $dname | wc -l);
 if [ \\\"\\\$num\\\" -ne 1 ]; then
     echo \\\$num instance of $dname;
     exit 1;
 fi; "
+       ret=$?
+       (( $ret == 0 )) || return $ret
+
+       for node in ${list//,/ }; do
+               loop=0
+               while (( $loop < $loopmax )); do
+                       do_nodesv $node "$L_GETAUTH -d"
+                       ret=$?
+                       (( $ret == 0 )) && break
+                       loop=$((loop + 1))
+                       sleep 5
+               done
+               (( $loop < $loopmax )) || return 1
+       done
+       return 0
 }
 
 check_gss_daemon_facet() {
@@ -997,6 +1018,7 @@ start_gss_daemons() {
        if [ "$nodes" ] && [ "$daemon" ] ; then
                echo "Starting gss daemon on nodes: $nodes"
                do_nodes $nodes "$daemon" "$options" || return 8
+               check_gss_daemon_nodes $nodes lsvcgssd || return 9
                return 0
        fi
 
@@ -1023,9 +1045,6 @@ start_gss_daemons() {
 
        local clients=${CLIENTS:-$HOSTNAME}
 
-       # wait daemons entering "stable" status
-       sleep 5
-
        #
        # check daemons are running
        #
@@ -1236,6 +1255,9 @@ init_gss() {
                lctl set_param -n \
                   sptlrpc.gss.lgss_keyring.debug_level=$LGSS_KEYRING_DEBUG"
        fi
+
+       do_nodesv $(comma_list $(all_server_nodes)) \
+               "$LCTL set_param sptlrpc.gss.rsi_upcall=$L_GETAUTH"
 }
 
 cleanup_gss() {
index 4abb8c0..a28ef0b 100644 (file)
@@ -3,3 +3,4 @@
 /l_idmap
 /lgss_keyring
 /lgss_sk
+/l_getauth
index be33ffe..c88e82e 100644 (file)
@@ -7,7 +7,7 @@ AM_CFLAGS := -fPIC \
 sbin_PROGRAMS = l_idmap
 
 if GSS_KEYRING
-sbin_PROGRAMS += lsvcgssd lgss_keyring
+sbin_PROGRAMS += lsvcgssd lgss_keyring l_getauth
 if GSS_SSK
 sbin_PROGRAMS += lgss_sk
 endif
@@ -61,6 +61,21 @@ l_idmap_SOURCES = \
 
 l_idmap_LDADD = $(top_builddir)/lustre/utils/liblustreapi.la $(KRBLIBS)
 
+l_getauth_SOURCES = \
+       l_getauth.c \
+       lsupport.c \
+       err_util.c \
+       lgss_utils.c \
+       lgss_krb5_utils.c \
+       lgss_null_utils.c \
+       lgss_utils.h \
+       lgss_krb5_utils.h \
+       lsupport.h
+
+l_getauth_CFLAGS = $(AM_CFLAGS) $(CFLAGS) $(KRBCFLAGS) -D _NEW_BUILD_
+l_getauth_LDADD = $(top_builddir)/lustre/utils/liblustreapi.la $(GSSAPI_LIBS) $(KRBLIBS) -lm -lkeyutils
+l_getauth_LDFLAGS = $(KRBLDFLAGS)
+
 lgss_keyring_SOURCES = \
        lgss_keyring.c \
        context.c \
@@ -82,6 +97,9 @@ lgss_keyring_LDADD = $(top_builddir)/lustre/utils/liblustreapi.la $(GSSAPI_LIBS)
 lgss_keyring_LDFLAGS = $(KRBLDFLAGS)
 
 if GSS_SSK
+l_getauth_SOURCES += sk_utils.c sk_utils.h lgss_sk_utils.c
+l_getauth_LDADD += -lcrypto -lssl
+
 lgss_keyring_SOURCES += sk_utils.c sk_utils.h lgss_sk_utils.c
 lgss_keyring_LDADD += -lcrypto -lssl
 
diff --git a/lustre/utils/gss/l_getauth.c b/lustre/utils/gss/l_getauth.c
new file mode 100644 (file)
index 0000000..d1fecbe
--- /dev/null
@@ -0,0 +1,111 @@
+#include <sys/types.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <glob.h>
+#include <getopt.h>
+
+#include "lsupport.h"
+#include "err_util.h"
+
+int main(int argc, char **argv)
+{
+       int local_socket;
+       struct sockaddr_un addr;
+       ssize_t bytes_sent;
+       char *auth_req = NULL, *cachename = NULL;
+       ssize_t req_len;
+       int opt, debug = 0, rc = 0;
+
+       /* Parameters received from kernel (see rsi_do_upcall()):
+        * -c <cache name> -r <auth request> -d
+        * -d checks connection to lsvcgssd daemon
+        */
+
+       static struct option long_opts[] = {
+               { .name = "cache",   .has_arg = required_argument, .val = 'c'},
+               { .name = "debug",   .has_arg = no_argument,       .val = 'd'},
+               { .name = "authreq", .has_arg = required_argument, .val = 'r'},
+               { .name = NULL, } };
+
+       /* init gss logger for foreground (stderr) or background (syslog) */
+       initerr(NULL, LL_MAX, isatty(STDOUT_FILENO));
+
+       while ((opt = getopt_long(argc, argv, "c:dr:",
+                                 long_opts, NULL)) != EOF) {
+               switch (opt) {
+               case 'c':
+                       cachename = optarg;
+                       break;
+               case 'd':
+                       debug = 1;
+                       goto connect;
+               case 'r':
+                       auth_req = optarg;
+                       break;
+               default:
+                       printerr(LL_ERR, "error: unknown option: '%c'\n", opt);
+                       return EXIT_FAILURE;
+               }
+       }
+
+       if (optind != argc) {
+               printerr(LL_ERR,
+                        "error: extraneous arguments provided, check usage\n");
+               return EXIT_FAILURE;
+       }
+
+       if (!cachename || !auth_req) {
+               printerr(LL_ERR, "error: missing arguments, check usage\n");
+               return EXIT_FAILURE;
+       }
+
+       if (strcmp(cachename, RSI_CACHE_NAME) != 0) {
+               printerr(LL_ERR, "invalid cache name %s\n", cachename);
+               return EXIT_FAILURE;
+       }
+
+       req_len = strlen(auth_req);
+
+connect:
+       /* Send auth request to lsvcgssd via a socket. */
+       local_socket = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (local_socket == -1) {
+               rc = -errno;
+               printerr(LL_ERR, "cannot create socket: %d\n", rc);
+               return rc;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       strncpy(addr.sun_path, GSS_SOCKET_PATH, sizeof(addr.sun_path) - 1);
+
+       if (connect(local_socket, (struct sockaddr *)&addr,
+                   sizeof(addr)) == -1) {
+               rc = -errno;
+               printerr(LL_ERR, "cannot connect to socket: %d\n", rc);
+               goto out;
+       }
+
+       if (debug)
+               goto out;
+
+       bytes_sent = write(local_socket, auth_req, req_len);
+       if (bytes_sent < 0) {
+               rc = -errno;
+               printerr(LL_ERR, "write failed: %d\n", rc);
+       } else if (bytes_sent != req_len) {
+               printerr(LL_ERR, "partial write %zu vs. %zu\n",
+                      bytes_sent, req_len);
+               rc = -EMSGSIZE;
+       }
+
+out:
+       close(local_socket);
+       return rc;
+}
index bd60f1e..36b8d67 100644 (file)
 #include <unistd.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <errno.h>
+#include <stdio.h>
 
 #include <libcfs/util/list.h>
 #include <linux/lnet/lnet-types.h>
 #include <linux/lnet/nidstr.h>
+#include <uapi/linux/lustre/lgss.h>
 
 #include <krb5.h>
 
@@ -109,4 +112,30 @@ int mapping_empty(void);
 int lookup_mapping(char *princ, lnet_nid_t nid, uid_t *uid);
 int gss_get_realm(char *realm);
 
+/*
+ * gss_buffer_write() - write some buffer to stream
+ */
+static inline int gss_buffer_write_file(FILE *f, void *value, size_t length)
+{
+       int rc = 0;
+
+       /* write size of data */
+       if (fwrite(&length, sizeof(__u32), 1, f) != 1) {
+               rc = -errno;
+               goto out;
+       }
+
+       if (!length || !value)
+               goto out;
+
+       /* write data itself */
+       if (fwrite(value, length, 1, f) != 1) {
+               rc = -errno;
+               goto out;
+       }
+
+out:
+       return rc;
+}
+
 #endif /* __LSUPPORT_H__ */
index 32ad64c..cdaf4ab 100644 (file)
@@ -170,6 +170,8 @@ sig_die(int signal)
        cleanup_mapping();
        /* cleanup allocated strings for realms */
        gssd_cleanup_realms();
+       /* remove socket */
+       unlink(GSS_SOCKET_PATH);
        printerr(LL_WARN, "exiting on signal %d\n", signal);
        exit(1);
 }
@@ -187,16 +189,16 @@ usage(FILE *fp, char *progname)
        fprintf(fp, "usage: %s [ -fnvmogkRsz ]\n",
                progname);
        fprintf(stderr, "-f             - Run in foreground\n");
-       fprintf(stderr, "-n             - Don't establish kerberos credentials\n");
-       fprintf(stderr, "-v             - Verbosity\n");
-       fprintf(stderr, "-m             - Service MDS\n");
-       fprintf(stderr, "-o             - Service OSS\n");
        fprintf(stderr, "-g             - Service MGS\n");
        fprintf(stderr, "-k             - Enable kerberos support\n");
+       fprintf(stderr, "-m             - Service MDS\n");
+       fprintf(stderr, "-n             - Don't establish kerberos credentials\n");
+       fprintf(stderr, "-o             - Service OSS\n");
        fprintf(stderr, "-R REALM       - Kerberos Realm to use, instead of default\n");
 #ifdef HAVE_OPENSSL_SSK
        fprintf(stderr, "-s             - Enable shared secret key support\n");
 #endif
+       fprintf(stderr, "-v             - Verbosity\n");
        fprintf(stderr, "-z             - Enable gssnull support\n");
 
        exit(fp == stderr);
index 9cf996a..936267d 100644 (file)
@@ -36,7 +36,7 @@
 #include <gssapi/gssapi.h>
 #include "lsupport.h"
 
-int handle_channel_request(FILE *f);
+int handle_channel_request(int fd);
 void svcgssd_run(void);
 int gssd_prepare_creds(int must_srv_mgs, int must_srv_mds, int must_srv_oss);
 gss_cred_id_t gssd_select_svc_cred(int lustre_svc);
index bbecd7f..7758013 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <sys/param.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <sys/poll.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -45,7 +46,9 @@
 /* For nanosleep() */
 #include <time.h>
 
+#include "cacheio.h"
 #include "svcgssd.h"
+#include "lsupport.h"
 #include "err_util.h"
 #include "sk_utils.h"
 
 #define MAX_ALLOWED_TIME_FOR_PRIME 400000
 int sk_dh_checks;
 
-/*
- * nfs4 in-kernel cache implementation make upcall failed directly
- * if there's no listener detected. so here we should keep the init
- * channel file open as possible as we can.
- *
- * unfortunately the proc doesn't support dir change notification.
- * and when an entry get unlinked, we only got POLLIN event once,
- * it's the only oppotunity we can close the file and startover.
- */
-void
-svcgssd_run()
+void svcgssd_run(void)
 {
-       static const char gss_rpc_channel_path[] =
-               "/proc/net/rpc/auth.sptlrpc.init/channel";
-       int                     ret;
-       FILE                    *f = NULL;
-       struct pollfd           pollfd;
-       struct timespec         halfsec = { .tv_sec = 0, .tv_nsec = 500000000 };
+       int local_socket, remote_socket;
+       struct sockaddr_un addr;
+       bool retried = false;
+       int ret = 0;
 
        if (sk_enabled) {
 #if !defined(HAVE_OPENSSL_EVP_PKEY) && OPENSSL_VERSION_NUMBER >= 0x1010103fL
@@ -89,48 +80,52 @@ svcgssd_run()
                load_mapping();
        }
 
-       while (1) {
-               int save_err;
-
-               while (f == NULL) {
-                       f = fopen(gss_rpc_channel_path, "r+");
-                       if (f == NULL) {
-                               printerr(LL_TRACE, "failed to open %s: %s\n",
-                                        gss_rpc_channel_path, strerror(errno));
-                               nanosleep(&halfsec, NULL);
-                       } else {
-                               printerr(LL_WARN, "successfully open %s\n",
-                                        gss_rpc_channel_path);
-                               break;
-                       }
+again:
+       local_socket = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (local_socket == -1) {
+               printerr(LL_ERR, "unable to create socket: %d\n", -errno);
+               ret = 1;
+               goto out_close;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       strncpy(addr.sun_path, GSS_SOCKET_PATH, sizeof(addr.sun_path) - 1);
+
+       if (bind(local_socket, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+               if (!retried) {
+                       retried = true;
+                       unlink(GSS_SOCKET_PATH);
+                       close(local_socket);
+                       goto again;
                }
-               pollfd.fd = fileno(f);
-               pollfd.events = POLLIN;
-
-               pollfd.revents = 0;
-               ret = poll(&pollfd, 1, 1000);
-               save_err = errno;
-
-               if (ret < 0) {
-                       printerr(LL_ERR, "error return from poll: %s\n",
-                                strerror(save_err));
-                       fclose(f);
-                       f = NULL;
-               } else if (ret == 0) {
-                       printerr(LL_TRACE, "poll timeout\n");
-               } else {
-                       if (ret != 1) {
-                               printerr(LL_ERR,
-                                        "bug: unexpected poll return %d\n",
-                                        ret);
-                               exit(1);
-                       }
-                       if (pollfd.revents & POLLIN) {
-                               if (handle_channel_request(f) < 0) {
-                                       fclose(f);
-                                       f = NULL;
-                               }
-                       }
+               printerr(LL_ERR, "unable to bind socket: %d\n", -errno);
+               ret = 1;
+               goto out_close;
+       }
+
+       if (listen(local_socket, 10) == -1) {
+               printerr(LL_ERR, "unable to listen on socket: %d\n", -errno);
+               ret = 1;
+               goto out;
+       }
+
+       while (1) {
+               remote_socket = accept(local_socket, NULL, NULL);
+               if (remote_socket == -1) {
+                       printerr(LL_TRACE, "accept on socket ret %d\n", -errno);
+                       continue;
                }
+
+               ret = handle_channel_request(remote_socket);
+               printerr(LL_DEBUG, "handle_channel_request ret %d\n", ret);
+               close(remote_socket);
        }
+
+out:
+       unlink(GSS_SOCKET_PATH);
+out_close:
+       if (local_socket >= 0)
+               close(local_socket);
+       exit(ret);
 }
index c2ef07f..a21b81c 100644 (file)
 #include "sk_utils.h"
 #include <sys/time.h>
 #include <gssapi/gssapi_krb5.h>
+#include <libcfs/util/param.h>
 
 #define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.sptlrpc.context/channel"
 #define SVCGSSD_INIT_CHANNEL    "/proc/net/rpc/auth.sptlrpc.init/channel"
 
-#define TOKEN_BUF_SIZE         8192
-
 struct svc_cred {
        uint32_t cr_remote;
        uint32_t cr_usr_root;
@@ -142,46 +141,88 @@ struct gss_verifier {
 
 #define RPCSEC_GSS_SEQ_WIN     5
 
-static int
-send_response(FILE *f, gss_buffer_desc *in_handle, gss_buffer_desc *in_token,
-             u_int32_t maj_stat, u_int32_t min_stat,
-             gss_buffer_desc *out_handle, gss_buffer_desc *out_token)
+static int send_response(int auth_res, uint64_t hash,
+                       gss_buffer_desc *in_handle, gss_buffer_desc *in_token,
+                       u_int32_t maj_stat, u_int32_t min_stat,
+                       gss_buffer_desc *out_handle, gss_buffer_desc *out_token)
 {
-       char buf[2 * TOKEN_BUF_SIZE];
-       char *bp = buf;
-       int blen = sizeof(buf);
-       /* XXXARG: */
-       int g;
+       struct rsi_downcall_data *rsi_dd;
+       int blen, fd, size, rc = 0;
+       glob_t path;
+       char *bp;
 
        printerr(LL_INFO, "sending reply\n");
-       qword_addhex(&bp, &blen, in_handle->value, in_handle->length);
-       qword_addhex(&bp, &blen, in_token->value, in_token->length);
-       qword_addint(&bp, &blen, time(NULL) + 3600);   /* 1 hour should be ok */
-       qword_adduint(&bp, &blen, maj_stat);
-       qword_adduint(&bp, &blen, min_stat);
-       qword_addhex(&bp, &blen, out_handle->value, out_handle->length);
-       qword_addhex(&bp, &blen, out_token->value, out_token->length);
-       qword_addeol(&bp, &blen);
-       if (blen <= 0) {
-               printerr(LL_ERR, "ERROR: %s: message too long\n", __func__);
-               return -1;
+
+       size = in_handle->length + sizeof(__u32) +
+               in_token->length + sizeof(__u32) +
+               sizeof(__u32) + sizeof(__u32);
+       if (!auth_res)
+               size += out_handle->length + out_token->length;
+       blen = size;
+
+       size += offsetof(struct rsi_downcall_data, sid_val[0]);
+       rsi_dd = calloc(1, size);
+       if (!rsi_dd) {
+               printerr(LL_ERR, "malloc downcall data (%d) failed\n", size);
+               return -ENOMEM;
+       }
+       rsi_dd->sid_magic = RSI_DOWNCALL_MAGIC;
+       rsi_dd->sid_hash = hash;
+       rsi_dd->sid_maj_stat = maj_stat;
+       rsi_dd->sid_min_stat = min_stat;
+
+       bp = rsi_dd->sid_val;
+       gss_buffer_write(&bp, &blen, in_handle->value, in_handle->length);
+       gss_buffer_write(&bp, &blen, in_token->value, in_token->length);
+       if (!auth_res) {
+               gss_buffer_write(&bp, &blen, out_handle->value,
+                                out_handle->length);
+               gss_buffer_write(&bp, &blen, out_token->value,
+                                out_token->length);
+       } else {
+               rsi_dd->sid_err = -EACCES;
+               gss_buffer_write(&bp, &blen, NULL, 0);
+               gss_buffer_write(&bp, &blen, NULL, 0);
        }
-       g = open(SVCGSSD_INIT_CHANNEL, O_WRONLY);
-       if (g == -1) {
+       if (blen < 0) {
+               printerr(LL_ERR, "ERROR: %s: message too long > %d\n",
+                        __func__, size);
+               rc = -EMSGSIZE;
+               goto out;
+       }
+       rsi_dd->sid_len = bp - rsi_dd->sid_val;
+
+       rc = cfs_get_param_paths(&path, RSI_DOWNCALL_PATH);
+       if (rc != 0) {
+               rc = -errno;
+               printerr(LL_ERR, "ERROR: %s: cannot get param path %s: %s\n",
+                        __func__, RSI_DOWNCALL_PATH, strerror(-rc));
+               goto out;
+       }
+
+       fd = open(path.gl_pathv[0], O_WRONLY);
+       if (fd == -1) {
+               rc = -errno;
                printerr(LL_ERR, "ERROR: %s: open %s failed: %s\n",
-                        __func__, SVCGSSD_INIT_CHANNEL, strerror(errno));
-               return -1;
+                        __func__, RSI_DOWNCALL_PATH, strerror(-rc));
+               goto out_path;
        }
-       *bp = '\0';
-       printerr(LL_DEBUG, "writing message: %s", buf);
-       if (write(g, buf, bp - buf) == -1) {
-               printerr(LL_ERR, "ERROR: %s: failed to write message\n",
-                        __func__);
-               close(g);
-               return -1;
+       size = offsetof(struct rsi_downcall_data,
+                       sid_val[bp - rsi_dd->sid_val]);
+       printerr(LL_DEBUG, "writing response, size %d\n", size);
+       if (write(fd, rsi_dd, size) == -1) {
+               rc = -errno;
+               printerr(LL_ERR, "ERROR: %s: failed to write message: %s\n",
+                        __func__, strerror(-rc));
        }
-       close(g);
-       return 0;
+       printerr(LL_DEBUG, "response written ok\n");
+
+       close(fd);
+out_path:
+       cfs_free_param_data(&path);
+out:
+       free(rsi_dd);
+       return rc;
 }
 
 #define rpc_auth_ok                    0
@@ -623,10 +664,17 @@ redo:
 
        do_svc_downcall(&snd->out_handle, &cred, snd->mech, &snd->ctx_token);
 
-       /* cleanup ctx_token, out_tok is cleaned up in handle_channel_req */
-       free(remote_pub_key.value);
-       free(snd->ctx_token.value);
-       snd->ctx_token.length = 0;
+       /* cleanup ctx_token, out_tok is cleaned up in handle_channel_request */
+       if (remote_pub_key.length != 0) {
+               free(remote_pub_key.value);
+               remote_pub_key.value = NULL;
+               remote_pub_key.length = 0;
+       }
+       if (snd->ctx_token.value) {
+               free(snd->ctx_token.value);
+               snd->ctx_token.value = NULL;
+               snd->ctx_token.length = 0;
+       }
 
        printerr(LL_DEBUG, "sk returning success\n");
        return 0;
@@ -643,7 +691,11 @@ cleanup_partial:
        free(bufs[SK_INIT_RANDOM].value);
        free(bufs[SK_INIT_TARGET].value);
        free(bufs[SK_INIT_FLAGS].value);
-       free(remote_pub_key.value);
+       if (remote_pub_key.length != 0) {
+               free(remote_pub_key.value);
+               remote_pub_key.value = NULL;
+               remote_pub_key.length = 0;
+       }
        sk_free_cred(skc);
        snd->maj_stat = rc;
        return -1;
@@ -652,10 +704,14 @@ out_err:
        snd->maj_stat = rc;
        if (snd->ctx_token.value) {
                free(snd->ctx_token.value);
-               snd->ctx_token.value = 0;
+               snd->ctx_token.value = NULL;
                snd->ctx_token.length = 0;
        }
-       free(remote_pub_key.value);
+       if (remote_pub_key.length != 0) {
+               free(remote_pub_key.value);
+               remote_pub_key.value = NULL;
+               remote_pub_key.length = 0;
+       }
        sk_free_cred(skc);
        printerr(LL_DEBUG, "sk returning failure\n");
 #else /* !HAVE_OPENSSL_SSK */
@@ -786,7 +842,12 @@ static int handle_krb(struct svc_nego_data *snd)
        /* We no longer need the gss context */
        gss_delete_sec_context(&ignore_min_stat, &snd->ctx, &ignore_out_tok);
        do_svc_downcall(&snd->out_handle, &cred, mech, &snd->ctx_token);
-
+       /* We no longer need the context token */
+       if (snd->ctx_token.value) {
+               free(snd->ctx_token.value);
+               snd->ctx_token.value = NULL;
+               snd->ctx_token.length = 0;
+       }
        return 0;
 
 out_err:
@@ -797,46 +858,48 @@ out_err:
        return 1;
 }
 
-/*
- * return -1 only if we detect error during reading from upcall channel,
- * all other cases return 0.
- */
-int handle_channel_request(FILE *f)
+int handle_channel_request(int fd)
 {
-       char                    in_tok_buf[TOKEN_BUF_SIZE];
-       char                    in_handle_buf[15];
-       char                    out_handle_buf[15];
-       gss_buffer_desc         ctx_token      = {.value = NULL},
-                               null_token     = {.value = NULL};
-       uint32_t                lustre_mech;
-       static char             *lbuf;
-       static int              lbuflen;
-       static char             *cp;
-       int                     get_len;
-       int                     rc = 1;
-       u_int32_t               ignore_min_stat;
-       struct svc_nego_data    snd = {
-               .in_tok.value           = in_tok_buf,
+       char in_handle_buf[15];
+       char out_handle_buf[15];
+       uint32_t lustre_mech;
+       static char *lbuf;
+       static int lbuflen;
+       static char *cp;
+       int get_len;
+       int rc;
+       u_int32_t ignore_min_stat;
+       struct svc_nego_data snd = {
+               .in_tok.value           = NULL,
                .in_handle.value        = in_handle_buf,
                .out_handle.value       = out_handle_buf,
                .maj_stat               = GSS_S_FAILURE,
                .ctx                    = GSS_C_NO_CONTEXT,
        };
+       uint64_t hash = 0;
 
        printerr(LL_INFO, "handling request\n");
-       if (readline(fileno(f), &lbuf, &lbuflen) != 1) {
+       if (readline(fd, &lbuf, &lbuflen) != 1) {
                printerr(LL_ERR, "ERROR: failed reading request\n");
                return -1;
        }
 
        cp = lbuf;
 
-       /* see rsi_request() for the format of data being input here */
-       qword_get(&cp, (char *)&snd.lustre_svc, sizeof(snd.lustre_svc));
-
+       /* see rsi_do_upcall() for the format of data being input here */
+       rc = gss_u64_read_string(&cp, (__u64 *)&hash);
+       if (rc < 0) {
+               printerr(LL_ERR, "ERROR: failed parsing request: hash\n");
+               goto out_err;
+       }
+       rc = gss_u64_read_string(&cp, (__u64 *)&snd.lustre_svc);
+       if (rc < 0) {
+               printerr(LL_ERR, "ERROR: failed parsing request: lustre svc\n");
+               goto out_err;
+       }
        /* lustre_svc is the svc and gss subflavor */
        lustre_mech = (snd.lustre_svc & LUSTRE_GSS_MECH_MASK) >>
-                     LUSTRE_GSS_MECH_SHIFT;
+               LUSTRE_GSS_MECH_SHIFT;
        snd.lustre_svc = snd.lustre_svc & LUSTRE_GSS_SVC_MASK;
        switch (lustre_mech) {
        case LGSS_MECH_KRB5:
@@ -892,16 +955,31 @@ int handle_channel_request(FILE *f)
                break;
        }
 
-       qword_get(&cp, (char *)&snd.nid, sizeof(snd.nid));
-       qword_get(&cp, (char *)&snd.handle_seq, sizeof(snd.handle_seq));
-       qword_get(&cp, snd.nm_name, sizeof(snd.nm_name));
+       rc = gss_u64_read_string(&cp, (__u64 *)&snd.nid);
+       if (rc < 0) {
+               printerr(LL_ERR, "ERROR: failed parsing request: source nid\n");
+               goto out_err;
+       }
+       rc = gss_u64_read_string(&cp, (__u64 *)&snd.handle_seq);
+       if (rc < 0) {
+               printerr(LL_ERR, "ERROR: failed parsing request: handle seq\n");
+               goto out_err;
+       }
+       get_len = gss_string_read(&cp, snd.nm_name, sizeof(snd.nm_name), 0);
+       if (get_len <= 0) {
+               printerr(LL_ERR,
+                        "ERROR: failed parsing request: nodemap name\n");
+               goto out_err;
+       }
+       snd.nm_name[get_len] = '\0';
        printerr(LL_INFO,
                 "handling req: svc %u, nid %016llx, idx %"PRIx64" nodemap %s\n",
                 snd.lustre_svc, snd.nid, snd.handle_seq, snd.nm_name);
 
-       get_len = qword_get(&cp, snd.in_handle.value, sizeof(in_handle_buf));
+       get_len = gss_base64url_decode(&cp, snd.in_handle.value,
+                                      sizeof(in_handle_buf));
        if (get_len < 0) {
-               printerr(LL_ERR, "ERROR: failed parsing request\n");
+               printerr(LL_ERR, "ERROR: failed parsing request: in handle\n");
                goto out_err;
        }
        snd.in_handle.length = (size_t)get_len;
@@ -909,9 +987,14 @@ int handle_channel_request(FILE *f)
        printerr(LL_DEBUG, "in_handle:\n");
        print_hexl(3, snd.in_handle.value, snd.in_handle.length);
 
-       get_len = qword_get(&cp, snd.in_tok.value, sizeof(in_tok_buf));
+       snd.in_tok.value = malloc(strlen(cp));
+       if (!snd.in_tok.value) {
+               printerr(LL_ERR, "ERROR: failed alloc for in token\n");
+               goto out_err;
+       }
+       get_len = gss_base64url_decode(&cp, snd.in_tok.value, strlen(cp));
        if (get_len < 0) {
-               printerr(LL_ERR, "ERROR: failed parsing request\n");
+               printerr(LL_ERR, "ERROR: failed parsing request: in token\n");
                goto out_err;
        }
        snd.in_tok.length = (size_t)get_len;
@@ -931,6 +1014,7 @@ int handle_channel_request(FILE *f)
                memcpy(&snd.ctx, snd.in_handle.value, snd.in_handle.length);
        }
 
+       rc = -1;
        if (lustre_mech == LGSS_MECH_KRB5)
                rc = handle_krb(&snd);
        else if (lustre_mech == LGSS_MECH_SK)
@@ -944,20 +1028,17 @@ int handle_channel_request(FILE *f)
 
 out_err:
        /* Failures send a null token */
-       if (rc == 0)
-               send_response(f, &snd.in_handle, &snd.in_tok, snd.maj_stat,
-                             snd.min_stat, &snd.out_handle, &snd.out_tok);
-       else
-               send_response(f, &snd.in_handle, &snd.in_tok, snd.maj_stat,
-                             snd.min_stat, &null_token, &null_token);
+       rc = send_response(rc, hash, &snd.in_handle, &snd.in_tok,
+                          snd.maj_stat, snd.min_stat,
+                          &snd.out_handle, &snd.out_tok);
 
        /* cleanup buffers */
-       if (snd.ctx_token.value != NULL)
-               free(ctx_token.value);
+       if (snd.in_tok.value)
+               free(snd.in_tok.value);
        if (snd.out_tok.value != NULL)
                gss_release_buffer(&ignore_min_stat, &snd.out_tok);
 
        /* For junk wire data just ignore */
 ignore:
-       return 0;
+       return rc;
 }
index bf10d28..fcc6a7f 100644 (file)
@@ -2046,6 +2046,21 @@ check_llog_changelog_user_rec(void)
 #endif /* !HAVE_NATIVE_LINUX_CLIENT */
 
 static void
+check_rsi_downcall_data(void)
+{
+       BLANK_LINE();
+       CHECK_STRUCT(rsi_downcall_data);
+       CHECK_MEMBER(rsi_downcall_data, sid_magic);
+       CHECK_MEMBER(rsi_downcall_data, sid_err);
+       CHECK_MEMBER(rsi_downcall_data, sid_hash);
+       CHECK_MEMBER(rsi_downcall_data, sid_maj_stat);
+       CHECK_MEMBER(rsi_downcall_data, sid_min_stat);
+       CHECK_MEMBER(rsi_downcall_data, sid_len);
+       CHECK_MEMBER(rsi_downcall_data, sid_offset);
+       CHECK_MEMBER(rsi_downcall_data, sid_val);
+}
+
+static void
 check_llog_gen(void)
 {
        BLANK_LINE();
@@ -3576,6 +3591,7 @@ main(int argc, char **argv)
 #ifndef HAVE_NATIVE_LINUX_CLIENT
        check_llog_changelog_user_rec();
 #endif /* !HAVE_NATIVE_LINUX_CLIENT */
+       check_rsi_downcall_data();
        check_llog_gen();
        check_llog_gen_rec();
        check_llog_log_hdr();
index 81739d4..905e71a 100644 (file)
@@ -48,6 +48,7 @@
 #endif /* CONFIG_FS_POSIX_ACL */
 #endif /* HAVE_SERVER_SUPPORT */
 #include <linux/lustre/lustre_cfg.h>
+#include <linux/lustre/lgss.h>
 #include <lustre/lustreapi.h>
 
 #ifndef BUILD_BUG_ON
@@ -4451,6 +4452,42 @@ void lustre_assert_wire_constants(void)
                 (long long)(int)sizeof(((struct llog_changelog_user_rec *)0)->cur_tail));
 #endif /* HAVE_SERVER_SUPPORT */
 
+       /* Checks for struct rsi_downcall_data */
+       LASSERTF((int)sizeof(struct rsi_downcall_data) == 32, "found %lld\n",
+                (long long)(int)sizeof(struct rsi_downcall_data));
+       LASSERTF((int)offsetof(struct rsi_downcall_data, sid_magic) == 0, "found %lld\n",
+                (long long)(int)offsetof(struct rsi_downcall_data, sid_magic));
+       LASSERTF((int)sizeof(((struct rsi_downcall_data *)0)->sid_magic) == 4, "found %lld\n",
+                (long long)(int)sizeof(((struct rsi_downcall_data *)0)->sid_magic));
+       LASSERTF((int)offsetof(struct rsi_downcall_data, sid_err) == 4, "found %lld\n",
+                (long long)(int)offsetof(struct rsi_downcall_data, sid_err));
+       LASSERTF((int)sizeof(((struct rsi_downcall_data *)0)->sid_err) == 4, "found %lld\n",
+                (long long)(int)sizeof(((struct rsi_downcall_data *)0)->sid_err));
+       LASSERTF((int)offsetof(struct rsi_downcall_data, sid_hash) == 8, "found %lld\n",
+                (long long)(int)offsetof(struct rsi_downcall_data, sid_hash));
+       LASSERTF((int)sizeof(((struct rsi_downcall_data *)0)->sid_hash) == 4, "found %lld\n",
+                (long long)(int)sizeof(((struct rsi_downcall_data *)0)->sid_hash));
+       LASSERTF((int)offsetof(struct rsi_downcall_data, sid_maj_stat) == 12, "found %lld\n",
+                (long long)(int)offsetof(struct rsi_downcall_data, sid_maj_stat));
+       LASSERTF((int)sizeof(((struct rsi_downcall_data *)0)->sid_maj_stat) == 4, "found %lld\n",
+                (long long)(int)sizeof(((struct rsi_downcall_data *)0)->sid_maj_stat));
+       LASSERTF((int)offsetof(struct rsi_downcall_data, sid_min_stat) == 16, "found %lld\n",
+                (long long)(int)offsetof(struct rsi_downcall_data, sid_min_stat));
+       LASSERTF((int)sizeof(((struct rsi_downcall_data *)0)->sid_min_stat) == 4, "found %lld\n",
+                (long long)(int)sizeof(((struct rsi_downcall_data *)0)->sid_min_stat));
+       LASSERTF((int)offsetof(struct rsi_downcall_data, sid_len) == 20, "found %lld\n",
+                (long long)(int)offsetof(struct rsi_downcall_data, sid_len));
+       LASSERTF((int)sizeof(((struct rsi_downcall_data *)0)->sid_len) == 4, "found %lld\n",
+                (long long)(int)sizeof(((struct rsi_downcall_data *)0)->sid_len));
+       LASSERTF((int)offsetof(struct rsi_downcall_data, sid_offset) == 24, "found %lld\n",
+                (long long)(int)offsetof(struct rsi_downcall_data, sid_offset));
+       LASSERTF((int)sizeof(((struct rsi_downcall_data *)0)->sid_offset) == 8, "found %lld\n",
+                (long long)(int)sizeof(((struct rsi_downcall_data *)0)->sid_offset));
+       LASSERTF((int)offsetof(struct rsi_downcall_data, sid_val) == 32, "found %lld\n",
+                (long long)(int)offsetof(struct rsi_downcall_data, sid_val));
+       LASSERTF((int)sizeof(((struct rsi_downcall_data *)0)->sid_val) == 0, "found %lld\n",
+                (long long)(int)sizeof(((struct rsi_downcall_data *)0)->sid_val));
+
        /* Checks for struct llog_gen */
        LASSERTF((int)sizeof(struct llog_gen) == 16, "found %lld\n",
                 (long long)(int)sizeof(struct llog_gen));