diff options
Diffstat (limited to 'usr.sbin/gssd/gssd.c')
-rw-r--r-- | usr.sbin/gssd/gssd.c | 153 |
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); +} + |