svn commit: r253015 - head/usr.sbin/gssd

Rick Macklem rmacklem at FreeBSD.org
Mon Jul 8 00:50:58 UTC 2013


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);
+}
+


More information about the svn-src-all mailing list