diff -up openssh-6.3p1/auth-krb5.c.ccache_name openssh-6.3p1/auth-krb5.c --- openssh-6.3p1/auth-krb5.c.ccache_name 2013-10-23 22:03:52.322950759 +0200 +++ openssh-6.3p1/auth-krb5.c 2013-10-23 22:04:24.295799873 +0200 @@ -50,7 +50,9 @@ #include #include #include +#include #include +#include extern ServerOptions options; @@ -91,6 +93,7 @@ auth_krb5_password(Authctxt *authctxt, c #endif krb5_error_code problem; krb5_ccache ccache = NULL; + const char *ccache_type; int len; char *client, *platform_client; const char *errmsg; @@ -191,12 +194,30 @@ auth_krb5_password(Authctxt *authctxt, c goto out; #endif + ccache_type = krb5_cc_get_type(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); - len = strlen(authctxt->krb5_ticket_file) + 6; + if (authctxt->krb5_ticket_file[0] == ':') + authctxt->krb5_ticket_file++; + + len = strlen(authctxt->krb5_ticket_file) + strlen(ccache_type) + 2; authctxt->krb5_ccname = xmalloc(len); - snprintf(authctxt->krb5_ccname, len, "FILE:%s", + +#ifdef USE_CCAPI + snprintf(authctxt->krb5_ccname, len, "API:%s", authctxt->krb5_ticket_file); +#else + snprintf(authctxt->krb5_ccname, len, "%s:%s", + ccache_type, authctxt->krb5_ticket_file); +#endif + + if (strcmp(ccache_type, "DIR") == 0) { + char *p; + p = strrchr(authctxt->krb5_ccname, '/'); + if (p) + *p = '\0'; + } + #ifdef USE_PAM if (options.use_pam) @@ -235,10 +256,34 @@ auth_krb5_password(Authctxt *authctxt, c void krb5_cleanup_proc(Authctxt *authctxt) { + struct stat krb5_ccname_stat; + char krb5_ccname[128], *krb5_ccname_dir_start, *krb5_ccname_dir_end; + debug("krb5_cleanup_proc called"); if (authctxt->krb5_fwd_ccache) { krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); authctxt->krb5_fwd_ccache = NULL; + + strncpy(krb5_ccname, authctxt->krb5_ccname, sizeof(krb5_ccname) - 10); + krb5_ccname_dir_start = strchr(krb5_ccname, ':') + 1; + *krb5_ccname_dir_start++ = '\0'; + if (strcmp(krb5_ccname, "DIR") == 0) { + + strcat(krb5_ccname_dir_start, "/primary"); + + if (stat(krb5_ccname_dir_start, &krb5_ccname_stat) == 0) { + if (unlink(krb5_ccname_dir_start) == 0) { + krb5_ccname_dir_end = strrchr(krb5_ccname_dir_start, '/'); + *krb5_ccname_dir_end = '\0'; + if (rmdir(krb5_ccname_dir_start) == -1) + debug("cache dir '%s' remove failed: %s", krb5_ccname_dir_start, strerror(errno)); + } + else + debug("cache primary file '%s', remove failed: %s", + krb5_ccname_dir_start, strerror(errno) + ); + } + } } if (authctxt->krb5_user) { krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user); @@ -250,34 +295,139 @@ krb5_cleanup_proc(Authctxt *authctxt) } } +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 = asprintf(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 = asprintf(&ccname, cctemplate, geteuid()); + if (ret == -1) + return ENOMEM; + 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)); }