=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/auth2.c,v retrieving revision 1.142 retrieving revision 1.143 diff -u -r1.142 -r1.143 --- src/usr.bin/ssh/auth2.c 2017/05/31 07:00:13 1.142 +++ src/usr.bin/ssh/auth2.c 2017/06/24 06:34:38 1.143 @@ -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 #include +#include #include #include #include @@ -52,6 +53,7 @@ #include "ssh-gss.h" #endif #include "monitor_wrap.h" +#include "ssherr.h" /* import */ extern ServerOptions options; @@ -257,6 +259,7 @@ 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 @@ /* 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 @@ 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)); +}