diff options
Diffstat (limited to 'swaylock/shadow.c')
-rw-r--r-- | swaylock/shadow.c | 155 |
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 | |||
14 | static int comm[2][2]; | ||
15 | |||
16 | static 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 | |||
24 | void 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 | |||
97 | void 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 | |||
131 | bool 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); | ||
152 | ret: | ||
153 | clear_password_buffer(pw); | ||
154 | return result; | ||
155 | } | ||