summaryrefslogtreecommitdiffhomepage
path: root/svr-auth.c
diff options
context:
space:
mode:
authorMatt Johnston <matt@ucc.asn.au>2018-02-26 22:44:48 +0800
committerMatt Johnston <matt@ucc.asn.au>2018-02-26 22:44:48 +0800
commit5df73215f887bbc4ebd122e725fe5497d92f511f (patch)
tree5eaaab331c7f481b736dcd6d0e526de1e2248a14 /svr-auth.c
parent573838a0278e56225bf2a4a1e386105525a6a91a (diff)
parent3996e93a2045b68cbec6d645e7a166358dac95f7 (diff)
merge from main
--HG-- branch : fuzz
Diffstat (limited to 'svr-auth.c')
-rw-r--r--svr-auth.c120
1 files changed, 77 insertions, 43 deletions
diff --git a/svr-auth.c b/svr-auth.c
index 0d2fce1..82e68f2 100644
--- a/svr-auth.c
+++ b/svr-auth.c
@@ -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;