diff options
author | Matt Johnston <matt@ucc.asn.au> | 2018-02-26 22:44:48 +0800 |
---|---|---|
committer | Matt Johnston <matt@ucc.asn.au> | 2018-02-26 22:44:48 +0800 |
commit | 5df73215f887bbc4ebd122e725fe5497d92f511f (patch) | |
tree | 5eaaab331c7f481b736dcd6d0e526de1e2248a14 /svr-auth.c | |
parent | 573838a0278e56225bf2a4a1e386105525a6a91a (diff) | |
parent | 3996e93a2045b68cbec6d645e7a166358dac95f7 (diff) |
merge from main
--HG--
branch : fuzz
Diffstat (limited to 'svr-auth.c')
-rw-r--r-- | svr-auth.c | 120 |
1 files changed, 77 insertions, 43 deletions
@@ -25,6 +25,8 @@ /* This file (auth.c) handles authentication requests, passing it to the * particular type (auth-passwd, auth-pubkey). */ +#include <limits.h> + #include "includes.h" #include "dbutil.h" #include "session.h" @@ -35,26 +37,10 @@ #include "runopts.h" #include "dbrandom.h" -static void authclear(void); -static int checkusername(char *username, unsigned int userlen); +static int checkusername(const char *username, unsigned int userlen); /* initialise the first time for a session, resetting all parameters */ 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)); #if DROPBEAR_SVR_PUBKEY_AUTH ses.authstate.authtypes |= AUTH_TYPE_PUBKEY; @@ -64,19 +50,6 @@ static void authclear() { ses.authstate.authtypes |= AUTH_TYPE_PASSWORD; } #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 @@ -224,31 +197,76 @@ out: m_free(methodname); } +/* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ +static int check_group_membership(gid_t check_gid, const char* username, gid_t user_gid) { + int ngroups, i, ret; + gid_t *grouplist = NULL; + int match = DROPBEAR_FAILURE; + + for (ngroups = 32; ngroups <= DROPBEAR_NGROUP_MAX; ngroups *= 2) { + grouplist = m_malloc(sizeof(gid_t) * ngroups); + + /* BSD returns ret==0 on success. Linux returns ret==ngroups on success */ + ret = getgrouplist(username, user_gid, grouplist, &ngroups); + if (ret >= 0) { + break; + } + m_free(grouplist); + grouplist = NULL; + } + + if (!grouplist) { + dropbear_log(LOG_ERR, "Too many groups for user '%s'", username); + return DROPBEAR_FAILURE; + } + + for (i = 0; i < ngroups; i++) { + if (grouplist[i] == check_gid) { + match = DROPBEAR_SUCCESS; + break; + } + } + m_free(grouplist); + + return match; +} + /* Check that the username exists and isn't disallowed (root), and has a valid shell. * returns DROPBEAR_SUCCESS on valid username, DROPBEAR_FAILURE on failure */ -static int checkusername(char *username, unsigned int userlen) { +static int checkusername(const char *username, unsigned int userlen) { char* listshell = NULL; char* usershell = NULL; uid_t uid; + TRACE(("enter checkusername")) if (userlen > MAX_USERNAME_LEN) { return DROPBEAR_FAILURE; } - /* new user or username has changed */ - if (ses.authstate.username == NULL || - 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); - m_free(ses.authstate.username); - } - authclear(); - fill_passwd(username); - ses.authstate.username = m_strdup(username); + if (strlen(username) != userlen) { + dropbear_exit("Attempted username with a null byte from %s", + svr_ses.addrstring); + } + + if (ses.authstate.username == NULL) { + /* first request */ + fill_passwd(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 */ @@ -257,6 +275,7 @@ static int checkusername(char *username, unsigned int userlen) { dropbear_log(LOG_WARNING, "Login attempt for nonexistent user from %s", svr_ses.addrstring); + ses.authstate.checkusername_failed = 1; return DROPBEAR_FAILURE; } @@ -268,6 +287,7 @@ static int checkusername(char *username, unsigned int userlen) { "Login attempt with wrong user %s from %s", ses.authstate.pw_name, svr_ses.addrstring); + ses.authstate.checkusername_failed = 1; return DROPBEAR_FAILURE; } @@ -275,9 +295,22 @@ static int checkusername(char *username, unsigned int userlen) { if (svr_opts.norootlogin && ses.authstate.pw_uid == 0) { TRACE(("leave checkusername: root login disabled")) dropbear_log(LOG_WARNING, "root login rejected"); + ses.authstate.checkusername_failed = 1; return DROPBEAR_FAILURE; } + /* check for login restricted to certain group if desired */ + if (svr_opts.restrict_group) { + if (check_group_membership(svr_opts.restrict_group_gid, + ses.authstate.pw_name, ses.authstate.pw_gid) == DROPBEAR_FAILURE) { + dropbear_log(LOG_WARNING, + "Logins are restricted to the group %s but user '%s' is not a member", + svr_opts.restrict_group, ses.authstate.pw_name); + ses.authstate.checkusername_failed = 1; + return DROPBEAR_FAILURE; + } + } + TRACE(("shell is %s", ses.authstate.pw_shell)) /* check that the shell is set */ @@ -301,6 +334,7 @@ static int checkusername(char *username, unsigned int userlen) { /* no matching shell */ endusershell(); TRACE(("no matching shell")) + ses.authstate.checkusername_failed = 1; dropbear_log(LOG_WARNING, "User '%s' has invalid shell, rejected", ses.authstate.pw_name); return DROPBEAR_FAILURE; |