diff -Nrup nfs-utils-1.0.11.lustre/configure.in nfs-utils-1.0.11/configure.in --- nfs-utils-1.0.11.lustre/configure.in 2007-02-21 21:50:03.000000000 -0700 +++ nfs-utils-1.0.11/configure.in 2008-01-02 18:10:29.000000000 -0700 @@ -18,61 +18,14 @@ AC_ARG_WITH(release, RELEASE=$withval, RELEASE=1) AC_SUBST(RELEASE) -AC_ARG_WITH(statedir, - [ --with-statedir=/foo use state dir /foo [/var/lib/nfs]], - statedir=$withval, - statedir=/var/lib/nfs) - AC_SUBST(statedir) -AC_ARG_WITH(statduser, - [AC_HELP_STRING([--with-statduser=rpcuser], - [statd to run under @<:@rpcuser or nobody@:>@] - )], - statduser=$withval, - if test "x$cross_compiling" = "xno"; then - if grep -s '^rpcuser:' /etc/passwd > /dev/null; then - statduser=rpcuser - else - statduser=nobody - fi - else - statduser=nobody - fi) - AC_SUBST(statduser) -AC_ARG_ENABLE(nfsv3, - [AC_HELP_STRING([--enable-nfsv3], - [enable support for NFSv3 @<:@default=yes@:>@])], - enable_nfsv3=$enableval, - enable_nfsv3=yes) - if test "$enable_nfsv3" = yes; then - AC_DEFINE(NFS3_SUPPORTED, 1, [Define this if you want NFSv3 support compiled in]) - else - enable_nfsv3= - fi - AC_SUBST(enable_nfsv3) -AC_ARG_ENABLE(nfsv4, - [AC_HELP_STRING([--enable-nfsv4], - [enable support for NFSv4 @<:@default=yes@:>@])], - enable_nfsv4=$enableval, - enable_nfsv4=yes) - if test "$enable_nfsv4" = yes; then - AC_DEFINE(NFS4_SUPPORTED, 1, [Define this if you want NFSv4 support compiled in]) - IDMAPD=idmapd - else - enable_nfsv4= - IDMAPD= - fi - AC_SUBST(IDMAPD) - AC_SUBST(enable_nfsv4) - AM_CONDITIONAL(CONFIG_NFSV4, [test "$enable_nfsv4" = "yes"]) AC_ARG_ENABLE(gss, [AC_HELP_STRING([--enable-gss], [enable support for rpcsec_gss @<:@default=yes@:>@])], enable_gss=$enableval, enable_gss=yes) if test "$enable_gss" = yes; then - AC_DEFINE(GSS_SUPPORTED, 1, [Define this if you want rpcsec_gss support compiled in]) - GSSD=gssd - SVCGSSD=svcgssd + GSSD=lgssd + SVCGSSD=lsvcgssd else enable_gss= GSSD= @@ -82,38 +35,6 @@ AC_ARG_ENABLE(gss, AC_SUBST(SVCGSSD) AC_SUBST(enable_gss) AM_CONDITIONAL(CONFIG_GSS, [test "$enable_gss" = "yes"]) -AC_ARG_ENABLE(kprefix, - [AC_HELP_STRING([--enable-kprefix], [install progs as rpc.knfsd etc])], - test "$enableval" = "yes" && kprefix=k, - kprefix=) - AC_SUBST(kprefix) -AC_ARG_ENABLE(secure-statd, - [AC_HELP_STRING([--enable-secure-statd], - [Only lockd can use statd (security)])], - test "$enableval" = "yes" && secure_statd=yes, - secure_statd=no) - if test "$secure_statd" = yes; then - AC_DEFINE(RESTRICTED_STATD, 1, [Define this if you want to enable various security checks in statd. These checks basically keep anyone but lockd from using this service.]) - fi - AC_SUBST(secure_statd) -AC_ARG_ENABLE(rquotad, - [AC_HELP_STRING([--enable-rquotad], - [enable rquotad @<:@default=yes@:>@])], - enable_rquotad=$enableval, - enable_rquotad=yes) - if test "$enable_rquotad" = yes; then - RQUOTAD=rquotad - else - RQUOTAD= - fi - AM_CONDITIONAL(CONFIG_RQUOTAD, [test "$enable_rquotad" = "yes"]) - -AC_ARG_ENABLE(mount, - [AC_HELP_STRING([--enable-mount], - [Create mount.nfs and don't use the util-linux mount(8) functionality. @<:@default=no@:>@])], - enable_mount=$enableval, - enable_mount=no) - AM_CONDITIONAL(CONFIG_MOUNT, [test "$enable_mount" = "yes"]) # Check whether user wants TCP wrappers support AC_TCP_WRAPPERS @@ -156,50 +77,15 @@ AC_CHECK_FUNC(connect, , AC_MSG_ERROR(Function 'socket' not found.), $LIBNSL)) AC_CHECK_LIB(crypt, crypt, [LIBCRYPT="-lcrypt"]) -if test "$enable_nfsv4" = yes; then - AC_CHECK_LIB(event, event_dispatch, [libevent=1], AC_MSG_ERROR([libevent needed for nfsv4 support])) - AC_CHECK_LIB(nfsidmap, nfs4_init_name_mapping, [libnfsidmap=1], AC_MSG_ERROR([libnfsidmap needed for nfsv4 support])) - AC_CHECK_HEADERS(event.h, ,AC_MSG_ERROR([libevent needed for nfsv4 support])) - AC_CHECK_HEADERS(nfsidmap.h, ,AC_MSG_ERROR([libnfsidmap needed for nfsv4 support])) - dnl librpcsecgss already has a dependency on libgssapi, - dnl but we need to make sure we get the right version - if test "$enable_gss" = yes; then - PKG_CHECK_MODULES(RPCSECGSS, librpcsecgss >= 0.10, , - [AC_MSG_ERROR([Unable to locate information required to use librpcsecgss. If you have pkgconfig installed, you might try setting environment variable PKG_CONFIG_PATH to /usr/local/lib/pkgconfig]) - ] - ) - PKG_CHECK_MODULES(GSSAPI, libgssapi >= 0.9) - fi - -fi -if test "$knfsd_cv_glibc2" = no; then - AC_CHECK_LIB(bsd, daemon, [LIBBSD="-lbsd"]) -fi -AC_CHECK_LIB(blkid, blkid_get_cache, [LIBBLKID="-lblkid"], AC_MSG_ERROR([libblkid needed])) -AC_CHECK_HEADER(blkid/blkid.h, , AC_MSG_ERROR([Cannot file libblkid header file blkid/blkid.h])) +PKG_CHECK_MODULES(GSSAPI, libgssapi >= 0.9) AC_SUBST(LIBSOCKET) AC_SUBST(LIBCRYPT) AC_SUBST(LIBBSD) AC_SUBST(LIBBLKID) if test "$enable_gss" = yes; then - dnl 'gss' also depends on nfsidmap.h - at least for svcgssd_proc.c - AC_CHECK_HEADERS(nfsidmap.h, ,AC_MSG_ERROR([libnfsidmap needed for gss support])) - AC_CHECK_HEADERS(spkm3.h, ,AC_MSG_WARN([could not locate SPKM3 header; will not have SPKM3 support])) - dnl the nfs4_set_debug function doesn't appear in all version of the library - AC_CHECK_LIB(nfsidmap, nfs4_set_debug, - AC_DEFINE(HAVE_NFS4_SET_DEBUG,1, - [Whether nfs4_set_debug() is present in libnfsidmap]),) - dnl Check for Kerberos V5 AC_KERBEROS_V5 - - dnl This is not done until here because we need to have KRBLIBS set - dnl ("librpcsecgss=1" is so that it doesn't get added to LIBS) - AC_CHECK_LIB(rpcsecgss, authgss_create_default, [librpcsecgss=1], AC_MSG_ERROR([librpcsecgss needed for nfsv4 support]), -lgssapi -ldl) - AC_CHECK_LIB(rpcsecgss, authgss_set_debug_level, - AC_DEFINE(HAVE_AUTHGSS_SET_DEBUG_LEVEL, 1, [Define this if the rpcsec_gss library has the function authgss_set_debug_level]),, -lgssapi -ldl) - fi dnl ************************************************************* @@ -311,33 +197,7 @@ AC_SUBST([ACLOCAL_AMFLAGS], ["-I $ac_mac AC_CONFIG_FILES([ Makefile - linux-nfs/Makefile - support/Makefile - support/export/Makefile - support/include/nfs/Makefile - support/include/rpcsvc/Makefile - support/include/sys/fs/Makefile - support/include/sys/Makefile - support/include/Makefile - support/misc/Makefile - support/nfs/Makefile - tools/Makefile - tools/getiversion/Makefile - tools/locktest/Makefile - tools/nlmtest/Makefile - tools/rpcdebug/Makefile - tools/rpcgen/Makefile utils/Makefile - utils/exportfs/Makefile - utils/gssd/Makefile - utils/idmapd/Makefile - utils/lockd/Makefile - utils/mount/Makefile - utils/mountd/Makefile - utils/nfsd/Makefile - utils/nfsstat/Makefile - utils/rquotad/Makefile - utils/showmount/Makefile - utils/statd/Makefile]) + utils/gssd/Makefile]) AC_OUTPUT diff -Nrup nfs-utils-1.0.11.lustre/Makefile.am nfs-utils-1.0.11/Makefile.am --- nfs-utils-1.0.11.lustre/Makefile.am 2007-02-21 21:50:03.000000000 -0700 +++ nfs-utils-1.0.11/Makefile.am 2008-01-02 18:10:29.000000000 -0700 @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in -SUBDIRS = tools support utils linux-nfs +SUBDIRS = utils MAINTAINERCLEANFILES = Makefile.in diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/cacheio.c nfs-utils-1.0.11/utils/gssd/cacheio.c --- nfs-utils-1.0.11.lustre/utils/gssd/cacheio.c 2007-02-21 21:50:03.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/cacheio.c 2008-01-02 18:11:38.000000000 -0700 @@ -240,7 +240,8 @@ int qword_get(char **bpp, char *dest, in return -1; while (*bp == ' ') bp++; *bpp = bp; - *dest = '\0'; +// why should we clear *dest??? +// *dest = '\0'; return len; } diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/context.c nfs-utils-1.0.11/utils/gssd/context.c --- nfs-utils-1.0.11.lustre/utils/gssd/context.c 2007-02-21 21:50:03.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/context.c 2008-01-02 18:11:38.000000000 -0700 @@ -33,11 +33,14 @@ #include #include #include -#include -#include -#include "gss_util.h" -#include "gss_oids.h" -#include "err_util.h" + +#ifdef _NEW_BUILD_ +# include "lgss_utils.h" +#else +# include "gss_util.h" +# include "gss_oids.h" +# include "err_util.h" +#endif #include "context.h" int diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/context.h nfs-utils-1.0.11/utils/gssd/context.h --- nfs-utils-1.0.11.lustre/utils/gssd/context.h 2008-01-02 17:22:48.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/context.h 2008-01-02 18:11:38.000000000 -0700 @@ -31,8 +31,6 @@ #ifndef _CONTEXT_H_ #define _CONTEXT_H_ -#include - /* Hopefully big enough to hold any serialized context */ #define MAX_CTX_LEN 4096 diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/context_heimdal.c nfs-utils-1.0.11/utils/gssd/context_heimdal.c --- nfs-utils-1.0.11.lustre/utils/gssd/context_heimdal.c 2007-02-21 21:50:03.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/context_heimdal.c 2008-01-02 18:11:38.000000000 -0700 @@ -43,8 +43,13 @@ #ifdef HAVE_COM_ERR_H #include #endif -#include "err_util.h" -#include "gss_oids.h" + +#ifdef _NEW_BUILD_ +# include "lgss_utils.h" +#else +# include "err_util.h" +# include "gss_oids.h" +#endif #include "write_bytes.h" int write_heimdal_keyblock(char **p, char *end, krb5_keyblock *key) diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/context_lucid.c nfs-utils-1.0.11/utils/gssd/context_lucid.c --- nfs-utils-1.0.11.lustre/utils/gssd/context_lucid.c 2008-01-02 17:22:48.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/context_lucid.c 2008-01-02 18:11:38.000000000 -0700 @@ -41,11 +41,7 @@ #include #include #include -#include "gss_util.h" -#include "gss_oids.h" -#include "err_util.h" -#include "context.h" - +#include #include #include #ifndef OM_uint64 @@ -53,6 +49,16 @@ typedef uint64_t OM_uint64; #endif #include +#ifdef _NEW_BUILD_ +# include "lgss_utils.h" +#else +# include "gss_util.h" +# include "gss_oids.h" +# include "err_util.h" +#endif +#include "write_bytes.h" +#include "context.h" + static int write_lucid_keyblock(char **p, char *end, gss_krb5_lucid_key_t *key) { @@ -354,6 +360,7 @@ static int prepare_krb5_rfc4121_buffer(gss_krb5_lucid_context_v1_t *lctx, gss_buffer_desc *buf) { + static int constant_two = 2; char *p, *end; uint32_t v2_flags = 0; gss_krb5_lucid_key_t enc_key; @@ -372,7 +379,7 @@ prepare_krb5_rfc4121_buffer(gss_krb5_luc end = buf->value + MAX_CTX_LEN; /* Version 2 */ - if (WRITE_BYTES(&p, end, lctx->initiate)) goto out_err; + if (WRITE_BYTES(&p, end, constant_two)) goto out_err; if (WRITE_BYTES(&p, end, lctx->endtime)) goto out_err; if (lctx->initiate) @@ -387,7 +394,7 @@ prepare_krb5_rfc4121_buffer(gss_krb5_luc if (WRITE_BYTES(&p, end, lctx->send_seq)) goto out_err; /* Protocol 0 here implies DES3 or RC4 */ - printerr(2, "%s: protocol %d\n", __FUNCTION__, lctx->protocol); + printerr(3, "protocol %d\n", lctx->protocol); if (lctx->protocol == 0) { enctype = lctx->rfc1964_kd.ctx_key.type; #ifdef HAVE_HEIMDAL @@ -415,8 +422,8 @@ prepare_krb5_rfc4121_buffer(gss_krb5_luc } numkeys = 3; } - printerr(2, "%s: serializing %d keys with enctype %d and size %d\n", - __FUNCTION__, numkeys, enctype, keysize); + printerr(3, "serializing %d keys with enctype %d and size %d\n", + numkeys, enctype, keysize); if (WRITE_BYTES(&p, end, enctype)) goto out_err; if (WRITE_BYTES(&p, end, keysize)) goto out_err; if (WRITE_BYTES(&p, end, numkeys)) goto out_err; @@ -434,14 +441,25 @@ prepare_krb5_rfc4121_buffer(gss_krb5_luc goto out_err; /* Kc */ - if (derive_key_lucid(&lctx->rfc1964_kd.ctx_key, - &derived_key, - KG_USAGE_SIGN, KEY_USAGE_SEED_CHECKSUM)) - goto out_err; - if (write_bytes(&p, end, derived_key.data, - derived_key.length)) - goto out_err; - free(derived_key.data); + /* + * RC4 is special, it dosen't need key derivation. Actually + * the Ke is based on plain text. Here we just let all three + * key identical, kernel will handle everything. --ericm + */ + if (lctx->rfc1964_kd.ctx_key.type == ENCTYPE_ARCFOUR_HMAC) { + if (write_bytes(&p, end, lctx->rfc1964_kd.ctx_key.data, + lctx->rfc1964_kd.ctx_key.length)) + goto out_err; + } else { + if (derive_key_lucid(&lctx->rfc1964_kd.ctx_key, + &derived_key, + KG_USAGE_SIGN, KEY_USAGE_SEED_CHECKSUM)) + goto out_err; + if (write_bytes(&p, end, derived_key.data, + derived_key.length)) + goto out_err; + free(derived_key.data); + } } else { gss_krb5_lucid_key_t *keyptr; uint32_t sign_usage, seal_usage; @@ -451,6 +469,7 @@ prepare_krb5_rfc4121_buffer(gss_krb5_luc else keyptr = &lctx->cfx_kd.ctx_key; +#if 0 if (lctx->initiate == 1) { sign_usage = KG_USAGE_INITIATOR_SIGN; seal_usage = KG_USAGE_INITIATOR_SEAL; @@ -458,6 +477,19 @@ prepare_krb5_rfc4121_buffer(gss_krb5_luc sign_usage = KG_USAGE_ACCEPTOR_SIGN; seal_usage = KG_USAGE_ACCEPTOR_SEAL; } +#else + /* FIXME + * These are from rfc4142, but I don't understand: if we supply + * different 'usage' value for client & server, then the peers + * will have different derived keys. How could this work? + * + * Here we simply use old SIGN/SEAL values until we find the + * answer. --ericm + * FIXME + */ + sign_usage = KG_USAGE_SIGN; + seal_usage = KG_USAGE_SEAL; +#endif /* derive and send down: Ke, Ki, and Kc */ @@ -515,7 +547,7 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss gss_krb5_lucid_context_v1_t *lctx = 0; int retcode = 0; - printerr(2, "DEBUG: %s: lucid version!\n", __FUNCTION__); + printerr(3, "lucid version!\n"); maj_stat = gss_export_lucid_sec_context(&min_stat, &ctx, 1, &return_ctx); if (maj_stat != GSS_S_COMPLETE) { diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/context_mit.c nfs-utils-1.0.11/utils/gssd/context_mit.c --- nfs-utils-1.0.11.lustre/utils/gssd/context_mit.c 2008-01-02 17:22:48.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/context_mit.c 2008-01-02 18:11:38.000000000 -0700 @@ -39,10 +39,15 @@ #include #include #include -#include -#include "gss_util.h" -#include "gss_oids.h" -#include "err_util.h" + +#ifdef _NEW_BUILD_ +# include "lgss_utils.h" +# include "write_bytes.h" +#else +# include "gss_util.h" +# include "gss_oids.h" +# include "err_util.h" +#endif #include "context.h" #include @@ -333,12 +338,7 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss * keydata-2; ( Ki (Kseq for DES3) ) * keydata-3; ( Kc (derived checksum key) ) */ - if (kctx->initiate) { - if (WRITE_BYTES(&p, end, constant_one)) goto out_err; - } - else { - if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; - } + if (WRITE_BYTES(&p, end, constant_two)) goto out_err; if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err; /* Only applicable flag for this is initiator */ diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/context_spkm3.c nfs-utils-1.0.11/utils/gssd/context_spkm3.c --- nfs-utils-1.0.11.lustre/utils/gssd/context_spkm3.c 2007-02-21 21:50:03.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/context_spkm3.c 2008-01-02 18:11:38.000000000 -0700 @@ -33,8 +33,6 @@ #include #include #include -#include -#include #include "gss_util.h" #include "gss_oids.h" #include "err_util.h" diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/err_util.c nfs-utils-1.0.11/utils/gssd/err_util.c --- nfs-utils-1.0.11.lustre/utils/gssd/err_util.c 2007-02-21 21:50:03.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/err_util.c 2008-01-02 18:11:38.000000000 -0700 @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include "err_util.h" static int verbosity = 0; @@ -91,3 +93,40 @@ printit: /* reset the buffer */ memset(message_buf, 0, sizeof(message_buf)); } + +void print_hexl(int pri, unsigned char *cp, int length) +{ + int i, j, jm; + unsigned char c; + + printerr(pri, "length %d\n",length); + printerr(pri, "\n"); + + for (i = 0; i < length; i += 0x10) { + printerr(pri, " %04x: ", (u_int)i); + jm = length - i; + jm = jm > 16 ? 16 : jm; + + for (j = 0; j < jm; j++) { + if ((j % 2) == 1) + printerr(pri,"%02x ", (u_int)cp[i+j]); + else + printerr(pri,"%02x", (u_int)cp[i+j]); + } + for (; j < 16; j++) { + if ((j % 2) == 1) + printerr(pri," "); + else + printerr(pri," "); + } + printerr(pri," "); + + for (j = 0; j < jm; j++) { + c = cp[i+j]; + c = isprint(c) ? c : '.'; + printerr(pri,"%c", c); + } + printerr(pri,"\n"); + } +} + diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/err_util.h nfs-utils-1.0.11/utils/gssd/err_util.h --- nfs-utils-1.0.11.lustre/utils/gssd/err_util.h 2007-02-21 21:50:03.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/err_util.h 2008-01-02 18:11:38.000000000 -0700 @@ -33,5 +33,6 @@ void initerr(char *progname, int verbosity, int fg); void printerr(int priority, char *format, ...); +void print_hexl(int pri, unsigned char *cp, int length); #endif /* _ERR_UTIL_H_ */ diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gss_clnt_send_err.c nfs-utils-1.0.11/utils/gssd/gss_clnt_send_err.c --- nfs-utils-1.0.11.lustre/utils/gssd/gss_clnt_send_err.c 2007-02-21 21:50:03.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/gss_clnt_send_err.c 2008-01-02 18:10:29.000000000 -0700 @@ -47,6 +47,7 @@ #include "gssd.h" #include "write_bytes.h" +#if 0 char pipefsdir[PATH_MAX] = GSSD_PIPEFS_DIR; static void @@ -102,3 +103,4 @@ main(int argc, char *argv[]) } exit(0); } +#endif diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gssd.c nfs-utils-1.0.11/utils/gssd/gssd.c --- nfs-utils-1.0.11.lustre/utils/gssd/gssd.c 2008-01-02 17:22:48.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/gssd.c 2008-01-02 18:11:38.000000000 -0700 @@ -38,9 +38,12 @@ #include "config.h" +#include #include #include -#include +#include +#include +#include #include #include @@ -48,23 +51,107 @@ #include #include #include +#include #include "gssd.h" #include "err_util.h" #include "gss_util.h" #include "krb5_util.h" +#include "lsupport.h" char pipefs_dir[PATH_MAX] = GSSD_PIPEFS_DIR; char pipefs_nfsdir[PATH_MAX] = GSSD_PIPEFS_DIR; char keytabfile[PATH_MAX] = GSSD_DEFAULT_KEYTAB_FILE; char ccachedir[PATH_MAX] = GSSD_DEFAULT_CRED_DIR; int use_memcache = 0; +int lgssd_mutex_downcall = -1; -void -sig_die(int signal) +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[1] = { {0, -1, 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[1] = { {0, 1, 0} }; + 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); } @@ -79,7 +166,7 @@ sig_hup(int signal) static void usage(char *progname) { - fprintf(stderr, "usage: %s [-f] [-v] [-r] [-p pipefsdir] [-k keytab] [-d ccachedir]\n", + fprintf(stderr, "usage: %s [-f] [-v] [-p pipefsdir] [-k keytab] [-d ccachedir]\n", progname); exit(1); } @@ -89,7 +176,6 @@ main(int argc, char *argv[]) { int fg = 0; int verbosity = 0; - int rpc_verbosity = 0; int opt; extern char *optarg; char *progname; @@ -99,18 +185,12 @@ main(int argc, char *argv[]) case 'f': fg = 1; break; - case 'm': - /* Accept but ignore this. Now the default. */ - break; case 'M': use_memcache = 1; break; case 'v': verbosity++; break; - case 'r': - rpc_verbosity++; - break; case 'p': strncpy(pipefs_dir, optarg, sizeof(pipefs_dir)); if (pipefs_dir[sizeof(pipefs_dir)-1] != '\0') @@ -131,10 +211,6 @@ main(int argc, char *argv[]) break; } } - snprintf(pipefs_nfsdir, sizeof(pipefs_nfsdir), "%s/%s", - pipefs_dir, GSSD_SERVICE_NAME); - if (pipefs_nfsdir[sizeof(pipefs_nfsdir)-1] != '\0') - errx(1, "pipefs_nfsdir path name too long"); if ((progname = strrchr(argv[0], '/'))) progname++; @@ -142,30 +218,42 @@ main(int argc, char *argv[]) progname = argv[0]; initerr(progname, verbosity, fg); -#ifdef HAVE_AUTHGSS_SET_DEBUG_LEVEL - authgss_set_debug_level(rpc_verbosity); -#else - if (rpc_verbosity > 0) - printerr(0, "Warning: rpcsec_gss library does not " - "support setting debug level\n"); -#endif 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); - /* Process keytab file and get machine credentials */ - gssd_refresh_krb5_machine_creds(); +#if 0 /* Determine Kerberos information from the kernel */ gssd_obtain_kernel_krb5_info(); +#endif + + lgssd_init_mutexs(); + + printerr(0, "lgssd initialized and ready to serve\n"); + lgssd_run(); - gssd_run(); - printerr(0, "gssd_run returned!\n"); - abort(); + lgssd_cleanup(); + printerr(0, "lgssd exiting\n"); + return 0; } diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gssd.h nfs-utils-1.0.11/utils/gssd/gssd.h --- nfs-utils-1.0.11.lustre/utils/gssd/gssd.h 2008-01-02 17:22:48.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/gssd.h 2008-01-02 18:11:38.000000000 -0700 @@ -48,8 +48,13 @@ #define GSSD_DEFAULT_CRED_PREFIX "krb5cc_" #define GSSD_DEFAULT_MACHINE_CRED_SUFFIX "machine" #define GSSD_DEFAULT_KEYTAB_FILE "/etc/krb5.keytab" -#define GSSD_SERVICE_NAME "nfs" -#define GSSD_SERVICE_NAME_LEN 3 +#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 @@ -59,9 +64,9 @@ enum {AUTHTYPE_KRB5, AUTHTYPE_SPKM3, AUT extern char pipefs_dir[PATH_MAX]; -extern char pipefs_nfsdir[PATH_MAX]; extern char keytabfile[PATH_MAX]; extern char ccachedir[PATH_MAX]; +extern char gethostname_ex[PATH_MAX]; extern int use_memcache; TAILQ_HEAD(clnt_list_head, clnt_info) clnt_list; @@ -71,10 +76,6 @@ struct clnt_info { char *dirname; int dir_fd; char *servicename; - char *servername; - int prog; - int vers; - char *protocol; int krb5_fd; int krb5_poll_index; int spkm3_fd; @@ -85,8 +86,14 @@ void init_client_list(void); int update_client_list(void); void handle_krb5_upcall(struct clnt_info *clp); void handle_spkm3_upcall(struct clnt_info *clp); -int gssd_acquire_cred(char *server_name); -void gssd_run(void); +void lgssd_run(void); + + +extern int lgssd_mutex_downcall; +void lgssd_init_mutexs(void); +void lgssd_fini_mutexs(void); +void lgssd_mutex_get(int semid); +void lgssd_mutex_put(int semid); #endif /* _RPC_GSSD_H_ */ diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gssd_main_loop.c nfs-utils-1.0.11/utils/gssd/gssd_main_loop.c --- nfs-utils-1.0.11.lustre/utils/gssd/gssd_main_loop.c 2008-01-02 17:22:48.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/gssd_main_loop.c 2008-01-02 18:11:38.000000000 -0700 @@ -44,6 +44,10 @@ #include #include #include +/* For time() */ +#include +/* For waitpid() */ +#include #include "gssd.h" #include "err_util.h" @@ -94,11 +98,13 @@ scan_poll_results(int ret) }; void -gssd_run() +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; @@ -106,10 +112,10 @@ gssd_run() dn_act.sa_flags = SA_SIGINFO; sigaction(DNOTIFY_SIGNAL, &dn_act, NULL); - if ((fd = open(pipefs_nfsdir, O_RDONLY)) == -1) { + if ((fd = open(pipefs_dir, O_RDONLY)) == -1) { printerr(0, "ERROR: failed to open %s: %s\n", - pipefs_nfsdir, strerror(errno)); - exit(1); + pipefs_dir, strerror(errno)); + return; } fcntl(fd, F_SETSIG, DNOTIFY_SIGNAL); fcntl(fd, F_NOTIFY, DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT); @@ -119,12 +125,30 @@ gssd_run() 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"); - exit(1); + 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. */ @@ -139,6 +163,7 @@ gssd_run() scan_poll_results(ret); } } +out: close(fd); return; } diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gssd_proc.c nfs-utils-1.0.11/utils/gssd/gssd_proc.c --- nfs-utils-1.0.11.lustre/utils/gssd/gssd_proc.c 2008-01-02 17:22:48.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/gssd_proc.c 2008-01-02 18:11:38.000000000 -0700 @@ -43,7 +43,6 @@ #endif #include "config.h" #include -#include #include #include #include @@ -69,6 +68,7 @@ #include "gss_oids.h" #include "krb5_util.h" #include "context.h" +#include "lsupport.h" /* * pollarray: @@ -99,86 +99,10 @@ struct pollfd * pollarray; int pollsize; /* the size of pollaray (in pollfd's) */ -/* XXX buffer problems: */ -static int -read_service_info(char *info_file_name, char **servicename, char **servername, - int *prog, int *vers, char **protocol) { -#define INFOBUFLEN 256 - char buf[INFOBUFLEN]; - static char dummy[128]; - int nbytes; - static char service[128]; - static char address[128]; - char program[16]; - char version[16]; - char protoname[16]; - in_addr_t inaddr; - int fd = -1; - struct hostent *ent = NULL; - int numfields; - - *servicename = *servername = *protocol = NULL; - - if ((fd = open(info_file_name, O_RDONLY)) == -1) { - printerr(0, "ERROR: can't open %s: %s\n", info_file_name, - strerror(errno)); - goto fail; - } - if ((nbytes = read(fd, buf, INFOBUFLEN)) == -1) - goto fail; - close(fd); - - numfields = sscanf(buf,"RPC server: %127s\n" - "service: %127s %15s version %15s\n" - "address: %127s\n" - "protocol: %15s\n", - dummy, - service, program, version, - address, - protoname); - - if (numfields == 5) { - strcpy(protoname, "tcp"); - } else if (numfields != 6) { - goto fail; - } - - /* check service, program, and version */ - if(memcmp(service, "nfs", 3)) return -1; - *prog = atoi(program + 1); /* skip open paren */ - *vers = atoi(version); - if((*prog != 100003) || ((*vers != 2) && (*vers != 3) && (*vers != 4))) - goto fail; - - /* create service name */ - inaddr = inet_addr(address); - if (!(ent = gethostbyaddr(&inaddr, sizeof(inaddr), AF_INET))) { - printerr(0, "ERROR: can't resolve server %s name\n", address); - goto fail; - } - if (!(*servername = calloc(strlen(ent->h_name) + 1, 1))) - goto fail; - memcpy(*servername, ent->h_name, strlen(ent->h_name)); - snprintf(buf, INFOBUFLEN, "%s@%s", service, ent->h_name); - if (!(*servicename = calloc(strlen(buf) + 1, 1))) - goto fail; - memcpy(*servicename, buf, strlen(buf)); - - if (!(*protocol = strdup(protoname))) - goto fail; - return 0; -fail: - printerr(0, "ERROR: failed to read service info\n"); - if (fd != -1) close(fd); - if (*servername) free(*servername); - if (*servicename) free(*servicename); - if (*protocol) free(*protocol); - return -1; -} - 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)); @@ -190,8 +114,6 @@ destroy_client(struct clnt_info *clp) if (clp->spkm3_fd != -1) close(clp->spkm3_fd); if (clp->dirname) free(clp->dirname); if (clp->servicename) free(clp->servicename); - if (clp->servername) free(clp->servername); - if (clp->protocol) free(clp->protocol); free(clp); } @@ -221,7 +143,6 @@ process_clnt_dir_files(struct clnt_info { char kname[32]; char sname[32]; - char info_file_name[32]; if (clp->krb5_fd == -1) { snprintf(kname, sizeof(kname), "%s/krb5", clp->dirname); @@ -233,13 +154,6 @@ process_clnt_dir_files(struct clnt_info } if((clp->krb5_fd == -1) && (clp->spkm3_fd == -1)) return -1; - snprintf(info_file_name, sizeof(info_file_name), "%s/info", - clp->dirname); - if ((clp->servicename == NULL) && - read_service_info(info_file_name, &clp->servicename, - &clp->servername, &clp->prog, &clp->vers, - &clp->protocol)) - return -1; return 0; } @@ -273,6 +187,8 @@ insert_clnt_poll(struct clnt_info *clp) } 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)) { @@ -386,67 +302,106 @@ find_client(char *dirname) int update_client_list(void) { - struct dirent **namelist; + 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_nfsdir) < 0) { + if (chdir(pipefs_dir) < 0) { printerr(0, "ERROR: can't chdir to %s: %s\n", - pipefs_nfsdir, strerror(errno)); + pipefs_dir, strerror(errno)); return -1; } - j = scandir(pipefs_nfsdir, &namelist, NULL, alphasort); - if (j < 0) { - printerr(0, "ERROR: can't scandir %s: %s\n", - pipefs_nfsdir, 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 - && !strncmp(namelist[i]->d_name, "clnt", 4) - && !find_client(namelist[i]->d_name)) + if (i < FD_ALLOC_BLOCK && !find_client(namelist[i]->d_name)) process_clnt_dir(namelist[i]->d_name); - free(namelist[i]); } - free(namelist); + chdir("/"); return 0; } +/* Context creation response. */ +struct lustre_gss_init_res { + gss_buffer_desc gr_ctx; /* context handle */ + u_int gr_major; /* major status */ + u_int gr_minor; /* minor status */ + u_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 */ + u_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, uid_t uid, struct authgss_private_data *pd, - gss_buffer_desc *context_token) +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(1, "doing downcall\n"); - buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) + - sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length + + 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, uid)) goto out_err; + 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, pd->pd_seq_win)) goto out_err; - if (write_buffer(&p, end, &pd->pd_ctx_hndl)) 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; - if (write(k5_fd, buf, p - buf) < p - buf) 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, "Failed to write downcall!\n"); + printerr(0, "ERROR: Failed to write downcall!\n"); return -1; } static int -do_error_downcall(int k5_fd, uid_t uid, int err) +do_error_downcall(int k5_fd, uint32_t seq, int rpc_err, int gss_err) { char buf[1024]; char *p = buf, *end = buf + 1024; @@ -455,19 +410,26 @@ do_error_downcall(int k5_fd, uid_t uid, printerr(1, "doing error downcall\n"); - if (WRITE_BYTES(&p, end, uid)) goto out_err; + 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, err)) goto out_err; + if (WRITE_BYTES(&p, end, rpc_err)) goto out_err; + if (WRITE_BYTES(&p, end, gss_err)) goto out_err; - if (write(k5_fd, buf, p - buf) < p - buf) 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; } +#if 0 /* * Create an RPC connection and establish an authenticated * gss context with a server. @@ -659,7 +621,287 @@ int create_auth_rpc_client(struct clnt_i goto out; } +#endif + +static +int do_negotiation(struct lustre_gss_data *lgd, + gss_buffer_desc *gss_token, + struct lustre_gss_init_res *gr, + int timeout) +{ + char *file = "/proc/fs/lustre/sptlrpc/gss/init_channel"; + struct lgssd_ioctl_param param; + struct passwd *pw; + int fd, ret; + char outbuf[8192]; + unsigned int *p; + int res; + + 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; + 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; + + fd = open(file, O_RDWR); + if (fd < 0) { + printerr(0, "can't open file %s\n", file); + return -1; + } + + ret = write(fd, ¶m, sizeof(param)); + + if (ret != sizeof(param)) { + printerr(0, "lustre ioctl err: %d\n", strerror(errno)); + close(fd); + return -1; + } + if (param.status) { + close(fd); + 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; + } + return -1; + } + p = (unsigned int *)outbuf; + res = *p++; + 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); + close(fd); + return 0; +} + +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 @@ -668,103 +910,145 @@ int create_auth_rpc_client(struct clnt_i void handle_krb5_upcall(struct clnt_info *clp) { - uid_t uid; - CLIENT *rpc_clnt = NULL; - AUTH *auth = NULL; - struct authgss_private_data pd; - gss_buffer_desc token; + 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(1, "handling krb5 upcall\n"); + printerr(2, "handling krb5 upcall\n"); - token.length = 0; - token.value = NULL; - memset(&pd, 0, sizeof(struct authgss_private_data)); + memset(&lgd, 0, sizeof(lgd)); + lgd.lgd_rpc_err = -EPERM; /* default error code */ - if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) { - printerr(0, "WARNING: failed reading uid from krb5 " + 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)); - goto out; + 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 (uid == 0) { + 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, "WARNING: Failed to obtain machine " - "credentials for connection to " - "server %s\n", clp->servername); - goto out_return_error; + 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 ((create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, - AUTHTYPE_KRB5)) == 0) { + 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 server %s\n", - uid, *ccname, clp->servername); + "cache %s for service %s\n", + updata.uid, *ccname, clp->servicename); } gssd_free_krb5_machine_cred_list(credlist); if (!success) { - printerr(0, "WARNING: Failed to create krb5 context " + printerr(0, "ERROR: Failed to create krb5 context " "for user with uid %d with any " - "credentials cache for server %s\n", - uid, clp->servername); + "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(uid, clp->servername); + gssd_setup_krb5_user_gss_ccache(updata.uid, clp->servicename); - if ((create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, - AUTHTYPE_KRB5)) != 0) { + if ((gssd_create_lgd(clp, &lgd, &updata, AUTHTYPE_KRB5)) != 0) { printerr(0, "WARNING: Failed to create krb5 context " - "for user with uid %d for server %s\n", - uid, clp->servername); + "for user with uid %d for service %s\n", + updata.uid, clp->servicename); goto out_return_error; } } - if (!authgss_get_private_data(auth, &pd)) { - printerr(0, "WARNING: Failed to obtain authentication " - "data for user with uid %d for server %s\n", - uid, clp->servername); - goto out_return_error; - } - - if (serialize_context_for_kernel(pd.pd_ctx, &token, &krb5oid)) { + if (serialize_context_for_kernel(lgd.lgd_ctx, &token, &krb5oid)) { printerr(0, "WARNING: Failed to serialize krb5 context for " - "user with uid %d for server %s\n", - uid, clp->servername); + "user with uid %d for service %s\n", + updata.uid, clp->servicename); goto out_return_error; } - do_downcall(clp->krb5_fd, uid, &pd, &token); + 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); - if (pd.pd_ctx_hndl.length != 0) - authgss_free_private_data(&pd); - if (auth) - AUTH_DESTROY(auth); - if (rpc_clnt) - clnt_destroy(rpc_clnt); - return; + + gssd_free_lgd(&lgd); + exit(0); /* i'm child process */ out_return_error: - do_error_downcall(clp->krb5_fd, uid, -1); + do_error_downcall(clp->krb5_fd, updata.seq, + lgd.lgd_rpc_err, lgd.lgd_gss_err); goto out; } @@ -775,6 +1059,7 @@ out_return_error: void handle_spkm3_upcall(struct clnt_info *clp) { +#if 0 uid_t uid; CLIENT *rpc_clnt = NULL; AUTH *auth = NULL; @@ -826,4 +1111,5 @@ out: out_return_error: do_error_downcall(clp->spkm3_fd, uid, -1); goto out; +#endif } diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gss_util.c nfs-utils-1.0.11/utils/gssd/gss_util.c --- nfs-utils-1.0.11.lustre/utils/gssd/gss_util.c 2007-02-21 21:50:03.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/gss_util.c 2008-01-02 18:11:38.000000000 -0700 @@ -87,9 +87,16 @@ #ifdef HAVE_COM_ERR_H #include #endif +#include "lsupport.h" /* Global gssd_credentials handle */ -gss_cred_id_t gssd_creds; +gss_cred_id_t gssd_cred_mds; +gss_cred_id_t gssd_cred_oss; +int gssd_cred_mds_valid = 0; +int gssd_cred_oss_valid = 0; + +char *mds_local_realm = NULL; +char *oss_local_realm = NULL; gss_OID g_mechOid = GSS_C_NULL_OID;; @@ -183,15 +190,56 @@ pgsserr(char *msg, u_int32_t maj_stat, u display_status_2(msg, maj_stat, min_stat, mech); } -int -gssd_acquire_cred(char *server_name) +static +int extract_realm_name(gss_buffer_desc *name, char **realm) +{ + char *sname, *c; + int rc = 0; + + sname = malloc(name->length + 1); + if (!sname) { + printerr(0, "out of memory\n"); + return -ENOMEM; + } + + memcpy(sname, name->value, name->length); + sname[name->length] = '\0'; + printerr(1, "service principal: %s\n", sname); + + c = strchr(sname, '@'); + if (!c) { + printerr(2, "no realm found in principal, use default\n"); + *realm = strdup(this_realm); + if (!*realm) { + printerr(0, "failed to duplicate default realm\n"); + rc = -ENOMEM; + } + } else { + c++; + *realm = strdup(c); + if (!*realm) { + printerr(0, "failed to duplicated realm\n"); + rc = -ENOMEM; + } + } + free(sname); + + return rc; +} + +static +int gssd_acquire_cred(char *server_name, gss_cred_id_t *cred, + char **local_realm, int *valid) { gss_buffer_desc name; gss_name_t target_name; u_int32_t maj_stat, min_stat; u_int32_t ignore_maj_stat, ignore_min_stat; + gss_OID name_type; gss_buffer_desc pbuf; + *valid = 0; + name.value = (void *)server_name; name.length = strlen(server_name); @@ -201,12 +249,20 @@ gssd_acquire_cred(char *server_name) if (maj_stat != GSS_S_COMPLETE) { pgsserr("gss_import_name", maj_stat, min_stat, g_mechOid); - return (FALSE); + return -1; + } + + maj_stat = gss_display_name(&min_stat, target_name, &name, &name_type); + if (maj_stat != GSS_S_COMPLETE) { + pgsserr(0, maj_stat, min_stat, g_mechOid); + return -1; } + if (extract_realm_name(&name, local_realm)) + return -1; maj_stat = gss_acquire_cred(&min_stat, target_name, 0, GSS_C_NULL_OID_SET, GSS_C_ACCEPT, - &gssd_creds, NULL, NULL); + cred, NULL, NULL); if (maj_stat != GSS_S_COMPLETE) { pgsserr("gss_acquire_cred", maj_stat, min_stat, g_mechOid); @@ -218,11 +274,67 @@ gssd_acquire_cred(char *server_name) ignore_maj_stat = gss_release_buffer(&ignore_min_stat, &pbuf); } - } + } else + *valid = 1; ignore_maj_stat = gss_release_name(&ignore_min_stat, &target_name); - return (maj_stat == GSS_S_COMPLETE); + if (maj_stat != GSS_S_COMPLETE) + return -1; + return 0; +} + +int gssd_prepare_creds(int must_srv_mds, int must_srv_oss) +{ + if (gssd_acquire_cred(GSSD_SERVICE_MDS, &gssd_cred_mds, + &mds_local_realm, &gssd_cred_mds_valid)) { + if (must_srv_mds) + return -1; + } + + if (gssd_acquire_cred(GSSD_SERVICE_OSS, &gssd_cred_oss, + &oss_local_realm, &gssd_cred_oss_valid)) { + if (must_srv_oss) + return -1; + } + + if (!gssd_cred_mds_valid && !gssd_cred_oss_valid) { + printerr(0, "can't obtain both mds & oss creds, exit\n"); + return -1; + } + + if (gssd_cred_mds_valid) + printerr(0, "Ready to serve Lustre MDS in realm %s\n", + mds_local_realm ? mds_local_realm : "N/A"); + if (gssd_cred_oss_valid) + printerr(0, "Ready to serve Lustre OSS in realm %s\n", + oss_local_realm ? oss_local_realm : "N/A"); + + return 0; +} + +gss_cred_id_t gssd_select_svc_cred(int lustre_svc) +{ + switch (lustre_svc) { + case LUSTRE_GSS_SVC_MDS: + if (!gssd_cred_mds_valid) { + printerr(0, "ERROR: service cred for mds not ready\n"); + return NULL; + } + printerr(2, "select mds service cred\n"); + return gssd_cred_mds; + case LUSTRE_GSS_SVC_OSS: + if (!gssd_cred_oss_valid) { + printerr(0, "ERROR: service cred for oss not ready\n"); + return NULL; + } + printerr(2, "select oss service cred\n"); + return gssd_cred_oss; + default: + printerr(0, "ERROR: invalid lustre svc id %d\n", lustre_svc); + } + + return NULL; } int gssd_check_mechs(void) @@ -249,3 +361,42 @@ out: return retval; } +/********************************* + * FIXME should be in krb5_util.c + *********************************/ + +#include "krb5_util.h" + +/* realm of this node */ +char *this_realm = NULL; + +int gssd_get_local_realm(void) +{ + krb5_context context = NULL; + krb5_error_code code; + int retval = -1; + + if (this_realm != NULL) + return 0; + + code = krb5_init_context(&context); + if (code) { + printerr(0, "ERROR: get default realm: init ctx: %s\n", + error_message(code)); + goto out; + } + + code = krb5_get_default_realm(context, &this_realm); + if (code) { + printerr(0, "ERROR: get default realm: %s\n", + error_message(code)); + goto out; + } + retval = 0; + + printerr(1, "Local realm: %s\n", this_realm); +out: + krb5_free_context(context); + return retval; +} + diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gss_util.h nfs-utils-1.0.11/utils/gssd/gss_util.h --- nfs-utils-1.0.11.lustre/utils/gssd/gss_util.h 2007-02-21 21:50:03.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/gss_util.h 2008-01-02 18:11:38.000000000 -0700 @@ -32,14 +32,14 @@ #define _GSS_UTIL_H_ #include -#include #include "write_bytes.h" +char *this_realm; extern gss_cred_id_t gssd_creds; -int gssd_acquire_cred(char *server_name); void pgsserr(char *msg, u_int32_t maj_stat, u_int32_t min_stat, const gss_OID mech); int gssd_check_mechs(void); +int gssd_get_local_realm(void); #endif /* _GSS_UTIL_H_ */ diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.c nfs-utils-1.0.11/utils/gssd/krb5_util.c --- nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.c 2008-01-02 17:22:48.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/krb5_util.c 2008-01-02 18:11:38.000000000 -0700 @@ -99,12 +99,15 @@ #include #include #include +#include #include #include +#include #include #include #include +#include #include #include #include @@ -114,7 +117,6 @@ #include #endif #include -#include #include "gssd.h" #include "err_util.h" @@ -129,6 +131,9 @@ struct gssd_k5_kt_princ *gssd_k5_kt_prin 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 ===*/ /*==========================*/ @@ -137,11 +142,55 @@ static int select_krb5_ccache(const stru 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_have_realm_ple(void *realm); 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 * @@ -288,7 +337,7 @@ gssd_get_single_krb5_cred(krb5_context c memset(&my_creds, 0, sizeof(my_creds)); - if (ple->ccname && ple->endtime > now) { + 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; @@ -308,6 +357,12 @@ gssd_get_single_krb5_cred(krb5_context c /* 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))) { @@ -319,11 +374,7 @@ gssd_get_single_krb5_cred(krb5_context c "principal '%s' from keytab '%s'\n", error_message(code), pname ? pname : "", kt_name); -#ifdef HAVE_KRB5 - if (pname) krb5_free_unparsed_name(context, pname); -#else - if (pname) free(pname); -#endif + if (pname) KRB5_FREE_UNPARSED_NAME(context, pname); goto out; } @@ -372,15 +423,7 @@ gssd_get_single_krb5_cred(krb5_context c return (code); } -/* - * Determine if we already have a ple for the given realm - * - * Returns: - * 0 => no ple found for given realm - * 1 => found ple for given realm - */ -static int -gssd_have_realm_ple(void *r) +static struct gssd_k5_kt_princ * gssd_get_realm_ple(void *r) { struct gssd_k5_kt_princ *ple; #ifdef HAVE_KRB5 @@ -390,18 +433,76 @@ gssd_have_realm_ple(void *r) #endif for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) { -#ifdef HAVE_KRB5 - if ((realm->length == strlen(ple->realm)) && - (strncmp(realm->data, ple->realm, realm->length) == 0)) { -#else - if (strcmp(realm, ple->realm) == 0) { -#endif - return 1; - } + 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. @@ -445,82 +546,106 @@ gssd_process_krb5_keytab(krb5_context co } printerr(2, "Processing keytab entry for principal '%s'\n", pname); -#ifdef HAVE_KRB5 - if ( (kte.principal->data[0].length == GSSD_SERVICE_NAME_LEN) && - (strncmp(kte.principal->data[0].data, GSSD_SERVICE_NAME, - GSSD_SERVICE_NAME_LEN) == 0) && -#else - if ( (strlen(kte.principal->name.name_string.val[0]) == GSSD_SERVICE_NAME_LEN) && - (strncmp(kte.principal->name.name_string.val[0], GSSD_SERVICE_NAME, - GSSD_SERVICE_NAME_LEN) == 0) && - -#endif - (!gssd_have_realm_ple((void *)&kte.principal->realm)) ) { - printerr(2, "We will use this entry (%s)\n", pname); - ple = malloc(sizeof(struct gssd_k5_kt_princ)); - if (ple == NULL) { - printerr(0, "ERROR: could not allocate storage " - "for principal list entry\n"); -#ifdef HAVE_KRB5 - krb5_free_unparsed_name(context, pname); -#else - free(pname); -#endif - retval = ENOMEM; - goto out; - } - /* These will be filled in later */ - ple->next = NULL; - ple->ccname = NULL; - ple->endtime = 0; - if ((ple->realm = -#ifdef HAVE_KRB5 - strndup(kte.principal->realm.data, - kte.principal->realm.length)) -#else - strdup(kte.principal->realm)) -#endif - == NULL) { - printerr(0, "ERROR: %s while copying realm to " - "principal list entry\n", - "not enough memory"); -#ifdef HAVE_KRB5 - krb5_free_unparsed_name(context, pname); -#else - free(pname); -#endif - retval = ENOMEM; - goto out; - } - if ((code = krb5_copy_principal(context, - kte.principal, &ple->princ))) { - printerr(0, "ERROR: %s while copying principal " - "to principal list entry\n", - error_message(code)); -#ifdef HAVE_KRB5 - krb5_free_unparsed_name(context, pname); -#else - free(pname); -#endif - retval = code; - goto out; - } - 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; + + /* 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 { + } else { printerr(2, "We will NOT use this entry (%s)\n", pname); + goto next; } -#ifdef HAVE_KRB5 - krb5_free_unparsed_name(context, pname); -#else - free(pname); -#endif + + /* 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))) { @@ -636,6 +761,7 @@ gssd_setup_krb5_user_gss_ccache(uid_t ui 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); @@ -696,7 +822,7 @@ gssd_refresh_krb5_machine_creds(void) goto out; } - printerr(1, "Using keytab file '%s'\n", keytabfile); + 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", @@ -711,12 +837,12 @@ gssd_refresh_krb5_machine_creds(void) if (gssd_k5_kt_princ_list == NULL) { printerr(0, "ERROR: No usable keytab entries found in " "keytab '%s'\n", keytabfile); - printerr(0, "Do you have a valid keytab entry for " - "%s/@ in " + printerr(0, "You must have a valid keytab entry for " + "%s/@ on MDT nodes, " + "and %s@ on client nodes, in " "keytab file %s ?\n", - GSSD_SERVICE_NAME, keytabfile); - printerr(0, "Continuing without (machine) credentials " - "- nfs4 mounts with Kerberos will fail\n"); + GSSD_SERVICE_MDS, LUSTRE_ROOT_NAME, + keytabfile); } } @@ -866,6 +992,7 @@ gssd_destroy_krb5_machine_creds(void) krb5_free_context(context); } +#if 0 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES /* * this routine obtains a credentials handle via gss_acquire_cred() @@ -921,7 +1048,9 @@ limit_krb5_enctypes(struct rpc_gss_sec * return 0; } #endif /* HAVE_SET_ALLOWABLE_ENCTYPES */ +#endif +#if 0 /* * Obtain supported enctypes from kernel. * Set defaults if info is not available. @@ -988,3 +1117,4 @@ gssd_obtain_kernel_krb5_info(void) code); } } +#endif diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.h nfs-utils-1.0.11/utils/gssd/krb5_util.h --- nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.h 2008-01-02 17:22:48.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/krb5_util.h 2008-01-02 18:11:38.000000000 -0700 @@ -10,6 +10,8 @@ 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; @@ -25,8 +27,4 @@ void gssd_destroy_krb5_machine_creds(voi void gssd_obtain_kernel_krb5_info(void); -#ifdef HAVE_SET_ALLOWABLE_ENCTYPES -int limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid); -#endif - #endif /* KRB5_UTIL_H */ diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/Makefile.am nfs-utils-1.0.11/utils/gssd/Makefile.am --- nfs-utils-1.0.11.lustre/utils/gssd/Makefile.am 2007-02-21 21:50:03.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/Makefile.am 2008-01-02 18:10:29.000000000 -0700 @@ -1,17 +1,11 @@ ## Process this file with automake to produce Makefile.in -man8_MANS = gssd.man svcgssd.man - -RPCPREFIX = rpc. +RPCPREFIX = KPREFIX = @kprefix@ -sbin_PREFIXED = gssd svcgssd -sbin_PROGRAMS = $(sbin_PREFIXED) gss_clnt_send_err +sbin_PREFIXED = lgssd lsvcgssd +sbin_PROGRAMS = $(sbin_PREFIXED) sbin_SCRIPTS = gss_destroy_creds -EXTRA_DIST = \ - gss_destroy_creds \ - $(man8_MANS) - COMMON_SRCS = \ context.c \ context_mit.c \ @@ -21,13 +15,15 @@ COMMON_SRCS = \ gss_util.c \ gss_oids.c \ err_util.c \ + lsupport.c \ \ context.h \ err_util.h \ gss_oids.h \ - gss_util.h + gss_util.h \ + lsupport.h -gssd_SOURCES = \ +lgssd_SOURCES = \ $(COMMON_SRCS) \ gssd.c \ gssd_main_loop.c \ @@ -38,13 +34,12 @@ gssd_SOURCES = \ krb5_util.h \ write_bytes.h -gssd_LDADD = $(RPCSECGSS_LIBS) $(KRBLIBS) -gssd_LDFLAGS = $(KRBLDFLAGS) +lgssd_LDADD = $(GSSAPI_LIBS) $(KRBLIBS) +lgssd_LDFLAGS = $(KRBLDFLAGS) -gssd_CFLAGS = $(AM_CFLAGS) $(CFLAGS) \ - $(RPCSECGSS_CFLAGS) $(KRBCFLAGS) +lgssd_CFLAGS = $(AM_CFLAGS) $(CFLAGS) $(GSSAPI_CFLAGS) $(KRBCFLAGS) -svcgssd_SOURCES = \ +lsvcgssd_SOURCES = \ $(COMMON_SRCS) \ cacheio.c \ svcgssd.c \ @@ -55,20 +50,11 @@ svcgssd_SOURCES = \ cacheio.h \ svcgssd.h -svcgssd_LDADD = \ - ../../support/nfs/libnfs.a \ - $(RPCSECGSS_LIBS) -lnfsidmap \ - $(KRBLIBS) - -svcgssd_LDFLAGS = $(KRBLDFLAGS) - -svcgssd_CFLAGS = $(AM_CFLAGS) $(CFLAGS) \ - $(RPCSECGSS_CFLAGS) $(KRBCFLAGS) +lsvcgssd_LDADD = $(GSSAPI_LIBS) $(KRBLIBS) -gss_clnt_send_err_SOURCES = gss_clnt_send_err.c +lsvcgssd_LDFLAGS = $(KRBLDFLAGS) -gss_clnt_send_err_CFLAGS = $(AM_CFLAGS) $(CFLAGS) \ - $(RPCSECGSS_CFLAGS) $(KRBCFLAGS) +lsvcgssd_CFLAGS = $(AM_CFLAGS) $(CFLAGS) $(GSSAPI_CFLAGS) $(KRBCFLAGS) MAINTAINERCLEANFILES = Makefile.in @@ -92,23 +78,3 @@ uninstall-hook: done) -# XXX This makes some assumptions about what automake does. -# XXX But there is no install-man-hook or install-man-local. -install-man: install-man8 install-man-links -uninstall-man: uninstall-man8 uninstall-man-links - -install-man-links: - (cd $(DESTDIR)$(man8dir) && \ - for m in $(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS); do \ - inst=`echo $$m | sed -e 's/man$$/8/'`; \ - rm -f $(RPCPREFIX)$$inst ; \ - $(LN_S) $$inst $(RPCPREFIX)$$inst ; \ - done) - -uninstall-man-links: - (cd $(DESTDIR)$(man8dir) && \ - for m in $(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS); do \ - inst=`echo $$m | sed -e 's/man$$/8/'`; \ - rm -f $(RPCPREFIX)$$inst ; \ - done) - diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.c nfs-utils-1.0.11/utils/gssd/svcgssd.c --- nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.c 2007-02-21 21:50:03.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/svcgssd.c 2008-01-02 18:11:38.000000000 -0700 @@ -43,7 +43,6 @@ #include #include #include -#include #include #include @@ -54,11 +53,33 @@ #include #include #include -#include -#include "nfslib.h" +#include #include "svcgssd.h" #include "gss_util.h" #include "err_util.h" +#include "lsupport.h" + +void +closeall(int min) +{ + DIR *dir = opendir("/proc/self/fd"); + if (dir != NULL) { + int dfd = dirfd(dir); + struct dirent *d; + + while ((d = readdir(dir)) != NULL) { + char *endp; + long n = strtol(d->d_name, &endp, 10); + if (*endp != '\0' && n >= min && n != dfd) + (void) close(n); + } + closedir(dir); + } else { + int fd = sysconf(_SC_OPEN_MAX); + while (--fd >= min) + (void) close(fd); + } +} /* * mydaemon creates a pipe between the partent and child @@ -140,6 +161,7 @@ void sig_die(int signal) { /* destroy krb5 machine creds */ + cleanup_mapping(); printerr(1, "exiting on signal %d\n", signal); exit(1); } @@ -155,7 +177,7 @@ sig_hup(int signal) static void usage(char *progname) { - fprintf(stderr, "usage: %s [-n] [-f] [-v] [-r] [-i]\n", + fprintf(stderr, "usage: %s [-n] [-f] [-v] [-r] [-m] [-o]\n", progname); exit(1); } @@ -166,9 +188,8 @@ main(int argc, char *argv[]) int get_creds = 1; int fg = 0; int verbosity = 0; - int rpc_verbosity = 0; - int idmap_verbosity = 0; int opt; + int must_srv_mds = 0, must_srv_oss = 0; extern char *optarg; char *progname; @@ -177,17 +198,19 @@ main(int argc, char *argv[]) case 'f': fg = 1; break; - case 'i': - idmap_verbosity++; - break; case 'n': get_creds = 0; break; case 'v': verbosity++; break; - case 'r': - rpc_verbosity++; + case 'm': + get_creds = 1; + must_srv_mds = 1; + break; + case 'o': + get_creds = 1; + must_srv_oss = 1; break; default: usage(argv[0]); @@ -201,34 +224,18 @@ main(int argc, char *argv[]) progname = argv[0]; initerr(progname, verbosity, fg); -#ifdef HAVE_AUTHGSS_SET_DEBUG_LEVEL - authgss_set_debug_level(rpc_verbosity); -#else - if (rpc_verbosity > 0) - printerr(0, "Warning: rpcsec_gss library does not " - "support setting debug level\n"); -#endif -#ifdef HAVE_NFS4_SET_DEBUG - nfs4_set_debug(idmap_verbosity, NULL); -#else - if (idmap_verbosity > 0) - printerr(0, "Warning: your nfsidmap library does not " - "support setting debug level\n"); -#endif if (gssd_check_mechs() != 0) { printerr(0, "ERROR: Problem with gssapi library\n"); exit(1); } - if (!fg) - mydaemon(0, 0); - - signal(SIGINT, sig_die); - signal(SIGTERM, sig_die); - signal(SIGHUP, sig_hup); - - if (get_creds && !gssd_acquire_cred(GSSD_SERVICE_NAME)) { + if (gssd_get_local_realm()) { + printerr(0, "ERROR: Can't get Local Kerberos realm\n"); + exit(1); + } + + if (get_creds && gssd_prepare_creds(must_srv_mds, must_srv_oss)) { printerr(0, "unable to obtain root (machine) credentials\n"); printerr(0, "do you have a keytab entry for " "nfs/@ in " @@ -237,9 +244,23 @@ main(int argc, char *argv[]) } if (!fg) + mydaemon(0, 0); + + /* + * XXX: There is risk of memory leak for missing call + * cleanup_mapping() for SIGKILL and SIGSTOP. + */ + signal(SIGINT, sig_die); + signal(SIGTERM, sig_die); + signal(SIGHUP, sig_hup); + + if (!fg) release_parent(); - gssd_run(); + gssd_init_unique(GSSD_SVC); + + svcgssd_run(); + cleanup_mapping(); printerr(0, "gssd_run returned!\n"); abort(); } diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.h nfs-utils-1.0.11/utils/gssd/svcgssd.h --- nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.h 2007-02-21 21:50:03.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/svcgssd.h 2008-01-02 18:11:38.000000000 -0700 @@ -35,9 +35,20 @@ #include #include -void handle_nullreq(FILE *f); -void gssd_run(void); +int handle_nullreq(FILE *f); +void svcgssd_run(void); +int gssd_prepare_creds(int must_srv_mds, int must_srv_oss); +gss_cred_id_t gssd_select_svc_cred(int lustre_svc); -#define GSSD_SERVICE_NAME "nfs" +extern char *mds_local_realm; +extern char *oss_local_realm; + +#define GSSD_SERVICE_NAME "lustre" + +/* XXX */ +#define GSSD_SERVICE_MDS "lustre_mds" +#define GSSD_SERVICE_OSS "lustre_oss" +#define LUSTRE_ROOT_NAME "lustre_root" +#define LUSTRE_ROOT_NAMELEN 11 #endif /* _RPC_SVCGSSD_H_ */ diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_main_loop.c nfs-utils-1.0.11/utils/gssd/svcgssd_main_loop.c --- nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_main_loop.c 2007-02-21 21:50:03.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/svcgssd_main_loop.c 2008-01-02 18:11:38.000000000 -0700 @@ -42,50 +42,72 @@ #include #include #include +/* For nanosleep() */ +#include #include "svcgssd.h" #include "err_util.h" +/* + * nfs4 in-kernel cache implementation make upcall failed directly + * if there's no listener detected. so here we should keep the init + * channel file open as possible as we can. + * + * unfortunately the proc doesn't support dir change notification. + * and when an entry get unlinked, we only got POLLIN event once, + * it's the only oppotunity we can close the file and startover. + */ void -gssd_run() +svcgssd_run() { int ret; - FILE *f; + FILE *f = NULL; struct pollfd pollfd; + struct timespec halfsec = { .tv_sec = 0, .tv_nsec = 500000000 }; -#define NULLRPC_FILE "/proc/net/rpc/auth.rpcsec.init/channel" +#define NULLRPC_FILE "/proc/net/rpc/auth.sptlrpc.init/channel" - f = fopen(NULLRPC_FILE, "rw"); - - if (!f) { - printerr(0, "failed to open %s: %s\n", - NULLRPC_FILE, strerror(errno)); - exit(1); - } - pollfd.fd = fileno(f); - pollfd.events = POLLIN; while (1) { int save_err; + while (f == NULL) { + f = fopen(NULLRPC_FILE, "rw"); + if (f == NULL) { + printerr(4, "failed to open %s: %s\n", + NULLRPC_FILE, strerror(errno)); + nanosleep(&halfsec, NULL); + } else { + printerr(1, "successfully open %s\n", + NULLRPC_FILE); + break; + } + } + pollfd.fd = fileno(f); + pollfd.events = POLLIN; + pollfd.revents = 0; - printerr(1, "entering poll\n"); - ret = poll(&pollfd, 1, -1); + ret = poll(&pollfd, 1, 1000); save_err = errno; - printerr(1, "leaving poll\n"); + if (ret < 0) { - if (save_err != EINTR) - printerr(0, "error return from poll: %s\n", - strerror(save_err)); + printerr(0, "error return from poll: %s\n", + strerror(save_err)); + fclose(f); + f = NULL; } else if (ret == 0) { - /* timeout; shouldn't happen. */ + printerr(3, "poll timeout\n"); } else { if (ret != 1) { printerr(0, "bug: unexpected poll return %d\n", ret); exit(1); } - if (pollfd.revents & POLLIN) - handle_nullreq(f); + if (pollfd.revents & POLLIN) { + if (handle_nullreq(f) < 0) { + fclose(f); + f = NULL; + } + } } } } diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_proc.c nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c --- nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_proc.c 2007-02-21 21:50:03.000000000 -0700 +++ nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c 2008-01-02 18:11:38.000000000 -0700 @@ -35,7 +35,6 @@ #include #include -#include #include #include @@ -44,25 +43,28 @@ #include #include #include -#include +#include #include "svcgssd.h" #include "gss_util.h" #include "err_util.h" #include "context.h" #include "cacheio.h" +#include "lsupport.h" extern char * mech2file(gss_OID mech); -#define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.rpcsec.context/channel" -#define SVCGSSD_INIT_CHANNEL "/proc/net/rpc/auth.rpcsec.init/channel" +#define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.sptlrpc.context/channel" +#define SVCGSSD_INIT_CHANNEL "/proc/net/rpc/auth.sptlrpc.init/channel" #define TOKEN_BUF_SIZE 8192 struct svc_cred { - uid_t cr_uid; - gid_t cr_gid; - int cr_ngroups; - gid_t cr_groups[NGROUPS]; + uint32_t cr_remote; + uint32_t cr_usr_root; + uint32_t cr_usr_mds; + uid_t cr_uid; + uid_t cr_mapped_uid; + uid_t cr_gid; }; static int @@ -70,11 +72,10 @@ do_svc_downcall(gss_buffer_desc *out_han gss_OID mech, gss_buffer_desc *context_token) { FILE *f; - int i; char *fname = NULL; int err; - printerr(1, "doing downcall\n"); + printerr(2, "doing downcall\n"); if ((fname = mech2file(mech)) == NULL) goto out_err; f = fopen(SVCGSSD_CONTEXT_CHANNEL, "w"); @@ -87,11 +88,12 @@ do_svc_downcall(gss_buffer_desc *out_han qword_printhex(f, out_handle->value, out_handle->length); /* XXX are types OK for the rest of this? */ qword_printint(f, 0x7fffffff); /*XXX need a better timeout */ + qword_printint(f, cred->cr_remote); + qword_printint(f, cred->cr_usr_root); + qword_printint(f, cred->cr_usr_mds); + qword_printint(f, cred->cr_mapped_uid); qword_printint(f, cred->cr_uid); qword_printint(f, cred->cr_gid); - qword_printint(f, cred->cr_ngroups); - for (i=0; i < cred->cr_ngroups; i++) - qword_printint(f, cred->cr_groups[i]); qword_print(f, fname); qword_printhex(f, context_token->value, context_token->length); err = qword_eol(f); @@ -120,7 +122,7 @@ send_response(FILE *f, gss_buffer_desc * /* XXXARG: */ int g; - printerr(1, "sending null reply\n"); + printerr(2, "sending null reply\n"); qword_addhex(&bp, &blen, in_handle->value, in_handle->length); qword_addhex(&bp, &blen, in_token->value, in_token->length); @@ -160,6 +162,7 @@ send_response(FILE *f, gss_buffer_desc * #define rpcsec_gsserr_credproblem 13 #define rpcsec_gsserr_ctxproblem 14 +#if 0 static void add_supplementary_groups(char *secname, char *name, struct svc_cred *cred) { @@ -183,7 +186,9 @@ add_supplementary_groups(char *secname, } } } +#endif +#if 0 static int get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred) { @@ -249,7 +254,9 @@ out_free: out: return res; } +#endif +#if 0 void print_hexl(int pri, unsigned char *cp, int length) { @@ -286,12 +293,149 @@ print_hexl(int pri, unsigned char *cp, i printerr(pri,"\n"); } } +#endif -void +static int +get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred, + lnet_nid_t nid, uint32_t lustre_svc) +{ + u_int32_t maj_stat, min_stat; + gss_buffer_desc name; + char *sname, *host, *realm; + const int namebuf_size = 512; + char namebuf[namebuf_size]; + int res = -1; + gss_OID name_type = GSS_C_NO_OID; + struct passwd *pw; + + cred->cr_remote = cred->cr_usr_root = cred->cr_usr_mds = 0; + cred->cr_uid = cred->cr_mapped_uid = cred->cr_gid = -1; + + maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type); + if (maj_stat != GSS_S_COMPLETE) { + pgsserr("get_ids: gss_display_name", + maj_stat, min_stat, mech); + return -1; + } + if (name.length >= 0xffff || /* be certain name.length+1 doesn't overflow */ + !(sname = calloc(name.length + 1, 1))) { + printerr(0, "WARNING: get_ids: error allocating %d bytes " + "for sname\n", name.length + 1); + gss_release_buffer(&min_stat, &name); + return -1; + } + memcpy(sname, name.value, name.length); + gss_release_buffer(&min_stat, &name); + + if (lustre_svc == LUSTRE_GSS_SVC_MDS) + lookup_mapping(sname, nid, &cred->cr_mapped_uid); + else + cred->cr_mapped_uid = -1; + + realm = strchr(sname, '@'); + if (realm) + *realm++ = '\0'; + + host = strchr(sname, '/'); + if (host) + *host++ = '\0'; + + if (strcmp(sname, GSSD_SERVICE_OSS) == 0) { + printerr(0, "forbid "GSSD_SERVICE_OSS" as user name\n"); + goto out_free; + } + + /* 1. check host part */ + if (host) { + if (lnet_nid2hostname(nid, namebuf, namebuf_size)) { + printerr(0, "ERROR: failed to resolve hostname for " + "%s/%s@%s from %016llx\n", + sname, host, realm, nid); + goto out_free; + } + + if (strcasecmp(host, namebuf)) { + printerr(0, "ERROR: %s/%s@s claimed hostname doesn't " + "match %s, nid %016llx\n", sname, host, realm, + namebuf, nid); + goto out_free; + } + } else { + if (!strcmp(sname, GSSD_SERVICE_MDS)) { + printerr(0, "ERROR: "GSSD_SERVICE_MDS"@%s from %016llx " + "doesn't bind with hostname\n", + realm ? realm : "", nid); + goto out_free; + } + } + + /* 2. check realm */ + if (!realm) { + /* just deny it + cred->cr_remote = (mds_local_realm != NULL); + */ + printerr(0, "ERROR: %s%s%s have no realm name\n", + sname, host ? "/" : "", host ? "host" : ""); + goto out_free; + } + + if (!mds_local_realm || strcasecmp(mds_local_realm, realm)) { + cred->cr_remote = 1; + + if (cred->cr_mapped_uid == -1) + printerr(0, "ERROR: %s from %016llx is remote but " + "without mapping\n", sname, nid); + /* mapped, skip user checking */ + goto out_free; + } + + /* 3. check user */ + if (!(pw = getpwnam(sname))) { + /* map lustre_root/lustre_mds to root user, which is subject + * to further mapping by root-squash in kernel. */ + if (!strcmp(sname, LUSTRE_ROOT_NAME)) { + cred->cr_uid = 0; + cred->cr_usr_root = 1; + } else if (!strcmp(sname, GSSD_SERVICE_MDS)) { + cred->cr_uid = 0; + cred->cr_usr_mds = 1; + } else { + if (cred->cr_mapped_uid == -1) { + printerr(0, "ERROR: invalid user, %s/%s@%s " + "from %016llx\n", sname, host, + realm, nid); + goto out_free; + } + } + printerr(2, "user %s from %016llx is mapped to %u\n", + sname, nid, cred->cr_mapped_uid); + } else { + /* note: a mapped local user will go to here too */ + cred->cr_uid = pw->pw_uid; + printerr(2, "%s resolve to uid %u\n", sname, cred->cr_uid); + } + + printerr(1, "%s: authenticated %s%s%s@%s from %016llx\n", + lustre_svc_name[lustre_svc], sname, + host ? "/" : "", host ? host : "", realm, nid); + res = 0; +out_free: + free(sname); + return res; +} + +typedef struct gss_union_ctx_id_t { + gss_OID mech_type; + gss_ctx_id_t internal_ctx_id; +} gss_union_ctx_id_desc, *gss_union_ctx_id_t; + +/* + * return -1 only if we detect error during reading from upcall channel, + * all other cases return 0. + */ +int handle_nullreq(FILE *f) { - /* XXX initialize to a random integer to reduce chances of unnecessary - * invalidation of existing ctx's on restarting svcgssd. */ - static u_int32_t handle_seq = 0; + uint64_t handle_seq; char in_tok_buf[TOKEN_BUF_SIZE]; char in_handle_buf[15]; char out_handle_buf[15]; @@ -303,10 +447,13 @@ handle_nullreq(FILE *f) { ignore_out_tok = {.value = NULL}, /* XXX isn't there a define for this?: */ null_token = {.value = NULL}; + uint32_t lustre_svc; + lnet_nid_t nid; u_int32_t ret_flags; gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; gss_name_t client_name; gss_OID mech = GSS_C_NO_OID; + gss_cred_id_t svc_cred; u_int32_t maj_stat = GSS_S_FAILURE, min_stat = 0; u_int32_t ignore_min_stat; struct svc_cred cred; @@ -314,25 +461,31 @@ handle_nullreq(FILE *f) { static int lbuflen = 0; static char *cp; - printerr(1, "handling null request\n"); + printerr(2, "handling null request\n"); if (readline(fileno(f), &lbuf, &lbuflen) != 1) { printerr(0, "WARNING: handle_nullreq: " "failed reading request\n"); - return; + return -1; } cp = lbuf; + qword_get(&cp, (char *) &lustre_svc, sizeof(lustre_svc)); + qword_get(&cp, (char *) &nid, sizeof(nid)); + qword_get(&cp, (char *) &handle_seq, sizeof(handle_seq)); + printerr(2, "handling req: svc %u, nid %016llx, idx %llx\n", + lustre_svc, nid, handle_seq); + in_handle.length = (size_t) qword_get(&cp, in_handle.value, sizeof(in_handle_buf)); - printerr(2, "in_handle: \n"); - print_hexl(2, in_handle.value, in_handle.length); + printerr(3, "in_handle: \n"); + print_hexl(3, in_handle.value, in_handle.length); in_tok.length = (size_t) qword_get(&cp, in_tok.value, sizeof(in_tok_buf)); - printerr(2, "in_tok: \n"); - print_hexl(2, in_tok.value, in_tok.length); + printerr(3, "in_tok: \n"); + print_hexl(3, in_tok.value, in_tok.length); if (in_tok.length < 0) { printerr(0, "WARNING: handle_nullreq: " @@ -352,7 +505,13 @@ handle_nullreq(FILE *f) { memcpy(&ctx, in_handle.value, in_handle.length); } - maj_stat = gss_accept_sec_context(&min_stat, &ctx, gssd_creds, + svc_cred = gssd_select_svc_cred(lustre_svc); + if (!svc_cred) { + printerr(0, "no service credential for svc %u\n", lustre_svc); + goto out_err; + } + + maj_stat = gss_accept_sec_context(&min_stat, &ctx, svc_cred, &in_tok, GSS_C_NO_CHANNEL_BINDINGS, &client_name, &mech, &out_tok, &ret_flags, NULL, NULL); @@ -370,7 +529,8 @@ handle_nullreq(FILE *f) { maj_stat, min_stat, mech); goto out_err; } - if (get_ids(client_name, mech, &cred)) { + + if (get_ids(client_name, mech, &cred, nid, lustre_svc)) { /* get_ids() prints error msg */ maj_stat = GSS_S_BAD_NAME; /* XXX ? */ gss_release_name(&ignore_min_stat, &client_name); @@ -378,10 +538,8 @@ handle_nullreq(FILE *f) { } gss_release_name(&ignore_min_stat, &client_name); - /* Context complete. Pass handle_seq in out_handle to use * for context lookup in the kernel. */ - handle_seq++; out_handle.length = sizeof(handle_seq); memcpy(out_handle.value, &handle_seq, sizeof(handle_seq)); @@ -405,8 +563,7 @@ out: free(ctx_token.value); if (out_tok.value != NULL) gss_release_buffer(&ignore_min_stat, &out_tok); - printerr(1, "finished handling null request\n"); - return; + return 0; out_err: if (ctx != GSS_C_NO_CONTEXT) diff -Nrup nfs-utils-1.0.11.lustre/utils/Makefile.am nfs-utils-1.0.11/utils/Makefile.am --- nfs-utils-1.0.11.lustre/utils/Makefile.am 2007-02-21 21:50:03.000000000 -0700 +++ nfs-utils-1.0.11/utils/Makefile.am 2008-01-02 18:10:29.000000000 -0700 @@ -2,30 +2,6 @@ OPTDIRS = -if CONFIG_RQUOTAD -OPTDIRS += rquotad -endif - -if CONFIG_NFSV4 -OPTDIRS += idmapd -endif - -if CONFIG_GSS -OPTDIRS += gssd -endif - -if CONFIG_MOUNT -OPTDIRS += mount -endif - -SUBDIRS = \ - exportfs \ - lockd \ - mountd \ - nfsd \ - nfsstat \ - showmount \ - statd \ - $(OPTDIRS) +SUBDIRS = gssd MAINTAINERCLEANFILES = Makefile.in