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
This commit is contained in:
djm@openbsd.org 2017-06-24 06:34:38 +00:00 committed by Damien Miller
parent e2004d4bb7
commit 8f57495927
13 changed files with 338 additions and 140 deletions

62
auth.c
View File

@ -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. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
@ -267,21 +267,41 @@ allowed_user(struct passwd * pw)
return 1; 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; const struct sshkey *key = authctxt->auth_method_key;
int i; const char *methinfo = authctxt->auth_method_info;
char *fp, *ret = NULL;
free(authctxt->info); if (key == NULL)
authctxt->info = NULL; return NULL;
va_start(ap, fmt); if (key_is_cert(key)) {
i = vasprintf(&authctxt->info, fmt, ap); fp = sshkey_fingerprint(key->cert->signature_key,
va_end(ap); options.fingerprint_hash, SSH_FP_DEFAULT);
xasprintf(&ret, "%s ID %s (serial %llu) CA %s %s%s%s",
if (i < 0 || authctxt->info == NULL) sshkey_type(key), key->cert->key_id,
fatal("vasprintf failed"); (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 void
@ -290,7 +310,8 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
{ {
struct ssh *ssh = active_state; /* XXX */ struct ssh *ssh = active_state; /* XXX */
void (*authlog) (const char *fmt,...) = verbose; void (*authlog) (const char *fmt,...) = verbose;
char *authmsg; const char *authmsg;
char *extra = NULL;
if (use_privsep && !mm_is_monitor() && !authctxt->postponed) if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
return; return;
@ -309,6 +330,11 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
else else
authmsg = authenticated ? "Accepted" : "Failed"; 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", authlog("%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s",
authmsg, authmsg,
method, method,
@ -317,10 +343,10 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
authctxt->user, authctxt->user,
ssh_remote_ipaddr(ssh), ssh_remote_ipaddr(ssh),
ssh_remote_port(ssh), ssh_remote_port(ssh),
authctxt->info != NULL ? ": " : "", extra != NULL ? ": " : "",
authctxt->info != NULL ? authctxt->info : ""); extra != NULL ? extra : "");
free(authctxt->info);
authctxt->info = NULL; free(extra);
#ifdef CUSTOM_FAILED_LOGIN #ifdef CUSTOM_FAILED_LOGIN
if (authenticated == 0 && !authctxt->postponed && if (authenticated == 0 && !authctxt->postponed &&

48
auth.h
View File

@ -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. * Copyright (c) 2000 Markus Friedl. All rights reserved.
@ -44,6 +44,7 @@
struct ssh; struct ssh;
struct sshkey; struct sshkey;
struct sshbuf;
typedef struct Authctxt Authctxt; typedef struct Authctxt Authctxt;
typedef struct Authmethod Authmethod; typedef struct Authmethod Authmethod;
@ -62,13 +63,17 @@ struct Authctxt {
char *service; char *service;
struct passwd *pw; /* set if 'valid' */ struct passwd *pw; /* set if 'valid' */
char *style; char *style;
/* 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; void *kbdintctxt;
char *info; /* Extra info for next auth_log */
#ifdef BSD_AUTH #ifdef BSD_AUTH
auth_session_t *as; auth_session_t *as;
#endif #endif
char **auth_methods; /* modified from server config */
u_int num_auth_methods;
#ifdef KRB5 #ifdef KRB5
krb5_context krb5_ctx; krb5_context krb5_ctx;
krb5_ccache krb5_fwd_ccache; krb5_ccache krb5_fwd_ccache;
@ -76,12 +81,20 @@ struct Authctxt {
char *krb5_ticket_file; char *krb5_ticket_file;
char *krb5_ccname; char *krb5_ccname;
#endif #endif
Buffer *loginmsg; struct sshbuf *loginmsg;
void *methoddata;
struct sshkey **prev_userkeys; /* Authentication keys already used; these will be refused henceforth */
u_int nprev_userkeys; 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 * Every authentication method has to handle authentication requests for
* non-existing users, or for users that are not allowed to login. In this * 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 *, int hostbased_key_allowed(struct passwd *, const char *, char *,
struct sshkey *); struct sshkey *);
int user_key_allowed(struct passwd *, struct sshkey *, int); int user_key_allowed(struct passwd *, struct sshkey *, int);
void pubkey_auth_info(Authctxt *, const struct sshkey *, const char *, ...) int auth2_key_already_used(Authctxt *, const struct sshkey *);
__attribute__((__format__ (printf, 3, 4)));
void auth2_record_userkey(Authctxt *, struct sshkey *); /*
int auth2_userkey_already_used(Authctxt *, 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; struct stat;
int auth_secure_path(const char *, struct stat *, const char *, uid_t, 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 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_log(Authctxt *, int, int, const char *, const char *);
void auth_maxtries_exceeded(Authctxt *) __attribute__((noreturn)); void auth_maxtries_exceeded(Authctxt *) __attribute__((noreturn));
void userauth_finish(struct ssh *, int, const char *, const char *); void userauth_finish(struct ssh *, int, const char *, const char *);

View File

@ -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. * 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; Authctxt *authctxt = ssh->authctxt;
int authenticated; int authenticated;
const char *displayname;
if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
fatal("No authentication or GSSAPI context"); 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)); 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; authctxt->postponed = 0;
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, 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; Buffer b;
gss_buffer_desc mic, gssbuf; gss_buffer_desc mic, gssbuf;
u_int len; u_int len;
const char *displayname;
if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
fatal("No authentication or GSSAPI context"); 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); buffer_free(&b);
free(mic.value); free(mic.value);
if ((!use_privsep || mm_is_monitor()) &&
(displayname = ssh_gssapi_displayname()) != NULL)
auth2_record_info(authctxt, "%s", displayname);
authctxt->postponed = 0; authctxt->postponed = 0;
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);

View File

@ -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. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
@ -137,7 +137,7 @@ userauth_hostbased(struct ssh *ssh)
sshbuf_dump(b, stderr); sshbuf_dump(b, stderr);
#endif #endif
pubkey_auth_info(authctxt, key, auth2_record_info(authctxt,
"client user \"%.100s\", client host \"%.100s\"", cuser, chost); "client user \"%.100s\", client host \"%.100s\"", cuser, chost);
/* test for allowed key and correct signature */ /* 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) sshbuf_ptr(b), sshbuf_len(b), ssh->compat)) == 0)
authenticated = 1; authenticated = 1;
auth2_record_key(authctxt, authenticated, key);
sshbuf_free(b); sshbuf_free(b);
done: done:
debug2("%s: authenticated %d", __func__, authenticated); debug2("%s: authenticated %d", __func__, authenticated);
if (key != NULL) sshkey_free(key);
sshkey_free(key);
free(pkalg); free(pkalg);
free(pkblob); free(pkblob);
free(cuser); free(cuser);

View File

@ -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. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
@ -137,7 +137,7 @@ userauth_pubkey(struct ssh *ssh)
goto done; goto done;
} }
fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT); 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)); logit("refusing previously-used %s key", sshkey_type(key));
goto done; goto done;
} }
@ -194,7 +194,6 @@ userauth_pubkey(struct ssh *ssh)
#ifdef DEBUG_PK #ifdef DEBUG_PK
sshbuf_dump(b, stderr); sshbuf_dump(b, stderr);
#endif #endif
pubkey_auth_info(authctxt, key, NULL);
/* test for correct signature */ /* test for correct signature */
authenticated = 0; authenticated = 0;
@ -202,12 +201,10 @@ userauth_pubkey(struct ssh *ssh)
PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b), PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b),
sshbuf_len(b), ssh->compat)) == 0) { sshbuf_len(b), ssh->compat)) == 0) {
authenticated = 1; authenticated = 1;
/* Record the successful key to prevent reuse */
auth2_record_userkey(authctxt, key);
key = NULL; /* Don't free below */
} }
sshbuf_free(b); sshbuf_free(b);
free(sig); free(sig);
auth2_record_key(authctxt, authenticated, key);
} else { } else {
debug("%s: test whether pkalg/pkblob are acceptable for %s %s", debug("%s: test whether pkalg/pkblob are acceptable for %s %s",
__func__, sshkey_type(key), fp); __func__, sshkey_type(key), fp);
@ -237,8 +234,7 @@ userauth_pubkey(struct ssh *ssh)
auth_clear_options(); auth_clear_options();
done: done:
debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg); debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg);
if (key != NULL) sshkey_free(key);
sshkey_free(key);
free(userstyle); free(userstyle);
free(pkalg); free(pkalg);
free(pkblob); free(pkblob);
@ -246,44 +242,6 @@ done:
return authenticated; 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 * Splits 's' into an argument vector. Handles quoted string and basic
* escape characters (\\, \", \'). Caller must free the argument vector * 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; 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 = { Authmethod method_pubkey = {
"publickey", "publickey",
userauth_pubkey, userauth_pubkey,

133
auth2.c
View File

@ -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. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
@ -30,6 +30,7 @@
#include <sys/uio.h> #include <sys/uio.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h>
#include <pwd.h> #include <pwd.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
@ -55,6 +56,7 @@
#include "ssh-gss.h" #include "ssh-gss.h"
#endif #endif
#include "monitor_wrap.h" #include "monitor_wrap.h"
#include "ssherr.h"
/* import */ /* import */
extern ServerOptions options; 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); ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
#endif #endif
auth2_authctxt_reset_info(authctxt);
authctxt->postponed = 0; authctxt->postponed = 0;
authctxt->server_caused_failure = 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 */ /* Log before sending the reply */
auth_log(authctxt, authenticated, partial, method, submethod); 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) if (authctxt->postponed)
return; return;
@ -624,4 +631,128 @@ auth2_update_methods_lists(Authctxt *authctxt, const char *method,
return 0; 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));
}

View File

@ -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. * 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); 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 #endif

View File

@ -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 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org> * Copyright 2002 Markus Friedl <markus@openbsd.org>
@ -308,6 +308,8 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
partial = 0; partial = 0;
auth_method = "unknown"; auth_method = "unknown";
auth_submethod = NULL; auth_submethod = NULL;
auth2_authctxt_reset_info(authctxt);
authenticated = (monitor_read(pmonitor, mon_dispatch, &ent) == 1); authenticated = (monitor_read(pmonitor, mon_dispatch, &ent) == 1);
/* Special handling for multiple required authentications */ /* Special handling for multiple required authentications */
@ -347,6 +349,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
auth_method, auth_submethod); auth_method, auth_submethod);
if (!partial && !authenticated) if (!partial && !authenticated)
authctxt->failures++; 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) { switch (type) {
case MM_USERKEY: case MM_USERKEY:
allowed = options.pubkey_authentication && allowed = options.pubkey_authentication &&
!auth2_userkey_already_used(authctxt, key) && !auth2_key_already_used(authctxt, key) &&
match_pattern_list(sshkey_ssh_name(key), match_pattern_list(sshkey_ssh_name(key),
options.pubkey_key_types, 0) == 1 && options.pubkey_key_types, 0) == 1 &&
user_key_allowed(authctxt->pw, key, user_key_allowed(authctxt->pw, key,
pubkey_auth_attempt); pubkey_auth_attempt);
pubkey_auth_info(authctxt, key, NULL);
auth_method = "publickey"; auth_method = "publickey";
if (options.pubkey_authentication && if (options.pubkey_authentication &&
(!pubkey_auth_attempt || allowed != 1)) (!pubkey_auth_attempt || allowed != 1))
@ -1160,11 +1165,12 @@ mm_answer_keyallowed(int sock, Buffer *m)
break; break;
case MM_HOSTKEY: case MM_HOSTKEY:
allowed = options.hostbased_authentication && allowed = options.hostbased_authentication &&
!auth2_key_already_used(authctxt, key) &&
match_pattern_list(sshkey_ssh_name(key), match_pattern_list(sshkey_ssh_name(key),
options.hostbased_key_types, 0) == 1 && options.hostbased_key_types, 0) == 1 &&
hostbased_key_allowed(authctxt->pw, hostbased_key_allowed(authctxt->pw,
cuser, chost, key); cuser, chost, key);
pubkey_auth_info(authctxt, key, auth2_record_info(authctxt,
"client user \"%.100s\", client host \"%.100s\"", "client user \"%.100s\", client host \"%.100s\"",
cuser, chost); cuser, chost);
auth_method = "hostbased"; auth_method = "hostbased";
@ -1175,11 +1181,10 @@ mm_answer_keyallowed(int sock, Buffer *m)
} }
} }
debug3("%s: key %p is %s", debug3("%s: key is %s", __func__, allowed ? "allowed" : "not allowed");
__func__, key, allowed ? "allowed" : "not allowed");
if (key != NULL) auth2_record_key(authctxt, 0, key);
key_free(key); sshkey_free(key);
/* clear temporarily storage (used by verify) */ /* clear temporarily storage (used by verify) */
monitor_reset_key_state(); monitor_reset_key_state();
@ -1353,10 +1358,12 @@ mm_answer_keyverify(int sock, struct sshbuf *m)
switch (key_blobtype) { switch (key_blobtype) {
case MM_USERKEY: case MM_USERKEY:
valid_data = monitor_valid_userblob(data, datalen); valid_data = monitor_valid_userblob(data, datalen);
auth_method = "publickey";
break; break;
case MM_HOSTKEY: case MM_HOSTKEY:
valid_data = monitor_valid_hostbasedblob(data, datalen, valid_data = monitor_valid_hostbasedblob(data, datalen,
hostbased_cuser, hostbased_chost); hostbased_cuser, hostbased_chost);
auth_method = "hostbased";
break; break;
default: default:
valid_data = 0; valid_data = 0;
@ -1367,23 +1374,17 @@ mm_answer_keyverify(int sock, struct sshbuf *m)
ret = sshkey_verify(key, signature, signaturelen, data, datalen, ret = sshkey_verify(key, signature, signaturelen, data, datalen,
active_state->compat); active_state->compat);
debug3("%s: key %p signature %s", debug3("%s: %s %p signature %s", __func__, auth_method, key,
__func__, key, (ret == 0) ? "verified" : "unverified"); (ret == 0) ? "verified" : "unverified");
auth2_record_key(authctxt, ret == 0, key);
/* 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);
free(blob); free(blob);
free(signature); free(signature);
free(data); free(data);
auth_method = key_blobtype == MM_USERKEY ? "publickey" : "hostbased";
monitor_reset_key_state(); monitor_reset_key_state();
sshkey_free(key);
sshbuf_reset(m); sshbuf_reset(m);
/* encode ret != 0 as positive integer, since we're sending u32 */ /* encode ret != 0 as positive integer, since we're sending u32 */
@ -1799,6 +1800,7 @@ int
mm_answer_gss_userok(int sock, Buffer *m) mm_answer_gss_userok(int sock, Buffer *m)
{ {
int authenticated; int authenticated;
const char *displayname;
if (!options.gss_authentication) if (!options.gss_authentication)
fatal("%s: GSSAPI authentication not enabled", __func__); fatal("%s: GSSAPI authentication not enabled", __func__);
@ -1813,6 +1815,9 @@ mm_answer_gss_userok(int sock, Buffer *m)
auth_method = "gssapi-with-mic"; auth_method = "gssapi-with-mic";
if ((displayname = ssh_gssapi_displayname()) != NULL)
auth2_record_info(authctxt, "%s", displayname);
/* Monitor loop will terminate if authenticated */ /* Monitor loop will terminate if authenticated */
return (authenticated); return (authenticated);
} }

View File

@ -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 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
@ -164,6 +164,7 @@ initialize_server_options(ServerOptions *options)
options->version_addendum = NULL; options->version_addendum = NULL;
options->fingerprint_hash = -1; options->fingerprint_hash = -1;
options->disable_forwarding = -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. */ /* 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; options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
if (options->disable_forwarding == -1) if (options->disable_forwarding == -1)
options->disable_forwarding = 0; options->disable_forwarding = 0;
if (options->expose_userauth_info == -1)
options->expose_userauth_info = 0;
assemble_algorithms(options); assemble_algorithms(options);
@ -418,6 +421,7 @@ typedef enum {
sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
sStreamLocalBindMask, sStreamLocalBindUnlink, sStreamLocalBindMask, sStreamLocalBindUnlink,
sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
sExposeAuthInfo,
sDeprecated, sIgnore, sUnsupported sDeprecated, sIgnore, sUnsupported
} ServerOpCodes; } ServerOpCodes;
@ -561,6 +565,7 @@ static struct {
{ "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL }, { "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
{ "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL }, { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
{ "disableforwarding", sDisableForwarding, SSHCFG_ALL }, { "disableforwarding", sDisableForwarding, SSHCFG_ALL },
{ "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL },
{ NULL, sBadOption, 0 } { NULL, sBadOption, 0 }
}; };
@ -1835,6 +1840,10 @@ process_server_config_line(ServerOptions *options, char *line,
options->fingerprint_hash = value; options->fingerprint_hash = value;
break; break;
case sExposeAuthInfo:
intptr = &options->expose_userauth_info;
goto parse_flag;
case sDeprecated: case sDeprecated:
case sIgnore: case sIgnore:
case sUnsupported: 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_streamlocal_forwarding);
M_CP_INTOPT(allow_agent_forwarding); M_CP_INTOPT(allow_agent_forwarding);
M_CP_INTOPT(disable_forwarding); M_CP_INTOPT(disable_forwarding);
M_CP_INTOPT(expose_userauth_info);
M_CP_INTOPT(permit_tun); M_CP_INTOPT(permit_tun);
M_CP_INTOPT(fwd_opts.gateway_ports); M_CP_INTOPT(fwd_opts.gateway_ports);
M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink); 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(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash); dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info);
/* string arguments */ /* string arguments */
dump_cfg_string(sPidFile, o->pid_file); dump_cfg_string(sPidFile, o->pid_file);

View File

@ -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> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -189,6 +189,7 @@ typedef struct {
char *auth_methods[MAX_AUTH_METHODS]; char *auth_methods[MAX_AUTH_METHODS];
int fingerprint_hash; int fingerprint_hash;
int expose_userauth_info;
} ServerOptions; } ServerOptions;
/* Information about the incoming connection as used by Match */ /* Information about the incoming connection as used by Match */

View File

@ -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 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
@ -94,6 +94,7 @@
#include "kex.h" #include "kex.h"
#include "monitor_wrap.h" #include "monitor_wrap.h"
#include "sftp.h" #include "sftp.h"
#include "atomicio.h"
#if defined(KRB5) && defined(USE_AFS) #if defined(KRB5) && defined(USE_AFS)
#include <kafs.h> #include <kafs.h>
@ -160,6 +161,9 @@ login_cap_t *lc;
static int is_child = 0; static int is_child = 0;
static int in_chroot = 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. */ /* Name and directory of socket for authentication agent forwarding. */
static char *auth_sock_name = NULL; static char *auth_sock_name = NULL;
static char *auth_sock_dir = 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 void
do_authenticated(Authctxt *authctxt) do_authenticated(Authctxt *authctxt)
{ {
@ -264,7 +302,10 @@ do_authenticated(Authctxt *authctxt)
auth_debug_send(); auth_debug_send();
prepare_auth_info_file(authctxt->pw, authctxt->session_info);
do_authenticated2(authctxt); do_authenticated2(authctxt);
do_cleanup(authctxt); do_cleanup(authctxt);
} }
@ -1077,6 +1118,8 @@ do_setup_env(Session *s, const char *shell)
free(laddr); free(laddr);
child_set_env(&env, &envsize, "SSH_CONNECTION", buf); 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) if (s->ttyfd != -1)
child_set_env(&env, &envsize, "SSH_TTY", s->tty); child_set_env(&env, &envsize, "SSH_TTY", s->tty);
if (s->term) if (s->term)
@ -2549,6 +2592,15 @@ do_cleanup(Authctxt *authctxt)
/* remove agent socket */ /* remove agent socket */
auth_sock_cleanup_proc(authctxt->pw); 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, * Cleanup ptys/utmp only if privsep is disabled,
* or if running in monitor. * or if running in monitor.

View File

@ -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. * 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_do_child(char ***, u_int *);
void ssh_gssapi_cleanup_creds(void); void ssh_gssapi_cleanup_creds(void);
void ssh_gssapi_storecreds(void); void ssh_gssapi_storecreds(void);
const char *ssh_gssapi_displayname(void);
#endif /* GSSAPI */ #endif /* GSSAPI */

View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" 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 $ .\" $OpenBSD: sshd_config.5,v 1.246 2017/06/24 06:34:38 djm Exp $
.Dd $Mdocdate: May 17 2017 $ .Dd $Mdocdate: June 24 2017 $
.Dt SSHD_CONFIG 5 .Dt SSHD_CONFIG 5
.Os .Os
.Sh NAME .Sh NAME
@ -564,6 +564,12 @@ Disables all forwarding features, including X11,
TCP and StreamLocal. TCP and StreamLocal.
This option overrides all other forwarding-related options and may This option overrides all other forwarding-related options and may
simplify restricted configurations. 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 .It Cm FingerprintHash
Specifies the hash algorithm used when logging key fingerprints. Specifies the hash algorithm used when logging key fingerprints.
Valid options are: Valid options are: