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