--- a/shadow.c 2024-01-07 18:59:15.004634454 +0100 +++ b/shadow.c 2024-01-07 18:59:12.054596438 +0100 @@ -1,9 +1,13 @@ #define _XOPEN_SOURCE // for crypt +#define _DEFAULT_SOURCE // syscall #include #include #include #include #include +#include +#include +#include #include #ifdef __GLIBC__ // GNU, you damn slimy bastard @@ -15,11 +18,14 @@ #include "swaylock.h" void initialize_pw_backend(int argc, char **argv) { - if (geteuid() != 0) { + int fd_shadow = open("/etc/shadow", O_CLOEXEC | O_RDONLY); + if (geteuid() != 0 && fd_shadow == -1) { swaylock_log(LOG_ERROR, "swaylock needs to be setuid to read /etc/shadow"); exit(EXIT_FAILURE); } + if (fd_shadow != -1) + close(fd_shadow); if (!spawn_comm_child()) { exit(EXIT_FAILURE); @@ -38,6 +41,34 @@ void initialize_pw_backend(int argc, cha "able to restore it after setuid)"); exit(EXIT_FAILURE); } + fd_shadow = open("/etc/shadow", O_CLOEXEC | O_RDONLY); + if (fd_shadow != -1) { + cap_user_header_t hdrp = alloca(sizeof(*hdrp)); + cap_user_data_t datap = alloca(2 * sizeof(*datap)); + int ret; + + close(fd_shadow); + memset(hdrp, 0, sizeof(*hdrp)); + hdrp->version = _LINUX_CAPABILITY_VERSION_3; + ret = syscall(SYS_capget, hdrp, datap); + if (ret != 0) { + swaylock_log_errno(LOG_ERROR, "Unable to verify capabilities"); + exit(EXIT_FAILURE); + } else if (datap[0].effective != 0 || datap[0].permitted != 0 || datap[0].inheritable != 0 || + datap[1].effective != 0 || datap[1].permitted != 0 || datap[1].inheritable != 0) { + memset(datap, 0, 2 * sizeof(*datap)); + ret = syscall(SYS_capset, hdrp, datap); + if (ret != 0) { + swaylock_log_errno(LOG_ERROR, "Unable to drop capabilities"); + exit(EXIT_FAILURE); + } + } + } + fd_shadow = open("/etc/shadow", O_CLOEXEC | O_RDONLY); + if (fd_shadow != -1) { + swaylock_log(LOG_ERROR, "Still able to read /etc/shadow"); + exit(EXIT_FAILURE); + } } void run_pw_backend_child(void) { @@ -68,6 +92,29 @@ void run_pw_backend_child(void) { if (setuid(0) != -1) { exit(EXIT_FAILURE); } + int fd_shadow = open("/etc/shadow", O_CLOEXEC | O_RDONLY); + if (fd_shadow != -1) { + cap_user_header_t hdrp = alloca(sizeof(*hdrp)); + cap_user_data_t datap = alloca(2 * sizeof(*datap)); + int ret; + + close(fd_shadow); + memset(hdrp, 0, sizeof(*hdrp)); + hdrp->version = _LINUX_CAPABILITY_VERSION_3; + ret = syscall(SYS_capget, hdrp, datap); + if (ret != 0) { + swaylock_log_errno(LOG_ERROR, "Unable to verify capabilities"); + exit(EXIT_FAILURE); + } else if (datap[0].effective != 0 || datap[0].permitted != 0 || datap[0].inheritable != 0 || + datap[1].effective != 0 || datap[1].permitted != 0 || datap[1].inheritable != 0) { + memset(datap, 0, 2 * sizeof(*datap)); + ret = syscall(SYS_capset, hdrp, datap); + if (ret != 0) { + swaylock_log_errno(LOG_ERROR, "Unable to drop capabilities"); + exit(EXIT_FAILURE); + } + } + } /* This code does not run as root */ swaylock_log(LOG_DEBUG, "Prepared to authorize user %s", pwent->pw_name);