6cf9b8e
diff -up openssh-7.4p1/auth2.c.expose-pam openssh-7.4p1/auth2.c
6cf9b8e
--- openssh-7.4p1/auth2.c.expose-pam	2016-12-23 15:40:26.768447868 +0100
6cf9b8e
+++ openssh-7.4p1/auth2.c	2016-12-23 15:40:26.818447876 +0100
209c7a8
@@ -310,6 +310,7 @@ userauth_finish(Authctxt *authctxt, int
209c7a8
     const char *submethod)
209c7a8
 {
209c7a8
 	char *methods;
209c7a8
+	char *prev_auth_details;
209c7a8
 	int partial = 0;
209c7a8
 
209c7a8
 	if (!authctxt->valid && authenticated)
209c7a8
@@ -340,6 +341,18 @@ userauth_finish(Authctxt *authctxt, int
209c7a8
 	if (authctxt->postponed)
209c7a8
 		return;
209c7a8
 
209c7a8
+	if (authenticated || partial) {
209c7a8
+		prev_auth_details = authctxt->auth_details;
209c7a8
+		xasprintf(&authctxt->auth_details, "%s%s%s%s%s",
209c7a8
+		    prev_auth_details ? prev_auth_details : "",
209c7a8
+		    prev_auth_details ? ", " : "", method,
209c7a8
+		    authctxt->last_details ? ": " : "",
209c7a8
+		    authctxt->last_details ? authctxt->last_details : "");
209c7a8
+		free(prev_auth_details);
209c7a8
+	}
209c7a8
+	free(authctxt->last_details);
209c7a8
+	authctxt->last_details = NULL;
209c7a8
+
209c7a8
 #ifdef USE_PAM
209c7a8
 	if (options.use_pam && authenticated) {
209c7a8
 		if (!PRIVSEP(do_pam_account())) {
6cf9b8e
diff -up openssh-7.4p1/auth2-gss.c.expose-pam openssh-7.4p1/auth2-gss.c
6cf9b8e
--- openssh-7.4p1/auth2-gss.c.expose-pam	2016-12-23 15:40:26.769447868 +0100
6cf9b8e
+++ openssh-7.4p1/auth2-gss.c	2016-12-23 15:40:26.818447876 +0100
209c7a8
@@ -276,6 +276,9 @@ input_gssapi_exchange_complete(int type,
209c7a8
 	authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
209c7a8
 	    authctxt->pw));
209c7a8
 
209c7a8
+	if (authenticated)
209c7a8
+		authctxt->last_details = ssh_gssapi_get_displayname();
209c7a8
+
209c7a8
 	authctxt->postponed = 0;
209c7a8
 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
209c7a8
 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
209c7a8
@@ -322,6 +325,9 @@ input_gssapi_mic(int type, u_int32_t ple
209c7a8
 	else
209c7a8
 		logit("GSSAPI MIC check failed");
209c7a8
 
209c7a8
+	if (authenticated)
209c7a8
+		authctxt->last_details = ssh_gssapi_get_displayname();
209c7a8
+
209c7a8
 	buffer_free(&b);
209c7a8
 	if (micuser != authctxt->user)
209c7a8
 		free(micuser);
6cf9b8e
diff -up openssh-7.4p1/auth2-hostbased.c.expose-pam openssh-7.4p1/auth2-hostbased.c
6cf9b8e
--- openssh-7.4p1/auth2-hostbased.c.expose-pam	2016-12-23 15:40:26.731447862 +0100
6cf9b8e
+++ openssh-7.4p1/auth2-hostbased.c	2016-12-23 15:40:26.818447876 +0100
209c7a8
@@ -60,7 +60,7 @@ userauth_hostbased(Authctxt *authctxt)
209c7a8
 {
209c7a8
 	Buffer b;
209c7a8
 	Key *key = NULL;
209c7a8
-	char *pkalg, *cuser, *chost, *service;
209c7a8
+	char *pkalg, *cuser, *chost, *service, *pubkey;
209c7a8
 	u_char *pkblob, *sig;
209c7a8
 	u_int alen, blen, slen;
209c7a8
 	int pktype;
209c7a8
@@ -140,15 +140,21 @@ userauth_hostbased(Authctxt *authctxt)
209c7a8
 	buffer_dump(&b);
209c7a8
 #endif
209c7a8
 
209c7a8
-	pubkey_auth_info(authctxt, key,
209c7a8
-	    "client user \"%.100s\", client host \"%.100s\"", cuser, chost);
209c7a8
+	pubkey = sshkey_format_oneline(key, options.fingerprint_hash);
209c7a8
+	auth_info(authctxt,
209c7a8
+	    "%s, client user \"%.100s\", client host \"%.100s\"",
209c7a8
+	    pubkey, cuser, chost);
209c7a8
 
209c7a8
 	/* test for allowed key and correct signature */
209c7a8
 	authenticated = 0;
209c7a8
 	if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) &&
209c7a8
 	    PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
209c7a8
-			buffer_len(&b))) == 1)
209c7a8
+			buffer_len(&b))) == 1) {
209c7a8
 		authenticated = 1;
209c7a8
+		authctxt->last_details = pubkey;
209c7a8
+	} else {
209c7a8
+		free(pubkey);
209c7a8
+	}
209c7a8
 
209c7a8
 	buffer_free(&b);
209c7a8
 done:
6cf9b8e
diff -up openssh-7.4p1/auth2-pubkey.c.expose-pam openssh-7.4p1/auth2-pubkey.c
6cf9b8e
--- openssh-7.4p1/auth2-pubkey.c.expose-pam	2016-12-23 15:40:26.746447864 +0100
6cf9b8e
+++ openssh-7.4p1/auth2-pubkey.c	2016-12-23 15:40:26.819447876 +0100
209c7a8
@@ -79,7 +79,7 @@ userauth_pubkey(Authctxt *authctxt)
209c7a8
 {
209c7a8
 	Buffer b;
209c7a8
 	Key *key = NULL;
209c7a8
-	char *pkalg, *userstyle, *fp = NULL;
209c7a8
+	char *pkalg, *userstyle, *pubkey, *fp = NULL;
209c7a8
 	u_char *pkblob, *sig;
209c7a8
 	u_int alen, blen, slen;
209c7a8
 	int have_sig, pktype;
6cf9b8e
@@ -177,7 +177,8 @@ userauth_pubkey(Authctxt *authctxt)
209c7a8
 #ifdef DEBUG_PK
209c7a8
 		buffer_dump(&b);
209c7a8
 #endif
209c7a8
-		pubkey_auth_info(authctxt, key, NULL);
209c7a8
+		pubkey = sshkey_format_oneline(key, options.fingerprint_hash);
209c7a8
+		auth_info(authctxt, "%s", pubkey);
209c7a8
 
209c7a8
 		/* test for correct signature */
209c7a8
 		authenticated = 0;
6cf9b8e
@@ -185,9 +186,12 @@ userauth_pubkey(Authctxt *authctxt)
209c7a8
 		    PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
209c7a8
 		    buffer_len(&b))) == 1) {
209c7a8
 			authenticated = 1;
209c7a8
+			authctxt->last_details = pubkey;
209c7a8
 			/* Record the successful key to prevent reuse */
209c7a8
 			auth2_record_userkey(authctxt, key);
209c7a8
 			key = NULL; /* Don't free below */
209c7a8
+		} else {
209c7a8
+			free(pubkey);
209c7a8
 		}
209c7a8
 		buffer_free(&b);
209c7a8
 		free(sig);
6cf9b8e
@@ -228,7 +232,7 @@ done:
209c7a8
 void
209c7a8
 pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...)
209c7a8
 {
209c7a8
-	char *fp, *extra;
209c7a8
+	char *extra, *pubkey;
209c7a8
 	va_list ap;
209c7a8
 	int i;
209c7a8
 
6cf9b8e
@@ -238,27 +242,13 @@ pubkey_auth_info(Authctxt *authctxt, con
209c7a8
 		i = vasprintf(&extra, fmt, ap);
209c7a8
 		va_end(ap);
209c7a8
 		if (i < 0 || extra == NULL)
209c7a8
-			fatal("%s: vasprintf failed", __func__);	
209c7a8
+			fatal("%s: vasprintf failed", __func__);
209c7a8
 	}
209c7a8
 
209c7a8
-	if (key_is_cert(key)) {
209c7a8
-		fp = sshkey_fingerprint(key->cert->signature_key,
209c7a8
-		    options.fingerprint_hash, SSH_FP_DEFAULT);
209c7a8
-		auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s", 
209c7a8
-		    key_type(key), key->cert->key_id,
209c7a8
-		    (unsigned long long)key->cert->serial,
209c7a8
-		    key_type(key->cert->signature_key),
209c7a8
-		    fp == NULL ? "(null)" : fp,
209c7a8
-		    extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
209c7a8
-		free(fp);
209c7a8
-	} else {
209c7a8
-		fp = sshkey_fingerprint(key, options.fingerprint_hash,
209c7a8
-		    SSH_FP_DEFAULT);
209c7a8
-		auth_info(authctxt, "%s %s%s%s", key_type(key),
209c7a8
-		    fp == NULL ? "(null)" : fp,
209c7a8
-		    extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
209c7a8
-		free(fp);
209c7a8
-	}
209c7a8
+	pubkey = sshkey_format_oneline(key, options.fingerprint_hash);
209c7a8
+	auth_info(authctxt, "%s%s%s", pubkey, extra == NULL ? "" : ", ",
209c7a8
+	    extra == NULL ? "" : extra);
209c7a8
+	free(pubkey);
209c7a8
 	free(extra);
209c7a8
 }
209c7a8
 
6cf9b8e
diff -up openssh-7.4p1/auth.h.expose-pam openssh-7.4p1/auth.h
6cf9b8e
--- openssh-7.4p1/auth.h.expose-pam	2016-12-23 15:40:26.782447870 +0100
6cf9b8e
+++ openssh-7.4p1/auth.h	2016-12-23 15:40:26.819447876 +0100
209c7a8
@@ -84,6 +84,9 @@ struct Authctxt {
209c7a8
 
209c7a8
 	struct sshkey	**prev_userkeys;
209c7a8
 	u_int		 nprev_userkeys;
209c7a8
+
209c7a8
+	char		*last_details;
209c7a8
+	char		*auth_details;
209c7a8
 };
209c7a8
 /*
209c7a8
  * Every authentication method has to handle authentication requests for
6cf9b8e
diff -up openssh-7.4p1/auth-pam.c.expose-pam openssh-7.4p1/auth-pam.c
6cf9b8e
--- openssh-7.4p1/auth-pam.c.expose-pam	2016-12-23 15:40:26.731447862 +0100
6cf9b8e
+++ openssh-7.4p1/auth-pam.c	2016-12-23 15:40:26.819447876 +0100
6cf9b8e
@@ -688,6 +688,11 @@ sshpam_init_ctx(Authctxt *authctxt)
209c7a8
 		return (NULL);
209c7a8
 	}
209c7a8
 
209c7a8
+	/* Notify PAM about any already successful auth methods */
209c7a8
+	if (options.expose_auth_methods >= EXPOSE_AUTHMETH_PAMONLY &&
209c7a8
+			authctxt->auth_details)
209c7a8
+		do_pam_putenv("SSH_USER_AUTH", authctxt->auth_details);
209c7a8
+
209c7a8
 	ctxt = xcalloc(1, sizeof *ctxt);
209c7a8
 
209c7a8
 	/* Start the authentication thread */
6cf9b8e
diff -up openssh-7.4p1/gss-serv.c.expose-pam openssh-7.4p1/gss-serv.c
6cf9b8e
--- openssh-7.4p1/gss-serv.c.expose-pam	2016-12-23 15:40:26.808447874 +0100
6cf9b8e
+++ openssh-7.4p1/gss-serv.c	2016-12-23 15:40:26.819447876 +0100
209c7a8
@@ -441,6 +441,16 @@ ssh_gssapi_do_child(char ***envp, u_int
209c7a8
 }
209c7a8
 
209c7a8
 /* Privileged */
209c7a8
+char*
209c7a8
+ssh_gssapi_get_displayname(void)
209c7a8
+{
209c7a8
+	if (gssapi_client.displayname.length != 0 &&
209c7a8
+	    gssapi_client.displayname.value != NULL)
209c7a8
+		return strdup((char *)gssapi_client.displayname.value);
209c7a8
+	return NULL;
209c7a8
+}
209c7a8
+
209c7a8
+/* Privileged */
209c7a8
 int
209c7a8
 ssh_gssapi_userok(char *user, struct passwd *pw)
209c7a8
 {
6cf9b8e
diff -up openssh-7.4p1/monitor.c.expose-pam openssh-7.4p1/monitor.c
6cf9b8e
--- openssh-7.4p1/monitor.c.expose-pam	2016-12-23 15:40:26.794447872 +0100
6cf9b8e
+++ openssh-7.4p1/monitor.c	2016-12-23 15:41:16.473455863 +0100
6cf9b8e
@@ -300,6 +300,7 @@ monitor_child_preauth(Authctxt *_authctx
209c7a8
 {
209c7a8
 	struct mon_table *ent;
209c7a8
 	int authenticated = 0, partial = 0;
209c7a8
+	char *prev_auth_details;
209c7a8
 
209c7a8
 	debug3("preauth child monitor started");
209c7a8
 
6cf9b8e
@@ -330,6 +331,18 @@ monitor_child_preauth(Authctxt *_authctx
209c7a8
 		auth_submethod = NULL;
209c7a8
 		authenticated = (monitor_read(pmonitor, mon_dispatch, &ent) == 1);
209c7a8
 
209c7a8
+		if (authenticated) {
209c7a8
+			prev_auth_details = authctxt->auth_details;
209c7a8
+			xasprintf(&authctxt->auth_details, "%s%s%s%s%s",
209c7a8
+			    prev_auth_details ? prev_auth_details : "",
209c7a8
+			    prev_auth_details ? ", " : "", auth_method,
209c7a8
+			    authctxt->last_details ? ": " : "",
209c7a8
+			    authctxt->last_details ? authctxt->last_details : "");
209c7a8
+			free(prev_auth_details);
209c7a8
+		}
209c7a8
+		free(authctxt->last_details);
209c7a8
+		authctxt->last_details = NULL;
209c7a8
+
209c7a8
 		/* Special handling for multiple required authentications */
209c7a8
 		if (options.num_auth_methods != 0) {
6cf9b8e
 			if (authenticated &&
6cf9b8e
@@ -1417,6 +1430,10 @@ mm_answer_keyverify(int sock, Buffer *m)
209c7a8
 	debug3("%s: key %p signature %s",
209c7a8
 	    __func__, key, (verified == 1) ? "verified" : "unverified");
209c7a8
 
209c7a8
+	if (verified == 1)
209c7a8
+		authctxt->last_details = sshkey_format_oneline(key,
209c7a8
+		    options.fingerprint_hash);
209c7a8
+
209c7a8
 	/* If auth was successful then record key to ensure it isn't reused */
209c7a8
 	if (verified == 1 && key_blobtype == MM_USERKEY)
209c7a8
 		auth2_record_userkey(authctxt, key);
6cf9b8e
@@ -1860,6 +1877,9 @@ mm_answer_gss_userok(int sock, Buffer *m
209c7a8
 
209c7a8
 	auth_method = "gssapi-with-mic";
209c7a8
 
209c7a8
+	if (authenticated)
209c7a8
+		authctxt->last_details = ssh_gssapi_get_displayname();
209c7a8
+
209c7a8
 	/* Monitor loop will terminate if authenticated */
209c7a8
 	return (authenticated);
209c7a8
 }
6cf9b8e
diff -up openssh-7.4p1/servconf.c.expose-pam openssh-7.4p1/servconf.c
6cf9b8e
--- openssh-7.4p1/servconf.c.expose-pam	2016-12-23 15:40:26.810447875 +0100
6cf9b8e
+++ openssh-7.4p1/servconf.c	2016-12-23 15:44:04.691482920 +0100
6cf9b8e
@@ -171,6 +171,7 @@ initialize_server_options(ServerOptions
6cf9b8e
 	options->disable_forwarding = -1;
209c7a8
 	options->use_kuserok = -1;
209c7a8
 	options->enable_k5users = -1;
209c7a8
+	options->expose_auth_methods = -1;
209c7a8
 }
209c7a8
 
209c7a8
 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
6cf9b8e
@@ -354,6 +355,8 @@ fill_default_server_options(ServerOption
209c7a8
 		options->use_kuserok = 1;
6cf9b8e
 	if (options->enable_k5users == -1)
6cf9b8e
 		options->enable_k5users = 0;
209c7a8
+	if (options->expose_auth_methods == -1)
209c7a8
+		options->expose_auth_methods = EXPOSE_AUTHMETH_NEVER;
209c7a8
 
209c7a8
 	assemble_algorithms(options);
209c7a8
 
6cf9b8e
@@ -439,6 +442,7 @@ typedef enum {
209c7a8
 	sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
209c7a8
 	sStreamLocalBindMask, sStreamLocalBindUnlink,
6cf9b8e
 	sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
209c7a8
+	sExposeAuthenticationMethods,
6cf9b8e
 	sDeprecated, sIgnore, sUnsupported
209c7a8
 } ServerOpCodes;
209c7a8
 
6cf9b8e
@@ -595,6 +599,7 @@ static struct {
209c7a8
 	{ "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
209c7a8
 	{ "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
6cf9b8e
 	{ "disableforwarding", sDisableForwarding, SSHCFG_ALL },
209c7a8
+	{ "exposeauthenticationmethods", sExposeAuthenticationMethods, SSHCFG_ALL },
209c7a8
 	{ NULL, sBadOption, 0 }
209c7a8
 };
209c7a8
 
6cf9b8e
@@ -984,6 +989,12 @@ static const struct multistate multistat
209c7a8
 	{ "local",			FORWARD_LOCAL },
209c7a8
 	{ NULL, -1 }
209c7a8
 };
209c7a8
+static const struct multistate multistate_exposeauthmeth[] = {
209c7a8
+	{ "never",			EXPOSE_AUTHMETH_NEVER },
209c7a8
+	{ "pam-only",			EXPOSE_AUTHMETH_PAMONLY },
209c7a8
+	{ "pam-and-env",		EXPOSE_AUTHMETH_PAMENV },
209c7a8
+	{ NULL, -1}
209c7a8
+};
209c7a8
 
209c7a8
 int
209c7a8
 process_server_config_line(ServerOptions *options, char *line,
6cf9b8e
@@ -1902,6 +1913,11 @@ process_server_config_line(ServerOptions
209c7a8
 			options->fingerprint_hash = value;
209c7a8
 		break;
209c7a8
 
209c7a8
+	case sExposeAuthenticationMethods:
209c7a8
+		intptr = &options->expose_auth_methods;
209c7a8
+		multistate_ptr = multistate_exposeauthmeth;
209c7a8
+		goto parse_multistate;
209c7a8
+
209c7a8
 	case sDeprecated:
6cf9b8e
 	case sIgnore:
6cf9b8e
 	case sUnsupported:
6cf9b8e
@@ -2060,6 +2076,7 @@ copy_set_server_options(ServerOptions *d
209c7a8
 	M_CP_INTOPT(enable_k5users);
209c7a8
 	M_CP_INTOPT(rekey_limit);
209c7a8
 	M_CP_INTOPT(rekey_interval);
209c7a8
+	M_CP_INTOPT(expose_auth_methods);
209c7a8
 
5878ebb
 	/*
5878ebb
 	 * The bind_mask is a mode_t that may be unsigned, so we can't use
6cf9b8e
@@ -2176,6 +2193,8 @@ fmt_intarg(ServerOpCodes code, int val)
209c7a8
 		return fmt_multistate_int(val, multistate_tcpfwd);
209c7a8
 	case sFingerprintHash:
209c7a8
 		return ssh_digest_alg_name(val);
209c7a8
+	case sExposeAuthenticationMethods:
209c7a8
+		return fmt_multistate_int(val, multistate_exposeauthmeth);
6cf9b8e
 	default:
209c7a8
 		switch (val) {
6cf9b8e
 		case 0:
6cf9b8e
@@ -2356,6 +2375,7 @@ dump_config(ServerOptions *o)
209c7a8
 	dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
209c7a8
 	dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok);
209c7a8
 	dump_cfg_fmtint(sGssEnablek5users, o->enable_k5users);
209c7a8
+	dump_cfg_fmtint(sExposeAuthenticationMethods, o->expose_auth_methods);
209c7a8
 
209c7a8
 	/* string arguments */
209c7a8
 	dump_cfg_string(sPidFile, o->pid_file);
6cf9b8e
diff -up openssh-7.4p1/servconf.h.expose-pam openssh-7.4p1/servconf.h
6cf9b8e
--- openssh-7.4p1/servconf.h.expose-pam	2016-12-23 15:40:26.810447875 +0100
6cf9b8e
+++ openssh-7.4p1/servconf.h	2016-12-23 15:40:26.821447876 +0100
209c7a8
@@ -48,6 +48,11 @@
209c7a8
 #define FORWARD_LOCAL		(1<<1)
209c7a8
 #define FORWARD_ALLOW		(FORWARD_REMOTE|FORWARD_LOCAL)
209c7a8
 
209c7a8
+/* Expose AuthenticationMethods */
209c7a8
+#define EXPOSE_AUTHMETH_NEVER   0
209c7a8
+#define EXPOSE_AUTHMETH_PAMONLY 1
209c7a8
+#define EXPOSE_AUTHMETH_PAMENV  2
209c7a8
+
209c7a8
 #define DEFAULT_AUTH_FAIL_MAX	6	/* Default for MaxAuthTries */
209c7a8
 #define DEFAULT_SESSIONS_MAX	10	/* Default for MaxSessions */
209c7a8
 
6cf9b8e
@@ -195,6 +200,8 @@ typedef struct {
209c7a8
 	char   *auth_methods[MAX_AUTH_METHODS];
209c7a8
 
209c7a8
 	int	fingerprint_hash;
209c7a8
+
209c7a8
+	int	expose_auth_methods; /* EXPOSE_AUTHMETH_* above */
209c7a8
 }       ServerOptions;
209c7a8
 
209c7a8
 /* Information about the incoming connection as used by Match */
6cf9b8e
diff -up openssh-7.4p1/session.c.expose-pam openssh-7.4p1/session.c
6cf9b8e
--- openssh-7.4p1/session.c.expose-pam	2016-12-23 15:40:26.794447872 +0100
6cf9b8e
+++ openssh-7.4p1/session.c	2016-12-23 15:40:26.821447876 +0100
6cf9b8e
@@ -997,6 +997,12 @@ copy_environment(char **source, char ***
209c7a8
 		}
209c7a8
 		*var_val++ = '\0';
209c7a8
 
209c7a8
+		if (options.expose_auth_methods < EXPOSE_AUTHMETH_PAMENV &&
209c7a8
+				strcmp(var_name, "SSH_USER_AUTH") == 0) {
209c7a8
+			free(var_name);
209c7a8
+			continue;
209c7a8
+		}
209c7a8
+
209c7a8
 		debug3("Copy environment: %s=%s", var_name, var_val);
209c7a8
 		child_set_env(env, envsize, var_name, var_val);
209c7a8
 
6cf9b8e
@@ -1173,6 +1179,11 @@ do_setup_env(Session *s, const char *she
209c7a8
 	}
209c7a8
 #endif /* USE_PAM */
209c7a8
 
209c7a8
+	if (options.expose_auth_methods >= EXPOSE_AUTHMETH_PAMENV &&
209c7a8
+			s->authctxt->auth_details)
209c7a8
+		child_set_env(&env, &envsize, "SSH_USER_AUTH",
209c7a8
+		     s->authctxt->auth_details);
209c7a8
+
209c7a8
 	if (auth_sock_name != NULL)
209c7a8
 		child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
209c7a8
 		    auth_sock_name);
6cf9b8e
@@ -2561,6 +2572,9 @@ do_cleanup(Authctxt *authctxt)
209c7a8
 	if (authctxt == NULL)
209c7a8
 		return;
209c7a8
 
209c7a8
+	free(authctxt->auth_details);
209c7a8
+	authctxt->auth_details = NULL;
209c7a8
+
209c7a8
 #ifdef USE_PAM
209c7a8
 	if (options.use_pam) {
209c7a8
 		sshpam_cleanup();
6cf9b8e
diff -up openssh-7.4p1/ssh.1.expose-pam openssh-7.4p1/ssh.1
6cf9b8e
--- openssh-7.4p1/ssh.1.expose-pam	2016-12-23 15:40:26.810447875 +0100
6cf9b8e
+++ openssh-7.4p1/ssh.1	2016-12-23 15:40:26.822447877 +0100
6cf9b8e
@@ -1421,6 +1421,10 @@ server IP address, and server port numbe
209c7a8
 This variable contains the original command line if a forced command
209c7a8
 is executed.
209c7a8
 It can be used to extract the original arguments.
209c7a8
+.It Ev SSH_USER_AUTH
209c7a8
+This variable contains, for SSH2 only, a comma-separated list of authentication
209c7a8
+methods that were successfuly used to authenticate. When possible, these
209c7a8
+methods are extended with detailed information on the credential used.
209c7a8
 .It Ev SSH_TTY
209c7a8
 This is set to the name of the tty (path to the device) associated
209c7a8
 with the current shell or command.
6cf9b8e
diff -up openssh-7.4p1/sshd_config.5.expose-pam openssh-7.4p1/sshd_config.5
6cf9b8e
--- openssh-7.4p1/sshd_config.5.expose-pam	2016-12-23 15:40:26.822447877 +0100
6cf9b8e
+++ openssh-7.4p1/sshd_config.5	2016-12-23 15:45:22.411495421 +0100
6cf9b8e
@@ -570,6 +570,21 @@ Disables all forwarding features, includ
6cf9b8e
 TCP and StreamLocal.
6cf9b8e
 This option overrides all other forwarding-related options and may
6cf9b8e
 simplify restricted configurations.
209c7a8
+.It Cm ExposeAuthenticationMethods
209c7a8
+When using SSH2, this option controls the exposure of the list of
209c7a8
+successful authentication methods to PAM during the authentication
209c7a8
+and to the shell environment via the
209c7a8
+.Cm SSH_USER_AUTH
209c7a8
+variable. See the description of this variable for more details.
209c7a8
+Valid options are:
6cf9b8e
+.Cm never
209c7a8
+(Do not expose successful authentication methods),
6cf9b8e
+.Cm pam-only
209c7a8
+(Only expose them to PAM during authentication, not afterwards),
6cf9b8e
+.Cm pam-and-env
209c7a8
+(Expose them to PAM and keep them in the shell environment).
209c7a8
+The default is
6cf9b8e
+.Cm never .
209c7a8
 .It Cm FingerprintHash
209c7a8
 Specifies the hash algorithm used when logging key fingerprints.
209c7a8
 Valid options are:
6cf9b8e
diff -up openssh-7.4p1/ssh-gss.h.expose-pam openssh-7.4p1/ssh-gss.h
6cf9b8e
--- openssh-7.4p1/ssh-gss.h.expose-pam	2016-12-23 15:40:26.811447875 +0100
6cf9b8e
+++ openssh-7.4p1/ssh-gss.h	2016-12-23 15:40:26.823447877 +0100
209c7a8
@@ -159,6 +159,7 @@ int ssh_gssapi_server_check_mech(Gssctxt
209c7a8
     const char *);
209c7a8
 OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
209c7a8
 int ssh_gssapi_userok(char *name, struct passwd *);
209c7a8
+char* ssh_gssapi_get_displayname(void);
209c7a8
 OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
209c7a8
 void ssh_gssapi_do_child(char ***, u_int *);
209c7a8
 void ssh_gssapi_cleanup_creds(void);
6cf9b8e
diff -up openssh-7.4p1/sshkey.c.expose-pam openssh-7.4p1/sshkey.c
6cf9b8e
--- openssh-7.4p1/sshkey.c.expose-pam	2016-12-23 15:40:26.777447869 +0100
6cf9b8e
+++ openssh-7.4p1/sshkey.c	2016-12-23 15:40:26.823447877 +0100
6cf9b8e
@@ -57,6 +57,7 @@
209c7a8
 #define SSHKEY_INTERNAL
209c7a8
 #include "sshkey.h"
209c7a8
 #include "match.h"
209c7a8
+#include "xmalloc.h"
209c7a8
 
209c7a8
 /* openssh private key file format */
209c7a8
 #define MARK_BEGIN		"-----BEGIN OPENSSH PRIVATE KEY-----\n"
6cf9b8e
@@ -1191,6 +1192,30 @@ sshkey_fingerprint(const struct sshkey *
209c7a8
 	return retval;
209c7a8
 }
209c7a8
 
209c7a8
+char *
209c7a8
+sshkey_format_oneline(const struct sshkey *key, int dgst_alg)
209c7a8
+{
209c7a8
+	char *fp, *result;
209c7a8
+
209c7a8
+	if (sshkey_is_cert(key)) {
209c7a8
+		fp = sshkey_fingerprint(key->cert->signature_key, dgst_alg,
209c7a8
+		    SSH_FP_DEFAULT);
209c7a8
+		xasprintf(&result, "%s ID %s (serial %llu) CA %s %s",
209c7a8
+		    sshkey_type(key), key->cert->key_id,
209c7a8
+		    (unsigned long long)key->cert->serial,
209c7a8
+		    sshkey_type(key->cert->signature_key),
209c7a8
+		    fp == NULL ? "(null)" : fp);
209c7a8
+		free(fp);
209c7a8
+	} else {
209c7a8
+		fp = sshkey_fingerprint(key, dgst_alg, SSH_FP_DEFAULT);
209c7a8
+		xasprintf(&result, "%s %s", sshkey_type(key),
209c7a8
+		    fp == NULL ? "(null)" : fp);
209c7a8
+		free(fp);
209c7a8
+	}
209c7a8
+
209c7a8
+	return result;
209c7a8
+}
209c7a8
+
209c7a8
 #ifdef WITH_SSH1
209c7a8
 /*
209c7a8
  * Reads a multiple-precision integer in decimal from the buffer, and advances
6cf9b8e
diff -up openssh-7.4p1/sshkey.h.expose-pam openssh-7.4p1/sshkey.h
6cf9b8e
--- openssh-7.4p1/sshkey.h.expose-pam	2016-12-23 15:40:26.777447869 +0100
6cf9b8e
+++ openssh-7.4p1/sshkey.h	2016-12-23 15:40:26.823447877 +0100
209c7a8
@@ -124,6 +124,7 @@ char		*sshkey_fingerprint(const struct s
209c7a8
     int, enum sshkey_fp_rep);
209c7a8
 int		 sshkey_fingerprint_raw(const struct sshkey *k,
209c7a8
     int, u_char **retp, size_t *lenp);
209c7a8
+char		*sshkey_format_oneline(const struct sshkey *k, int dgst_alg);
209c7a8
 const char	*sshkey_type(const struct sshkey *);
209c7a8
 const char	*sshkey_cert_type(const struct sshkey *);
209c7a8
 int		 sshkey_write(const struct sshkey *, FILE *);