changeset 1534:ed930fd6f60f

Added the -G option to allow logins only for users that are members of a certain group. This allows finer control of an instance on who can and cannot login over a certain instance (e.g. password and not key). Needs double-checking and ensuring it meets platform requirements.
author stellarpower <stellarpower@googlemail.com>
date Tue, 20 Feb 2018 02:11:55 +0000
parents 47fcbdd12d9b
children b918ad1c5b25
files runopts.h svr-auth.c svr-runopts.c
diffstat 3 files changed, 70 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/runopts.h	Mon Feb 19 23:04:46 2018 +0800
+++ b/runopts.h	Tue Feb 20 02:11:55 2018 +0000
@@ -92,6 +92,8 @@
 #endif
 
 	int norootlogin;
+        char *grouploginname;
+        gid_t *grouploginid;
 
 	int noauthpass;
 	int norootpass;
--- a/svr-auth.c	Mon Feb 19 23:04:46 2018 +0800
+++ b/svr-auth.c	Tue Feb 20 02:11:55 2018 +0000
@@ -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"
@@ -232,6 +234,10 @@
 	char* listshell = NULL;
 	char* usershell = NULL;
 	uid_t uid;
+        int ngroups = 32, ret;
+        gid_t *grouplist;
+
+
 	TRACE(("enter checkusername"))
 	if (userlen > MAX_USERNAME_LEN) {
 		return DROPBEAR_FAILURE;
@@ -278,6 +284,46 @@
 		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;
+            }
+        }
+
 	TRACE(("shell is %s", ses.authstate.pw_shell))
 
 	/* check that the shell is set */
--- a/svr-runopts.c	Mon Feb 19 23:04:46 2018 +0800
+++ b/svr-runopts.c	Tue Feb 20 02:11:55 2018 +0000
@@ -30,6 +30,8 @@
 #include "algo.h"
 #include "ecdsa.h"
 
+#include <grp.h>
+
 svr_runopts svr_opts; /* GLOBAL */
 
 static void printhelp(const char * progname);
@@ -68,6 +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"
 #if DROPBEAR_SVR_PASSWORD_AUTH || DROPBEAR_SVR_PAM_AUTH
 					"-s		Disable password logins\n"
 					"-g		Disable password logins for root\n"
@@ -132,6 +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.noauthpass = 0;
 	svr_opts.norootpass = 0;
 	svr_opts.allowblankpass = 0;
@@ -230,6 +235,11 @@
 				case 'w':
 					svr_opts.norootlogin = 1;
 					break;
+
+                                case 'G':
+                                        next = &svr_opts.grouploginname;
+                                        break;
+
 				case 'W':
 					next = &recv_window_arg;
 					break;
@@ -331,6 +341,18 @@
 		}
 		buf_setpos(svr_opts.banner, 0);
 	}
+
+        if (svr_opts.grouploginname) {
+                struct group *restrictedgroup = getgrnam(svr_opts.grouploginname);
+
+                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 (recv_window_arg) {
 		opts.recv_window = atol(recv_window_arg);