dovecot-2.1: lib-storage: Handle %{uid} and %{gid} expansion wit...

dovecot at dovecot.org dovecot at dovecot.org
Mon Dec 12 06:38:43 EET 2011


details:   http://hg.dovecot.org/dovecot-2.1/rev/9352c4ccb1f9
changeset: 13848:9352c4ccb1f9
user:      Timo Sirainen <tss at iki.fi>
date:      Mon Dec 12 06:36:31 2011 +0200
description:
lib-storage: Handle %{uid} and %{gid} expansion without relying on process's euid/egid.

diffstat:

 src/lib-storage/mail-storage-service.c |  301 ++++++++++++++++++--------------
 src/lib-storage/mail-user.c            |    6 +-
 src/lib-storage/mail-user.h            |    4 +-
 3 files changed, 177 insertions(+), 134 deletions(-)

diffs (truncated from 477 to 300 lines):

diff -r 3c5fda349c1f -r 9352c4ccb1f9 src/lib-storage/mail-storage-service.c
--- a/src/lib-storage/mail-storage-service.c	Mon Dec 12 06:07:33 2011 +0200
+++ b/src/lib-storage/mail-storage-service.c	Mon Dec 12 06:36:31 2011 +0200
@@ -38,6 +38,15 @@
 #define ERRSTR_INVALID_USER_SETTINGS \
 	"Invalid user settings. Refer to server log for more information."
 
+struct mail_storage_service_privileges {
+	uid_t uid;
+	gid_t gid;
+	const char *uid_source, *gid_source;
+
+	const char *home;
+	const char *chroot;
+};
+
 struct mail_storage_service_ctx {
 	pool_t pool;
 	struct master_service *service;
@@ -348,13 +357,124 @@
 	}
 }
 
+static const struct var_expand_table *
+get_var_expand_table(struct master_service *service,
+		     struct mail_storage_service_input *input,
+		     struct mail_storage_service_privileges *priv)
+{
+	static struct var_expand_table static_tab[] = {
+		{ 'u', NULL, "user" },
+		{ 'n', NULL, "username" },
+		{ 'd', NULL, "domain" },
+		{ 's', NULL, "service" },
+		{ 'l', NULL, "lip" },
+		{ 'r', NULL, "rip" },
+		{ 'p', NULL, "pid" },
+		{ 'i', NULL, "uid" },
+		{ '\0', NULL, "gid" },
+		{ '\0', NULL, NULL }
+	};
+	struct var_expand_table *tab;
+
+	tab = t_malloc(sizeof(static_tab));
+	memcpy(tab, static_tab, sizeof(static_tab));
+
+	tab[0].value = input->username;
+	tab[1].value = t_strcut(input->username, '@');
+	tab[2].value = strchr(input->username, '@');
+	if (tab[2].value != NULL) tab[2].value++;
+	tab[3].value = service->name;
+	tab[4].value = net_ip2addr(&input->local_ip);
+	tab[5].value = net_ip2addr(&input->remote_ip);
+	tab[6].value = my_pid;
+	tab[7].value = dec2str(priv->uid == (uid_t)-1 ? geteuid() : priv->uid);
+	tab[8].value = dec2str(priv->gid == (gid_t)-1 ? getegid() : priv->gid);
+	return tab;
+}
+
+static const char *
+user_expand_varstr(struct master_service *service,
+		   struct mail_storage_service_input *input,
+		   struct mail_storage_service_privileges *priv,
+		   const char *str)
+{
+	string_t *ret;
+
+	if (*str == SETTING_STRVAR_EXPANDED[0])
+		return str + 1;
+
+	i_assert(*str == SETTING_STRVAR_UNEXPANDED[0]);
+
+	ret = t_str_new(256);
+	var_expand(ret, str + 1, get_var_expand_table(service, input, priv));
+	return str_c(ret);
+}
+
+static int
+service_parse_privileges(struct mail_storage_service_ctx *ctx,
+			 struct mail_storage_service_user *user,
+			 struct mail_storage_service_privileges *priv_r,
+			 const char **error_r)
+{
+	const struct mail_user_settings *set = user->user_set;
+	uid_t uid = (uid_t)-1;
+	gid_t gid = (gid_t)-1;
+
+	memset(priv_r, 0, sizeof(*priv_r));
+	if (*set->mail_uid != '\0') {
+		if (!parse_uid(set->mail_uid, &uid, error_r)) {
+			*error_r = t_strdup_printf("%s (from %s)", *error_r,
+						   user->uid_source);
+			return -1;
+		}
+		if (uid < (uid_t)set->first_valid_uid ||
+		    (set->last_valid_uid != 0 &&
+		     uid > (uid_t)set->last_valid_uid)) {
+			*error_r = t_strdup_printf(
+				"Mail access for users with UID %s not permitted "
+				"(see first_valid_uid in config file, uid from %s).",
+				dec2str(uid), user->uid_source);
+			return -1;
+		}
+	}
+	priv_r->uid = uid;
+	priv_r->uid_source = user->uid_source;
+
+	if (*set->mail_gid != '\0') {
+		if (!parse_gid(set->mail_gid, &gid, error_r)) {
+			*error_r = t_strdup_printf("%s (from %s)", *error_r,
+						   user->gid_source);
+			return -1;
+		}
+		if (gid < (gid_t)set->first_valid_gid ||
+		    (set->last_valid_gid != 0 &&
+		     gid > (gid_t)set->last_valid_gid)) {
+			*error_r = t_strdup_printf(
+				"Mail access for users with GID %s not permitted "
+				"(see first_valid_gid in config file, gid from %s).",
+				dec2str(gid), user->gid_source);
+			return -1;
+		}
+	}
+	priv_r->gid = gid;
+	priv_r->gid_source = user->gid_source;
+
+	/* variable strings are expanded in mail_user_init(),
+	   but we need the home and chroot sooner so do them separately here. */
+	priv_r->home = user_expand_varstr(ctx->service, &user->input, priv_r,
+					  user->user_set->mail_home);
+	priv_r->chroot = user_expand_varstr(ctx->service, &user->input, priv_r,
+					    user->user_set->mail_chroot);
+	return 0;
+}
+
 static int
 service_drop_privileges(struct mail_storage_service_user *user,
-			const struct mail_user_settings *set,
-			const char *home, const char *chroot,
+			struct mail_storage_service_privileges *priv,
 			bool disallow_root, bool keep_setuid_root,
 			bool setenv_only, const char **error_r)
 {
+	const struct mail_user_settings *set = user->user_set;
 	struct restrict_access_settings rset;
 	uid_t current_euid, setuid_uid = 0;
 	const char *cur_chroot, *error;
@@ -362,43 +482,17 @@
 	current_euid = geteuid();
 	restrict_access_init(&rset);
 	restrict_access_get_env(&rset);
-	if (*set->mail_uid != '\0') {
-		if (!parse_uid(set->mail_uid, &rset.uid, &error)) {
-			*error_r = t_strdup_printf("%s (from %s)", error,
-						   user->uid_source);
-			return -1;
-		}
-		if (rset.uid < (uid_t)set->first_valid_uid ||
-		    (set->last_valid_uid != 0 &&
-		     rset.uid > (uid_t)set->last_valid_uid)) {
-			*error_r = t_strdup_printf(
-				"Mail access for users with UID %s not permitted "
-				"(see first_valid_uid in config file, uid from %s).",
-				dec2str(rset.uid), user->uid_source);
-			return -1;
-		}
-		rset.uid_source = user->uid_source;
+	if (priv->uid != (uid_t)-1) {
+		rset.uid = priv->uid;
+		rset.uid_source = priv->uid_source;
 	} else if (rset.uid == (uid_t)-1 &&
-		   disallow_root && current_euid == 0) {
+		 disallow_root && current_euid == 0) {
 		*error_r = "User is missing UID (see mail_uid setting)";
 		return -1;
 	}
-	if (*set->mail_gid != '\0') {
-		if (!parse_gid(set->mail_gid, &rset.gid, &error)) {
-			*error_r = t_strdup_printf("%s (from %s)", error,
-						   user->gid_source);
-			return -1;
-		}
-		if (rset.gid < (gid_t)set->first_valid_gid ||
-		    (set->last_valid_gid != 0 &&
-		     rset.gid > (gid_t)set->last_valid_gid)) {
-			*error_r = t_strdup_printf(
-				"Mail access for users with GID %s not permitted "
-				"(see first_valid_gid in config file, gid from %s).",
-				dec2str(rset.gid), user->gid_source);
-			return -1;
-		}
-		rset.gid_source = user->gid_source;
+	if (priv->gid != (gid_t)-1) {
+		rset.gid = priv->gid;
+		rset.gid_source = priv->gid_source;
 	} else if (rset.gid == (gid_t)-1 && disallow_root &&
 		   set->first_valid_gid > 0 && getegid() == 0) {
 		*error_r = "User is missing GID (see mail_gid setting)";
@@ -419,7 +513,7 @@
 
 	rset.first_valid_gid = set->first_valid_gid;
 	rset.last_valid_gid = set->last_valid_gid;
-	rset.chroot_dir = *chroot == '\0' ? NULL : chroot;
+	rset.chroot_dir = *priv->chroot == '\0' ? NULL : priv->chroot;
 	rset.system_groups_user = user->system_groups_user;
 
 	cur_chroot = restrict_access_get_current_chroot();
@@ -433,7 +527,7 @@
 		if (strcmp(rset.chroot_dir, cur_chroot) != 0) {
 			*error_r = t_strdup_printf(
 				"Process is already chrooted to %s, "
-				"can't chroot to %s", cur_chroot, chroot);
+				"can't chroot to %s", cur_chroot, priv->chroot);
 			return -1;
 		}
 		/* chrooting to same directory where we're already chrooted */
@@ -460,7 +554,7 @@
 		disallow_root = FALSE;
 	}
 	if (!setenv_only) {
-		restrict_access(&rset, *home == '\0' ? NULL : home,
+		restrict_access(&rset, *priv->home == '\0' ? NULL : priv->home,
 				disallow_root);
 	} else {
 		restrict_access_set_env(&rset);
@@ -475,17 +569,21 @@
 static int
 mail_storage_service_init_post(struct mail_storage_service_ctx *ctx,
 			       struct mail_storage_service_user *user,
-			       const char *home, struct mail_user **mail_user_r,
+			       struct mail_storage_service_privileges *priv,
+			       struct mail_user **mail_user_r,
 			       const char **error_r)
 {
 	const struct mail_storage_settings *mail_set;
+	const char *home = priv->home;
 	struct mail_user *mail_user;
 
 	mail_user = mail_user_alloc(user->input.username, user->user_info,
 				    user->user_set);
 	mail_user_set_home(mail_user, *home == '\0' ? NULL : home);
-	mail_user_set_vars(mail_user, geteuid(), getegid(), ctx->service->name,
+	mail_user_set_vars(mail_user, ctx->service->name,
 			   &user->input.local_ip, &user->input.remote_ip);
+	mail_user->uid = priv->uid == (uid_t)-1 ? geteuid() : priv->uid;
+	mail_user->gid = priv->gid == (gid_t)-1 ? getegid() : priv->gid;
 
 	mail_set = mail_user_set_get_storage_set(mail_user);
 
@@ -528,54 +626,6 @@
 	return 0;
 }
 
-static const struct var_expand_table *
-get_var_expand_table(struct master_service *service,
-		     struct mail_storage_service_input *input)
-{
-	static struct var_expand_table static_tab[] = {
-		{ 'u', NULL, "user" },
-		{ 'n', NULL, "username" },
-		{ 'd', NULL, "domain" },
-		{ 's', NULL, "service" },
-		{ 'l', NULL, "lip" },
-		{ 'r', NULL, "rip" },
-		{ 'p', NULL, "pid" },
-		{ 'i', NULL, "uid" },
-		{ '\0', NULL, NULL }
-	};
-	struct var_expand_table *tab;
-
-	tab = t_malloc(sizeof(static_tab));
-	memcpy(tab, static_tab, sizeof(static_tab));
-
-	tab[0].value = input->username;
-	tab[1].value = t_strcut(input->username, '@');
-	tab[2].value = strchr(input->username, '@');
-	if (tab[2].value != NULL) tab[2].value++;
-	tab[3].value = service->name;
-	tab[4].value = net_ip2addr(&input->local_ip);
-	tab[5].value = net_ip2addr(&input->remote_ip);
-	tab[6].value = my_pid;
-	tab[7].value = dec2str(geteuid());
-	return tab;
-}
-
-static const char *
-user_expand_varstr(struct master_service *service,
-		   struct mail_storage_service_input *input, const char *str)
-{
-	string_t *ret;
-
-	if (*str == SETTING_STRVAR_EXPANDED[0])
-		return str + 1;
-
-	i_assert(*str == SETTING_STRVAR_UNEXPANDED[0]);
-
-	ret = t_str_new(256);
-	var_expand(ret, str + 1, get_var_expand_table(service, input));
-	return str_c(ret);
-}
-


More information about the dovecot-cvs mailing list