# HG changeset patch # User Matt Johnston # Date 1519651033 -28800 # Node ID 6a83b1944432597106a0046d30966ac30cb53c82 # Parent a55a6901a181d0b68a444126d5603c3776f57c80 Fix restricted group code for BSDs, move to separate function diff -r a55a6901a181 -r 6a83b1944432 runopts.h --- a/runopts.h Thu Feb 22 23:07:13 2018 +0800 +++ b/runopts.h Mon Feb 26 21:17:13 2018 +0800 @@ -92,8 +92,8 @@ #endif int norootlogin; - char *grouploginname; - gid_t *grouploginid; + char *restrict_group; + gid_t restrict_group_gid; int noauthpass; int norootpass; diff -r a55a6901a181 -r 6a83b1944432 svr-auth.c --- a/svr-auth.c Thu Feb 22 23:07:13 2018 +0800 +++ b/svr-auth.c Mon Feb 26 21:17:13 2018 +0800 @@ -226,6 +226,40 @@ 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 */ @@ -234,9 +268,6 @@ char* listshell = NULL; char* usershell = NULL; uid_t uid; - int ngroups = 32, ret; - gid_t *grouplist; - TRACE(("enter checkusername")) if (userlen > MAX_USERNAME_LEN) { @@ -284,45 +315,16 @@ return DROPBEAR_FAILURE; } - /* check for login restricted to certain group if desired */ - if (svr_opts.grouploginid) { - - for ( ; (ngroups <= NGROUPS_MAX) && (ngroups <= INT_MAX / 8); ngroups *= 2){ - - grouplist = malloc(sizeof(gid_t) * ngroups); - - ret = getgrouplist(ses.authstate.pw_name, ses.authstate.pw_gid, grouplist, &ngroups); - - if (ret != -1){ - break; - } - - free(grouplist); - ngroups *= 2; - } - - if ((ngroups > NGROUPS_MAX / 8) || (ngroups > INT_MAX / 8)){ - - TRACE(("Cannot walk group structure for current user, too many groups")) - dropbear_log(LOG_ERR, "Cannot walk group structure for current user, too many groups"); - return DROPBEAR_FAILURE; - } - - ngroups = 0; - for (int i = 0; i < ret; i++){ - if (grouplist[i] == *svr_opts.grouploginid){ - ngroups = 1; //Just used as a flag to indicate success; - break; - } - - } - - if (!ngroups){ - TRACE(("leave checkusername: user not in permitted group")) - dropbear_log(LOG_WARNING, "logins are restricted to the group %s but user %s is not a member", svr_opts.grouploginname, ses.authstate.pw_name); - 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); + return DROPBEAR_FAILURE; + } + } TRACE(("shell is %s", ses.authstate.pw_shell)) diff -r a55a6901a181 -r 6a83b1944432 svr-runopts.c --- a/svr-runopts.c Thu Feb 22 23:07:13 2018 +0800 +++ b/svr-runopts.c Mon Feb 26 21:17:13 2018 +0800 @@ -70,7 +70,7 @@ "-m Don't display the motd on login\n" #endif "-w Disallow root logins\n" - "-G Restrict logins to members of specified group\n" + "-G Restrict logins to members of specified group\n" #if DROPBEAR_SVR_PASSWORD_AUTH || DROPBEAR_SVR_PAM_AUTH "-s Disable password logins\n" "-g Disable password logins for root\n" @@ -135,8 +135,8 @@ svr_opts.forced_command = NULL; svr_opts.forkbg = 1; svr_opts.norootlogin = 0; - svr_opts.grouploginname = NULL; - svr_opts.grouploginid = NULL; + svr_opts.restrict_group = NULL; + svr_opts.restrict_group_gid = 0; svr_opts.noauthpass = 0; svr_opts.norootpass = 0; svr_opts.allowblankpass = 0; @@ -235,11 +235,9 @@ case 'w': svr_opts.norootlogin = 1; break; - - case 'G': - next = &svr_opts.grouploginname; - break; - + case 'G': + next = &svr_opts.restrict_group; + break; case 'W': next = &recv_window_arg; break; @@ -342,17 +340,16 @@ buf_setpos(svr_opts.banner, 0); } - if (svr_opts.grouploginname) { - struct group *restrictedgroup = getgrnam(svr_opts.grouploginname); + if (svr_opts.restrict_group) { + struct group *restrictedgroup = getgrnam(svr_opts.restrict_group); - if (restrictedgroup){ - svr_opts.grouploginid = malloc(sizeof(gid_t)); - *svr_opts.grouploginid = restrictedgroup->gr_gid; - } else { - dropbear_exit("Cannot restrict logins to group '%s' as the group does not exist", svr_opts.grouploginname); - } + if (restrictedgroup){ + svr_opts.restrict_group_gid = restrictedgroup->gr_gid; + } else { + dropbear_exit("Cannot restrict logins to group '%s' as the group does not exist", svr_opts.restrict_group); + } - } + } if (recv_window_arg) { opts.recv_window = atol(recv_window_arg); diff -r a55a6901a181 -r 6a83b1944432 sysoptions.h --- a/sysoptions.h Thu Feb 22 23:07:13 2018 +0800 +++ b/sysoptions.h Mon Feb 26 21:17:13 2018 +0800 @@ -81,6 +81,8 @@ #define DROPBEAR_PASSWORD_ENV "DROPBEAR_PASSWORD" +#define DROPBEAR_NGROUP_MAX 1024 + /* Required for pubkey auth */ #define DROPBEAR_SIGNKEY_VERIFY ((DROPBEAR_SVR_PUBKEY_AUTH) || (DROPBEAR_CLIENT))