changeset 1537:6a83b1944432

Fix restricted group code for BSDs, move to separate function
author Matt Johnston <matt@ucc.asn.au>
date Mon, 26 Feb 2018 21:17:13 +0800
parents a55a6901a181
children f20038b513a5
files runopts.h svr-auth.c svr-runopts.c sysoptions.h
diffstat 4 files changed, 62 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- 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;
--- 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))
 
--- 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);
--- 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))