/* * seatd-user.c - minimal setuid-root wrapper to start/stop seatd for one user * * build: u=n76310; gcc -O2 -Wall -Wextra -DSEATD_USER="$u" seatd-user.c -o seatd-$u * install: chown root:$u seatd-$u; chmod 4750 seatd-$u; mv seatd-$u /usr/bin/ * * Only the group owner (the user) may execute it. seatd runs as root and * hands its socket to SEATD_USER. */ #include #include #include #include #include #include #include #define STRINGIFY(x) #x #define STRINGIFY2(x) STRINGIFY(x) #ifndef SEATD_USER #error "SEATD_USER not defined, build with -DSEATD_USER=" #endif #define SEATD_USER_STRING STRINGIFY2(SEATD_USER) #define SEATD_BIN "/usr/bin/seatd" #define PKILL_BIN "/usr/bin/pkill" /* fixed environment, nothing from the caller leaks into root context */ static char *const clean_env[] = { "PATH=/usr/bin:/bin", NULL }; /* make sure 0/1/2 are open so nothing we open later lands on them */ static void secure_std_fds(void) { for (int fd = 0; fd <= 2; fd++) { if (fcntl(fd, F_GETFD) == -1 && errno == EBADF) { int n = open("/dev/null", fd == 0 ? O_RDONLY : O_WRONLY); if (n != fd) _exit(1); } } } static int become_root(void) { if (setgid(0) != 0 || setuid(0) != 0) { fprintf(stderr, "not running setuid root: %s\n", strerror(errno)); return -1; } return 0; } static int start_seatd(void) { char *const argv[] = { "seatd", "-u", SEATD_USER_STRING, NULL }; execve(SEATD_BIN, argv, clean_env); fprintf(stderr, "exec %s: %s\n", SEATD_BIN, strerror(errno)); return 1; } static int stop_seatd(void) { char *const argv[] = { "pkill", "-x", "seatd", NULL }; int status; pid_t pid = fork(); if (pid < 0) { fprintf(stderr, "fork: %s\n", strerror(errno)); return 1; } if (pid == 0) { execve(PKILL_BIN, argv, clean_env); fprintf(stderr, "exec %s: %s\n", PKILL_BIN, strerror(errno)); _exit(127); } if (waitpid(pid, &status, 0) < 0) { fprintf(stderr, "waitpid: %s\n", strerror(errno)); return 1; } if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { fprintf(stderr, "no running seatd or failed to stop it\n"); return 1; } return 0; } int main(int argc, char *argv[]) { secure_std_fds(); if (argc != 2) { fprintf(stderr, "Usage: %s start|stop\n", argv[0]); return 1; } if (strcmp(argv[1], "start") != 0 && strcmp(argv[1], "stop") != 0) { fprintf(stderr, "Invalid argument. Use 'start' or 'stop'\n"); return 1; } if (become_root() != 0) return 1; return strcmp(argv[1], "start") == 0 ? start_seatd() : stop_seatd(); }