main
44ceea7 ยท 1 month ago 7 commits
  1#define _XOPEN_SOURCE // for crypt
  2#include <pwd.h>
  3#include <shadow.h>
  4#include <stdlib.h>
  5#include <stdbool.h>
  6#include <sys/types.h>
  7#include <unistd.h>
  8#ifdef __GLIBC__
  9// GNU, you damn slimy bastard
 10#include <crypt.h>
 11#endif
 12#include "comm.h"
 13#include "log.h"
 14#include "password-buffer.h"
 15#include "swaylock.h"
 16
 17void initialize_pw_backend(int argc, char **argv) {
 18	if (geteuid() != 0) {
 19		swaylock_log(LOG_ERROR,
 20				"swaylock needs to be setuid to read /etc/shadow");
 21		exit(EXIT_FAILURE);
 22	}
 23
 24	if (!spawn_comm_child()) {
 25		exit(EXIT_FAILURE);
 26	}
 27
 28	if (setgid(getgid()) != 0) {
 29		swaylock_log_errno(LOG_ERROR, "Unable to drop root");
 30		exit(EXIT_FAILURE);
 31	}
 32	if (setuid(getuid()) != 0) {
 33		swaylock_log_errno(LOG_ERROR, "Unable to drop root");
 34		exit(EXIT_FAILURE);
 35	}
 36	if (setuid(0) != -1) {
 37		swaylock_log_errno(LOG_ERROR, "Unable to drop root (we shouldn't be "
 38			"able to restore it after setuid)");
 39		exit(EXIT_FAILURE);
 40	}
 41}
 42
 43void run_pw_backend_child(void) {
 44	/* This code runs as root */
 45	struct passwd *pwent = getpwuid(getuid());
 46	if (!pwent) {
 47		swaylock_log_errno(LOG_ERROR, "failed to getpwuid");
 48		exit(EXIT_FAILURE);
 49	}
 50	char *encpw = pwent->pw_passwd;
 51	if (strcmp(encpw, "x") == 0) {
 52		struct spwd *swent = getspnam(pwent->pw_name);
 53		if (!swent) {
 54			swaylock_log_errno(LOG_ERROR, "failed to getspnam");
 55			exit(EXIT_FAILURE);
 56		}
 57		encpw = swent->sp_pwdp;
 58	}
 59
 60	/* We don't need any additional logging here because the parent process will
 61	 * also fail here and will handle logging for us. */
 62	if (setgid(getgid()) != 0) {
 63		exit(EXIT_FAILURE);
 64	}
 65	if (setuid(getuid()) != 0) {
 66		exit(EXIT_FAILURE);
 67	}
 68	if (setuid(0) != -1) {
 69		exit(EXIT_FAILURE);
 70	}
 71
 72	/* This code does not run as root */
 73	swaylock_log(LOG_DEBUG, "Prepared to authorize user %s", pwent->pw_name);
 74
 75	while (1) {
 76		char *buf;
 77		ssize_t size = read_comm_request(&buf);
 78		if (size < 0) {
 79			exit(EXIT_FAILURE);
 80		} else if (size == 0) {
 81			break;
 82		}
 83
 84		const char *c = crypt(buf, encpw);
 85		password_buffer_destroy(buf, size);
 86		buf = NULL;
 87
 88		if (c == NULL) {
 89			swaylock_log_errno(LOG_ERROR, "crypt failed");
 90			exit(EXIT_FAILURE);
 91		}
 92		bool success = strcmp(c, encpw) == 0;
 93
 94		if (!write_comm_reply(success)) {
 95			exit(EXIT_FAILURE);
 96		}
 97
 98		sleep(2);
 99	}
100
101	clear_buffer(encpw, strlen(encpw));
102	exit(EXIT_SUCCESS);
103}