restrict-access.c revision 7f97ca94363c9e38fbbaaef204d6d01c54af6fc4
/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
#define _GNU_SOURCE /* setresgid() */
#include <unistd.h>
#include "lib.h"
#include "restrict-access.h"
#include "env-util.h"
#include <stdlib.h>
#include <time.h>
#include <grp.h>
static bool using_priv_gid = FALSE;
const char *chroot_dir,
const char *extra_groups)
{
}
extra_groups, NULL));
}
if (first_valid_gid != 0) {
}
if (last_valid_gid != 0) {
}
}
{
/* everything is already set */
return;
}
if (setgid(primary_gid) != 0) {
i_fatal("setgid(%s) failed with euid=%s, "
"gid=%s, egid=%s: %m",
}
return;
}
primary_gid == getegid()) {
/* privileged_gid is hopefully in saved ID. if not,
there's nothing we can do about it. */
return;
}
#ifdef HAVE_SETRESGID
i_fatal("setresgid(%s,%s,%s) failed with euid=%s: %m",
}
#else
/* real: primary_gid
effective: privileged_gid
saved: privileged_gid */
i_fatal("setregid(%s,%s) failed with euid=%s: %m",
}
/* effective: privileged_gid -> primary_gid */
if (setegid(privileged_gid) != 0) {
i_fatal("setegid(%s) failed with euid=%s: %m",
}
#endif
}
{
i_fatal("getgroups() failed: %m");
/* @UNSAFE */
i_fatal("getgroups() failed: %m");
*gid_count_r = ret;
return gid_list;
}
bool *have_root_group)
{
/* @UNSAFE */
const char *env;
unsigned int i, used;
if (gid_list[i] >= first_valid &&
if (gid_list[i] == 0)
*have_root_group = TRUE;
}
}
return FALSE;
return TRUE;
}
{
}
bool preserve_existing, bool *have_root_group)
{
unsigned int gid_count;
if (preserve_existing) {
have_root_group) &&
/* nothing dropped, no extra groups to grant. */
return;
}
} else {
/* nothing to do */
return;
}
/* Some OSes don't like an empty groups list,
so use the effective GID as the only one. */
gid_count = 1;
}
/* @UNSAFE: add extra groups to gids list */
}
i_fatal("setgroups(%s) failed: Too many extra groups",
} else {
i_fatal("setgroups() failed: %m");
}
}
}
void restrict_access_by_env(bool disallow_root)
{
const char *env;
bool allow_root_gid;
/* set the primary/privileged group */
have_root_group = primary_gid == 0;
primary_gid = getegid();
}
/* set system user's groups */
i_fatal("initgroups(%s, %s) failed: %m",
}
}
/* add extra groups. if we set system user's groups, drop the
restricted groups at the same time. */
if (is_root) {
T_BEGIN {
} T_END;
}
/* chrooting */
/* kludge: localtime() must be called before chroot(),
or the timezone isn't known */
time_t t = 0;
(void)localtime(&t);
}
}
if (chdir("/") != 0)
i_fatal("chdir(/) failed: %m");
}
}
/* uid last */
if (uid != 0) {
i_fatal("setuid(%s) failed with euid=%s: %m",
}
}
/* verify that we actually dropped the privileges */
if (uid != 0 || disallow_root) {
if (setuid(0) == 0) {
if (uid == 0)
i_fatal("Running as root isn't permitted");
i_fatal("We couldn't drop root privileges");
}
}
else if (primary_gid == 0 || privileged_gid == 0)
else
if (!allow_root_gid && uid != 0) {
if (primary_gid == 0)
i_fatal("GID 0 isn't permitted");
i_fatal("We couldn't drop root group privileges "
"(wanted=%s, gid=%s, egid=%s)",
}
}
/* 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=");
/* if we're dropping privileges before executing and
a privileged group is set, the groups must be fixed
after exec */
env_put("RESTRICT_SETGID=");
env_put("RESTRICT_SETGID_PRIV=");
}
env_put("RESTRICT_SETEXTRAGROUPS=");
env_put("RESTRICT_GID_FIRST=");
env_put("RESTRICT_GID_LAST=");
}
int restrict_access_use_priv_gid(void)
{
return 0;
if (setegid(privileged_gid) < 0) {
i_error("setegid(privileged) failed: %m");
return -1;
}
return 0;
}
void restrict_access_drop_priv_gid(void)
{
if (!using_priv_gid)
return;
if (setegid(primary_gid) < 0)
i_fatal("setegid(primary) failed: %m");
}
bool restrict_access_have_priv_gid(void)
{
}