summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorDamien Miller <djm@cvs.openbsd.org>2017-06-24 06:34:39 +0000
committerDamien Miller <djm@cvs.openbsd.org>2017-06-24 06:34:39 +0000
commit088cbd83831e88dbcf96ee9f711b7913792b095d (patch)
tree4618d4e69f58daa028a3327dbc8ca1390837cf19 /usr.bin
parent8dd4c06c2ed3fa9130d2fa5549be60acaf4b2cec (diff)
refactor authentication logging
optionally record successful auth methods and public credentials used in a file accessible to user sessions feedback and ok markus@
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/ssh/auth.c62
-rw-r--r--usr.bin/ssh/auth.h45
-rw-r--r--usr.bin/ssh/auth2-gss.c12
-rw-r--r--usr.bin/ssh/auth2-hostbased.c8
-rw-r--r--usr.bin/ssh/auth2-pubkey.c80
-rw-r--r--usr.bin/ssh/auth2.c133
-rw-r--r--usr.bin/ssh/gss-serv.c11
-rw-r--r--usr.bin/ssh/monitor.c41
-rw-r--r--usr.bin/ssh/servconf.c13
-rw-r--r--usr.bin/ssh/servconf.h3
-rw-r--r--usr.bin/ssh/session.c54
-rw-r--r--usr.bin/ssh/ssh-gss.h3
-rw-r--r--usr.bin/ssh/sshd_config.510
13 files changed, 336 insertions, 139 deletions
diff --git a/usr.bin/ssh/auth.c b/usr.bin/ssh/auth.c
index 8f0b8ed2c2c..ab433613b59 100644
--- a/usr.bin/ssh/auth.c
+++ b/usr.bin/ssh/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.
*
@@ -195,21 +195,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;
-
- free(authctxt->info);
- authctxt->info = NULL;
+ const struct sshkey *key = authctxt->auth_method_key;
+ const char *methinfo = authctxt->auth_method_info;
+ char *fp, *ret = NULL;
- va_start(ap, fmt);
- i = vasprintf(&authctxt->info, fmt, ap);
- va_end(ap);
+ if (key == NULL)
+ return NULL;
- 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
@@ -218,7 +238,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;
@@ -237,6 +258,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,
@@ -245,10 +271,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);
}
void
diff --git a/usr.bin/ssh/auth.h b/usr.bin/ssh/auth.h
index 1fea67ce3b6..96fd1a72ed2 100644
--- a/usr.bin/ssh/auth.h
+++ b/usr.bin/ssh/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.
@@ -57,22 +57,34 @@ struct Authctxt {
char *service;
struct passwd *pw; /* set if 'valid' */
char *style;
- void *kbdintctxt;
- char *info; /* Extra info for next auth_log */
- auth_session_t *as;
+
+ /* 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;
+ auth_session_t *as;
#ifdef KRB5
krb5_context krb5_ctx;
krb5_ccache krb5_fwd_ccache;
krb5_principal krb5_user;
char *krb5_ticket_file;
#endif
- void *methoddata;
- 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
@@ -111,10 +123,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,
@@ -129,9 +149,6 @@ void krb5_cleanup_proc(Authctxt *authctxt);
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/usr.bin/ssh/auth2-gss.c b/usr.bin/ssh/auth2-gss.c
index 18cfaf73700..c9c11a130c9 100644
--- a/usr.bin/ssh/auth2-gss.c
+++ b/usr.bin/ssh/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.
@@ -223,6 +223,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");
@@ -236,6 +237,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);
@@ -254,6 +259,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");
@@ -277,6 +283,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/usr.bin/ssh/auth2-hostbased.c b/usr.bin/ssh/auth2-hostbased.c
index e982d19e752..3ea8311524e 100644
--- a/usr.bin/ssh/auth2-hostbased.c
+++ b/usr.bin/ssh/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.
*
@@ -136,7 +136,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 */
@@ -146,11 +146,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/usr.bin/ssh/auth2-pubkey.c b/usr.bin/ssh/auth2-pubkey.c
index 67837293554..c79a2f2334d 100644
--- a/usr.bin/ssh/auth2-pubkey.c
+++ b/usr.bin/ssh/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.
*
@@ -134,7 +134,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;
}
@@ -191,7 +191,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;
@@ -199,12 +198,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);
@@ -234,8 +231,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);
@@ -243,44 +239,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
@@ -1145,36 +1103,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/usr.bin/ssh/auth2.c b/usr.bin/ssh/auth2.c
index f83131a4e7b..68aca4d5c90 100644
--- a/usr.bin/ssh/auth2.c
+++ b/usr.bin/ssh/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.
*
@@ -29,6 +29,7 @@
#include <sys/uio.h>
#include <fcntl.h>
+#include <limits.h>
#include <pwd.h>
#include <stdarg.h>
#include <string.h>
@@ -52,6 +53,7 @@
#include "ssh-gss.h"
#endif
#include "monitor_wrap.h"
+#include "ssherr.h"
/* import */
extern ServerOptions options;
@@ -257,6 +259,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;
@@ -303,6 +306,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;
@@ -573,4 +580,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/usr.bin/ssh/gss-serv.c b/usr.bin/ssh/gss-serv.c
index f26db425964..add350db382 100644
--- a/usr.bin/ssh/gss-serv.c
+++ b/usr.bin/ssh/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.
@@ -389,4 +389,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/usr.bin/ssh/monitor.c b/usr.bin/ssh/monitor.c
index ef5e9fc1276..08fb96de694 100644
--- a/usr.bin/ssh/monitor.c
+++ b/usr.bin/ssh/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@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -247,6 +247,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 */
@@ -274,6 +276,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);
+ }
}
}
@@ -856,12 +862,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))
@@ -869,11 +874,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";
@@ -884,11 +890,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();
@@ -1062,10 +1067,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;
@@ -1076,23 +1083,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 */
@@ -1459,6 +1460,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__);
@@ -1473,6 +1475,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/usr.bin/ssh/servconf.c b/usr.bin/ssh/servconf.c
index 747e8df35fe..10fed9b23bb 100644
--- a/usr.bin/ssh/servconf.c
+++ b/usr.bin/ssh/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@cs.hut.fi>, Espoo, Finland
* All rights reserved
@@ -154,6 +154,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. */
@@ -316,6 +317,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);
@@ -388,6 +391,7 @@ typedef enum {
sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
sStreamLocalBindMask, sStreamLocalBindUnlink,
sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
+ sExposeAuthInfo,
sDeprecated, sIgnore, sUnsupported
} ServerOpCodes;
@@ -515,6 +519,7 @@ static struct {
{ "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
{ "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
{ "disableforwarding", sDisableForwarding, SSHCFG_ALL },
+ { "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL },
{ NULL, sBadOption, 0 }
};
@@ -1783,6 +1788,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:
@@ -1921,6 +1930,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);
@@ -2213,6 +2223,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/usr.bin/ssh/servconf.h b/usr.bin/ssh/servconf.h
index 712e7563be8..0ccafdd8bb4 100644
--- a/usr.bin/ssh/servconf.h
+++ b/usr.bin/ssh/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@cs.hut.fi>
@@ -187,6 +187,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/usr.bin/ssh/session.c b/usr.bin/ssh/session.c
index 32046efdb6a..2f4ca7a37e0 100644
--- a/usr.bin/ssh/session.c
+++ b/usr.bin/ssh/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@cs.hut.fi>, Espoo, Finland
* All rights reserved
@@ -85,6 +85,7 @@
#endif
#include "monitor_wrap.h"
#include "sftp.h"
+#include "atomicio.h"
#ifdef KRB5
#include <kafs.h>
@@ -142,6 +143,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;
@@ -231,6 +235,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)
{
@@ -246,7 +284,10 @@ do_authenticated(Authctxt *authctxt)
auth_debug_send();
+ prepare_auth_info_file(authctxt->pw, authctxt->session_info);
+
do_authenticated2(authctxt);
+
do_cleanup(authctxt);
}
@@ -845,6 +886,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)
@@ -2147,6 +2190,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/usr.bin/ssh/ssh-gss.h b/usr.bin/ssh/ssh-gss.h
index f5e744ff629..09ea35a155d 100644
--- a/usr.bin/ssh/ssh-gss.h
+++ b/usr.bin/ssh/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.
*
@@ -107,6 +107,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/usr.bin/ssh/sshd_config.5 b/usr.bin/ssh/sshd_config.5
index 48b551a987c..d52abbb74ae 100644
--- a/usr.bin/ssh/sshd_config.5
+++ b/usr.bin/ssh/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
@@ -565,6 +565,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: