[openssh-commits] [openssh] 08/12: upstream commit

git+noreply at mindrot.org git+noreply at mindrot.org
Sat Jun 24 17:50:05 AEST 2017


This is an automated email from the git hooks/post-receive script.

djm pushed a commit to branch master
in repository openssh.

commit 8f574959272ac7fe9239c4f5d10fd913f8920ab0
Author: djm at openbsd.org <djm at openbsd.org>
Date:   Sat Jun 24 06:34:38 2017 +0000

    upstream commit
    
    refactor authentication logging
    
    optionally record successful auth methods and public credentials
    used in a file accessible to user sessions
    
    feedback and ok markus@
    
    Upstream-ID: 090b93036967015717b9a54fd0467875ae9d32fb
---
 auth.c            |  62 +++++++++++++++++--------
 auth.h            |  52 ++++++++++++++-------
 auth2-gss.c       |  12 ++++-
 auth2-hostbased.c |   8 ++--
 auth2-pubkey.c    |  80 ++------------------------------
 auth2.c           | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 gss-serv.c        |  11 ++++-
 monitor.c         |  41 +++++++++--------
 servconf.c        |  13 +++++-
 servconf.h        |   3 +-
 session.c         |  54 +++++++++++++++++++++-
 ssh-gss.h         |   3 +-
 sshd_config.5     |  10 +++-
 13 files changed, 340 insertions(+), 142 deletions(-)

diff --git a/auth.c b/auth.c
index fd821150..96116ecf 100644
--- a/auth.c
+++ b/auth.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.c,v 1.121 2017/05/30 08:52:19 markus Exp $ */
+/* $OpenBSD: auth.c,v 1.122 2017/06/24 06:34:38 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -267,21 +267,41 @@ allowed_user(struct passwd * pw)
 	return 1;
 }
 
-void
-auth_info(Authctxt *authctxt, const char *fmt, ...)
+/*
+ * Formats any key left in authctxt->auth_method_key for inclusion in
+ * auth_log()'s message. Also includes authxtct->auth_method_info if present.
+ */
+static char *
+format_method_key(Authctxt *authctxt)
 {
-	va_list ap;
-        int i;
+	const struct sshkey *key = authctxt->auth_method_key;
+	const char *methinfo = authctxt->auth_method_info;
+	char *fp, *ret = NULL;
 
-	free(authctxt->info);
-	authctxt->info = NULL;
+	if (key == NULL)
+		return NULL;
 
-	va_start(ap, fmt);
-	i = vasprintf(&authctxt->info, fmt, ap);
-	va_end(ap);
-
-	if (i < 0 || authctxt->info == NULL)
-		fatal("vasprintf failed");
+	if (key_is_cert(key)) {
+		fp = sshkey_fingerprint(key->cert->signature_key,
+		    options.fingerprint_hash, SSH_FP_DEFAULT);
+		xasprintf(&ret, "%s ID %s (serial %llu) CA %s %s%s%s",
+		    sshkey_type(key), key->cert->key_id,
+		    (unsigned long long)key->cert->serial,
+		    sshkey_type(key->cert->signature_key),
+		    fp == NULL ? "(null)" : fp,
+		    methinfo == NULL ? "" : ", ",
+		    methinfo == NULL ? "" : methinfo);
+		free(fp);
+	} else {
+		fp = sshkey_fingerprint(key, options.fingerprint_hash,
+		    SSH_FP_DEFAULT);
+		xasprintf(&ret, "%s %s%s%s", sshkey_type(key),
+		    fp == NULL ? "(null)" : fp,
+		    methinfo == NULL ? "" : ", ",
+		    methinfo == NULL ? "" : methinfo);
+		free(fp);
+	}
+	return ret;
 }
 
 void
@@ -290,7 +310,8 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
 {
 	struct ssh *ssh = active_state; /* XXX */
 	void (*authlog) (const char *fmt,...) = verbose;
-	char *authmsg;
+	const char *authmsg;
+	char *extra = NULL;
 
 	if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
 		return;
@@ -309,6 +330,11 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
 	else
 		authmsg = authenticated ? "Accepted" : "Failed";
 
+	if ((extra = format_method_key(authctxt)) == NULL) {
+		if (authctxt->auth_method_info != NULL)
+			extra = xstrdup(authctxt->auth_method_info);
+	}
+
 	authlog("%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s",
 	    authmsg,
 	    method,
@@ -317,10 +343,10 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
 	    authctxt->user,
 	    ssh_remote_ipaddr(ssh),
 	    ssh_remote_port(ssh),
-	    authctxt->info != NULL ? ": " : "",
-	    authctxt->info != NULL ? authctxt->info : "");
-	free(authctxt->info);
-	authctxt->info = NULL;
+	    extra != NULL ? ": " : "",
+	    extra != NULL ? extra : "");
+
+	free(extra);
 
 #ifdef CUSTOM_FAILED_LOGIN
 	if (authenticated == 0 && !authctxt->postponed &&
diff --git a/auth.h b/auth.h
index 67793546..cbbc9623 100644
--- a/auth.h
+++ b/auth.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.h,v 1.91 2017/05/30 14:29:59 markus Exp $ */
+/* $OpenBSD: auth.h,v 1.92 2017/06/24 06:34:38 djm Exp $ */
 
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
@@ -44,6 +44,7 @@
 
 struct ssh;
 struct sshkey;
+struct sshbuf;
 
 typedef struct Authctxt Authctxt;
 typedef struct Authmethod Authmethod;
@@ -62,13 +63,17 @@ struct Authctxt {
 	char		*service;
 	struct passwd	*pw;		/* set if 'valid' */
 	char		*style;
-	void		*kbdintctxt;
-	char		*info;		/* Extra info for next auth_log */
-#ifdef BSD_AUTH
-	auth_session_t	*as;
-#endif
+
+	/* Method lists for multiple authentication */
 	char		**auth_methods;	/* modified from server config */
 	u_int		 num_auth_methods;
+
+	/* Authentication method-specific data */
+	void		*methoddata;
+	void		*kbdintctxt;
+#ifdef BSD_AUTH
+	auth_session_t	*as;
+#endif
 #ifdef KRB5
 	krb5_context	 krb5_ctx;
 	krb5_ccache	 krb5_fwd_ccache;
@@ -76,12 +81,20 @@ struct Authctxt {
 	char		*krb5_ticket_file;
 	char		*krb5_ccname;
 #endif
-	Buffer		*loginmsg;
-	void		*methoddata;
+	struct sshbuf	*loginmsg;
 
-	struct sshkey	**prev_userkeys;
-	u_int		 nprev_userkeys;
+	/* Authentication keys already used; these will be refused henceforth */
+	struct sshkey	**prev_keys;
+	u_int		 nprev_keys;
+
+	/* Last used key and ancilliary information from active auth method */
+	struct sshkey	*auth_method_key;
+	char		*auth_method_info;
+
+	/* Information exposed to session */
+	struct sshbuf	*session_info;	/* Auth info for environment */
 };
+
 /*
  * Every authentication method has to handle authentication requests for
  * non-existing users, or for users that are not allowed to login. In this
@@ -120,10 +133,18 @@ int      auth_password(Authctxt *, const char *);
 int	 hostbased_key_allowed(struct passwd *, const char *, char *,
 	    struct sshkey *);
 int	 user_key_allowed(struct passwd *, struct sshkey *, int);
-void	 pubkey_auth_info(Authctxt *, const struct sshkey *, const char *, ...)
-	    __attribute__((__format__ (printf, 3, 4)));
-void	 auth2_record_userkey(Authctxt *, struct sshkey *);
-int	 auth2_userkey_already_used(Authctxt *, struct sshkey *);
+int	 auth2_key_already_used(Authctxt *, const struct sshkey *);
+
+/*
+ * Handling auth method-specific information for logging and prevention
+ * of key reuse during multiple authentication.
+ */
+void	 auth2_authctxt_reset_info(Authctxt *);
+void	 auth2_record_key(Authctxt *, int, const struct sshkey *);
+void	 auth2_record_info(Authctxt *authctxt, const char *, ...)
+	    __attribute__((__format__ (printf, 2, 3)))
+	    __attribute__((__nonnull__ (2)));
+void	 auth2_update_session_info(Authctxt *, const char *, const char *);
 
 struct stat;
 int	 auth_secure_path(const char *, struct stat *, const char *, uid_t,
@@ -150,9 +171,6 @@ void disable_forwarding(void);
 
 void	do_authentication2(Authctxt *);
 
-void	auth_info(Authctxt *authctxt, const char *, ...)
-	    __attribute__((__format__ (printf, 2, 3)))
-	    __attribute__((__nonnull__ (2)));
 void	auth_log(Authctxt *, int, int, const char *, const char *);
 void	auth_maxtries_exceeded(Authctxt *) __attribute__((noreturn));
 void	userauth_finish(struct ssh *, int, const char *, const char *);
diff --git a/auth2-gss.c b/auth2-gss.c
index 680d5e71..589283b7 100644
--- a/auth2-gss.c
+++ b/auth2-gss.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-gss.c,v 1.25 2017/05/30 14:29:59 markus Exp $ */
+/* $OpenBSD: auth2-gss.c,v 1.26 2017/06/24 06:34:38 djm Exp $ */
 
 /*
  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
@@ -228,6 +228,7 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh)
 {
 	Authctxt *authctxt = ssh->authctxt;
 	int authenticated;
+	const char *displayname;
 
 	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
 		fatal("No authentication or GSSAPI context");
@@ -241,6 +242,10 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh)
 
 	authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
 
+	if ((!use_privsep || mm_is_monitor()) &&
+	    (displayname = ssh_gssapi_displayname()) != NULL)
+		auth2_record_info(authctxt, "%s", displayname);
+
 	authctxt->postponed = 0;
 	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
 	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
@@ -259,6 +264,7 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh)
 	Buffer b;
 	gss_buffer_desc mic, gssbuf;
 	u_int len;
+	const char *displayname;
 
 	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
 		fatal("No authentication or GSSAPI context");
@@ -282,6 +288,10 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh)
 	buffer_free(&b);
 	free(mic.value);
 
+	if ((!use_privsep || mm_is_monitor()) &&
+	    (displayname = ssh_gssapi_displayname()) != NULL)
+		auth2_record_info(authctxt, "%s", displayname);
+
 	authctxt->postponed = 0;
 	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
 	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
diff --git a/auth2-hostbased.c b/auth2-hostbased.c
index 63fe9ae6..92758b38 100644
--- a/auth2-hostbased.c
+++ b/auth2-hostbased.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-hostbased.c,v 1.30 2017/05/30 14:29:59 markus Exp $ */
+/* $OpenBSD: auth2-hostbased.c,v 1.31 2017/06/24 06:34:38 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -137,7 +137,7 @@ userauth_hostbased(struct ssh *ssh)
 	sshbuf_dump(b, stderr);
 #endif
 
-	pubkey_auth_info(authctxt, key,
+	auth2_record_info(authctxt,
 	    "client user \"%.100s\", client host \"%.100s\"", cuser, chost);
 
 	/* test for allowed key and correct signature */
@@ -147,11 +147,11 @@ userauth_hostbased(struct ssh *ssh)
 	    sshbuf_ptr(b), sshbuf_len(b), ssh->compat)) == 0)
 		authenticated = 1;
 
+	auth2_record_key(authctxt, authenticated, key);
 	sshbuf_free(b);
 done:
 	debug2("%s: authenticated %d", __func__, authenticated);
-	if (key != NULL)
-		sshkey_free(key);
+	sshkey_free(key);
 	free(pkalg);
 	free(pkblob);
 	free(cuser);
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index 5794f1f4..1c59b5bb 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-pubkey.c,v 1.67 2017/05/31 10:54:00 markus Exp $ */
+/* $OpenBSD: auth2-pubkey.c,v 1.68 2017/06/24 06:34:38 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -137,7 +137,7 @@ userauth_pubkey(struct ssh *ssh)
 		goto done;
 	}
 	fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT);
-	if (auth2_userkey_already_used(authctxt, key)) {
+	if (auth2_key_already_used(authctxt, key)) {
 		logit("refusing previously-used %s key", sshkey_type(key));
 		goto done;
 	}
@@ -194,7 +194,6 @@ userauth_pubkey(struct ssh *ssh)
 #ifdef DEBUG_PK
 		sshbuf_dump(b, stderr);
 #endif
-		pubkey_auth_info(authctxt, key, NULL);
 
 		/* test for correct signature */
 		authenticated = 0;
@@ -202,12 +201,10 @@ userauth_pubkey(struct ssh *ssh)
 		    PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b),
 		    sshbuf_len(b), ssh->compat)) == 0) {
 			authenticated = 1;
-			/* Record the successful key to prevent reuse */
-			auth2_record_userkey(authctxt, key);
-			key = NULL; /* Don't free below */
 		}
 		sshbuf_free(b);
 		free(sig);
+		auth2_record_key(authctxt, authenticated, key);
 	} else {
 		debug("%s: test whether pkalg/pkblob are acceptable for %s %s",
 		    __func__, sshkey_type(key), fp);
@@ -237,8 +234,7 @@ userauth_pubkey(struct ssh *ssh)
 		auth_clear_options();
 done:
 	debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg);
-	if (key != NULL)
-		sshkey_free(key);
+	sshkey_free(key);
 	free(userstyle);
 	free(pkalg);
 	free(pkblob);
@@ -246,44 +242,6 @@ done:
 	return authenticated;
 }
 
-void
-pubkey_auth_info(Authctxt *authctxt, const struct sshkey *key,
-    const char *fmt, ...)
-{
-	char *fp, *extra;
-	va_list ap;
-	int i;
-
-	extra = NULL;
-	if (fmt != NULL) {
-		va_start(ap, fmt);
-		i = vasprintf(&extra, fmt, ap);
-		va_end(ap);
-		if (i < 0 || extra == NULL)
-			fatal("%s: vasprintf failed", __func__);
-	}
-
-	if (sshkey_is_cert(key)) {
-		fp = sshkey_fingerprint(key->cert->signature_key,
-		    options.fingerprint_hash, SSH_FP_DEFAULT);
-		auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s", 
-		    sshkey_type(key), key->cert->key_id,
-		    (unsigned long long)key->cert->serial,
-		    sshkey_type(key->cert->signature_key),
-		    fp == NULL ? "(null)" : fp,
-		    extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
-		free(fp);
-	} else {
-		fp = sshkey_fingerprint(key, options.fingerprint_hash,
-		    SSH_FP_DEFAULT);
-		auth_info(authctxt, "%s %s%s%s", sshkey_type(key),
-		    fp == NULL ? "(null)" : fp,
-		    extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
-		free(fp);
-	}
-	free(extra);
-}
-
 /*
  * Splits 's' into an argument vector. Handles quoted string and basic
  * escape characters (\\, \", \'). Caller must free the argument vector
@@ -1148,36 +1106,6 @@ user_key_allowed(struct passwd *pw, struct sshkey *key, int auth_attempt)
 	return success;
 }
 
-/* Records a public key in the list of previously-successful keys */
-void
-auth2_record_userkey(Authctxt *authctxt, struct sshkey *key)
-{
-	struct sshkey **tmp;
-
-	if (authctxt->nprev_userkeys >= INT_MAX ||
-	    (tmp = recallocarray(authctxt->prev_userkeys,
-	    authctxt->nprev_userkeys, authctxt->nprev_userkeys + 1,
-	    sizeof(*tmp))) == NULL)
-		fatal("%s: recallocarray failed", __func__);
-	authctxt->prev_userkeys = tmp;
-	authctxt->prev_userkeys[authctxt->nprev_userkeys] = key;
-	authctxt->nprev_userkeys++;
-}
-
-/* Checks whether a key has already been used successfully for authentication */
-int
-auth2_userkey_already_used(Authctxt *authctxt, struct sshkey *key)
-{
-	u_int i;
-
-	for (i = 0; i < authctxt->nprev_userkeys; i++) {
-		if (sshkey_equal_public(key, authctxt->prev_userkeys[i])) {
-			return 1;
-		}
-	}
-	return 0;
-}
-
 Authmethod method_pubkey = {
 	"publickey",
 	userauth_pubkey,
diff --git a/auth2.c b/auth2.c
index cb4c2fd5..862e0996 100644
--- a/auth2.c
+++ b/auth2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2.c,v 1.142 2017/05/31 07:00:13 markus Exp $ */
+/* $OpenBSD: auth2.c,v 1.143 2017/06/24 06:34:38 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -30,6 +30,7 @@
 #include <sys/uio.h>
 
 #include <fcntl.h>
+#include <limits.h>
 #include <pwd.h>
 #include <stdarg.h>
 #include <string.h>
@@ -55,6 +56,7 @@
 #include "ssh-gss.h"
 #endif
 #include "monitor_wrap.h"
+#include "ssherr.h"
 
 /* import */
 extern ServerOptions options;
@@ -277,6 +279,7 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
 	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
 #endif
 
+	auth2_authctxt_reset_info(authctxt);
 	authctxt->postponed = 0;
 	authctxt->server_caused_failure = 0;
 
@@ -327,6 +330,10 @@ userauth_finish(struct ssh *ssh, int authenticated, const char *method,
 	/* Log before sending the reply */
 	auth_log(authctxt, authenticated, partial, method, submethod);
 
+	/* Update information exposed to session */
+	if (authenticated || partial)
+		auth2_update_session_info(authctxt, method, submethod);
+
 	if (authctxt->postponed)
 		return;
 
@@ -624,4 +631,128 @@ auth2_update_methods_lists(Authctxt *authctxt, const char *method,
 	return 0;
 }
 
+/* Reset method-specific information */
+void auth2_authctxt_reset_info(Authctxt *authctxt)
+{
+	sshkey_free(authctxt->auth_method_key);
+	free(authctxt->auth_method_info);
+	authctxt->auth_method_key = NULL;
+	authctxt->auth_method_info = NULL;
+}
+
+/* Record auth method-specific information for logs */
+void
+auth2_record_info(Authctxt *authctxt, const char *fmt, ...)
+{
+	va_list ap;
+        int i;
+
+	free(authctxt->auth_method_info);
+	authctxt->auth_method_info = NULL;
+
+	va_start(ap, fmt);
+	i = vasprintf(&authctxt->auth_method_info, fmt, ap);
+	va_end(ap);
+
+	if (i < 0 || authctxt->auth_method_info == NULL)
+		fatal("%s: vasprintf failed", __func__);
+}
+
+/*
+ * Records a public key used in authentication. This is used for logging
+ * and to ensure that the same key is not subsequently accepted again for
+ * multiple authentication.
+ */
+void
+auth2_record_key(Authctxt *authctxt, int authenticated,
+    const struct sshkey *key)
+{
+	struct sshkey **tmp, *dup;
+	int r;
+
+	if ((r = sshkey_demote(key, &dup)) != 0)
+		fatal("%s: copy key: %s", __func__, ssh_err(r));
+	sshkey_free(authctxt->auth_method_key);
+	authctxt->auth_method_key = dup;
+
+	if (!authenticated)
+		return;
+
+	/* If authenticated, make sure we don't accept this key again */
+	if ((r = sshkey_demote(key, &dup)) != 0)
+		fatal("%s: copy key: %s", __func__, ssh_err(r));
+	if (authctxt->nprev_keys >= INT_MAX ||
+	    (tmp = recallocarray(authctxt->prev_keys, authctxt->nprev_keys,
+	    authctxt->nprev_keys + 1, sizeof(*authctxt->prev_keys))) == NULL)
+		fatal("%s: reallocarray failed", __func__);
+	authctxt->prev_keys = tmp;
+	authctxt->prev_keys[authctxt->nprev_keys] = dup;
+	authctxt->nprev_keys++;
+
+}
+
+/* Checks whether a key has already been previously used for authentication */
+int
+auth2_key_already_used(Authctxt *authctxt, const struct sshkey *key)
+{
+	u_int i;
+	char *fp;
+
+	for (i = 0; i < authctxt->nprev_keys; i++) {
+		if (sshkey_equal_public(key, authctxt->prev_keys[i])) {
+			fp = sshkey_fingerprint(authctxt->prev_keys[i],
+			    options.fingerprint_hash, SSH_FP_DEFAULT);
+			debug3("%s: key already used: %s %s", __func__,
+			    sshkey_type(authctxt->prev_keys[i]),
+			    fp == NULL ? "UNKNOWN" : fp);
+			free(fp);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Updates authctxt->session_info with details of authentication. Should be
+ * whenever an authentication method succeeds.
+ */
+void
+auth2_update_session_info(Authctxt *authctxt, const char *method,
+    const char *submethod)
+{
+	int r;
+
+	if (authctxt->session_info == NULL) {
+		if ((authctxt->session_info = sshbuf_new()) == NULL)
+			fatal("%s: sshbuf_new", __func__);
+	}
+
+	/* Append method[/submethod] */
+	if ((r = sshbuf_putf(authctxt->session_info, "%s%s%s",
+	    method, submethod == NULL ? "" : "/",
+	    submethod == NULL ? "" : submethod)) != 0)
+		fatal("%s: append method: %s", __func__, ssh_err(r));
+
+	/* Append key if present */
+	if (authctxt->auth_method_key != NULL) {
+		if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 ||
+		    (r = sshkey_format_text(authctxt->auth_method_key,
+		    authctxt->session_info)) != 0)
+			fatal("%s: append key: %s", __func__, ssh_err(r));
+	}
+
+	if (authctxt->auth_method_info != NULL) {
+		/* Ensure no ambiguity here */
+		if (strchr(authctxt->auth_method_info, '\n') != NULL)
+			fatal("%s: auth_method_info contains \\n", __func__);
+		if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 ||
+		    (r = sshbuf_putf(authctxt->session_info, "%s",
+		    authctxt->auth_method_info)) != 0) {
+			fatal("%s: append method info: %s",
+			    __func__, ssh_err(r));
+		}
+	}
+	if ((r = sshbuf_put_u8(authctxt->session_info, '\n')) != 0)
+		fatal("%s: append: %s", __func__, ssh_err(r));
+}
 
diff --git a/gss-serv.c b/gss-serv.c
index 53993d67..6cae720e 100644
--- a/gss-serv.c
+++ b/gss-serv.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: gss-serv.c,v 1.29 2015/05/22 03:50:02 djm Exp $ */
+/* $OpenBSD: gss-serv.c,v 1.30 2017/06/24 06:34:38 djm Exp $ */
 
 /*
  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
@@ -393,4 +393,13 @@ ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
 	return (ctx->major);
 }
 
+/* Privileged */
+const char *ssh_gssapi_displayname(void)
+{
+	if (gssapi_client.displayname.length == 0 ||
+	    gssapi_client.displayname.value == NULL)
+		return NULL;
+	return (char *)gssapi_client.displayname.value;
+}
+
 #endif
diff --git a/monitor.c b/monitor.c
index 8897f6a8..8a7897bd 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor.c,v 1.171 2017/05/31 10:04:29 markus Exp $ */
+/* $OpenBSD: monitor.c,v 1.172 2017/06/24 06:34:38 djm Exp $ */
 /*
  * Copyright 2002 Niels Provos <provos at citi.umich.edu>
  * Copyright 2002 Markus Friedl <markus at openbsd.org>
@@ -308,6 +308,8 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
 		partial = 0;
 		auth_method = "unknown";
 		auth_submethod = NULL;
+		auth2_authctxt_reset_info(authctxt);
+
 		authenticated = (monitor_read(pmonitor, mon_dispatch, &ent) == 1);
 
 		/* Special handling for multiple required authentications */
@@ -347,6 +349,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
 			    auth_method, auth_submethod);
 			if (!partial && !authenticated)
 				authctxt->failures++;
+			if (authenticated || partial) {
+				auth2_update_session_info(authctxt,
+				    auth_method, auth_submethod);
+			}
 		}
 	}
 
@@ -1147,12 +1153,11 @@ mm_answer_keyallowed(int sock, Buffer *m)
 		switch (type) {
 		case MM_USERKEY:
 			allowed = options.pubkey_authentication &&
-			    !auth2_userkey_already_used(authctxt, key) &&
+			    !auth2_key_already_used(authctxt, key) &&
 			    match_pattern_list(sshkey_ssh_name(key),
 			    options.pubkey_key_types, 0) == 1 &&
 			    user_key_allowed(authctxt->pw, key,
 			    pubkey_auth_attempt);
-			pubkey_auth_info(authctxt, key, NULL);
 			auth_method = "publickey";
 			if (options.pubkey_authentication &&
 			    (!pubkey_auth_attempt || allowed != 1))
@@ -1160,11 +1165,12 @@ mm_answer_keyallowed(int sock, Buffer *m)
 			break;
 		case MM_HOSTKEY:
 			allowed = options.hostbased_authentication &&
+			    !auth2_key_already_used(authctxt, key) &&
 			    match_pattern_list(sshkey_ssh_name(key),
 			    options.hostbased_key_types, 0) == 1 &&
 			    hostbased_key_allowed(authctxt->pw,
 			    cuser, chost, key);
-			pubkey_auth_info(authctxt, key,
+			auth2_record_info(authctxt,
 			    "client user \"%.100s\", client host \"%.100s\"",
 			    cuser, chost);
 			auth_method = "hostbased";
@@ -1175,11 +1181,10 @@ mm_answer_keyallowed(int sock, Buffer *m)
 		}
 	}
 
-	debug3("%s: key %p is %s",
-	    __func__, key, allowed ? "allowed" : "not allowed");
+	debug3("%s: key is %s", __func__, allowed ? "allowed" : "not allowed");
 
-	if (key != NULL)
-		key_free(key);
+	auth2_record_key(authctxt, 0, key);
+	sshkey_free(key);
 
 	/* clear temporarily storage (used by verify) */
 	monitor_reset_key_state();
@@ -1353,10 +1358,12 @@ mm_answer_keyverify(int sock, struct sshbuf *m)
 	switch (key_blobtype) {
 	case MM_USERKEY:
 		valid_data = monitor_valid_userblob(data, datalen);
+		auth_method = "publickey";
 		break;
 	case MM_HOSTKEY:
 		valid_data = monitor_valid_hostbasedblob(data, datalen,
 		    hostbased_cuser, hostbased_chost);
+		auth_method = "hostbased";
 		break;
 	default:
 		valid_data = 0;
@@ -1367,23 +1374,17 @@ mm_answer_keyverify(int sock, struct sshbuf *m)
 
 	ret = sshkey_verify(key, signature, signaturelen, data, datalen,
 	    active_state->compat);
-	debug3("%s: key %p signature %s",
-	    __func__, key, (ret == 0) ? "verified" : "unverified");
-
-	/* If auth was successful then record key to ensure it isn't reused */
-	if (ret == 0 && key_blobtype == MM_USERKEY)
-		auth2_record_userkey(authctxt, key);
-	else
-		sshkey_free(key);
+	debug3("%s: %s %p signature %s", __func__, auth_method, key,
+	    (ret == 0) ? "verified" : "unverified");
+	auth2_record_key(authctxt, ret == 0, key);
 
 	free(blob);
 	free(signature);
 	free(data);
 
-	auth_method = key_blobtype == MM_USERKEY ? "publickey" : "hostbased";
-
 	monitor_reset_key_state();
 
+	sshkey_free(key);
 	sshbuf_reset(m);
 
 	/* encode ret != 0 as positive integer, since we're sending u32 */
@@ -1799,6 +1800,7 @@ int
 mm_answer_gss_userok(int sock, Buffer *m)
 {
 	int authenticated;
+	const char *displayname;
 
 	if (!options.gss_authentication)
 		fatal("%s: GSSAPI authentication not enabled", __func__);
@@ -1813,6 +1815,9 @@ mm_answer_gss_userok(int sock, Buffer *m)
 
 	auth_method = "gssapi-with-mic";
 
+	if ((displayname = ssh_gssapi_displayname()) != NULL)
+		auth2_record_info(authctxt, "%s", displayname);
+
 	/* Monitor loop will terminate if authenticated */
 	return (authenticated);
 }
diff --git a/servconf.c b/servconf.c
index a112798e..ed1fc71c 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,5 +1,5 @@
 
-/* $OpenBSD: servconf.c,v 1.308 2017/05/17 01:24:17 djm Exp $ */
+/* $OpenBSD: servconf.c,v 1.309 2017/06/24 06:34:38 djm Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -164,6 +164,7 @@ initialize_server_options(ServerOptions *options)
 	options->version_addendum = NULL;
 	options->fingerprint_hash = -1;
 	options->disable_forwarding = -1;
+	options->expose_userauth_info = -1;
 }
 
 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
@@ -333,6 +334,8 @@ fill_default_server_options(ServerOptions *options)
 		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
 	if (options->disable_forwarding == -1)
 		options->disable_forwarding = 0;
+	if (options->expose_userauth_info == -1)
+		options->expose_userauth_info = 0;
 
 	assemble_algorithms(options);
 
@@ -418,6 +421,7 @@ typedef enum {
 	sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
 	sStreamLocalBindMask, sStreamLocalBindUnlink,
 	sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
+	sExposeAuthInfo,
 	sDeprecated, sIgnore, sUnsupported
 } ServerOpCodes;
 
@@ -561,6 +565,7 @@ static struct {
 	{ "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
 	{ "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
 	{ "disableforwarding", sDisableForwarding, SSHCFG_ALL },
+	{ "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL },
 	{ NULL, sBadOption, 0 }
 };
 
@@ -1835,6 +1840,10 @@ process_server_config_line(ServerOptions *options, char *line,
 			options->fingerprint_hash = value;
 		break;
 
+	case sExposeAuthInfo:
+		intptr = &options->expose_userauth_info;
+		goto parse_flag;
+
 	case sDeprecated:
 	case sIgnore:
 	case sUnsupported:
@@ -1973,6 +1982,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
 	M_CP_INTOPT(allow_streamlocal_forwarding);
 	M_CP_INTOPT(allow_agent_forwarding);
 	M_CP_INTOPT(disable_forwarding);
+	M_CP_INTOPT(expose_userauth_info);
 	M_CP_INTOPT(permit_tun);
 	M_CP_INTOPT(fwd_opts.gateway_ports);
 	M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink);
@@ -2272,6 +2282,7 @@ dump_config(ServerOptions *o)
 	dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
 	dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
 	dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
+	dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info);
 
 	/* string arguments */
 	dump_cfg_string(sPidFile, o->pid_file);
diff --git a/servconf.h b/servconf.h
index 5853a974..c2848a76 100644
--- a/servconf.h
+++ b/servconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: servconf.h,v 1.123 2016/11/30 03:00:05 djm Exp $ */
+/* $OpenBSD: servconf.h,v 1.124 2017/06/24 06:34:38 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
@@ -189,6 +189,7 @@ typedef struct {
 	char   *auth_methods[MAX_AUTH_METHODS];
 
 	int	fingerprint_hash;
+	int	expose_userauth_info;
 }       ServerOptions;
 
 /* Information about the incoming connection as used by Match */
diff --git a/session.c b/session.c
index 295204c6..a2588e74 100644
--- a/session.c
+++ b/session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.289 2017/06/24 05:24:11 djm Exp $ */
+/* $OpenBSD: session.c,v 1.290 2017/06/24 06:34:38 djm Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -94,6 +94,7 @@
 #include "kex.h"
 #include "monitor_wrap.h"
 #include "sftp.h"
+#include "atomicio.h"
 
 #if defined(KRB5) && defined(USE_AFS)
 #include <kafs.h>
@@ -160,6 +161,9 @@ login_cap_t *lc;
 static int is_child = 0;
 static int in_chroot = 0;
 
+/* File containing userauth info, if ExposeAuthInfo set */
+static char *auth_info_file = NULL;
+
 /* Name and directory of socket for authentication agent forwarding. */
 static char *auth_sock_name = NULL;
 static char *auth_sock_dir = NULL;
@@ -249,6 +253,40 @@ display_loginmsg(void)
 	}
 }
 
+static void
+prepare_auth_info_file(struct passwd *pw, struct sshbuf *info)
+{
+	int fd = -1, success = 0;
+
+	if (!options.expose_userauth_info || info == NULL)
+		return;
+
+	temporarily_use_uid(pw);
+	auth_info_file = xstrdup("/tmp/sshauth.XXXXXXXXXXXXXXX");
+	if ((fd = mkstemp(auth_info_file)) == -1) {
+		error("%s: mkstemp: %s", __func__, strerror(errno));
+		goto out;
+	}
+	if (atomicio(vwrite, fd, sshbuf_mutable_ptr(info),
+	    sshbuf_len(info)) != sshbuf_len(info)) {
+		error("%s: write: %s", __func__, strerror(errno));
+		goto out;
+	}
+	if (close(fd) != 0) {
+		error("%s: close: %s", __func__, strerror(errno));
+		goto out;
+	}
+	success = 1;
+ out:
+	if (!success) {
+		if (fd != -1)
+			close(fd);
+		free(auth_info_file);
+		auth_info_file = NULL;
+	}
+	restore_uid();
+}
+
 void
 do_authenticated(Authctxt *authctxt)
 {
@@ -264,7 +302,10 @@ do_authenticated(Authctxt *authctxt)
 
 	auth_debug_send();
 
+	prepare_auth_info_file(authctxt->pw, authctxt->session_info);
+
 	do_authenticated2(authctxt);
+
 	do_cleanup(authctxt);
 }
 
@@ -1077,6 +1118,8 @@ do_setup_env(Session *s, const char *shell)
 	free(laddr);
 	child_set_env(&env, &envsize, "SSH_CONNECTION", buf);
 
+	if (auth_info_file != NULL)
+		child_set_env(&env, &envsize, "SSH_USER_AUTH", auth_info_file);
 	if (s->ttyfd != -1)
 		child_set_env(&env, &envsize, "SSH_TTY", s->tty);
 	if (s->term)
@@ -2549,6 +2592,15 @@ do_cleanup(Authctxt *authctxt)
 	/* remove agent socket */
 	auth_sock_cleanup_proc(authctxt->pw);
 
+	/* remove userauth info */
+	if (auth_info_file != NULL) {
+		temporarily_use_uid(authctxt->pw);
+		unlink(auth_info_file);
+		restore_uid();
+		free(auth_info_file);
+		auth_info_file = NULL;
+	}
+
 	/*
 	 * Cleanup ptys/utmp only if privsep is disabled,
 	 * or if running in monitor.
diff --git a/ssh-gss.h b/ssh-gss.h
index a99d7f08..6593e422 100644
--- a/ssh-gss.h
+++ b/ssh-gss.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-gss.h,v 1.11 2014/02/26 20:28:44 djm Exp $ */
+/* $OpenBSD: ssh-gss.h,v 1.12 2017/06/24 06:34:38 djm Exp $ */
 /*
  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
  *
@@ -128,6 +128,7 @@ 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);
+const char *ssh_gssapi_displayname(void);
 
 #endif /* GSSAPI */
 
diff --git a/sshd_config.5 b/sshd_config.5
index 7b4cb1d9..cfe1db82 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -33,8 +33,8 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $OpenBSD: sshd_config.5,v 1.245 2017/05/17 01:24:17 djm Exp $
-.Dd $Mdocdate: May 17 2017 $
+.\" $OpenBSD: sshd_config.5,v 1.246 2017/06/24 06:34:38 djm Exp $
+.Dd $Mdocdate: June 24 2017 $
 .Dt SSHD_CONFIG 5
 .Os
 .Sh NAME
@@ -564,6 +564,12 @@ Disables all forwarding features, including X11,
 TCP and StreamLocal.
 This option overrides all other forwarding-related options and may
 simplify restricted configurations.
+.It Cm ExposeAuthInfo
+Enables writing a file containing a list of authentication methods and
+public credentials (e.g. keys) used to authenticate the user.
+The location of the file is exposed to the user session though the
+.Ev SSH_AUTH_INFO
+enviornment variable.
 .It Cm FingerprintHash
 Specifies the hash algorithm used when logging key fingerprints.
 Valid options are:

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list