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