From 0109865363bf5da415f191cd74e9b5f737888547 Mon Sep 17 00:00:00 2001 From: Aurelien Degremont Date: Wed, 3 May 2023 16:48:49 +0200 Subject: [PATCH] LU-16848 gss: drop legacy 'lgssd' and pipefs code Get rid of the old 'lgssd' code which is unused for a while, and not even buildable. Test-Parameters: trivial Test-Parameters: testlist=sanity-sec Test-Parameters: kerberos=true testlist=sanity-krb5 Change-Id: I821cc5b625e97c7f5fdc758b166bd54e5e4b379e Signed-off-by: Aurelien Degremont Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/51032 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Sebastien Buisson Reviewed-by: Timothy Day Reviewed-by: Oleg Drokin --- lustre/autoconf/lustre-core.m4 | 3 - lustre/ptlrpc/gss/Makefile.in | 1 - lustre/ptlrpc/gss/gss_internal.h | 29 +- lustre/ptlrpc/gss/gss_pipefs.c | 1255 ------------------------------------- lustre/ptlrpc/gss/sec_gss.c | 7 - lustre/tests/sanity-krb5.sh | 44 -- lustre/tests/test-framework.sh | 19 - lustre/utils/gss/.gitignore | 1 - lustre/utils/gss/Makefile.am | 22 +- lustre/utils/gss/gss_util.c | 9 +- lustre/utils/gss/gss_util.h | 1 - lustre/utils/gss/gssd.c | 262 -------- lustre/utils/gss/gssd.h | 97 --- lustre/utils/gss/gssd_main_loop.c | 166 ----- lustre/utils/gss/gssd_proc.c | 877 -------------------------- lustre/utils/gss/krb5_util.c | 1002 ----------------------------- lustre/utils/gss/krb5_util.h | 30 - lustre/utils/gss/lsupport.c | 2 +- lustre/utils/gss/write_bytes.h | 80 --- 19 files changed, 10 insertions(+), 3897 deletions(-) delete mode 100644 lustre/ptlrpc/gss/gss_pipefs.c delete mode 100644 lustre/utils/gss/gssd.c delete mode 100644 lustre/utils/gss/gssd.h delete mode 100644 lustre/utils/gss/gssd_main_loop.c delete mode 100644 lustre/utils/gss/gssd_proc.c delete mode 100644 lustre/utils/gss/krb5_util.c delete mode 100644 lustre/utils/gss/krb5_util.h diff --git a/lustre/autoconf/lustre-core.m4 b/lustre/autoconf/lustre-core.m4 index ee485d3..9fc136e 100644 --- a/lustre/autoconf/lustre-core.m4 +++ b/lustre/autoconf/lustre-core.m4 @@ -4458,8 +4458,6 @@ AS_IF([test $target_cpu == "i686" -o $target_cpu == "x86_64"], LC_MDS_MAX_THREADS # lustre/utils/gss/gss_util.c -# lustre/utils/gss/gssd_proc.c -# lustre/utils/gss/krb5_util.c # lustre/utils/llog_reader.c # lustre/utils/create_iam.c # lustre/utils/libiam.c @@ -4627,7 +4625,6 @@ AM_CONDITIONAL(SPLIT, test x$enable_split = xyes) AM_CONDITIONAL(EXT2FS_DEVEL, test x$ac_cv_header_ext2fs_ext2fs_h = xyes) AM_CONDITIONAL(GSS, test x$enable_gss = xyes) AM_CONDITIONAL(GSS_KEYRING, test x$enable_gss_keyring = xyes) -AM_CONDITIONAL(GSS_PIPEFS, test x$enable_gss_pipefs = xyes) AM_CONDITIONAL(GSS_SSK, test x$enable_ssk = xyes) AM_CONDITIONAL(LIBPTHREAD, test x$enable_libpthread = xyes) AM_CONDITIONAL(HAVE_SYSTEMD, test "x$with_systemdsystemunitdir" != "xno") diff --git a/lustre/ptlrpc/gss/Makefile.in b/lustre/ptlrpc/gss/Makefile.in index 578cc09..3d1e0f8 100644 --- a/lustre/ptlrpc/gss/Makefile.in +++ b/lustre/ptlrpc/gss/Makefile.in @@ -7,7 +7,6 @@ ptlrpc_gss-objs := sec_gss.o gss_bulk.o gss_cli_upcall.o gss_svc_upcall.o \ @GSS_SSK_TRUE@ptlrpc_gss-objs += gss_sk_mech.o @GSS_KEYRING_TRUE@ptlrpc_gss-objs += gss_keyring.o -@GSS_PIPEFS_TRUE@ptlrpc_gss-objs += gss_pipefs.o default: all diff --git a/lustre/ptlrpc/gss/gss_internal.h b/lustre/ptlrpc/gss/gss_internal.h index d8302ba..f27779f 100644 --- a/lustre/ptlrpc/gss/gss_internal.h +++ b/lustre/ptlrpc/gss/gss_internal.h @@ -45,17 +45,10 @@ int buffer_extract_bytes(const void **buf, __u32 *buflen, void *res, __u32 reslen); /* - * several timeout values. client refresh upcall timeout we using - * default in pipefs implemnetation. + * several timeout values. client refresh upcall timeout */ #define __TIMEOUT_DELTA (10) -#define GSS_SECINIT_RPC_TIMEOUT \ - (obd_timeout < __TIMEOUT_DELTA ? \ - __TIMEOUT_DELTA : obd_timeout - __TIMEOUT_DELTA) - -#define GSS_SECFINI_RPC_TIMEOUT (__TIMEOUT_DELTA) -#define GSS_SECSVC_UPCALL_TIMEOUT (GSS_SECINIT_RPC_TIMEOUT) /* * default gc interval @@ -231,12 +224,6 @@ struct gss_sec { __u64 gs_rvs_hdl; }; -struct gss_sec_pipefs { - struct gss_sec gsp_base; - int gsp_chash_size; /* must be 2^n */ - struct hlist_head gsp_chash[0]; -}; - /* * FIXME cleanup the keyring upcall mutexes */ @@ -280,11 +267,6 @@ static inline struct gss_sec *sec2gsec(struct ptlrpc_sec *sec) return container_of(sec, struct gss_sec, gs_base); } -static inline struct gss_sec_pipefs *sec2gsec_pipefs(struct ptlrpc_sec *sec) -{ - return container_of(sec2gsec(sec), struct gss_sec_pipefs, gsp_base); -} - static inline struct gss_sec_keyring *sec2gsec_keyring(struct ptlrpc_sec *sec) { return container_of(sec2gsec(sec), struct gss_sec_keyring, gsk_base); @@ -390,15 +372,6 @@ void __exit gss_exit_keyring(void); #endif extern unsigned int gss_check_upcall_ns; -/* gss_pipefs.c */ -#ifndef HAVE_GSS_PIPEFS -static inline int __init gss_init_pipefs(void) { return 0; } -static inline void __exit gss_exit_pipefs(void) { return; } -#else -int __init gss_init_pipefs(void); -void __exit gss_exit_pipefs(void); -#endif - /* gss_bulk.c */ int gss_cli_prep_bulk(struct ptlrpc_request *req, struct ptlrpc_bulk_desc *desc); diff --git a/lustre/ptlrpc/gss/gss_pipefs.c b/lustre/ptlrpc/gss/gss_pipefs.c deleted file mode 100644 index 4a21cc7..0000000 --- a/lustre/ptlrpc/gss/gss_pipefs.c +++ /dev/null @@ -1,1255 +0,0 @@ -/* - * Modifications for Lustre - * - * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * - * Copyright (c) 2012, 2016, Intel Corporation. - * - * Author: Eric Mei - */ - -/* - * linux/net/sunrpc/auth_gss.c - * - * RPCSEC_GSS client authentication. - * - * Copyright (c) 2000 The Regents of the University of Michigan. - * All rights reserved. - * - * Dug Song - * Andy Adamson - * - * 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 -#include -#include -#include -#include -struct rpc_clnt; /* for rpc_pipefs */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gss_err.h" -#include "gss_internal.h" -#include "gss_api.h" - -static struct ptlrpc_sec_policy gss_policy_pipefs; -static struct ptlrpc_ctx_ops gss_pipefs_ctxops; - -static int gss_cli_ctx_refresh_pf(struct ptlrpc_cli_ctx *ctx); - -static int gss_sec_pipe_upcall_init(struct gss_sec *gsec) -{ - return 0; -} - -static void gss_sec_pipe_upcall_fini(struct gss_sec *gsec) -{ -} - -/**************************************** - * internal context helpers * - ****************************************/ - -static -struct ptlrpc_cli_ctx *ctx_create_pf(struct ptlrpc_sec *sec, - struct vfs_cred *vcred) -{ - struct gss_cli_ctx *gctx; - int rc; - - OBD_ALLOC_PTR(gctx); - if (gctx == NULL) - return NULL; - - rc = gss_cli_ctx_init_common(sec, &gctx->gc_base, - &gss_pipefs_ctxops, vcred); - if (rc) { - OBD_FREE_PTR(gctx); - return NULL; - } - - return &gctx->gc_base; -} - -static -void ctx_destroy_pf(struct ptlrpc_sec *sec, struct ptlrpc_cli_ctx *ctx) -{ - struct gss_cli_ctx *gctx = ctx2gctx(ctx); - - if (gss_cli_ctx_fini_common(sec, ctx)) - return; - - OBD_FREE_PTR(gctx); - - atomic_dec(&sec->ps_nctx); - sptlrpc_sec_put(sec); -} - -static -void ctx_enhash_pf(struct ptlrpc_cli_ctx *ctx, struct hlist_head *hash) -{ - set_bit(PTLRPC_CTX_CACHED_BIT, &ctx->cc_flags); - atomic_inc(&ctx->cc_refcount); - hlist_add_head(&ctx->cc_cache, hash); -} - -/* - * caller must hold spinlock - */ -static -void ctx_unhash_pf(struct ptlrpc_cli_ctx *ctx, struct hlist_head *freelist) -{ - assert_spin_locked(&ctx->cc_sec->ps_lock); - LASSERT(atomic_read(&ctx->cc_refcount) > 0); - LASSERT(test_bit(PTLRPC_CTX_CACHED_BIT, &ctx->cc_flags)); - LASSERT(!hlist_unhashed(&ctx->cc_cache)); - - clear_bit(PTLRPC_CTX_CACHED_BIT, &ctx->cc_flags); - - if (atomic_dec_and_test(&ctx->cc_refcount)) { - __hlist_del(&ctx->cc_cache); - hlist_add_head(&ctx->cc_cache, freelist); - } else { - hlist_del_init(&ctx->cc_cache); - } -} - -/* - * return 1 if the context is dead. - */ -static -int ctx_check_death_pf(struct ptlrpc_cli_ctx *ctx, - struct hlist_head *freelist) -{ - if (cli_ctx_check_death(ctx)) { - if (freelist) - ctx_unhash_pf(ctx, freelist); - return 1; - } - - return 0; -} - -static inline -int ctx_check_death_locked_pf(struct ptlrpc_cli_ctx *ctx, - struct hlist_head *freelist) -{ - LASSERT(ctx->cc_sec); - LASSERT(atomic_read(&ctx->cc_refcount) > 0); - LASSERT(test_bit(PTLRPC_CTX_CACHED_BIT, &ctx->cc_flags)); - - return ctx_check_death_pf(ctx, freelist); -} - -static inline -int ctx_match_pf(struct ptlrpc_cli_ctx *ctx, struct vfs_cred *vcred) -{ - /* a little bit optimization for null policy */ - if (!ctx->cc_ops->match) - return 1; - - return ctx->cc_ops->match(ctx, vcred); -} - -static -void ctx_list_destroy_pf(struct hlist_head *head) -{ - struct ptlrpc_cli_ctx *ctx; - - while (!hlist_empty(head)) { - ctx = cfs_hlist_entry(head->first, struct ptlrpc_cli_ctx, - cc_cache); - - LASSERT(atomic_read(&ctx->cc_refcount) == 0); - LASSERT(test_bit(PTLRPC_CTX_CACHED_BIT, - &ctx->cc_flags) == 0); - - hlist_del_init(&ctx->cc_cache); - ctx_destroy_pf(ctx->cc_sec, ctx); - } -} - -/**************************************** - * context apis * - ****************************************/ - -static -int gss_cli_ctx_validate_pf(struct ptlrpc_cli_ctx *ctx) -{ - if (ctx_check_death_pf(ctx, NULL)) - return 1; - if (cli_ctx_is_ready(ctx)) - return 0; - return 1; -} - -static -void gss_cli_ctx_die_pf(struct ptlrpc_cli_ctx *ctx, int grace) -{ - LASSERT(ctx->cc_sec); - LASSERT(atomic_read(&ctx->cc_refcount) > 0); - - cli_ctx_expire(ctx); - - spin_lock(&ctx->cc_sec->ps_lock); - - if (test_and_clear_bit(PTLRPC_CTX_CACHED_BIT, &ctx->cc_flags)) { - LASSERT(!hlist_unhashed(&ctx->cc_cache)); - LASSERT(atomic_read(&ctx->cc_refcount) > 1); - - hlist_del_init(&ctx->cc_cache); - if (atomic_dec_and_test(&ctx->cc_refcount)) - LBUG(); - } - - spin_unlock(&ctx->cc_sec->ps_lock); -} - -/**************************************** - * reverse context installation * - ****************************************/ - -static inline -unsigned int ctx_hash_index(int hashsize, __u64 key) -{ - return (unsigned int) (key & ((__u64) hashsize - 1)); -} - -static -void gss_sec_ctx_replace_pf(struct gss_sec *gsec, - struct ptlrpc_cli_ctx *new) -{ - struct hlist_node __maybe_unused *pos, *next; - struct gss_sec_pipefs *gsec_pf; - struct ptlrpc_cli_ctx *ctx; - HLIST_HEAD(freelist); - unsigned int hash; - ENTRY; - - gsec_pf = container_of(gsec, struct gss_sec_pipefs, gsp_base); - - hash = ctx_hash_index(gsec_pf->gsp_chash_size, - (__u64) new->cc_vcred.vc_uid); - LASSERT(hash < gsec_pf->gsp_chash_size); - - spin_lock(&gsec->gs_base.ps_lock); - - cfs_hlist_for_each_entry_safe(ctx, pos, next, - &gsec_pf->gsp_chash[hash], cc_cache) { - if (!ctx_match_pf(ctx, &new->cc_vcred)) - continue; - - cli_ctx_expire(ctx); - ctx_unhash_pf(ctx, &freelist); - break; - } - - ctx_enhash_pf(new, &gsec_pf->gsp_chash[hash]); - - spin_unlock(&gsec->gs_base.ps_lock); - - ctx_list_destroy_pf(&freelist); - EXIT; -} - -static -int gss_install_rvs_cli_ctx_pf(struct gss_sec *gsec, - struct ptlrpc_svc_ctx *svc_ctx) -{ - struct vfs_cred vcred; - struct ptlrpc_cli_ctx *cli_ctx; - int rc; - ENTRY; - - vcred.vc_uid = 0; - vcred.vc_gid = 0; - - cli_ctx = ctx_create_pf(&gsec->gs_base, &vcred); - if (!cli_ctx) - RETURN(-ENOMEM); - - rc = gss_copy_rvc_cli_ctx(cli_ctx, svc_ctx); - if (rc) { - ctx_destroy_pf(cli_ctx->cc_sec, cli_ctx); - RETURN(rc); - } - - gss_sec_ctx_replace_pf(gsec, cli_ctx); - RETURN(0); -} - -static -void gss_ctx_cache_gc_pf(struct gss_sec_pipefs *gsec_pf, - struct hlist_head *freelist) -{ - struct ptlrpc_sec *sec; - struct ptlrpc_cli_ctx *ctx; - struct hlist_node __maybe_unused *pos; - struct hlist_node *next; - int i; - ENTRY; - - sec = &gsec_pf->gsp_base.gs_base; - - CDEBUG(D_SEC, "do gc on sec %s@%p\n", sec->ps_policy->sp_name, sec); - - for (i = 0; i < gsec_pf->gsp_chash_size; i++) { - cfs_hlist_for_each_entry_safe(ctx, pos, next, - &gsec_pf->gsp_chash[i], cc_cache) - ctx_check_death_locked_pf(ctx, freelist); - } - - sec->ps_gc_next = ktime_get_real_seconds() + sec->ps_gc_interval; - EXIT; -} - -static -struct ptlrpc_sec* gss_sec_create_pf(struct obd_import *imp, - struct ptlrpc_svc_ctx *ctx, - struct sptlrpc_flavor *sf) -{ - struct gss_sec_pipefs *gsec_pf; - int alloc_size, hash_size, i; - ENTRY; - -#define GSS_SEC_PIPEFS_CTX_HASH_SIZE (32) - - if (ctx || - sf->sf_flags & (PTLRPC_SEC_FL_ROOTONLY | PTLRPC_SEC_FL_REVERSE)) - hash_size = 1; - else - hash_size = GSS_SEC_PIPEFS_CTX_HASH_SIZE; - - alloc_size = sizeof(*gsec_pf) + - sizeof(struct hlist_head) * hash_size; - - OBD_ALLOC(gsec_pf, alloc_size); - if (!gsec_pf) - RETURN(NULL); - - gsec_pf->gsp_chash_size = hash_size; - for (i = 0; i < hash_size; i++) - INIT_HLIST_HEAD(&gsec_pf->gsp_chash[i]); - - if (gss_sec_create_common(&gsec_pf->gsp_base, &gss_policy_pipefs, - imp, ctx, sf)) - goto err_free; - - if (ctx == NULL) { - if (gss_sec_pipe_upcall_init(&gsec_pf->gsp_base)) - goto err_destroy; - } else { - if (gss_install_rvs_cli_ctx_pf(&gsec_pf->gsp_base, ctx)) - goto err_destroy; - } - - RETURN(&gsec_pf->gsp_base.gs_base); - -err_destroy: - gss_sec_destroy_common(&gsec_pf->gsp_base); -err_free: - OBD_FREE(gsec_pf, alloc_size); - RETURN(NULL); -} - -static -void gss_sec_destroy_pf(struct ptlrpc_sec *sec) -{ - struct gss_sec_pipefs *gsec_pf; - struct gss_sec *gsec; - - CWARN("destroy %s@%p\n", sec->ps_policy->sp_name, sec); - - gsec = container_of(sec, struct gss_sec, gs_base); - gsec_pf = container_of(gsec, struct gss_sec_pipefs, gsp_base); - - LASSERT(gsec_pf->gsp_chash); - LASSERT(gsec_pf->gsp_chash_size); - - gss_sec_pipe_upcall_fini(gsec); - - gss_sec_destroy_common(gsec); - - OBD_FREE(gsec, sizeof(*gsec_pf) + - sizeof(struct hlist_head) * gsec_pf->gsp_chash_size); -} - -static -struct ptlrpc_cli_ctx * gss_sec_lookup_ctx_pf(struct ptlrpc_sec *sec, - struct vfs_cred *vcred, - int create, int remove_dead) -{ - struct gss_sec *gsec; - struct gss_sec_pipefs *gsec_pf; - struct ptlrpc_cli_ctx *ctx = NULL, *new = NULL; - struct hlist_head *hash_head; - struct hlist_node __maybe_unused *pos, *next; - unsigned int hash, gc = 0, found = 0; - HLIST_HEAD(freelist); - ENTRY; - - might_sleep(); - - gsec = container_of(sec, struct gss_sec, gs_base); - gsec_pf = container_of(gsec, struct gss_sec_pipefs, gsp_base); - - hash = ctx_hash_index(gsec_pf->gsp_chash_size, - (__u64) vcred->vc_uid); - hash_head = &gsec_pf->gsp_chash[hash]; - LASSERT(hash < gsec_pf->gsp_chash_size); - -retry: - spin_lock(&sec->ps_lock); - - /* gc_next == 0 means never do gc */ - if (remove_dead && sec->ps_gc_next && - (ktime_get_real_seconds() > sec->ps_gc_next)) { - gss_ctx_cache_gc_pf(gsec_pf, &freelist); - gc = 1; - } - - cfs_hlist_for_each_entry_safe(ctx, pos, next, hash_head, cc_cache) { - if (gc == 0 && - ctx_check_death_locked_pf(ctx, - remove_dead ? &freelist : NULL)) - continue; - - if (ctx_match_pf(ctx, vcred)) { - found = 1; - break; - } - } - - if (found) { - if (new && new != ctx) { - /* lost the race, just free it */ - hlist_add_head(&new->cc_cache, &freelist); - new = NULL; - } - - /* hot node, move to head */ - if (hash_head->first != &ctx->cc_cache) { - __hlist_del(&ctx->cc_cache); - hlist_add_head(&ctx->cc_cache, hash_head); - } - } else { - /* don't allocate for reverse sec */ - if (sec_is_reverse(sec)) { - spin_unlock(&sec->ps_lock); - RETURN(NULL); - } - - if (new) { - ctx_enhash_pf(new, hash_head); - ctx = new; - } else if (create) { - spin_unlock(&sec->ps_lock); - new = ctx_create_pf(sec, vcred); - if (new) { - clear_bit(PTLRPC_CTX_NEW_BIT, &new->cc_flags); - goto retry; - } - } else { - ctx = NULL; - } - } - - /* hold a ref */ - if (ctx) - atomic_inc(&ctx->cc_refcount); - - spin_unlock(&sec->ps_lock); - - /* the allocator of the context must give the first push to refresh */ - if (new) { - LASSERT(new == ctx); - gss_cli_ctx_refresh_pf(new); - } - - ctx_list_destroy_pf(&freelist); - RETURN(ctx); -} - -static -void gss_sec_release_ctx_pf(struct ptlrpc_sec *sec, - struct ptlrpc_cli_ctx *ctx, - int sync) -{ - LASSERT(test_bit(PTLRPC_CTX_CACHED_BIT, &ctx->cc_flags) == 0); - LASSERT(hlist_unhashed(&ctx->cc_cache)); - - /* if required async, we must clear the UPTODATE bit to prevent extra - * rpcs during destroy procedure. */ - if (!sync) - clear_bit(PTLRPC_CTX_UPTODATE_BIT, &ctx->cc_flags); - - /* destroy this context */ - ctx_destroy_pf(sec, ctx); -} - -/* - * @uid: which user. "-1" means flush all. - * @grace: mark context DEAD, allow graceful destroy like notify - * server side, etc. - * @force: also flush busy entries. - * - * return the number of busy context encountered. - * - * In any cases, never touch "eternal" contexts. - */ -static -int gss_sec_flush_ctx_cache_pf(struct ptlrpc_sec *sec, - uid_t uid, - int grace, int force) -{ - struct gss_sec *gsec; - struct gss_sec_pipefs *gsec_pf; - struct ptlrpc_cli_ctx *ctx; - struct hlist_node __maybe_unused *pos, *next; - HLIST_HEAD(freelist); - int i, busy = 0; - ENTRY; - - might_sleep_if(grace); - - gsec = container_of(sec, struct gss_sec, gs_base); - gsec_pf = container_of(gsec, struct gss_sec_pipefs, gsp_base); - - spin_lock(&sec->ps_lock); - for (i = 0; i < gsec_pf->gsp_chash_size; i++) { - cfs_hlist_for_each_entry_safe(ctx, pos, next, - &gsec_pf->gsp_chash[i], - cc_cache) { - LASSERT(atomic_read(&ctx->cc_refcount) > 0); - - if (uid != -1 && uid != ctx->cc_vcred.vc_uid) - continue; - - if (atomic_read(&ctx->cc_refcount) > 1) { - busy++; - if (!force) - continue; - - CWARN("flush busy(%d) ctx %p(%u->%s) by force, " - "grace %d\n", - atomic_read(&ctx->cc_refcount), - ctx, ctx->cc_vcred.vc_uid, - sec2target_str(ctx->cc_sec), grace); - } - ctx_unhash_pf(ctx, &freelist); - - set_bit(PTLRPC_CTX_DEAD_BIT, &ctx->cc_flags); - if (!grace) - clear_bit(PTLRPC_CTX_UPTODATE_BIT, - &ctx->cc_flags); - } - } - spin_unlock(&sec->ps_lock); - - ctx_list_destroy_pf(&freelist); - RETURN(busy); -} - -/**************************************** - * service apis * - ****************************************/ - -static -int gss_svc_accept_pf(struct ptlrpc_request *req) -{ - return gss_svc_accept(&gss_policy_pipefs, req); -} - -static -int gss_svc_install_rctx_pf(struct obd_import *imp, - struct ptlrpc_svc_ctx *ctx) -{ - struct ptlrpc_sec *sec; - int rc; - - sec = sptlrpc_import_sec_ref(imp); - LASSERT(sec); - rc = gss_install_rvs_cli_ctx_pf(sec2gsec(sec), ctx); - - sptlrpc_sec_put(sec); - return rc; -} - -/**************************************** - * rpc_pipefs definitions * - ****************************************/ - -#define LUSTRE_PIPE_ROOT "/lustre" -#define LUSTRE_PIPE_KRB5 LUSTRE_PIPE_ROOT"/krb5" - -struct gss_upcall_msg_data { - __u32 gum_seq; - __u32 gum_uid; - __u32 gum_gid; - __u32 gum_svc; /* MDS/OSS... */ - __u64 gum_nid; /* peer NID */ - __u8 gum_obd[64]; /* client obd name */ -}; - -struct gss_upcall_msg { - struct rpc_pipe_msg gum_base; - atomic_t gum_refcount; - struct list_head gum_list; - __u32 gum_mechidx; - struct gss_sec *gum_gsec; - struct gss_cli_ctx *gum_gctx; - struct gss_upcall_msg_data gum_data; -}; - -static atomic_t upcall_seq = ATOMIC_INIT(0); - -static inline -__u32 upcall_get_sequence(void) -{ - return (__u32) atomic_inc_return(&upcall_seq); -} - -enum mech_idx_t { - MECH_KRB5 = 0, - MECH_MAX -}; - -static inline -__u32 mech_name2idx(const char *name) -{ - LASSERT(!strcmp(name, "krb5")); - return MECH_KRB5; -} - -/* pipefs dentries for each mechanisms */ -static struct dentry *de_pipes[MECH_MAX] = { NULL, }; -/* all upcall messgaes linked here */ -static struct list_head upcall_lists[MECH_MAX]; -/* and protected by this */ -static spinlock_t upcall_locks[MECH_MAX]; - -static inline -void upcall_list_lock(int idx) -{ - spin_lock(&upcall_locks[idx]); -} - -static inline -void upcall_list_unlock(int idx) -{ - spin_unlock(&upcall_locks[idx]); -} - -static -void upcall_msg_enlist(struct gss_upcall_msg *msg) -{ - __u32 idx = msg->gum_mechidx; - - upcall_list_lock(idx); - list_add(&msg->gum_list, &upcall_lists[idx]); - upcall_list_unlock(idx); -} - -static -void upcall_msg_delist(struct gss_upcall_msg *msg) -{ - __u32 idx = msg->gum_mechidx; - - upcall_list_lock(idx); - list_del_init(&msg->gum_list); - upcall_list_unlock(idx); -} - -/**************************************** - * rpc_pipefs upcall helpers * - ****************************************/ - -static -void gss_release_msg(struct gss_upcall_msg *gmsg) -{ - ENTRY; - LASSERT(atomic_read(&gmsg->gum_refcount) > 0); - - if (!atomic_dec_and_test(&gmsg->gum_refcount)) { - EXIT; - return; - } - - if (gmsg->gum_gctx) { - sptlrpc_cli_ctx_wakeup(&gmsg->gum_gctx->gc_base); - sptlrpc_cli_ctx_put(&gmsg->gum_gctx->gc_base, 1); - gmsg->gum_gctx = NULL; - } - - LASSERT(list_empty(&gmsg->gum_list)); - LASSERT(list_empty(&gmsg->gum_base.list)); - OBD_FREE_PTR(gmsg); - EXIT; -} - -static -void gss_unhash_msg_nolock(struct gss_upcall_msg *gmsg) -{ - __u32 idx = gmsg->gum_mechidx; - - LASSERT(idx < MECH_MAX); - assert_spin_locked(&upcall_locks[idx]); - - if (list_empty(&gmsg->gum_list)) - return; - - list_del_init(&gmsg->gum_list); - LASSERT(atomic_read(&gmsg->gum_refcount) > 1); - atomic_dec(&gmsg->gum_refcount); -} - -static -void gss_unhash_msg(struct gss_upcall_msg *gmsg) -{ - __u32 idx = gmsg->gum_mechidx; - - LASSERT(idx < MECH_MAX); - upcall_list_lock(idx); - gss_unhash_msg_nolock(gmsg); - upcall_list_unlock(idx); -} - -static -void gss_msg_fail_ctx(struct gss_upcall_msg *gmsg) -{ - if (gmsg->gum_gctx) { - struct ptlrpc_cli_ctx *ctx = &gmsg->gum_gctx->gc_base; - - LASSERT(atomic_read(&ctx->cc_refcount) > 0); - sptlrpc_cli_ctx_expire(ctx); - set_bit(PTLRPC_CTX_ERROR_BIT, &ctx->cc_flags); - } -} - -static -struct gss_upcall_msg * gss_find_upcall(__u32 mechidx, __u32 seq) -{ - struct gss_upcall_msg *gmsg; - - upcall_list_lock(mechidx); - list_for_each_entry(gmsg, &upcall_lists[mechidx], gum_list) { - if (gmsg->gum_data.gum_seq != seq) - continue; - - LASSERT(atomic_read(&gmsg->gum_refcount) > 0); - LASSERT(gmsg->gum_mechidx == mechidx); - - atomic_inc(&gmsg->gum_refcount); - upcall_list_unlock(mechidx); - return gmsg; - } - upcall_list_unlock(mechidx); - return NULL; -} - -static -int simple_get_bytes(char **buf, __u32 *buflen, void *res, __u32 reslen) -{ - if (*buflen < reslen) { - CERROR("shorter buflen than needed: %u < %u\n", - *buflen, reslen); - return -EINVAL; - } - - memcpy(res, *buf, reslen); - *buf += reslen; - *buflen -= reslen; - return 0; -} - -/**************************************** - * rpc_pipefs apis * - ****************************************/ - -static -ssize_t gss_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg, - char *dst, size_t buflen) -{ - char *data = (char *)msg->data + msg->copied; - ssize_t mlen = msg->len; - ssize_t left; - ENTRY; - - if (mlen > buflen) - mlen = buflen; - left = copy_to_user(dst, data, mlen); - if (left < 0) { - msg->errno = left; - RETURN(left); - } - mlen -= left; - msg->copied += mlen; - msg->errno = 0; - RETURN(mlen); -} - -static -ssize_t gss_pipe_downcall(struct file *filp, const char *src, size_t mlen) -{ - struct rpc_inode *rpci = RPC_I(file_inode(filp)); - struct gss_upcall_msg *gss_msg; - struct ptlrpc_cli_ctx *ctx; - struct gss_cli_ctx *gctx = NULL; - char *buf, *data; - int datalen; - int timeout, rc; - __u32 mechidx, seq, gss_err; - ENTRY; - - mechidx = (__u32) (long) rpci->private; - LASSERT(mechidx < MECH_MAX); - - OBD_ALLOC(buf, mlen); - if (!buf) - RETURN(-ENOMEM); - - if (copy_from_user(buf, src, mlen)) { - CERROR("failed copy user space data\n"); - GOTO(out_free, rc = -EFAULT); - } - data = buf; - datalen = mlen; - - /* data passed down format: - * - seq - * - timeout - * - gc_win / error - * - wire_ctx (rawobj) - * - mech_ctx (rawobj) - */ - if (simple_get_bytes(&data, &datalen, &seq, sizeof(seq))) { - CERROR("fail to get seq\n"); - GOTO(out_free, rc = -EFAULT); - } - - gss_msg = gss_find_upcall(mechidx, seq); - if (!gss_msg) { - CERROR("upcall %u has aborted earlier\n", seq); - GOTO(out_free, rc = -EINVAL); - } - - gss_unhash_msg(gss_msg); - gctx = gss_msg->gum_gctx; - LASSERT(gctx); - LASSERT(atomic_read(&gctx->gc_base.cc_refcount) > 0); - - /* timeout is not in use for now */ - if (simple_get_bytes(&data, &datalen, &timeout, sizeof(timeout))) - GOTO(out_msg, rc = -EFAULT); - - /* lgssd signal an error by gc_win == 0 */ - if (simple_get_bytes(&data, &datalen, &gctx->gc_win, - sizeof(gctx->gc_win))) - GOTO(out_msg, rc = -EFAULT); - - if (gctx->gc_win == 0) { - /* followed by: - * - rpc error - * - gss error - */ - if (simple_get_bytes(&data, &datalen, &rc, sizeof(rc))) - GOTO(out_msg, rc = -EFAULT); - if (simple_get_bytes(&data, &datalen, &gss_err,sizeof(gss_err))) - GOTO(out_msg, rc = -EFAULT); - - if (rc == 0 && gss_err == GSS_S_COMPLETE) { - CWARN("both rpc & gss error code not set\n"); - rc = -EPERM; - } - } else { - rawobj_t tmpobj; - - /* handle */ - if (rawobj_extract_local(&tmpobj, (__u32 **) &data, &datalen)) - GOTO(out_msg, rc = -EFAULT); - if (rawobj_dup(&gctx->gc_handle, &tmpobj)) - GOTO(out_msg, rc = -ENOMEM); - - /* mechctx */ - if (rawobj_extract_local(&tmpobj, (__u32 **) &data, &datalen)) - GOTO(out_msg, rc = -EFAULT); - gss_err = lgss_import_sec_context(&tmpobj, - gss_msg->gum_gsec->gs_mech, - &gctx->gc_mechctx); - rc = 0; - } - - if (likely(rc == 0 && gss_err == GSS_S_COMPLETE)) { - gss_cli_ctx_uptodate(gctx); - } else { - ctx = &gctx->gc_base; - sptlrpc_cli_ctx_expire(ctx); - if (rc != -ERESTART || gss_err != GSS_S_COMPLETE) - set_bit(PTLRPC_CTX_ERROR_BIT, &ctx->cc_flags); - - CERROR("refresh ctx %p(uid %d) failed: %d/0x%08x: %s\n", - ctx, ctx->cc_vcred.vc_uid, rc, gss_err, - test_bit(PTLRPC_CTX_ERROR_BIT, &ctx->cc_flags) ? - "fatal error" : "non-fatal"); - } - - rc = mlen; - -out_msg: - gss_release_msg(gss_msg); - -out_free: - OBD_FREE(buf, mlen); - /* FIXME - * hack pipefs: always return asked length unless all following - * downcalls might be messed up. */ - rc = mlen; - RETURN(rc); -} - -static -void gss_pipe_destroy_msg(struct rpc_pipe_msg *msg) -{ - struct gss_upcall_msg *gmsg; - struct gss_upcall_msg_data *gumd; - static time64_t ratelimit; - ENTRY; - - LASSERT(list_empty(&msg->list)); - - /* normally errno is >= 0 */ - if (msg->errno >= 0) { - EXIT; - return; - } - - gmsg = container_of(msg, struct gss_upcall_msg, gum_base); - gumd = &gmsg->gum_data; - LASSERT(atomic_read(&gmsg->gum_refcount) > 0); - - CERROR("failed msg %p (seq %u, uid %u, svc %u, nid %#llx, obd %.*s): " - "errno %d\n", msg, gumd->gum_seq, gumd->gum_uid, gumd->gum_svc, - gumd->gum_nid, (int) sizeof(gumd->gum_obd), - gumd->gum_obd, msg->errno); - - atomic_inc(&gmsg->gum_refcount); - gss_unhash_msg(gmsg); - if (msg->errno == -ETIMEDOUT || msg->errno == -EPIPE) { - time64_t now = ktime_get_real_seconds(); - - if (now > ratelimit) { - CWARN("upcall timed out, is lgssd running?\n"); - ratelimit = now + 15; - } - } - gss_msg_fail_ctx(gmsg); - gss_release_msg(gmsg); - EXIT; -} - -static -void gss_pipe_release(struct inode *inode) -{ - struct rpc_inode *rpci = RPC_I(inode); - __u32 idx; - ENTRY; - - idx = (__u32) (long) rpci->private; - LASSERT(idx < MECH_MAX); - - upcall_list_lock(idx); - while (!list_empty(&upcall_lists[idx])) { - struct gss_upcall_msg *gmsg; - struct gss_upcall_msg_data *gumd; - - gmsg = list_entry(upcall_lists[idx].next, - struct gss_upcall_msg, gum_list); - gumd = &gmsg->gum_data; - LASSERT(list_empty(&gmsg->gum_base.list)); - - CERROR("failing remaining msg %p:seq %u, uid %u, svc %u, " - "nid %#llx, obd %.*s\n", gmsg, - gumd->gum_seq, gumd->gum_uid, gumd->gum_svc, - gumd->gum_nid, (int) sizeof(gumd->gum_obd), - gumd->gum_obd); - - gmsg->gum_base.errno = -EPIPE; - atomic_inc(&gmsg->gum_refcount); - gss_unhash_msg_nolock(gmsg); - - gss_msg_fail_ctx(gmsg); - - upcall_list_unlock(idx); - gss_release_msg(gmsg); - upcall_list_lock(idx); - } - upcall_list_unlock(idx); - EXIT; -} - -static struct rpc_pipe_ops gss_upcall_ops = { - .upcall = gss_pipe_upcall, - .downcall = gss_pipe_downcall, - .destroy_msg = gss_pipe_destroy_msg, - .release_pipe = gss_pipe_release, -}; - -/**************************************** - * upcall helper functions * - ****************************************/ - -static -int gss_ctx_refresh_pf(struct ptlrpc_cli_ctx *ctx) -{ - struct obd_import *imp; - struct gss_sec *gsec; - struct gss_upcall_msg *gmsg; - int rc = 0; - ENTRY; - - might_sleep(); - - LASSERT(ctx->cc_sec); - LASSERT(ctx->cc_sec->ps_import); - LASSERT(ctx->cc_sec->ps_import->imp_obd); - - imp = ctx->cc_sec->ps_import; - if (!imp->imp_connection) { - CERROR("import has no connection set\n"); - RETURN(-EINVAL); - } - - gsec = container_of(ctx->cc_sec, struct gss_sec, gs_base); - - OBD_ALLOC_PTR(gmsg); - if (!gmsg) - RETURN(-ENOMEM); - - /* initialize pipefs base msg */ - INIT_LIST_HEAD(&gmsg->gum_base.list); - gmsg->gum_base.data = &gmsg->gum_data; - gmsg->gum_base.len = sizeof(gmsg->gum_data); - gmsg->gum_base.copied = 0; - gmsg->gum_base.errno = 0; - - /* init upcall msg */ - atomic_set(&gmsg->gum_refcount, 1); - gmsg->gum_mechidx = mech_name2idx(gsec->gs_mech->gm_name); - gmsg->gum_gsec = gsec; - gmsg->gum_gctx = container_of(sptlrpc_cli_ctx_get(ctx), - struct gss_cli_ctx, gc_base); - gmsg->gum_data.gum_seq = upcall_get_sequence(); - gmsg->gum_data.gum_uid = ctx->cc_vcred.vc_uid; - gmsg->gum_data.gum_gid = 0; /* not used for now */ - gmsg->gum_data.gum_svc = import_to_gss_svc(imp); - gmsg->gum_data.gum_nid = imp->imp_connection->c_peer.nid; - strlcpy(gmsg->gum_data.gum_obd, imp->imp_obd->obd_name, - sizeof(gmsg->gum_data.gum_obd)); - - /* This only could happen when sysadmin set it dead/expired - * using lctl by force. */ - if (ctx->cc_flags & PTLRPC_CTX_STATUS_MASK) { - CWARN("ctx %p(%u->%s) was set flags %lx unexpectedly\n", - ctx, ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec), - ctx->cc_flags); - - LASSERT(!(ctx->cc_flags & PTLRPC_CTX_UPTODATE)); - ctx->cc_flags |= PTLRPC_CTX_DEAD | PTLRPC_CTX_ERROR; - - rc = -EIO; - goto err_free; - } - - upcall_msg_enlist(gmsg); - - rc = rpc_queue_upcall(de_pipes[gmsg->gum_mechidx]->d_inode, - &gmsg->gum_base); - if (rc) { - CERROR("rpc_queue_upcall failed: %d\n", rc); - - upcall_msg_delist(gmsg); - goto err_free; - } - - RETURN(0); -err_free: - OBD_FREE_PTR(gmsg); - RETURN(rc); -} - -static -int gss_cli_ctx_refresh_pf(struct ptlrpc_cli_ctx *ctx) -{ - /* if we are refreshing for root, also update the reverse - * handle index, do not confuse reverse contexts. */ - if (ctx->cc_vcred.vc_uid == 0) { - struct gss_sec *gsec; - - gsec = container_of(ctx->cc_sec, struct gss_sec, gs_base); - gsec->gs_rvs_hdl = gss_get_next_ctx_index(); - } - - return gss_ctx_refresh_pf(ctx); -} - -/**************************************** - * lustre gss pipefs policy * - ****************************************/ - -static struct ptlrpc_ctx_ops gss_pipefs_ctxops = { - .match = gss_cli_ctx_match, - .refresh = gss_cli_ctx_refresh_pf, - .validate = gss_cli_ctx_validate_pf, - .die = gss_cli_ctx_die_pf, - .sign = gss_cli_ctx_sign, - .verify = gss_cli_ctx_verify, - .seal = gss_cli_ctx_seal, - .unseal = gss_cli_ctx_unseal, - .wrap_bulk = gss_cli_ctx_wrap_bulk, - .unwrap_bulk = gss_cli_ctx_unwrap_bulk, -}; - -static struct ptlrpc_sec_cops gss_sec_pipefs_cops = { - .create_sec = gss_sec_create_pf, - .destroy_sec = gss_sec_destroy_pf, - .kill_sec = gss_sec_kill, - .lookup_ctx = gss_sec_lookup_ctx_pf, - .release_ctx = gss_sec_release_ctx_pf, - .flush_ctx_cache = gss_sec_flush_ctx_cache_pf, - .install_rctx = gss_sec_install_rctx, - .alloc_reqbuf = gss_alloc_reqbuf, - .free_reqbuf = gss_free_reqbuf, - .alloc_repbuf = gss_alloc_repbuf, - .free_repbuf = gss_free_repbuf, - .enlarge_reqbuf = gss_enlarge_reqbuf, -}; - -static struct ptlrpc_sec_sops gss_sec_pipefs_sops = { - .accept = gss_svc_accept_pf, - .invalidate_ctx = gss_svc_invalidate_ctx, - .alloc_rs = gss_svc_alloc_rs, - .authorize = gss_svc_authorize, - .free_rs = gss_svc_free_rs, - .free_ctx = gss_svc_free_ctx, - .unwrap_bulk = gss_svc_unwrap_bulk, - .wrap_bulk = gss_svc_wrap_bulk, - .install_rctx = gss_svc_install_rctx_pf, -}; - -static struct ptlrpc_sec_policy gss_policy_pipefs = { - .sp_owner = THIS_MODULE, - .sp_name = "gss.pipefs", - .sp_policy = SPTLRPC_POLICY_GSS_PIPEFS, - .sp_cops = &gss_sec_pipefs_cops, - .sp_sops = &gss_sec_pipefs_sops, -}; - -static -int __init gss_init_pipefs_upcall(void) -{ - struct dentry *de; - - /* pipe dir */ - de = rpc_mkdir(LUSTRE_PIPE_ROOT, NULL); - if (IS_ERR(de) && PTR_ERR(de) != -EEXIST) { - CERROR("Failed to create gss pipe dir: %ld\n", PTR_ERR(de)); - return PTR_ERR(de); - } - - /* FIXME hack pipefs: dput will sometimes cause oops during module - * unload and lgssd close the pipe fds. */ - - /* krb5 mechanism */ - de = rpc_mkpipe(LUSTRE_PIPE_KRB5, (void *) MECH_KRB5, &gss_upcall_ops, - RPC_PIPE_WAIT_FOR_OPEN); - if (!de || IS_ERR(de)) { - CERROR("failed to make rpc_pipe %s: %ld\n", - LUSTRE_PIPE_KRB5, PTR_ERR(de)); - rpc_rmdir(LUSTRE_PIPE_ROOT); - return PTR_ERR(de); - } - - de_pipes[MECH_KRB5] = de; - INIT_LIST_HEAD(&upcall_lists[MECH_KRB5]); - spin_lock_init(&upcall_locks[MECH_KRB5]); - - return 0; -} - -static -void __exit gss_exit_pipefs_upcall(void) -{ - __u32 i; - - for (i = 0; i < MECH_MAX; i++) { - LASSERT(list_empty(&upcall_lists[i])); - - /* dput pipe dentry here might cause lgssd oops. */ - de_pipes[i] = NULL; - } - - rpc_unlink(LUSTRE_PIPE_KRB5); - rpc_rmdir(LUSTRE_PIPE_ROOT); -} - -int __init gss_init_pipefs(void) -{ - int rc; - - rc = gss_init_pipefs_upcall(); - if (rc) - return rc; - - rc = sptlrpc_register_policy(&gss_policy_pipefs); - if (rc) { - gss_exit_pipefs_upcall(); - return rc; - } - - return 0; -} - -void __exit gss_exit_pipefs(void) -{ - gss_exit_pipefs_upcall(); - sptlrpc_unregister_policy(&gss_policy_pipefs); -} diff --git a/lustre/ptlrpc/gss/sec_gss.c b/lustre/ptlrpc/gss/sec_gss.c index 1ced073..392b247 100644 --- a/lustre/ptlrpc/gss/sec_gss.c +++ b/lustre/ptlrpc/gss/sec_gss.c @@ -2876,16 +2876,10 @@ static int __init sptlrpc_gss_init(void) if (rc) goto out_sk; - rc = gss_init_pipefs(); - if (rc) - goto out_keyring; - gss_init_at_reply_offset(); return 0; -out_keyring: - gss_exit_keyring(); out_sk: cleanup_sk_module(); out_kerberos: @@ -2904,7 +2898,6 @@ out_tunables: static void __exit sptlrpc_gss_exit(void) { gss_exit_keyring(); - gss_exit_pipefs(); cleanup_kerberos_module(); gss_exit_svc_upcall(); gss_exit_cli_upcall(); diff --git a/lustre/tests/sanity-krb5.sh b/lustre/tests/sanity-krb5.sh index f7a1002..2a941709 100755 --- a/lustre/tests/sanity-krb5.sh +++ b/lustre/tests/sanity-krb5.sh @@ -155,27 +155,17 @@ test_0() { echo "check with someone already running..." check_multiple_gss_daemons $my_facet $LSVCGSSD - if $GSS_PIPEFS; then - check_multiple_gss_daemons $my_facet $LGSSD - fi echo "check with someone run & finished..." do_facet $my_facet killall -q -2 lgssd $LSVCGSSD || true sleep 5 # wait fully exit check_multiple_gss_daemons $my_facet $LSVCGSSD - if $GSS_PIPEFS; then - check_multiple_gss_daemons $my_facet $LGSSD - fi echo "check refresh..." do_facet $my_facet killall -q -2 lgssd $LSVCGSSD || true sleep 5 # wait fully exit do_facet $my_facet ipcrm -S 0x3b92d473 check_multiple_gss_daemons $my_facet $LSVCGSSD - if $GSS_PIPEFS; then - do_facet $my_facet ipcrm -S 0x3a92d473 - check_multiple_gss_daemons $my_facet $LGSSD - fi } run_test 0 "start multiple gss daemons" @@ -262,40 +252,6 @@ test_3() { } run_test 3 "local cache under DLM lock" -test_4() { - local file1=$DIR/$tfile-1 - local file2=$DIR/$tfile-2 - - ! $GSS_PIPEFS && skip "pipefs not used" && return - - chmod 0777 $DIR || error "chmod $DIR failed" - # current access should be ok - $RUNAS touch $file1 || error "can't touch $file1" - [ -f $file1 ] || error "$file1 not found" - - # stop lgssd - send_sigint client lgssd - sleep 5 - check_gss_daemon_facet client lgssd && error "lgssd still running" - - # flush context, and touch - $RUNAS $LFS flushctx $MOUNT || error "can't flush context on $MOUNT" - $RUNAS touch $file2 & - TOUCHPID=$! - echo "waiting touch pid $TOUCHPID" - wait $TOUCHPID && error "touch should fail" - - # restart lgssd - do_facet client "$LGSSD -v" - sleep 5 - check_gss_daemon_facet client lgssd - - # touch new should succeed - $RUNAS touch $file2 || error "can't touch $file2" - [ -f $file2 ] || error "$file2 not found" -} -run_test 4 "lgssd dead, operations should wait timeout and fail" - test_5() { local file1=$DIR/$tdir/$tfile-1 local file2=$DIR/$tdir/$tfile-2 diff --git a/lustre/tests/test-framework.sh b/lustre/tests/test-framework.sh index 70768d6..242cb5d 100755 --- a/lustre/tests/test-framework.sh +++ b/lustre/tests/test-framework.sh @@ -11,7 +11,6 @@ export VERBOSE=${VERBOSE:-false} export GSS=${GSS:-false} export GSS_SK=${GSS_SK:-false} export GSS_KRB5=false -export GSS_PIPEFS=false export SHARED_KEY=${SHARED_KEY:-false} export SK_PATH=${SK_PATH:-/tmp/test-framework-keys} export SK_OM_PATH=$SK_PATH'/tmp-request-mount' @@ -352,9 +351,6 @@ init_test_env() { [ ! -f "$LSOM_SYNC" ] && export LSOM_SYNC=$(which llsom_sync 2> /dev/null) [ -z "$LSOM_SYNC" ] && export LSOM_SYNC="/usr/sbin/llsom_sync" - export LGSSD=${LGSSD:-"$LUSTRE/utils/gss/lgssd"} - [ "$GSS_PIPEFS" = "true" ] && [ ! -f "$LGSSD" ] && - export LGSSD=$(which lgssd) export LSVCGSSD=${LSVCGSSD:-"$LUSTRE/utils/gss/lsvcgssd"} [ ! -f "$LSVCGSSD" ] && export LSVCGSSD=$(which lsvcgssd 2> /dev/null) export KRB5DIR=${KRB5DIR:-"/usr/kerberos"} @@ -1019,9 +1015,6 @@ start_gss_daemons() { else do_nodes $nodes "$LSVCGSSD -vvv" || return 1 fi - if $GSS_PIPEFS; then - do_nodes $nodes "$LGSSD -v" || return 2 - fi nodes=$(comma_list $(osts_nodes)) echo "Starting gss daemon on ost: $nodes" @@ -1035,11 +1028,6 @@ start_gss_daemons() { local clients=${CLIENTS:-$HOSTNAME} - if $GSS_PIPEFS; then - echo "Starting $LGSSD on clients $clients " - do_nodes $clients "$LGSSD -v" || return 4 - fi - # wait daemons entering "stable" status sleep 5 @@ -1048,13 +1036,6 @@ start_gss_daemons() { # nodes=$(comma_list $(mdts_nodes) $(osts_nodes)) check_gss_daemon_nodes $nodes lsvcgssd || return 5 - if $GSS_PIPEFS; then - nodes=$(comma_list $(mdts_nodes)) - check_gss_daemon_nodes $nodes lgssd || return 6 - fi - if $GSS_PIPEFS; then - check_gss_daemon_nodes $clients lgssd || return 7 - fi } stop_gss_daemons() { diff --git a/lustre/utils/gss/.gitignore b/lustre/utils/gss/.gitignore index 87d15ec..4abb8c0 100644 --- a/lustre/utils/gss/.gitignore +++ b/lustre/utils/gss/.gitignore @@ -1,5 +1,4 @@ /Makefile.in -/lgssd /lsvcgssd /l_idmap /lgss_keyring diff --git a/lustre/utils/gss/Makefile.am b/lustre/utils/gss/Makefile.am index 5798389..78d1296 100644 --- a/lustre/utils/gss/Makefile.am +++ b/lustre/utils/gss/Makefile.am @@ -13,10 +13,6 @@ sbin_PROGRAMS += lgss_sk endif endif -if GSS_PIPEFS -sbin_PROGRAMS += lgssd -endif - COMMON_SRCS = \ context.c \ context_lucid.c \ @@ -32,27 +28,13 @@ COMMON_SRCS = \ err_util.h \ gss_oids.h \ gss_util.h \ - lsupport.h + lsupport.h \ + write_bytes.h if GSS_SSK COMMON_SRCS += sk_utils.h sk_utils.c endif -lgssd_SOURCES = \ - $(COMMON_SRCS) \ - gssd.c \ - gssd_main_loop.c \ - gssd_proc.c \ - krb5_util.c \ - \ - gssd.h \ - krb5_util.h \ - write_bytes.h - -lgssd_CFLAGS = $(AM_CFLAGS) $(CFLAGS) $(KRBCFLAGS) -lgssd_LDADD = $(GSSAPI_LIBS) $(KRBLIBS) -lgssd_LDFLAGS = $(KRBLDFLAGS) - lsvcgssd_SOURCES = \ $(COMMON_SRCS) \ cacheio.c \ diff --git a/lustre/utils/gss/gss_util.c b/lustre/utils/gss/gss_util.c index 7b9a9ff..df5a8d3 100644 --- a/lustre/utils/gss/gss_util.c +++ b/lustre/utils/gss/gss_util.c @@ -62,7 +62,9 @@ #include #include #include +#include #include +#include #include #if defined(HAVE_KRB5) && !defined(GSS_C_NT_HOSTBASED_SERVICE) #include @@ -70,7 +72,6 @@ #endif #include "gss_util.h" #include "err_util.h" -#include "gssd.h" #ifdef HAVE_UNISTD_H # include #endif @@ -80,6 +81,10 @@ #endif #include "lsupport.h" +#define GSSD_SERVICE_MGS "lustre_mgs" +#define GSSD_SERVICE_MDS "lustre_mds" +#define GSSD_SERVICE_OSS "lustre_oss" + /* Global gssd_credentials handle */ gss_cred_id_t gssd_cred_mgs; gss_cred_id_t gssd_cred_mds; @@ -376,8 +381,6 @@ out: * FIXME should be in krb5_util.c *********************************/ -#include "krb5_util.h" - /* realm of this node */ char *this_realm = NULL; diff --git a/lustre/utils/gss/gss_util.h b/lustre/utils/gss/gss_util.h index 07b0f30..b53c256 100644 --- a/lustre/utils/gss/gss_util.h +++ b/lustre/utils/gss/gss_util.h @@ -32,7 +32,6 @@ #define _GSS_UTIL_H_ #include -#include "write_bytes.h" #ifndef fallthrough # if defined(__GNUC__) && __GNUC__ >= 7 diff --git a/lustre/utils/gss/gssd.c b/lustre/utils/gss/gssd.c deleted file mode 100644 index 5f7bb40..0000000 --- a/lustre/utils/gss/gssd.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - gssd.c - - Copyright (c) 2000 The Regents of the University of Michigan. - All rights reserved. - - Copyright (c) 2000 Dug Song . - Copyright (c) 2002 Andy Adamson . - Copyright (c) 2002 Marius Aamodt Eriksen . - All rights reserved, all wrongs reversed. - - Copyright (c) 2014, Intel Corporation. - - 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. - -*/ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gssd.h" -#include "err_util.h" -#include "gss_util.h" -#include "krb5_util.h" -#include "lsupport.h" - -char *pipefs_dir = GSSD_PIPEFS_DIR; -char pipefs_nfsdir[PATH_MAX] = GSSD_PIPEFS_DIR; -char *keytabfile = GSSD_DEFAULT_KEYTAB_FILE; -char *ccachedir = GSSD_DEFAULT_CRED_DIR; -int use_memcache = 0; -int lgssd_mutex_downcall = -1; - -static int lgssd_create_mutex(int *semid) -{ - int id; - int arg; - - id = semget(IPC_PRIVATE, 1, IPC_CREAT); - if (id == -1) { - printerr(0, "semget: %s\n", strerror(errno)); - return -1; - } - - arg = 1; - if (semctl(id, 0, SETVAL, arg) != 0) { - printerr(0, "semctl: %s\n", strerror(errno)); - semctl(id, 1, IPC_RMID, arg); - return -1; - } - - *semid = id; - return 0; -} - -void lgssd_init_mutexs(void) -{ - if (lgssd_create_mutex(&lgssd_mutex_downcall)) { - printerr(0, "can't create downcall mutex\n"); - exit(1); - } -} - -void lgssd_fini_mutexs(void) -{ - int arg = 0; - - if (lgssd_mutex_downcall != -1) - semctl(lgssd_mutex_downcall, 1, IPC_RMID, arg); -} - -void lgssd_mutex_get(int semid) -{ - struct sembuf op = { - .sem_op = -1, - .sem_flag = SEM_UNDO - }; - int rc; - - rc = semop(semid, &op, 1); - if (rc != 0) { - printerr(0, "exit on mutex_get err %d: %s\n", - rc, strerror(errno)); - exit(1); - } -} - -void lgssd_mutex_put(int semid) -{ - struct sembuf op = { - .sem_op = 1 - }; - int rc; - - rc = semop(semid, &op, 1); - if (rc != 0) { - printerr(0, "ignore mutex_put err %d: %s\n", - rc, strerror(errno)); - } -} - -static void lgssd_cleanup(void) -{ - pid_t child_pid; - - /* make sure all children finished */ - while (1) { - child_pid = waitpid(-1, NULL, 0); - if (child_pid < 0) - break; - - printerr(3, "cleanup: child %d terminated\n", child_pid); - } - - lgssd_fini_mutexs(); - - /* destroy krb5 machine creds */ - gssd_destroy_krb5_machine_creds(); -} - -void -sig_die(int signal) -{ - printerr(1, "exiting on signal %d\n", signal); - lgssd_cleanup(); - exit(1); -} - -void -sig_hup(int signal) -{ - /* don't exit on SIGHUP */ - printerr(1, "Received SIGHUP... Ignoring.\n"); -} - -static void -usage(char *progname) -{ - fprintf(stderr, "usage: %s [-f] [-v] [-p pipefsdir] [-k keytab] [-d ccachedir]\n", - progname); - exit(1); -} - -int -main(int argc, char *argv[]) -{ - int fg = 0; - int verbosity = 0; - int opt; - extern char *optarg; - char *progname; - - while ((opt = getopt(argc, argv, "fvrmMp:k:d:")) != -1) { - switch (opt) { - case 'f': - fg = 1; - break; - case 'M': - use_memcache = 1; - break; - case 'v': - verbosity++; - break; - case 'p': - pipefs_dir = strdup(optarg); - if (!pipe_dir) - errx(1, "pipefs path name not aquired"); - break; - case 'k': - keytabfile = strdup(optarg); - if (!keytab_file) - errx(1, "keytab path name not aquired"); - break; - case 'd': - ccachedir = strdup(optarg); - if (!ccachedir) - errx(1, "ccachedir path name not aquired"); - break; - default: - usage(argv[0]); - break; - } - } - - if ((progname = strrchr(argv[0], '/'))) - progname++; - else - progname = argv[0]; - - initerr(progname, verbosity, fg); - - if (gssd_check_mechs() != 0) - errx(1, "Problem with gssapi library"); - - if (gssd_get_local_realm()) - errx(1, "get local realm"); - - if (!fg && daemon(0, 0) < 0) - errx(1, "fork"); - - /* This should be checked _after_ daemon(), because we need to own - * the undo-able semaphore by this process - */ - gssd_init_unique(GSSD_CLI); - - /* Process keytab file and get machine credentials. This will modify - * disk status so do it after we are sure we are the only instance - */ - if (gssd_refresh_krb5_machine_creds()) - return -1; - - signal(SIGINT, sig_die); - signal(SIGTERM, sig_die); - signal(SIGHUP, sig_hup); - - lgssd_init_mutexs(); - - printerr(0, "lgssd initialized and ready to serve\n"); - lgssd_run(); - - lgssd_cleanup(); - printerr(0, "lgssd exiting\n"); - return 0; -} diff --git a/lustre/utils/gss/gssd.h b/lustre/utils/gss/gssd.h deleted file mode 100644 index 86cd658..0000000 --- a/lustre/utils/gss/gssd.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - Copyright (c) 2004 The Regents of the University of Michigan. - All rights reserved. - - 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. -*/ - -#ifndef _RPC_GSSD_H_ -#define _RPC_GSSD_H_ - -#include -#include -#include - -#define MAX_FILE_NAMELEN 32 -#define FD_ALLOC_BLOCK 32 -#ifndef GSSD_PIPEFS_DIR -#define GSSD_PIPEFS_DIR "/var/lib/nfs/rpc_pipefs" -#endif -#define INFO "info" -#define KRB5 "krb5" -#define DNOTIFY_SIGNAL (SIGRTMIN + 3) - -#define GSSD_DEFAULT_CRED_DIR "/tmp" -#define GSSD_DEFAULT_CRED_PREFIX "krb5cc_" -#define GSSD_DEFAULT_MACHINE_CRED_SUFFIX "machine" -#define GSSD_DEFAULT_KEYTAB_FILE "/etc/krb5.keytab" -#define GSSD_SERVICE_MGS "lustre_mgs" -#define GSSD_SERVICE_MDS "lustre_mds" -#define GSSD_SERVICE_OSS "lustre_oss" -#define GSSD_SERVICE_MDS_NAMELEN 10 -#define GSSD_SERVICE_OSS_NAMELEN 10 - -#define LUSTRE_ROOT_NAME "lustre_root" -#define LUSTRE_ROOT_NAMELEN 11 - -/* - * The gss mechanisms that we can handle - */ -enum {AUTHTYPE_KRB5, AUTHTYPE_SPKM3, AUTHTYPE_LIPKEY}; - - - -extern char *pipefs_dir; -extern char *keytabfile; -extern char *ccachedir; -extern char gethostname_ex[PATH_MAX]; -extern int use_memcache; - -struct clnt_info { - TAILQ_ENTRY(clnt_info) list; - char *dirname; - int dir_fd; - char *servicename; - int krb5_fd; - int krb5_poll_index; - int spkm3_fd; - int spkm3_poll_index; -}; - -void init_client_list(void); -int update_client_list(void); -void handle_krb5_upcall(struct clnt_info *clp); -void lgssd_run(void); -struct clnt_info *clnt_list_first_entry(void); - -extern int lgssd_mutex_downcall; - -void lgssd_init_mutexs(void); -void lgssd_fini_mutexs(void); -void lgssd_mutex_get(int semid); -void lgssd_mutex_put(int semid); - -#endif /* _RPC_GSSD_H_ */ diff --git a/lustre/utils/gss/gssd_main_loop.c b/lustre/utils/gss/gssd_main_loop.c deleted file mode 100644 index ccb5515..0000000 --- a/lustre/utils/gss/gssd_main_loop.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - Copyright (c) 2004 The Regents of the University of Michigan. - All rights reserved. - - 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. -*/ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -/* For time() */ -#include -/* For waitpid() */ -#include - -#include "gssd.h" -#include "err_util.h" - -extern struct pollfd *pollarray; -extern int pollsize; - -#define POLL_MILLISECS 500 - -static volatile int dir_changed = 1; - -static void dir_notify_handler(int sig, siginfo_t *si, void *data) -{ - dir_changed = 1; -} - -static void -scan_poll_results(int ret) -{ - int i; - struct clnt_info *clp; - - for (clp = clnt_list_first_entry(); clp != NULL; clp = clp->list.tqe_next) - { - i = clp->krb5_poll_index; - if (i >= 0 && pollarray[i].revents) { - if (pollarray[i].revents & POLLHUP) - dir_changed = 1; - if (pollarray[i].revents & POLLIN) - handle_krb5_upcall(clp); - pollarray[clp->krb5_poll_index].revents = 0; - ret--; - if (!ret) - break; - } - i = clp->spkm3_poll_index; - if (i >= 0 && pollarray[i].revents) { - if (pollarray[i].revents & POLLHUP) - dir_changed = 1; - pollarray[clp->spkm3_poll_index].revents = 0; - ret--; - if (!ret) - break; - } - } -}; - -void -lgssd_run() -{ - int ret; - struct sigaction dn_act; - int fd; - time_t child_check = 0; - pid_t child_pid; - - /* Taken from linux/Documentation/dnotify.txt: */ - dn_act.sa_sigaction = dir_notify_handler; - sigemptyset(&dn_act.sa_mask); - dn_act.sa_flags = SA_SIGINFO; - sigaction(DNOTIFY_SIGNAL, &dn_act, NULL); - - if ((fd = open(pipefs_dir, O_RDONLY)) == -1) { - printerr(0, "ERROR: failed to open %s: %s\n", - pipefs_dir, strerror(errno)); - return; - } - fcntl(fd, F_SETSIG, DNOTIFY_SIGNAL); - fcntl(fd, F_NOTIFY, DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT); - - init_client_list(); - - while (1) { - while (dir_changed) { - dir_changed = 0; - printerr(2, "pipefs root dir changed\n"); - if (update_client_list()) { - printerr(0, "ERROR: couldn't update " - "client list\n"); - goto out; - } - } - - /* every 5s cleanup possible zombies of child processes */ - if (time(NULL) - child_check >= 5) { - printerr(3, "check zombie children...\n"); - - while (1) { - child_pid = waitpid(-1, NULL, WNOHANG); - if (child_pid <= 0) - break; - - printerr(2, "terminate zombie child: %d\n", - child_pid); - } - - child_check = time(NULL); - } - - /* race condition here: dir_changed could be set before we - * enter the poll, and we'd never notice if it weren't for the - * timeout. */ - ret = poll(pollarray, pollsize, POLL_MILLISECS); - if (ret < 0) { - if (errno != EINTR) - printerr(0, - "WARNING: error return from poll\n"); - } else if (ret == 0) { - /* timeout */ - } else { /* ret > 0 */ - scan_poll_results(ret); - } - } -out: - close(fd); -} diff --git a/lustre/utils/gss/gssd_proc.c b/lustre/utils/gss/gssd_proc.c deleted file mode 100644 index 3a82045..0000000 --- a/lustre/utils/gss/gssd_proc.c +++ /dev/null @@ -1,877 +0,0 @@ -/* - gssd_proc.c - - Copyright (c) 2000-2004 The Regents of the University of Michigan. - All rights reserved. - - Copyright (c) 2000 Dug Song . - Copyright (c) 2001 Andy Adamson . - Copyright (c) 2002 Marius Aamodt Eriksen . - Copyright (c) 2002 Bruce Fields - Copyright (c) 2004 Kevin Coffman - All rights reserved, all wrongs reversed. - - 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. - -*/ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include "config.h" -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_NETDB_H -# include -#endif - -#include -#include - -#include "gssd.h" -#include "err_util.h" -#include "gss_util.h" -#include "gss_oids.h" -#include "krb5_util.h" -#include "context.h" -#include "lsupport.h" - -/* - * pollarray: - * array of struct pollfd suitable to pass to poll. initialized to - * zero - a zero struct is ignored by poll() because the events mask is 0. - * - * clnt_list: - * linked list of struct clnt_info which associates a clntXXX directory - * with an index into pollarray[], and other basic data about that client. - * - * Directory structure: created by the kernel nfs client - * {pipefs_nfsdir}/clntXX : one per rpc_clnt struct in the kernel - * {pipefs_nfsdir}/clntXX/krb5 : read uid for which kernel wants - * a context, write the resulting context - * {pipefs_nfsdir}/clntXX/info : stores info such as server name - * - * Algorithm: - * Poll all {pipefs_nfsdir}/clntXX/krb5 files. When ready, data read - * is a uid; performs rpcsec_gss context initialization protocol to - * get a cred for that user. Writes result to corresponding krb5 file - * in a form the kernel code will understand. - * In addition, we make sure we are notified whenever anything is - * created or destroyed in {pipefs_nfsdir} or in an of the clntXX directories, - * and rescan the whole {pipefs_nfsdir} when this happens. - */ - -TAILQ_HEAD(clnt_list_head, clnt_info) clnt_list; - -struct pollfd * pollarray; - -int pollsize; /* the size of pollaray (in pollfd's) */ - -static void -destroy_client(struct clnt_info *clp) -{ - printerr(3, "clp %p: dirname %s, krb5fd %d\n", clp, clp->dirname, clp->krb5_fd); - if (clp->krb5_poll_index != -1) - memset(&pollarray[clp->krb5_poll_index], 0, - sizeof(struct pollfd)); - if (clp->spkm3_poll_index != -1) - memset(&pollarray[clp->spkm3_poll_index], 0, - sizeof(struct pollfd)); - if (clp->dir_fd != -1) close(clp->dir_fd); - if (clp->krb5_fd != -1) close(clp->krb5_fd); - if (clp->spkm3_fd != -1) close(clp->spkm3_fd); - if (clp->dirname) free(clp->dirname); - if (clp->servicename) free(clp->servicename); - free(clp); -} - -static struct clnt_info * -insert_new_clnt(void) -{ - struct clnt_info *clp = NULL; - - if (!(clp = (struct clnt_info *)calloc(1,sizeof(struct clnt_info)))) { - printerr(0, "ERROR: can't malloc clnt_info: %s\n", - strerror(errno)); - goto out; - } - clp->krb5_poll_index = -1; - clp->spkm3_poll_index = -1; - clp->krb5_fd = -1; - clp->spkm3_fd = -1; - clp->dir_fd = -1; - - TAILQ_INSERT_HEAD(&clnt_list, clp, list); -out: - return clp; -} - -static int -process_clnt_dir_files(struct clnt_info * clp) -{ - char kname[32]; - char sname[32]; - - if (clp->krb5_fd == -1) { - snprintf(kname, sizeof(kname), "%s/krb5", clp->dirname); - clp->krb5_fd = open(kname, O_RDWR); - } - if (clp->spkm3_fd == -1) { - snprintf(sname, sizeof(sname), "%s/spkm3", clp->dirname); - clp->spkm3_fd = open(sname, O_RDWR); - } - if((clp->krb5_fd == -1) && (clp->spkm3_fd == -1)) - return -1; - return 0; -} - -static int -get_poll_index(int *ind) -{ - int i; - - *ind = -1; - for (i=0; ikrb5_fd != -1) && (clp->krb5_poll_index == -1)) { - if (get_poll_index(&clp->krb5_poll_index)) { - printerr(0, "ERROR: Too many krb5 clients\n"); - return -1; - } - pollarray[clp->krb5_poll_index].fd = clp->krb5_fd; - pollarray[clp->krb5_poll_index].events |= POLLIN; - printerr(2, "monitoring krb5 channel under %s\n", - clp->dirname); - } - - if ((clp->spkm3_fd != -1) && (clp->spkm3_poll_index == -1)) { - if (get_poll_index(&clp->spkm3_poll_index)) { - printerr(0, "ERROR: Too many spkm3 clients\n"); - return -1; - } - pollarray[clp->spkm3_poll_index].fd = clp->spkm3_fd; - pollarray[clp->spkm3_poll_index].events |= POLLIN; - } - - return 0; -} - -static void -process_clnt_dir(char *dir) -{ - struct clnt_info * clp; - - if (!(clp = insert_new_clnt())) - goto fail_destroy_client; - - if (!(clp->dirname = calloc(strlen(dir) + 1, 1))) { - goto fail_destroy_client; - } - memcpy(clp->dirname, dir, strlen(dir)); - if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) { - printerr(0, "ERROR: can't open %s: %s\n", - clp->dirname, strerror(errno)); - goto fail_destroy_client; - } - fcntl(clp->dir_fd, F_SETSIG, DNOTIFY_SIGNAL); - fcntl(clp->dir_fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_MULTISHOT); - - if (process_clnt_dir_files(clp)) - goto fail_keep_client; - - if (insert_clnt_poll(clp)) - goto fail_destroy_client; - - return; - -fail_destroy_client: - if (clp) { - TAILQ_REMOVE(&clnt_list, clp, list); - destroy_client(clp); - } -fail_keep_client: - /* We couldn't find some subdirectories, but we keep the client - * around in case we get a notification on the directory when the - * subdirectories are created. */ -} - -void -init_client_list(void) -{ - TAILQ_INIT(&clnt_list); - /* Eventually plan to grow/shrink poll array: */ - pollsize = FD_ALLOC_BLOCK; - pollarray = calloc(pollsize, sizeof(struct pollfd)); -} - -struct clnt_info *clnt_list_first_entry(void) -{ - return clnt_list.tqh_first; -} - -/* - * This is run after a DNOTIFY signal, and should clear up any - * directories that are no longer around, and re-scan any existing - * directories, since the DNOTIFY could have been in there. - */ -static void -update_old_clients(struct dirent **namelist, int size) -{ - struct clnt_info *clp; - void *saveprev; - int i, stillhere; - - for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) { - stillhere = 0; - for (i=0; i < size; i++) { - if (!strcmp(clp->dirname, namelist[i]->d_name)) { - stillhere = 1; - break; - } - } - if (!stillhere) { - printerr(2, "destroying client %s\n", clp->dirname); - saveprev = clp->list.tqe_prev; - TAILQ_REMOVE(&clnt_list, clp, list); - destroy_client(clp); - clp = saveprev; - } - } - for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) { - if (!process_clnt_dir_files(clp)) - insert_clnt_poll(clp); - } -} - -/* Search for a client by directory name, return 1 if found, 0 otherwise */ -static int -find_client(char *dirname) -{ - struct clnt_info *clp; - - for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) - if (!strcmp(clp->dirname, dirname)) - return 1; - return 0; -} - -/* Used to read (and re-read) list of clients, set up poll array. */ -int -update_client_list(void) -{ - char lustre_dir[PATH_MAX]; - struct dirent lustre_dirent = { .d_name = "lustre" }; - struct dirent *namelist[1]; - struct stat statbuf; - int i, j; - - if (chdir(pipefs_dir) < 0) { - printerr(0, "ERROR: can't chdir to %s: %s\n", - pipefs_dir, strerror(errno)); - return -1; - } - - snprintf(lustre_dir, sizeof(lustre_dir), "%s/%s", pipefs_dir, "lustre"); - if (stat(lustre_dir, &statbuf) == 0) { - namelist[0] = &lustre_dirent; - j = 1; - printerr(2, "re-processing lustre directory\n"); - } else { - namelist[0] = NULL; - j = 0; - printerr(2, "lustre directory not exist\n"); - } - - update_old_clients(namelist, j); - for (i=0; i < j; i++) { - if (i < FD_ALLOC_BLOCK && !find_client(namelist[i]->d_name)) - process_clnt_dir(namelist[i]->d_name); - } - - chdir("/"); - return 0; -} - -/* Context creation response. */ -struct lustre_gss_init_res { - gss_buffer_desc gr_ctx; /* context handle */ - unsigned int gr_major; /* major status */ - unsigned int gr_minor; /* minor status */ - unsigned int gr_win; /* sequence window */ - gss_buffer_desc gr_token; /* token */ -}; - -struct lustre_gss_data { - int lgd_established; - int lgd_lustre_svc; /* mds/oss */ - int lgd_uid; /* uid */ - char *lgd_uuid; /* client device uuid */ - gss_name_t lgd_name; /* service name */ - - gss_OID lgd_mech; /* mech OID */ - unsigned int lgd_req_flags; /* request flags */ - gss_cred_id_t lgd_cred; /* credential */ - gss_ctx_id_t lgd_ctx; /* session context */ - gss_buffer_desc lgd_rmt_ctx; /* remote handle of context */ - uint32_t lgd_seq_win; /* sequence window */ - - int lgd_rpc_err; - int lgd_gss_err; -}; - -static int -do_downcall(int k5_fd, struct lgssd_upcall_data *updata, - struct lustre_gss_data *lgd, gss_buffer_desc *context_token) -{ - char *buf = NULL, *p = NULL, *end = NULL; - unsigned int timeout = 0; /* XXX decide on a reasonable value */ - unsigned int buf_size = 0; - - printerr(2, "doing downcall\n"); - buf_size = sizeof(updata->seq) + sizeof(timeout) + - sizeof(lgd->lgd_seq_win) + - sizeof(lgd->lgd_rmt_ctx.length) + lgd->lgd_rmt_ctx.length + - sizeof(context_token->length) + context_token->length; - p = buf = malloc(buf_size); - end = buf + buf_size; - - if (WRITE_BYTES(&p, end, updata->seq)) goto out_err; - /* Not setting any timeout for now: */ - if (WRITE_BYTES(&p, end, timeout)) goto out_err; - if (WRITE_BYTES(&p, end, lgd->lgd_seq_win)) goto out_err; - if (write_buffer(&p, end, &lgd->lgd_rmt_ctx)) goto out_err; - if (write_buffer(&p, end, context_token)) goto out_err; - - lgssd_mutex_get(lgssd_mutex_downcall); - if (write(k5_fd, buf, p - buf) < p - buf) { - lgssd_mutex_put(lgssd_mutex_downcall); - goto out_err; - } - lgssd_mutex_put(lgssd_mutex_downcall); - - if (buf) free(buf); - return 0; -out_err: - if (buf) free(buf); - printerr(0, "ERROR: Failed to write downcall!\n"); - return -1; -} - -static int -do_error_downcall(int k5_fd, uint32_t seq, int rpc_err, int gss_err) -{ - char buf[1024]; - char *p = buf, *end = buf + 1024; - unsigned int timeout = 0; - int zero = 0; - - printerr(1, "doing error downcall\n"); - - if (WRITE_BYTES(&p, end, seq)) goto out_err; - if (WRITE_BYTES(&p, end, timeout)) goto out_err; - /* use seq_win = 0 to indicate an error: */ - if (WRITE_BYTES(&p, end, zero)) goto out_err; - if (WRITE_BYTES(&p, end, rpc_err)) goto out_err; - if (WRITE_BYTES(&p, end, gss_err)) goto out_err; - - lgssd_mutex_get(lgssd_mutex_downcall); - if (write(k5_fd, buf, p - buf) < p - buf) { - lgssd_mutex_put(lgssd_mutex_downcall); - goto out_err; - } - lgssd_mutex_put(lgssd_mutex_downcall); - return 0; -out_err: - printerr(0, "Failed to write error downcall!\n"); - return -1; -} - -static -int do_negotiation(struct lustre_gss_data *lgd, - gss_buffer_desc *gss_token, - struct lustre_gss_init_res *gr, - int timeout) -{ - struct lgssd_ioctl_param param; - struct passwd *pw; - char outbuf[8192]; - unsigned int *p; - glob_t path; - int fd; - int rc; - - pw = getpwuid(lgd->lgd_uid); - if (!pw) { - printerr(0, "no uid %u in local user database\n", - lgd->lgd_uid); - return -1; - } - - param.version = GSSD_INTERFACE_VERSION_V1; - param.uuid = lgd->lgd_uuid; - param.lustre_svc = lgd->lgd_lustre_svc; - param.uid = lgd->lgd_uid; - param.gid = pw->pw_gid; - param.send_token_size = gss_token->length; - param.send_token = (char *) gss_token->value; - param.reply_buf_size = sizeof(outbuf); - param.reply_buf = outbuf; - - if (cfs_get_param_paths(&path, "sptlrpc/gss/init_channel") != 0) - return -1; - - fd = open(path.gl_pathv[0], O_RDWR); - if (fd < 0) { - printerr(0, "can't open file %s\n", path.gl_pathv[0]); - rc = -1; - goto out_params; - } - - rc = write(fd, ¶m, sizeof(param)); - if (rc != sizeof(param)) { - printerr(0, "lustre ioctl err: %d\n", strerror(errno)); - rc = -1; - goto out_fd; - } - if (param.status) { - printerr(0, "status: %d (%s)\n", - param.status, strerror((int)param.status)); - if (param.status == -ETIMEDOUT) { - /* kernel return -ETIMEDOUT means the rpc timedout, - * we should notify the caller to reinitiate the - * gss negotiation, by return -ERESTART - */ - lgd->lgd_rpc_err = -ERESTART; - lgd->lgd_gss_err = 0; - } else { - lgd->lgd_rpc_err = param.status; - lgd->lgd_gss_err = 0; - } - rc = -1; - goto out_fd; - } - p = (unsigned int *)outbuf; - gr->gr_major = *p++; - 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); - - printerr(2, "do_negotiation: receive handle len %d, token len %d\n", - gr->gr_ctx.length, gr->gr_token.length); - rc = 0; -out_fd: - close(fd); -out_params: - cfs_free_param_data(&path); - return rc; -} - -static -int gssd_refresh_lgd(struct lustre_gss_data *lgd) -{ - struct lustre_gss_init_res gr; - gss_buffer_desc *recv_tokenp, send_token; - OM_uint32 maj_stat, min_stat, call_stat, ret_flags; - - /* GSS context establishment loop. */ - memset(&gr, 0, sizeof(gr)); - recv_tokenp = GSS_C_NO_BUFFER; - - for (;;) { - /* print the token we just received */ - if (recv_tokenp != GSS_C_NO_BUFFER) { - printerr(3, "The received token length %d\n", - recv_tokenp->length); - print_hexl(3, recv_tokenp->value, recv_tokenp->length); - } - - maj_stat = gss_init_sec_context(&min_stat, - lgd->lgd_cred, - &lgd->lgd_ctx, - lgd->lgd_name, - lgd->lgd_mech, - lgd->lgd_req_flags, - 0, /* time req */ - NULL, /* channel */ - recv_tokenp, - NULL, /* used mech */ - &send_token, - &ret_flags, - NULL); /* time rec */ - - if (recv_tokenp != GSS_C_NO_BUFFER) { - gss_release_buffer(&min_stat, &gr.gr_token); - recv_tokenp = GSS_C_NO_BUFFER; - } - if (maj_stat != GSS_S_COMPLETE && - maj_stat != GSS_S_CONTINUE_NEEDED) { - pgsserr("gss_init_sec_context", maj_stat, min_stat, - lgd->lgd_mech); - break; - } - if (send_token.length != 0) { - memset(&gr, 0, sizeof(gr)); - - /* print the token we are about to send */ - printerr(3, "token being sent length %d\n", - send_token.length); - print_hexl(3, send_token.value, send_token.length); - - call_stat = do_negotiation(lgd, &send_token, &gr, 0); - gss_release_buffer(&min_stat, &send_token); - - if (call_stat != 0 || - (gr.gr_major != GSS_S_COMPLETE && - gr.gr_major != GSS_S_CONTINUE_NEEDED)) { - printerr(0, "call stat %d, major stat 0x%x\n", - (int)call_stat, gr.gr_major); - return -1; - } - - if (gr.gr_ctx.length != 0) { - if (lgd->lgd_rmt_ctx.value) - gss_release_buffer(&min_stat, - &lgd->lgd_rmt_ctx); - lgd->lgd_rmt_ctx = gr.gr_ctx; - } - if (gr.gr_token.length != 0) { - if (maj_stat != GSS_S_CONTINUE_NEEDED) - break; - recv_tokenp = &gr.gr_token; - } - } - - /* GSS_S_COMPLETE => check gss header verifier, - * usually checked in gss_validate - */ - if (maj_stat == GSS_S_COMPLETE) { - lgd->lgd_established = 1; - lgd->lgd_seq_win = gr.gr_win; - break; - } - } - /* End context negotiation loop. */ - if (!lgd->lgd_established) { - if (gr.gr_token.length != 0) - gss_release_buffer(&min_stat, &gr.gr_token); - - printerr(0, "context negotiation failed\n"); - return -1; - } - - printerr(2, "successfully refreshed lgd\n"); - return 0; -} - -static -int gssd_create_lgd(struct clnt_info *clp, - struct lustre_gss_data *lgd, - struct lgssd_upcall_data *updata, - int authtype) -{ - gss_buffer_desc sname; - OM_uint32 maj_stat, min_stat; - int retval = -1; - - lgd->lgd_established = 0; - lgd->lgd_lustre_svc = updata->svc; - lgd->lgd_uid = updata->uid; - lgd->lgd_uuid = updata->obd; - - switch (authtype) { - case AUTHTYPE_KRB5: - lgd->lgd_mech = (gss_OID) &krb5oid; - lgd->lgd_req_flags = GSS_C_MUTUAL_FLAG; - break; - case AUTHTYPE_SPKM3: - lgd->lgd_mech = (gss_OID) &spkm3oid; - /* XXX sec.req_flags = GSS_C_ANON_FLAG; - * Need a way to switch.... - */ - lgd->lgd_req_flags = GSS_C_MUTUAL_FLAG; - break; - default: - printerr(0, "Invalid authentication type (%d)\n", authtype); - return -1; - } - - lgd->lgd_cred = GSS_C_NO_CREDENTIAL; - lgd->lgd_ctx = GSS_C_NO_CONTEXT; - lgd->lgd_rmt_ctx = (gss_buffer_desc) GSS_C_EMPTY_BUFFER; - lgd->lgd_seq_win = 0; - - sname.value = clp->servicename; - sname.length = strlen(clp->servicename); - - maj_stat = gss_import_name(&min_stat, &sname, - (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, - &lgd->lgd_name); - if (maj_stat != GSS_S_COMPLETE) { - pgsserr(0, maj_stat, min_stat, lgd->lgd_mech); - goto out_fail; - } - - retval = gssd_refresh_lgd(lgd); - - if (lgd->lgd_name != GSS_C_NO_NAME) - gss_release_name(&min_stat, &lgd->lgd_name); - - if (lgd->lgd_cred != GSS_C_NO_CREDENTIAL) - gss_release_cred(&min_stat, &lgd->lgd_cred); - - out_fail: - return retval; -} - -static -void gssd_free_lgd(struct lustre_gss_data *lgd) -{ - gss_buffer_t token = GSS_C_NO_BUFFER; - OM_uint32 maj_stat, min_stat; - - if (lgd->lgd_ctx == GSS_C_NO_CONTEXT) - return; - - maj_stat = gss_delete_sec_context(&min_stat, &lgd->lgd_ctx, token); -} - -static -int construct_service_name(struct clnt_info *clp, - struct lgssd_upcall_data *ud) -{ - const int buflen = 256; - char name[buflen]; - - if (clp->servicename) { - free(clp->servicename); - clp->servicename = NULL; - } - - if (lnet_nid2hostname(ud->nid, name, buflen)) - return -1; - - clp->servicename = malloc(32 + strlen(name)); - if (!clp->servicename) { - printerr(0, "can't alloc memory\n"); - return -1; - } - sprintf(clp->servicename, "%s@%s", - ud->svc == LUSTRE_GSS_SVC_MDS ? - GSSD_SERVICE_MDS : GSSD_SERVICE_OSS, - name); - printerr(2, "constructed servicename: %s\n", clp->servicename); - return 0; -} - -/* - * this code uses the userland rpcsec gss library to create a krb5 - * context on behalf of the kernel - */ -void -handle_krb5_upcall(struct clnt_info *clp) -{ - pid_t pid; - gss_buffer_desc token = { 0, NULL }; - struct lgssd_upcall_data updata; - struct lustre_gss_data lgd; - char **credlist = NULL; - char **ccname; - int read_rc; - - printerr(2, "handling krb5 upcall\n"); - - memset(&lgd, 0, sizeof(lgd)); - lgd.lgd_rpc_err = -EPERM; /* default error code */ - - read_rc = read(clp->krb5_fd, &updata, sizeof(updata)); - if (read_rc < 0) { - printerr(0, "WARNING: failed reading from krb5 " - "upcall pipe: %s\n", strerror(errno)); - return; - } else if (read_rc != sizeof(updata)) { - printerr(0, "upcall data mismatch: length %d, expect %d\n", - read_rc, sizeof(updata)); - - /* the sequence number must be the first field. if read >= 4 - * bytes then we know at least sequence is fine, try to send - * error notification nicely. - */ - if (read_rc >= 4) - do_error_downcall(clp->krb5_fd, updata.seq, -EPERM, 0); - return; - } - - /* FIXME temporary fix, do this before fork. - * in case of errors could have memory leak!!! - */ - if (updata.uid == 0) { - if (gssd_get_krb5_machine_cred_list(&credlist)) { - printerr(0, "ERROR: Failed to obtain machine " - "credentials\n"); - do_error_downcall(clp->krb5_fd, updata.seq, -EPERM, 0); - return; - } - } - - /* fork child process */ - pid = fork(); - if (pid < 0) { - printerr(0, "can't fork: %s\n", strerror(errno)); - do_error_downcall(clp->krb5_fd, updata.seq, -EPERM, 0); - return; - } else if (pid > 0) { - printerr(2, "forked child process: %d\n", pid); - return; - } - - printerr(1, "krb5 upcall: seq %u, uid %u, svc %u, nid 0x%llx, obd %s\n", - updata.seq, updata.uid, updata.svc, updata.nid, updata.obd); - - if (updata.svc != LUSTRE_GSS_SVC_MDS && - updata.svc != LUSTRE_GSS_SVC_OSS) { - printerr(0, "invalid svc %d\n", updata.svc); - lgd.lgd_rpc_err = -EPROTO; - goto out_return_error; - } - updata.obd[sizeof(updata.obd)-1] = '\0'; - - if (construct_service_name(clp, &updata)) { - printerr(0, "failed to construct service name\n"); - goto out_return_error; - } - - if (updata.uid == 0) { - int success = 0; - - /* - * Get a list of credential cache names and try each - * of them until one works or we've tried them all - */ -/* - if (gssd_get_krb5_machine_cred_list(&credlist)) { - printerr(0, "ERROR: Failed to obtain machine " - "credentials for %s\n", clp->servicename); - goto out_return_error; - } -*/ - for (ccname = credlist; ccname && *ccname; ccname++) { - gssd_setup_krb5_machine_gss_ccache(*ccname); - if ((gssd_create_lgd(clp, &lgd, &updata, - AUTHTYPE_KRB5)) == 0) { - /* Success! */ - success++; - break; - } - printerr(2, "WARNING: Failed to create krb5 context " - "for user with uid %d with credentials " - "cache %s for service %s\n", - updata.uid, *ccname, clp->servicename); - } - gssd_free_krb5_machine_cred_list(credlist); - if (!success) { - printerr(0, "ERROR: Failed to create krb5 context " - "for user with uid %d with any " - "credentials cache for service %s\n", - updata.uid, clp->servicename); - goto out_return_error; - } - } - else { - /* Tell krb5 gss which credentials cache to use */ - gssd_setup_krb5_user_gss_ccache(updata.uid, clp->servicename); - - if ((gssd_create_lgd(clp, &lgd, &updata, AUTHTYPE_KRB5)) != 0) { - printerr(0, "WARNING: Failed to create krb5 context " - "for user with uid %d for service %s\n", - updata.uid, clp->servicename); - goto out_return_error; - } - } - - if (serialize_context_for_kernel(lgd.lgd_ctx, &token, &krb5oid)) { - printerr(0, "WARNING: Failed to serialize krb5 context for " - "user with uid %d for service %s\n", - updata.uid, clp->servicename); - goto out_return_error; - } - - printerr(1, "refreshed: %u@%s for %s\n", - updata.uid, updata.obd, clp->servicename); - do_downcall(clp->krb5_fd, &updata, &lgd, &token); - -out: - if (token.value) - free(token.value); - - gssd_free_lgd(&lgd); - exit(0); /* i'm child process */ - -out_return_error: - do_error_downcall(clp->krb5_fd, updata.seq, - lgd.lgd_rpc_err, lgd.lgd_gss_err); - goto out; -} - diff --git a/lustre/utils/gss/krb5_util.c b/lustre/utils/gss/krb5_util.c deleted file mode 100644 index f3e99f9..0000000 --- a/lustre/utils/gss/krb5_util.c +++ /dev/null @@ -1,1002 +0,0 @@ -/* - * Adapted in part from MIT Kerberos 5-1.2.1 slave/kprop.c and from - * http://docs.sun.com/?p=/doc/816-1331/6m7oo9sms&a=view - * - * Copyright (c) 2002-2004 The Regents of the University of Michigan. - * All rights reserved. - * - * Andy Adamson - * J. Bruce Fields - * Marius Aamodt Eriksen - * Kevin Coffman - */ - -/* - * slave/kprop.c - * - * Copyright 1990,1991 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. - */ - -/* - * Copyright 1994 by OpenVision Technologies, Inc. - * - * Permission to use, copy, modify, distribute, and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appears in all copies and - * that both that copyright notice and this permission notice appear in - * supporting documentation, and that the name of OpenVision not be used - * in advertising or publicity pertaining to distribution of the software - * without specific, written prior permission. OpenVision makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ -/* - krb5_util.c - - Copyright (c) 2004 The Regents of the University of Michigan. - All rights reserved. - - 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. - -*/ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include "config.h" -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#ifdef HAVE_NETDB_H -# include -#endif -#include -#include -#include -#include -#include -#ifdef USE_PRIVATE_KRB5_FUNCTIONS -#include -#endif -#include - -#include "gssd.h" -#include "err_util.h" -#include "gss_util.h" -#include "gss_oids.h" -#include "krb5_util.h" - -/* Global list of principals/cache file names for machine credentials */ -struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL; - -/* Encryption types supported by the kernel rpcsec_gss code */ -int num_krb5_enctypes = 0; -krb5_enctype *krb5_enctypes = NULL; - -/* credential expire time in advance */ -unsigned long machine_cred_expire_advance = 300; /* 5 mins */ - -/*==========================*/ -/*=== Internal routines ===*/ -/*==========================*/ - -static int select_krb5_ccache(const struct dirent *d); -static int gssd_find_existing_krb5_ccache(uid_t uid, struct dirent **d); -static int gssd_get_single_krb5_cred(krb5_context context, - krb5_keytab kt, struct gssd_k5_kt_princ *ple); -static int gssd_process_krb5_keytab(krb5_context context, krb5_keytab kt, - char *kt_name); - -/* - * convenient macros, these perhaps need further cleanup - */ -#ifdef HAVE_KRB5 - -#define KEYTAB_ENTRY_MATCH(kte, name) \ - ( \ - (kte).principal->data[0].length == (sizeof(name)-1) && \ - strncmp((kte).principal->data[0].data, (name), sizeof(name)-1) == 0 \ - ) -#define KRB5_FREE_UNPARSED_NAME(ctx, name) \ - krb5_free_unparsed_name((ctx), (name)); -#define KRB5_STRDUP(str) \ - strndup((str).data, (str).length) -#define KRB5_STRCMP(str, name) \ - ( \ - (str)->length != strlen(name) || \ - strncmp((str)->data, (name), (str)->length) != 0 \ - ) -#define KRB5_STRCASECMP(str, name) \ - ( \ - (str)->length != strlen(name) || \ - strncasecmp((str)->data, (name), (str)->length) != 0 \ - ) - -#else /* !HAVE_KRB5 */ - -#define KEYTAB_ENTRY_MATCH(kte, name) \ - ( \ - strlen((kte).principal->name.name_string.val[0]) == \ - (sizeof(name)-1) && \ - strncmp(kte.principal->name.name_string.val[0], (name), \ - sizeof(name)-1) == 0 \ - ) -#define KRB5_FREE_UNPARSED_NAME(ctx, name) \ - free(pname); -#define KRB5_STRDUP(str) \ - strdup(str) -#define KRB5_STRCMP(str, name) \ - strcmp((str), (name)) -#define KRB5_STRCASECMP(str, name) \ - strcmp((str), (name)) - -#endif /* HAVE_KRB5 */ - -/* - * Called from the scandir function to weed out potential krb5 - * credentials cache files - * - * Returns: - * 0 => don't select this one - * 1 => select this one - */ -static int -select_krb5_ccache(const struct dirent *d) -{ - /* - * Note: We used to check d->d_type for DT_REG here, - * but apparenlty reiser4 always has DT_UNKNOWN. - * Check for IS_REG after stat() call instead. - */ - if (strstr(d->d_name, GSSD_DEFAULT_CRED_PREFIX)) - return 1; - else - return 0; -} - -/* - * Look in the ccachedir for files that look like they - * are Kerberos Credential Cache files for a given UID. Return - * non-zero and the dirent pointer for the entry most likely to be - * what we want. Otherwise, return zero and no dirent pointer. - * The caller is responsible for freeing the dirent if one is returned. - * - * Returns: - * 0 => could not find an existing entry - * 1 => found an existing entry - */ -static int -gssd_find_existing_krb5_ccache(uid_t uid, struct dirent **d) -{ - struct dirent **namelist; - int n; - int i; - int found = 0; - struct dirent *best_match_dir = NULL; - struct stat best_match_stat, tmp_stat; - - memset(&best_match_stat, 0, sizeof(best_match_stat)); - *d = NULL; - n = scandir(ccachedir, &namelist, select_krb5_ccache, 0); - if (n < 0) { - perror("scandir looking for krb5 credentials caches"); - } - else if (n > 0) { - char statname[1024]; - for (i = 0; i < n; i++) { - printerr(3, "CC file '%s' being considered\n", - namelist[i]->d_name); - snprintf(statname, sizeof(statname), - "%s/%s", ccachedir, namelist[i]->d_name); - if (stat(statname, &tmp_stat)) { - printerr(0, "Error doing stat on file '%s'\n", - statname); - free(namelist[i]); - continue; - } - /* Only pick caches owned by the user (uid) */ - if (tmp_stat.st_uid != uid) { - printerr(3, "'%s' owned by %u, not %u\n", - statname, tmp_stat.st_uid, uid); - free(namelist[i]); - continue; - } - if (!S_ISREG(tmp_stat.st_mode)) { - printerr(3, "'%s' is not a regular file\n", - statname); - free(namelist[i]); - continue; - } - printerr(3, "CC file '%s' matches owner check and has " - "mtime of %u\n", - namelist[i]->d_name, tmp_stat.st_mtime); - /* - * if more than one match is found, return the most - * recent (the one with the latest mtime), and - * don't free the dirent - */ - if (!found) { - best_match_dir = namelist[i]; - best_match_stat = tmp_stat; - found++; - } - else { - /* - * If the current match has an mtime later - * than the one we are looking at, then use - * the current match. Otherwise, we still - * have the best match. - */ - if (tmp_stat.st_mtime > - best_match_stat.st_mtime) { - free(best_match_dir); - best_match_dir = namelist[i]; - best_match_stat = tmp_stat; - } - else { - free(namelist[i]); - } - printerr(3, "CC file '%s' is our " - "current best match " - "with mtime of %u\n", - best_match_dir->d_name, - best_match_stat.st_mtime); - } - } - free(namelist); - } - if (found) - { - *d = best_match_dir; - } - return found; -} - - -/* - * Obtain credentials via a key in the keytab given - * a keytab handle and a gssd_k5_kt_princ structure. - * Checks to see if current credentials are expired, - * if not, uses the keytab to obtain new credentials. - * - * Returns: - * 0 => success (or credentials have not expired) - * nonzero => error - */ -static int -gssd_get_single_krb5_cred(krb5_context context, - krb5_keytab kt, - struct gssd_k5_kt_princ *ple) -{ - krb5_get_init_creds_opt options; - krb5_creds my_creds; - krb5_ccache ccache = NULL; - char kt_name[BUFSIZ]; - char cc_name[BUFSIZ]; - int code; - time_t now = time(0); - char *cache_type; - - memset(&my_creds, 0, sizeof(my_creds)); - - if (ple->ccname && ple->endtime > now + machine_cred_expire_advance) { - printerr(2, "INFO: Credentials in CC '%s' are good until %d\n", - ple->ccname, ple->endtime); - code = 0; - goto out; - } - - if ((code = krb5_kt_get_name(context, kt, kt_name, BUFSIZ))) { - printerr(0, "ERROR: Unable to get keytab name in " - "gssd_get_single_krb5_cred\n"); - goto out; - } - - krb5_get_init_creds_opt_init(&options); - krb5_get_init_creds_opt_set_address_list(&options, NULL); - -#ifdef TEST_SHORT_LIFETIME - /* set a short lifetime (for debugging only!) */ - printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n"); - krb5_get_init_creds_opt_set_tkt_life(&options, 5*60); -#else - /* FIXME try to get the ticket with lifetime as long as possible, - * to work around ticket-expiry + recovery problem in cmd3-11 - * remove this!!! - */ - krb5_get_init_creds_opt_set_tkt_life(&options, 30*24*60*60); -#endif - if ((code = krb5_get_init_creds_keytab(context, &my_creds, ple->princ, - kt, 0, NULL, &options))) { - char *pname; - if ((krb5_unparse_name(context, ple->princ, &pname))) { - pname = NULL; - } - printerr(0, "WARNING: %s while getting initial ticket for " - "principal '%s' from keytab '%s'\n", - error_message(code), - pname ? pname : "", kt_name); - if (pname) KRB5_FREE_UNPARSED_NAME(context, pname); - goto out; - } - - /* - * Initialize cache file which we're going to be using - */ - - if (use_memcache) - cache_type = "MEMORY"; - else - cache_type = "FILE"; - snprintf(cc_name, sizeof(cc_name), "%s:%s/%s%s_%s", - cache_type, - GSSD_DEFAULT_CRED_DIR, GSSD_DEFAULT_CRED_PREFIX, - GSSD_DEFAULT_MACHINE_CRED_SUFFIX, ple->realm); - ple->endtime = my_creds.times.endtime; - ple->ccname = strdup(cc_name); - if (ple->ccname == NULL) { - printerr(0, "ERROR: no storage to duplicate credentials " - "cache name\n"); - code = ENOMEM; - goto out; - } - if ((code = krb5_cc_resolve(context, cc_name, &ccache))) { - printerr(0, "ERROR: %s while opening credential cache '%s'\n", - error_message(code), cc_name); - goto out; - } - if ((code = krb5_cc_initialize(context, ccache, ple->princ))) { - printerr(0, "ERROR: %s while initializing credential " - "cache '%s'\n", error_message(code), cc_name); - goto out; - } - if ((code = krb5_cc_store_cred(context, ccache, &my_creds))) { - printerr(0, "ERROR: %s while storing credentials in '%s'\n", - error_message(code), cc_name); - goto out; - } - - code = 0; - printerr(1, "Using (machine) credentials cache: '%s'\n", cc_name); - out: - if (ccache) - krb5_cc_close(context, ccache); - krb5_free_cred_contents(context, &my_creds); - return (code); -} - -static struct gssd_k5_kt_princ * gssd_get_realm_ple(void *r) -{ - struct gssd_k5_kt_princ *ple; -#ifdef HAVE_KRB5 - krb5_data *realm = (krb5_data *)r; -#else - char *realm = (char *)r; -#endif - - for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) { - if (KRB5_STRCMP(realm, ple->realm) == 0) - return ple; - } - return NULL; -} - -static void gssd_free_ple(krb5_context kctx, struct gssd_k5_kt_princ *ple) -{ - if (ple->princ) - krb5_free_principal(kctx, ple->princ); - if (ple->realm) - free(ple->realm); - if (ple->ccname) - free(ple->ccname); - free(ple); -} - -static int gssd_remove_ple(krb5_context kctx, struct gssd_k5_kt_princ *ple) -{ - struct gssd_k5_kt_princ **prev = &gssd_k5_kt_princ_list; - struct gssd_k5_kt_princ *ent = gssd_k5_kt_princ_list; - - for (; ent; prev = &ent->next, ent = ent->next) { - if (ent != ple) - continue; - - *prev = ent->next; - gssd_free_ple(kctx, ent); - return 1; - } - return 0; -} - -static -struct gssd_k5_kt_princ *gssd_create_ple(krb5_context kctx, - krb5_principal principal) -{ - struct gssd_k5_kt_princ *ple; - krb5_error_code code; - - ple = malloc(sizeof(*ple)); - if (ple == NULL) { - printerr(0, "ERROR: could not allocate storage " - "for principal list entry\n"); - return NULL; - } - - memset(ple, 0, sizeof(*ple)); - - ple->realm = KRB5_STRDUP(principal->realm); - if (ple->realm == NULL) { - printerr(0, "ERROR: not enough memory while copying realm to " - "principal list entry\n"); - goto err_free; - } - - code = krb5_copy_principal(kctx, principal, &ple->princ); - if (code) { - printerr(0, "ERROR: %s while copying principal " - "to principal list entry\n", - error_message(code)); - goto err_free; - } - - return ple; -err_free: - gssd_free_ple(kctx, ple); - return NULL; -} - -/* - * Process the given keytab file and create a list of principals we - * might use to perform mount operations. - * - * Returns: - * 0 => Success - * nonzero => Error - */ -static int -gssd_process_krb5_keytab(krb5_context context, krb5_keytab kt, char *kt_name) -{ - krb5_kt_cursor cursor; - krb5_keytab_entry kte; - krb5_error_code code; - struct gssd_k5_kt_princ *ple; - int retval = -1; - - /* - * Look through each entry in the keytab file and determine - * if we might want to use it later to do a mount. If so, - * save info in the global principal list - * (gssd_k5_kt_princ_list). - * Note: (ple == principal list entry) - */ - if ((code = krb5_kt_start_seq_get(context, kt, &cursor))) { - printerr(0, "ERROR: %s while beginning keytab scan " - "for keytab '%s'\n", - error_message(code), kt_name); - retval = code; - goto out; - } - - while ((code = krb5_kt_next_entry(context, kt, &kte, &cursor)) == 0) { - char *pname; - if ((code = krb5_unparse_name(context, kte.principal, - &pname))) { - printerr(0, "WARNING: Skipping keytab entry because " - "we failed to unparse principal name: %s\n", - error_message(code)); - continue; - } - printerr(2, "Processing keytab entry for principal '%s'\n", - pname); - - /* mds service entry: - * - hostname and realm should match this node - * - replace existing non-mds entry of this realm - */ - if (KEYTAB_ENTRY_MATCH(kte, GSSD_SERVICE_MDS)) { - krb5_principal princ = kte.principal; - krb5_data *princ_host; - struct utsname utsbuf; - struct hostent *host; - - if (KRB5_STRCASECMP(krb5_princ_realm(context, princ), - this_realm) != 0) { - printerr(2, "alien mds service entry, skip\n"); - goto next; - } - - princ_host = krb5_princ_component(context, princ, 1); - if (princ_host == NULL) { - printerr(2, "mds service entry: no hostname in " - "principal, skip\n"); - goto next; - } - - if (uname(&utsbuf)) { - printerr(2, "mds service entry: unable to get " - "UTS name, skip\n"); - goto next; - } - host = gethostbyname(utsbuf.nodename); - if (host == NULL) { - printerr(2, "mds service entry: unable to get " - "local hostname, skip\n"); - goto next; - } - - if (KRB5_STRCASECMP(princ_host, host->h_name) != 0) { - printerr(2, "mds service entry: hostname " - "doesn't match: %s - %.*s, skip\n", - host->h_name, - princ_host->length, princ_host->data); - goto next; - } - - ple = gssd_get_realm_ple((void *)&kte.principal->realm); - if (ple) { - if (ple->fl_mds) { - printerr(2, - "mds service entry: found a duplicated one, it's like a mis-configuration, skip\n"); - goto next; - } - - gssd_remove_ple(context, ple); - printerr(2, "mds service entry: replace an " - "existed non-mds one\n"); - } - } else if (KEYTAB_ENTRY_MATCH(kte, LUSTRE_ROOT_NAME)) { - ple = gssd_get_realm_ple((void *)&kte.principal->realm); - if (ple) { - if (ple->fl_mds || ple->fl_root) { - printerr(2, "root entry: found a " - "existed %s entry, skip\n", - ple->fl_mds ? "mds" : "root"); - goto next; - } - - gssd_remove_ple(context, ple); - printerr(2, "root entry: replace an existed " - "non-mds non-root one\n"); - } - } else { - printerr(2, "We will NOT use this entry (%s)\n", - pname); - goto next; - } - - /* construct ple */ - printerr(2, "We will use this entry (%s)\n", pname); - ple = gssd_create_ple(context, kte.principal); - if (ple == NULL) { - KRB5_FREE_UNPARSED_NAME(context, pname); - goto out; - } - - /* add proper flags */ - if (KEYTAB_ENTRY_MATCH(kte, GSSD_SERVICE_MDS)) - ple->fl_mds = 1; - else if (KEYTAB_ENTRY_MATCH(kte, LUSTRE_ROOT_NAME)) - ple->fl_root = 1; - - /* enqueue */ - if (gssd_k5_kt_princ_list == NULL) - gssd_k5_kt_princ_list = ple; - else { - ple->next = gssd_k5_kt_princ_list; - gssd_k5_kt_princ_list = ple; - } - next: - KRB5_FREE_UNPARSED_NAME(context, pname); - } - - if ((code = krb5_kt_end_seq_get(context, kt, &cursor))) { - printerr(0, "WARNING: %s while ending keytab scan for " - "keytab '%s'\n", - error_message(code), kt_name); - } - - retval = 0; - out: - return retval; -} - -/* - * Depending on the version of Kerberos, we either need to use - * a private function, or simply set the environment variable. - */ -static void -gssd_set_krb5_ccache_name(char *ccname) -{ -#ifdef USE_GSS_KRB5_CCACHE_NAME - unsigned int maj_stat, min_stat; - - printerr(2, "using gss_krb5_ccache_name to select krb5 ccache %s\n", - ccname); - maj_stat = gss_krb5_ccache_name(&min_stat, ccname, NULL); - if (maj_stat != GSS_S_COMPLETE) { - printerr(0, "WARNING: gss_krb5_ccache_name with " - "name '%s' failed (%s)\n", - ccname, error_message(min_stat)); - } -#else - /* - * Set the KRB5CCNAME environment variable to tell the krb5 code - * which credentials cache to use. (Instead of using the private - * function above for which there is no generic gssapi - * equivalent.) - */ - printerr(2, "using environment variable to select krb5 ccache %s\n", - ccname); - setenv("KRB5CCNAME", ccname, 1); -#endif -} - -/* - * Parse the supported encryption type information - */ -static int -parse_enctypes(char *enctypes) -{ - int n = 0; - char *curr, *comma; - int i; - - /* Just in case this ever gets called more than once */ - if (krb5_enctypes != NULL) { - free(krb5_enctypes); - krb5_enctypes = NULL; - num_krb5_enctypes = 0; - } - - /* count the number of commas */ - for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) { - comma = strchr(curr, ','); - if (comma != NULL) - n++; - else - break; - } - /* If no more commas and we're not at the end, there's one more value */ - if (*curr != '\0') - n++; - - /* Empty string, return an error */ - if (n == 0) - return ENOENT; - - /* Allocate space for enctypes array */ - if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) { - return ENOMEM; - } - - /* Now parse each value into the array */ - for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) { - krb5_enctypes[i++] = atoi(curr); - comma = strchr(curr, ','); - if (comma == NULL) - break; - } - - num_krb5_enctypes = n; - return 0; -} - -/*==========================*/ -/*=== External routines ===*/ -/*==========================*/ - -/* - * Attempt to find the best match for a credentials cache file - * given only a UID. We really need more information, but we - * do the best we can. - * - * Returns: - * void - */ -void -gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername) -{ - char buf[MAX_NETOBJ_SZ]; - struct dirent *d; - - printerr(2, "getting credentials for client with uid %u for " - "server %s\n", uid, servername); - memset(buf, 0, sizeof(buf)); - - if (gssd_find_existing_krb5_ccache(uid, &d)) { - snprintf(buf, sizeof(buf), "FILE:%s/%s", - ccachedir, d->d_name); - free(d); - } - else - snprintf(buf, sizeof(buf), "FILE:%s/%s%u", - ccachedir, GSSD_DEFAULT_CRED_PREFIX, uid); - printerr(2, "using %s as credentials cache for client with " - "uid %u for server %s\n", buf, uid, servername); - gssd_set_krb5_ccache_name(buf); -} - -/* - * Let the gss code know where to find the machine credentials ccache. - * - * Returns: - * void - */ -void -gssd_setup_krb5_machine_gss_ccache(char *ccname) -{ - printerr(2, "using %s as credentials cache for machine creds\n", - ccname); - gssd_set_krb5_ccache_name(ccname); -} - -/* - * The first time through this routine, go through the keytab and - * determine which keys we will try to use as machine credentials. - * Every time through this routine, try to obtain credentials using - * the keytab entries selected the first time through. - * - * Returns: - * 0 => obtained one or more credentials - * nonzero => error - * - */ - -int -gssd_refresh_krb5_machine_creds(void) -{ - krb5_context context = NULL; - krb5_keytab kt = NULL;; - krb5_error_code code; - int retval = -1; - struct gssd_k5_kt_princ *ple; - int gotone = 0; - static int processed_keytab = 0; - - - code = krb5_init_context(&context); - if (code) { - printerr(0, "ERROR: %s while initializing krb5 in " - "gssd_refresh_krb5_machine_creds\n", - error_message(code)); - retval = code; - goto out; - } - - printerr(2, "Using keytab file '%s'\n", keytabfile); - - if ((code = krb5_kt_resolve(context, keytabfile, &kt))) { - printerr(0, "ERROR: %s while resolving keytab '%s'\n", - error_message(code), keytabfile); - goto out; - } - - /* Only go through the keytab file once. Only print messages once. */ - if (gssd_k5_kt_princ_list == NULL && !processed_keytab) { - processed_keytab = 1; - gssd_process_krb5_keytab(context, kt, keytabfile); - if (gssd_k5_kt_princ_list == NULL) { - printerr(0, "ERROR: No usable keytab entries found in " - "keytab '%s'\n", keytabfile); - printerr(0, "You must have a valid keytab entry for " - "%s/@ on MDT nodes, " - "and %s@ on client nodes, in " - "keytab file %s ?\n", - GSSD_SERVICE_MDS, LUSTRE_ROOT_NAME, - keytabfile); - } - } - - /* - * If we don't have any keytab entries we liked, then we have a problem - */ - if (gssd_k5_kt_princ_list == NULL) { - retval = ENOENT; - goto out; - } - - /* - * Now go through the list of saved entries and get initial - * credentials for them (We can't do this while making the - * list because it messes up the keytab iteration cursor - * when we use the keytab to get credentials.) - */ - for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) { - if ((gssd_get_single_krb5_cred(context, kt, ple)) == 0) { - gotone++; - } - } - if (!gotone) { - printerr(0, "ERROR: No usable machine credentials obtained\n"); - goto out; - } - - retval = 0; - out: - if (kt) krb5_kt_close(context, kt); - krb5_free_context(context); - - return retval; -} - - -/* - * Return an array of pointers to names of credential cache files - * which can be used to try to create gss contexts with a server. - * - * Returns: - * 0 => list is attached - * nonzero => error - */ -int -gssd_get_krb5_machine_cred_list(char ***list) -{ - char **l; - int listinc = 10; - int listsize = listinc; - int i = 0; - int retval; - struct gssd_k5_kt_princ *ple; - - /* Assume failure */ - *list = NULL; - - /* Refresh machine credentials */ - retval = gssd_refresh_krb5_machine_creds(); - if (retval) - goto out; - - l = malloc(listsize * sizeof(char *)); - if (l == NULL) { - retval = ENOMEM; - goto out; - } - - for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) { - if (ple->ccname) { - if (i + 1 > listsize) { - void *tmp; - - listsize += listinc; - tmp = realloc(l, listsize * sizeof(char *)); - if (tmp == NULL) { - retval = ENOMEM; - goto out_free; - } - l = tmp; - } - l[i] = strdup(ple->ccname); - if (l[i++] == NULL) { - retval = ENOMEM; - goto out_free; - } - } - } - if (i > 0) { - l[i] = NULL; - *list = l; - return 0; - } -out_free: - while (i > 0) - free(l[i--]); - free(l); -out: - return retval; -} - -/* - * Frees the list of names returned in get_krb5_machine_cred_list() - */ -void -gssd_free_krb5_machine_cred_list(char **list) -{ - char **n; - - if (list == NULL) - return; - for (n = list; n && *n; n++) { - free(*n); - } - free(list); -} - -/* - * Called upon exit. Destroys machine credentials. - */ -void -gssd_destroy_krb5_machine_creds(void) -{ - krb5_context context; - krb5_error_code code = 0; - krb5_ccache ccache; - struct gssd_k5_kt_princ *ple; - - code = krb5_init_context(&context); - if (code) { - printerr(0, "ERROR: %s while initializing krb5\n", - error_message(code)); - goto out; - } - - for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) { - if (!ple->ccname) - continue; - if ((code = krb5_cc_resolve(context, ple->ccname, &ccache))) { - printerr(0, "WARNING: %s while resolving credential " - "cache '%s' for destruction\n", - error_message(code), ple->ccname); - continue; - } - - if ((code = krb5_cc_destroy(context, ccache))) { - printerr(0, "WARNING: %s while destroying credential " - "cache '%s'\n", - error_message(code), ple->ccname); - } - } - out: - krb5_free_context(context); -} - - diff --git a/lustre/utils/gss/krb5_util.h b/lustre/utils/gss/krb5_util.h deleted file mode 100644 index fa5292d..0000000 --- a/lustre/utils/gss/krb5_util.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef KRB5_UTIL_H -#define KRB5_UTIL_H - -#include - -/* - * List of principals from our keytab that we - * may try to get credentials for - */ -struct gssd_k5_kt_princ { - struct gssd_k5_kt_princ *next; - krb5_principal princ; - unsigned int fl_root:1, - fl_mds:1; - char *ccname; - char *realm; - krb5_timestamp endtime; -}; - - -void gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername); -int gssd_get_krb5_machine_cred_list(char ***list); -int gssd_refresh_krb5_machine_creds(void); -void gssd_free_krb5_machine_cred_list(char **list); -void gssd_setup_krb5_machine_gss_ccache(char *servername); -void gssd_destroy_krb5_machine_creds(void); -void gssd_obtain_kernel_krb5_info(void); - - -#endif /* KRB5_UTIL_H */ diff --git a/lustre/utils/gss/lsupport.c b/lustre/utils/gss/lsupport.c index 343a6e6..eda236f 100644 --- a/lustre/utils/gss/lsupport.c +++ b/lustre/utils/gss/lsupport.c @@ -62,7 +62,7 @@ # include "lgss_utils.h" #else # include "err_util.h" -# include "gssd.h" +# include #endif #include "lsupport.h" diff --git a/lustre/utils/gss/write_bytes.h b/lustre/utils/gss/write_bytes.h index a9b24d8..0454ab5 100644 --- a/lustre/utils/gss/write_bytes.h +++ b/lustre/utils/gss/write_bytes.h @@ -33,7 +33,6 @@ #include #include -#include /* for ntohl */ static inline int write_bytes(char **ptr, const char *end, const void *arg, int arg_len) @@ -76,83 +75,4 @@ write_oid(char **p, char *end, gss_OID_desc *arg) return 0; } -static inline 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 inline int -get_buffer(char **ptr, const char *end, gss_buffer_desc *res) -{ - char *p, *q; - p = *ptr; - int len; - if (get_bytes(&p, end, &len, sizeof(len))) - return -1; - res->length = len; /* promote to size_t if necessary */ - q = p + res->length; - if (q > end || q < p) - return -1; - if (!(res->value = malloc(res->length))) - return -1; - memcpy(res->value, p, res->length); - *ptr = q; - return 0; -} - -static inline int -xdr_get_u32(u_int32_t **ptr, const u_int32_t *end, u_int32_t *res) -{ - if (get_bytes((char **)ptr, (char *)end, res, sizeof(res))) - return -1; - *res = ntohl(*res); - return 0; -} - -static inline int -xdr_get_buffer(u_int32_t **ptr, const u_int32_t *end, gss_buffer_desc *res) -{ - u_int32_t *p, *q; - u_int32_t len; - p = *ptr; - if (xdr_get_u32(&p, end, &len)) - return -1; - res->length = len; - q = p + ((res->length + 3) >> 2); - if (q > end || q < p) - return -1; - if (!(res->value = malloc(res->length))) - return -1; - memcpy(res->value, p, res->length); - *ptr = q; - return 0; -} - -static inline int -xdr_write_u32(u_int32_t **ptr, const u_int32_t *end, u_int32_t arg) -{ - u_int32_t tmp; - - tmp = htonl(arg); - return WRITE_BYTES((char **)ptr, (char *)end, tmp); -} - -static inline int -xdr_write_buffer(u_int32_t **ptr, const u_int32_t *end, gss_buffer_desc *arg) -{ - int len = arg->length; - if (xdr_write_u32(ptr, end, len)) - return -1; - return write_bytes((char **)ptr, (char *)end, arg->value, - (arg->length + 3) & ~3); -} - #endif /* _WRITE_BYTES_H_ */ -- 1.8.3.1