summaryrefslogtreecommitdiff
path: root/auth2.c
diff options
context:
space:
mode:
Diffstat (limited to 'auth2.c')
-rw-r--r--auth2.c173
1 files changed, 153 insertions, 20 deletions
diff --git a/auth2.c b/auth2.c
index 97dd2ef0a4ff..862e09960b29 100644
--- a/auth2.c
+++ b/auth2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2.c,v 1.137 2017/02/03 23:05:57 djm 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;
@@ -87,8 +89,8 @@ Authmethod *authmethods[] = {
/* protocol */
-static int input_service_request(int, u_int32_t, void *);
-static int input_userauth_request(int, u_int32_t, void *);
+static int input_service_request(int, u_int32_t, struct ssh *);
+static int input_userauth_request(int, u_int32_t, struct ssh *);
/* helper */
static Authmethod *authmethod_lookup(Authctxt *, const char *);
@@ -168,16 +170,19 @@ done:
void
do_authentication2(Authctxt *authctxt)
{
- dispatch_init(&dispatch_protocol_error);
- dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
- dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
+ struct ssh *ssh = active_state; /* XXX */
+ ssh->authctxt = authctxt; /* XXX move to caller */
+ ssh_dispatch_init(ssh, &dispatch_protocol_error);
+ ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_REQUEST, &input_service_request);
+ ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt->success);
+ ssh->authctxt = NULL;
}
/*ARGSUSED*/
static int
-input_service_request(int type, u_int32_t seq, void *ctxt)
+input_service_request(int type, u_int32_t seq, struct ssh *ssh)
{
- Authctxt *authctxt = ctxt;
+ Authctxt *authctxt = ssh->authctxt;
u_int len;
int acceptit = 0;
char *service = packet_get_cstring(&len);
@@ -190,7 +195,7 @@ input_service_request(int type, u_int32_t seq, void *ctxt)
if (!authctxt->success) {
acceptit = 1;
/* now we can handle user-auth requests */
- dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
+ ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
}
}
/* XXX all other service requests are denied */
@@ -210,10 +215,9 @@ input_service_request(int type, u_int32_t seq, void *ctxt)
/*ARGSUSED*/
static int
-input_userauth_request(int type, u_int32_t seq, void *ctxt)
+input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
{
- struct ssh *ssh = active_state; /* XXX */
- Authctxt *authctxt = ctxt;
+ Authctxt *authctxt = ssh->authctxt;
Authmethod *m = NULL;
char *user, *service, *method, *style = NULL;
int authenticated = 0;
@@ -267,14 +271,15 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
authctxt->user, authctxt->service, user, service);
}
/* reset state */
- auth2_challenge_stop(authctxt);
+ auth2_challenge_stop(ssh);
#ifdef GSSAPI
/* XXX move to auth2_gssapi_stop() */
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
+ ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+ 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;
@@ -282,9 +287,9 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
m = authmethod_lookup(authctxt, method);
if (m != NULL && authctxt->failures < options.max_authtries) {
debug2("input_userauth_request: try method %s", method);
- authenticated = m->userauth(authctxt);
+ authenticated = m->userauth(ssh);
}
- userauth_finish(authctxt, authenticated, method, NULL);
+ userauth_finish(ssh, authenticated, method, NULL);
free(service);
free(user);
@@ -293,10 +298,10 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
}
void
-userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
+userauth_finish(struct ssh *ssh, int authenticated, const char *method,
const char *submethod)
{
- struct ssh *ssh = active_state; /* XXX */
+ Authctxt *authctxt = ssh->authctxt;
char *methods;
int partial = 0;
@@ -325,6 +330,10 @@ userauth_finish(Authctxt *authctxt, 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;
@@ -352,7 +361,7 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
if (authenticated == 1) {
/* turn off userauth */
- dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
+ ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
packet_start(SSH2_MSG_USERAUTH_SUCCESS);
packet_send();
packet_write_wait();
@@ -622,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));
+}