From owner-svn-src-head@FreeBSD.ORG Mon Jul 8 00:50:58 2013 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 5F7B2359; Mon, 8 Jul 2013 00:50:58 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 40F0D1DEA; Mon, 8 Jul 2013 00:50:58 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r680ow1S004500; Mon, 8 Jul 2013 00:50:58 GMT (envelope-from rmacklem@svn.freebsd.org) Received: (from rmacklem@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r680owcc004499; Mon, 8 Jul 2013 00:50:58 GMT (envelope-from rmacklem@svn.freebsd.org) Message-Id: <201307080050.r680owcc004499@svn.freebsd.org> From: Rick Macklem Date: Mon, 8 Jul 2013 00:50:58 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r253015 - head/usr.sbin/gssd X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 08 Jul 2013 00:50:58 -0000 Author: rmacklem Date: Mon Jul 8 00:50:57 2013 New Revision: 253015 URL: http://svnweb.freebsd.org/changeset/base/253015 Log: Add a new "-h" option to the gssd daemon that enables support for host based (kerberos service principal) initiator credentials in the default keytab file. This option won't actually be useful until the corresponding kernel changes are committed. Reviewed by: jhb Modified: head/usr.sbin/gssd/gssd.c Modified: head/usr.sbin/gssd/gssd.c ============================================================================== --- head/usr.sbin/gssd/gssd.c Mon Jul 8 00:36:42 2013 (r253014) +++ head/usr.sbin/gssd/gssd.c Mon Jul 8 00:50:57 2013 (r253015) @@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); #ifndef _PATH_GSSDSOCK #define _PATH_GSSDSOCK "/var/run/gssd.sock" #endif +#define GSSD_CREDENTIAL_CACHE_FILE "/tmp/krb5cc_gssd" struct gss_resource { LIST_ENTRY(gss_resource) gr_link; @@ -75,6 +76,7 @@ static char ccfile_dirlist[PATH_MAX + 1] static char pref_realm[1024]; static int verbose; static int use_old_des; +static int hostbased_initiator_cred; #ifndef WITHOUT_KERBEROS /* 1.2.752.43.13.14 */ static gss_OID_desc gss_krb5_set_allowable_enctypes_x_desc = @@ -92,8 +94,10 @@ static int find_ccache_file(const char * static int is_a_valid_tgt_cache(const char *, uid_t, int *, time_t *); static void gssd_verbose_out(const char *, ...); #ifndef WITHOUT_KERBEROS +static krb5_error_code gssd_get_cc_from_keytab(const char *); static OM_uint32 gssd_get_user_cred(OM_uint32 *, uid_t, gss_cred_id_t *); #endif +void gssd_terminate(int); extern void gssd_1(struct svc_req *rqstp, SVCXPRT *transp); extern int gssd_syscall(char *path); @@ -119,11 +123,23 @@ main(int argc, char **argv) pref_realm[0] = '\0'; debug = 0; verbose = 0; - while ((ch = getopt(argc, argv, "dovs:c:r:")) != -1) { + while ((ch = getopt(argc, argv, "dhovs:c:r:")) != -1) { switch (ch) { case 'd': debug_level++; break; + case 'h': +#ifndef WITHOUT_KERBEROS + /* + * Enable use of a host based initiator credential + * in the default keytab file. + */ + hostbased_initiator_cred = 1; +#else + errx(1, "This option not available when built" + " without MK_KERBEROS\n"); +#endif + break; case 'o': #ifndef WITHOUT_KERBEROS /* @@ -182,6 +198,7 @@ main(int argc, char **argv) signal(SIGQUIT, SIG_IGN); signal(SIGHUP, SIG_IGN); } + signal(SIGTERM, gssd_terminate); memset(&sun, 0, sizeof sun); sun.sun_family = AF_LOCAL; @@ -377,7 +394,17 @@ gssd_init_sec_context_1_svc(init_sec_con #endif memset(result, 0, sizeof(*result)); - if (ccfile_dirlist[0] != '\0' && argp->cred == 0) { + if (hostbased_initiator_cred != 0 && argp->cred != 0 && + argp->uid == 0) { + /* + * These credentials are for a host based initiator name + * in a keytab file, which should now have credentials + * in /tmp/krb5cc_gssd, because gss_acquire_cred() did + * the equivalent of "kinit -k". + */ + snprintf(ccname, sizeof(ccname), "FILE:%s", + GSSD_CREDENTIAL_CACHE_FILE); + } else if (ccfile_dirlist[0] != '\0' && argp->cred == 0) { /* * For the "-s" case and no credentials provided as an * argument, search the directory list for an appropriate @@ -773,6 +800,51 @@ gssd_acquire_cred_1_svc(acquire_cred_arg #endif memset(result, 0, sizeof(*result)); + if (argp->desired_name) { + desired_name = gssd_find_resource(argp->desired_name); + if (!desired_name) { + result->major_status = GSS_S_BAD_NAME; + gssd_verbose_out("gssd_acquire_cred: no desired name" + " found\n"); + return (TRUE); + } + } + +#ifndef WITHOUT_KERBEROS + if (hostbased_initiator_cred != 0 && argp->desired_name != 0 && + argp->uid == 0 && argp->cred_usage == GSS_C_INITIATE) { + /* This is a host based initiator name in the keytab file. */ + snprintf(ccname, sizeof(ccname), "FILE:%s", + GSSD_CREDENTIAL_CACHE_FILE); + setenv("KRB5CCNAME", ccname, TRUE); + result->major_status = gss_display_name(&result->minor_status, + desired_name, &namebuf, NULL); + gssd_verbose_out("gssd_acquire_cred: desired name for host " + "based initiator cred major=0x%x minor=%d\n", + (unsigned int)result->major_status, + (int)result->minor_status); + if (result->major_status != GSS_S_COMPLETE) + return (TRUE); + if (namebuf.length > PATH_MAX + 5) { + result->minor_status = 0; + result->major_status = GSS_S_FAILURE; + return (TRUE); + } + memcpy(ccname, namebuf.value, namebuf.length); + ccname[namebuf.length] = '\0'; + if ((cp = strchr(ccname, '@')) != NULL) + *cp = '/'; + kret = gssd_get_cc_from_keytab(ccname); + gssd_verbose_out("gssd_acquire_cred: using keytab entry for " + "%s, kerberos ret=%d\n", ccname, (int)kret); + gss_release_buffer(&minstat, &namebuf); + if (kret != 0) { + result->minor_status = kret; + result->major_status = GSS_S_FAILURE; + return (TRUE); + } + } else +#endif /* !WITHOUT_KERBEROS */ if (ccfile_dirlist[0] != '\0' && argp->desired_name == 0) { /* * For the "-s" case and no name provided as an @@ -798,6 +870,7 @@ gssd_acquire_cred_1_svc(acquire_cred_arg " file found\n"); return (TRUE); } + setenv("KRB5CCNAME", ccname, TRUE); } else { /* * If there wasn't a "-s" option or the name has @@ -815,17 +888,7 @@ gssd_acquire_cred_1_svc(acquire_cred_arg } snprintf(ccname, sizeof(ccname), "FILE:/tmp/krb5cc_%d", (int) argp->uid); - } - setenv("KRB5CCNAME", ccname, TRUE); - - if (argp->desired_name) { - desired_name = gssd_find_resource(argp->desired_name); - if (!desired_name) { - result->major_status = GSS_S_BAD_NAME; - gssd_verbose_out("gssd_acquire_cred: no desired name" - " found\n"); - return (TRUE); - } + setenv("KRB5CCNAME", ccname, TRUE); } result->major_status = gss_acquire_cred(&result->minor_status, @@ -964,6 +1027,8 @@ find_ccache_file(const char *dirpath, ui len = snprintf(namepath, sizeof(namepath), "%s/%s", dirpath, dp->d_name); if (len < sizeof(namepath) && + (hostbased_initiator_cred == 0 || strcmp(namepath, + GSSD_CREDENTIAL_CACHE_FILE) != 0) && strstr(dp->d_name, ccfile_substring) != NULL && lstat(namepath, &sb) >= 0 && sb.st_uid == uid && @@ -1112,6 +1177,57 @@ is_a_valid_tgt_cache(const char *filepat #ifndef WITHOUT_KERBEROS /* + * This function attempts to do essentially a "kinit -k" for the principal + * name provided as the argument, so that there will be a TGT in the + * credential cache. + */ +static krb5_error_code +gssd_get_cc_from_keytab(const char *name) +{ + krb5_error_code ret, opt_ret, princ_ret, cc_ret, kt_ret, cred_ret; + krb5_context context; + krb5_principal principal; + krb5_keytab kt; + krb5_creds cred; + krb5_get_init_creds_opt *opt; + krb5_deltat start_time = 0; + krb5_ccache ccache; + + ret = krb5_init_context(&context); + if (ret != 0) + return (ret); + princ_ret = ret = krb5_parse_name(context, name, &principal); + if (ret == 0) + opt_ret = ret = krb5_get_init_creds_opt_alloc(context, &opt); + if (ret == 0) + cc_ret = ret = krb5_cc_default(context, &ccache); + if (ret == 0) + ret = krb5_cc_initialize(context, ccache, principal); + if (ret == 0) { + krb5_get_init_creds_opt_set_default_flags(context, "gssd", + krb5_principal_get_realm(context, principal), opt); + kt_ret = ret = krb5_kt_default(context, &kt); + } + if (ret == 0) + cred_ret = ret = krb5_get_init_creds_keytab(context, &cred, + principal, kt, start_time, NULL, opt); + if (ret == 0) + ret = krb5_cc_store_cred(context, ccache, &cred); + if (kt_ret == 0) + krb5_kt_close(context, kt); + if (cc_ret == 0) + krb5_cc_close(context, ccache); + if (opt_ret == 0) + krb5_get_init_creds_opt_free(context, opt); + if (princ_ret == 0) + krb5_free_principal(context, principal); + if (cred_ret == 0) + krb5_free_cred_contents(context, &cred); + krb5_free_context(context); + return (ret); +} + +/* * Acquire a gss credential for a uid. */ static OM_uint32 @@ -1159,3 +1275,14 @@ gssd_get_user_cred(OM_uint32 *min_statp, return (maj_stat); } #endif /* !WITHOUT_KERBEROS */ + +void gssd_terminate(int sig __unused) +{ + +#ifndef WITHOUT_KERBEROS + if (hostbased_initiator_cred != 0) + unlink(GSSD_CREDENTIAL_CACHE_FILE); +#endif + exit(0); +} +