- Don't try to handle changed usernames

- Avoid logging repeated failed username messages
This commit is contained in:
Matt Johnston 2018-02-26 22:07:18 +08:00
parent 2e836bb553
commit 7435369615
2 changed files with 31 additions and 43 deletions

6
auth.h
View File

@ -105,12 +105,14 @@ struct AuthState {
unsigned char authtypes; /* Flags indicating which auth types are still unsigned char authtypes; /* Flags indicating which auth types are still
valid */ valid */
unsigned int failcount; /* Number of (failed) authentication attempts.*/ unsigned int failcount; /* Number of (failed) authentication attempts.*/
unsigned authdone : 1; /* 0 if we haven't authed, 1 if we have. Applies for unsigned int authdone; /* 0 if we haven't authed, 1 if we have. Applies for
client and server (though has differing client and server (though has differing
meanings). */ meanings). */
unsigned perm_warn : 1; /* Server only, set if bad permissions on unsigned int perm_warn; /* Server only, set if bad permissions on
~/.ssh/authorized_keys have already been ~/.ssh/authorized_keys have already been
logged. */ logged. */
unsigned int checkusername_failed; /* Server only, set if checkusername
has already failed */
/* These are only used for the server */ /* These are only used for the server */
uid_t pw_uid; uid_t pw_uid;

View File

@ -37,26 +37,10 @@
#include "runopts.h" #include "runopts.h"
#include "dbrandom.h" #include "dbrandom.h"
static void authclear(void);
static int checkusername(const char *username, unsigned int userlen); static int checkusername(const char *username, unsigned int userlen);
/* initialise the first time for a session, resetting all parameters */ /* initialise the first time for a session, resetting all parameters */
void svr_authinitialise() { void svr_authinitialise() {
ses.authstate.failcount = 0;
ses.authstate.pw_name = NULL;
ses.authstate.pw_dir = NULL;
ses.authstate.pw_shell = NULL;
ses.authstate.pw_passwd = NULL;
authclear();
}
/* Reset the auth state, but don't reset the failcount. This is for if the
* user decides to try with a different username etc, and is also invoked
* on initialisation */
static void authclear() {
memset(&ses.authstate, 0, sizeof(ses.authstate)); memset(&ses.authstate, 0, sizeof(ses.authstate));
#if DROPBEAR_SVR_PUBKEY_AUTH #if DROPBEAR_SVR_PUBKEY_AUTH
ses.authstate.authtypes |= AUTH_TYPE_PUBKEY; ses.authstate.authtypes |= AUTH_TYPE_PUBKEY;
@ -66,19 +50,6 @@ static void authclear() {
ses.authstate.authtypes |= AUTH_TYPE_PASSWORD; ses.authstate.authtypes |= AUTH_TYPE_PASSWORD;
} }
#endif #endif
if (ses.authstate.pw_name) {
m_free(ses.authstate.pw_name);
}
if (ses.authstate.pw_shell) {
m_free(ses.authstate.pw_shell);
}
if (ses.authstate.pw_dir) {
m_free(ses.authstate.pw_dir);
}
if (ses.authstate.pw_passwd) {
m_free(ses.authstate.pw_passwd);
}
} }
/* Send a banner message if specified to the client. The client might /* Send a banner message if specified to the client. The client might
@ -274,18 +245,28 @@ static int checkusername(const char *username, unsigned int userlen) {
return DROPBEAR_FAILURE; return DROPBEAR_FAILURE;
} }
/* new user or username has changed */ if (strlen(username) != userlen) {
if (ses.authstate.username == NULL || dropbear_exit("Attempted username with a null byte from %s",
strcmp(username, ses.authstate.username) != 0) {
/* the username needs resetting */
if (ses.authstate.username != NULL) {
dropbear_log(LOG_WARNING, "Client trying multiple usernames from %s",
svr_ses.addrstring); svr_ses.addrstring);
m_free(ses.authstate.username);
} }
authclear();
if (ses.authstate.username == NULL) {
/* first request */
fill_passwd(username); fill_passwd(username);
ses.authstate.username = m_strdup(username); ses.authstate.username = m_strdup(username);
} else {
/* check username hasn't changed */
if (strcmp(username, ses.authstate.username) != 0) {
dropbear_exit("Client trying multiple usernames from %s",
svr_ses.addrstring);
}
}
/* avoids cluttering logs with repeated failure messages from
consecutive authentication requests in a sesssion */
if (ses.authstate.checkusername_failed) {
TRACE(("checkusername: returning cached failure"))
return DROPBEAR_FAILURE;
} }
/* check that user exists */ /* check that user exists */
@ -294,6 +275,7 @@ static int checkusername(const char *username, unsigned int userlen) {
dropbear_log(LOG_WARNING, dropbear_log(LOG_WARNING,
"Login attempt for nonexistent user from %s", "Login attempt for nonexistent user from %s",
svr_ses.addrstring); svr_ses.addrstring);
ses.authstate.checkusername_failed = 1;
return DROPBEAR_FAILURE; return DROPBEAR_FAILURE;
} }
@ -305,6 +287,7 @@ static int checkusername(const char *username, unsigned int userlen) {
"Login attempt with wrong user %s from %s", "Login attempt with wrong user %s from %s",
ses.authstate.pw_name, ses.authstate.pw_name,
svr_ses.addrstring); svr_ses.addrstring);
ses.authstate.checkusername_failed = 1;
return DROPBEAR_FAILURE; return DROPBEAR_FAILURE;
} }
@ -312,6 +295,7 @@ static int checkusername(const char *username, unsigned int userlen) {
if (svr_opts.norootlogin && ses.authstate.pw_uid == 0) { if (svr_opts.norootlogin && ses.authstate.pw_uid == 0) {
TRACE(("leave checkusername: root login disabled")) TRACE(("leave checkusername: root login disabled"))
dropbear_log(LOG_WARNING, "root login rejected"); dropbear_log(LOG_WARNING, "root login rejected");
ses.authstate.checkusername_failed = 1;
return DROPBEAR_FAILURE; return DROPBEAR_FAILURE;
} }
@ -322,6 +306,7 @@ static int checkusername(const char *username, unsigned int userlen) {
dropbear_log(LOG_WARNING, dropbear_log(LOG_WARNING,
"Logins are restricted to the group %s but user '%s' is not a member", "Logins are restricted to the group %s but user '%s' is not a member",
svr_opts.restrict_group, ses.authstate.pw_name); svr_opts.restrict_group, ses.authstate.pw_name);
ses.authstate.checkusername_failed = 1;
return DROPBEAR_FAILURE; return DROPBEAR_FAILURE;
} }
} }
@ -349,6 +334,7 @@ static int checkusername(const char *username, unsigned int userlen) {
/* no matching shell */ /* no matching shell */
endusershell(); endusershell();
TRACE(("no matching shell")) TRACE(("no matching shell"))
ses.authstate.checkusername_failed = 1;
dropbear_log(LOG_WARNING, "User '%s' has invalid shell, rejected", dropbear_log(LOG_WARNING, "User '%s' has invalid shell, rejected",
ses.authstate.pw_name); ses.authstate.pw_name);
return DROPBEAR_FAILURE; return DROPBEAR_FAILURE;