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
This commit is contained in:
Rick Macklem 2013-07-08 00:50:57 +00:00
parent 875f3108f7
commit bd5012b2df
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=253015

View File

@ -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 &&
@ -1111,6 +1176,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.
*/
@ -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);
}