dovecot: Build environment using envarr and pass it to execve()....

dovecot at dovecot.org dovecot at dovecot.org
Wed Jan 2 01:36:56 EET 2008


details:   http://hg.dovecot.org/dovecot/rev/59ac3628b8d8
changeset: 7091:59ac3628b8d8
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Jan 02 01:36:51 2008 +0200
description:
Build environment using envarr and pass it to execve(). This is faster than
using putenv() directly. restrict_access_*_env() API changed to take
environment array parameter.

diffstat:

17 files changed, 373 insertions(+), 312 deletions(-)
src/auth/main.c                  |    2 
src/deliver/auth-client.c        |    2 
src/dict/main.c                  |    2 
src/imap/main.c                  |    2 
src/lib/restrict-access.c        |  130 ++++++++++++++-------
src/lib/restrict-access.h        |    9 +
src/login-common/main.c          |    2 
src/master/auth-process.c        |  146 +++++++++++++-----------
src/master/child-process.c       |   23 ++-
src/master/child-process.h       |    5 
src/master/dict-process.c        |   13 +-
src/master/login-process.c       |  113 +++++++++----------
src/master/mail-process.c        |  225 +++++++++++++++++++-------------------
src/master/ssl-init.c            |    5 
src/plugins/expire/auth-client.c |    2 
src/pop3/main.c                  |    2 
src/util/rawlog.c                |    2 

diffs (truncated from 1346 to 300 lines):

diff -r c8878d66c4a1 -r 59ac3628b8d8 src/auth/main.c
--- a/src/auth/main.c	Wed Jan 02 01:35:21 2008 +0200
+++ b/src/auth/main.c	Wed Jan 02 01:36:51 2008 +0200
@@ -209,7 +209,7 @@ static void drop_privileges(void)
 		add_extra_listeners();
 
 	/* Password lookups etc. may require roots, allow it. */
-	restrict_access_by_env(FALSE);
+	restrict_access_by_env(NULL, FALSE);
 }
 
 static void main_init(bool nodaemon)
diff -r c8878d66c4a1 -r 59ac3628b8d8 src/deliver/auth-client.c
--- a/src/deliver/auth-client.c	Wed Jan 02 01:35:21 2008 +0200
+++ b/src/deliver/auth-client.c	Wed Jan 02 01:36:51 2008 +0200
@@ -173,7 +173,7 @@ static void auth_parse_input(struct auth
 				    extra_groups, NULL));
 	}
 
-	restrict_access_by_env(TRUE);
+	restrict_access_by_env(NULL, TRUE);
 	return_value = EX_OK;
 }
 
diff -r c8878d66c4a1 -r 59ac3628b8d8 src/dict/main.c
--- a/src/dict/main.c	Wed Jan 02 01:35:21 2008 +0200
+++ b/src/dict/main.c	Wed Jan 02 01:36:51 2008 +0200
@@ -51,7 +51,7 @@ static void drop_privileges(void)
 	sql_drivers_init();
 	sql_drivers_register_all();
 
-	restrict_access_by_env(FALSE);
+	restrict_access_by_env(NULL, FALSE);
 }
 
 static void main_init(void)
diff -r c8878d66c4a1 -r 59ac3628b8d8 src/imap/main.c
--- a/src/imap/main.c	Wed Jan 02 01:35:21 2008 +0200
+++ b/src/imap/main.c	Wed Jan 02 01:36:51 2008 +0200
@@ -157,7 +157,7 @@ static void drop_privileges(void)
 					  TRUE, version);
 	}
 
-	restrict_access_by_env(!IS_STANDALONE());
+	restrict_access_by_env(NULL, !IS_STANDALONE());
 }
 
 static void main_init(void)
diff -r c8878d66c4a1 -r 59ac3628b8d8 src/lib/restrict-access.c
--- a/src/lib/restrict-access.c	Wed Jan 02 01:35:21 2008 +0200
+++ b/src/lib/restrict-access.c	Wed Jan 02 01:36:51 2008 +0200
@@ -1,6 +1,7 @@
 /* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "array.h"
 #include "restrict-access.h"
 #include "env-util.h"
 
@@ -9,31 +10,54 @@
 #include <time.h>
 #include <grp.h>
 
-void restrict_access_set_env(const char *user, uid_t uid, gid_t gid,
+enum restrict_env {
+	RESTRICT_ENV_USER,
+	RESTRICT_ENV_CHROOT,
+	RESTRICT_ENV_SETUID,
+	RESTRICT_ENV_SETGID,
+	RESTRICT_ENV_SETEXTRAGROUPS,
+	RESTRICT_ENV_GID_FIRST,
+	RESTRICT_ENV_GID_LAST,
+
+	RESTRICT_ENV_COUNT
+};
+
+static const char *restrict_env_strings[RESTRICT_ENV_COUNT] = {
+	"RESTRICT_USER",
+	"RESTRICT_CHROOT",
+	"RESTRICT_SETUID",
+	"RESTRICT_SETGID",
+	"RESTRICT_SETEXTRAGROUPS",
+	"RESTRICT_GID_FIRST",
+	"RESTRICT_GID_LAST"
+};
+
+static void renv_add(ARRAY_TYPE(const_string) *env, enum restrict_env key,
+		     const char *value)
+{
+	envarr_add(env, restrict_env_strings[key], value);
+}
+
+void restrict_access_set_env(ARRAY_TYPE(const_string) *env,
+			     const char *user, uid_t uid, gid_t gid,
 			     const char *chroot_dir,
 			     gid_t first_valid_gid, gid_t last_valid_gid,
 			     const char *extra_groups)
 {
 	if (user != NULL && *user != '\0')
-		env_put(t_strconcat("RESTRICT_USER=", user, NULL));
+		renv_add(env, RESTRICT_ENV_USER, user);
 	if (chroot_dir != NULL && *chroot_dir != '\0')
-		env_put(t_strconcat("RESTRICT_CHROOT=", chroot_dir, NULL));
-
-	env_put(t_strdup_printf("RESTRICT_SETUID=%s", dec2str(uid)));
-	env_put(t_strdup_printf("RESTRICT_SETGID=%s", dec2str(gid)));
-	if (extra_groups != NULL && *extra_groups != '\0') {
-		env_put(t_strconcat("RESTRICT_SETEXTRAGROUPS=",
-				    extra_groups, NULL));
-	}
-
-	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)));
-	}
+		renv_add(env, RESTRICT_ENV_CHROOT, chroot_dir);
+
+	renv_add(env, RESTRICT_ENV_SETUID, dec2str(uid));
+	renv_add(env, RESTRICT_ENV_SETGID, dec2str(gid));
+	if (extra_groups != NULL && *extra_groups != '\0')
+		renv_add(env, RESTRICT_ENV_SETEXTRAGROUPS, extra_groups);
+
+	if (first_valid_gid != 0)
+		renv_add(env, RESTRICT_ENV_GID_FIRST, dec2str(first_valid_gid));
+	if (last_valid_gid != 0)
+		renv_add(env, RESTRICT_ENV_GID_LAST, dec2str(last_valid_gid));
 }
 
 static gid_t *get_groups_list(unsigned int *gid_count_r)
@@ -53,7 +77,8 @@ static gid_t *get_groups_list(unsigned i
 	return gid_list;
 }
 
-static bool drop_restricted_groups(gid_t *gid_list, unsigned int *gid_count,
+static bool drop_restricted_groups(const char *const *env_values,
+				   gid_t *gid_list, unsigned int *gid_count,
 				   bool *have_root_group)
 {
 	/* @UNSAFE */
@@ -61,9 +86,9 @@ static bool drop_restricted_groups(gid_t
 	const char *env;
 	unsigned int i, used;
 
-	env = getenv("RESTRICT_GID_FIRST");
+	env = env_values[RESTRICT_ENV_GID_FIRST];
 	first_valid = env == NULL ? 0 : (gid_t)strtoul(env, NULL, 10);
-	env = getenv("RESTRICT_GID_LAST");
+	env = env_values[RESTRICT_ENV_GID_LAST];
 	last_valid = env == NULL ? (gid_t)-1 : (gid_t)strtoul(env, NULL, 10);
 
 	for (i = 0, used = 0; i < *gid_count; i++) {
@@ -93,19 +118,20 @@ static gid_t get_group_id(const char *na
 	return group->gr_gid;
 }
 
-static void fix_groups_list(const char *extra_groups, gid_t egid,
+static void fix_groups_list(const char *const *env_values, gid_t egid,
 			    bool preserve_existing, bool *have_root_group)
 {
 	gid_t *gid_list;
-	const char *const *tmp, *empty = NULL;
+	const char *const *tmp, *extra_groups, *empty = NULL;
 	unsigned int gid_count;
 
+	extra_groups = env_values[RESTRICT_ENV_SETEXTRAGROUPS];
 	tmp = extra_groups == NULL ? &empty :
 		t_strsplit_spaces(extra_groups, ", ");
 
 	if (preserve_existing) {
 		gid_list = get_groups_list(&gid_count);
-		if (!drop_restricted_groups(gid_list, &gid_count,
+		if (!drop_restricted_groups(env_values, gid_list, &gid_count,
 					    have_root_group) &&
 		    *tmp == NULL) {
 			/* nothing dropped, no extra groups to grant. */
@@ -135,17 +161,40 @@ static void fix_groups_list(const char *
 	}
 }
 
-void restrict_access_by_env(bool disallow_root)
-{
-	const char *env;
+void restrict_access_by_env(ARRAY_TYPE(const_string) *envarr,
+			    bool disallow_root)
+{
+	const char *env_values[RESTRICT_ENV_COUNT], *const *envs, *env;
+	const char *home = NULL;
+	unsigned int i, j, count, len;
 	gid_t gid;
 	uid_t uid;
 	bool is_root, have_root_group, preserve_groups = FALSE;
 
+	if (envarr == NULL) {
+		/* use environment */
+		for (i = 0; i < RESTRICT_ENV_COUNT; i++)
+			env_values[i] = getenv(restrict_env_strings[i]);
+		home = getenv("HOME");
+	} else {
+		envs = array_get(envarr, &count);
+		memset(env_values, 0, sizeof(env_values));
+		for (i = 0; i < count; i++) {
+			for (j = 0; j < RESTRICT_ENV_COUNT; j++) {
+				len = strlen(restrict_env_strings[j]);
+				if (strncmp(envs[i], restrict_env_strings[j],
+					    len) == 0 &&
+				    envs[i][len] == '=')
+					env_values[j] = envs[i] + len + 1;
+			}
+			if (strncmp(envs[i], "HOME=", 5) == 0)
+				home = envs[i] + 5;
+		}
+	}
 	is_root = geteuid() == 0;
 
 	/* set the primary group */
-	env = getenv("RESTRICT_SETGID");
+	env = env_values[RESTRICT_ENV_SETGID];
 	gid = env == NULL || *env == '\0' ? (gid_t)-1 :
 		(gid_t)strtoul(env, NULL, 10);
 	have_root_group = gid == 0;
@@ -158,7 +207,7 @@ void restrict_access_by_env(bool disallo
 	}
 
 	/* set system user's groups */
-	env = getenv("RESTRICT_USER");
+	env = env_values[RESTRICT_ENV_USER];
 	if (env != NULL && *env != '\0' && is_root) {
 		if (initgroups(env, gid) < 0) {
 			i_fatal("initgroups(%s, %s) failed: %m",
@@ -169,20 +218,18 @@ void restrict_access_by_env(bool disallo
 
 	/* add extra groups. if we set system user's groups, drop the
 	   restricted groups at the same time. */
-	env = getenv("RESTRICT_SETEXTRAGROUPS");
 	if (is_root) {
 		T_FRAME(
-			fix_groups_list(env, gid, preserve_groups,
+			fix_groups_list(env_values, gid, preserve_groups,
 					&have_root_group);
 		);
 	}
 
 	/* chrooting */
-	env = getenv("RESTRICT_CHROOT");
+	env = env_values[RESTRICT_ENV_CHROOT];
 	if (env != NULL && *env != '\0') {
 		/* kludge: localtime() must be called before chroot(),
 		   or the timezone isn't known */
-		const char *home = getenv("HOME");
 		time_t t = 0;
 		(void)localtime(&t);
 
@@ -202,7 +249,7 @@ void restrict_access_by_env(bool disallo
 	}
 
 	/* uid last */
-	env = getenv("RESTRICT_SETUID");
+	env = env_values[RESTRICT_ENV_SETUID];
 	uid = env == NULL || *env == '\0' ? 0 : (uid_t)strtoul(env, NULL, 10);
 	if (uid != 0) {
 		if (setuid(uid) != 0) {
@@ -220,7 +267,7 @@ void restrict_access_by_env(bool disallo
 		}
 	}
 
-	env = getenv("RESTRICT_GID_FIRST");
+	env = env_values[RESTRICT_ENV_GID_FIRST];
 	if ((!have_root_group || (env != NULL && atoi(env) != 0)) && uid != 0) {
 		if (getgid() == 0 || getegid() == 0 || setgid(0) == 0) {
 			if (gid == 0)
@@ -230,13 +277,4 @@ void restrict_access_by_env(bool disallo
 				dec2str(getgid()), dec2str(getegid()));
 		}
 	}
-
-	/* clear the environment, so we don't fail if we get back here */
-	env_put("RESTRICT_USER=");
-	env_put("RESTRICT_CHROOT=");
-	env_put("RESTRICT_SETUID=");
-	env_put("RESTRICT_SETGID=");
-	env_put("RESTRICT_SETEXTRAGROUPS=");
-	env_put("RESTRICT_GID_FIRST=");
-	env_put("RESTRICT_GID_LAST=");
-}
+}
diff -r c8878d66c4a1 -r 59ac3628b8d8 src/lib/restrict-access.h
--- a/src/lib/restrict-access.h	Wed Jan 02 01:35:21 2008 +0200
+++ b/src/lib/restrict-access.h	Wed Jan 02 01:36:51 2008 +0200
@@ -3,14 +3,17 @@
 
 /* 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,
+void restrict_access_set_env(ARRAY_TYPE(const_string) *env,
+			     const char *user, uid_t uid, gid_t gid,
 			     const char *chroot_dir,


More information about the dovecot-cvs mailing list