]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Added mail_extra_groups setting.
authorTimo Sirainen <tss@iki.fi>
Wed, 16 Jun 2004 02:04:01 +0000 (05:04 +0300)
committerTimo Sirainen <tss@iki.fi>
Wed, 16 Jun 2004 02:04:01 +0000 (05:04 +0300)
--HG--
branch : HEAD

dovecot-example.conf
src/lib/restrict-access.c
src/lib/restrict-access.h
src/master/auth-process.c
src/master/login-process.c
src/master/mail-process.c
src/master/master-settings.c
src/master/master-settings.h

index d46e345cb85644da9dc18ee97fafa2639519a3c8..464ef6ceb1fe1b53032284824a63e6d9453f381f 100644 (file)
 #first_valid_gid = 1
 #last_valid_gid = 0
 
+# Grant access to these extra groups for mail processes. Typical use would be
+# to give "mail" group write access to /var/mail to be able to create dotlocks.
+#mail_extra_groups =
+
 # ':' separated list of directories under which chrooting is allowed for mail
 # processes (ie. /var/mail will allow chrooting to /var/mail/foo/bar too).
 # This setting doesn't affect login_chroot or auth_chroot variables.
index 032ede4fea243edc4ecee32ae63cf5a73625e672..8831f20b6f69ae9c38bf3d3c84f6497ecc9aa61c 100644 (file)
@@ -17,7 +17,8 @@
 
 void restrict_access_set_env(const char *user, uid_t uid, gid_t gid,
                             const char *chroot_dir,
-                            gid_t first_valid_gid, gid_t last_valid_gid)
+                            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));
@@ -26,6 +27,10 @@ void restrict_access_set_env(const char *user, uid_t uid, gid_t gid,
 
        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",
@@ -37,12 +42,34 @@ void restrict_access_set_env(const char *user, uid_t uid, gid_t gid,
        }
 }
 
+static gid_t *get_groups_list(int *gid_count_r)
+{
+       /* @UNSAFE */
+       gid_t *gid_list;
+       int ret, gid_count;
+
+       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);
+       }
+       t_buffer_alloc(sizeof(gid_t) * ret);
+
+       *gid_count_r = ret;
+       return gid_list;
+}
+
 static void drop_restricted_groups(void)
 {
        /* @UNSAFE */
        const char *env;
        gid_t *gid_list, first_valid_gid, last_valid_gid;
-       int ret, i, gid_count;
+       int i, used, gid_count;
 
        env = getenv("RESTRICT_GID_FIRST");
        first_valid_gid = env == NULL ? 0 : (gid_t)atol(env);
@@ -52,29 +79,58 @@ static void drop_restricted_groups(void)
        if (first_valid_gid == 0 && last_valid_gid == 0)
                return;
 
-       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);
-       }
+       t_push();
+       gid_list = get_groups_list(&gid_count);
 
-       gid_count = 0;
-       for (i = 0; i < ret; i++) {
+       for (i = 0, used = 0; i < gid_count; 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];
+                       gid_list[used++] = gid_list[i];
        }
 
-       if (ret != gid_count) {
-               /* it did contain 0, remove it */
+       if (used != gid_count) {
+               /* it did contain restricted groups, remove it */
                if (setgroups(gid_count, gid_list) < 0)
                        i_fatal("setgroups() failed: %m");
        }
+       t_pop();
+}
+
+static gid_t get_group_id(const char *name)
+{
+       struct group *group;
+
+       if (is_numeric(name, '\0'))
+               return (gid_t)atol(name);
+
+       group = getgrnam(name);
+       if (group == NULL)
+               i_fatal("unknown group name in extra_groups: %s", name);
+       return group->gr_gid;
+}
+
+static void grant_extra_groups(const char *groups)
+{
+       const char *const *tmp;
+       gid_t *gid_list;
+       int gid_count;
+
+       t_push();
+       tmp = t_strsplit(groups, ", ");
+       gid_list = get_groups_list(&gid_count);
+       for (; *tmp != NULL; tmp++) {
+               if (**tmp == '\0')
+                       continue;
+
+               if (!t_try_realloc(gid_list, (gid_count+1) * sizeof(gid_t)))
+                       i_panic("won't happen");
+               gid_list[gid_count++] = get_group_id(*tmp);
+       }
+
+       if (setgroups(gid_count, gid_list) < 0)
+               i_fatal("setgroups() failed: %m");
+
+       t_pop();
 }
 
 void restrict_access_by_env(int disallow_root)
@@ -109,9 +165,14 @@ void restrict_access_by_env(int disallow_root)
                }
        }
 
+       /* grant additional groups to process */
+       env = getenv("RESTRICT_SETEXTRAGROUPS");
+       if (env != NULL && *env != '\0')
+               grant_extra_groups(env);
+
        /* chrooting */
        env = getenv("RESTRICT_CHROOT");
-       if (env != NULL) {
+       if (env != NULL && *env != '\0') {
                /* kludge: localtime() must be called before chroot(),
                   or the timezone isn't known */
                time_t t = 0;
@@ -142,4 +203,13 @@ void restrict_access_by_env(int disallow_root)
                if (getgid() == 0 || getegid() == 0 || setgid(0) == 0)
                        i_fatal("We couldn't drop root group privileges");
        }
+
+       /* 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=");
 }
index b3ea5d7b770e97c3cd58f395d01069259ddf75a6..9c4b11381c5f0a635b759cad3497ea877854546d 100644 (file)
@@ -5,7 +5,8 @@
    restrict_access_by_env() */
 void restrict_access_set_env(const char *user, uid_t uid, gid_t gid,
                             const char *chroot_dir,
-                            gid_t first_valid_gid, gid_t last_valid_gid);
+                            gid_t first_valid_gid, gid_t last_valid_gid,
+                            const char *extra_groups);
 
 /* chroot, setuid() and setgid() based on environment variables.
    If disallow_roots is TRUE, we'll kill ourself if we didn't have the
index a444bb8d159405b2a01fceaa8cc91ddecf920bf1..e281f34b7cbb3f107aeb6fa8d1c625ce7281cd02 100644 (file)
@@ -324,7 +324,8 @@ static pid_t create_auth_process(struct auth_process_group *group)
 
        /* setup access environment */
        restrict_access_set_env(group->set->user, group->set->uid,
-                               group->set->gid, group->set->chroot, 0, 0);
+                               group->set->gid, group->set->chroot,
+                               0, 0, NULL);
 
        /* set other environment */
        env_put(t_strconcat("AUTH_PROCESS=", dec2str(getpid()), NULL));
index f3a48bb35505936aee34a699e4edd77ead89dbbd..9defa05ec621b6e2eda631cc1ddb23d53b716ed5 100644 (file)
@@ -383,7 +383,7 @@ static void login_process_init_env(struct login_group *group, pid_t pid)
        restrict_access_set_env(set->login_user, set->login_uid,
                                set->server->login_gid,
                                set->login_chroot ? set->login_dir : NULL,
-                               0, 0);
+                               0, 0, NULL);
 
        env_put("DOVECOT_MASTER=1");
 
index 0831e720aeebbe1f9cb530dd44f1258a5fae3236..75ee0c7921dc37b2d4eddb55311c94dff054c1c0 100644 (file)
@@ -268,7 +268,8 @@ int create_mail_process(struct login_group *group, int socket,
           (paranoia about filling up environment without noticing) */
        restrict_access_set_env(data + reply->system_user_idx,
                                reply->uid, reply->gid, chroot_dir,
-                               set->first_valid_gid, set->last_valid_gid);
+                               set->first_valid_gid, set->last_valid_gid,
+                               set->mail_extra_groups);
 
        restrict_process_size(group->set->mail_process_size, (unsigned int)-1);
 
index c1f15ef428213170a4458ea4ea5193368a49d462..88c2f9841ec236f96d319b5f58af1a8442f41d6f 100644 (file)
@@ -79,6 +79,7 @@ static struct setting_def setting_defs[] = {
        DEF(SET_INT, last_valid_uid),
        DEF(SET_INT, first_valid_gid),
        DEF(SET_INT, last_valid_gid),
+       DEF(SET_STR, mail_extra_groups),
 
        DEF(SET_STR, default_mail_env),
        DEF(SET_STR, mail_cache_fields),
@@ -210,6 +211,7 @@ struct settings default_settings = {
        MEMBER(last_valid_uid) 0,
        MEMBER(first_valid_gid) 1,
        MEMBER(last_valid_gid) 0,
+       MEMBER(mail_extra_groups) NULL,
 
        MEMBER(default_mail_env) NULL,
        MEMBER(mail_cache_fields) "MessagePart",
index 2dfa36d22fdd9de9c993187c73ad55a78ed62952..7d8199c72f8e44573dbb1454850714007df89ed3 100644 (file)
@@ -54,6 +54,7 @@ struct settings {
 
        unsigned int first_valid_uid, last_valid_uid;
        unsigned int first_valid_gid, last_valid_gid;
+       const char *mail_extra_groups;
 
        const char *default_mail_env;
        const char *mail_cache_fields;