restrict-access.c revision 0c450f355c18905dd18d1559bf815d6b6332cd26
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#define _GNU_SOURCE /* setresgid() */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include <sys/types.h>
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include <unistd.h>
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "lib.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "restrict-access.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "env-util.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include <stdlib.h>
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include <time.h>
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include <grp.h>
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic gid_t primary_gid = (gid_t)-1, privileged_gid = (gid_t)-1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic bool using_priv_gid = FALSE;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosevoid restrict_access_set_env(const char *user, uid_t uid,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose gid_t gid, gid_t privileged_gid,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose const char *chroot_dir,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose gid_t first_valid_gid, gid_t last_valid_gid,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose const char *extra_groups)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (user != NULL && *user != '\0')
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env_put(t_strconcat("RESTRICT_USER=", user, NULL));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (chroot_dir != NULL && *chroot_dir != '\0')
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env_put(t_strconcat("RESTRICT_CHROOT=", chroot_dir, NULL));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env_put(t_strdup_printf("RESTRICT_SETUID=%s", dec2str(uid)));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env_put(t_strdup_printf("RESTRICT_SETGID=%s", dec2str(gid)));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (privileged_gid != (gid_t)-1) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env_put(t_strdup_printf("RESTRICT_SETGID_PRIV=%s",
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose dec2str(privileged_gid)));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (extra_groups != NULL && *extra_groups != '\0') {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env_put(t_strconcat("RESTRICT_SETEXTRAGROUPS=",
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose extra_groups, NULL));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (first_valid_gid != 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env_put(t_strdup_printf("RESTRICT_GID_FIRST=%s",
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose dec2str(first_valid_gid)));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (last_valid_gid != 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env_put(t_strdup_printf("RESTRICT_GID_LAST=%s",
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose dec2str(last_valid_gid)));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic void restrict_init_groups(gid_t primary_gid, gid_t privileged_gid)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (privileged_gid == (gid_t)-1) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (primary_gid == getgid() && primary_gid == getegid()) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* everything is already set */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (setgid(primary_gid) != 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_fatal("setgid(%s) failed with euid=%s, "
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose "gid=%s, egid=%s: %m",
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov dec2str(primary_gid), dec2str(geteuid()),
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose dec2str(getgid()), dec2str(getegid()));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (getegid() != 0 && primary_gid == getgid() &&
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov primary_gid == getegid()) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* privileged_gid is hopefully in saved ID. if not,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose there's nothing we can do about it. */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#ifdef HAVE_SETRESGID
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (setresgid(primary_gid, primary_gid, privileged_gid) != 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_fatal("setresgid(%s,%s,%s) failed with euid=%s: %m",
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose dec2str(primary_gid), dec2str(primary_gid),
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose dec2str(privileged_gid), dec2str(geteuid()));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#else
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* real: primary_gid
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose effective: privileged_gid
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose saved: privileged_gid */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (setregid(primary_gid, privileged_gid) != 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_fatal("setregid(%s,%s) failed with euid=%s: %m",
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov dec2str(primary_gid), dec2str(privileged_gid),
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose dec2str(geteuid()));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* effective: privileged_gid -> primary_gid */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (setegid(privileged_gid) != 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_fatal("setegid(%s) failed with euid=%s: %m",
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose dec2str(privileged_gid), dec2str(geteuid()));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#endif
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic gid_t *get_groups_list(unsigned int *gid_count_r)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose gid_t *gid_list;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose int ret, gid_count;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if ((gid_count = getgroups(0, NULL)) < 0)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_fatal("getgroups() failed: %m");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* @UNSAFE */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose gid_list = t_new(gid_t, gid_count);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if ((ret = getgroups(gid_count, gid_list)) < 0)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov i_fatal("getgroups() failed: %m");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose *gid_count_r = ret;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return gid_list;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic bool drop_restricted_groups(gid_t *gid_list, unsigned int *gid_count,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose bool *have_root_group)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov{
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* @UNSAFE */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose gid_t first_valid, last_valid;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose const char *env;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov unsigned int i, used;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env = getenv("RESTRICT_GID_FIRST");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose first_valid = env == NULL ? 0 : (gid_t)strtoul(env, NULL, 10);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env = getenv("RESTRICT_GID_LAST");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose last_valid = env == NULL ? (gid_t)-1 : (gid_t)strtoul(env, NULL, 10);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov for (i = 0, used = 0; i < *gid_count; i++) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (gid_list[i] >= first_valid &&
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose (last_valid == (gid_t)-1 || gid_list[i] <= last_valid)) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (gid_list[i] == 0)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose *have_root_group = TRUE;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose gid_list[used++] = gid_list[i];
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (*gid_count == used)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return FALSE;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose *gid_count = used;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov return TRUE;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic gid_t get_group_id(const char *name)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose struct group *group;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (is_numeric(name, '\0'))
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov return (gid_t)strtoul(name, NULL, 10);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose group = getgrnam(name);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (group == NULL)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_fatal("unknown group name in extra_groups: %s", name);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return group->gr_gid;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashovstatic void fix_groups_list(const char *extra_groups, gid_t egid,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose bool preserve_existing, bool *have_root_group)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose gid_t *gid_list, *gid_list2;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose const char *const *tmp, *empty = NULL;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose unsigned int gid_count;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose tmp = extra_groups == NULL ? &empty :
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose t_strsplit_spaces(extra_groups, ", ");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (preserve_existing) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose gid_list = get_groups_list(&gid_count);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (!drop_restricted_groups(gid_list, &gid_count,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose have_root_group) &&
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose *tmp == NULL) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* nothing dropped, no extra groups to grant. */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose } else {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (egid == (gid_t)-1 && *tmp == NULL) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* nothing to do */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* Some OSes don't like an empty groups list,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose so use the effective GID as the only one. */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose gid_list = t_new(gid_t, 2);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose gid_list[0] = egid != (gid_t)-1 ? egid : getegid();
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose gid_count = 1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (*tmp != NULL) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* @UNSAFE: add extra groups to gids list */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose gid_list2 = t_new(gid_t, gid_count + str_array_length(tmp));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose memcpy(gid_list2, gid_list, gid_count * sizeof(gid_t));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose for (; *tmp != NULL; tmp++)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose gid_list2[gid_count++] = get_group_id(*tmp);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose gid_list = gid_list2;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (setgroups(gid_count, gid_list) < 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (errno == EINVAL) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_fatal("setgroups(%s) failed: Too many extra groups",
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose extra_groups == NULL ? "" : extra_groups);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose } else {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_fatal("setgroups() failed: %m");
b3292840ebaa747a9fd596ff47cc5d18198361d0Michal Zidek }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosevoid restrict_access_by_env(bool disallow_root)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose const char *env;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov uid_t uid;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov bool is_root, have_root_group, preserve_groups = FALSE;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose bool allow_root_gid;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose is_root = geteuid() == 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* set the primary/privileged group */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env = getenv("RESTRICT_SETGID");
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov primary_gid = env == NULL || *env == '\0' ? (gid_t)-1 :
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose (gid_t)strtoul(env, NULL, 10);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env = getenv("RESTRICT_SETGID_PRIV");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose privileged_gid = env == NULL || *env == '\0' ? (gid_t)-1 :
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose (gid_t)strtoul(env, NULL, 10);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose have_root_group = primary_gid == 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (primary_gid != (gid_t)-1 || privileged_gid != (gid_t)-1) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (primary_gid == (gid_t)-1)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose primary_gid = getegid();
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose restrict_init_groups(primary_gid, privileged_gid);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* set system user's groups */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov env = getenv("RESTRICT_USER");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (env != NULL && *env != '\0' && is_root) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (initgroups(env, primary_gid) < 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_fatal("initgroups(%s, %s) failed: %m",
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env, dec2str(primary_gid));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose preserve_groups = TRUE;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov }
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* add extra groups. if we set system user's groups, drop the
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose restricted groups at the same time. */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env = getenv("RESTRICT_SETEXTRAGROUPS");
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (is_root) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose T_BEGIN {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose fix_groups_list(env, primary_gid, preserve_groups,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose &have_root_group);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose } T_END;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* chrooting */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov env = getenv("RESTRICT_CHROOT");
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (env != NULL && *env != '\0') {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* kludge: localtime() must be called before chroot(),
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose or the timezone isn't known */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose const char *home = getenv("HOME");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose time_t t = 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose (void)localtime(&t);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (chroot(env) != 0)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_fatal("chroot(%s) failed: %m", env);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (home != NULL) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (chdir(home) < 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_error("chdir(%s) failed: %m", home);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov home = NULL;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (home == NULL) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (chdir("/") != 0)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_fatal("chdir(/) failed: %m");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* uid last */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env = getenv("RESTRICT_SETUID");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose uid = env == NULL || *env == '\0' ? 0 : (uid_t)strtoul(env, NULL, 10);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (uid != 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (setuid(uid) != 0) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov i_fatal("setuid(%s) failed with euid=%s: %m",
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose dec2str(uid), dec2str(geteuid()));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* verify that we actually dropped the privileges */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (uid != 0 || disallow_root) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (setuid(0) == 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (uid == 0)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov i_fatal("Running as root isn't permitted");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_fatal("We couldn't drop root privileges");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env = getenv("RESTRICT_GID_FIRST");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (env != NULL && atoi(env) != 0)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose allow_root_gid = FALSE;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose else if (primary_gid == 0 || privileged_gid == 0)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov allow_root_gid = TRUE;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose else
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose allow_root_gid = FALSE;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (!allow_root_gid && uid != 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (getgid() == 0 || getegid() == 0 || setgid(0) == 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (primary_gid == 0)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_fatal("GID 0 isn't permitted");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_fatal("We couldn't drop root group privileges "
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose "(wanted=%s, gid=%s, egid=%s)",
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose dec2str(primary_gid),
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose dec2str(getgid()), dec2str(getegid()));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* clear the environment, so we don't fail if we get back here */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env_put("RESTRICT_USER=");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env_put("RESTRICT_CHROOT=");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env_put("RESTRICT_SETUID=");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (privileged_gid == (gid_t)-1) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* if we're dropping privileges before executing and
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose a privileged group is set, the groups must be fixed
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose after exec */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env_put("RESTRICT_SETGID=");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env_put("RESTRICT_SETGID_PRIV=");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env_put("RESTRICT_SETEXTRAGROUPS=");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env_put("RESTRICT_GID_FIRST=");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose env_put("RESTRICT_GID_LAST=");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Boseint restrict_access_use_priv_gid(void)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov i_assert(!using_priv_gid);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (privileged_gid == (gid_t)-1)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (setegid(privileged_gid) < 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_error("setegid(privileged) failed: %m");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose using_priv_gid = TRUE;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosevoid restrict_access_drop_priv_gid(void)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (!using_priv_gid)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return;
d115f40c7a3999e3cbe705a2ff9cf0fd493f80fbMichal Zidek
d115f40c7a3999e3cbe705a2ff9cf0fd493f80fbMichal Zidek if (setegid(primary_gid) < 0)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_fatal("setegid(primary) failed: %m");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose using_priv_gid = FALSE;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov}
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosebool restrict_access_have_priv_gid(void)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return privileged_gid != (gid_t)-1;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose