On 12/04/2014 12:22 AM, James Ralston wrote: > The MIT Kerberos library has supported credential cache locations > other than "FILE:" for a while now: > > http://web.mit.edu/kerberos/krb5-devel/doc/basic/ccache_def.html > > In fact, RHEL7 sets the default credential cache to use the kernel > keyring, via the new(ish) "default_ccache_name" option in > /etc/krb5.conf: > > [libdefaults] > default_ccache_name = KEYRING:persistent:%{uid} > > However, this will break forwarding Kerberos credentials via > GSSAPIDelegateCredentials. It seems to work for me using rhel-7's openssh sshd: tom@ipa-server $ klist Ticket cache: DIR::/tmp/597000004/tkthx4K48 Default principal: tom@VIRT Valid starting Expires Service principal 12/10/2014 19:08:41 12/11/2014 19:08:41 krbtgt/VIRT@VIRT 12/10/2014 19:08:50 12/11/2014 19:08:41 host/rhel-7-devel.virt@VIRT tom@ipa-server $ ssh -o GSSAPIDelegateCredentials=yes tom@xxxxxxxxxxxxxxxxx Last login: Wed Dec 10 19:29:31 2014 from master.virt tom@rhel-7-devel $ klist Ticket cache: KEYRING:persistent:597000004:krb_ccache_t0MhS7l Default principal: tom@VIRT Valid starting Expires Service principal 12/10/2014 19:29:50 12/11/2014 19:08:41 krbtgt/VIRT@VIRT And using sshd from stock openssh, it works for me too: tom@ipa-server $ ssh -o GSSAPIDelegateCredentials=yes -o GSSAPIAuthentication=yes tom@xxxxxxxxxxxxxxxxx Last login: Wed Dec 10 19:35:22 2014 from ipa-server.virt tom@rhel-7-devel $ klist Ticket cache: FILE:/tmp/krb5cc_597000004_rubDAg07mz Default principal: tom@VIRT Valid starting Expires Service principal 12/10/2014 19:44:19 12/11/2014 19:08:41 krbtgt/VIRT@VIRT and sshd logs show: sshd[27716]: debug1: Setting KRB5CCNAME to FILE:/tmp/krb5cc_597000004_rubDAg07mz > ... > Based on this, I would expect openssh to blast over the library > default, but when I test, I see $KRB5CCNAME set to (e.g.) > KEYRING:persistent:12345, but without credentials in it. (And tracing > the sshd process shows that it never attempted to create any > file-based credential cache.) > > So, two questions: > > First, does anyone know what happens to the credential cache openssh > creates when the library default location is a keyring? Openssh isn't > logging any errors, so I don't think the various krb5 library > functions are failing. Has anyone else already played around with > this? Is it possible that you don't use GSSAPIAuthentication but e.g. PublicKeyAuthentication? Can you see an attempt to send credentials in ssh client logs? Using 'ssh -vv ...' might help. > > Second, is there a reason why openssh hardcodes the ccname location, > instead of using krb5_cc_default_name() to obtain the library default? > > The only reason I can see for doing this is because if the library > default starts with FILE: or DIR:, then you need to append > "XXXXXXXXXX" (if necessary) and then use mkstemp() to get a > non-predictable location. So that would be a little more effort than > what openssh currently does. > > However, this would enable openssh to support Kerberos credential > types other than "FILE:", so I'd argue it's worth it. > Please try attached patch or krb5_cc_default_name branch at [1]. It adds support for using Kerberos credential cache locations based on system wide configuration in /etc/krb5.conf. It tries to read a value of: [libdefaults] default_ccache_name = KEYRING:persistent:%{uid} and parse it. If it's not able to get the value or parse it, it falls back to the original FILE: template. The patch also adds support for DIR and KEYRING types. [1] https://github.com/bachradsusi/openssh-portable/tree/krb5_cc_default_name Petr -- Petr Lautrbach
From 530b2e88029237646048468fb17ea359e899d5ec Mon Sep 17 00:00:00 2001 From: Petr Lautrbach <plautrba@xxxxxxxxxx> Date: Wed, 10 Dec 2014 19:13:38 +0100 Subject: [PATCH] Add support for using kerberos credential location set by "default_ccache_name" in /etc/krb5.conf --- auth-krb5.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++++-------- configure.ac | 2 +- gss-serv-krb5.c | 23 ++++++-- gss-serv.c | 19 +++++-- 4 files changed, 178 insertions(+), 37 deletions(-) diff --git a/auth-krb5.c b/auth-krb5.c index 0089b18..1139134 100644 --- a/auth-krb5.c +++ b/auth-krb5.c @@ -52,6 +52,7 @@ #include <unistd.h> #include <string.h> #include <krb5.h> +#include <profile.h> extern ServerOptions options; @@ -78,7 +79,7 @@ auth_krb5_password(Authctxt *authctxt, const char *password) #endif krb5_error_code problem; krb5_ccache ccache = NULL; - int len; + const char *ccache_type, *ccache_name; char *client, *platform_client; const char *errmsg; @@ -179,12 +180,23 @@ auth_krb5_password(Authctxt *authctxt, const char *password) goto out; #endif - authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); + ccache_type = krb5_cc_get_type(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); + ccache_name = krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); - len = strlen(authctxt->krb5_ticket_file) + 6; - authctxt->krb5_ccname = xmalloc(len); - snprintf(authctxt->krb5_ccname, len, "FILE:%s", - authctxt->krb5_ticket_file); + if (ccache_type == NULL || ccache_name == NULL) + goto out; + + if (ccache_name[0] == ':') + /* DIR caches has two forms: DIR:dirname or DIR::pathname */ + authctxt->krb5_ticket_file = xstrdup(ccache_name + 1); + else + authctxt->krb5_ticket_file = xstrdup(ccache_name); + +#ifdef USE_CCAPI + xasprintf(&authctxt->krb5_ccname, "API:%s", ccache_name); +#else + xasprintf(&authctxt->krb5_ccname, "%s:%s", ccache_type, ccache_name); +#endif #ifdef USE_PAM if (options.use_pam) @@ -236,36 +248,147 @@ krb5_cleanup_proc(Authctxt *authctxt) krb5_free_context(authctxt->krb5_ctx); authctxt->krb5_ctx = NULL; } + if (authctxt->krb5_ccname) { + free(authctxt->krb5_ccname); + authctxt->krb5_ccname = NULL; + } + if (authctxt->krb5_ticket_file) { + free(authctxt->krb5_ticket_file); + authctxt->krb5_ticket_file = NULL; + } +} + +int +ssh_asprintf_append(char **dsc, const char *fmt, ...) { + char *src, *old; + va_list ap; + int i; + + va_start(ap, fmt); + i = vasprintf(&src, fmt, ap); + va_end(ap); + + if (i == -1 || src == NULL) + return -1; + + old = *dsc; + + i = xasprintf(dsc, "%s%s", *dsc, src); + if (i == -1 || src == NULL) { + free(src); + return -1; + } + + free(old); + free(src); + + return i; +} + +int +ssh_krb5_expand_template(char **result, const char *template) { + char *p_n, *p_o, *r, *tmp_template; + + if (template == NULL) + return -1; + + tmp_template = p_n = p_o = xstrdup(template); + r = xstrdup(""); + + while ((p_n = strstr(p_o, "%{")) != NULL) { + + *p_n++ = '\0'; + if (ssh_asprintf_append(&r, "%s", p_o) == -1) + goto cleanup; + + if (strncmp(p_n, "{uid}", 5) == 0 || strncmp(p_n, "{euid}", 6) == 0 || + strncmp(p_n, "{USERID}", 8) == 0) { + p_o = strchr(p_n, '}') + 1; + if (ssh_asprintf_append(&r, "%d", geteuid()) == -1) + goto cleanup; + continue; + } + else if (strncmp(p_n, "{TEMP}", 6) == 0) { + p_o = strchr(p_n, '}') + 1; + if (ssh_asprintf_append(&r, "/tmp") == -1) + goto cleanup; + continue; + } else { + p_o = strchr(p_n, '}') + 1; + p_o = '\0'; + debug("%s: unsupported token %s in %s", __func__, p_n, template); + /* unknown token, fallback to the default */ + goto cleanup; + } + } + + if (ssh_asprintf_append(&r, "%s", p_o) == -1) + goto cleanup; + + *result = r; + free(tmp_template); + return 0; + +cleanup: + free(r); + free(tmp_template); + return -1; +} + +krb5_error_code +ssh_krb5_get_cctemplate(krb5_context ctx, char **ccname) { + profile_t p; + int ret = 0; + char *value = NULL; + + ret = krb5_get_profile(ctx, &p); + if (ret) + return ret; + + ret = profile_get_string(p, "libdefaults", "default_ccache_name", NULL, NULL, &value); + if (ret) + return ret; + + ret = ssh_krb5_expand_template(ccname, value); + + return ret; } #ifndef HEIMDAL krb5_error_code ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { int tmpfd, ret, oerrno; - char ccname[40]; + char *ccname; +#ifdef USE_CCAPI + char cctemplate[] = "API:krb5cc_%d"; +#else mode_t old_umask; + char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX"; - ret = snprintf(ccname, sizeof(ccname), - "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); - if (ret < 0 || (size_t)ret >= sizeof(ccname)) - return ENOMEM; - - old_umask = umask(0177); - tmpfd = mkstemp(ccname + strlen("FILE:")); - oerrno = errno; - umask(old_umask); - if (tmpfd == -1) { - logit("mkstemp(): %.100s", strerror(oerrno)); - return oerrno; - } +#endif + + ret = ssh_krb5_get_cctemplate(ctx, &ccname); - if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) { + if (ret) { + ret = xasprintf(&ccname, cctemplate, geteuid()); + old_umask = umask(0177); + tmpfd = mkstemp(ccname + strlen("FILE:")); oerrno = errno; - logit("fchmod(): %.100s", strerror(oerrno)); + umask(old_umask); + if (tmpfd == -1) { + logit("mkstemp(): %.100s", strerror(oerrno)); + return oerrno; + } + + if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) { + oerrno = errno; + logit("fchmod(): %.100s", strerror(oerrno)); + close(tmpfd); + return oerrno; + } close(tmpfd); - return oerrno; } - close(tmpfd); + debug("%s: Setting ccname to %s", __func__, ccname); return (krb5_cc_resolve(ctx, ccname, ccache)); } diff --git a/configure.ac b/configure.ac index 5f5905b..7df6fc3 100644 --- a/configure.ac +++ b/configure.ac @@ -4025,7 +4025,7 @@ AC_ARG_WITH([kerberos5], ]]) saved_LIBS="$LIBS" LIBS="$LIBS $K5LIBS" - AC_CHECK_FUNCS([krb5_cc_new_unique krb5_get_error_message krb5_free_error_message]) + AC_CHECK_FUNCS([krb5_cc_new_unique krb5_get_error_message krb5_free_error_message krb5_cc_get_type]) LIBS="$saved_LIBS" fi diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c index 795992d..27e6642 100644 --- a/gss-serv-krb5.c +++ b/gss-serv-krb5.c @@ -121,8 +121,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) krb5_error_code problem; krb5_principal princ; OM_uint32 maj_status, min_status; - int len; - const char *errmsg; + const char *ccache_name, *ccache_type, *errmsg; if (client->creds == NULL) { debug("No credentials stored"); @@ -181,11 +180,23 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) return; } - client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); + ccache_name = krb5_cc_get_name(krb_context, ccache); + ccache_type = krb5_cc_get_type(krb_context, ccache); + if (ccache_name == NULL || ccache_type == NULL) { + logit("can't get krb5 cache name or type"); + krb5_cc_destroy(krb_context, ccache); + return; + } + + if (ccache_name[0] == ':') + /* for DIR::pathname form ccache_name begins with : */ + client->store.filename = xstrdup(ccache_name + 1); + else + client->store.filename = xstrdup(ccache_name); + + client->store.envvar = "KRB5CCNAME"; - len = strlen(client->store.filename) + 6; - client->store.envval = xmalloc(len); - snprintf(client->store.envval, len, "FILE:%s", client->store.filename); + xasprintf(&client->store.envval, "%s:%s", ccache_type, ccache_name); #ifdef USE_PAM if (options.use_pam) diff --git a/gss-serv.c b/gss-serv.c index 5c59924..7237db7 100644 --- a/gss-serv.c +++ b/gss-serv.c @@ -311,12 +311,19 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) void ssh_gssapi_cleanup_creds(void) { - if (gssapi_client.store.filename != NULL) { - /* Unlink probably isn't sufficient */ - debug("removing gssapi cred file\"%s\"", - gssapi_client.store.filename); - unlink(gssapi_client.store.filename); - } + krb5_ccache ccache; + krb5_context ctx; + + if (gssapi_client.creds == NULL) + return; + + if (krb5_init_context(&ctx)) + return; + + krb5_cc_resolve(ctx, gssapi_client.store.envval, &ccache); + krb5_cc_destroy(ctx, ccache); + + krb5_free_context(ctx); } /* As user */ -- 2.2.0
_______________________________________________ openssh-unix-dev mailing list openssh-unix-dev@xxxxxxxxxxx https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev