aboutsummaryrefslogtreecommitdiffstats
path: root/swaylock/shadow.c
diff options
context:
space:
mode:
Diffstat (limited to 'swaylock/shadow.c')
-rw-r--r--swaylock/shadow.c155
1 files changed, 0 insertions, 155 deletions
diff --git a/swaylock/shadow.c b/swaylock/shadow.c
deleted file mode 100644
index b7b10a67..00000000
--- a/swaylock/shadow.c
+++ /dev/null
@@ -1,155 +0,0 @@
1#define _XOPEN_SOURCE // for crypt
2#include <pwd.h>
3#include <shadow.h>
4#include <stdbool.h>
5#include <sys/types.h>
6#include <unistd.h>
7#include <wlr/util/log.h>
8#include "swaylock/swaylock.h"
9#ifdef __GLIBC__
10// GNU, you damn slimy bastard
11#include <crypt.h>
12#endif
13
14static int comm[2][2];
15
16static void clear_buffer(void *buf, size_t bytes) {
17 volatile char *buffer = buf;
18 volatile char zero = '\0';
19 for (size_t i = 0; i < bytes; ++i) {
20 buffer[i] = zero;
21 }
22}
23
24void run_child(void) {
25 /* This code runs as root */
26 struct passwd *pwent = getpwuid(getuid());
27 if (!pwent) {
28 wlr_log_errno(WLR_ERROR, "failed to getpwuid");
29 exit(EXIT_FAILURE);
30 }
31 char *encpw = pwent->pw_passwd;
32 if (strcmp(encpw, "x") == 0) {
33 struct spwd *swent = getspnam(pwent->pw_name);
34 if (!swent) {
35 wlr_log_errno(WLR_ERROR, "failed to getspnam");
36 exit(EXIT_FAILURE);
37 }
38 encpw = swent->sp_pwdp;
39 }
40
41 /* We don't need any additional logging here because the parent process will
42 * also fail here and will handle logging for us. */
43 if (setgid(getgid()) != 0) {
44 exit(EXIT_FAILURE);
45 }
46 if (setuid(getuid()) != 0) {
47 exit(EXIT_FAILURE);
48 }
49
50 /* This code does not run as root */
51 wlr_log(WLR_DEBUG, "prepared to authorize user %s", pwent->pw_name);
52
53 size_t size;
54 char *buf;
55 while (1) {
56 ssize_t amt;
57 amt = read(comm[0][0], &size, sizeof(size));
58 if (amt == 0) {
59 break;
60 } else if (amt < 0) {
61 wlr_log_errno(WLR_ERROR, "read pw request");
62 }
63 wlr_log(WLR_DEBUG, "received pw check request");
64 buf = malloc(size);
65 if (!buf) {
66 wlr_log_errno(WLR_ERROR, "failed to malloc pw buffer");
67 exit(EXIT_FAILURE);
68 }
69 size_t offs = 0;
70 do {
71 amt = read(comm[0][0], &buf[offs], size - offs);
72 if (amt <= 0) {
73 wlr_log_errno(WLR_ERROR, "failed to read pw");
74 exit(EXIT_FAILURE);
75 }
76 offs += (size_t)amt;
77 } while (offs < size);
78 bool result = false;
79 char *c = crypt(buf, encpw);
80 if (c == NULL) {
81 wlr_log_errno(WLR_ERROR, "crypt");
82 }
83 result = strcmp(c, encpw) == 0;
84 if (write(comm[1][1], &result, sizeof(result)) != sizeof(result)) {
85 wlr_log_errno(WLR_ERROR, "failed to write pw check result");
86 clear_buffer(buf, size);
87 exit(EXIT_FAILURE);
88 }
89 clear_buffer(buf, size);
90 free(buf);
91 }
92
93 clear_buffer(encpw, strlen(encpw));
94 exit(EXIT_SUCCESS);
95}
96
97void initialize_pw_backend(void) {
98 if (geteuid() != 0) {
99 wlr_log(WLR_ERROR, "swaylock needs to be setuid to read /etc/shadow");
100 exit(EXIT_FAILURE);
101 }
102 if (pipe(comm[0]) != 0) {
103 wlr_log_errno(WLR_ERROR, "failed to create pipe");
104 exit(EXIT_FAILURE);
105 }
106 if (pipe(comm[1]) != 0) {
107 wlr_log_errno(WLR_ERROR, "failed to create pipe");
108 exit(EXIT_FAILURE);
109 }
110 pid_t child = fork();
111 if (child == 0) {
112 close(comm[0][1]);
113 close(comm[1][0]);
114 run_child();
115 } else if (child < 0) {
116 wlr_log_errno(WLR_ERROR, "failed to fork");
117 exit(EXIT_FAILURE);
118 }
119 close(comm[0][0]);
120 close(comm[1][1]);
121 if (setgid(getgid()) != 0) {
122 wlr_log_errno(WLR_ERROR, "Unable to drop root");
123 exit(EXIT_FAILURE);
124 }
125 if (setuid(getuid()) != 0) {
126 wlr_log_errno(WLR_ERROR, "Unable to drop root");
127 exit(EXIT_FAILURE);
128 }
129}
130
131bool attempt_password(struct swaylock_password *pw) {
132 bool result = false;
133 size_t len = pw->len + 1;
134 size_t offs = 0;
135 if (write(comm[0][1], &len, sizeof(len)) < 0) {
136 wlr_log_errno(WLR_ERROR, "Failed to request pw check");
137 goto ret;
138 }
139 do {
140 ssize_t amt = write(comm[0][1], &pw->buffer[offs], len - offs);
141 if (amt < 0) {
142 wlr_log_errno(WLR_ERROR, "Failed to write pw buffer");
143 goto ret;
144 }
145 offs += amt;
146 } while (offs < len);
147 if (read(comm[1][0], &result, sizeof(result)) != sizeof(result)) {
148 wlr_log_errno(WLR_ERROR, "Failed to read pw result");
149 goto ret;
150 }
151 wlr_log(WLR_DEBUG, "pw result: %d", result);
152ret:
153 clear_password_buffer(pw);
154 return result;
155}