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
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")
@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
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
__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
*/
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);
#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);
+++ /dev/null
-/*
- * Modifications for Lustre
- *
- * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- *
- * Copyright (c) 2012, 2016, Intel Corporation.
- *
- * Author: Eric Mei <ericm@clusterfs.com>
- */
-
-/*
- * 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 <dugsong@monkey.org>
- * Andy Adamson <andros@umich.edu>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#define DEBUG_SUBSYSTEM S_SEC
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/dcache.h>
-#include <linux/fs.h>
-#include <linux/mutex.h>
-#include <linux/crypto.h>
-#include <asm/atomic.h>
-struct rpc_clnt; /* for rpc_pipefs */
-#include <linux/sunrpc/rpc_pipe_fs.h>
-
-#include <libcfs/linux/linux-list.h>
-#include <obd.h>
-#include <obd_class.h>
-#include <obd_support.h>
-#include <uapi/linux/lustre/lustre_idl.h>
-#include <lustre_sec.h>
-#include <lustre_net.h>
-#include <lustre_import.h>
-
-#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);
-}
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:
static void __exit sptlrpc_gss_exit(void)
{
gss_exit_keyring();
- gss_exit_pipefs();
cleanup_kerberos_module();
gss_exit_svc_upcall();
gss_exit_cli_upcall();
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"
}
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
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'
[ ! -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"}
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"
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
#
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() {
/Makefile.in
-/lgssd
/lsvcgssd
/l_idmap
/lgss_keyring
endif
endif
-if GSS_PIPEFS
-sbin_PROGRAMS += lgssd
-endif
-
COMMON_SRCS = \
context.c \
context_lucid.c \
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 \
#include <stdio.h>
#include <ctype.h>
#include <string.h>
+#include <krb5.h>
#include <sys/param.h>
+#include <sys/types.h>
#include <gssapi/gssapi.h>
#if defined(HAVE_KRB5) && !defined(GSS_C_NT_HOSTBASED_SERVICE)
#include <gssapi/gssapi_generic.h>
#endif
#include "gss_util.h"
#include "err_util.h"
-#include "gssd.h"
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#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;
* FIXME should be in krb5_util.c
*********************************/
-#include "krb5_util.h"
-
/* realm of this node */
char *this_realm = NULL;
#define _GSS_UTIL_H_
#include <stdlib.h>
-#include "write_bytes.h"
#ifndef fallthrough
# if defined(__GNUC__) && __GNUC__ >= 7
+++ /dev/null
-/*
- gssd.c
-
- Copyright (c) 2000 The Regents of the University of Michigan.
- All rights reserved.
-
- Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
- Copyright (c) 2002 Andy Adamson <andros@UMICH.EDU>.
- Copyright (c) 2002 Marius Aamodt Eriksen <marius@UMICH.EDU>.
- 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 <sys/types.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-#include <sys/ipc.h>
-#include <sys/sem.h>
-
-#include <unistd.h>
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <signal.h>
-#include <errno.h>
-#include <libcfs/util/string.h>
-
-#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;
-}
+++ /dev/null
-/*
- 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 <sys/types.h>
-#include <sys/queue.h>
-#include <gssapi/gssapi.h>
-
-#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_ */
+++ /dev/null
-/*
- 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 <sys/param.h>
-#include <sys/socket.h>
-#include <sys/poll.h>
-#include <netinet/in.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <memory.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <unistd.h>
-/* For time() */
-#include <time.h>
-/* For waitpid() */
-#include <wait.h>
-
-#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);
-}
+++ /dev/null
-/*
- gssd_proc.c
-
- Copyright (c) 2000-2004 The Regents of the University of Michigan.
- All rights reserved.
-
- Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
- Copyright (c) 2001 Andy Adamson <andros@UMICH.EDU>.
- Copyright (c) 2002 Marius Aamodt Eriksen <marius@UMICH.EDU>.
- Copyright (c) 2002 Bruce Fields <bfields@UMICH.EDU>
- Copyright (c) 2004 Kevin Coffman <kwc@umich.edu>
- 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 <sys/param.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <sys/fsuid.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <pwd.h>
-#include <grp.h>
-#include <string.h>
-#include <dirent.h>
-#include <poll.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <unistd.h>
-#include <errno.h>
-#include <gssapi/gssapi.h>
-#ifdef HAVE_NETDB_H
-# include <netdb.h>
-#endif
-
-#include <libcfs/util/param.h>
-#include <uapi/linux/lustre/lgss.h>
-
-#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; i<FD_ALLOC_BLOCK; i++) {
- if (pollarray[i].events == 0) {
- *ind = i;
- break;
- }
- }
- if (*ind == -1) {
- printerr(0, "ERROR: No pollarray slots open\n");
- return -1;
- }
- return 0;
-}
-
-
-static int
-insert_clnt_poll(struct clnt_info *clp)
-{
- if ((clp->krb5_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;
-}
-
+++ /dev/null
-/*
- * 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 <andros@umich.edu>
- * J. Bruce Fields <bfields@umich.edu>
- * Marius Aamodt Eriksen <marius@umich.edu>
- * Kevin Coffman <kwc@umich.edu>
- */
-
-/*
- * 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 <sys/param.h>
-#include <rpc/rpc.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/utsname.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef HAVE_NETDB_H
-# include <netdb.h>
-#endif
-#include <dirent.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <time.h>
-#include <gssapi/gssapi.h>
-#ifdef USE_PRIVATE_KRB5_FUNCTIONS
-#include <gssapi/gssapi_krb5.h>
-#endif
-#include <krb5.h>
-
-#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 : "<unparsable>", 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/<your.host>@<YOUR.REALM> on MDT nodes, "
- "and %s@<YOUR.REALM> 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);
-}
-
-
+++ /dev/null
-#ifndef KRB5_UTIL_H
-#define KRB5_UTIL_H
-
-#include <krb5.h>
-
-/*
- * 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 */
# include "lgss_utils.h"
#else
# include "err_util.h"
-# include "gssd.h"
+# include <gssapi/gssapi.h>
#endif
#include "lsupport.h"
#include <stdlib.h>
#include <sys/types.h>
-#include <netinet/in.h> /* for ntohl */
static inline int
write_bytes(char **ptr, const char *end, const void *arg, int arg_len)
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_ */