SPDX: Mass-update to GPL-2.0-or-later
[exim.git] / src / src / priv.c
1 /* Copyright (c)  The Exim Maintainers 2022 *
2 /* SPDX-License-Identifier: GPL-2.0-or-later */
3
4 #include "exim.h"
5 #include <sys/types.h>
6 #include <unistd.h>
7 #include <string.h>
8
9 static enum {
10   PRIV_DROPPING, PRIV_DROPPED,
11   PRIV_RESTORING, PRIV_RESTORED
12 } priv_state = PRIV_RESTORED;
13
14
15 static uid_t priv_euid;
16 static gid_t priv_egid;
17 static gid_t priv_groups[EXIM_GROUPLIST_SIZE + 1];
18 static int priv_ngroups;
19
20 /* Inspired by OpenSSH's temporarily_use_uid(). Thanks! */
21
22 void
23 priv_drop_temp(const uid_t temp_uid, const gid_t temp_gid)
24 {
25 if (priv_state != PRIV_RESTORED)
26   log_write(0, LOG_PANIC_DIE, "priv_drop_temp: unexpected priv_state %d != %d", priv_state, PRIV_RESTORED);
27
28 priv_state = PRIV_DROPPING;
29
30 priv_euid = geteuid();
31 if (priv_euid == root_uid)
32   {
33   priv_egid = getegid();
34   priv_ngroups = getgroups(nelem(priv_groups), priv_groups);
35   if (priv_ngroups < 0)
36     log_write(0, LOG_PANIC_DIE, "getgroups: %s", strerror(errno));
37
38   if (priv_ngroups > 0 && setgroups(1, &temp_gid) != 0)
39     log_write(0, LOG_PANIC_DIE, "setgroups: %s", strerror(errno));
40   if (setegid(temp_gid) != 0)
41     log_write(0, LOG_PANIC_DIE, "setegid(%d): %s", temp_gid, strerror(errno));
42   if (seteuid(temp_uid) != 0)
43     log_write(0, LOG_PANIC_DIE, "seteuid(%d): %s", temp_uid, strerror(errno));
44
45   if (geteuid() != temp_uid)
46     log_write(0, LOG_PANIC_DIE, "getdeuid() != %d", temp_uid);
47   if (getegid() != temp_gid)
48     log_write(0, LOG_PANIC_DIE, "getegid() != %d", temp_gid);
49   }
50
51 priv_state = PRIV_DROPPED;
52 }
53
54 /* Inspired by OpenSSH's restore_uid(). Thanks! */
55
56 void
57 priv_restore(void)
58 {
59 if (priv_state != PRIV_DROPPED)
60   log_write(0, LOG_PANIC_DIE, "priv_restore: unexpected priv_state %d != %d", priv_state, PRIV_DROPPED);
61 priv_state = PRIV_RESTORING;
62
63 if (priv_euid == root_uid)
64   {
65   if (seteuid(priv_euid) != 0)
66     log_write(0, LOG_PANIC_DIE, "seteuid(%d): %s", priv_euid, strerror(errno));
67   if (setegid(priv_egid) != 0)
68     log_write(0, LOG_PANIC_DIE, "setegid(%d): %s", priv_egid, strerror(errno));
69   if (priv_ngroups > 0 && setgroups(priv_ngroups, priv_groups) != 0)
70     log_write(0, LOG_PANIC_DIE, "setgroups: %s", strerror(errno));
71
72   if (geteuid() != priv_euid)
73     log_write(0, LOG_PANIC_DIE, "getdeuid() != %d", priv_euid);
74   if (getegid() != priv_egid)
75     log_write(0, LOG_PANIC_DIE, "getdegid() != %d", priv_egid);
76   }
77
78 priv_state = PRIV_RESTORED;
79 }