зеркало из https://github.com/Azure/sonic-openssh.git
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:
Родитель
e2004d4bb7
Коммит
8f57495927
62
auth.c
62
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 &&
|
||||
|
|
48
auth.h
48
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;
|
||||
|
||||
/* 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;
|
||||
char *info; /* Extra info for next auth_log */
|
||||
#ifdef BSD_AUTH
|
||||
auth_session_t *as;
|
||||
#endif
|
||||
char **auth_methods; /* modified from server config */
|
||||
u_int num_auth_methods;
|
||||
#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 *);
|
||||
|
|
12
auth2-gss.c
12
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
133
auth2.c
133
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));
|
||||
}
|
||||
|
||||
|
|
11
gss-serv.c
11
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
|
||||
|
|
41
monitor.c
41
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>
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
13
servconf.c
13
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
|
||||
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
@ -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 */
|
||||
|
|
54
session.c
54
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
|
||||
|
@ -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.
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
Загрузка…
Ссылка в новой задаче