restrict-access.c revision e8c0c0ba05a76410ef908ab5b694559d25f98ae7
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic gid_t process_privileged_gid = (gid_t)-1;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenvoid restrict_access_init(struct restrict_access_settings *set)
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen const char *ret;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen ret = t_strdup_printf("%s(%s)", dec2str(uid), pw->pw_name);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen const char *ret;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen ret = t_strdup_printf("%s(%s)", dec2str(gid), group->gr_name);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainenstatic void restrict_init_groups(gid_t primary_gid, gid_t privileged_gid)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (primary_gid == getgid() && primary_gid == getegid()) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* everything is already set */
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen "euid=%s, gid=%s, egid=%s: %m "
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "(This binary should probably be called with "
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "process group set to %s instead of %s)",
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen get_gid_str(primary_gid), get_uid_str(geteuid()),
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen get_gid_str(getgid()), get_gid_str(getegid()),
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen get_gid_str(primary_gid), get_uid_str(geteuid()));
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen if (getegid() != 0 && primary_gid == getgid() &&
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* privileged_gid is hopefully in saved ID. if not,
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen there's nothing we can do about it. */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (setresgid(primary_gid, primary_gid, privileged_gid) != 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen i_fatal("setresgid(%s,%s,%s) failed with euid=%s: %m",
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen get_gid_str(primary_gid), get_gid_str(primary_gid),
b04e691711fd026fc82ba3e0b411420e7da4ec7eTimo Sirainen get_gid_str(privileged_gid), get_uid_str(geteuid()));
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (geteuid() == 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* real, effective, saved -> privileged_gid */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* real, effective -> primary_gid
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen saved -> keep */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (setregid(primary_gid, primary_gid) != 0) {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen i_fatal("setregid(%s,%s) failed with euid=%s: %m",
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen get_gid_str(primary_gid), get_gid_str(privileged_gid),
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainengid_t *restrict_get_groups_list(unsigned int *gid_count_r)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen /* @UNSAFE */
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if ((ret = getgroups(gid_count, gid_list)) < 0)
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainenstatic void drop_restricted_groups(const struct restrict_access_settings *set,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen /* @UNSAFE */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen unsigned int i, used;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen i_fatal("unknown group name in extra_groups: %s", name);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic void fix_groups_list(const struct restrict_access_settings *set,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen bool preserve_existing, bool *have_root_group)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen unsigned int i, gid_count;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* if we're using a privileged GID, we can temporarily drop our
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen effective GID. we still want to be able to use its privileges,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen so add it to supplementary groups. */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen add_primary_gid = process_privileged_gid != (gid_t)-1;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen gid_list = restrict_get_groups_list(&gid_count);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen drop_restricted_groups(set, gid_list, &gid_count,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* see if the list already contains the primary GID */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen for (i = 0; i < gid_count; i++) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* Some OSes don't like an empty groups list,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen so use the primary GID as the only one. */
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen /* @UNSAFE: add extra groups and/or primary GID to gids list */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen gid_list2 = t_new(gid_t, gid_count + str_array_length(tmp) + 1);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen memcpy(gid_list2, gid_list, gid_count * sizeof(gid_t));
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen i_fatal("setgroups(%s) failed: Too many extra groups",
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenvoid restrict_access(const struct restrict_access_settings *set,
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen bool is_root, have_root_group, preserve_groups = FALSE;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* set the primary/privileged group */
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen /* set system user's groups */
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen if (set->system_groups_user != NULL && is_root) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* add extra groups. if we set system user's groups, drop the
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen restricted groups at the same time. */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* chrooting */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* kludge: localtime() must be called before chroot(),
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen or the timezone isn't known */
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen i_fatal("chroot(%s) failed: %m", set->chroot_dir);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* uid last */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "(This binary should probably be called with "
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "process user set to %s instead of %s)",
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen get_uid_str(set->uid), get_uid_str(geteuid()),
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen get_uid_str(set->uid), get_uid_str(geteuid()));
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* verify that we actually dropped the privileges */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if ((set->uid != (uid_t)-1 && set->uid != 0) || disallow_root) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (setuid(0) == 0) {
if (disallow_root &&
if (process_primary_gid == 0)
const char *value;
const char *restrict_access_get_current_chroot(void)
return chroot_dir;
#ifdef HAVE_PR_SET_DUMPABLE
int restrict_access_use_priv_gid(void)
void restrict_access_drop_priv_gid(void)
if (!process_using_priv_gid)
bool restrict_access_have_priv_gid(void)