restrict-access.c revision de0034cc6bb52585bc82289801435418a7ee7298
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#define _GNU_SOURCE /* setresgid() */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#include <stdio.h> /* for AIX */
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen#include <sys/types.h>
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen#include <unistd.h>
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen#include "lib.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "str.h"
4499995f7029bafd85094694b6a14752ea34c9b3Timo Sirainen#include "restrict-access.h"
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#include "env-util.h"
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#include "ipwd.h"
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen#include <time.h>
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#ifdef HAVE_PR_SET_DUMPABLE
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen# include <sys/prctl.h>
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#endif
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainenstatic gid_t process_primary_gid = (gid_t)-1;
fcca16701767c6b92227a9ee125de69d257882f6Timo Sirainenstatic gid_t process_privileged_gid = (gid_t)-1;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainenstatic bool process_using_priv_gid = FALSE;
d10cb4d7a80571af21f776c65604442bf09b1765Timo Sirainenstatic char *chroot_dir = NULL;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
fcca16701767c6b92227a9ee125de69d257882f6Timo Sirainenvoid restrict_access_init(struct restrict_access_settings *set)
fcca16701767c6b92227a9ee125de69d257882f6Timo Sirainen{
fcca16701767c6b92227a9ee125de69d257882f6Timo Sirainen i_zero(set);
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen set->uid = (uid_t)-1;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen set->gid = (gid_t)-1;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen set->privileged_gid = (gid_t)-1;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen}
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainenstatic const char *get_uid_str(uid_t uid)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen{
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen struct passwd pw;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen const char *ret;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen int old_errno = errno;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (i_getpwuid(uid, &pw) <= 0)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen ret = dec2str(uid);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen else
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen ret = t_strdup_printf("%s(%s)", dec2str(uid), pw.pw_name);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen errno = old_errno;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return ret;
a6f281d078ed03d555802c1a8e15fefce80132dcTimo Sirainen}
a6f281d078ed03d555802c1a8e15fefce80132dcTimo Sirainen
a6f281d078ed03d555802c1a8e15fefce80132dcTimo Sirainenstatic const char *get_gid_str(gid_t gid)
a6f281d078ed03d555802c1a8e15fefce80132dcTimo Sirainen{
a6f281d078ed03d555802c1a8e15fefce80132dcTimo Sirainen struct group group;
a6f281d078ed03d555802c1a8e15fefce80132dcTimo Sirainen const char *ret;
a6f281d078ed03d555802c1a8e15fefce80132dcTimo Sirainen int old_errno = errno;
a6f281d078ed03d555802c1a8e15fefce80132dcTimo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen if (i_getgrgid(gid, &group) <= 0)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen ret = dec2str(gid);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen else
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen ret = t_strdup_printf("%s(%s)", dec2str(gid), group.gr_name);
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen errno = old_errno;
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen return ret;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen}
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
a6f281d078ed03d555802c1a8e15fefce80132dcTimo Sirainenstatic void restrict_init_groups(gid_t primary_gid, gid_t privileged_gid,
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen const char *gid_source)
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen{
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen string_t *str;
fcca16701767c6b92227a9ee125de69d257882f6Timo Sirainen
c1d4780bc0c9017e8e5d366b81e4fad31174c0adTimo Sirainen if (privileged_gid == (gid_t)-1) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (primary_gid == getgid() && primary_gid == getegid()) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* everything is already set */
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen return;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen }
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (setgid(primary_gid) == 0)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen str = t_str_new(128);
597dba3488c648ffb375ee4a552bd52ac4346979Timo Sirainen str_printfa(str, "setgid(%s", get_gid_str(primary_gid));
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (gid_source != NULL)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen str_printfa(str, " from %s", gid_source);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen str_printfa(str, ") failed with euid=%s, gid=%s, egid=%s: %m "
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen "(This binary should probably be called with "
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen "process group set to %s instead of %s)",
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen get_uid_str(geteuid()),
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen get_gid_str(getgid()), get_gid_str(getegid()),
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen get_gid_str(primary_gid), get_gid_str(getegid()));
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen i_fatal("%s", str_c(str));
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen if (getegid() != 0 && primary_gid == getgid() &&
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen primary_gid == getegid()) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* privileged_gid is hopefully in saved ID. if not,
fcca16701767c6b92227a9ee125de69d257882f6Timo Sirainen there's nothing we can do about it. */
fcca16701767c6b92227a9ee125de69d257882f6Timo Sirainen return;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
fcca16701767c6b92227a9ee125de69d257882f6Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#ifdef HAVE_SETRESGID
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen if (setresgid(primary_gid, primary_gid, privileged_gid) != 0) {
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen i_fatal("setresgid(%s,%s,%s) failed with euid=%s: %m",
9e406b04bb5bed7d73aeed375c40c6a3fea1a2cbTimo Sirainen get_gid_str(primary_gid), get_gid_str(primary_gid),
4307c886579381dbb1897ea1388ae6978c96f560Timo Sirainen get_gid_str(privileged_gid), get_uid_str(geteuid()));
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#else
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen if (geteuid() == 0) {
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen /* real, effective, saved -> privileged_gid */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (setgid(privileged_gid) < 0) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_fatal("setgid(%s) failed: %m",
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen get_gid_str(privileged_gid));
bace943c67e6cd14ce6c994f533d82a3caad5bf1Timo Sirainen }
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen }
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen /* real, effective -> primary_gid
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen saved -> keep */
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen if (setregid(primary_gid, primary_gid) != 0) {
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen i_fatal("setregid(%s,%s) failed with euid=%s: %m",
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen get_gid_str(primary_gid), get_gid_str(privileged_gid),
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen get_uid_str(geteuid()));
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen }
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen#endif
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen}
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainengid_t *restrict_get_groups_list(unsigned int *gid_count_r)
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen{
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen gid_t *gid_list;
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen int ret, gid_count;
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen if ((gid_count = getgroups(0, NULL)) < 0)
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen i_fatal("getgroups() failed: %m");
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* @UNSAFE */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen gid_list = t_new(gid_t, gid_count+1); /* +1 in case gid_count=0 */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if ((ret = getgroups(gid_count, gid_list)) < 0)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_fatal("getgroups() failed: %m");
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
5069adb2f5b3609fff9a0a705c6edeae56e0030aTimo Sirainen *gid_count_r = ret;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return gid_list;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen}
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainenstatic void drop_restricted_groups(const struct restrict_access_settings *set,
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen gid_t *gid_list, unsigned int *gid_count,
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen bool *have_root_group)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen{
8d56f3334e22619abf56833d290bb1f49ac6722cTimo Sirainen /* @UNSAFE */
8d56f3334e22619abf56833d290bb1f49ac6722cTimo Sirainen unsigned int i, used;
2c42748505ef4aed83ff59b34e50ed5606900c86Timo Sirainen
2c42748505ef4aed83ff59b34e50ed5606900c86Timo Sirainen for (i = 0, used = 0; i < *gid_count; i++) {
2c42748505ef4aed83ff59b34e50ed5606900c86Timo Sirainen if (gid_list[i] >= set->first_valid_gid &&
2c42748505ef4aed83ff59b34e50ed5606900c86Timo Sirainen (set->last_valid_gid == 0 ||
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen gid_list[i] <= set->last_valid_gid)) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (gid_list[i] == 0)
156736910057b280cb9999d4c6c7221c4c80f5c2Timo Sirainen *have_root_group = TRUE;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen gid_list[used++] = gid_list[i];
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen *gid_count = used;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen}
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
d10cb4d7a80571af21f776c65604442bf09b1765Timo Sirainenstatic gid_t get_group_id(const char *name)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen{
81b1d14891415fef0c2f37ef1ef3680cdcc600f1Timo Sirainen struct group group;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen gid_t gid;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
5069adb2f5b3609fff9a0a705c6edeae56e0030aTimo Sirainen if (str_to_gid(name, &gid) == 0)
5069adb2f5b3609fff9a0a705c6edeae56e0030aTimo Sirainen return gid;
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen
5069adb2f5b3609fff9a0a705c6edeae56e0030aTimo Sirainen switch (i_getgrnam(name, &group)) {
5069adb2f5b3609fff9a0a705c6edeae56e0030aTimo Sirainen case -1:
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_fatal("getgrnam(%s) failed: %m", name);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen case 0:
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_fatal("unknown group name in extra_groups: %s", name);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen default:
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen return group.gr_gid;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen}
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainenstatic void fix_groups_list(const struct restrict_access_settings *set,
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen bool preserve_existing, bool *have_root_group)
f2b95f63ebdf77dba4dac938cf8c65c839f1067dTimo Sirainen{
f2b95f63ebdf77dba4dac938cf8c65c839f1067dTimo Sirainen gid_t gid, *gid_list, *gid_list2;
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen const char *const *tmp, *empty = NULL;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen unsigned int i, gid_count;
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen bool add_primary_gid;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* if we're using a privileged GID, we can temporarily drop our
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen effective GID. we still want to be able to use its privileges,
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen so add it to supplementary groups. */
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen add_primary_gid = process_privileged_gid != (gid_t)-1;
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen tmp = set->extra_groups == NULL ? &empty :
8d56f3334e22619abf56833d290bb1f49ac6722cTimo Sirainen t_strsplit_spaces(set->extra_groups, ", ");
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen if (preserve_existing) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen gid_list = restrict_get_groups_list(&gid_count);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen drop_restricted_groups(set, gid_list, &gid_count,
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen have_root_group);
5297aa3ceddf3a4ecc09f49c832bc424eff8f906Timo Sirainen /* see if the list already contains the primary GID */
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen for (i = 0; i < gid_count; i++) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (gid_list[i] == process_primary_gid) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen add_primary_gid = FALSE;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen break;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen }
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen } else {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen gid_list = NULL;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen gid_count = 0;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (gid_count == 0) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* Some OSes don't like an empty groups list,
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen so use the primary GID as the only one. */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen gid_list = t_new(gid_t, 2);
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen gid_list[0] = process_primary_gid;
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen gid_count = 1;
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen add_primary_gid = FALSE;
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen }
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen if (*tmp != NULL || add_primary_gid) {
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen /* @UNSAFE: add extra groups and/or primary GID to gids list */
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen gid_list2 = t_new(gid_t, gid_count + str_array_length(tmp) + 1);
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen memcpy(gid_list2, gid_list, gid_count * sizeof(gid_t));
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen for (; *tmp != NULL; tmp++) {
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen gid = get_group_id(*tmp);
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen if (gid != process_primary_gid)
9e406b04bb5bed7d73aeed375c40c6a3fea1a2cbTimo Sirainen gid_list2[gid_count++] = gid;
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen }
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen if (add_primary_gid)
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen gid_list2[gid_count++] = process_primary_gid;
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen gid_list = gid_list2;
4307c886579381dbb1897ea1388ae6978c96f560Timo Sirainen }
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen if (setgroups(gid_count, gid_list) < 0) {
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen if (errno == EINVAL) {
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen i_fatal("setgroups(%s) failed: Too many extra groups",
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen set->extra_groups == NULL ? "" :
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen set->extra_groups);
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen } else {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_fatal("setgroups() failed: %m");
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen}
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainenstatic const char *
f2b95f63ebdf77dba4dac938cf8c65c839f1067dTimo Sirainenget_setuid_error_str(const struct restrict_access_settings *set, uid_t target_uid)
f2b95f63ebdf77dba4dac938cf8c65c839f1067dTimo Sirainen{
f2b95f63ebdf77dba4dac938cf8c65c839f1067dTimo Sirainen string_t *str = t_str_new(128);
f2b95f63ebdf77dba4dac938cf8c65c839f1067dTimo Sirainen
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen str_printfa(str, "setuid(%s", get_uid_str(target_uid));
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (set->uid_source != NULL)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen str_printfa(str, " from %s", set->uid_source);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen str_printfa(str, ") failed with euid=%s: %m ",
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen get_uid_str(geteuid()));
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (errno == EAGAIN) {
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen str_append(str, "(ulimit -u reached)");
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen } else {
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen str_printfa(str, "(This binary should probably be called with "
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen "process user set to %s instead of %s)",
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen get_uid_str(target_uid), get_uid_str(geteuid()));
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return str_c(str);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen}
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainenvoid restrict_access(const struct restrict_access_settings *set,
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen const char *home, bool disallow_root)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen{
8451cf67733f6633510f6619301474be349c5035Timo Sirainen bool is_root, have_root_group, preserve_groups = FALSE;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen bool allow_root_gid;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen uid_t target_uid = set->uid;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen is_root = geteuid() == 0;
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen if (!is_root &&
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen !set->allow_setuid_root &&
9e406b04bb5bed7d73aeed375c40c6a3fea1a2cbTimo Sirainen getuid() == 0) {
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen /* recover current effective UID */
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen if (target_uid == (uid_t)-1)
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen target_uid = geteuid();
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen else
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen i_assert(target_uid > 0);
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen /* try to elevate to root */
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen if (seteuid(0) < 0)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_fatal("seteuid(0) failed: %m");
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen is_root = TRUE;
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen }
34830cefe1757de0ffca67acdc529d5bc8b06b66Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* set the primary/privileged group */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen process_primary_gid = set->gid;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen process_privileged_gid = set->privileged_gid;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (process_privileged_gid == process_primary_gid) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* a pointless configuration, ignore it */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen process_privileged_gid = (gid_t)-1;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
1b9aae1cb53708b5a3d861b4db6ba96ac2eb35b4Timo Sirainen have_root_group = process_primary_gid == 0;
1b9aae1cb53708b5a3d861b4db6ba96ac2eb35b4Timo Sirainen if (process_primary_gid != (gid_t)-1 ||
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen process_privileged_gid != (gid_t)-1) {
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen if (process_primary_gid == (gid_t)-1)
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen process_primary_gid = getegid();
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen restrict_init_groups(process_primary_gid,
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen process_privileged_gid, set->gid_source);
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen } else {
4da70fe8c9cb6e57b36103d78ab1e9c8654f76d9Timo Sirainen if (process_primary_gid == (gid_t)-1)
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen process_primary_gid = getegid();
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* set system user's groups */
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen if (set->system_groups_user != NULL && is_root) {
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen if (initgroups(set->system_groups_user,
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen process_primary_gid) < 0) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_fatal("initgroups(%s, %s) failed: %m",
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen set->system_groups_user,
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen get_gid_str(process_primary_gid));
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen preserve_groups = TRUE;
d10cb4d7a80571af21f776c65604442bf09b1765Timo Sirainen }
d10cb4d7a80571af21f776c65604442bf09b1765Timo Sirainen
d10cb4d7a80571af21f776c65604442bf09b1765Timo Sirainen /* add extra groups. if we set system user's groups, drop the
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen restricted groups at the same time. */
d10cb4d7a80571af21f776c65604442bf09b1765Timo Sirainen if (is_root) T_BEGIN {
d10cb4d7a80571af21f776c65604442bf09b1765Timo Sirainen fix_groups_list(set, preserve_groups,
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen &have_root_group);
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen } T_END;
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* chrooting */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (set->chroot_dir != NULL) {
1fb8ce8b21d0616796ced699b1573b5dd0b61793Timo Sirainen /* kludge: localtime() must be called before chroot(),
1fb8ce8b21d0616796ced699b1573b5dd0b61793Timo Sirainen or the timezone isn't known */
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen time_t t = 0;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen (void)localtime(&t);
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen if (chroot(set->chroot_dir) != 0)
9ec30d84a736a2d0726b600213dcf630ff28bdebTimo Sirainen i_fatal("chroot(%s) failed: %m", set->chroot_dir);
9ec30d84a736a2d0726b600213dcf630ff28bdebTimo Sirainen /* makes static analyzers happy, and is more secure */
9ec30d84a736a2d0726b600213dcf630ff28bdebTimo Sirainen if (chdir("/") != 0)
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen i_fatal("chdir(/) failed: %m");
1fb8ce8b21d0616796ced699b1573b5dd0b61793Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen chroot_dir = i_strdup(set->chroot_dir);
a6f281d078ed03d555802c1a8e15fefce80132dcTimo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (home != NULL) {
2a8b891366a3fc69524c2bb07f68d42c16223a56Timo Sirainen if (chdir(home) < 0) {
2a8b891366a3fc69524c2bb07f68d42c16223a56Timo Sirainen i_error("chdir(%s) failed: %m", home);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen }
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen }
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen /* uid last */
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen if (target_uid != (uid_t)-1) {
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen if (setuid(target_uid) != 0)
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen i_fatal("%s", get_setuid_error_str(set, target_uid));
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen /* verify that we actually dropped the privileges */
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen if ((target_uid != (uid_t)-1 && target_uid != 0) || disallow_root) {
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen if (setuid(0) == 0) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (disallow_root &&
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen (target_uid == 0 || target_uid == (uid_t)-1))
be51dfea768ad502e08ebd02917138f7a0f8f625Timo Sirainen i_fatal("This process must not be run as root");
be51dfea768ad502e08ebd02917138f7a0f8f625Timo Sirainen
be51dfea768ad502e08ebd02917138f7a0f8f625Timo Sirainen i_fatal("We couldn't drop root privileges");
be51dfea768ad502e08ebd02917138f7a0f8f625Timo Sirainen }
be51dfea768ad502e08ebd02917138f7a0f8f625Timo Sirainen }
be51dfea768ad502e08ebd02917138f7a0f8f625Timo Sirainen
be51dfea768ad502e08ebd02917138f7a0f8f625Timo Sirainen if (set->first_valid_gid != 0)
be51dfea768ad502e08ebd02917138f7a0f8f625Timo Sirainen allow_root_gid = FALSE;
be51dfea768ad502e08ebd02917138f7a0f8f625Timo Sirainen else if (process_primary_gid == 0 || process_privileged_gid == 0)
be51dfea768ad502e08ebd02917138f7a0f8f625Timo Sirainen allow_root_gid = TRUE;
be51dfea768ad502e08ebd02917138f7a0f8f625Timo Sirainen else
be51dfea768ad502e08ebd02917138f7a0f8f625Timo Sirainen allow_root_gid = FALSE;
be51dfea768ad502e08ebd02917138f7a0f8f625Timo Sirainen
be51dfea768ad502e08ebd02917138f7a0f8f625Timo Sirainen if (!allow_root_gid && target_uid != 0 &&
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen (target_uid != (uid_t)-1 || !is_root)) {
4d33a3133e8484ebd00f677f457cda82f1365b84Timo Sirainen if (getgid() == 0 || getegid() == 0 || setgid(0) == 0) {
4d33a3133e8484ebd00f677f457cda82f1365b84Timo Sirainen if (process_primary_gid == 0)
4d33a3133e8484ebd00f677f457cda82f1365b84Timo Sirainen i_fatal("GID 0 isn't permitted");
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_fatal("We couldn't drop root group privileges "
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen "(wanted=%s, gid=%s, egid=%s)",
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen get_gid_str(process_primary_gid),
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen get_gid_str(getgid()), get_gid_str(getegid()));
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen}
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainenvoid restrict_access_set_env(const struct restrict_access_settings *set)
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen{
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen if (set->system_groups_user != NULL &&
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen *set->system_groups_user != '\0') {
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen env_put(t_strconcat("RESTRICT_USER=",
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen set->system_groups_user, NULL));
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen if (set->chroot_dir != NULL && *set->chroot_dir != '\0')
fcca16701767c6b92227a9ee125de69d257882f6Timo Sirainen env_put(t_strconcat("RESTRICT_CHROOT=", set->chroot_dir, NULL));
fcca16701767c6b92227a9ee125de69d257882f6Timo Sirainen
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen if (set->uid != (uid_t)-1) {
597dba3488c648ffb375ee4a552bd52ac4346979Timo Sirainen env_put(t_strdup_printf("RESTRICT_SETUID=%s",
7bcb308d0e13dfa48b483b0addccd889a77bb598Timo Sirainen dec2str(set->uid)));
d10cb4d7a80571af21f776c65604442bf09b1765Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (set->gid != (gid_t)-1) {
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen env_put(t_strdup_printf("RESTRICT_SETGID=%s",
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen dec2str(set->gid)));
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (set->privileged_gid != (gid_t)-1) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen env_put(t_strdup_printf("RESTRICT_SETGID_PRIV=%s",
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen dec2str(set->privileged_gid)));
5702c81e2d788449c3bc207eb9c19e539458ad9eTimo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (set->extra_groups != NULL && *set->extra_groups != '\0') {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen env_put(t_strconcat("RESTRICT_SETEXTRAGROUPS=",
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen set->extra_groups, NULL));
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen }
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen if (set->first_valid_gid != 0) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen env_put(t_strdup_printf("RESTRICT_GID_FIRST=%s",
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen dec2str(set->first_valid_gid)));
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen }
be51dfea768ad502e08ebd02917138f7a0f8f625Timo Sirainen if (set->last_valid_gid != 0) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen env_put(t_strdup_printf("RESTRICT_GID_LAST=%s",
da2aa032ccfa8e7e4a4380ef738014549f4d2c2dTimo Sirainen dec2str(set->last_valid_gid)));
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen }
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen}
9511a40d933181045343110c8101b75887062aaeTimo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainenstatic const char *null_if_empty(const char *str)
4d33a3133e8484ebd00f677f457cda82f1365b84Timo Sirainen{
c395e7d730eb4ee17e2b619acec487637a785110Timo Sirainen return str == NULL || *str == '\0' ? NULL : str;
c395e7d730eb4ee17e2b619acec487637a785110Timo Sirainen}
c395e7d730eb4ee17e2b619acec487637a785110Timo Sirainen
c395e7d730eb4ee17e2b619acec487637a785110Timo Sirainenvoid restrict_access_get_env(struct restrict_access_settings *set_r)
c395e7d730eb4ee17e2b619acec487637a785110Timo Sirainen{
c395e7d730eb4ee17e2b619acec487637a785110Timo Sirainen const char *value;
c395e7d730eb4ee17e2b619acec487637a785110Timo Sirainen
c395e7d730eb4ee17e2b619acec487637a785110Timo Sirainen restrict_access_init(set_r);
c395e7d730eb4ee17e2b619acec487637a785110Timo Sirainen if ((value = getenv("RESTRICT_SETUID")) != NULL) {
c395e7d730eb4ee17e2b619acec487637a785110Timo Sirainen if (str_to_uid(value, &set_r->uid) < 0)
c395e7d730eb4ee17e2b619acec487637a785110Timo Sirainen i_fatal("Invalid uid: %s", value);
4d33a3133e8484ebd00f677f457cda82f1365b84Timo Sirainen }
4d33a3133e8484ebd00f677f457cda82f1365b84Timo Sirainen if ((value = getenv("RESTRICT_SETGID")) != NULL) {
4d33a3133e8484ebd00f677f457cda82f1365b84Timo Sirainen if (str_to_gid(value, &set_r->gid) < 0)
4d33a3133e8484ebd00f677f457cda82f1365b84Timo Sirainen i_fatal("Invalid gid: %s", value);
4d33a3133e8484ebd00f677f457cda82f1365b84Timo Sirainen }
4d33a3133e8484ebd00f677f457cda82f1365b84Timo Sirainen if ((value = getenv("RESTRICT_SETGID_PRIV")) != NULL) {
4d33a3133e8484ebd00f677f457cda82f1365b84Timo Sirainen if (str_to_gid(value, &set_r->privileged_gid) < 0)
c395e7d730eb4ee17e2b619acec487637a785110Timo Sirainen i_fatal("Invalid privileged_gid: %s", value);
4d33a3133e8484ebd00f677f457cda82f1365b84Timo Sirainen }
4d33a3133e8484ebd00f677f457cda82f1365b84Timo Sirainen if ((value = getenv("RESTRICT_GID_FIRST")) != NULL) {
4d33a3133e8484ebd00f677f457cda82f1365b84Timo Sirainen if (str_to_gid(value, &set_r->first_valid_gid) < 0)
4d33a3133e8484ebd00f677f457cda82f1365b84Timo Sirainen i_fatal("Invalid first_valid_gid: %s", value);
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen }
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen if ((value = getenv("RESTRICT_GID_LAST")) != NULL) {
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen if (str_to_gid(value, &set_r->last_valid_gid) < 0)
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen i_fatal("Invalid last_value_gid: %s", value);
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen }
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen set_r->extra_groups = null_if_empty(getenv("RESTRICT_SETEXTRAGROUPS"));
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen set_r->system_groups_user = null_if_empty(getenv("RESTRICT_USER"));
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen set_r->chroot_dir = null_if_empty(getenv("RESTRICT_CHROOT"));
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen}
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen
9e406b04bb5bed7d73aeed375c40c6a3fea1a2cbTimo Sirainenvoid restrict_access_by_env(const char *home, bool disallow_root)
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen{
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen struct restrict_access_settings set;
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen restrict_access_get_env(&set);
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen restrict_access(&set, home, disallow_root);
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen
9e406b04bb5bed7d73aeed375c40c6a3fea1a2cbTimo Sirainen /* clear the environment, so we don't fail if we get back here */
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen env_remove("RESTRICT_SETUID");
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen if (process_privileged_gid == (gid_t)-1) {
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen /* if we're dropping privileges before executing and
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen a privileged group is set, the groups must be fixed
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen after exec */
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen env_remove("RESTRICT_SETGID");
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen env_remove("RESTRICT_SETGID_PRIV");
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen }
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen env_remove("RESTRICT_GID_FIRST");
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen env_remove("RESTRICT_GID_LAST");
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen if (getuid() != 0)
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen env_remove("RESTRICT_SETEXTRAGROUPS");
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen else {
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen /* Preserve RESTRICT_SETEXTRAGROUPS, so if we're again dropping
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen more privileges we'll still preserve the extra groups. This
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen mainly means preserving service { extra_groups } for lmtp
c395e7d730eb4ee17e2b619acec487637a785110Timo Sirainen and doveadm accesses. */
c395e7d730eb4ee17e2b619acec487637a785110Timo Sirainen }
c395e7d730eb4ee17e2b619acec487637a785110Timo Sirainen env_remove("RESTRICT_USER");
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen env_remove("RESTRICT_CHROOT");
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen}
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen
c395e7d730eb4ee17e2b619acec487637a785110Timo Sirainenconst char *restrict_access_get_current_chroot(void)
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen{
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen return chroot_dir;
6967fa47dde9f2726bd86019a50627dacf2d7509Timo Sirainen}
void restrict_access_set_dumpable(bool allow ATTR_UNUSED)
{
#ifdef HAVE_PR_SET_DUMPABLE
if (prctl(PR_SET_DUMPABLE, allow ? 1 : 0, 0, 0, 0) < 0)
i_error("prctl(PR_SET_DUMPABLE) failed: %m");
#endif
}
bool restrict_access_get_dumpable(void)
{
#ifdef HAVE_PR_SET_DUMPABLE
bool allow = FALSE;
if (prctl(PR_GET_DUMPABLE, &allow, 0, 0, 0) < 0)
i_error("prctl(PR_GET_DUMPABLE) failed: %m");
return allow;
#endif
return TRUE;
}
void restrict_access_allow_coredumps(bool allow)
{
if (getenv("PR_SET_DUMPABLE") != NULL) {
restrict_access_set_dumpable(allow);
}
}
int restrict_access_use_priv_gid(void)
{
i_assert(!process_using_priv_gid);
if (process_privileged_gid == (gid_t)-1)
return 0;
if (setegid(process_privileged_gid) < 0) {
i_error("setegid(privileged) failed: %m");
return -1;
}
process_using_priv_gid = TRUE;
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");
process_using_priv_gid = FALSE;
}
bool restrict_access_have_priv_gid(void)
{
return process_privileged_gid != (gid_t)-1;
}