# The following scripts are Red Hat specific
%if %{with servers}
echo '%{_sysconfdir}/sysconfig/lustre' >>lustre.files
+echo '%{_sysconfdir}/sysconfig/lsvcgss' >>lustre.files
echo '%{_sysconfdir}/init.d/lustre' >>lustre.files
%endif
echo '%{_sysconfdir}/init.d/lnet' >>lustre.files
#
EXTRA_DIST = lustre.dtd slapd-lustre.conf lustre2ldif.xsl top.ldif \
- 99-lustre.rules lustre ldev.conf ko2iblnd.conf
+ 99-lustre.rules lustre ldev.conf ko2iblnd.conf lsvcgss
ldapconfdir = $(sysconfdir)/openldap
if UTILS
if RHEL
if SERVER
sysconfigdir = $(sysconfdir)/sysconfig
-sysconfig_DATA = lustre
+sysconfig_DATA = lustre lsvcgss
endif
endif
--- /dev/null
+# Optional arguments passed to lsvcgssd.
+LSVCGSSDARGS=''
#define _LUSTRE_NODEMAP_H
#include <lustre/lustre_idl.h>
+#include <lustre/lustre_user.h>
#define LUSTRE_NODEMAP_NAME "nodemap"
enum nodemap_tree_type tree_type, __u32 id);
ssize_t nodemap_map_acl(struct lu_nodemap *nodemap, void *buf, size_t size,
enum nodemap_tree_type tree_type);
+#ifdef HAVE_SERVER_SUPPORT
void nodemap_test_nid(lnet_nid_t nid, char *name_buf, size_t name_len);
+#else
+#define nodemap_test_nid(nid, name_buf, name_len) do {} while(0)
+#endif
__u32 nodemap_test_id(lnet_nid_t nid, enum nodemap_id_type idtype,
__u32 client_id);
struct nm_config_file *nm_config_file_register(const struct lu_env *env,
ptlrpc_gss-objs := sec_gss.o gss_bulk.o gss_cli_upcall.o gss_svc_upcall.o \
gss_rawobj.o lproc_gss.o \
gss_generic_token.o gss_mech_switch.o gss_krb5_mech.o \
- gss_null_mech.o gss_sk_mech.o
+ gss_null_mech.o gss_sk_mech.o gss_crypto.o
@GSS_KEYRING_TRUE@ptlrpc_gss-objs += gss_keyring.o
@GSS_PIPEFS_TRUE@ptlrpc_gss-objs += gss_pipefs.o
--- /dev/null
+/*
+ * Modifications for Lustre
+ *
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Copyright (c) 2011, 2014, Intel Corporation.
+ *
+ * Author: Eric Mei <ericm@clusterfs.com>
+ */
+
+/*
+ * linux/net/sunrpc/gss_krb5_mech.c
+ * linux/net/sunrpc/gss_krb5_crypto.c
+ * linux/net/sunrpc/gss_krb5_seal.c
+ * linux/net/sunrpc/gss_krb5_seqnum.c
+ * linux/net/sunrpc/gss_krb5_unseal.c
+ *
+ * Copyright (c) 2001 The Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Andy Adamson <andros@umich.edu>
+ * J. Bruce Fields <bfields@umich.edu>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define DEBUG_SUBSYSTEM S_SEC
+
+#include <libcfs/linux/linux-crypto.h>
+#include <obd.h>
+#include <obd_support.h>
+
+#include "gss_internal.h"
+#include "gss_crypto.h"
+
+int gss_keyblock_init(struct gss_keyblock *kb, char *alg_name,
+ const int alg_mode)
+{
+ int rc;
+
+ kb->kb_tfm = crypto_alloc_blkcipher(alg_name, alg_mode, 0);
+ if (IS_ERR(kb->kb_tfm)) {
+ rc = PTR_ERR(kb->kb_tfm);
+ kb->kb_tfm = NULL;
+ CERROR("failed to alloc tfm: %s, mode %d: rc = %d\n", alg_name,
+ alg_mode, rc);
+ return rc;
+ }
+
+ rc = crypto_blkcipher_setkey(kb->kb_tfm, kb->kb_key.data,
+ kb->kb_key.len);
+ if (rc) {
+ CERROR("failed to set %s key, len %d, rc = %d\n", alg_name,
+ kb->kb_key.len, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+void gss_keyblock_free(struct gss_keyblock *kb)
+{
+ rawobj_free(&kb->kb_key);
+ if (kb->kb_tfm)
+ crypto_free_blkcipher(kb->kb_tfm);
+}
+
+int gss_keyblock_dup(struct gss_keyblock *new, struct gss_keyblock *kb)
+{
+ return rawobj_dup(&new->kb_key, &kb->kb_key);
+}
+
+int gss_get_bytes(char **ptr, const char *end, void *res, size_t len)
+{
+ char *p, *q;
+ p = *ptr;
+ q = p + len;
+ if (q > end || q < p)
+ return -EINVAL;
+ memcpy(res, p, len);
+ *ptr = q;
+ return 0;
+}
+
+int gss_get_rawobj(char **ptr, const char *end, rawobj_t *res)
+{
+ char *p, *q;
+ __u32 len;
+
+ p = *ptr;
+ if (gss_get_bytes(&p, end, &len, sizeof(len)))
+ return -EINVAL;
+
+ q = p + len;
+ if (q > end || q < p)
+ return -EINVAL;
+
+ /* Support empty objects */
+ if (len != 0) {
+ OBD_ALLOC_LARGE(res->data, len);
+ if (!res->data)
+ return -ENOMEM;
+ } else {
+ res->len = len;
+ res->data = NULL;
+ return 0;
+ }
+
+ res->len = len;
+ memcpy(res->data, p, len);
+ *ptr = q;
+ return 0;
+}
+
+int gss_get_keyblock(char **ptr, const char *end,
+ struct gss_keyblock *kb, __u32 keysize)
+{
+ char *buf;
+ int rc;
+
+ OBD_ALLOC_LARGE(buf, keysize);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ rc = gss_get_bytes(ptr, end, buf, keysize);
+ if (rc) {
+ OBD_FREE_LARGE(buf, keysize);
+ return rc;
+ }
+
+ kb->kb_key.len = keysize;
+ kb->kb_key.data = buf;
+ return 0;
+}
+
+/*
+ * Should be used for buffers allocated with k/vmalloc().
+ *
+ * Dispose of @sgt with gss_teardown_sgtable().
+ *
+ * @prealloc_sg is to avoid memory allocation inside sg_alloc_table()
+ * in cases where a single sg is sufficient. No attempt to reduce the
+ * number of sgs by squeezing physically contiguous pages together is
+ * made though, for simplicity.
+ *
+ * This function is copied from the ceph filesystem code.
+ */
+int gss_setup_sgtable(struct sg_table *sgt, struct scatterlist *prealloc_sg,
+ const void *buf, unsigned int buf_len)
+{
+ struct scatterlist *sg;
+ const bool is_vmalloc = is_vmalloc_addr(buf);
+ unsigned int off = offset_in_page(buf);
+ unsigned int chunk_cnt = 1;
+ unsigned int chunk_len = PAGE_ALIGN(off + buf_len);
+ int i;
+ int rc;
+
+ if (buf_len == 0) {
+ memset(sgt, 0, sizeof(*sgt));
+ return -EINVAL;
+ }
+
+ if (is_vmalloc) {
+ chunk_cnt = chunk_len >> PAGE_SHIFT;
+ chunk_len = PAGE_SIZE;
+ }
+
+ if (chunk_cnt > 1) {
+ rc = sg_alloc_table(sgt, chunk_cnt, GFP_NOFS);
+ if (rc)
+ return rc;
+ } else {
+ WARN_ON_ONCE(chunk_cnt != 1);
+ sg_init_table(prealloc_sg, 1);
+ sgt->sgl = prealloc_sg;
+ sgt->nents = sgt->orig_nents = 1;
+ }
+
+ for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) {
+ struct page *page;
+ unsigned int len = min(chunk_len - off, buf_len);
+
+ if (is_vmalloc)
+ page = vmalloc_to_page(buf);
+ else
+ page = virt_to_page(buf);
+
+ sg_set_page(sg, page, len, off);
+
+ off = 0;
+ buf += len;
+ buf_len -= len;
+ }
+
+ WARN_ON_ONCE(buf_len != 0);
+
+ return 0;
+}
+
+void gss_teardown_sgtable(struct sg_table *sgt)
+{
+ if (sgt->orig_nents > 1)
+ sg_free_table(sgt);
+}
+
+int gss_crypt_generic(struct crypto_blkcipher *tfm, int decrypt, void *iv,
+ void *in, void *out, int length)
+{
+ struct blkcipher_desc desc;
+ struct scatterlist sg;
+ struct sg_table sg_out;
+ __u8 local_iv[16] = {0};
+ __u32 ret = -EINVAL;
+
+ LASSERT(tfm);
+ desc.tfm = tfm;
+ desc.info = local_iv;
+ desc.flags = 0;
+
+ if (length % crypto_blkcipher_blocksize(tfm) != 0) {
+ CERROR("output length %d mismatch blocksize %d\n",
+ length, crypto_blkcipher_blocksize(tfm));
+ goto out;
+ }
+
+ if (crypto_blkcipher_ivsize(tfm) > ARRAY_SIZE(local_iv)) {
+ CERROR("iv size too large %d\n", crypto_blkcipher_ivsize(tfm));
+ goto out;
+ }
+
+ if (iv)
+ memcpy(local_iv, iv, crypto_blkcipher_ivsize(tfm));
+
+ memcpy(out, in, length);
+
+ ret = gss_setup_sgtable(&sg_out, &sg, out, length);
+ if (ret != 0)
+ goto out;
+
+ if (decrypt)
+ ret = crypto_blkcipher_decrypt_iv(&desc, &sg, &sg, length);
+ else
+ ret = crypto_blkcipher_encrypt_iv(&desc, &sg, &sg, length);
+
+ gss_teardown_sgtable(&sg_out);
+out:
+ return ret;
+}
+
+int gss_digest_hmac(struct crypto_hash *tfm,
+ rawobj_t *key,
+ rawobj_t *hdr,
+ int msgcnt, rawobj_t *msgs,
+ int iovcnt, lnet_kiov_t *iovs,
+ rawobj_t *cksum)
+{
+ struct hash_desc desc = {
+ .tfm = tfm,
+ .flags = 0,
+ };
+ struct scatterlist sg[1];
+ struct sg_table sgt;
+ int i;
+ int rc;
+
+ rc = crypto_hash_setkey(tfm, key->data, key->len);
+ if (rc)
+ return rc;
+
+ rc = crypto_hash_init(&desc);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < msgcnt; i++) {
+ if (msgs[i].len == 0)
+ continue;
+
+ rc = gss_setup_sgtable(&sgt, sg, msgs[i].data, msgs[i].len);
+ if (rc != 0)
+ return rc;
+ rc = crypto_hash_update(&desc, sg, msgs[i].len);
+ if (rc)
+ return rc;
+
+ gss_teardown_sgtable(&sgt);
+ }
+
+ for (i = 0; i < iovcnt; i++) {
+ if (iovs[i].kiov_len == 0)
+ continue;
+
+ sg_init_table(sg, 1);
+ sg_set_page(&sg[0], iovs[i].kiov_page, iovs[i].kiov_len,
+ iovs[i].kiov_offset);
+ rc = crypto_hash_update(&desc, sg, iovs[i].kiov_len);
+ if (rc)
+ return rc;
+ }
+
+ if (hdr) {
+ rc = gss_setup_sgtable(&sgt, sg, (char *)hdr, sizeof(*hdr));
+ if (rc != 0)
+ return rc;
+ rc = crypto_hash_update(&desc, sg, sizeof(hdr->len));
+ if (rc)
+ return rc;
+
+ gss_teardown_sgtable(&sgt);
+ }
+
+ return crypto_hash_final(&desc, cksum->data);
+}
+
+int gss_digest_norm(struct crypto_hash *tfm,
+ struct gss_keyblock *kb,
+ rawobj_t *hdr,
+ int msgcnt, rawobj_t *msgs,
+ int iovcnt, lnet_kiov_t *iovs,
+ rawobj_t *cksum)
+{
+ struct hash_desc desc;
+ struct scatterlist sg[1];
+ struct sg_table sgt;
+ int i;
+ int rc;
+
+ LASSERT(kb->kb_tfm);
+ desc.tfm = tfm;
+ desc.flags = 0;
+
+ rc = crypto_hash_init(&desc);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < msgcnt; i++) {
+ if (msgs[i].len == 0)
+ continue;
+
+ rc = gss_setup_sgtable(&sgt, sg, msgs[i].data, msgs[i].len);
+ if (rc != 0)
+ return rc;
+
+ rc = crypto_hash_update(&desc, sg, msgs[i].len);
+ if (rc)
+ return rc;
+
+ gss_teardown_sgtable(&sgt);
+ }
+
+ for (i = 0; i < iovcnt; i++) {
+ if (iovs[i].kiov_len == 0)
+ continue;
+
+ sg_init_table(sg, 1);
+ sg_set_page(&sg[0], iovs[i].kiov_page, iovs[i].kiov_len,
+ iovs[i].kiov_offset);
+ rc = crypto_hash_update(&desc, sg, iovs[i].kiov_len);
+ if (rc)
+ return rc;
+ }
+
+ if (hdr) {
+ rc = gss_setup_sgtable(&sgt, sg, (char *)hdr, sizeof(*hdr));
+ if (rc != 0)
+ return rc;
+
+ rc = crypto_hash_update(&desc, sg, sizeof(*hdr));
+ if (rc)
+ return rc;
+
+ gss_teardown_sgtable(&sgt);
+ }
+
+ rc = crypto_hash_final(&desc, cksum->data);
+ if (rc)
+ return rc;
+
+ return gss_crypt_generic(kb->kb_tfm, 0, NULL, cksum->data,
+ cksum->data, cksum->len);
+}
+
+int gss_add_padding(rawobj_t *msg, int msg_buflen, int blocksize)
+{
+ int padding;
+
+ padding = (blocksize - (msg->len & (blocksize - 1))) &
+ (blocksize - 1);
+ if (!padding)
+ return 0;
+
+ if (msg->len + padding > msg_buflen) {
+ CERROR("bufsize %u too small: datalen %u, padding %u\n",
+ msg_buflen, msg->len, padding);
+ return -EINVAL;
+ }
+
+ memset(msg->data + msg->len, padding, padding);
+ msg->len += padding;
+ return 0;
+}
+
+int gss_crypt_rawobjs(struct crypto_blkcipher *tfm,
+ int use_internal_iv,
+ int inobj_cnt,
+ rawobj_t *inobjs,
+ rawobj_t *outobj,
+ int enc)
+{
+ struct blkcipher_desc desc;
+ struct scatterlist src;
+ struct scatterlist dst;
+ struct sg_table sg_dst;
+ struct sg_table sg_src;
+ __u8 local_iv[16] = {0}, *buf;
+ __u32 datalen = 0;
+ int i, rc;
+ ENTRY;
+
+ buf = outobj->data;
+ desc.tfm = tfm;
+ desc.info = local_iv;
+ desc.flags = 0;
+
+ for (i = 0; i < inobj_cnt; i++) {
+ LASSERT(buf + inobjs[i].len <= outobj->data + outobj->len);
+
+ rc = gss_setup_sgtable(&sg_src, &src, inobjs[i].data,
+ inobjs[i].len);
+ if (rc != 0)
+ RETURN(rc);
+
+ rc = gss_setup_sgtable(&sg_dst, &dst, buf,
+ outobj->len - datalen);
+ if (rc != 0) {
+ gss_teardown_sgtable(&sg_src);
+ RETURN(rc);
+ }
+
+ if (use_internal_iv) {
+ if (enc)
+ rc = crypto_blkcipher_encrypt(&desc, &dst, &src,
+ src.length);
+ else
+ rc = crypto_blkcipher_decrypt(&desc, &dst, &src,
+ src.length);
+ } else {
+ if (enc)
+ rc = crypto_blkcipher_encrypt_iv(&desc, &dst,
+ &src,
+ src.length);
+ else
+ rc = crypto_blkcipher_decrypt_iv(&desc, &dst,
+ &src,
+ src.length);
+ }
+
+ gss_teardown_sgtable(&sg_src);
+ gss_teardown_sgtable(&sg_dst);
+
+ if (rc) {
+ CERROR("encrypt error %d\n", rc);
+ RETURN(rc);
+ }
+
+ datalen += inobjs[i].len;
+ buf += inobjs[i].len;
+ }
+
+ outobj->len = datalen;
+ RETURN(0);
+}
--- /dev/null
+/*
+ * Modifications for Lustre
+ *
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Author: Eric Mei <ericm@clusterfs.com>
+ */
+
+/*
+ * linux/include/linux/sunrpc/gss_krb5_types.h
+ *
+ * Adapted from MIT Kerberos 5-1.2.1 lib/include/krb5.h,
+ * lib/gssapi/krb5/gssapiP_krb5.h, and others
+ *
+ * Copyright (c) 2000 The Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Andy Adamson <andros@umich.edu>
+ * Bruce Fields <bfields@umich.edu>
+ */
+
+/*
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+#ifndef PTLRPC_GSS_UTILS_H
+#define PTLRPC_GSS_UTILS_H
+
+#include "gss_internal.h"
+
+struct gss_keyblock {
+ rawobj_t kb_key;
+ struct crypto_blkcipher *kb_tfm;
+};
+
+int gss_keyblock_init(struct gss_keyblock *kb, char *alg_name,
+ const int alg_mode);
+void gss_keyblock_free(struct gss_keyblock *kb);
+int gss_keyblock_dup(struct gss_keyblock *new, struct gss_keyblock *kb);
+int gss_get_bytes(char **ptr, const char *end, void *res, size_t len);
+int gss_get_rawobj(char **ptr, const char *end, rawobj_t *res);
+int gss_get_keyblock(char **ptr, const char *end, struct gss_keyblock *kb,
+ __u32 keysize);
+int gss_setup_sgtable(struct sg_table *sgt, struct scatterlist *prealloc_sg,
+ const void *buf, unsigned int buf_len);
+void gss_teardown_sgtable(struct sg_table *sgt);
+int gss_crypt_generic(struct crypto_blkcipher *tfm, int decrypt, void *iv,
+ void *in, void *out, int length);
+int gss_digest_hmac(struct crypto_hash *tfm, rawobj_t *key, rawobj_t *hdr,
+ int msgcnt, rawobj_t *msgs, int iovcnt, lnet_kiov_t *iovs,
+ rawobj_t *cksum);
+int gss_digest_norm(struct crypto_hash *tfm, struct gss_keyblock *kb,
+ rawobj_t *hdr, int msgcnt, rawobj_t *msgs, int iovcnt,
+ lnet_kiov_t *iovs, rawobj_t *cksum);
+int gss_add_padding(rawobj_t *msg, int msg_buflen, int blocksize);
+int gss_crypt_rawobjs(struct crypto_blkcipher *tfm, int use_internal_iv,
+ int inobj_cnt, rawobj_t *inobjs, rawobj_t *outobj,
+ int enc);
+
+#endif /* PTLRPC_GSS_UTILS_H */
/*
* XXX make it visible of kernel and lgssd/lsvcgssd
*/
-#define GSSD_INTERFACE_VERSION (1)
+enum {
+ GSSD_INTERFACE_VERSION_V1 = 1,
+ GSSD_INTERFACE_VERSION_V2 = 2,
+ GSSD_INTERFACE_VERSION = GSSD_INTERFACE_VERSION_V2,
+};
#define PTLRPC_GSS_VERSION (1)
char desc[24];
char *coinfo;
int coinfo_size;
- char *co_flags = "";
+ const char *sec_part_flags = "";
+ char svc_flag = '\0';
ENTRY;
LASSERT(imp != NULL);
/* update reverse handle for root user */
sec2gsec(sec)->gs_rvs_hdl = gss_get_next_ctx_index();
- switch (sec->ps_part) {
- case LUSTRE_SP_MDT:
- co_flags = "m";
- break;
- case LUSTRE_SP_OST:
- co_flags = "o";
- break;
- case LUSTRE_SP_MGC:
- co_flags = "rmo";
- break;
- case LUSTRE_SP_CLI:
- co_flags = "r";
- break;
- case LUSTRE_SP_MGS:
- default:
- LBUG();
+ switch (sec->ps_part) {
+ case LUSTRE_SP_MDT:
+ sec_part_flags = "m";
+ break;
+ case LUSTRE_SP_OST:
+ sec_part_flags = "o";
+ break;
+ case LUSTRE_SP_MGC:
+ sec_part_flags = "rmo";
+ break;
+ case LUSTRE_SP_CLI:
+ sec_part_flags = "r";
+ break;
+ case LUSTRE_SP_MGS:
+ default:
+ LBUG();
}
- }
- /* in case of setuid, key will be constructed as owner of fsuid/fsgid,
- * but we do authentication based on real uid/gid. the key permission
- * bits will be exactly as POS_ALL, so only processes who subscribed
- * this key could have the access, although the quota might be counted
- * on others (fsuid/fsgid).
- *
- * keyring will use fsuid/fsgid as upcall parameters, so we have to
- * encode real uid/gid into callout info.
- */
+ switch (SPTLRPC_FLVR_SVC(sec->ps_flvr.sf_rpc)) {
+ case SPTLRPC_SVC_NULL:
+ svc_flag = 'n';
+ break;
+ case SPTLRPC_SVC_AUTH:
+ svc_flag = 'a';
+ break;
+ case SPTLRPC_SVC_INTG:
+ svc_flag = 'i';
+ break;
+ case SPTLRPC_SVC_PRIV:
+ svc_flag = 'p';
+ break;
+ default:
+ LBUG();
+ }
+ }
+
+ /* in case of setuid, key will be constructed as owner of fsuid/fsgid,
+ * but we do authentication based on real uid/gid. the key permission
+ * bits will be exactly as POS_ALL, so only processes who subscribed
+ * this key could have the access, although the quota might be counted
+ * on others (fsuid/fsgid).
+ *
+ * keyring will use fsuid/fsgid as upcall parameters, so we have to
+ * encode real uid/gid into callout info.
+ */
/* But first we need to make sure the obd type is supported */
if (strcmp(imp->imp_obd->obd_type->typ_name, LUSTRE_MDC_NAME) &&
strcmp(imp->imp_obd->obd_type->typ_name, LUSTRE_LWP_NAME) &&
strcmp(imp->imp_obd->obd_type->typ_name, LUSTRE_OSP_NAME)) {
CERROR("obd %s is not a supported device\n",
- imp->imp_obd->obd_name);
+ imp->imp_obd->obd_name);
GOTO(out, ctx = NULL);
}
- construct_key_desc(desc, sizeof(desc), sec, vcred->vc_uid);
+ construct_key_desc(desc, sizeof(desc), sec, vcred->vc_uid);
- /* callout info format:
- * secid:mech:uid:gid:flags:svc_type:peer_nid:target_uuid
- */
+ /* callout info format:
+ * secid:mech:uid:gid:sec_flags:svc_flag:svc_type:peer_nid:target_uuid
+ */
coinfo_size = sizeof(struct obd_uuid) + MAX_OBD_NAME + 64;
OBD_ALLOC(coinfo, coinfo_size);
if (coinfo == NULL)
goto out;
- snprintf(coinfo, coinfo_size, "%d:%s:%u:%u:%s:%d:"LPX64":%s:"LPX64,
+ snprintf(coinfo, coinfo_size, "%d:%s:%u:%u:%s:%c:%d:"LPX64":%s:"LPX64,
sec->ps_id, sec2gsec(sec)->gs_mech->gm_name,
vcred->vc_uid, vcred->vc_gid,
- co_flags, import_to_gss_svc(imp),
+ sec_part_flags, svc_flag, import_to_gss_svc(imp),
imp->imp_connection->c_peer.nid, imp->imp_obd->obd_name,
imp->imp_connection->c_self);
snprintf(mech, sizeof(mech), "N/A");
mech[sizeof(mech) - 1] = '\0';
- seq_printf(seq, "%p: uid %u, ref %d, expire %ld(%+ld), fl %s, "
+ seq_printf(seq, "%p: uid %u, ref %d, expire %lu(%+ld), fl %s, "
"seq %d, win %u, key %08x(ref %d), "
"hdl "LPX64":"LPX64", mech: %s\n",
ctx, ctx->cc_vcred.vc_uid,
goto out;
}
- if (gctx->gc_win == 0) {
- __u32 nego_rpc_err, nego_gss_err;
+ if (gctx->gc_win == 0) {
+ __u32 nego_rpc_err, nego_gss_err;
- rc = buffer_extract_bytes(&data, &datalen32, &nego_rpc_err,
- sizeof(nego_rpc_err));
- if (rc) {
- CERROR("failed to extrace rpc rc\n");
- goto out;
- }
+ rc = buffer_extract_bytes(&data, &datalen32, &nego_rpc_err,
+ sizeof(nego_rpc_err));
+ if (rc) {
+ CERROR("cannot extract RPC: rc = %d\n", rc);
+ goto out;
+ }
- rc = buffer_extract_bytes(&data, &datalen32, &nego_gss_err,
- sizeof(nego_gss_err));
- if (rc) {
- CERROR("failed to extrace gss rc\n");
- goto out;
- }
+ rc = buffer_extract_bytes(&data, &datalen32, &nego_gss_err,
+ sizeof(nego_gss_err));
+ if (rc) {
+ CERROR("failed to extract gss rc = %d\n", rc);
+ goto out;
+ }
- CERROR("negotiation: rpc err %d, gss err %x\n",
- nego_rpc_err, nego_gss_err);
+ CERROR("negotiation: rpc err %d, gss err %x\n",
+ nego_rpc_err, nego_gss_err);
- rc = nego_rpc_err ? nego_rpc_err : -EACCES;
- } else {
- rc = rawobj_extract_local_alloc(&gctx->gc_handle,
- (__u32 **) &data, &datalen32);
- if (rc) {
- CERROR("failed extract handle\n");
- goto out;
- }
+ rc = nego_rpc_err ? nego_rpc_err : -EACCES;
+ } else {
+ rc = rawobj_extract_local_alloc(&gctx->gc_handle,
+ (__u32 **) &data, &datalen32);
+ if (rc) {
+ CERROR("failed extract handle\n");
+ goto out;
+ }
- rc = rawobj_extract_local(&tmpobj, (__u32 **) &data,&datalen32);
- if (rc) {
- CERROR("failed extract mech\n");
- goto out;
- }
+ rc = rawobj_extract_local(&tmpobj, (__u32 **) &data,&datalen32);
+ if (rc) {
+ CERROR("failed extract mech\n");
+ goto out;
+ }
- rc = lgss_import_sec_context(&tmpobj,
- sec2gsec(ctx->cc_sec)->gs_mech,
- &gctx->gc_mechctx);
- if (rc != GSS_S_COMPLETE)
- CERROR("failed import context\n");
- else
- rc = 0;
- }
+ rc = lgss_import_sec_context(&tmpobj,
+ sec2gsec(ctx->cc_sec)->gs_mech,
+ &gctx->gc_mechctx);
+ if (rc != GSS_S_COMPLETE)
+ CERROR("failed import context\n");
+ else
+ rc = 0;
+ }
out:
/* we don't care what current status of this ctx, even someone else
* is operating on the ctx at the same time. we just add up our own
#ifndef PTLRPC_GSS_KRB5_H
#define PTLRPC_GSS_KRB5_H
+#include "gss_crypto.h"
+
/*
* RFC 4142
*/
__u8 kh_cksum[0]; /* checksum */
};
-struct krb5_keyblock {
- rawobj_t kb_key;
- struct crypto_blkcipher *kb_tfm;
-};
-
struct krb5_ctx {
- unsigned int kc_initiate:1,
- kc_cfx:1,
- kc_seed_init:1,
- kc_have_acceptor_subkey:1;
- __s32 kc_endtime;
- __u8 kc_seed[16];
- __u64 kc_seq_send;
- __u64 kc_seq_recv;
- __u32 kc_enctype;
- struct krb5_keyblock kc_keye; /* encryption */
- struct krb5_keyblock kc_keyi; /* integrity */
- struct krb5_keyblock kc_keyc; /* checksum */
- rawobj_t kc_mech_used;
+ unsigned int kc_initiate:1,
+ kc_cfx:1,
+ kc_seed_init:1,
+ kc_have_acceptor_subkey:1;
+ __s32 kc_endtime;
+ __u8 kc_seed[16];
+ __u64 kc_seq_send;
+ __u64 kc_seq_recv;
+ __u32 kc_enctype;
+ struct gss_keyblock kc_keye; /* encryption */
+ struct gss_keyblock kc_keyi; /* integrity */
+ struct gss_keyblock kc_keyc; /* checksum */
+ rawobj_t kc_mech_used;
};
enum sgn_alg {
#include "gss_api.h"
#include "gss_asn1.h"
#include "gss_krb5.h"
+#include "gss_crypto.h"
static spinlock_t krb5_seq_lock;
}
static
-int keyblock_init(struct krb5_keyblock *kb, char *alg_name, int alg_mode)
-{
- kb->kb_tfm = crypto_alloc_blkcipher(alg_name, alg_mode, 0);
- if (IS_ERR(kb->kb_tfm)) {
- CERROR("failed to alloc tfm: %s, mode %d\n",
- alg_name, alg_mode);
- return -1;
- }
-
- if (crypto_blkcipher_setkey(kb->kb_tfm, kb->kb_key.data, kb->kb_key.len)) {
- CERROR("failed to set %s key, len %d\n",
- alg_name, kb->kb_key.len);
- return -1;
- }
-
- return 0;
-}
-
-static
int krb5_init_keys(struct krb5_ctx *kctx)
{
struct krb5_enctype *ke;
ke = &enctypes[kctx->kc_enctype];
- /* tfm arc4 is stateful, user should alloc-use-free by his own */
- if (kctx->kc_enctype != ENCTYPE_ARCFOUR_HMAC &&
- keyblock_init(&kctx->kc_keye, ke->ke_enc_name, ke->ke_enc_mode))
- return -1;
-
- /* tfm hmac is stateful, user should alloc-use-free by his own */
- if (ke->ke_hash_hmac == 0 &&
- keyblock_init(&kctx->kc_keyi, ke->ke_enc_name, ke->ke_enc_mode))
- return -1;
- if (ke->ke_hash_hmac == 0 &&
- keyblock_init(&kctx->kc_keyc, ke->ke_enc_name, ke->ke_enc_mode))
- return -1;
-
- return 0;
-}
-
-static
-void keyblock_free(struct krb5_keyblock *kb)
-{
- rawobj_free(&kb->kb_key);
- if (kb->kb_tfm)
- crypto_free_blkcipher(kb->kb_tfm);
-}
-
-static
-int keyblock_dup(struct krb5_keyblock *new, struct krb5_keyblock *kb)
-{
- return rawobj_dup(&new->kb_key, &kb->kb_key);
-}
-
-static
-int get_bytes(char **ptr, const char *end, void *res, int len)
-{
- char *p, *q;
- p = *ptr;
- q = p + len;
- if (q > end || q < p)
- return -1;
- memcpy(res, p, len);
- *ptr = q;
- return 0;
-}
-
-static
-int get_rawobj(char **ptr, const char *end, rawobj_t *res)
-{
- char *p, *q;
- __u32 len;
-
- p = *ptr;
- if (get_bytes(&p, end, &len, sizeof(len)))
- return -1;
-
- q = p + len;
- if (q > end || q < p)
- return -1;
-
- OBD_ALLOC_LARGE(res->data, len);
- if (!res->data)
- return -1;
-
- res->len = len;
- memcpy(res->data, p, len);
- *ptr = q;
- return 0;
-}
-
-static
-int get_keyblock(char **ptr, const char *end,
- struct krb5_keyblock *kb, __u32 keysize)
-{
- char *buf;
-
- OBD_ALLOC_LARGE(buf, keysize);
- if (buf == NULL)
- return -1;
+ /* tfm arc4 is stateful, user should alloc-use-free by his own */
+ if (kctx->kc_enctype != ENCTYPE_ARCFOUR_HMAC &&
+ gss_keyblock_init(&kctx->kc_keye, ke->ke_enc_name, ke->ke_enc_mode))
+ return -1;
- if (get_bytes(ptr, end, buf, keysize)) {
- OBD_FREE_LARGE(buf, keysize);
- return -1;
- }
+ /* tfm hmac is stateful, user should alloc-use-free by his own */
+ if (ke->ke_hash_hmac == 0 &&
+ gss_keyblock_init(&kctx->kc_keyi, ke->ke_enc_name, ke->ke_enc_mode))
+ return -1;
+ if (ke->ke_hash_hmac == 0 &&
+ gss_keyblock_init(&kctx->kc_keyc, ke->ke_enc_name, ke->ke_enc_mode))
+ return -1;
- kb->kb_key.len = keysize;
- kb->kb_key.data = buf;
return 0;
}
static
void delete_context_kerberos(struct krb5_ctx *kctx)
{
- rawobj_free(&kctx->kc_mech_used);
+ rawobj_free(&kctx->kc_mech_used);
- keyblock_free(&kctx->kc_keye);
- keyblock_free(&kctx->kc_keyi);
- keyblock_free(&kctx->kc_keyc);
+ gss_keyblock_free(&kctx->kc_keye);
+ gss_keyblock_free(&kctx->kc_keyi);
+ gss_keyblock_free(&kctx->kc_keyc);
}
static
__u32 import_context_rfc1964(struct krb5_ctx *kctx, char *p, char *end)
{
- unsigned int tmp_uint, keysize;
+ unsigned int tmp_uint, keysize;
- /* seed_init flag */
- if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
- goto out_err;
- kctx->kc_seed_init = (tmp_uint != 0);
+ /* seed_init flag */
+ if (gss_get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
+ goto out_err;
+ kctx->kc_seed_init = (tmp_uint != 0);
- /* seed */
- if (get_bytes(&p, end, kctx->kc_seed, sizeof(kctx->kc_seed)))
- goto out_err;
+ /* seed */
+ if (gss_get_bytes(&p, end, kctx->kc_seed, sizeof(kctx->kc_seed)))
+ goto out_err;
- /* sign/seal algorithm, not really used now */
- if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)) ||
- get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
- goto out_err;
+ /* sign/seal algorithm, not really used now */
+ if (gss_get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)) ||
+ gss_get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
+ goto out_err;
- /* end time */
- if (get_bytes(&p, end, &kctx->kc_endtime, sizeof(kctx->kc_endtime)))
- goto out_err;
+ /* end time */
+ if (gss_get_bytes(&p, end, &kctx->kc_endtime, sizeof(kctx->kc_endtime)))
+ goto out_err;
- /* seq send */
- if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
- goto out_err;
- kctx->kc_seq_send = tmp_uint;
+ /* seq send */
+ if (gss_get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
+ goto out_err;
+ kctx->kc_seq_send = tmp_uint;
- /* mech oid */
- if (get_rawobj(&p, end, &kctx->kc_mech_used))
- goto out_err;
+ /* mech oid */
+ if (gss_get_rawobj(&p, end, &kctx->kc_mech_used))
+ goto out_err;
- /* old style enc/seq keys in format:
- * - enctype (u32)
- * - keysize (u32)
- * - keydata
- * we decompose them to fit into the new context
- */
+ /* old style enc/seq keys in format:
+ * - enctype (u32)
+ * - keysize (u32)
+ * - keydata
+ * we decompose them to fit into the new context
+ */
- /* enc key */
- if (get_bytes(&p, end, &kctx->kc_enctype, sizeof(kctx->kc_enctype)))
- goto out_err;
+ /* enc key */
+ if (gss_get_bytes(&p, end, &kctx->kc_enctype, sizeof(kctx->kc_enctype)))
+ goto out_err;
- if (get_bytes(&p, end, &keysize, sizeof(keysize)))
- goto out_err;
+ if (gss_get_bytes(&p, end, &keysize, sizeof(keysize)))
+ goto out_err;
- if (get_keyblock(&p, end, &kctx->kc_keye, keysize))
- goto out_err;
+ if (gss_get_keyblock(&p, end, &kctx->kc_keye, keysize))
+ goto out_err;
- /* seq key */
- if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)) ||
- tmp_uint != kctx->kc_enctype)
- goto out_err;
+ /* seq key */
+ if (gss_get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)) ||
+ tmp_uint != kctx->kc_enctype)
+ goto out_err;
- if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)) ||
- tmp_uint != keysize)
- goto out_err;
+ if (gss_get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)) ||
+ tmp_uint != keysize)
+ goto out_err;
- if (get_keyblock(&p, end, &kctx->kc_keyc, keysize))
- goto out_err;
+ if (gss_get_keyblock(&p, end, &kctx->kc_keyc, keysize))
+ goto out_err;
- /* old style fallback */
- if (keyblock_dup(&kctx->kc_keyi, &kctx->kc_keyc))
- goto out_err;
+ /* old style fallback */
+ if (gss_keyblock_dup(&kctx->kc_keyi, &kctx->kc_keyc))
+ goto out_err;
- if (p != end)
- goto out_err;
+ if (p != end)
+ goto out_err;
CDEBUG(D_SEC, "successfully imported rfc1964 context\n");
- return 0;
+ return 0;
out_err:
- return GSS_S_FAILURE;
+ return GSS_S_FAILURE;
}
/* Flags for version 2 context flags */
static
__u32 import_context_rfc4121(struct krb5_ctx *kctx, char *p, char *end)
{
- unsigned int tmp_uint, keysize;
-
- /* end time */
- if (get_bytes(&p, end, &kctx->kc_endtime, sizeof(kctx->kc_endtime)))
- goto out_err;
-
- /* flags */
- if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
- goto out_err;
-
- if (tmp_uint & KRB5_CTX_FLAG_INITIATOR)
- kctx->kc_initiate = 1;
- if (tmp_uint & KRB5_CTX_FLAG_CFX)
- kctx->kc_cfx = 1;
- if (tmp_uint & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY)
- kctx->kc_have_acceptor_subkey = 1;
-
- /* seq send */
- if (get_bytes(&p, end, &kctx->kc_seq_send, sizeof(kctx->kc_seq_send)))
- goto out_err;
-
- /* enctype */
- if (get_bytes(&p, end, &kctx->kc_enctype, sizeof(kctx->kc_enctype)))
- goto out_err;
-
- /* size of each key */
- if (get_bytes(&p, end, &keysize, sizeof(keysize)))
- goto out_err;
-
- /* number of keys - should always be 3 */
- if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
- goto out_err;
-
- if (tmp_uint != 3) {
- CERROR("Invalid number of keys: %u\n", tmp_uint);
- goto out_err;
- }
+ unsigned int tmp_uint, keysize;
+
+ /* end time */
+ if (gss_get_bytes(&p, end, &kctx->kc_endtime, sizeof(kctx->kc_endtime)))
+ goto out_err;
+
+ /* flags */
+ if (gss_get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
+ goto out_err;
+
+ if (tmp_uint & KRB5_CTX_FLAG_INITIATOR)
+ kctx->kc_initiate = 1;
+ if (tmp_uint & KRB5_CTX_FLAG_CFX)
+ kctx->kc_cfx = 1;
+ if (tmp_uint & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY)
+ kctx->kc_have_acceptor_subkey = 1;
+
+ /* seq send */
+ if (gss_get_bytes(&p, end, &kctx->kc_seq_send,
+ sizeof(kctx->kc_seq_send)))
+ goto out_err;
+
+ /* enctype */
+ if (gss_get_bytes(&p, end, &kctx->kc_enctype, sizeof(kctx->kc_enctype)))
+ goto out_err;
+
+ /* size of each key */
+ if (gss_get_bytes(&p, end, &keysize, sizeof(keysize)))
+ goto out_err;
+
+ /* number of keys - should always be 3 */
+ if (gss_get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
+ goto out_err;
+
+ if (tmp_uint != 3) {
+ CERROR("Invalid number of keys: %u\n", tmp_uint);
+ goto out_err;
+ }
- /* ke */
- if (get_keyblock(&p, end, &kctx->kc_keye, keysize))
- goto out_err;
- /* ki */
- if (get_keyblock(&p, end, &kctx->kc_keyi, keysize))
- goto out_err;
- /* ki */
- if (get_keyblock(&p, end, &kctx->kc_keyc, keysize))
- goto out_err;
+ /* ke */
+ if (gss_get_keyblock(&p, end, &kctx->kc_keye, keysize))
+ goto out_err;
+ /* ki */
+ if (gss_get_keyblock(&p, end, &kctx->kc_keyi, keysize))
+ goto out_err;
+ /* ki */
+ if (gss_get_keyblock(&p, end, &kctx->kc_keyc, keysize))
+ goto out_err;
CDEBUG(D_SEC, "successfully imported v2 context\n");
- return 0;
+ return 0;
out_err:
- return GSS_S_FAILURE;
+ return GSS_S_FAILURE;
}
/*
__u32 gss_import_sec_context_kerberos(rawobj_t *inbuf,
struct gss_ctx *gctx)
{
- struct krb5_ctx *kctx;
- char *p = (char *) inbuf->data;
- char *end = (char *) (inbuf->data + inbuf->len);
- unsigned int tmp_uint, rc;
+ struct krb5_ctx *kctx;
+ char *p = (char *)inbuf->data;
+ char *end = (char *)(inbuf->data + inbuf->len);
+ unsigned int tmp_uint, rc;
- if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint))) {
- CERROR("Fail to read version\n");
- return GSS_S_FAILURE;
- }
+ if (gss_get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint))) {
+ CERROR("Fail to read version\n");
+ return GSS_S_FAILURE;
+ }
/* only support 0, 1 for the moment */
if (tmp_uint > 2) {
if (rawobj_dup(&knew->kc_mech_used, &kctx->kc_mech_used))
goto out_err;
- if (keyblock_dup(&knew->kc_keye, &kctx->kc_keye))
- goto out_err;
- if (keyblock_dup(&knew->kc_keyi, &kctx->kc_keyi))
- goto out_err;
- if (keyblock_dup(&knew->kc_keyc, &kctx->kc_keyc))
- goto out_err;
+ if (gss_keyblock_dup(&knew->kc_keye, &kctx->kc_keye))
+ goto out_err;
+ if (gss_keyblock_dup(&knew->kc_keyi, &kctx->kc_keyi))
+ goto out_err;
+ if (gss_keyblock_dup(&knew->kc_keyc, &kctx->kc_keyc))
+ goto out_err;
if (krb5_init_keys(knew))
goto out_err;
{
struct krb5_ctx *kctx = gctx->internal_ctx_id;
- *endtime = (unsigned long) ((__u32) kctx->kc_endtime);
+ *endtime = (unsigned long)((__u32) kctx->kc_endtime);
return GSS_S_COMPLETE;
}
}
/*
- * Should be used for buffers allocated with k/vmalloc().
- *
- * Dispose of @sgt with teardown_sgtable().
- *
- * @prealloc_sg is to avoid memory allocation inside sg_alloc_table()
- * in cases where a single sg is sufficient. No attempt to reduce the
- * number of sgs by squeezing physically contiguous pages together is
- * made though, for simplicity.
- *
- * This function is copied from the ceph filesystem code.
- */
-static int setup_sgtable(struct sg_table *sgt, struct scatterlist *prealloc_sg,
- const void *buf, unsigned int buf_len)
-{
- struct scatterlist *sg;
- const bool is_vmalloc = is_vmalloc_addr(buf);
- unsigned int off = offset_in_page(buf);
- unsigned int chunk_cnt = 1;
- unsigned int chunk_len = PAGE_ALIGN(off + buf_len);
- int i;
- int ret;
-
- if (buf_len == 0) {
- memset(sgt, 0, sizeof(*sgt));
- return -EINVAL;
- }
-
- if (is_vmalloc) {
- chunk_cnt = chunk_len >> PAGE_SHIFT;
- chunk_len = PAGE_SIZE;
- }
-
- if (chunk_cnt > 1) {
- ret = sg_alloc_table(sgt, chunk_cnt, GFP_NOFS);
- if (ret)
- return ret;
- } else {
- WARN_ON(chunk_cnt != 1);
- sg_init_table(prealloc_sg, 1);
- sgt->sgl = prealloc_sg;
- sgt->nents = sgt->orig_nents = 1;
- }
-
- for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) {
- struct page *page;
- unsigned int len = min(chunk_len - off, buf_len);
-
- if (is_vmalloc)
- page = vmalloc_to_page(buf);
- else
- page = virt_to_page(buf);
-
- sg_set_page(sg, page, len, off);
-
- off = 0;
- buf += len;
- buf_len -= len;
- }
-
- WARN_ON(buf_len != 0);
-
- return 0;
-}
-
-static void teardown_sgtable(struct sg_table *sgt)
-{
- if (sgt->orig_nents > 1)
- sg_free_table(sgt);
-}
-
-static
-__u32 krb5_encrypt(struct crypto_blkcipher *tfm,
- int decrypt,
- void * iv,
- void * in,
- void * out,
- int length)
-{
- struct sg_table sg_out;
- struct blkcipher_desc desc;
- struct scatterlist sg;
- __u8 local_iv[16] = {0};
- __u32 ret = -EINVAL;
-
- LASSERT(tfm);
- desc.tfm = tfm;
- desc.info = local_iv;
- desc.flags= 0;
-
- if (length % crypto_blkcipher_blocksize(tfm) != 0) {
- CERROR("output length %d mismatch blocksize %d\n",
- length, crypto_blkcipher_blocksize(tfm));
- goto out;
- }
-
- if (crypto_blkcipher_ivsize(tfm) > 16) {
- CERROR("iv size too large %d\n", crypto_blkcipher_ivsize(tfm));
- goto out;
- }
-
- if (iv)
- memcpy(local_iv, iv, crypto_blkcipher_ivsize(tfm));
-
- memcpy(out, in, length);
-
- ret = setup_sgtable(&sg_out, &sg, out, length);
- if (ret != 0)
- goto out;
-
- if (decrypt)
- ret = crypto_blkcipher_decrypt_iv(&desc, sg_out.sgl,
- sg_out.sgl, length);
- else
- ret = crypto_blkcipher_encrypt_iv(&desc, sg_out.sgl,
- sg_out.sgl, length);
-
- teardown_sgtable(&sg_out);
-out:
- return ret;
-}
-
-static inline
-int krb5_digest_hmac(struct crypto_hash *tfm,
- rawobj_t *key,
- struct krb5_header *khdr,
- int msgcnt, rawobj_t *msgs,
- int iovcnt, lnet_kiov_t *iovs,
- rawobj_t *cksum)
-{
- struct hash_desc desc;
- struct sg_table sgt;
- struct scatterlist sg[1];
- int i, rc;
-
- crypto_hash_setkey(tfm, key->data, key->len);
- desc.tfm = tfm;
- desc.flags= 0;
-
- crypto_hash_init(&desc);
-
- for (i = 0; i < msgcnt; i++) {
- if (msgs[i].len == 0)
- continue;
-
- rc = setup_sgtable(&sgt, sg, msgs[i].data, msgs[i].len);
- if (rc != 0)
- return rc;
-
- crypto_hash_update(&desc, sgt.sgl, msgs[i].len);
-
- teardown_sgtable(&sgt);
- }
-
- for (i = 0; i < iovcnt; i++) {
- if (iovs[i].kiov_len == 0)
- continue;
-
- sg_init_table(sg, 1);
- sg_set_page(&sg[0], iovs[i].kiov_page, iovs[i].kiov_len,
- iovs[i].kiov_offset);
- crypto_hash_update(&desc, sg, iovs[i].kiov_len);
- }
-
- if (khdr) {
- rc = setup_sgtable(&sgt, sg, (char *) khdr, sizeof(*khdr));
- if (rc != 0)
- return rc;
-
- crypto_hash_update(&desc, sgt.sgl, sizeof(*khdr));
-
- teardown_sgtable(&sgt);
- }
-
- return crypto_hash_final(&desc, cksum->data);
-}
-
-static inline
-int krb5_digest_norm(struct crypto_hash *tfm,
- struct krb5_keyblock *kb,
- struct krb5_header *khdr,
- int msgcnt, rawobj_t *msgs,
- int iovcnt, lnet_kiov_t *iovs,
- rawobj_t *cksum)
-{
- struct hash_desc desc;
- struct scatterlist sg[1];
- struct sg_table sgt;
- int i, rc;
-
- LASSERT(kb->kb_tfm);
- desc.tfm = tfm;
- desc.flags= 0;
-
- crypto_hash_init(&desc);
-
- for (i = 0; i < msgcnt; i++) {
- if (msgs[i].len == 0)
- continue;
-
- rc = setup_sgtable(&sgt, sg, msgs[i].data, msgs[i].len);
- if (rc != 0)
- return rc;
-
- crypto_hash_update(&desc, sgt.sgl, msgs[i].len);
-
- teardown_sgtable(&sgt);
- }
-
- for (i = 0; i < iovcnt; i++) {
- if (iovs[i].kiov_len == 0)
- continue;
-
- sg_init_table(sg, 1);
- sg_set_page(&sg[0], iovs[i].kiov_page, iovs[i].kiov_len,
- iovs[i].kiov_offset);
- crypto_hash_update(&desc, sg, iovs[i].kiov_len);
- }
-
- if (khdr) {
- rc = setup_sgtable(&sgt, sg, (char *) khdr, sizeof(*khdr));
- if (rc != 0)
- return rc;
-
- crypto_hash_update(&desc, sgt.sgl, sizeof(*khdr));
-
- teardown_sgtable(&sgt);
- }
-
- crypto_hash_final(&desc, cksum->data);
-
- return krb5_encrypt(kb->kb_tfm, 0, NULL, cksum->data,
- cksum->data, cksum->len);
-}
-
-/*
* compute (keyed/keyless) checksum against the plain text which appended
* with krb5 wire token header.
*/
static
__s32 krb5_make_checksum(__u32 enctype,
- struct krb5_keyblock *kb,
- struct krb5_header *khdr,
- int msgcnt, rawobj_t *msgs,
- int iovcnt, lnet_kiov_t *iovs,
- rawobj_t *cksum)
+ struct gss_keyblock *kb,
+ struct krb5_header *khdr,
+ int msgcnt, rawobj_t *msgs,
+ int iovcnt, lnet_kiov_t *iovs,
+ rawobj_t *cksum)
{
struct krb5_enctype *ke = &enctypes[enctype];
struct crypto_hash *tfm;
+ rawobj_t hdr;
__u32 code = GSS_S_FAILURE;
int rc;
goto out_tfm;
}
+ hdr.data = (__u8 *)khdr;
+ hdr.len = sizeof(*khdr);
+
if (ke->ke_hash_hmac)
- rc = krb5_digest_hmac(tfm, &kb->kb_key,
- khdr, msgcnt, msgs, iovcnt, iovs, cksum);
+ rc = gss_digest_hmac(tfm, &kb->kb_key,
+ &hdr, msgcnt, msgs, iovcnt, iovs, cksum);
else
- rc = krb5_digest_norm(tfm, kb,
- khdr, msgcnt, msgs, iovcnt, iovs, cksum);
+ rc = gss_digest_norm(tfm, kb,
+ &hdr, msgcnt, msgs, iovcnt, iovs, cksum);
if (rc == 0)
code = GSS_S_COMPLETE;
/* fill krb5 header */
LASSERT(token->len >= sizeof(*khdr));
- khdr = (struct krb5_header *) token->data;
+ khdr = (struct krb5_header *)token->data;
fill_krb5_header(kctx, khdr, 0);
/* checksum */
return GSS_S_DEFECTIVE_TOKEN;
}
- khdr = (struct krb5_header *) token->data;
+ khdr = (struct krb5_header *)token->data;
major = verify_krb5_header(kctx, khdr, 0);
if (major != GSS_S_COMPLETE) {
return GSS_S_COMPLETE;
}
-static
-int add_padding(rawobj_t *msg, int msg_buflen, int blocksize)
-{
- int padding;
-
- padding = (blocksize - (msg->len & (blocksize - 1))) &
- (blocksize - 1);
- if (!padding)
- return 0;
-
- if (msg->len + padding > msg_buflen) {
- CERROR("bufsize %u too small: datalen %u, padding %u\n",
- msg_buflen, msg->len, padding);
- return -EINVAL;
- }
-
- memset(msg->data + msg->len, padding, padding);
- msg->len += padding;
- return 0;
-}
-
-static
-int krb5_encrypt_rawobjs(struct crypto_blkcipher *tfm,
- int mode_ecb,
- int inobj_cnt,
- rawobj_t *inobjs,
- rawobj_t *outobj,
- int enc)
-{
- struct blkcipher_desc desc;
- struct scatterlist src, dst;
- struct sg_table sg_src, sg_dst;
- __u8 local_iv[16] = {0}, *buf;
- __u32 datalen = 0;
- int i, rc;
- ENTRY;
-
- buf = outobj->data;
- desc.tfm = tfm;
- desc.info = local_iv;
- desc.flags = 0;
-
- for (i = 0; i < inobj_cnt; i++) {
- LASSERT(buf + inobjs[i].len <= outobj->data + outobj->len);
-
- rc = setup_sgtable(&sg_src, &src, inobjs[i].data,
- inobjs[i].len);
- if (rc != 0)
- RETURN(rc);
-
- rc = setup_sgtable(&sg_dst, &dst, buf,
- outobj->len - datalen);
- if (rc != 0) {
- teardown_sgtable(&sg_src);
- RETURN(rc);
- }
-
- if (mode_ecb) {
- if (enc)
- rc = crypto_blkcipher_encrypt(&desc, sg_dst.sgl,
- sg_src.sgl,
- inobjs[i].len);
- else
- rc = crypto_blkcipher_decrypt(&desc, sg_dst.sgl,
- sg_src.sgl,
- inobjs[i].len);
- } else {
- if (enc)
- rc = crypto_blkcipher_encrypt_iv(&desc,
- sg_dst.sgl,
- sg_src.sgl,
- inobjs[i].len);
- else
- rc = crypto_blkcipher_decrypt_iv(&desc,
- sg_dst.sgl,
- sg_src.sgl,
- inobjs[i].len);
- }
-
- teardown_sgtable(&sg_src);
- teardown_sgtable(&sg_dst);
-
- if (rc) {
- CERROR("encrypt error %d\n", rc);
- RETURN(rc);
- }
-
- datalen += inobjs[i].len;
- buf += inobjs[i].len;
- }
-
- outobj->len = datalen;
- RETURN(0);
-}
-
/*
* if adj_nob != 0, we adjust desc->bd_nob to the actual cipher text size.
*/
ciph_desc.flags = 0;
/* encrypt confounder */
- rc = setup_sgtable(&sg_src, &src, confounder, blocksize);
+ rc = gss_setup_sgtable(&sg_src, &src, confounder, blocksize);
if (rc != 0)
return rc;
- rc = setup_sgtable(&sg_dst, &dst, cipher->data, blocksize);
+ rc = gss_setup_sgtable(&sg_dst, &dst, cipher->data, blocksize);
if (rc != 0) {
- teardown_sgtable(&sg_src);
+ gss_teardown_sgtable(&sg_src);
return rc;
}
rc = crypto_blkcipher_encrypt_iv(&ciph_desc, sg_dst.sgl,
sg_src.sgl, blocksize);
- teardown_sgtable(&sg_dst);
- teardown_sgtable(&sg_src);
+ gss_teardown_sgtable(&sg_dst);
+ gss_teardown_sgtable(&sg_src);
if (rc) {
CERROR("error to encrypt confounder: %d\n", rc);
}
/* encrypt krb5 header */
- rc = setup_sgtable(&sg_src, &src, khdr, sizeof(*khdr));
+ rc = gss_setup_sgtable(&sg_src, &src, khdr, sizeof(*khdr));
if (rc != 0)
return rc;
- rc = setup_sgtable(&sg_dst, &dst, cipher->data + blocksize,
+ rc = gss_setup_sgtable(&sg_dst, &dst, cipher->data + blocksize,
sizeof(*khdr));
if (rc != 0) {
- teardown_sgtable(&sg_src);
+ gss_teardown_sgtable(&sg_src);
return rc;
}
rc = crypto_blkcipher_encrypt_iv(&ciph_desc, sg_dst.sgl, sg_src.sgl,
sizeof(*khdr));
- teardown_sgtable(&sg_dst);
- teardown_sgtable(&sg_src);
+ gss_teardown_sgtable(&sg_dst);
+ gss_teardown_sgtable(&sg_src);
if (rc) {
CERROR("error to encrypt krb5 header: %d\n", rc);
}
/* decrypt head (confounder) */
- rc = setup_sgtable(&sg_src, &src, cipher->data, blocksize);
+ rc = gss_setup_sgtable(&sg_src, &src, cipher->data, blocksize);
if (rc != 0)
return rc;
- rc = setup_sgtable(&sg_dst, &dst, plain->data, blocksize);
+ rc = gss_setup_sgtable(&sg_dst, &dst, plain->data, blocksize);
if (rc != 0) {
- teardown_sgtable(&sg_src);
+ gss_teardown_sgtable(&sg_src);
return rc;
}
rc = crypto_blkcipher_decrypt_iv(&ciph_desc, sg_dst.sgl,
sg_src.sgl, blocksize);
- teardown_sgtable(&sg_dst);
- teardown_sgtable(&sg_src);
+ gss_teardown_sgtable(&sg_dst);
+ gss_teardown_sgtable(&sg_src);
if (rc) {
CERROR("error to decrypt confounder: %d\n", rc);
BD_GET_KIOV(desc, i++).kiov_len = 0;
/* decrypt tail (krb5 header) */
- rc = setup_sgtable(&sg_src, &src, cipher->data + blocksize,
- sizeof(*khdr));
+ rc = gss_setup_sgtable(&sg_src, &src, cipher->data + blocksize,
+ sizeof(*khdr));
if (rc != 0)
return rc;
- rc = setup_sgtable(&sg_dst, &dst, cipher->data + blocksize,
- sizeof(*khdr));
+ rc = gss_setup_sgtable(&sg_dst, &dst, cipher->data + blocksize,
+ sizeof(*khdr));
if (rc != 0) {
- teardown_sgtable(&sg_src);
+ gss_teardown_sgtable(&sg_src);
return rc;
}
rc = crypto_blkcipher_decrypt_iv(&ciph_desc, sg_dst.sgl, sg_src.sgl,
sizeof(*khdr));
- teardown_sgtable(&sg_src);
- teardown_sgtable(&sg_dst);
+ gss_teardown_sgtable(&sg_src);
+ gss_teardown_sgtable(&sg_dst);
if (rc) {
CERROR("error to decrypt tail: %d\n", rc);
/* fill krb5 header */
LASSERT(token->len >= sizeof(*khdr));
- khdr = (struct krb5_header *) token->data;
+ khdr = (struct krb5_header *)token->data;
fill_krb5_header(kctx, khdr, 1);
/* generate confounder */
}
LASSERT(blocksize <= ke->ke_conf_size);
- /* padding the message */
- if (add_padding(msg, msg_buflen, blocksize))
- return GSS_S_FAILURE;
+ /* padding the message */
+ if (gss_add_padding(msg, msg_buflen, blocksize))
+ return GSS_S_FAILURE;
/*
* clear text layout for checksum:
data_desc[2].len = sizeof(*khdr);
/* cipher text will be directly inplace */
- cipher.data = (__u8 *) (khdr + 1);
+ cipher.data = (__u8 *)(khdr + 1);
cipher.len = token->len - sizeof(*khdr);
LASSERT(cipher.len >= ke->ke_conf_size + msg->len + sizeof(*khdr));
GOTO(arc4_out_tfm, rc = -EACCES);
}
- rc = krb5_encrypt_rawobjs(arc4_tfm, 1,
- 3, data_desc, &cipher, 1);
+ rc = gss_crypt_rawobjs(arc4_tfm, 1, 3, data_desc, &cipher, 1);
arc4_out_tfm:
crypto_free_blkcipher(arc4_tfm);
arc4_out_key:
arc4_out:
do {} while(0); /* just to avoid compile warning */
} else {
- rc = krb5_encrypt_rawobjs(kctx->kc_keye.kb_tfm, 0,
- 3, data_desc, &cipher, 1);
+ rc = gss_crypt_rawobjs(kctx->kc_keye.kb_tfm, 0, 3, data_desc,
+ &cipher, 1);
}
if (rc != 0) {
/* fill krb5 header */
LASSERT(token->len >= sizeof(*khdr));
- khdr = (struct krb5_header *) token->data;
+ khdr = (struct krb5_header *)token->data;
fill_krb5_header(kctx, khdr, 1);
/* generate confounder */
data_desc[0].data = conf;
data_desc[0].len = ke->ke_conf_size;
- cipher.data = (__u8 *) (khdr + 1);
+ cipher.data = (__u8 *)(khdr + 1);
cipher.len = blocksize + sizeof(*khdr);
if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
return GSS_S_DEFECTIVE_TOKEN;
}
- khdr = (struct krb5_header *) token->data;
+ khdr = (struct krb5_header *)token->data;
major = verify_krb5_header(kctx, khdr, 1);
if (major != GSS_S_COMPLETE) {
major = GSS_S_FAILURE;
- cipher_in.data = (__u8 *) (khdr + 1);
+ cipher_in.data = (__u8 *)(khdr + 1);
cipher_in.len = bodysize;
plain_out.data = tmpbuf;
plain_out.len = bodysize;
GOTO(arc4_out_tfm, rc = -EACCES);
}
- rc = krb5_encrypt_rawobjs(arc4_tfm, 1,
- 1, &cipher_in, &plain_out, 0);
+ rc = gss_crypt_rawobjs(arc4_tfm, 1, 1, &cipher_in,
+ &plain_out, 0);
arc4_out_tfm:
crypto_free_blkcipher(arc4_tfm);
arc4_out_key:
arc4_out:
cksum = RAWOBJ_EMPTY;
} else {
- rc = krb5_encrypt_rawobjs(kctx->kc_keye.kb_tfm, 0,
- 1, &cipher_in, &plain_out, 0);
+ rc = gss_crypt_rawobjs(kctx->kc_keye.kb_tfm, 0, 1, &cipher_in,
+ &plain_out, 0);
}
if (rc != 0) {
return GSS_S_DEFECTIVE_TOKEN;
}
- khdr = (struct krb5_header *) token->data;
+ khdr = (struct krb5_header *)token->data;
major = verify_krb5_header(kctx, khdr, 1);
if (major != GSS_S_COMPLETE) {
#include <obd_class.h>
#include <obd_support.h>
#include <lustre/lustre_idl.h>
-#include <lustre_net.h>
#include <lustre_import.h>
+#include <lustre_net.h>
+#include <lustre_nodemap.h>
#include <lustre_sec.h>
#include "gss_err.h"
#endif
}
/****************************************
- * rsi cache *
+ * rpc sec init (rsi) cache *
****************************************/
#define RSI_HASHBITS (6)
struct cache_head h;
__u32 lustre_svc;
__u64 nid;
+ char nm_name[LUSTRE_NODEMAP_NAME_LENGTH + 1];
wait_queue_head_t waitq;
rawobj_t in_handle, in_token;
rawobj_t out_handle, out_token;
rawobj_free(&rsi->out_token);
}
+/* See handle_req() userspace for where the upcall data is read */
static void rsi_request(struct cache_detail *cd,
struct cache_head *h,
char **bpp, int *blen)
sizeof(rsi->lustre_svc));
qword_addhex(bpp, blen, (char *) &rsi->nid, sizeof(rsi->nid));
qword_addhex(bpp, blen, (char *) &index, sizeof(index));
+ qword_addhex(bpp, blen, (char *) rsi->nm_name,
+ strlen(rsi->nm_name) + 1);
qword_addhex(bpp, blen, rsi->in_handle.data, rsi->in_handle.len);
qword_addhex(bpp, blen, rsi->in_token.data, rsi->in_token.len);
(*bpp)[-1] = '\n';
new->lustre_svc = item->lustre_svc;
new->nid = item->nid;
+ memcpy(new->nm_name, item->nm_name, sizeof(item->nm_name));
init_waitqueue_head(&new->waitq);
}
}
/****************************************
- * rsc cache *
+ * rpc sec context (rsc) cache *
****************************************/
#define RSC_HASHBITS (10)
int rc = SECSVC_DROP;
ENTRY;
- memset(&rsikey, 0, sizeof(rsikey));
- rsikey.lustre_svc = lustre_svc;
- rsikey.nid = (__u64) req->rq_peer.nid;
+ memset(&rsikey, 0, sizeof(rsikey));
+ rsikey.lustre_svc = lustre_svc;
+ rsikey.nid = (__u64) req->rq_peer.nid;
+ nodemap_test_nid(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)) {
. /etc/init.d/functions
LOCKFILE="/var/lock/subsys/lsvcgssd"
+LSVCGSSDARGS="-k"
+
+# Check for and source configuration file
+[ -f /etc/sysconfig/lsvcgss ] && . /etc/sysconfig/lsvcgss
# See how we were called.
case "$1" in
start)
echo $"Starting lsvcgssd"
- /usr/sbin/lsvcgssd
+ /usr/sbin/lsvcgssd ${LSVCGSSDARGS}
RETVAL=$?
[ $RETVAL -eq 0 ] && touch $LOCKFILE
;;
#include <errno.h>
#include "err_util.h"
-void qword_add(char **bpp, int *lp, char *str)
+void qword_add(char **bpp, int *lp, const char *str)
{
char *bp = *bpp;
int len = *lp;
static char qword_buf[8192];
static char tmp_buf[8192];
-int qword_print(FILE *f, char *str)
+int qword_print(FILE *f, const char *str)
{
char *bp = qword_buf;
int len = sizeof(qword_buf);
#include <stdio.h>
-void qword_add(char **bpp, int *lp, char *str);
+void qword_add(char **bpp, int *lp, const char *str);
void qword_addhex(char **bpp, int *lp, char *buf, int blen);
void qword_addint(char **bpp, int *lp, int n);
void qword_adduint(char **bpp, int *lp, unsigned int n);
void qword_addeol(char **bpp, int *lp);
-int qword_print(FILE *f, char *str);
+int qword_print(FILE *f, const char *str);
int qword_printhex(FILE *f, char *str, int slen);
void qword_printint(FILE *f, int num);
int qword_eol(FILE *f);
void print_hexl(int pri, unsigned char *cp, int length)
{
- int i, j, jm;
- unsigned char c;
-
printerr(pri, "length %d\n",length);
printerr(pri, "\n");
+ print_hex(pri, cp, length);
+}
+
+void print_hex(int pri, unsigned char *cp, int length)
+{
+ int i, j, jm;
+ unsigned char c;
for (i = 0; i < length; i += 0x10) {
printerr(pri, " %04x: ", (unsigned int)i);
void printerr(int priority, char *format, ...)
__attribute__((__format__(__printf__, 2, 3)));
void print_hexl(int pri, unsigned char *cp, int length);
+void print_hex(int pri, unsigned char *cp, int length);
#endif /* _ERR_UTIL_H_ */
return -1;
}
- param.version = GSSD_INTERFACE_VERSION;
+ param.version = GSSD_INTERFACE_VERSION_V1;
param.uuid = lgd->lgd_uuid;
param.lustre_svc = lgd->lgd_lustre_svc;
param.uid = lgd->lgd_uid;
* all data about negotiation
*/
struct lgss_nego_data {
- uint32_t lnd_established:1;
-
- int lnd_secid;
- uint32_t lnd_uid;
- uint32_t lnd_lsvc;
- char *lnd_uuid;
-
- gss_OID lnd_mech; /* mech OID */
- gss_name_t lnd_svc_name; /* service name */
- unsigned int lnd_req_flags; /* request flags */
- gss_cred_id_t lnd_cred; /* credential */
- gss_ctx_id_t lnd_ctx; /* session context */
- gss_buffer_desc lnd_rmt_ctx; /* remote handle of context */
- uint32_t lnd_seq_win; /* sequence window */
-
- int lnd_rpc_err;
- int lnd_gss_err;
+ uint32_t lnd_established:1;
+
+ int lnd_secid;
+ uint32_t lnd_uid;
+ uint32_t lnd_lsvc;
+ char *lnd_uuid;
+
+ gss_OID lnd_mech; /* mech OID */
+ gss_name_t lnd_svc_name; /* service name */
+ unsigned int lnd_req_flags; /* request flags */
+ gss_cred_id_t lnd_cred; /* credential */
+ gss_ctx_id_t lnd_ctx; /* session context */
+ gss_buffer_desc lnd_rmt_ctx; /* remote handle of context */
+ gss_buffer_desc lnd_ctx_token; /* context token for kernel */
+ uint32_t lnd_seq_win; /* sequence window */
+
+ int lnd_rpc_err;
+ int lnd_gss_err;
};
/*
};
struct keyring_upcall_param {
- uint32_t kup_ver;
- uint32_t kup_secid;
- uint32_t kup_uid;
- uint32_t kup_fsuid;
- uint32_t kup_gid;
- uint32_t kup_fsgid;
- uint32_t kup_svc;
- uint64_t kup_nid;
- uint64_t kup_selfnid;
- char kup_tgt[64];
- char kup_mech[16];
- unsigned int kup_is_root:1,
- kup_is_mdt:1,
- kup_is_ost:1;
+ uint32_t kup_ver;
+ uint32_t kup_secid;
+ uint32_t kup_uid;
+ uint32_t kup_fsuid;
+ uint32_t kup_gid;
+ uint32_t kup_fsgid;
+ uint32_t kup_svc;
+ uint64_t kup_nid;
+ uint64_t kup_selfnid;
+ char kup_svc_type;
+ char kup_tgt[64];
+ char kup_mech[16];
+ unsigned int kup_is_root:1,
+ kup_is_mdt:1,
+ kup_is_ost:1;
};
/****************************************
logmsg(LL_TRACE, "do_nego_rpc: to parse reply\n");
if (param.status) {
logmsg(LL_ERR, "status: %ld (%s)\n",
- param.status, strerror((int)param.status));
+ param.status, strerror((int)(-param.status)));
/* kernel return -ETIMEDOUT means the rpc timedout, we should
* notify the caller to reinitiate the gss negotiation, by
gr->gr_minor = *p++;
gr->gr_win = *p++;
- gr->gr_ctx.length = *p++;
- gr->gr_ctx.value = malloc(gr->gr_ctx.length);
- memcpy(gr->gr_ctx.value, p, gr->gr_ctx.length);
- p += (((gr->gr_ctx.length + 3) & ~3) / 4);
-
- gr->gr_token.length = *p++;
- gr->gr_token.value = malloc(gr->gr_token.length);
- memcpy(gr->gr_token.value, p, gr->gr_token.length);
- p += (((gr->gr_token.length + 3) & ~3) / 4);
+ gr->gr_ctx.length = *p++;
+ gr->gr_ctx.value = malloc(gr->gr_ctx.length);
+ if (gr->gr_ctx.value == NULL)
+ return -ENOMEM;
+ memcpy(gr->gr_ctx.value, p, gr->gr_ctx.length);
+ p += (((gr->gr_ctx.length + 3) & ~3) / 4);
+
+ gr->gr_token.length = *p++;
+ gr->gr_token.value = malloc(gr->gr_token.length);
+ if (gr->gr_token.value == NULL) {
+ free(gr->gr_ctx.value);
+ return -ENOMEM;
+ }
+ memcpy(gr->gr_token.value, p, gr->gr_token.length);
+ p += (((gr->gr_token.length + 3) & ~3) / 4);
logmsg(LL_DEBUG, "do_nego_rpc: receive handle len %zu, token len %zu, "
"res %d\n", gr->gr_ctx.length, gr->gr_token.length, res);
* if return error, the lnd_rpc_err or lnd_gss_err is set.
*/
static int lgssc_init_nego_data(struct lgss_nego_data *lnd,
- struct keyring_upcall_param *kup,
- lgss_mech_t mech)
+ struct keyring_upcall_param *kup,
+ enum lgss_mech mech)
{
gss_buffer_desc sname;
OM_uint32 maj_stat, min_stat;
memset(lnd, 0, sizeof(*lnd));
- lnd->lnd_secid = kup->kup_secid;
- lnd->lnd_uid = kup->kup_uid;
- lnd->lnd_lsvc = kup->kup_svc;
- lnd->lnd_uuid = kup->kup_tgt;
+ lnd->lnd_secid = kup->kup_secid;
+ lnd->lnd_uid = kup->kup_uid;
+ lnd->lnd_lsvc = kup->kup_svc | mech << LUSTRE_GSS_MECH_SHIFT;
+ lnd->lnd_uuid = kup->kup_tgt;
lnd->lnd_established = 0;
lnd->lnd_svc_name = GSS_C_NO_NAME;
return rc;
}
-/*
- * note we inherited assumed authority from parent process
- */
-static int lgssc_kr_negotiate(key_serial_t keyid, struct lgss_cred *cred,
- struct keyring_upcall_param *kup)
+static int lgssc_kr_negotiate_krb(key_serial_t keyid, struct lgss_cred *cred,
+ struct keyring_upcall_param *kup)
{
- struct lgss_nego_data lnd;
- gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
- OM_uint32 min_stat;
- int rc = -1;
+ struct lgss_nego_data lnd;
+ OM_uint32 min_stat;
+ int rc = -1;
- logmsg(LL_TRACE, "child start on behalf of key %08x: "
- "cred %p, uid %u, svc %u, nid %"PRIx64", uids: %u:%u/%u:%u\n",
- keyid, cred, cred->lc_uid, cred->lc_tgt_svc, cred->lc_tgt_nid,
- kup->kup_uid, kup->kup_gid, kup->kup_fsuid, kup->kup_fsgid);
+ memset(&lnd, 0, sizeof(lnd));
if (lgss_get_service_str(&g_service, kup->kup_svc, kup->kup_nid)) {
logmsg(LL_ERR, "key %08x: failed to construct service "
goto out;
}
- rc = serialize_context_for_kernel(lnd.lnd_ctx, &token, lnd.lnd_mech);
- if (rc) {
- logmsg(LL_ERR, "key %08x: failed to export context\n", keyid);
- error_kernel_key(keyid, rc, lnd.lnd_gss_err);
- goto out;
- }
+ rc = serialize_context_for_kernel(lnd.lnd_ctx, &lnd.lnd_ctx_token,
+ lnd.lnd_mech);
+ if (rc) {
+ logmsg(LL_ERR, "key %08x: failed to export context\n", keyid);
+ error_kernel_key(keyid, rc, lnd.lnd_gss_err);
+ goto out;
+ }
- rc = update_kernel_key(keyid, &lnd, &token);
- if (rc)
- goto out;
+ rc = update_kernel_key(keyid, &lnd, &lnd.lnd_ctx_token);
+ if (rc)
+ goto out;
- rc = 0;
- logmsg(LL_INFO, "key %08x for user %u is updated OK!\n",
- keyid, kup->kup_uid);
+ rc = 0;
+ logmsg(LL_INFO, "key %08x for user %u is updated OK!\n",
+ keyid, kup->kup_uid);
out:
- if (token.length != 0)
- gss_release_buffer(&min_stat, &token);
+ if (lnd.lnd_ctx_token.length != 0)
+ gss_release_buffer(&min_stat, &lnd.lnd_ctx_token);
- lgssc_fini_nego_data(&lnd);
+ lgssc_fini_nego_data(&lnd);
out_cred:
- lgss_release_cred(cred);
- return rc;
+ lgss_release_cred(cred);
+ return rc;
+}
+
+/*
+ * note we inherited assumed authority from parent process
+ */
+static int lgssc_kr_negotiate(key_serial_t keyid, struct lgss_cred *cred,
+ struct keyring_upcall_param *kup)
+{
+ int rc;
+
+ logmsg(LL_TRACE, "child start on behalf of key %08x: "
+ "cred %p, uid %u, svc %u, nid %"PRIx64", uids: %u:%u/%u:%u\n",
+ keyid, cred, cred->lc_uid, cred->lc_tgt_svc, cred->lc_tgt_nid,
+ kup->kup_uid, kup->kup_gid, kup->kup_fsuid, kup->kup_fsgid);
+
+ switch (cred->lc_mech->lmt_mech_n) {
+ case LGSS_MECH_KRB5:
+ default:
+ rc = lgssc_kr_negotiate_krb(keyid, cred, kup);
+ break;
+ }
+
+ return rc;
}
/*
* [2]: uid (uint)
* [3]: gid (uint)
* [4]: flags (string) FMT: r-root; m-mdt; o-ost
- * [5]: lustre_svc (uint)
- * [6]: target_nid (uint64)
- * [7]: target_uuid (string)
- * [8]: self_nid (uint64)
+ * [5]: svc type (char)
+ * [6]: lustre_svc (int)
+ * [7]: target_nid (uint64)
+ * [8]: target_uuid (string)
+ * [9]: self_nid (uint64)
*/
static int parse_callout_info(const char *coinfo,
struct keyring_upcall_param *uparam)
{
- const int nargs = 9;
+ const int nargs = 10;
char buf[1024];
char *string = buf;
int length, i;
}
data[i] = string;
- logmsg(LL_TRACE, "components: %s,%s,%s,%s,%s,%s,%s,%s,%s\n",
- data[0], data[1], data[2], data[3], data[4], data[5],
- data[6], data[7], data[8]);
+ logmsg(LL_TRACE, "components: %s,%s,%s,%s,%s,%c,%s,%s,%s,%s\n",
+ data[0], data[1], data[2], data[3], data[4], data[5][0],
+ data[6], data[7], data[8], data[9]);
uparam->kup_secid = strtol(data[0], NULL, 0);
strlcpy(uparam->kup_mech, data[1], sizeof(uparam->kup_mech));
uparam->kup_is_mdt = 1;
if (strchr(data[4], 'o'))
uparam->kup_is_ost = 1;
- uparam->kup_svc = strtol(data[5], NULL, 0);
- uparam->kup_nid = strtoll(data[6], NULL, 0);
- strlcpy(uparam->kup_tgt, data[7], sizeof(uparam->kup_tgt));
- uparam->kup_selfnid = strtoll(data[8], NULL, 0);
+ uparam->kup_svc_type = data[5][0];
+ uparam->kup_svc = strtol(data[6], NULL, 0);
+ uparam->kup_nid = strtoll(data[7], NULL, 0);
+ strlcpy(uparam->kup_tgt, data[8], sizeof(uparam->kup_tgt));
+ uparam->kup_selfnid = strtoll(data[9], NULL, 0);
logmsg(LL_DEBUG, "parse call out info: secid %d, mech %s, ugid %u:%u, "
- "is_root %d, is_mdt %d, is_ost %d, svc %d, nid 0x%"PRIx64", "
- "tgt %s, self nid 0x%"PRIx64"\n",
+ "is_root %d, is_mdt %d, is_ost %d, svc type %c, svc %d, "
+ "nid 0x%"PRIx64", tgt %s, self nid 0x%"PRIx64"\n",
uparam->kup_secid, uparam->kup_mech,
uparam->kup_uid, uparam->kup_gid,
uparam->kup_is_root, uparam->kup_is_mdt, uparam->kup_is_ost,
- uparam->kup_svc, uparam->kup_nid, uparam->kup_tgt,
- uparam->kup_selfnid);
+ uparam->kup_svc_type, uparam->kup_svc, uparam->kup_nid,
+ uparam->kup_tgt, uparam->kup_selfnid);
return 0;
}
cred->lc_root_flags |= uparam.kup_is_ost ? LGSS_ROOT_CRED_OST : 0;
cred->lc_tgt_nid = uparam.kup_nid;
cred->lc_tgt_svc = uparam.kup_svc;
+ cred->lc_tgt_uuid = uparam.kup_tgt;
+ cred->lc_svc_type = uparam.kup_svc_type;
cred->lc_self_nid = uparam.kup_selfnid;
if (lgss_prepare_cred(cred)) {
****************************************/
/* from kerberos source, gssapi_krb5.c */
-gss_OID_desc krb5oid =
- {9, "\052\206\110\206\367\022\001\002\002"};
-
-gss_OID_desc spkm3oid =
- {7, "\053\006\001\005\005\001\003"};
+gss_OID_desc krb5oid = {
+ .length = 9,
+ .elements = "\052\206\110\206\367\022\001\002\002"
+};
+gss_OID_desc spkm3oid = {
+ .length = 7,
+ .elements = "\053\006\001\005\005\001\003"
+};
+/* null and sk come from IU's oid space */
+gss_OID_desc nulloid = {
+ .length = 12,
+ .elements = "\053\006\001\004\001\311\146\215\126\001\000\000"
+};
+gss_OID_desc skoid = {
+ .length = 12,
+ .elements = "\053\006\001\004\001\311\146\215\126\001\000\001"
+};
/****************************************
* log facilities *
void lgss_destroy_cred(struct lgss_cred *cred)
{
- lassert(cred->lc_mech);
+ lassert(cred->lc_mech != NULL);
lassert(cred->lc_mech_cred == NULL);
logmsg(LL_TRACE, "destroying a %s cred at %p\n",
{
struct lgss_mech_type *mech = cred->lc_mech;
- lassert(mech);
+ lassert(mech != NULL);
logmsg(LL_TRACE, "preparing %s cred %p\n", mech->lmt_name, cred);
{
struct lgss_mech_type *mech = cred->lc_mech;
- lassert(mech);
+ lassert(mech != NULL);
logmsg(LL_TRACE, "releasing %s cred %p\n", mech->lmt_name, cred);
if (cred->lc_mech_cred) {
lassert(cred->lc_mech != NULL);
- lassert(cred->lc_mech->lmt_release_cred);
+ lassert(cred->lc_mech->lmt_release_cred != NULL);
cred->lc_mech->lmt_release_cred(cred);
}
{
struct lgss_mech_type *mech = cred->lc_mech;
- lassert(mech);
+ lassert(mech != NULL);
logmsg(LL_TRACE, "using %s cred %p\n", mech->lmt_name, cred);
return 0;
}
+int lgss_validate_cred(struct lgss_cred *cred, gss_buffer_desc *token,
+ gss_buffer_desc *ctx_token)
+{
+ struct lgss_mech_type *mech = cred->lc_mech;
+
+ lassert(mech != NULL);
+
+ logmsg(LL_TRACE, "validate %s cred %p with token %p\n", mech->lmt_name,
+ cred, token);
+
+ if (mech->lmt_validate_cred)
+ return mech->lmt_validate_cred(cred, token, ctx_token);
+
+ return 0;
+}
+
/****************************************
* helper functions *
****************************************/
#include <stdint.h>
#include <gssapi/gssapi.h>
+#include "lsupport.h"
+
#define LGSS_SVC_MGS_STR "lustre_mgs"
#define LGSS_SVC_MDS_STR "lustre_mds"
#define LGSS_SVC_OSS_STR "lustre_oss"
****************************************/
typedef enum {
- LGSS_MUTEX_KRB5 = 0,
- LGSS_MUTEX_MAX
+ LGSS_MUTEX_KRB5 = 0,
+ LGSS_MUTEX_MAX
} lgss_mutex_id_t;
int lgss_mutex_lock(lgss_mutex_id_t mid);
extern gss_OID_desc krb5oid;
extern gss_OID_desc spkm3oid;
-
-typedef enum {
- LGSS_MECH_KRB5 = 0,
-} lgss_mech_t;
+extern gss_OID_desc nulloid;
+extern gss_OID_desc skoid;
/****************************************
* client credentials *
struct lgss_cred;
struct lgss_mech_type {
- char *lmt_name;
- lgss_mech_t lmt_mech_n;
-
- int (*lmt_init)(void);
- void (*lmt_fini)(void);
- int (*lmt_prepare_cred)(struct lgss_cred *cred);
- void (*lmt_release_cred)(struct lgss_cred *cred);
- int (*lmt_using_cred)(struct lgss_cred *cred);
+ char *lmt_name;
+ enum lgss_mech lmt_mech_n;
+
+ int (*lmt_init)(void);
+ void (*lmt_fini)(void);
+ int (*lmt_prepare_cred)(struct lgss_cred *cred);
+ void (*lmt_release_cred)(struct lgss_cred *cred);
+ int (*lmt_using_cred)(struct lgss_cred *cred);
+ int (*lmt_validate_cred)(struct lgss_cred *cred,
+ gss_buffer_desc *token,
+ gss_buffer_desc *ctx_token);
};
enum {
};
struct lgss_cred {
- int lc_uid;
- unsigned int lc_root_flags;
- uint64_t lc_self_nid;
- uint64_t lc_tgt_nid;
- uint32_t lc_tgt_svc;
-
- struct lgss_mech_type *lc_mech;
- void *lc_mech_cred;
+ int lc_uid;
+ unsigned int lc_root_flags;
+ uint64_t lc_self_nid;
+ uint64_t lc_tgt_nid;
+ uint32_t lc_tgt_svc;
+ char lc_svc_type;
+ char *lc_tgt_uuid;
+
+ struct lgss_mech_type *lc_mech;
+ void *lc_mech_cred;
+ gss_buffer_desc lc_mech_token;
};
struct lgss_mech_type *lgss_name2mech(const char *mech_name);
int lgss_prepare_cred(struct lgss_cred *cred);
void lgss_release_cred(struct lgss_cred *cred);
int lgss_using_cred(struct lgss_cred *cred);
+int lgss_validate_cred(struct lgss_cred *cred, gss_buffer_desc *token,
+ gss_buffer_desc *ctx_token);
int lgss_get_service_str(char **string, uint32_t lsvc, uint64_t tgt_nid);
-
-extern gss_OID_desc krb5oid;
-extern gss_OID_desc spkm3oid;
-
static inline
int gss_OID_equal(gss_OID_desc *oid1, gss_OID_desc *oid2)
{
#define LUSTRE_GSS_SVC_MDS 1
#define LUSTRE_GSS_SVC_OSS 2
+#define LUSTRE_GSS_SVC_MASK 0x0000FFFF
+#define LUSTRE_GSS_MECH_MASK 0xFFFF0000
+#define LUSTRE_GSS_MECH_SHIFT 16
+
extern const char * lustre_svc_name[];
+enum lgss_mech {
+ LGSS_MECH_KRB5 = 0,
+ LGSS_MECH_NULL = 1,
+ LGSS_MECH_SK = 2,
+};
+
struct lgssd_upcall_data {
uint32_t seq;
uint32_t uid;
}
static void
-usage(char *progname)
+usage(FILE *fp, char *progname)
{
- fprintf(stderr, "usage: %s [-n] [-f] [-v] [-r] [-m] [-o] [-g]\n",
+ fprintf(fp, "usage: %s [ -fnvmogk ]\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");
+
exit(1);
}
int verbosity = 0;
int opt;
int must_srv_mds = 0, must_srv_oss = 0, must_srv_mgs = 0;
- extern char *optarg;
char *progname;
- while ((opt = getopt(argc, argv, "fvrnmog:")) != -1) {
+ while ((opt = getopt(argc, argv, "fnvmogk")) != -1) {
switch (opt) {
- case 'f':
- fg = 1;
- break;
- case 'n':
- get_creds = 0;
- break;
- case 'v':
- verbosity++;
- break;
- case 'm':
- get_creds = 1;
- must_srv_mds = 1;
- break;
- case 'o':
- get_creds = 1;
- must_srv_oss = 1;
- break;
- case 'g':
- get_creds = 1;
- must_srv_mgs = 1;
- break;
- default:
- usage(argv[0]);
- break;
+ case 'f':
+ fg = 1;
+ break;
+ case 'n':
+ get_creds = 0;
+ break;
+ case 'v':
+ verbosity++;
+ break;
+ case 'm':
+ get_creds = 1;
+ must_srv_mds = 1;
+ break;
+ case 'o':
+ get_creds = 1;
+ must_srv_oss = 1;
+ break;
+ case 'g':
+ get_creds = 1;
+ must_srv_mgs = 1;
+ break;
+ case 'k':
+ krb_enabled = 1;
+ break;
+ case 'h':
+ usage(stdout, argv[0]);
+ break;
+ default:
+ usage(stderr, argv[0]);
+ break;
}
}
initerr(progname, verbosity, fg);
- if (gssd_check_mechs() != 0) {
- printerr(0, "ERROR: Problem with gssapi library\n");
- exit(1);
- }
+ /* For kerberos use gss mechanisms but ignore for sk and null */
+ if (krb_enabled && gssd_check_mechs() == 0) {
+ if (gssd_get_local_realm()) {
+ printerr(0, "ERROR: Can't get Local Kerberos realm\n");
+ exit(1);
+ }
- if (gssd_get_local_realm()) {
- printerr(0, "ERROR: Can't get Local Kerberos realm\n");
- exit(1);
- }
-
- if (get_creds &&
- gssd_prepare_creds(must_srv_mgs, must_srv_mds, must_srv_oss)) {
- printerr(0, "unable to obtain root (machine) credentials\n");
- printerr(0, "do you have a keytab entry for "
- "<lustre_xxs>/<your.host>@<YOUR.REALM> in "
- "/etc/krb5.keytab?\n");
- exit(1);
+ if (get_creds &&
+ gssd_prepare_creds(must_srv_mgs, must_srv_mds,
+ must_srv_oss)) {
+ printerr(0, "unable to obtain root (machine) "
+ "credentials\n");
+ printerr(0, "do you have a keytab entry for "
+ "<lustre_xxs>/<your.host>@<YOUR.REALM> in "
+ "/etc/krb5.keytab?\n");
+ exit(1);
+ }
}
if (!fg)
#include <sys/queue.h>
#include <gssapi/gssapi.h>
-int handle_nullreq(FILE *f);
+int krb_enabled;
+
+int handle_channel_request(FILE *f);
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);
void
svcgssd_run()
{
+ 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 };
-#define NULLRPC_FILE "/proc/net/rpc/auth.sptlrpc.init/channel"
-
while (1) {
int save_err;
while (f == NULL) {
- f = fopen(NULLRPC_FILE, "rw");
+ f = fopen(gss_rpc_channel_path, "rw");
if (f == NULL) {
printerr(4, "failed to open %s: %s\n",
- NULLRPC_FILE, strerror(errno));
+ gss_rpc_channel_path, strerror(errno));
nanosleep(&halfsec, NULL);
} else {
printerr(1, "successfully open %s\n",
- NULLRPC_FILE);
+ gss_rpc_channel_path);
break;
}
}
fclose(f);
f = NULL;
} else if (ret == 0) {
- printerr(3, "poll timeout\n");
+ printerr(4, "poll timeout\n");
} else {
if (ret != 1) {
printerr(0, "bug: unexpected poll return %d\n",
exit(1);
}
if (pollfd.revents & POLLIN) {
- if (handle_nullreq(f) < 0) {
+ if (handle_channel_request(f) < 0) {
fclose(f);
f = NULL;
}
(((o1)->length == (o2)->length) && \
(memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0))
-struct mech2file {
+struct oid2mech {
gss_OID_desc mech;
- char filename[8];
+ char mechname[8];
};
-struct mech2file m2f[] = {
+static const struct oid2mech o2m[] = {
{{9, "\052\206\110\206\367\022\001\002\002"}, "krb5"},
{{7, "\053\006\001\005\005\001\003"}, "spkm3"},
{{7, "\053\006\001\005\005\001\009"}, "lipkey"},
+ {{12, "\053\006\001\004\001\311\146\215\126\001\000\000"}, "gssnull"},
+ {{12, "\053\006\001\004\001\311\146\215\126\001\000\001"}, "sk"},
{{0,0},""},
};
/*
* Find the Linux svcgssd downcall file name given the mechanism
*/
-char *
-mech2file(gss_OID mech)
+const char *gss_OID_mech_name(gss_OID mech)
{
- struct mech2file *m2fp = m2f;
+ const struct oid2mech *o2mp = o2m;
- while(m2fp->mech.length != 0) {
- if (g_OID_equal(mech,&m2fp->mech))
- return(m2fp->filename);
- m2fp++;
+ while (o2mp->mech.length != 0) {
+ if (g_OID_equal(mech, &o2mp->mech))
+ return o2mp->mechname;
+ o2mp++;
}
return NULL;
}
# include <netdb.h>
#endif
+#include <stdbool.h>
+#include <lnet/nidstr.h>
+
#include "svcgssd.h"
#include "gss_util.h"
#include "err_util.h"
#include "context.h"
#include "cacheio.h"
#include "lsupport.h"
+#include "gss_oids.h"
+#include <lustre/lustre_idl.h>
+
+extern const char *gss_OID_mech_name(gss_OID mech);
-extern char * mech2file(gss_OID mech);
#define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.sptlrpc.context/channel"
#define SVCGSSD_INIT_CHANNEL "/proc/net/rpc/auth.sptlrpc.init/channel"
uid_t cr_gid;
};
+struct svc_nego_data {
+ /* kernel data*/
+ uint32_t lustre_svc;
+ lnet_nid_t nid;
+ uint64_t handle_seq;
+ char nm_name[LUSTRE_NODEMAP_NAME_LENGTH + 1];
+ gss_buffer_desc in_tok;
+ gss_buffer_desc out_tok;
+ gss_buffer_desc in_handle;
+ gss_buffer_desc out_handle;
+ uint32_t maj_stat;
+ uint32_t min_stat;
+
+ /* userspace data */
+ gss_OID mech;
+ gss_ctx_id_t ctx;
+ gss_buffer_desc ctx_token;
+};
+
static int
do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred,
- gss_OID mech, gss_buffer_desc *context_token)
+ gss_OID mechoid, gss_buffer_desc *context_token)
{
FILE *f;
- char *fname = NULL;
+ const char *mechname;
int err;
printerr(2, "doing downcall\n");
- if ((fname = mech2file(mech)) == NULL)
+ mechname = gss_OID_mech_name(mechoid);
+ if (mechname == NULL)
goto out_err;
f = fopen(SVCGSSD_CONTEXT_CHANNEL, "w");
if (f == NULL) {
}
qword_printhex(f, out_handle->value, out_handle->length);
/* XXX are types OK for the rest of this? */
- qword_printint(f, 0x7fffffff); /*XXX need a better timeout */
+ qword_printint(f, 3600); /* an hour should be sufficient */
qword_printint(f, cred->cr_remote);
qword_printint(f, cred->cr_usr_root);
qword_printint(f, cred->cr_usr_mds);
qword_printint(f, cred->cr_mapped_uid);
qword_printint(f, cred->cr_uid);
qword_printint(f, cred->cr_gid);
- qword_print(f, fname);
+ qword_print(f, mechname);
qword_printhex(f, context_token->value, context_token->length);
err = qword_eol(f);
fclose(f);
qword_addhex(&bp, &blen, in_handle->value, in_handle->length);
qword_addhex(&bp, &blen, in_token->value, in_token->length);
- qword_addint(&bp, &blen, 0x7fffffff); /*XXX need a better timeout */
+ qword_addint(&bp, &blen, 3600); /* an hour should be sufficient */
qword_adduint(&bp, &blen, maj_stat);
qword_adduint(&bp, &blen, min_stat);
qword_addhex(&bp, &blen, out_handle->value, out_handle->length);
gss_ctx_id_t internal_ctx_id;
} gss_union_ctx_id_desc, *gss_union_ctx_id_t;
+static int handle_krb(struct svc_nego_data *snd)
+{
+ u_int32_t ret_flags;
+ gss_name_t client_name;
+ gss_buffer_desc ignore_out_tok = {.value = NULL};
+ gss_OID mech = GSS_C_NO_OID;
+ gss_cred_id_t svc_cred;
+ u_int32_t ignore_min_stat;
+ struct svc_cred cred;
+
+ svc_cred = gssd_select_svc_cred(snd->lustre_svc);
+ if (!svc_cred) {
+ printerr(0, "no service credential for svc %u\n",
+ snd->lustre_svc);
+ goto out_err;
+ }
+
+ snd->maj_stat = gss_accept_sec_context(&snd->min_stat, &snd->ctx,
+ svc_cred, &snd->in_tok,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &client_name, &mech,
+ &snd->out_tok, &ret_flags, NULL,
+ NULL);
+
+ if (snd->maj_stat == GSS_S_CONTINUE_NEEDED) {
+ printerr(1, "gss_accept_sec_context GSS_S_CONTINUE_NEEDED\n");
+
+ /* Save the context handle for future calls */
+ snd->out_handle.length = sizeof(snd->ctx);
+ memcpy(snd->out_handle.value, &snd->ctx, sizeof(snd->ctx));
+ return 0;
+ } else if (snd->maj_stat != GSS_S_COMPLETE) {
+ printerr(0, "WARNING: gss_accept_sec_context failed\n");
+ pgsserr("handle_krb: gss_accept_sec_context",
+ snd->maj_stat, snd->min_stat, mech);
+ goto out_err;
+ }
+
+ if (get_ids(client_name, mech, &cred, snd->nid, snd->lustre_svc)) {
+ /* get_ids() prints error msg */
+ snd->maj_stat = GSS_S_BAD_NAME; /* XXX ? */
+ gss_release_name(&ignore_min_stat, &client_name);
+ goto out_err;
+ }
+ gss_release_name(&ignore_min_stat, &client_name);
+
+ /* Context complete. Pass handle_seq in out_handle to use
+ * for context lookup in the kernel. */
+ snd->out_handle.length = sizeof(snd->handle_seq);
+ memcpy(snd->out_handle.value, &snd->handle_seq,
+ sizeof(snd->handle_seq));
+
+ /* kernel needs ctx to calculate verifier on null response, so
+ * must give it context before doing null call: */
+ if (serialize_context_for_kernel(snd->ctx, &snd->ctx_token, mech)) {
+ printerr(0, "WARNING: handle_krb: "
+ "serialize_context_for_kernel failed\n");
+ snd->maj_stat = GSS_S_FAILURE;
+ goto out_err;
+ }
+ /* 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);
+
+ return 0;
+
+out_err:
+ if (snd->ctx != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context(&ignore_min_stat, &snd->ctx,
+ &ignore_out_tok);
+
+ return 1;
+}
+
/*
* return -1 only if we detect error during reading from upcall channel,
* all other cases return 0.
*/
-int
-handle_nullreq(FILE *f) {
- uint64_t handle_seq;
+int handle_channel_request(FILE *f)
+{
char in_tok_buf[TOKEN_BUF_SIZE];
char in_handle_buf[15];
char out_handle_buf[15];
- gss_buffer_desc in_tok = {.value = in_tok_buf},
- out_tok = {.value = NULL},
- in_handle = {.value = in_handle_buf},
- out_handle = {.value = out_handle_buf},
- ctx_token = {.value = NULL},
- ignore_out_tok = {.value = NULL},
- /* XXX isn't there a define for this?: */
- null_token = {.value = NULL};
- uint32_t lustre_svc;
- lnet_nid_t nid;
- u_int32_t ret_flags;
- gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
- gss_name_t client_name;
- gss_OID mech = GSS_C_NO_OID;
- gss_cred_id_t svc_cred;
- u_int32_t maj_stat = GSS_S_FAILURE, min_stat = 0;
- u_int32_t ignore_min_stat;
- int get_len;
- struct svc_cred cred;
- static char *lbuf = NULL;
- static int lbuflen = 0;
+ gss_buffer_desc ctx_token = {.value = NULL},
+ null_token = {.value = NULL};
+ uint32_t lustre_mech;
+ static char *lbuf;
+ static int lbuflen;
static char *cp;
-
- printerr(2, "handling null request\n");
-
+ int get_len;
+ int rc = 1;
+ u_int32_t ignore_min_stat;
+ struct svc_nego_data snd = {
+ .in_tok.value = in_tok_buf,
+ .in_handle.value = in_handle_buf,
+ .out_handle.value = out_handle_buf,
+ .maj_stat = GSS_S_FAILURE,
+ .ctx = GSS_C_NO_CONTEXT,
+ };
+
+ printerr(2, "handling request\n");
if (readline(fileno(f), &lbuf, &lbuflen) != 1) {
- printerr(0, "WARNING: handle_nullreq: "
- "failed reading request\n");
+ printerr(0, "WARNING: handle_req: failed reading request\n");
return -1;
}
cp = lbuf;
- qword_get(&cp, (char *) &lustre_svc, sizeof(lustre_svc));
- qword_get(&cp, (char *) &nid, sizeof(nid));
- qword_get(&cp, (char *) &handle_seq, sizeof(handle_seq));
- printerr(2, "handling req: svc %u, nid %016llx, idx %"PRIx64"\n",
- lustre_svc, nid, handle_seq);
+ /* see rsi_request() for the format of data being input here */
+ qword_get(&cp, (char *)&snd.lustre_svc, sizeof(snd.lustre_svc));
+
+ /* lustre_svc is the svc and gss subflavor */
+ lustre_mech = (snd.lustre_svc & LUSTRE_GSS_MECH_MASK) >>
+ LUSTRE_GSS_MECH_SHIFT;
+ snd.lustre_svc = snd.lustre_svc & LUSTRE_GSS_SVC_MASK;
+ switch (lustre_mech) {
+ case LGSS_MECH_KRB5:
+ if (!krb_enabled) {
+ printerr(1, "WARNING: Request for kerberos but service "
+ "support not enabled\n");
+ goto ignore;
+ }
+ snd.mech = &krb5oid;
+ break;
+ default:
+ printerr(0, "WARNING: invalid mechanism recevied: %d\n",
+ lustre_mech);
+ goto out_err;
+ 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));
+ printerr(2, "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, in_handle.value, sizeof(in_handle_buf));
+ get_len = qword_get(&cp, snd.in_handle.value, sizeof(in_handle_buf));
if (get_len < 0) {
- printerr(0, "WARNING: handle_nullreq: "
- "failed parsing request\n");
+ printerr(0, "WARNING: handle_req: failed parsing request\n");
goto out_err;
}
- in_handle.length = (size_t)get_len;
+ snd.in_handle.length = (size_t)get_len;
printerr(3, "in_handle:\n");
- print_hexl(3, in_handle.value, in_handle.length);
+ print_hexl(3, snd.in_handle.value, snd.in_handle.length);
- get_len = qword_get(&cp, in_tok.value, sizeof(in_tok_buf));
+ get_len = qword_get(&cp, snd.in_tok.value, sizeof(in_tok_buf));
if (get_len < 0) {
- printerr(0, "WARNING: handle_nullreq: "
- "failed parsing request\n");
+ printerr(0, "WARNING: handle_req: failed parsing request\n");
goto out_err;
}
- in_tok.length = (size_t)get_len;
+ snd.in_tok.length = (size_t)get_len;
printerr(3, "in_tok:\n");
- print_hexl(3, in_tok.value, in_tok.length);
+ print_hexl(3, snd.in_tok.value, snd.in_tok.length);
- if (in_handle.length != 0) { /* CONTINUE_INIT case */
- if (in_handle.length != sizeof(ctx)) {
- printerr(0, "WARNING: handle_nullreq: "
+ if (snd.in_handle.length != 0) { /* CONTINUE_INIT case */
+ if (snd.in_handle.length != sizeof(snd.ctx)) {
+ printerr(0, "WARNING: handle_req: "
"input handle has unexpected length %zu\n",
- in_handle.length);
+ snd.in_handle.length);
goto out_err;
}
/* in_handle is the context id stored in the out_handle
* for the GSS_S_CONTINUE_NEEDED case below. */
- memcpy(&ctx, in_handle.value, in_handle.length);
- }
-
- svc_cred = gssd_select_svc_cred(lustre_svc);
- if (!svc_cred) {
- printerr(0, "no service credential for svc %u\n", lustre_svc);
- goto out_err;
- }
-
- maj_stat = gss_accept_sec_context(&min_stat, &ctx, svc_cred,
- &in_tok, GSS_C_NO_CHANNEL_BINDINGS, &client_name,
- &mech, &out_tok, &ret_flags, NULL, NULL);
-
- if (maj_stat == GSS_S_CONTINUE_NEEDED) {
- printerr(1, "gss_accept_sec_context GSS_S_CONTINUE_NEEDED\n");
-
- /* Save the context handle for future calls */
- out_handle.length = sizeof(ctx);
- memcpy(out_handle.value, &ctx, sizeof(ctx));
- goto continue_needed;
- }
- else if (maj_stat != GSS_S_COMPLETE) {
- printerr(0, "WARNING: gss_accept_sec_context failed\n");
- pgsserr("handle_nullreq: gss_accept_sec_context",
- maj_stat, min_stat, mech);
- goto out_err;
+ memcpy(&snd.ctx, snd.in_handle.value, snd.in_handle.length);
}
- if (get_ids(client_name, mech, &cred, nid, lustre_svc)) {
- /* get_ids() prints error msg */
- maj_stat = GSS_S_BAD_NAME; /* XXX ? */
- gss_release_name(&ignore_min_stat, &client_name);
- goto out_err;
- }
- gss_release_name(&ignore_min_stat, &client_name);
-
- /* Context complete. Pass handle_seq in out_handle to use
- * for context lookup in the kernel. */
- out_handle.length = sizeof(handle_seq);
- memcpy(out_handle.value, &handle_seq, sizeof(handle_seq));
+ if (lustre_mech == LGSS_MECH_KRB5)
+ rc = handle_krb(&snd);
+ else
+ printerr(0, "WARNING: Received or request for"
+ "subflavor that is not enabled: %d\n", lustre_mech);
- /* kernel needs ctx to calculate verifier on null response, so
- * must give it context before doing null call: */
- if (serialize_context_for_kernel(ctx, &ctx_token, mech)) {
- printerr(0, "WARNING: handle_nullreq: "
- "serialize_context_for_kernel failed\n");
- maj_stat = GSS_S_FAILURE;
- goto out_err;
- }
- /* We no longer need the gss context */
- gss_delete_sec_context(&ignore_min_stat, &ctx, &ignore_out_tok);
+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);
- do_svc_downcall(&out_handle, &cred, mech, &ctx_token);
-continue_needed:
- send_response(f, &in_handle, &in_tok, maj_stat, min_stat,
- &out_handle, &out_tok);
-out:
- if (ctx_token.value != NULL)
+ /* cleanup buffers */
+ if (snd.ctx_token.value != NULL)
free(ctx_token.value);
- if (out_tok.value != NULL)
- gss_release_buffer(&ignore_min_stat, &out_tok);
- return 0;
+ if (snd.out_tok.value != NULL)
+ gss_release_buffer(&ignore_min_stat, &snd.out_tok);
-out_err:
- if (ctx != GSS_C_NO_CONTEXT)
- gss_delete_sec_context(&ignore_min_stat, &ctx, &ignore_out_tok);
- send_response(f, &in_handle, &in_tok, maj_stat, min_stat,
- &null_token, &null_token);
- goto out;
+ /* For junk wire data just ignore */
+ignore:
+ return 0;
}
+