[dovecot-cvs] dovecot/src/lib restrict-access.c,1.10,1.11 restrict-access.h,1.4,1.5

cras at procontrol.fi cras at procontrol.fi
Mon May 26 19:26:31 EEST 2003


Update of /home/cvs/dovecot/src/lib
In directory danu:/tmp/cvs-serv10925/src/lib

Modified Files:
	restrict-access.c restrict-access.h 
Log Message:
Allow first_valid_gid to be 0. Drop any supplementary groups not in valid
gid range.



Index: restrict-access.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib/restrict-access.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- restrict-access.c	4 Mar 2003 04:00:13 -0000	1.10
+++ restrict-access.c	26 May 2003 15:26:29 -0000	1.11
@@ -30,8 +30,15 @@
 #include <time.h>
 #include <grp.h>
 
+#define HARD_MAX_GROUPS 10240
+
+#ifndef NGROUPS_MAX
+#  define NGROUPS_MAX 128
+#endif
+
 void restrict_access_set_env(const char *user, uid_t uid, gid_t gid,
-			     const char *chroot_dir)
+			     const char *chroot_dir,
+			     gid_t first_valid_gid, gid_t last_valid_gid)
 {
 	if (user != NULL && *user != '\0')
 		env_put(t_strconcat("RESTRICT_USER=", user, NULL));
@@ -40,33 +47,68 @@
 
 	env_put(t_strdup_printf("RESTRICT_SETUID=%s", dec2str(uid)));
 	env_put(t_strdup_printf("RESTRICT_SETGID=%s", dec2str(gid)));
+
+	if (first_valid_gid != 0) {
+		env_put(t_strdup_printf("RESTRICT_GID_FIRST=%s",
+					dec2str(first_valid_gid)));
+	}
+	if (last_valid_gid != 0) {
+		env_put(t_strdup_printf("RESTRICT_GID_LAST=%s",
+					dec2str(last_valid_gid)));
+	}
 }
 
-void restrict_access_by_env(int disallow_root)
+static void drop_restricted_groups(void)
 {
+	/* @UNSAFE */
 	const char *env;
-	gid_t gid;
-	uid_t uid;
+	gid_t *gid_list, first_valid_gid, last_valid_gid;
+	int ret, i, gid_count;
 
-	/* chrooting */
-	env = getenv("RESTRICT_CHROOT");
-	if (env != NULL) {
-		/* kludge: localtime() must be called before chroot(),
-		   or the timezone isn't known */
-		time_t t = 0;
-		(void)localtime(&t);
+	env = getenv("RESTRICT_GID_FIRST");
+	first_valid_gid = env == NULL ? 0 : (gid_t)atol(env);
+	env = getenv("RESTRICT_GID_LAST");
+	last_valid_gid = env == NULL ? 0 : (gid_t)atol(env);
 
-		if (chroot(env) != 0)
-			i_fatal("chroot(%s) failed: %m", env);
+	if (first_valid_gid == 0 && last_valid_gid == 0)
+		return;
 
-		if (chdir("/") != 0)
-			i_fatal("chdir(/) failed: %m");
+	gid_count = NGROUPS_MAX;
+	gid_list = t_buffer_get(sizeof(gid_t) * gid_count);
+	while ((ret = getgroups(gid_count, gid_list)) < 0) {
+		if (errno != EINVAL ||
+		    gid_count < HARD_MAX_GROUPS)
+			i_fatal("getgroups() failed: %m");
+
+		gid_count *= 2;
+		gid_list = t_buffer_reget(gid_list, sizeof(gid_t) * gid_count);
 	}
 
+	gid_count = 0;
+	for (i = 0; i < ret; i++) {
+		if (gid_list[i] >= first_valid_gid &&
+		    (last_valid_gid == 0 || gid_list[i] <= last_valid_gid))
+			gid_list[gid_count++] = gid_list[i];
+	}
+
+	if (ret != gid_count) {
+		/* it did contain 0, remove it */
+		if (setgroups(gid_count, gid_list) < 0)
+			i_fatal("setgroups() failed: %m");
+	}
+}
+
+void restrict_access_by_env(int disallow_root)
+{
+	const char *env;
+	gid_t gid;
+	uid_t uid;
+
 	/* groups - the getgid() checks are just so we don't fail if we're
-	   not running as root and try to just use our own GID. */
+	   not running as root and try to just use our own GID. Do this
+	   before chrooting so initgroups() actually works. */
 	env = getenv("RESTRICT_SETGID");
-	gid = env == NULL ? 0 : (gid_t) atol(env);
+	gid = env == NULL ? 0 : (gid_t)atol(env);
 	if (gid != 0 && (gid != getgid() || gid != getegid())) {
 		if (setgid(gid) != 0)
 			i_fatal("setgid(%s) failed: %m", dec2str(gid));
@@ -74,18 +116,38 @@
 		env = getenv("RESTRICT_USER");
 		if (env == NULL) {
 			/* user not known, use only this one group */
-			(void)setgroups(1, &gid);
+			if (setgroups(1, &gid) < 0) {
+				i_fatal("setgroups(%s) failed: %m",
+					dec2str(gid));
+			}
 		} else {
 			if (initgroups(env, gid) != 0) {
 				i_fatal("initgroups(%s, %s) failed: %m",
 					env, dec2str(gid));
 			}
+
+                        drop_restricted_groups();
 		}
 	}
 
+	/* chrooting */
+	env = getenv("RESTRICT_CHROOT");
+	if (env != NULL) {
+		/* kludge: localtime() must be called before chroot(),
+		   or the timezone isn't known */
+		time_t t = 0;
+		(void)localtime(&t);
+
+		if (chroot(env) != 0)
+			i_fatal("chroot(%s) failed: %m", env);
+
+		if (chdir("/") != 0)
+			i_fatal("chdir(/) failed: %m");
+	}
+
 	/* uid last */
 	env = getenv("RESTRICT_SETUID");
-	uid = env == NULL ? 0 : (uid_t) atol(env);
+	uid = env == NULL ? 0 : (uid_t)atol(env);
 	if (uid != 0) {
 		if (setuid(uid) != 0)
 			i_fatal("setuid(%s) failed: %m", dec2str(uid));

Index: restrict-access.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib/restrict-access.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- restrict-access.h	4 Mar 2003 04:00:13 -0000	1.4
+++ restrict-access.h	26 May 2003 15:26:29 -0000	1.5
@@ -4,7 +4,8 @@
 /* set environment variables so they can be read with
    restrict_access_by_env() */
 void restrict_access_set_env(const char *user, uid_t uid, gid_t gid,
-			     const char *chroot_dir);
+			     const char *chroot_dir,
+			     gid_t first_valid_gid, gid_t last_valid_gid);
 
 /* chroot, setuid() and setgid() based on environment variables.
    If disallow_roots is TRUE, we'll kill ourself if we didn't have the



More information about the dovecot-cvs mailing list