39
static gid_t *get_groups_list(int *gid_count_r)
50
static void restrict_init_groups(gid_t primary_gid, gid_t privileged_gid)
52
if (privileged_gid == (gid_t)-1) {
53
if (primary_gid == getgid() && primary_gid == getegid()) {
54
/* everything is already set */
58
if (setgid(primary_gid) != 0) {
59
i_fatal("setgid(%s) failed with euid=%s, "
60
"gid=%s, egid=%s: %m",
61
dec2str(primary_gid), dec2str(geteuid()),
62
dec2str(getgid()), dec2str(getegid()));
67
if (getegid() != 0 && primary_gid == getgid() &&
68
primary_gid == getegid()) {
69
/* privileged_gid is hopefully in saved ID. if not,
70
there's nothing we can do about it. */
75
if (setresgid(primary_gid, primary_gid, privileged_gid) != 0) {
76
i_fatal("setresgid(%s,%s,%s) failed with euid=%s: %m",
77
dec2str(primary_gid), dec2str(primary_gid),
78
dec2str(privileged_gid), dec2str(geteuid()));
82
/* real, effective, saved -> privileged_gid */
83
if (setgid(privileged_gid) < 0) {
84
i_fatal("setgid(%s) failed: %m",
85
dec2str(privileged_gid));
88
/* real, effective -> primary_gid
90
if (setregid(primary_gid, primary_gid) != 0) {
91
i_fatal("setregid(%s,%s) failed with euid=%s: %m",
92
dec2str(primary_gid), dec2str(privileged_gid),
98
static gid_t *get_groups_list(unsigned int *gid_count_r)
42
101
int ret, gid_count;
56
static void drop_restricted_groups(bool *have_root_group)
115
static void drop_restricted_groups(gid_t *gid_list, unsigned int *gid_count,
116
bool *have_root_group)
119
gid_t first_valid, last_valid;
60
gid_t *gid_list, first_valid_gid, last_valid_gid;
61
int i, used, gid_count;
121
unsigned int i, used;
63
123
env = getenv("RESTRICT_GID_FIRST");
64
first_valid_gid = env == NULL ? 0 : (gid_t)strtoul(env, NULL, 10);
124
first_valid = env == NULL ? 0 : (gid_t)strtoul(env, NULL, 10);
65
125
env = getenv("RESTRICT_GID_LAST");
66
last_valid_gid = env == NULL ? 0 : (gid_t)strtoul(env, NULL, 10);
68
if (first_valid_gid == 0 && last_valid_gid == 0)
72
gid_list = get_groups_list(&gid_count);
74
for (i = 0, used = 0; i < gid_count; i++) {
75
if (gid_list[i] >= first_valid_gid &&
76
(last_valid_gid == 0 || gid_list[i] <= last_valid_gid)) {
126
last_valid = env == NULL ? (gid_t)-1 : (gid_t)strtoul(env, NULL, 10);
128
for (i = 0, used = 0; i < *gid_count; i++) {
129
if (gid_list[i] >= first_valid &&
130
(last_valid == (gid_t)-1 || gid_list[i] <= last_valid)) {
77
131
if (gid_list[i] == 0)
78
132
*have_root_group = TRUE;
79
133
gid_list[used++] = gid_list[i];
83
if (used != gid_count) {
84
/* it did contain restricted groups, remove it */
85
if (setgroups(used, gid_list) < 0)
86
i_fatal("setgroups() failed: %m");
91
139
static gid_t get_group_id(const char *name)
101
149
return group->gr_gid;
104
static void grant_extra_groups(const char *groups)
152
static void fix_groups_list(const char *extra_groups,
153
bool preserve_existing, bool *have_root_group)
106
const char *const *tmp;
111
tmp = t_strsplit(groups, ", ");
112
gid_list = get_groups_list(&gid_count);
113
for (; *tmp != NULL; tmp++) {
117
if (!t_try_realloc(gid_list, (gid_count+1) * sizeof(gid_t)))
119
gid_list[gid_count++] = get_group_id(*tmp);
122
if (setgroups(gid_count, gid_list) < 0)
123
i_fatal("setgroups() failed: %m");
155
gid_t gid, *gid_list, *gid_list2;
156
const char *const *tmp, *empty = NULL;
157
unsigned int i, gid_count;
158
bool add_primary_gid;
160
/* if we're using a privileged GID, we can temporarily drop our
161
effective GID. we still want to be able to use its privileges,
162
so add it to supplementary groups. */
163
add_primary_gid = privileged_gid != (gid_t)-1;
165
tmp = extra_groups == NULL ? &empty :
166
t_strsplit_spaces(extra_groups, ", ");
168
if (preserve_existing) {
169
gid_list = get_groups_list(&gid_count);
170
drop_restricted_groups(gid_list, &gid_count,
172
/* see if the list already contains the primary GID */
173
for (i = 0; i < gid_count; i++) {
174
if (gid_list[i] == primary_gid) {
175
add_primary_gid = FALSE;
183
if (gid_count == 0) {
184
/* Some OSes don't like an empty groups list,
185
so use the primary GID as the only one. */
186
gid_list = t_new(gid_t, 2);
187
gid_list[0] = primary_gid;
189
add_primary_gid = FALSE;
192
if (*tmp != NULL || add_primary_gid) {
193
/* @UNSAFE: add extra groups and/or primary GID to gids list */
194
gid_list2 = t_new(gid_t, gid_count + strarray_length(tmp) + 1);
195
memcpy(gid_list2, gid_list, gid_count * sizeof(gid_t));
196
for (; *tmp != NULL; tmp++) {
197
gid = get_group_id(*tmp);
198
if (gid != primary_gid)
199
gid_list2[gid_count++] = gid;
202
gid_list2[gid_count++] = primary_gid;
203
gid_list = gid_list2;
206
if (setgroups(gid_count, gid_list) < 0) {
207
if (errno == EINVAL) {
208
i_fatal("setgroups(%s) failed: Too many extra groups",
209
extra_groups == NULL ? "" : extra_groups);
211
i_fatal("setgroups() failed: %m");
128
216
void restrict_access_by_env(bool disallow_root)
133
bool have_root_group;
135
/* groups - the getgid() checks are just so we don't fail if we're
136
not running as root and try to just use our own GID. Do this
137
before chrooting so initgroups() actually works. */
220
bool is_root, have_root_group, preserve_groups = FALSE;
223
is_root = geteuid() == 0;
225
/* set the primary/privileged group */
138
226
env = getenv("RESTRICT_SETGID");
139
gid = env == NULL ? 0 : (gid_t)strtoul(env, NULL, 10);
140
have_root_group = gid == 0;
141
if (gid != 0 && (gid != getgid() || gid != getegid())) {
142
if (setgid(gid) != 0) {
143
i_fatal("setgid(%s) failed with euid=%s, egid=%s: %m",
144
dec2str(gid), dec2str(geteuid()),
148
env = getenv("RESTRICT_USER");
150
/* user not known, use only this one group */
151
if (setgroups(1, &gid) < 0) {
152
i_fatal("setgroups(%s) failed: %m",
156
if (initgroups(env, gid) != 0) {
157
i_fatal("initgroups(%s, %s) failed: %m",
161
drop_restricted_groups(&have_root_group);
165
/* grant additional groups to process */
227
primary_gid = env == NULL || *env == '\0' ? (gid_t)-1 :
228
(gid_t)strtoul(env, NULL, 10);
229
env = getenv("RESTRICT_SETGID_PRIV");
230
privileged_gid = env == NULL || *env == '\0' ? (gid_t)-1 :
231
(gid_t)strtoul(env, NULL, 10);
233
have_root_group = primary_gid == 0;
234
if (primary_gid != (gid_t)-1 || privileged_gid != (gid_t)-1) {
235
if (primary_gid == (gid_t)-1)
236
primary_gid = getegid();
237
restrict_init_groups(primary_gid, privileged_gid);
239
if (primary_gid == (gid_t)-1)
240
primary_gid = getegid();
243
/* set system user's groups */
244
env = getenv("RESTRICT_USER");
245
if (env != NULL && *env != '\0' && is_root) {
246
if (initgroups(env, primary_gid) < 0) {
247
i_fatal("initgroups(%s, %s) failed: %m",
248
env, dec2str(primary_gid));
250
preserve_groups = TRUE;
253
/* add extra groups. if we set system user's groups, drop the
254
restricted groups at the same time. */
166
255
env = getenv("RESTRICT_SETEXTRAGROUPS");
167
if (env != NULL && *env != '\0')
168
grant_extra_groups(env);
258
fix_groups_list(env, preserve_groups, &have_root_group);
171
263
env = getenv("RESTRICT_CHROOT");
225
325
env_put("RESTRICT_USER=");
226
326
env_put("RESTRICT_CHROOT=");
227
327
env_put("RESTRICT_SETUID=");
228
env_put("RESTRICT_SETGID=");
328
if (privileged_gid == (gid_t)-1) {
329
/* if we're dropping privileges before executing and
330
a privileged group is set, the groups must be fixed
332
env_put("RESTRICT_SETGID=");
333
env_put("RESTRICT_SETGID_PRIV=");
229
335
env_put("RESTRICT_SETEXTRAGROUPS=");
230
336
env_put("RESTRICT_GID_FIRST=");
231
337
env_put("RESTRICT_GID_LAST=");
340
int restrict_access_use_priv_gid(void)
342
i_assert(!using_priv_gid);
344
if (privileged_gid == (gid_t)-1)
346
if (setegid(privileged_gid) < 0) {
347
i_error("setegid(privileged) failed: %m");
350
using_priv_gid = TRUE;
354
void restrict_access_drop_priv_gid(void)
359
if (setegid(primary_gid) < 0)
360
i_fatal("setegid(primary) failed: %m");
361
using_priv_gid = FALSE;
364
bool restrict_access_have_priv_gid(void)
366
return privileged_gid != (gid_t)-1;