aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/gssd/gssd.c
diff options
context:
space:
mode:
authorRick Macklem <rmacklem@FreeBSD.org>2013-07-08 00:50:57 +0000
committerRick Macklem <rmacklem@FreeBSD.org>2013-07-08 00:50:57 +0000
commitbd5012b2df2da5cd42d16be3fed14464baa52e6b (patch)
treecdd55bb1b7fbfe0e01e4e1336bee3ab1c74ed6b3 /usr.sbin/gssd/gssd.c
parent875f3108f7e424b799364e50d41a9628b166decc (diff)
downloadsrc-bd5012b2df2da5cd42d16be3fed14464baa52e6b.tar.gz
src-bd5012b2df2da5cd42d16be3fed14464baa52e6b.zip
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
Notes
Notes: svn path=/head/; revision=253015
Diffstat (limited to 'usr.sbin/gssd/gssd.c')
-rw-r--r--usr.sbin/gssd/gssd.c153
1 files changed, 140 insertions, 13 deletions
diff --git a/usr.sbin/gssd/gssd.c b/usr.sbin/gssd/gssd.c
index 5252fd8f572c..276735cf70e3 100644
--- a/usr.sbin/gssd/gssd.c
+++ b/usr.sbin/gssd/gssd.c
@@ -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], ccfile_substring[NAME_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 *, uid_t, 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_context_args *argp, init_sec_context_res *r
#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_args *argp, acquire_cred_res *result, struc
#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_args *argp, acquire_cred_res *result, struc
" 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_args *argp, acquire_cred_res *result, struc
}
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, uid_t uid, char *rpath)
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 *filepath, uid_t uid, int *retrating,
#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, uid_t uid, gss_cred_id_t *credp)
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);
+}
+