From: Heiko Schlittermann (HS12-RIPE) Date: Wed, 10 Mar 2021 22:37:29 +0000 (+0100) Subject: Add priv.c: reworked version of priv dropping code X-Git-Tag: exim-4.94.1~25 X-Git-Url: https://git.exim.org/exim.git/commitdiff_plain/be31ef213f118abe5fc68732f5492b6b16d28b87 Add priv.c: reworked version of priv dropping code (cherry picked from commit 82b545236e6dc82b7af34528c532811bfc74ea19) --- diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base index 9eed7b0b9..c7bb116ab 100644 --- a/src/OS/Makefile-Base +++ b/src/OS/Makefile-Base @@ -486,7 +486,7 @@ OBJ_EXIM = acl.o base64.o child.o crypt16.o daemon.o dbfn.o debug.o deliver.o \ directory.o dns.o drtables.o enq.o exim.o expand.o filter.o \ filtertest.o globals.o dkim.o dkim_transport.o hash.o \ header.o host.o ip.o log.o lss.o match.o md5.o moan.o \ - os.o parse.o queue.o \ + os.o parse.o priv.o queue.o \ rda.o readconf.o receive.o retry.o rewrite.o rfc2047.o \ route.o search.o sieve.o smtp_in.o smtp_out.o spool_in.o spool_out.o \ std-crypto.o store.o string.o tls.o tod.o transport.o tree.o verify.o \ @@ -792,6 +792,7 @@ md5.o: $(HDRS) md5.c moan.o: $(HDRS) moan.c os.o: $(HDRS) $(OS_C_INCLUDES) os.c parse.o: $(HDRS) parse.c +priv.o: $(HDRS) priv.c queue.o: $(HDRS) queue.c rda.o: $(HDRS) rda.c readconf.o: $(HDRS) readconf.c diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks index 784247d99..0bc7bb2a8 100755 --- a/src/scripts/MakeLinks +++ b/src/scripts/MakeLinks @@ -103,7 +103,7 @@ for f in blob.h dbfunctions.h dbstuff.h exim.h functions.h globals.h \ deliver.c directory.c dns.c drtables.c dummies.c enq.c exim.c \ exim_dbmbuild.c exim_dbutil.c exim_lock.c expand.c filter.c filtertest.c \ globals.c hash.c header.c host.c ip.c log.c lss.c match.c md5.c moan.c \ - parse.c perl.c queue.c rda.c readconf.c receive.c retry.c rewrite.c \ + parse.c perl.c priv.c queue.c rda.c readconf.c receive.c retry.c rewrite.c \ rfc2047.c route.c search.c setenv.c environment.c \ sieve.c smtp_in.c smtp_out.c spool_in.c spool_out.c std-crypto.c store.c \ string.c tls.c tlscert-gnu.c tlscert-openssl.c tls-cipher-stdname.c \ diff --git a/src/src/dbfn.c b/src/src/dbfn.c index dceb5f140..e9a0fc27c 100644 --- a/src/src/dbfn.c +++ b/src/src/dbfn.c @@ -58,68 +58,6 @@ log_write(0, LOG_MAIN, "Berkeley DB error: %s", msg); #endif - - -static enum { - PRIV_DROPPING, PRIV_DROPPED, - PRIV_RESTORING, PRIV_RESTORED -} priv_state = PRIV_RESTORED; - -static uid_t priv_euid; -static gid_t priv_egid; -static gid_t priv_groups[EXIM_GROUPLIST_SIZE + 1]; -static int priv_ngroups; - -/* Inspired by OpenSSH's temporarily_use_uid(). Thanks! */ - -static void -priv_drop_temp(const uid_t temp_uid, const gid_t temp_gid) -{ -if (priv_state != PRIV_RESTORED) _exit(EXIT_FAILURE); -priv_state = PRIV_DROPPING; - -priv_euid = geteuid(); -if (priv_euid == root_uid) - { - priv_egid = getegid(); - priv_ngroups = getgroups(nelem(priv_groups), priv_groups); - if (priv_ngroups < 0) _exit(EXIT_FAILURE); - - if (priv_ngroups > 0 && setgroups(1, &temp_gid) != 0) _exit(EXIT_FAILURE); - if (setegid(temp_gid) != 0) _exit(EXIT_FAILURE); - if (seteuid(temp_uid) != 0) _exit(EXIT_FAILURE); - - if (geteuid() != temp_uid) _exit(EXIT_FAILURE); - if (getegid() != temp_gid) _exit(EXIT_FAILURE); - } - -priv_state = PRIV_DROPPED; -} - -/* Inspired by OpenSSH's restore_uid(). Thanks! */ - -static void -priv_restore(void) -{ -if (priv_state != PRIV_DROPPED) _exit(EXIT_FAILURE); -priv_state = PRIV_RESTORING; - -if (priv_euid == root_uid) - { - if (seteuid(priv_euid) != 0) _exit(EXIT_FAILURE); - if (setegid(priv_egid) != 0) _exit(EXIT_FAILURE); - if (priv_ngroups > 0 && setgroups(priv_ngroups, priv_groups) != 0) _exit(EXIT_FAILURE); - - if (geteuid() != priv_euid) _exit(EXIT_FAILURE); - if (getegid() != priv_egid) _exit(EXIT_FAILURE); - } - -priv_state = PRIV_RESTORED; -} - - - - /************************************************* * Open and lock a database file * *************************************************/ diff --git a/src/src/functions.h b/src/src/functions.h index 4ce0f093d..fc4e0444d 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -370,6 +370,8 @@ extern const uschar *parse_fix_phrase(const uschar *, int); extern const uschar *parse_message_id(const uschar *, uschar **, uschar **); extern const uschar *parse_quote_2047(const uschar *, int, uschar *, BOOL); extern const uschar *parse_date_time(const uschar *str, time_t *t); +extern void priv_drop_temp(const uid_t, const gid_t); +extern void priv_restore(void); extern int vaguely_random_number(int); #ifndef DISABLE_TLS extern int vaguely_random_number_fallback(int); diff --git a/src/src/priv.c b/src/src/priv.c new file mode 100644 index 000000000..94d425401 --- /dev/null +++ b/src/src/priv.c @@ -0,0 +1,76 @@ +#include "exim.h" +#include +#include +#include + +static enum { + PRIV_DROPPING, PRIV_DROPPED, + PRIV_RESTORING, PRIV_RESTORED +} priv_state = PRIV_RESTORED; + + +static uid_t priv_euid; +static gid_t priv_egid; +static gid_t priv_groups[EXIM_GROUPLIST_SIZE + 1]; +static int priv_ngroups; + +/* Inspired by OpenSSH's temporarily_use_uid(). Thanks! */ + +void +priv_drop_temp(const uid_t temp_uid, const gid_t temp_gid) +{ +if (priv_state != PRIV_RESTORED) + log_write(0, LOG_PANIC_DIE, "priv_drop_temp: unexpected priv_state %d != %d", priv_state, PRIV_RESTORED); + +priv_state = PRIV_DROPPING; + +priv_euid = geteuid(); +if (priv_euid == root_uid) + { + priv_egid = getegid(); + priv_ngroups = getgroups(nelem(priv_groups), priv_groups); + if (priv_ngroups < 0) + log_write(0, LOG_PANIC_DIE, "getgroups: %s", strerror(errno)); + + if (priv_ngroups > 0 && setgroups(1, &temp_gid) != 0) + log_write(0, LOG_PANIC_DIE, "setgroups: %s", strerror(errno)); + if (setegid(temp_gid) != 0) + log_write(0, LOG_PANIC_DIE, "setegid(%d): %s", temp_gid, strerror(errno)); + if (seteuid(temp_uid) != 0) + log_write(0, LOG_PANIC_DIE, "seteuid(%d): %s", temp_uid, strerror(errno)); + + if (geteuid() != temp_uid) + log_write(0, LOG_PANIC_DIE, "getdeuid() != %d", temp_uid); + if (getegid() != temp_gid) + log_write(0, LOG_PANIC_DIE, "getegid() != %d", temp_gid); + } + +priv_state = PRIV_DROPPED; +} + +/* Inspired by OpenSSH's restore_uid(). Thanks! */ + +void +priv_restore(void) +{ +if (priv_state != PRIV_DROPPED) + log_write(0, LOG_PANIC_DIE, "priv_restore: unexpected priv_state %d != %d", priv_state, PRIV_DROPPED); +priv_state = PRIV_RESTORING; + +if (priv_euid == root_uid) + { + if (seteuid(priv_euid) != 0) + log_write(0, LOG_PANIC_DIE, "seteuid(%d): %s", priv_euid, strerror(errno)); + if (setegid(priv_egid) != 0) + log_write(0, LOG_PANIC_DIE, "setegid(%d): %s", priv_egid, strerror(errno)); + if (priv_ngroups > 0 && setgroups(priv_ngroups, priv_groups) != 0) + log_write(0, LOG_PANIC_DIE, "setgroups: %s", strerror(errno)); + + if (geteuid() != priv_euid) + log_write(0, LOG_PANIC_DIE, "getdeuid() != %d", priv_euid); + if (getegid() != priv_egid) + log_write(0, LOG_PANIC_DIE, "getdegid() != %d", priv_egid); + } + +priv_state = PRIV_RESTORED; +} diff --git a/test/stderr/0275 b/test/stderr/0275 index 47c9c9e28..1d85b56c1 100644 --- a/test/stderr/0275 +++ b/test/stderr/0275 @@ -171,7 +171,6 @@ Delivery address list: locked TESTSUITE/spool/db/retry.lockfile EXIM_DBOPEN: file dir flags=O_RDONLY returned from EXIM_DBOPEN: (nil) - ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim failed to open DB file TESTSUITE/spool/db/retry: No such file or directory no retry data available >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/test/stderr/0278 b/test/stderr/0278 index c09920b94..5e9428da0 100644 --- a/test/stderr/0278 +++ b/test/stderr/0278 @@ -130,7 +130,6 @@ Delivery address list: locked TESTSUITE/spool/db/retry.lockfile EXIM_DBOPEN: file dir flags=O_RDONLY returned from EXIM_DBOPEN: (nil) - ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim failed to open DB file TESTSUITE/spool/db/retry: No such file or directory no retry data available >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/test/stderr/0386 b/test/stderr/0386 index 7bc56d9b7..608aa0402 100644 --- a/test/stderr/0386 +++ b/test/stderr/0386 @@ -272,7 +272,6 @@ Delivery address list: locked TESTSUITE/spool/db/retry.lockfile EXIM_DBOPEN: file dir flags=O_RDONLY returned from EXIM_DBOPEN: (nil) - ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim failed to open DB file TESTSUITE/spool/db/retry: No such file or directory no retry data available >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/test/stderr/0388 b/test/stderr/0388 index 7819fe907..91fcf830b 100644 --- a/test/stderr/0388 +++ b/test/stderr/0388 @@ -10,7 +10,6 @@ set_process_info: pppp delivering 10HmaX-0005vi-00 locked TESTSUITE/spool/db/retry.lockfile EXIM_DBOPEN: file dir flags=O_RDONLY returned from EXIM_DBOPEN: (nil) - ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim failed to open DB file TESTSUITE/spool/db/retry: No such file or directory no retry data available >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/test/stderr/0402 b/test/stderr/0402 index ec4b9ea72..e4ffc0ee5 100644 --- a/test/stderr/0402 +++ b/test/stderr/0402 @@ -213,7 +213,6 @@ Delivery address list: locked TESTSUITE/spool/db/retry.lockfile EXIM_DBOPEN: file dir flags=O_RDONLY returned from EXIM_DBOPEN: (nil) - ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim failed to open DB file TESTSUITE/spool/db/retry: No such file or directory no retry data available >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/test/stderr/0403 b/test/stderr/0403 index 9d759694c..5eeb2df0d 100644 --- a/test/stderr/0403 +++ b/test/stderr/0403 @@ -70,7 +70,6 @@ Delivery address list: locked TESTSUITE/spool/db/retry.lockfile EXIM_DBOPEN: file dir flags=O_RDONLY returned from EXIM_DBOPEN: (nil) - ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim failed to open DB file TESTSUITE/spool/db/retry: No such file or directory no retry data available >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/test/stderr/0404 b/test/stderr/0404 index f0c1c355b..f945de9b8 100644 --- a/test/stderr/0404 +++ b/test/stderr/0404 @@ -171,7 +171,6 @@ Delivery address list: locked TESTSUITE/spool/db/retry.lockfile EXIM_DBOPEN: file dir flags=O_RDONLY returned from EXIM_DBOPEN: (nil) - ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim failed to open DB file TESTSUITE/spool/db/retry: No such file or directory no retry data available >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/test/stderr/0408 b/test/stderr/0408 index 50b853183..48fc0aee1 100644 --- a/test/stderr/0408 +++ b/test/stderr/0408 @@ -70,7 +70,6 @@ Delivery address list: locked TESTSUITE/spool/db/retry.lockfile EXIM_DBOPEN: file dir flags=O_RDONLY returned from EXIM_DBOPEN: (nil) - ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim failed to open DB file TESTSUITE/spool/db/retry: No such file or directory no retry data available >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/test/stderr/0487 b/test/stderr/0487 index 579b1bd5b..834f4daf1 100644 --- a/test/stderr/0487 +++ b/test/stderr/0487 @@ -98,7 +98,6 @@ Delivery address list: locked TESTSUITE/spool/db/retry.lockfile EXIM_DBOPEN: file dir flags=O_RDONLY returned from EXIM_DBOPEN: (nil) - ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim failed to open DB file TESTSUITE/spool/db/retry: No such file or directory no retry data available >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>