2018-06-19 11:35:38 +00:00
|
|
|
diff --git a/auth-krb5.c b/auth-krb5.c
|
|
|
|
index a5a81ed2..63f877f2 100644
|
|
|
|
--- a/auth-krb5.c
|
|
|
|
+++ b/auth-krb5.c
|
|
|
|
@@ -51,6 +51,7 @@
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <krb5.h>
|
|
|
|
+#include <profile.h>
|
|
|
|
|
|
|
|
extern ServerOptions options;
|
|
|
|
|
|
|
|
@@ -77,7 +78,7 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
|
|
|
|
#endif
|
|
|
|
krb5_error_code problem;
|
|
|
|
krb5_ccache ccache = NULL;
|
|
|
|
- int len;
|
|
|
|
+ char *ticket_name = NULL;
|
|
|
|
char *client, *platform_client;
|
|
|
|
const char *errmsg;
|
|
|
|
|
|
|
|
@@ -163,7 +164,8 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
- problem = ssh_krb5_cc_gen(authctxt->krb5_ctx, &authctxt->krb5_fwd_ccache);
|
|
|
|
+ problem = ssh_krb5_cc_new_unique(authctxt->krb5_ctx,
|
|
|
|
+ &authctxt->krb5_fwd_ccache, &authctxt->krb5_set_env);
|
|
|
|
if (problem)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
@@ -172,21 +174,20 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
|
|
|
|
if (problem)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
- problem= krb5_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache,
|
|
|
|
+ problem = krb5_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache,
|
|
|
|
&creds);
|
|
|
|
if (problem)
|
|
|
|
goto out;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
- authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
|
|
|
|
+ problem = krb5_cc_get_full_name(authctxt->krb5_ctx,
|
|
|
|
+ authctxt->krb5_fwd_ccache, &ticket_name);
|
|
|
|
|
|
|
|
- len = strlen(authctxt->krb5_ticket_file) + 6;
|
|
|
|
- authctxt->krb5_ccname = xmalloc(len);
|
|
|
|
- snprintf(authctxt->krb5_ccname, len, "FILE:%s",
|
|
|
|
- authctxt->krb5_ticket_file);
|
|
|
|
+ authctxt->krb5_ccname = xstrdup(ticket_name);
|
|
|
|
+ krb5_free_string(authctxt->krb5_ctx, ticket_name);
|
|
|
|
|
|
|
|
#ifdef USE_PAM
|
|
|
|
- if (options.use_pam)
|
|
|
|
+ if (options.use_pam && authctxt->krb5_set_env)
|
|
|
|
do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname);
|
|
|
|
#endif
|
|
|
|
|
2018-06-28 07:24:57 +00:00
|
|
|
@@ -222,11 +223,54 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
|
2018-06-19 11:35:38 +00:00
|
|
|
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);
|
|
|
|
+ krb5_context ctx = authctxt->krb5_ctx;
|
|
|
|
+ krb5_cccol_cursor cursor;
|
|
|
|
+ krb5_ccache ccache;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ krb5_cc_destroy(ctx, authctxt->krb5_fwd_ccache);
|
|
|
|
authctxt->krb5_fwd_ccache = NULL;
|
|
|
|
+
|
|
|
|
+ ret = krb5_cccol_cursor_new(ctx, &cursor);
|
|
|
|
+ if (ret)
|
2018-06-28 07:24:57 +00:00
|
|
|
+ goto out;
|
2018-06-19 11:35:38 +00:00
|
|
|
+
|
|
|
|
+ ret = krb5_cccol_cursor_next(ctx, cursor, &ccache);
|
|
|
|
+ if (ret == 0 && ccache != NULL) {
|
|
|
|
+ /* There is at least one other ccache in collection
|
|
|
|
+ * we can switch to */
|
|
|
|
+ krb5_cc_switch(ctx, ccache);
|
|
|
|
+ } else {
|
|
|
|
+ /* Clean up the collection too */
|
|
|
|
+ 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));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ krb5_cccol_cursor_free(ctx, &cursor);
|
|
|
|
}
|
2018-06-28 07:24:57 +00:00
|
|
|
+out:
|
2018-06-19 11:35:38 +00:00
|
|
|
if (authctxt->krb5_user) {
|
|
|
|
krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user);
|
2018-06-28 07:24:57 +00:00
|
|
|
authctxt->krb5_user = NULL;
|
2018-09-25 14:34:19 +00:00
|
|
|
@@ -237,36 +287,188 @@ krb5_cleanup_proc(Authctxt *authctxt)
|
2018-06-19 11:35:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
-#ifndef HEIMDAL
|
|
|
|
-krb5_error_code
|
|
|
|
-ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
|
|
|
|
- int tmpfd, ret, oerrno;
|
|
|
|
- char ccname[40];
|
|
|
|
- mode_t old_umask;
|
|
|
|
|
|
|
|
- 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;
|
|
|
|
+#if !defined(HEIMDAL)
|
|
|
|
+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;
|
|
|
|
+
|
|
|
|
+ debug3("%s: called, template = %s", __func__, 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;
|
2018-09-25 14:34:19 +00:00
|
|
|
+ *p_o = '\0';
|
2018-06-19 11:35:38 +00:00
|
|
|
+ debug("%s: unsupported token %s in %s", __func__, p_n, template);
|
|
|
|
+ /* unknown token, fallback to the default */
|
|
|
|
+ goto cleanup;
|
|
|
|
+ }
|
|
|
|
}
|
|
|
|
|
|
|
|
- if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) {
|
|
|
|
+ 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;
|
|
|
|
+
|
|
|
|
+ debug3("%s: called", __func__);
|
|
|
|
+ ret = krb5_get_profile(ctx, &p);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ ret = profile_get_string(p, "libdefaults", "default_ccache_name", NULL, NULL, &value);
|
|
|
|
+ if (ret || !value)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ ret = ssh_krb5_expand_template(ccname, value);
|
|
|
|
+
|
|
|
|
+ debug3("%s: returning with ccname = %s", __func__, *ccname);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+krb5_error_code
|
|
|
|
+ssh_krb5_cc_new_unique(krb5_context ctx, krb5_ccache *ccache, int *need_environment) {
|
|
|
|
+ int tmpfd, ret, oerrno, type_len;
|
|
|
|
+ char *ccname = NULL;
|
|
|
|
+ mode_t old_umask;
|
|
|
|
+ char *type = NULL, *colon = NULL;
|
|
|
|
+
|
|
|
|
+ debug3("%s: called", __func__);
|
|
|
|
+ if (need_environment)
|
|
|
|
+ *need_environment = 0;
|
|
|
|
+ ret = ssh_krb5_get_cctemplate(ctx, &ccname);
|
|
|
|
+ if (ret || !ccname || options.kerberos_unique_ticket) {
|
|
|
|
+ /* Otherwise, go with the old method */
|
|
|
|
+ if (ccname)
|
|
|
|
+ free(ccname);
|
|
|
|
+ ccname = NULL;
|
|
|
|
+
|
|
|
|
+ ret = asprintf(&ccname,
|
|
|
|
+ "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid());
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ 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;
|
|
|
|
+ }
|
|
|
|
+ /* make sure the KRB5CCNAME is set for non-standard location */
|
|
|
|
+ if (need_environment)
|
|
|
|
+ *need_environment = 1;
|
|
|
|
close(tmpfd);
|
|
|
|
- return oerrno;
|
|
|
|
}
|
|
|
|
- close(tmpfd);
|
|
|
|
|
|
|
|
- return (krb5_cc_resolve(ctx, ccname, ccache));
|
|
|
|
+ debug3("%s: setting default ccname to %s", __func__, ccname);
|
|
|
|
+ /* set the default with already expanded user IDs */
|
|
|
|
+ ret = krb5_cc_set_default_name(ctx, ccname);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ if ((colon = strstr(ccname, ":")) != NULL) {
|
|
|
|
+ type_len = colon - ccname;
|
|
|
|
+ type = malloc((type_len + 1) * sizeof(char));
|
|
|
|
+ if (type == NULL)
|
|
|
|
+ return ENOMEM;
|
|
|
|
+ strncpy(type, ccname, type_len);
|
|
|
|
+ type[type_len] = 0;
|
|
|
|
+ } else {
|
|
|
|
+ type = strdup(ccname);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* If we have a credential cache from krb5.conf, we need to switch
|
|
|
|
+ * a primary cache for this collection, if it supports that (non-FILE)
|
|
|
|
+ */
|
|
|
|
+ if (krb5_cc_support_switch(ctx, type)) {
|
|
|
|
+ debug3("%s: calling cc_new_unique(%s)", __func__, ccname);
|
|
|
|
+ ret = krb5_cc_new_unique(ctx, type, NULL, ccache);
|
2018-09-25 14:34:19 +00:00
|
|
|
+ free(type);
|
2018-06-19 11:35:38 +00:00
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ debug3("%s: calling cc_switch()", __func__);
|
|
|
|
+ return krb5_cc_switch(ctx, *ccache);
|
|
|
|
+ } else {
|
|
|
|
+ /* Otherwise, we can not create a unique ccname here (either
|
|
|
|
+ * it is already unique from above or the type does not support
|
|
|
|
+ * collections
|
|
|
|
+ */
|
2018-09-25 14:34:19 +00:00
|
|
|
+ free(type);
|
2018-06-19 11:35:38 +00:00
|
|
|
+ debug3("%s: calling cc_resolve(%s)", __func__, ccname);
|
|
|
|
+ return (krb5_cc_resolve(ctx, ccname, ccache));
|
|
|
|
+ }
|
|
|
|
}
|
|
|
|
#endif /* !HEIMDAL */
|
|
|
|
#endif /* KRB5 */
|
|
|
|
diff --git a/auth.h b/auth.h
|
|
|
|
index 29491df9..fdab5040 100644
|
|
|
|
--- a/auth.h
|
|
|
|
+++ b/auth.h
|
|
|
|
@@ -82,6 +82,7 @@ struct Authctxt {
|
|
|
|
krb5_principal krb5_user;
|
|
|
|
char *krb5_ticket_file;
|
|
|
|
char *krb5_ccname;
|
|
|
|
+ int krb5_set_env;
|
|
|
|
#endif
|
|
|
|
struct sshbuf *loginmsg;
|
|
|
|
|
|
|
|
@@ -243,6 +244,6 @@ int sys_auth_passwd(struct ssh *, const char *);
|
|
|
|
|
|
|
|
#if defined(KRB5) && !defined(HEIMDAL)
|
|
|
|
#include <krb5.h>
|
|
|
|
-krb5_error_code ssh_krb5_cc_gen(krb5_context, krb5_ccache *);
|
|
|
|
+krb5_error_code ssh_krb5_cc_new_unique(krb5_context, krb5_ccache *, int *);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
|
|
|
|
index 795992d9..0623a107 100644
|
|
|
|
--- a/gss-serv-krb5.c
|
|
|
|
+++ b/gss-serv-krb5.c
|
|
|
|
@@ -114,7 +114,7 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
|
|
|
|
/* This writes out any forwarded credentials from the structure populated
|
|
|
|
* during userauth. Called after we have setuid to the user */
|
|
|
|
|
|
|
|
-static void
|
|
|
|
+static int
|
|
|
|
ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
|
|
|
|
{
|
|
|
|
krb5_ccache ccache;
|
|
|
|
@@ -121,16 +121,17 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
|
|
|
|
krb5_error_code problem;
|
|
|
|
krb5_principal princ;
|
|
|
|
OM_uint32 maj_status, min_status;
|
|
|
|
- const char *new_ccname, *new_cctype;
|
|
|
|
+ int len;
|
|
|
|
const char *errmsg;
|
|
|
|
+ int set_env = 0;
|
|
|
|
|
|
|
|
if (client->creds == NULL) {
|
|
|
|
debug("No credentials stored");
|
|
|
|
- return;
|
|
|
|
+ return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ssh_gssapi_krb5_init() == 0)
|
|
|
|
- return;
|
|
|
|
+ return 0;
|
|
|
|
|
|
|
|
#ifdef HEIMDAL
|
|
|
|
# ifdef HAVE_KRB5_CC_NEW_UNIQUE
|
|
|
|
@@ -144,14 +145,14 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
|
|
|
|
krb5_get_err_text(krb_context, problem));
|
|
|
|
# endif
|
|
|
|
krb5_free_error_message(krb_context, errmsg);
|
|
|
|
- return;
|
|
|
|
+ return 0;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
- if ((problem = ssh_krb5_cc_gen(krb_context, &ccache))) {
|
|
|
|
+ if ((problem = ssh_krb5_cc_new_unique(krb_context, &ccache, &set_env)) != 0) {
|
|
|
|
errmsg = krb5_get_error_message(krb_context, problem);
|
|
|
|
- logit("ssh_krb5_cc_gen(): %.100s", errmsg);
|
|
|
|
+ logit("ssh_krb5_cc_new_unique(): %.100s", errmsg);
|
|
|
|
krb5_free_error_message(krb_context, errmsg);
|
|
|
|
- return;
|
|
|
|
+ return 0;
|
|
|
|
}
|
|
|
|
#endif /* #ifdef HEIMDAL */
|
|
|
|
|
|
|
|
@@ -160,7 +161,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
|
|
|
|
errmsg = krb5_get_error_message(krb_context, problem);
|
|
|
|
logit("krb5_parse_name(): %.100s", errmsg);
|
|
|
|
krb5_free_error_message(krb_context, errmsg);
|
|
|
|
- return;
|
|
|
|
+ return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((problem = krb5_cc_initialize(krb_context, ccache, princ))) {
|
|
|
|
@@ -169,7 +170,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
|
|
|
|
krb5_free_error_message(krb_context, errmsg);
|
|
|
|
krb5_free_principal(krb_context, princ);
|
|
|
|
krb5_cc_destroy(krb_context, ccache);
|
|
|
|
- return;
|
|
|
|
+ return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
krb5_free_principal(krb_context, princ);
|
|
|
|
@@ -178,37 +179,27 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
|
|
|
|
client->creds, ccache))) {
|
|
|
|
logit("gss_krb5_copy_ccache() failed");
|
|
|
|
krb5_cc_destroy(krb_context, ccache);
|
|
|
|
- return;
|
|
|
|
+ return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
- new_cctype = krb5_cc_get_type(krb_context, ccache);
|
|
|
|
- new_ccname = krb5_cc_get_name(krb_context, ccache);
|
|
|
|
-
|
|
|
|
- client->store.envvar = "KRB5CCNAME";
|
|
|
|
-#ifdef USE_CCAPI
|
|
|
|
- xasprintf(&client->store.envval, "API:%s", new_ccname);
|
|
|
|
-#else
|
|
|
|
- if (new_ccname[0] == ':')
|
|
|
|
- new_ccname++;
|
|
|
|
- xasprintf(&client->store.envval, "%s:%s", new_cctype, new_ccname);
|
|
|
|
- if (strcmp(new_cctype, "DIR") == 0) {
|
|
|
|
- char *p;
|
|
|
|
- p = strrchr(client->store.envval, '/');
|
|
|
|
- if (p)
|
|
|
|
- *p = '\0';
|
|
|
|
- }
|
|
|
|
-#endif
|
|
|
|
+ if (set_env) {
|
|
|
|
+ const char *filename = krb5_cc_get_name(krb_context, ccache);
|
|
|
|
+ client->store.envvar = "KRB5CCNAME";
|
|
|
|
+ len = strlen(filename) + 6;
|
|
|
|
+ client->store.envval = xmalloc(len);
|
|
|
|
+ snprintf(client->store.envval, len, "FILE:%s", filename);
|
|
|
|
+ }
|
|
|
|
|
|
|
|
#ifdef USE_PAM
|
|
|
|
- if (options.use_pam)
|
|
|
|
+ if (options.use_pam && set_env)
|
|
|
|
do_pam_putenv(client->store.envvar, client->store.envval);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
krb5_cc_close(krb_context, ccache);
|
|
|
|
|
|
|
|
client->store.data = krb_context;
|
|
|
|
|
|
|
|
- return;
|
|
|
|
+ return set_env;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
diff --git a/gss-serv.c b/gss-serv.c
|
|
|
|
index 6cae720e..16e55cbc 100644
|
|
|
|
--- a/gss-serv.c
|
|
|
|
+++ b/gss-serv.c
|
|
|
|
@@ -320,13 +320,15 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
|
|
|
|
}
|
|
|
|
|
|
|
|
/* As user */
|
|
|
|
-void
|
|
|
|
+int
|
|
|
|
ssh_gssapi_storecreds(void)
|
|
|
|
{
|
|
|
|
if (gssapi_client.mech && gssapi_client.mech->storecreds) {
|
|
|
|
- (*gssapi_client.mech->storecreds)(&gssapi_client);
|
|
|
|
+ return (*gssapi_client.mech->storecreds)(&gssapi_client);
|
|
|
|
} else
|
|
|
|
debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This allows GSSAPI methods to do things to the childs environment based
|
|
|
|
diff --git a/servconf.c b/servconf.c
|
|
|
|
index cb578658..a6e01df2 100644
|
|
|
|
--- a/servconf.c
|
|
|
|
+++ b/servconf.c
|
|
|
|
@@ -122,6 +122,7 @@ initialize_server_options(ServerOptions *options)
|
|
|
|
options->kerberos_or_local_passwd = -1;
|
|
|
|
options->kerberos_ticket_cleanup = -1;
|
|
|
|
options->kerberos_get_afs_token = -1;
|
|
|
|
+ options->kerberos_unique_ticket = -1;
|
|
|
|
options->gss_authentication=-1;
|
|
|
|
options->gss_keyex = -1;
|
|
|
|
options->gss_cleanup_creds = -1;
|
|
|
|
@@ -315,6 +316,8 @@ fill_default_server_options(ServerOptions *options)
|
|
|
|
options->kerberos_ticket_cleanup = 1;
|
|
|
|
if (options->kerberos_get_afs_token == -1)
|
|
|
|
options->kerberos_get_afs_token = 0;
|
|
|
|
+ if (options->kerberos_unique_ticket == -1)
|
|
|
|
+ options->kerberos_unique_ticket = 0;
|
|
|
|
if (options->gss_authentication == -1)
|
|
|
|
options->gss_authentication = 0;
|
|
|
|
if (options->gss_keyex == -1)
|
|
|
|
@@ -447,7 +450,8 @@ typedef enum {
|
|
|
|
sPermitRootLogin, sLogFacility, sLogLevel,
|
|
|
|
sRhostsRSAAuthentication, sRSAAuthentication,
|
|
|
|
sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
|
|
|
|
- sKerberosGetAFSToken, sChallengeResponseAuthentication,
|
|
|
|
+ sKerberosGetAFSToken, sKerberosUniqueTicket,
|
|
|
|
+ sChallengeResponseAuthentication,
|
|
|
|
sPasswordAuthentication, sKbdInteractiveAuthentication,
|
|
|
|
sListenAddress, sAddressFamily,
|
|
|
|
sPrintMotd, sPrintLastLog, sIgnoreRhosts,
|
|
|
|
@@ -526,11 +530,13 @@ static struct {
|
|
|
|
#else
|
|
|
|
{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
|
|
|
|
#endif
|
|
|
|
+ { "kerberosuniqueticket", sKerberosUniqueTicket, SSHCFG_GLOBAL },
|
|
|
|
#else
|
|
|
|
{ "kerberosauthentication", sUnsupported, SSHCFG_ALL },
|
|
|
|
{ "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
|
|
|
|
{ "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
|
|
|
|
{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
|
|
|
|
+ { "kerberosuniqueticket", sUnsupported, SSHCFG_GLOBAL },
|
|
|
|
#endif
|
|
|
|
{ "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
|
|
|
|
{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
|
|
|
|
@@ -1437,6 +1443,10 @@ process_server_config_line(ServerOptions *options, char *line,
|
|
|
|
intptr = &options->kerberos_get_afs_token;
|
|
|
|
goto parse_flag;
|
|
|
|
|
|
|
|
+ case sKerberosUniqueTicket:
|
|
|
|
+ intptr = &options->kerberos_unique_ticket;
|
|
|
|
+ goto parse_flag;
|
|
|
|
+
|
|
|
|
case sGssAuthentication:
|
|
|
|
intptr = &options->gss_authentication;
|
|
|
|
goto parse_flag;
|
|
|
|
@@ -2507,6 +2517,7 @@ dump_config(ServerOptions *o)
|
|
|
|
# ifdef USE_AFS
|
|
|
|
dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
|
|
|
|
# endif
|
|
|
|
+ dump_cfg_fmtint(sKerberosUniqueTicket, o->kerberos_unique_ticket);
|
|
|
|
#endif
|
|
|
|
#ifdef GSSAPI
|
|
|
|
dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
|
|
|
|
diff --git a/servconf.h b/servconf.h
|
|
|
|
index db8362c6..4fa42d64 100644
|
|
|
|
--- a/servconf.h
|
|
|
|
+++ b/servconf.h
|
|
|
|
@@ -123,6 +123,8 @@ typedef struct {
|
|
|
|
* file on logout. */
|
|
|
|
int kerberos_get_afs_token; /* If true, try to get AFS token if
|
|
|
|
* authenticated with Kerberos. */
|
|
|
|
+ int kerberos_unique_ticket; /* If true, the aquired ticket will
|
|
|
|
+ * be stored in per-session ccache */
|
|
|
|
int gss_authentication; /* If true, permit GSSAPI authentication */
|
|
|
|
int gss_keyex; /* If true, permit GSSAPI key exchange */
|
|
|
|
int gss_cleanup_creds; /* If true, destroy cred cache on logout */
|
|
|
|
diff --git a/session.c b/session.c
|
|
|
|
index 85df6a27..480a5ead 100644
|
|
|
|
--- a/session.c
|
|
|
|
+++ b/session.c
|
|
|
|
@@ -1033,7 +1033,8 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell)
|
|
|
|
/* Allow any GSSAPI methods that we've used to alter
|
|
|
|
* the childs environment as they see fit
|
|
|
|
*/
|
|
|
|
- ssh_gssapi_do_child(&env, &envsize);
|
|
|
|
+ if (s->authctxt->krb5_set_env)
|
|
|
|
+ ssh_gssapi_do_child(&env, &envsize);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Set basic environment. */
|
|
|
|
@@ -1105,7 +1106,7 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell)
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef KRB5
|
|
|
|
- if (s->authctxt->krb5_ccname)
|
|
|
|
+ if (s->authctxt->krb5_ccname && s->authctxt->krb5_set_env)
|
|
|
|
child_set_env(&env, &envsize, "KRB5CCNAME",
|
|
|
|
s->authctxt->krb5_ccname);
|
|
|
|
#endif
|
|
|
|
diff --git a/ssh-gss.h b/ssh-gss.h
|
|
|
|
index 6593e422..245178af 100644
|
|
|
|
--- a/ssh-gss.h
|
|
|
|
+++ b/ssh-gss.h
|
|
|
|
@@ -62,7 +62,6 @@
|
|
|
|
#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-"
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
- char *filename;
|
|
|
|
char *envvar;
|
|
|
|
char *envval;
|
|
|
|
struct passwd *owner;
|
|
|
|
@@ -83,7 +82,7 @@ typedef struct ssh_gssapi_mech_struct {
|
|
|
|
int (*dochild) (ssh_gssapi_client *);
|
|
|
|
int (*userok) (ssh_gssapi_client *, char *);
|
|
|
|
int (*localname) (ssh_gssapi_client *, char **);
|
|
|
|
- void (*storecreds) (ssh_gssapi_client *);
|
|
|
|
+ int (*storecreds) (ssh_gssapi_client *);
|
|
|
|
int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *);
|
|
|
|
} ssh_gssapi_mech;
|
|
|
|
|
|
|
|
@@ -127,7 +126,7 @@ int ssh_gssapi_userok(char *name);
|
|
|
|
OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
|
|
|
|
void ssh_gssapi_do_child(char ***, u_int *);
|
|
|
|
void ssh_gssapi_cleanup_creds(void);
|
|
|
|
-void ssh_gssapi_storecreds(void);
|
|
|
|
+int ssh_gssapi_storecreds(void);
|
|
|
|
const char *ssh_gssapi_displayname(void);
|
|
|
|
|
|
|
|
char *ssh_gssapi_server_mechanisms(void);
|
|
|
|
diff --git a/sshd.c b/sshd.c
|
|
|
|
index edbe815c..89514e8a 100644
|
|
|
|
--- a/sshd.c
|
|
|
|
+++ b/sshd.c
|
|
|
|
@@ -2162,7 +2162,7 @@ main(int ac, char **av)
|
|
|
|
#ifdef GSSAPI
|
|
|
|
if (options.gss_authentication) {
|
|
|
|
temporarily_use_uid(authctxt->pw);
|
|
|
|
- ssh_gssapi_storecreds();
|
|
|
|
+ authctxt->krb5_set_env = ssh_gssapi_storecreds();
|
|
|
|
restore_uid();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
diff --git a/sshd_config.5 b/sshd_config.5
|
|
|
|
index c0683d4a..2349f477 100644
|
|
|
|
--- a/sshd_config.5
|
|
|
|
+++ b/sshd_config.5
|
|
|
|
@@ -860,6 +860,12 @@ Specifies whether to automatically destroy the user's ticket cache
|
|
|
|
file on logout.
|
|
|
|
The default is
|
|
|
|
.Cm yes .
|
|
|
|
+.It Cm KerberosUniqueTicket
|
|
|
|
+Specifies whether to store the aquired tickets in the per-session credential
|
|
|
|
+cache or whether to use per-user credential cache, which might overwrite
|
|
|
|
+tickets aquired in different sessions of the same user.
|
|
|
|
+The default is
|
|
|
|
+.Cm no .
|
|
|
|
.It Cm KexAlgorithms
|
|
|
|
Specifies the available KEX (Key Exchange) algorithms.
|
|
|
|
Multiple algorithms must be comma-separated.
|