restrict-access.c revision b6afd653db20e6939bc392e1a8597e29e49f815a
/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
#define _GNU_SOURCE /* setresgid() */
#include <stdio.h> /* for AIX */
#include <unistd.h>
#include "lib.h"
#include "restrict-access.h"
#include "env-util.h"
#include <stdlib.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
static bool process_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) {
}
}
{
const char *ret;
else
return ret;
}
{
const char *ret;
else
return ret;
}
{
/* 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
if (geteuid() == 0) {
/* real, effective, saved -> privileged_gid */
if (setgid(privileged_gid) < 0) {
i_fatal("setgid(%s) failed: %m",
}
}
/* real, effective -> primary_gid
saved -> keep */
i_fatal("setregid(%s,%s) failed with euid=%s: %m",
get_uid_str(geteuid()));
}
#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;
}
}
}
{
}
static void fix_groups_list(const char *extra_groups,
bool preserve_existing, bool *have_root_group)
{
unsigned int i, gid_count;
bool add_primary_gid;
/* if we're using a privileged GID, we can temporarily drop our
effective GID. we still want to be able to use its privileges,
so add it to supplementary groups. */
if (preserve_existing) {
/* see if the list already contains the primary GID */
for (i = 0; i < gid_count; i++) {
if (gid_list[i] == process_primary_gid) {
break;
}
}
} else {
gid_count = 0;
}
if (gid_count == 0) {
/* Some OSes don't like an empty groups list,
so use the primary GID as the only one. */
gid_list[0] = process_primary_gid;
gid_count = 1;
}
if (gid != process_primary_gid)
}
if (add_primary_gid)
}
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 = process_primary_gid == 0;
} else {
}
/* 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. */
} 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 (process_primary_gid == 0 || process_privileged_gid == 0)
else
if (!allow_root_gid && uid != 0) {
if (process_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(process_privileged_gid) < 0) {
i_error("setegid(privileged) failed: %m");
return -1;
}
return 0;
}
void restrict_access_drop_priv_gid(void)
{
if (!process_using_priv_gid)
return;
if (setegid(process_primary_gid) < 0)
i_fatal("setegid(primary) failed: %m");
}
bool restrict_access_have_priv_gid(void)
{
}