restrict-access.c revision cdfc424ddf1c85f47d9c9b3a855cfdf1b985569a
/* Copyright (c) 2002-2009 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>
#ifdef HAVE_PR_SET_DUMPABLE
#endif
static bool process_using_priv_gid = FALSE;
{
set->first_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 */
unsigned int i, used;
if (gid_list[i] == 0)
*have_root_group = TRUE;
}
}
}
{
}
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",
set->extra_groups);
} else {
i_fatal("setgroups() failed: %m");
}
}
}
const char *home, bool disallow_root)
{
bool allow_root_gid;
/* set the primary/privileged group */
have_root_group = process_primary_gid == 0;
} else {
}
/* set system user's groups */
process_primary_gid) < 0) {
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 */
i_fatal("setuid(%s) failed with euid=%s: %m",
}
}
/* verify that we actually dropped the privileges */
if (setuid(0) == 0) {
if (disallow_root &&
i_fatal("This process must not be run as root");
i_fatal("We couldn't drop root privileges");
}
}
if (set->first_valid_gid != 0)
else if (process_primary_gid == 0 || process_privileged_gid == 0)
else
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)",
}
}
}
{
}
}
}
}
}
if (set->first_valid_gid != 0) {
}
if (set->last_valid_gid != 0) {
}
}
static const char *null_if_empty(const char *str)
{
}
{
struct restrict_access_settings set;
const char *value;
/* clear the environment, so we don't fail if we get back here */
env_remove("RESTRICT_SETUID");
/* if we're dropping privileges before executing and
a privileged group is set, the groups must be fixed
after exec */
env_remove("RESTRICT_SETGID");
env_remove("RESTRICT_SETGID_PRIV");
}
env_remove("RESTRICT_GID_FIRST");
env_remove("RESTRICT_GID_LAST");
env_remove("RESTRICT_SETEXTRAGROUPS");
env_remove("RESTRICT_USER");
env_remove("RESTRICT_CHROOT");
}
{
#ifdef HAVE_PR_SET_DUMPABLE
#endif
}
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)
{
}