Dmitry Belyavskiy f32b84
diff -up openssh-8.6p1/auth.h.ccache_name openssh-8.6p1/auth.h
Dmitry Belyavskiy f32b84
--- openssh-8.6p1/auth.h.ccache_name	2021-04-19 14:05:10.820744325 +0200
Dmitry Belyavskiy f32b84
+++ openssh-8.6p1/auth.h	2021-04-19 14:05:10.853744569 +0200
Dmitry Belyavskiy f32b84
@@ -83,6 +83,7 @@ struct Authctxt {
Dmitry Belyavskiy f32b84
 	krb5_principal	 krb5_user;
Dmitry Belyavskiy f32b84
 	char		*krb5_ticket_file;
Dmitry Belyavskiy f32b84
 	char		*krb5_ccname;
Dmitry Belyavskiy f32b84
+	int		 krb5_set_env;
Dmitry Belyavskiy f32b84
 #endif
Dmitry Belyavskiy f32b84
 	struct sshbuf	*loginmsg;
Dmitry Belyavskiy f32b84
 
Dmitry Belyavskiy f32b84
@@ -231,7 +232,7 @@ struct passwd *fakepw(void);
Dmitry Belyavskiy f32b84
 int	 sys_auth_passwd(struct ssh *, const char *);
Dmitry Belyavskiy f32b84
 
Dmitry Belyavskiy f32b84
 #if defined(KRB5) && !defined(HEIMDAL)
Dmitry Belyavskiy f32b84
-krb5_error_code ssh_krb5_cc_gen(krb5_context, krb5_ccache *);
Dmitry Belyavskiy f32b84
+krb5_error_code ssh_krb5_cc_new_unique(krb5_context, krb5_ccache *, int *);
Dmitry Belyavskiy f32b84
 #endif
Dmitry Belyavskiy f32b84
 
Dmitry Belyavskiy f32b84
 #endif /* AUTH_H */
Dmitry Belyavskiy f32b84
diff -up openssh-8.6p1/auth-krb5.c.ccache_name openssh-8.6p1/auth-krb5.c
Dmitry Belyavskiy f32b84
--- openssh-8.6p1/auth-krb5.c.ccache_name	2021-04-16 05:55:25.000000000 +0200
Dmitry Belyavskiy f32b84
+++ openssh-8.6p1/auth-krb5.c	2021-04-19 14:40:55.142832954 +0200
Jakub Jelen 117678
@@ -51,6 +51,7 @@
Jakub Jelen 117678
 #include <unistd.h>
Jakub Jelen 117678
 #include <string.h>
Jakub Jelen 117678
 #include <krb5.h>
Jakub Jelen 117678
+#include <profile.h>
Jakub Jelen 117678
 
Jakub Jelen 117678
 extern ServerOptions	 options;
Jakub Jelen 117678
 
Dmitry Belyavskiy f32b84
@@ -77,7 +78,7 @@ auth_krb5_password(Authctxt *authctxt, c
Jakub Jelen 117678
 #endif
Jakub Jelen 117678
 	krb5_error_code problem;
Jakub Jelen 117678
 	krb5_ccache ccache = NULL;
Jakub Jelen 117678
-	int len;
Jakub Jelen 117678
+	char *ticket_name = NULL;
Jakub Jelen 117678
 	char *client, *platform_client;
Jakub Jelen 117678
 	const char *errmsg;
Jakub Jelen 117678
 
Dmitry Belyavskiy f32b84
@@ -163,8 +164,8 @@ auth_krb5_password(Authctxt *authctxt, c
Jakub Jelen 117678
 		goto out;
Jakub Jelen 117678
 	}
Jakub Jelen 117678
 
Dmitry Belyavskiy f32b84
-	problem = ssh_krb5_cc_gen(authctxt->krb5_ctx,
Dmitry Belyavskiy f32b84
-	    &authctxt->krb5_fwd_ccache);
Jakub Jelen 117678
+	problem = ssh_krb5_cc_new_unique(authctxt->krb5_ctx,
Jakub Jelen 117678
+	     &authctxt->krb5_fwd_ccache, &authctxt->krb5_set_env);
Jakub Jelen 117678
 	if (problem)
Jakub Jelen 117678
 		goto out;
Jakub Jelen 117678
 
Dmitry Belyavskiy f32b84
@@ -179,15 +180,14 @@ auth_krb5_password(Authctxt *authctxt, c
Jakub Jelen 117678
 		goto out;
Jakub Jelen 117678
 #endif
Jakub Jelen 117678
 
Jakub Jelen 117678
-	authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
Jakub Jelen 117678
+	problem = krb5_cc_get_full_name(authctxt->krb5_ctx,
Jakub Jelen 117678
+	    authctxt->krb5_fwd_ccache, &ticket_name);
Jakub Jelen 117678
 
Jakub Jelen 117678
-	len = strlen(authctxt->krb5_ticket_file) + 6;
Jakub Jelen 117678
-	authctxt->krb5_ccname = xmalloc(len);
Jakub Jelen 117678
-	snprintf(authctxt->krb5_ccname, len, "FILE:%s",
Jakub Jelen 117678
-	    authctxt->krb5_ticket_file);
Jakub Jelen 117678
+	authctxt->krb5_ccname = xstrdup(ticket_name);
Jakub Jelen 117678
+	krb5_free_string(authctxt->krb5_ctx, ticket_name);
Jakub Jelen 117678
 
Jakub Jelen 117678
 #ifdef USE_PAM
Jakub Jelen 117678
-	if (options.use_pam)
Jakub Jelen 117678
+	if (options.use_pam && authctxt->krb5_set_env)
Jakub Jelen 117678
 		do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname);
Jakub Jelen 117678
 #endif
Jakub Jelen 117678
 
Dmitry Belyavskiy f32b84
@@ -223,11 +223,54 @@ auth_krb5_password(Authctxt *authctxt, c
Jakub Jelen 117678
 void
Jakub Jelen 117678
 krb5_cleanup_proc(Authctxt *authctxt)
Jakub Jelen 117678
 {
Jakub Jelen 117678
+	struct stat krb5_ccname_stat;
Jakub Jelen 117678
+	char krb5_ccname[128], *krb5_ccname_dir_start, *krb5_ccname_dir_end;
Jakub Jelen 117678
+
Jakub Jelen 117678
 	debug("krb5_cleanup_proc called");
Jakub Jelen 117678
 	if (authctxt->krb5_fwd_ccache) {
Jakub Jelen 117678
-		krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
Jakub Jelen 117678
+		krb5_context ctx = authctxt->krb5_ctx;
Jakub Jelen 117678
+		krb5_cccol_cursor cursor;
Jakub Jelen 117678
+		krb5_ccache ccache;
Jakub Jelen 117678
+		int ret;
Jakub Jelen 117678
+
Jakub Jelen 117678
+		krb5_cc_destroy(ctx, authctxt->krb5_fwd_ccache);
Jakub Jelen 117678
 		authctxt->krb5_fwd_ccache = NULL;
Jakub Jelen 117678
+
Jakub Jelen 117678
+		ret = krb5_cccol_cursor_new(ctx, &cursor);
Jakub Jelen 117678
+		if (ret)
Jakub Jelen 191bbb
+			goto out;
Jakub Jelen 117678
+
Jakub Jelen 117678
+		ret = krb5_cccol_cursor_next(ctx, cursor, &ccache);
Jakub Jelen 117678
+		if (ret == 0 && ccache != NULL) {
Jakub Jelen 117678
+			/* There is at least one other ccache in collection
Jakub Jelen 117678
+			 * we can switch to */
Jakub Jelen 117678
+			krb5_cc_switch(ctx, ccache);
Jakub Jelen 0b6cc1
+		} else if (authctxt->krb5_ccname != NULL) {
Jakub Jelen 117678
+			/* Clean up the collection too */
Jakub Jelen 117678
+			strncpy(krb5_ccname, authctxt->krb5_ccname, sizeof(krb5_ccname) - 10);
Jakub Jelen 117678
+			krb5_ccname_dir_start = strchr(krb5_ccname, ':') + 1;
Jakub Jelen 117678
+			*krb5_ccname_dir_start++ = '\0';
Jakub Jelen 117678
+			if (strcmp(krb5_ccname, "DIR") == 0) {
Jakub Jelen 117678
+
Jakub Jelen 117678
+				strcat(krb5_ccname_dir_start, "/primary");
Jakub Jelen 117678
+
Jakub Jelen 117678
+				if (stat(krb5_ccname_dir_start, &krb5_ccname_stat) == 0) {
Jakub Jelen 117678
+					if (unlink(krb5_ccname_dir_start) == 0) {
Jakub Jelen 117678
+						krb5_ccname_dir_end = strrchr(krb5_ccname_dir_start, '/');
Jakub Jelen 117678
+						*krb5_ccname_dir_end = '\0';
Jakub Jelen 117678
+						if (rmdir(krb5_ccname_dir_start) == -1)
Jakub Jelen 117678
+							debug("cache dir '%s' remove failed: %s",
Jakub Jelen 117678
+							    krb5_ccname_dir_start, strerror(errno));
Jakub Jelen 117678
+					}
Jakub Jelen 117678
+					else
Jakub Jelen 117678
+						debug("cache primary file '%s', remove failed: %s",
Jakub Jelen 117678
+						    krb5_ccname_dir_start, strerror(errno));
Jakub Jelen 117678
+				}
Jakub Jelen 117678
+			}
Jakub Jelen 117678
+		}
Jakub Jelen 117678
+		krb5_cccol_cursor_free(ctx, &cursor);
Jakub Jelen 117678
 	}
Jakub Jelen 191bbb
+out:
Jakub Jelen 117678
 	if (authctxt->krb5_user) {
Jakub Jelen 117678
 		krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user);
Jakub Jelen 191bbb
 		authctxt->krb5_user = NULL;
Dmitry Belyavskiy f32b84
@@ -238,36 +281,188 @@ krb5_cleanup_proc(Authctxt *authctxt)
Jakub Jelen 117678
 	}
Jakub Jelen 117678
 }
Jakub Jelen 117678
 
Jakub Jelen 117678
-#ifndef HEIMDAL
Jakub Jelen 372226
+
Jakub Jelen 117678
+#if !defined(HEIMDAL)
Jakub Jelen 117678
+int
Jakub Jelen 117678
+ssh_asprintf_append(char **dsc, const char *fmt, ...) {
Jakub Jelen 117678
+	char *src, *old;
Jakub Jelen 117678
+	va_list ap;
Jakub Jelen 117678
+	int i;
Jakub Jelen 117678
+
Jakub Jelen 117678
+	va_start(ap, fmt);
Jakub Jelen 117678
+	i = vasprintf(&src, fmt, ap);
Jakub Jelen 117678
+	va_end(ap);
Jakub Jelen 117678
+
Jakub Jelen 117678
+	if (i == -1 || src == NULL)
Jakub Jelen 117678
+		return -1;
Jakub Jelen 117678
+
Jakub Jelen 117678
+	old = *dsc;
Jakub Jelen 117678
+
Jakub Jelen 117678
+	i = asprintf(dsc, "%s%s", *dsc, src);
Jakub Jelen 117678
+	if (i == -1 || src == NULL) {
Jakub Jelen 117678
+		free(src);
Jakub Jelen 117678
+		return -1;
Jakub Jelen 117678
+	}
Jakub Jelen 117678
+
Jakub Jelen 117678
+	free(old);
Jakub Jelen 117678
+	free(src);
Jakub Jelen 117678
+
Jakub Jelen 117678
+	return i;
Jakub Jelen 117678
+}
Jakub Jelen 117678
+
Jakub Jelen 117678
+int
Jakub Jelen 117678
+ssh_krb5_expand_template(char **result, const char *template) {
Jakub Jelen 117678
+	char *p_n, *p_o, *r, *tmp_template;
Jakub Jelen 117678
+
Jakub Jelen 25c16c
+	debug3_f("called, template = %s", template);
Jakub Jelen 117678
+	if (template == NULL)
Jakub Jelen 117678
+		return -1;
Jakub Jelen 117678
+
Jakub Jelen 117678
+	tmp_template = p_n = p_o = xstrdup(template);
Jakub Jelen 117678
+	r = xstrdup("");
Jakub Jelen 117678
+
Jakub Jelen 117678
+	while ((p_n = strstr(p_o, "%{")) != NULL) {
Jakub Jelen 117678
+
Jakub Jelen 117678
+		*p_n++ = '\0';
Jakub Jelen 117678
+		if (ssh_asprintf_append(&r, "%s", p_o) == -1)
Jakub Jelen 117678
+			goto cleanup;
Jakub Jelen 117678
+
Jakub Jelen 117678
+		if (strncmp(p_n, "{uid}", 5) == 0 || strncmp(p_n, "{euid}", 6) == 0 ||
Jakub Jelen 117678
+			strncmp(p_n, "{USERID}", 8) == 0) {
Jakub Jelen 117678
+			p_o = strchr(p_n, '}') + 1;
Jakub Jelen 117678
+			if (ssh_asprintf_append(&r, "%d", geteuid()) == -1)
Jakub Jelen 117678
+				goto cleanup;
Jakub Jelen 117678
+			continue;
Jakub Jelen 117678
+		}
Jakub Jelen 117678
+		else if (strncmp(p_n, "{TEMP}", 6) == 0) {
Jakub Jelen 117678
+			p_o = strchr(p_n, '}') + 1;
Jakub Jelen 117678
+			if (ssh_asprintf_append(&r, "/tmp") == -1)
Jakub Jelen 117678
+				goto cleanup;
Jakub Jelen 117678
+			continue;
Jakub Jelen 117678
+		} else {
Jakub Jelen 117678
+			p_o = strchr(p_n, '}') + 1;
Jakub Jelen f3715e
+			*p_o = '\0';
Jakub Jelen 25c16c
+			debug_f("unsupported token %s in %s", p_n, template);
Jakub Jelen 117678
+			/* unknown token, fallback to the default */
Jakub Jelen 117678
+			goto cleanup;
Jakub Jelen 117678
+		}
Jakub Jelen 372226
+	}
Jakub Jelen 372226
+
Jakub Jelen 117678
+	if (ssh_asprintf_append(&r, "%s", p_o) == -1)
Jakub Jelen 117678
+		goto cleanup;
Jakub Jelen 117678
+
Jakub Jelen 117678
+	*result = r;
Jakub Jelen 117678
+	free(tmp_template);
Jakub Jelen 117678
+	return 0;
Jakub Jelen 117678
+
Jakub Jelen 117678
+cleanup:
Jakub Jelen 117678
+	free(r);
Jakub Jelen 117678
+	free(tmp_template);
Jakub Jelen 117678
+	return -1;
Jakub Jelen 117678
+}
Jakub Jelen 117678
+
Dmitry Belyavskiy f32b84
+krb5_error_code
Jakub Jelen 117678
+ssh_krb5_get_cctemplate(krb5_context ctx, char **ccname) {
Jakub Jelen 117678
+	profile_t p;
Jakub Jelen 117678
+	int ret = 0;
Jakub Jelen 117678
+	char *value = NULL;
Jakub Jelen 117678
+
Jakub Jelen 25c16c
+	debug3_f("called");
Jakub Jelen 117678
+	ret = krb5_get_profile(ctx, &p);
Jakub Jelen 117678
+	if (ret)
Jakub Jelen 117678
+		return ret;
Jakub Jelen 117678
+
Jakub Jelen 117678
+	ret = profile_get_string(p, "libdefaults", "default_ccache_name", NULL, NULL, &value);
Jakub Jelen 117678
+	if (ret || !value)
Jakub Jelen 117678
+		return ret;
Jakub Jelen 117678
+
Jakub Jelen 117678
+	ret = ssh_krb5_expand_template(ccname, value);
Jakub Jelen 117678
+
Jakub Jelen 25c16c
+	debug3_f("returning with ccname = %s", *ccname);
Jakub Jelen 117678
+	return ret;
Jakub Jelen 117678
+}
Jakub Jelen 117678
+
Dmitry Belyavskiy f32b84
 krb5_error_code
Dmitry Belyavskiy f32b84
-ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
Dmitry Belyavskiy f32b84
-	int tmpfd, ret, oerrno;
Dmitry Belyavskiy f32b84
-	char ccname[40];
Jakub Jelen 117678
+ssh_krb5_cc_new_unique(krb5_context ctx, krb5_ccache *ccache, int *need_environment) {
Jakub Jelen 117678
+	int tmpfd, ret, oerrno, type_len;
Jakub Jelen 117678
+	char *ccname = NULL;
Jakub Jelen 372226
 	mode_t old_umask;
Jakub Jelen 117678
+	char *type = NULL, *colon = NULL;
Jakub Jelen 372226
 
Jakub Jelen 372226
-	ret = snprintf(ccname, sizeof(ccname),
Jakub Jelen 372226
-	    "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid());
Jakub Jelen 372226
-	if (ret < 0 || (size_t)ret >= sizeof(ccname))
Jakub Jelen 372226
-		return ENOMEM;
Jakub Jelen 372226
-
Jakub Jelen 372226
-	old_umask = umask(0177);
Jakub Jelen 372226
-	tmpfd = mkstemp(ccname + strlen("FILE:"));
Jakub Jelen 372226
-	oerrno = errno;
Jakub Jelen 372226
-	umask(old_umask);
Jakub Jelen 372226
-	if (tmpfd == -1) {
Jakub Jelen 372226
-		logit("mkstemp(): %.100s", strerror(oerrno));
Jakub Jelen 372226
-		return oerrno;
Jakub Jelen 372226
-	}
Jakub Jelen 25c16c
+	debug3_f("called");
Jakub Jelen 117678
+	if (need_environment)
Jakub Jelen 117678
+		*need_environment = 0;
Jakub Jelen 117678
+	ret = ssh_krb5_get_cctemplate(ctx, &ccname);
Jakub Jelen 808908
+	if (ret || !ccname || options.kerberos_unique_ccache) {
Jakub Jelen 117678
+		/* Otherwise, go with the old method */
Jakub Jelen 117678
+		if (ccname)
Jakub Jelen 117678
+			free(ccname);
Jakub Jelen 117678
+		ccname = NULL;
Jakub Jelen 117678
+
Jakub Jelen 117678
+		ret = asprintf(&ccname,
Jakub Jelen 117678
+		    "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid());
Jakub Jelen 117678
+		if (ret < 0)
Jakub Jelen 117678
+			return ENOMEM;
Jakub Jelen 372226
 
Jakub Jelen 372226
-	if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) {
Jakub Jelen 117678
+		old_umask = umask(0177);
Jakub Jelen 117678
+		tmpfd = mkstemp(ccname + strlen("FILE:"));
Jakub Jelen 117678
 		oerrno = errno;
Jakub Jelen 117678
-		logit("fchmod(): %.100s", strerror(oerrno));
Jakub Jelen 117678
+		umask(old_umask);
Jakub Jelen 117678
+		if (tmpfd == -1) {
Jakub Jelen 117678
+			logit("mkstemp(): %.100s", strerror(oerrno));
Jakub Jelen 117678
+			return oerrno;
Jakub Jelen 117678
+		}
Jakub Jelen 117678
+
Jakub Jelen 117678
+		if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) {
Jakub Jelen 117678
+			oerrno = errno;
Jakub Jelen 117678
+			logit("fchmod(): %.100s", strerror(oerrno));
Jakub Jelen 117678
+			close(tmpfd);
Jakub Jelen 117678
+			return oerrno;
Jakub Jelen 117678
+		}
Jakub Jelen 117678
+		/* make sure the KRB5CCNAME is set for non-standard location */
Jakub Jelen 117678
+		if (need_environment)
Jakub Jelen 117678
+			*need_environment = 1;
Jakub Jelen 117678
 		close(tmpfd);
Jakub Jelen 117678
-		return oerrno;
Jakub Jelen 117678
 	}
Jakub Jelen 117678
-	close(tmpfd);
Jakub Jelen 117678
 
Jakub Jelen 117678
-	return (krb5_cc_resolve(ctx, ccname, ccache));
Jakub Jelen 25c16c
+	debug3_f("setting default ccname to %s", ccname);
Jakub Jelen 117678
+	/* set the default with already expanded user IDs */
Jakub Jelen 117678
+	ret = krb5_cc_set_default_name(ctx, ccname);
Jakub Jelen 117678
+	if (ret)
Jakub Jelen 117678
+		return ret;
Jakub Jelen 117678
+
Jakub Jelen 117678
+	if ((colon = strstr(ccname, ":")) != NULL) {
Jakub Jelen 117678
+		type_len = colon - ccname;
Jakub Jelen 117678
+		type = malloc((type_len + 1) * sizeof(char));
Jakub Jelen 117678
+		if (type == NULL)
Jakub Jelen 117678
+			return ENOMEM;
Jakub Jelen 117678
+		strncpy(type, ccname, type_len);
Jakub Jelen 117678
+		type[type_len] = 0;
Jakub Jelen 117678
+	} else {
Jakub Jelen 117678
+		type = strdup(ccname);
Jakub Jelen 117678
+	}
Jakub Jelen 117678
+
Jakub Jelen 117678
+	/* If we have a credential cache from krb5.conf, we need to switch
Jakub Jelen 117678
+	 * a primary cache for this collection, if it supports that (non-FILE)
Jakub Jelen 117678
+	 */
Jakub Jelen 117678
+	if (krb5_cc_support_switch(ctx, type)) {
Jakub Jelen 25c16c
+		debug3_f("calling cc_new_unique(%s)", ccname);
Jakub Jelen 117678
+		ret = krb5_cc_new_unique(ctx, type, NULL, ccache);
Jakub Jelen f3715e
+		free(type);
Jakub Jelen 117678
+		if (ret)
Jakub Jelen 117678
+			return ret;
Jakub Jelen 117678
+
Jakub Jelen 25c16c
+		debug3_f("calling cc_switch()");
Jakub Jelen 117678
+		return krb5_cc_switch(ctx, *ccache);
Jakub Jelen 117678
+	} else {
Jakub Jelen 117678
+		/* Otherwise, we can not create a unique ccname here (either
Jakub Jelen 117678
+		 * it is already unique from above or the type does not support
Jakub Jelen 117678
+		 * collections
Jakub Jelen 117678
+		 */
Jakub Jelen f3715e
+		free(type);
Jakub Jelen 25c16c
+		debug3_f("calling cc_resolve(%s)", ccname);
Jakub Jelen 117678
+		return (krb5_cc_resolve(ctx, ccname, ccache));
Jakub Jelen 117678
+	}
Jakub Jelen 117678
 }
Jakub Jelen 117678
 #endif /* !HEIMDAL */
Jakub Jelen 117678
 #endif /* KRB5 */
Dmitry Belyavskiy f32b84
diff -up openssh-8.6p1/gss-serv.c.ccache_name openssh-8.6p1/gss-serv.c
Dmitry Belyavskiy f32b84
--- openssh-8.6p1/gss-serv.c.ccache_name	2021-04-19 14:05:10.844744503 +0200
Dmitry Belyavskiy f32b84
+++ openssh-8.6p1/gss-serv.c	2021-04-19 14:05:10.854744577 +0200
Dmitry Belyavskiy f32b84
@@ -413,13 +413,15 @@ ssh_gssapi_cleanup_creds(void)
Dmitry Belyavskiy f32b84
 }
Jakub Jelen 117678
 
Dmitry Belyavskiy f32b84
 /* As user */
Dmitry Belyavskiy f32b84
-void
Dmitry Belyavskiy f32b84
+int
Dmitry Belyavskiy f32b84
 ssh_gssapi_storecreds(void)
Dmitry Belyavskiy f32b84
 {
Dmitry Belyavskiy f32b84
 	if (gssapi_client.mech && gssapi_client.mech->storecreds) {
Dmitry Belyavskiy f32b84
-		(*gssapi_client.mech->storecreds)(&gssapi_client);
Dmitry Belyavskiy f32b84
+		return (*gssapi_client.mech->storecreds)(&gssapi_client);
Dmitry Belyavskiy f32b84
 	} else
Dmitry Belyavskiy f32b84
 		debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	return 0;
Dmitry Belyavskiy f32b84
 }
Jakub Jelen 117678
 
Dmitry Belyavskiy f32b84
 /* This allows GSSAPI methods to do things to the child's environment based
Dmitry Belyavskiy f32b84
@@ -499,9 +501,7 @@ ssh_gssapi_rekey_creds(void) {
Dmitry Belyavskiy f32b84
 	char *envstr;
Jakub Jelen 117678
 #endif
Jakub Jelen 36fef5
 
Dmitry Belyavskiy f32b84
-	if (gssapi_client.store.filename == NULL &&
Dmitry Belyavskiy f32b84
-	    gssapi_client.store.envval == NULL &&
Dmitry Belyavskiy f32b84
-	    gssapi_client.store.envvar == NULL)
Dmitry Belyavskiy f32b84
+	if (gssapi_client.store.envval == NULL)
Dmitry Belyavskiy f32b84
 		return;
Dmitry Belyavskiy f32b84
 
Dmitry Belyavskiy 089d79
 	ok = mm_ssh_gssapi_update_creds(&gssapi_client.store);
Dmitry Belyavskiy f32b84
diff -up openssh-8.6p1/gss-serv-krb5.c.ccache_name openssh-8.6p1/gss-serv-krb5.c
Dmitry Belyavskiy f32b84
--- openssh-8.6p1/gss-serv-krb5.c.ccache_name	2021-04-19 14:05:10.852744562 +0200
Dmitry Belyavskiy f32b84
+++ openssh-8.6p1/gss-serv-krb5.c	2021-04-19 14:05:10.854744577 +0200
Jakub Jelen 372226
@@ -267,7 +267,7 @@ ssh_gssapi_krb5_cmdok(krb5_principal pri
Jakub Jelen 117678
 /* This writes out any forwarded credentials from the structure populated
Jakub Jelen 117678
  * during userauth. Called after we have setuid to the user */
Jakub Jelen 117678
 
Jakub Jelen 117678
-static void
Jakub Jelen 117678
+static int
Jakub Jelen 117678
 ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
Jakub Jelen 117678
 {
Jakub Jelen 117678
 	krb5_ccache ccache;
Jakub Jelen 372226
@@ -276,14 +276,15 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
Jakub Jelen 117678
 	OM_uint32 maj_status, min_status;
Jakub Jelen 372226
 	const char *new_ccname, *new_cctype;
Jakub Jelen 117678
 	const char *errmsg;
Jakub Jelen 117678
+	int set_env = 0;
Jakub Jelen 117678
 
Jakub Jelen 117678
 	if (client->creds == NULL) {
Jakub Jelen 117678
 		debug("No credentials stored");
Jakub Jelen 117678
-		return;
Jakub Jelen 117678
+		return 0;
Jakub Jelen 117678
 	}
Jakub Jelen 117678
 
Jakub Jelen 117678
 	if (ssh_gssapi_krb5_init() == 0)
Jakub Jelen 117678
-		return;
Jakub Jelen 117678
+		return 0;
Jakub Jelen 117678
 
Jakub Jelen 117678
 #ifdef HEIMDAL
Jakub Jelen 117678
 # ifdef HAVE_KRB5_CC_NEW_UNIQUE
Jakub Jelen 372226
@@ -297,14 +298,14 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
Jakub Jelen 117678
 		krb5_get_err_text(krb_context, problem));
Jakub Jelen 117678
 # endif
Jakub Jelen 117678
 		krb5_free_error_message(krb_context, errmsg);
Jakub Jelen 117678
-		return;
Jakub Jelen 117678
+		return 0;
Jakub Jelen 117678
 	}
Jakub Jelen 117678
 #else
Jakub Jelen 117678
-	if ((problem = ssh_krb5_cc_gen(krb_context, &ccache))) {
Jakub Jelen 117678
+	if ((problem = ssh_krb5_cc_new_unique(krb_context, &ccache, &set_env)) != 0) {
Jakub Jelen 117678
 		errmsg = krb5_get_error_message(krb_context, problem);
Jakub Jelen 117678
-		logit("ssh_krb5_cc_gen(): %.100s", errmsg);
Jakub Jelen 117678
+		logit("ssh_krb5_cc_new_unique(): %.100s", errmsg);
Jakub Jelen 117678
 		krb5_free_error_message(krb_context, errmsg);
Jakub Jelen 117678
-		return;
Jakub Jelen 117678
+		return 0;
Jakub Jelen 117678
 	}
Jakub Jelen 117678
 #endif	/* #ifdef HEIMDAL */
Jakub Jelen 117678
 
Jakub Jelen 372226
@@ -313,7 +314,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
Jakub Jelen 117678
 		errmsg = krb5_get_error_message(krb_context, problem);
Jakub Jelen 117678
 		logit("krb5_parse_name(): %.100s", errmsg);
Jakub Jelen 117678
 		krb5_free_error_message(krb_context, errmsg);
Jakub Jelen 117678
-		return;
Jakub Jelen 117678
+		return 0;
Jakub Jelen 117678
 	}
Jakub Jelen 117678
 
Jakub Jelen 117678
 	if ((problem = krb5_cc_initialize(krb_context, ccache, princ))) {
Jakub Jelen 372226
@@ -322,7 +323,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
Jakub Jelen 117678
 		krb5_free_error_message(krb_context, errmsg);
Jakub Jelen 117678
 		krb5_free_principal(krb_context, princ);
Jakub Jelen 117678
 		krb5_cc_destroy(krb_context, ccache);
Jakub Jelen 117678
-		return;
Jakub Jelen 117678
+		return 0;
Jakub Jelen 117678
 	}
Jakub Jelen 117678
 
Jakub Jelen 117678
 	krb5_free_principal(krb_context, princ);
Jakub Jelen def1de
@@ -331,32 +332,21 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
Jakub Jelen 117678
 	    client->creds, ccache))) {
Jakub Jelen 117678
 		logit("gss_krb5_copy_ccache() failed");
Jakub Jelen 117678
 		krb5_cc_destroy(krb_context, ccache);
Jakub Jelen 117678
-		return;
Jakub Jelen 117678
+		return 0;
Jakub Jelen 117678
 	}
Jakub Jelen 117678
 
Jakub Jelen 372226
 	new_cctype = krb5_cc_get_type(krb_context, ccache);
Jakub Jelen 372226
 	new_ccname = krb5_cc_get_name(krb_context, ccache);
Jakub Jelen 117678
-
Jakub Jelen 117678
-	client->store.envvar = "KRB5CCNAME";
Jakub Jelen 117678
-#ifdef USE_CCAPI
Jakub Jelen 117678
-	xasprintf(&client->store.envval, "API:%s", new_ccname);
Jakub Jelen def1de
-	client->store.filename = NULL;
Jakub Jelen 117678
-#else
Jakub Jelen 117678
-	if (new_ccname[0] == ':')
Jakub Jelen 117678
-		new_ccname++;
Jakub Jelen 372226
 	xasprintf(&client->store.envval, "%s:%s", new_cctype, new_ccname);
Jakub Jelen 117678
-	if (strcmp(new_cctype, "DIR") == 0) {
Jakub Jelen 117678
-		char *p;
Jakub Jelen 117678
-		p = strrchr(client->store.envval, '/');
Jakub Jelen 117678
-		if (p)
Jakub Jelen 117678
-			*p = '\0';
Jakub Jelen 372226
+
Jakub Jelen 117678
+	if (set_env) {
Jakub Jelen 117678
+		client->store.envvar = "KRB5CCNAME";
Jakub Jelen 372226
 	}
Jakub Jelen def1de
 	if ((strcmp(new_cctype, "FILE") == 0) || (strcmp(new_cctype, "DIR") == 0))
Jakub Jelen def1de
 		client->store.filename = xstrdup(new_ccname);
Jakub Jelen 372226
-#endif
Jakub Jelen 117678
 
Jakub Jelen 117678
 #ifdef USE_PAM
Jakub Jelen 117678
-	if (options.use_pam)
Jakub Jelen 117678
+	if (options.use_pam && set_env)
Jakub Jelen 117678
 		do_pam_putenv(client->store.envvar, client->store.envval);
Jakub Jelen 117678
 #endif
Jakub Jelen 117678
 
Dmitry Belyavskiy f32b84
@@ -364,7 +354,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
Jakub Jelen 117678
 
Jakub Jelen 117678
 	client->store.data = krb_context;
Jakub Jelen 117678
 
Jakub Jelen 117678
-	return;
Jakub Jelen 117678
+	return set_env;
Jakub Jelen 117678
 }
Jakub Jelen 117678
 
Jakub Jelen 117678
 int
Dmitry Belyavskiy f32b84
diff -up openssh-8.6p1/servconf.c.ccache_name openssh-8.6p1/servconf.c
Dmitry Belyavskiy f32b84
--- openssh-8.6p1/servconf.c.ccache_name	2021-04-19 14:05:10.848744532 +0200
Dmitry Belyavskiy f32b84
+++ openssh-8.6p1/servconf.c	2021-04-19 14:05:10.854744577 +0200
Dmitry Belyavskiy f32b84
@@ -136,6 +136,7 @@ initialize_server_options(ServerOptions
Jakub Jelen 117678
 	options->kerberos_or_local_passwd = -1;
Jakub Jelen 117678
 	options->kerberos_ticket_cleanup = -1;
Jakub Jelen 117678
 	options->kerberos_get_afs_token = -1;
Jakub Jelen 808908
+	options->kerberos_unique_ccache = -1;
Jakub Jelen 117678
 	options->gss_authentication=-1;
Jakub Jelen 117678
 	options->gss_keyex = -1;
Jakub Jelen 117678
 	options->gss_cleanup_creds = -1;
Dmitry Belyavskiy f32b84
@@ -359,6 +360,8 @@ fill_default_server_options(ServerOption
Jakub Jelen 117678
 		options->kerberos_ticket_cleanup = 1;
Jakub Jelen 117678
 	if (options->kerberos_get_afs_token == -1)
Jakub Jelen 117678
 		options->kerberos_get_afs_token = 0;
Jakub Jelen 808908
+	if (options->kerberos_unique_ccache == -1)
Jakub Jelen 808908
+		options->kerberos_unique_ccache = 0;
Jakub Jelen 117678
 	if (options->gss_authentication == -1)
Jakub Jelen 117678
 		options->gss_authentication = 0;
Jakub Jelen 117678
 	if (options->gss_keyex == -1)
Dmitry Belyavskiy 7b76af
@@ -506,7 +509,7 @@ typedef enum {
Dmitry Belyavskiy 8f4d19
	sPort, sHostKeyFile, sLoginGraceTime,
Dmitry Belyavskiy 8f4d19
	sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose,
Dmitry Belyavskiy 8f4d19
	sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
Dmitry Belyavskiy 7b76af
-	sKerberosGetAFSToken, sPasswordAuthentication,
Dmitry Belyavskiy 7b76af
+	sKerberosGetAFSToken, sKerberosUniqueCCache, sPasswordAuthentication,
Dmitry Belyavskiy 7b76af
	sKbdInteractiveAuthentication, sListenAddress, sAddressFamily,
Dmitry Belyavskiy 8f4d19
	sPrintMotd, sPrintLastLog, sIgnoreRhosts,
Dmitry Belyavskiy 7b76af
	sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
Dmitry Belyavskiy f32b84
@@ -593,11 +597,13 @@ static struct {
Jakub Jelen 117678
 #else
Jakub Jelen 117678
 	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
Jakub Jelen 117678
 #endif
Jakub Jelen 808908
+	{ "kerberosuniqueccache", sKerberosUniqueCCache, SSHCFG_GLOBAL },
Jakub Jelen 117678
 #else
Jakub Jelen 117678
 	{ "kerberosauthentication", sUnsupported, SSHCFG_ALL },
Jakub Jelen 117678
 	{ "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
Jakub Jelen 117678
 	{ "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
Jakub Jelen 117678
 	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
Jakub Jelen 808908
+	{ "kerberosuniqueccache", sUnsupported, SSHCFG_GLOBAL },
Jakub Jelen 117678
 #endif
Jakub Jelen 117678
 	{ "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
Jakub Jelen 117678
 	{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
Dmitry Belyavskiy f32b84
@@ -1573,6 +1579,10 @@ process_server_config_line_depth(ServerO
Jakub Jelen 117678
 		intptr = &options->kerberos_get_afs_token;
Jakub Jelen 117678
 		goto parse_flag;
Jakub Jelen 117678
 
Jakub Jelen 808908
+	case sKerberosUniqueCCache:
Jakub Jelen 808908
+		intptr = &options->kerberos_unique_ccache;
Jakub Jelen 117678
+		goto parse_flag;
Jakub Jelen 117678
+
Jakub Jelen 117678
 	case sGssAuthentication:
Jakub Jelen 117678
 		intptr = &options->gss_authentication;
Jakub Jelen 117678
 		goto parse_flag;
Dmitry Belyavskiy f32b84
@@ -2891,6 +2901,7 @@ dump_config(ServerOptions *o)
Jakub Jelen 117678
 # ifdef USE_AFS
Jakub Jelen 117678
 	dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
Jakub Jelen 117678
 # endif
Jakub Jelen 808908
+	dump_cfg_fmtint(sKerberosUniqueCCache, o->kerberos_unique_ccache);
Jakub Jelen 117678
 #endif
Jakub Jelen 117678
 #ifdef GSSAPI
Jakub Jelen 117678
 	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
Dmitry Belyavskiy f32b84
diff -up openssh-8.6p1/servconf.h.ccache_name openssh-8.6p1/servconf.h
Dmitry Belyavskiy f32b84
--- openssh-8.6p1/servconf.h.ccache_name	2021-04-19 14:05:10.848744532 +0200
Dmitry Belyavskiy f32b84
+++ openssh-8.6p1/servconf.h	2021-04-19 14:05:10.855744584 +0200
Dmitry Belyavskiy f32b84
@@ -140,6 +140,8 @@ typedef struct {
Jakub Jelen 117678
 						 * file on logout. */
Jakub Jelen 117678
 	int     kerberos_get_afs_token;		/* If true, try to get AFS token if
Jakub Jelen 117678
 						 * authenticated with Kerberos. */
Jakub Jelen 808908
+	int     kerberos_unique_ccache;		/* If true, the acquired ticket will
Jakub Jelen 117678
+						 * be stored in per-session ccache */
Jakub Jelen 117678
 	int     gss_authentication;	/* If true, permit GSSAPI authentication */
Jakub Jelen 117678
 	int     gss_keyex;		/* If true, permit GSSAPI key exchange */
Jakub Jelen 117678
 	int     gss_cleanup_creds;	/* If true, destroy cred cache on logout */
Dmitry Belyavskiy f32b84
diff -up openssh-8.6p1/session.c.ccache_name openssh-8.6p1/session.c
Dmitry Belyavskiy f32b84
--- openssh-8.6p1/session.c.ccache_name	2021-04-19 14:05:10.852744562 +0200
Dmitry Belyavskiy f32b84
+++ openssh-8.6p1/session.c	2021-04-19 14:05:10.855744584 +0200
Dmitry Belyavskiy f32b84
@@ -1038,7 +1038,8 @@ do_setup_env(struct ssh *ssh, Session *s
Jakub Jelen 117678
 	/* Allow any GSSAPI methods that we've used to alter
Jakub Jelen 5cd955
 	 * the child's environment as they see fit
Jakub Jelen 117678
 	 */
Jakub Jelen 117678
-	ssh_gssapi_do_child(&env, &envsize);
Jakub Jelen 117678
+	if (s->authctxt->krb5_set_env)
Jakub Jelen 117678
+		ssh_gssapi_do_child(&env, &envsize);
Jakub Jelen 117678
 #endif
Jakub Jelen 117678
 
Jakub Jelen 117678
 	/* Set basic environment. */
Dmitry Belyavskiy f32b84
@@ -1114,7 +1115,7 @@ do_setup_env(struct ssh *ssh, Session *s
Jakub Jelen 117678
 	}
Jakub Jelen 117678
 #endif
Jakub Jelen 117678
 #ifdef KRB5
Jakub Jelen 117678
-	if (s->authctxt->krb5_ccname)
Jakub Jelen 117678
+	if (s->authctxt->krb5_ccname && s->authctxt->krb5_set_env)
Jakub Jelen 117678
 		child_set_env(&env, &envsize, "KRB5CCNAME",
Jakub Jelen 117678
 		    s->authctxt->krb5_ccname);
Jakub Jelen 117678
 #endif
Dmitry Belyavskiy 089d79
diff -up openssh-8.6p1/sshd-session.c.ccache_name openssh-8.6p1/sshd-session.c
Dmitry Belyavskiy 089d79
--- openssh-8.6p1/sshd-session.c.ccache_name	2021-04-19 14:05:10.849744540 +0200
Dmitry Belyavskiy 089d79
+++ openssh-8.6p1/sshd-session.c	2021-04-19 14:05:10.855744584 +0200
Dmitry Belyavskiy f32b84
@@ -2284,7 +2284,7 @@ main(int ac, char **av)
Jakub Jelen 117678
 #ifdef GSSAPI
Jakub Jelen 117678
 	if (options.gss_authentication) {
Jakub Jelen 117678
 		temporarily_use_uid(authctxt->pw);
Jakub Jelen 117678
-		ssh_gssapi_storecreds();
Jakub Jelen 117678
+		authctxt->krb5_set_env = ssh_gssapi_storecreds();
Jakub Jelen 117678
 		restore_uid();
Jakub Jelen 117678
 	}
Jakub Jelen 117678
 #endif
Dmitry Belyavskiy f32b84
diff -up openssh-8.6p1/sshd_config.5.ccache_name openssh-8.6p1/sshd_config.5
Dmitry Belyavskiy f32b84
--- openssh-8.6p1/sshd_config.5.ccache_name	2021-04-19 14:05:10.849744540 +0200
Dmitry Belyavskiy f32b84
+++ openssh-8.6p1/sshd_config.5	2021-04-19 14:05:10.856744592 +0200
Dmitry Belyavskiy f32b84
@@ -939,6 +939,14 @@ Specifies whether to automatically destr
Jakub Jelen 117678
 file on logout.
Jakub Jelen 117678
 The default is
Jakub Jelen 117678
 .Cm yes .
Jakub Jelen 808908
+.It Cm KerberosUniqueCCache
Jakub Jelen 808908
+Specifies whether to store the acquired tickets in the per-session credential
Jakub Jelen 808908
+cache under /tmp/ or whether to use per-user credential cache as configured in
Jakub Jelen 808908
+.Pa /etc/krb5.conf .
Jakub Jelen 808908
+The default value
Jakub Jelen 808908
+.Cm no
Jakub Jelen 808908
+can lead to overwriting previous tickets by subseqent connections to the same
Jakub Jelen 808908
+user account.
Jakub Jelen 117678
 .It Cm KexAlgorithms
Dmitry Belyavskiy 089d79
 Specifies the permitted KEX (Key Exchange) algorithms that the server will
Dmitry Belyavskiy 089d79
 offer to clients.
Dmitry Belyavskiy f32b84
diff -up openssh-8.6p1/ssh-gss.h.ccache_name openssh-8.6p1/ssh-gss.h
Dmitry Belyavskiy f32b84
--- openssh-8.6p1/ssh-gss.h.ccache_name	2021-04-19 14:05:10.852744562 +0200
Dmitry Belyavskiy f32b84
+++ openssh-8.6p1/ssh-gss.h	2021-04-19 14:05:10.855744584 +0200
Dmitry Belyavskiy f32b84
@@ -114,7 +114,7 @@ typedef struct ssh_gssapi_mech_struct {
Dmitry Belyavskiy f32b84
 	int (*dochild) (ssh_gssapi_client *);
Dmitry Belyavskiy f32b84
 	int (*userok) (ssh_gssapi_client *, char *);
Dmitry Belyavskiy f32b84
 	int (*localname) (ssh_gssapi_client *, char **);
Dmitry Belyavskiy f32b84
-	void (*storecreds) (ssh_gssapi_client *);
Dmitry Belyavskiy f32b84
+	int (*storecreds) (ssh_gssapi_client *);
Dmitry Belyavskiy f32b84
 	int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *);
Dmitry Belyavskiy f32b84
 } ssh_gssapi_mech;
Dmitry Belyavskiy f32b84
 
Dmitry Belyavskiy f32b84
@@ -175,7 +175,7 @@ int ssh_gssapi_userok(char *name, struct
Dmitry Belyavskiy f32b84
 OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
Dmitry Belyavskiy f32b84
 void ssh_gssapi_do_child(char ***, u_int *);
Dmitry Belyavskiy f32b84
 void ssh_gssapi_cleanup_creds(void);
Dmitry Belyavskiy f32b84
-void ssh_gssapi_storecreds(void);
Dmitry Belyavskiy f32b84
+int ssh_gssapi_storecreds(void);
Dmitry Belyavskiy f32b84
 const char *ssh_gssapi_displayname(void);
Dmitry Belyavskiy f32b84
 
Dmitry Belyavskiy f32b84
 char *ssh_gssapi_server_mechanisms(void);