From: Jeremy Filizetti Date: Tue, 6 Oct 2015 01:41:28 +0000 (-0400) Subject: LU-3289 gss: Interface and code changes for shared key X-Git-Tag: 2.8.55~76 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=9a163f389e96f8c3682391f8aa967a48e3daaaf4 LU-3289 gss: Interface and code changes for shared key This patch moves and modifies some of the kerberos code to be more general so it can be utilized by the sk and null gss implementations. This includes the userspace portion for lsvcgssd and the kernel pipefs interface. Since the gss interface has changed the version has also been incremented. Signed-off-by: Jeremy Filizetti Change-Id: Ib46b74c9b0e01c4f71f16d288eae83c5c1567bfb Reviewed-on: http://review.whamcloud.com/16728 Tested-by: Jenkins Reviewed-by: Andreas Dilger Tested-by: Andreas Dilger Reviewed-by: Oleg Drokin --- diff --git a/lustre.spec.in b/lustre.spec.in index f20e064..ce40332 100644 --- a/lustre.spec.in +++ b/lustre.spec.in @@ -337,6 +337,7 @@ echo '%{_sysconfdir}/ha.d/resource.d/Lustre' >>lustre.files # 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 diff --git a/lustre/conf/Makefile.am b/lustre/conf/Makefile.am index 9dd742d..ce11fe9 100644 --- a/lustre/conf/Makefile.am +++ b/lustre/conf/Makefile.am @@ -37,7 +37,7 @@ # 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 @@ -51,7 +51,7 @@ udevrules_DATA = 99-lustre.rules if RHEL if SERVER sysconfigdir = $(sysconfdir)/sysconfig -sysconfig_DATA = lustre +sysconfig_DATA = lustre lsvcgss endif endif diff --git a/lustre/conf/lsvcgss b/lustre/conf/lsvcgss new file mode 100644 index 0000000..9f930e0 --- /dev/null +++ b/lustre/conf/lsvcgss @@ -0,0 +1,2 @@ +# Optional arguments passed to lsvcgssd. +LSVCGSSDARGS='' diff --git a/lustre/include/lustre_nodemap.h b/lustre/include/lustre_nodemap.h index 82931c0..685e1d8 100644 --- a/lustre/include/lustre_nodemap.h +++ b/lustre/include/lustre_nodemap.h @@ -28,6 +28,7 @@ #define _LUSTRE_NODEMAP_H #include +#include #define LUSTRE_NODEMAP_NAME "nodemap" @@ -132,7 +133,11 @@ __u32 nodemap_map_id(struct lu_nodemap *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, diff --git a/lustre/ptlrpc/gss/Makefile.in b/lustre/ptlrpc/gss/Makefile.in index 6eec564..bcc076c 100644 --- a/lustre/ptlrpc/gss/Makefile.in +++ b/lustre/ptlrpc/gss/Makefile.in @@ -3,7 +3,7 @@ MODULES := ptlrpc_gss 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 diff --git a/lustre/ptlrpc/gss/gss_crypto.c b/lustre/ptlrpc/gss/gss_crypto.c new file mode 100644 index 0000000..2032f94 --- /dev/null +++ b/lustre/ptlrpc/gss/gss_crypto.c @@ -0,0 +1,496 @@ +/* + * Modifications for Lustre + * + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * + * Copyright (c) 2011, 2014, Intel Corporation. + * + * Author: Eric Mei + */ + +/* + * 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 + * J. Bruce Fields + * + * 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 +#include +#include + +#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); +} diff --git a/lustre/ptlrpc/gss/gss_crypto.h b/lustre/ptlrpc/gss/gss_crypto.h new file mode 100644 index 0000000..91d1a4b --- /dev/null +++ b/lustre/ptlrpc/gss/gss_crypto.h @@ -0,0 +1,81 @@ +/* + * Modifications for Lustre + * + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * + * Author: Eric Mei + */ + +/* + * 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 + * Bruce Fields + */ + +/* + * 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 */ diff --git a/lustre/ptlrpc/gss/gss_internal.h b/lustre/ptlrpc/gss/gss_internal.h index 690704e..0c95d8d 100644 --- a/lustre/ptlrpc/gss/gss_internal.h +++ b/lustre/ptlrpc/gss/gss_internal.h @@ -92,7 +92,11 @@ unsigned long gss_round_ctx_expiry(unsigned long expiry, /* * 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) diff --git a/lustre/ptlrpc/gss/gss_keyring.c b/lustre/ptlrpc/gss/gss_keyring.c index e8fbe50..1c28ede 100644 --- a/lustre/ptlrpc/gss/gss_keyring.c +++ b/lustre/ptlrpc/gss/gss_keyring.c @@ -726,7 +726,8 @@ struct ptlrpc_cli_ctx * gss_sec_lookup_ctx_kr(struct ptlrpc_sec *sec, char desc[24]; char *coinfo; int coinfo_size; - char *co_flags = ""; + const char *sec_part_flags = ""; + char svc_flag = '\0'; ENTRY; LASSERT(imp != NULL); @@ -759,34 +760,51 @@ struct ptlrpc_cli_ctx * gss_sec_lookup_ctx_kr(struct ptlrpc_sec *sec, /* 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) && @@ -795,24 +813,24 @@ struct ptlrpc_cli_ctx * gss_sec_lookup_ctx_kr(struct ptlrpc_sec *sec, 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); @@ -1070,7 +1088,7 @@ int gss_sec_display_kr(struct ptlrpc_sec *sec, struct seq_file *seq) 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, @@ -1382,49 +1400,49 @@ int gss_kt_update(struct key *key, const void *data, size_t datalen) 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 diff --git a/lustre/ptlrpc/gss/gss_krb5.h b/lustre/ptlrpc/gss/gss_krb5.h index 01edf15..97ad55e 100644 --- a/lustre/ptlrpc/gss/gss_krb5.h +++ b/lustre/ptlrpc/gss/gss_krb5.h @@ -47,6 +47,8 @@ #ifndef PTLRPC_GSS_KRB5_H #define PTLRPC_GSS_KRB5_H +#include "gss_crypto.h" + /* * RFC 4142 */ @@ -73,25 +75,20 @@ struct krb5_header { __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 { diff --git a/lustre/ptlrpc/gss/gss_krb5_mech.c b/lustre/ptlrpc/gss/gss_krb5_mech.c index 289ab08..acb6308 100644 --- a/lustre/ptlrpc/gss/gss_krb5_mech.c +++ b/lustre/ptlrpc/gss/gss_krb5_mech.c @@ -68,6 +68,7 @@ #include "gss_api.h" #include "gss_asn1.h" #include "gss_krb5.h" +#include "gss_crypto.h" static spinlock_t krb5_seq_lock; @@ -145,25 +146,6 @@ static const char * enctype2str(__u32 enctype) } 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; @@ -176,175 +158,104 @@ int krb5_init_keys(struct krb5_ctx *kctx) 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 */ @@ -355,58 +266,59 @@ out_err: 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; } /* @@ -418,15 +330,15 @@ static __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) { @@ -484,12 +396,12 @@ __u32 gss_copy_reverse_context_kerberos(struct gss_ctx *gctx, 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; @@ -509,7 +421,7 @@ __u32 gss_inquire_context_kerberos(struct gss_ctx *gctx, { 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; } @@ -523,254 +435,20 @@ void gss_delete_sec_context_kerberos(void *internal_ctx) } /* - * 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; @@ -786,12 +464,15 @@ __s32 krb5_make_checksum(__u32 enctype, 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; @@ -883,7 +564,7 @@ __u32 gss_get_mic_kerberos(struct gss_ctx *gctx, /* 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 */ @@ -920,7 +601,7 @@ __u32 gss_verify_mic_kerberos(struct gss_ctx *gctx, 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) { @@ -952,101 +633,6 @@ __u32 gss_verify_mic_kerberos(struct gss_ctx *gctx, 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. */ @@ -1077,21 +663,21 @@ int krb5_encrypt_bulk(struct crypto_blkcipher *tfm, 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); @@ -1124,22 +710,22 @@ int krb5_encrypt_bulk(struct crypto_blkcipher *tfm, } /* 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); @@ -1204,21 +790,21 @@ int krb5_decrypt_bulk(struct crypto_blkcipher *tfm, } /* 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); @@ -1309,23 +895,23 @@ int krb5_decrypt_bulk(struct crypto_blkcipher *tfm, 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); @@ -1371,7 +957,7 @@ __u32 gss_wrap_kerberos(struct gss_ctx *gctx, /* 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 */ @@ -1388,9 +974,9 @@ __u32 gss_wrap_kerberos(struct gss_ctx *gctx, } 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: @@ -1425,7 +1011,7 @@ __u32 gss_wrap_kerberos(struct gss_ctx *gctx, 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)); @@ -1452,8 +1038,7 @@ __u32 gss_wrap_kerberos(struct gss_ctx *gctx, 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: @@ -1461,8 +1046,8 @@ 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) { @@ -1545,7 +1130,7 @@ __u32 gss_wrap_bulk_kerberos(struct gss_ctx *gctx, /* 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 */ @@ -1602,7 +1187,7 @@ __u32 gss_wrap_bulk_kerberos(struct gss_ctx *gctx, 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) { @@ -1654,7 +1239,7 @@ __u32 gss_unwrap_kerberos(struct gss_ctx *gctx, 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) { @@ -1701,7 +1286,7 @@ __u32 gss_unwrap_kerberos(struct gss_ctx *gctx, 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; @@ -1732,8 +1317,8 @@ __u32 gss_unwrap_kerberos(struct gss_ctx *gctx, 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: @@ -1741,8 +1326,8 @@ 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) { @@ -1820,7 +1405,7 @@ __u32 gss_unwrap_bulk_kerberos(struct gss_ctx *gctx, 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) { diff --git a/lustre/ptlrpc/gss/gss_svc_upcall.c b/lustre/ptlrpc/gss/gss_svc_upcall.c index 2786d69..8944ef8 100644 --- a/lustre/ptlrpc/gss/gss_svc_upcall.c +++ b/lustre/ptlrpc/gss/gss_svc_upcall.c @@ -61,8 +61,9 @@ #include #include #include -#include #include +#include +#include #include #include "gss_err.h" @@ -132,7 +133,7 @@ static inline void _cache_unregister_net(struct cache_detail *cd, #endif } /**************************************** - * rsi cache * + * rpc sec init (rsi) cache * ****************************************/ #define RSI_HASHBITS (6) @@ -143,6 +144,7 @@ struct rsi { 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; @@ -180,6 +182,7 @@ static void rsi_free(struct rsi *rsi) 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) @@ -195,6 +198,8 @@ static void rsi_request(struct cache_detail *cd, 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'; @@ -225,6 +230,7 @@ static inline void __rsi_init(struct rsi *new, struct rsi *item) 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); } @@ -424,7 +430,7 @@ static struct rsi *rsi_update(struct rsi *new, struct rsi *old) } /**************************************** - * rsc cache * + * rpc sec context (rsc) cache * ****************************************/ #define RSC_HASHBITS (10) @@ -923,9 +929,11 @@ int gss_svc_upcall_handle_init(struct ptlrpc_request *req, 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)) { diff --git a/lustre/scripts/lsvcgss b/lustre/scripts/lsvcgss index 87c3b80..03d6233 100755 --- a/lustre/scripts/lsvcgss +++ b/lustre/scripts/lsvcgss @@ -10,12 +10,16 @@ . /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 ;; diff --git a/lustre/utils/gss/cacheio.c b/lustre/utils/gss/cacheio.c index 93eada7..bbb03d7 100644 --- a/lustre/utils/gss/cacheio.c +++ b/lustre/utils/gss/cacheio.c @@ -58,7 +58,7 @@ #include #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; @@ -154,7 +154,7 @@ void qword_addeol(char **bpp, int *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); diff --git a/lustre/utils/gss/cacheio.h b/lustre/utils/gss/cacheio.h index 4e2da47..365fcf1 100644 --- a/lustre/utils/gss/cacheio.h +++ b/lustre/utils/gss/cacheio.h @@ -33,12 +33,12 @@ #include -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); diff --git a/lustre/utils/gss/err_util.c b/lustre/utils/gss/err_util.c index fa457f5..76a172f 100644 --- a/lustre/utils/gss/err_util.c +++ b/lustre/utils/gss/err_util.c @@ -97,11 +97,15 @@ printit: 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); diff --git a/lustre/utils/gss/err_util.h b/lustre/utils/gss/err_util.h index 7fff5ba..0070a3b 100644 --- a/lustre/utils/gss/err_util.h +++ b/lustre/utils/gss/err_util.h @@ -35,5 +35,6 @@ void initerr(char *progname, int verbosity, int fg); 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_ */ diff --git a/lustre/utils/gss/gssd_proc.c b/lustre/utils/gss/gssd_proc.c index 10768ca..2429f5c 100644 --- a/lustre/utils/gss/gssd_proc.c +++ b/lustre/utils/gss/gssd_proc.c @@ -648,7 +648,7 @@ int do_negotiation(struct lustre_gss_data *lgd, 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; diff --git a/lustre/utils/gss/lgss_keyring.c b/lustre/utils/gss/lgss_keyring.c index c50f4b8..16e966e 100644 --- a/lustre/utils/gss/lgss_keyring.c +++ b/lustre/utils/gss/lgss_keyring.c @@ -67,23 +67,24 @@ static char *g_service = NULL; * 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; }; /* @@ -98,20 +99,21 @@ struct lgss_init_res { }; struct keyring_upcall_param { - uint32_t kup_ver; - uint32_t kup_secid; - uint32_t kup_uid; - uint32_t kup_fsuid; - uint32_t kup_gid; - uint32_t kup_fsgid; - uint32_t kup_svc; - uint64_t kup_nid; - 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; }; /**************************************** @@ -176,7 +178,7 @@ int do_nego_rpc(struct lgss_nego_data *lnd, 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 @@ -195,15 +197,21 @@ int do_nego_rpc(struct lgss_nego_data *lnd, 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); @@ -321,18 +329,18 @@ static int lgssc_negotiation(struct lgss_nego_data *lnd) * 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; @@ -474,21 +482,14 @@ out: 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 " @@ -517,29 +518,53 @@ static int lgssc_kr_negotiate(key_serial_t keyid, struct lgss_cred *cred, 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; } /* @@ -549,15 +574,16 @@ out_cred: * [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; @@ -584,9 +610,9 @@ static int parse_callout_info(const char *coinfo, } 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)); @@ -598,19 +624,20 @@ static int parse_callout_info(const char *coinfo, 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; } @@ -743,6 +770,8 @@ int main(int argc, char *argv[]) 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)) { diff --git a/lustre/utils/gss/lgss_utils.c b/lustre/utils/gss/lgss_utils.c index 6f13f8f..14f0f72 100644 --- a/lustre/utils/gss/lgss_utils.c +++ b/lustre/utils/gss/lgss_utils.c @@ -224,11 +224,23 @@ int lgss_mutex_unlock(lgss_mutex_id_t mid) ****************************************/ /* 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 * @@ -362,7 +374,7 @@ struct lgss_cred * lgss_create_cred(struct lgss_mech_type *mech) 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", @@ -374,7 +386,7 @@ int lgss_prepare_cred(struct lgss_cred *cred) { 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); @@ -387,13 +399,13 @@ void lgss_release_cred(struct lgss_cred *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); } @@ -403,7 +415,7 @@ int lgss_using_cred(struct lgss_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); @@ -412,6 +424,22 @@ int lgss_using_cred(struct lgss_cred *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 * ****************************************/ diff --git a/lustre/utils/gss/lgss_utils.h b/lustre/utils/gss/lgss_utils.h index 1c0e377..3417aa6 100644 --- a/lustre/utils/gss/lgss_utils.h +++ b/lustre/utils/gss/lgss_utils.h @@ -44,6 +44,8 @@ #include #include +#include "lsupport.h" + #define LGSS_SVC_MGS_STR "lustre_mgs" #define LGSS_SVC_MDS_STR "lustre_mds" #define LGSS_SVC_OSS_STR "lustre_oss" @@ -63,8 +65,8 @@ extern const char *lgss_svc_str[LGSS_SVC_MAX]; ****************************************/ 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); @@ -138,10 +140,8 @@ do { \ 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 * @@ -150,14 +150,17 @@ typedef enum { 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 { @@ -169,14 +172,17 @@ 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); @@ -188,13 +194,11 @@ void lgss_destroy_cred(struct lgss_cred *cred); 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) { diff --git a/lustre/utils/gss/lsupport.h b/lustre/utils/gss/lsupport.h index 0745ad1..f01b3cf 100644 --- a/lustre/utils/gss/lsupport.h +++ b/lustre/utils/gss/lsupport.h @@ -56,8 +56,18 @@ void gssd_exit_unique(int type); #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; diff --git a/lustre/utils/gss/svcgssd.c b/lustre/utils/gss/svcgssd.c index 457d991..4ae3a17 100644 --- a/lustre/utils/gss/svcgssd.c +++ b/lustre/utils/gss/svcgssd.c @@ -176,10 +176,18 @@ sig_hup(int signal) } 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); } @@ -191,35 +199,40 @@ main(int argc, char *argv[]) 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; } } @@ -230,23 +243,23 @@ main(int argc, char *argv[]) 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 " - "/@ 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 " + "/@ in " + "/etc/krb5.keytab?\n"); + exit(1); + } } if (!fg) diff --git a/lustre/utils/gss/svcgssd.h b/lustre/utils/gss/svcgssd.h index a2eece6..94b95a3 100644 --- a/lustre/utils/gss/svcgssd.h +++ b/lustre/utils/gss/svcgssd.h @@ -35,7 +35,9 @@ #include #include -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); diff --git a/lustre/utils/gss/svcgssd_main_loop.c b/lustre/utils/gss/svcgssd_main_loop.c index bd5fea7..c8cfb41 100644 --- a/lustre/utils/gss/svcgssd_main_loop.c +++ b/lustre/utils/gss/svcgssd_main_loop.c @@ -60,25 +60,25 @@ 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; } } @@ -95,7 +95,7 @@ svcgssd_run() 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", @@ -103,7 +103,7 @@ svcgssd_run() exit(1); } if (pollfd.revents & POLLIN) { - if (handle_nullreq(f) < 0) { + if (handle_channel_request(f) < 0) { fclose(f); f = NULL; } diff --git a/lustre/utils/gss/svcgssd_mech2file.c b/lustre/utils/gss/svcgssd_mech2file.c index 22c3ed8..ca98f42 100644 --- a/lustre/utils/gss/svcgssd_mech2file.c +++ b/lustre/utils/gss/svcgssd_mech2file.c @@ -44,30 +44,31 @@ (((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; } diff --git a/lustre/utils/gss/svcgssd_proc.c b/lustre/utils/gss/svcgssd_proc.c index 588b524..508a3ad 100644 --- a/lustre/utils/gss/svcgssd_proc.c +++ b/lustre/utils/gss/svcgssd_proc.c @@ -50,14 +50,20 @@ # include #endif +#include +#include + #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 + +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" @@ -73,16 +79,36 @@ struct svc_cred { 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) { @@ -93,7 +119,7 @@ do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred, } 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); @@ -101,7 +127,7 @@ do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred, 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); @@ -133,7 +159,7 @@ send_response(FILE *f, gss_buffer_desc *in_handle, gss_buffer_desc *in_token, 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); @@ -466,153 +492,198 @@ typedef struct gss_union_ctx_id_t { 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; } +