Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <errno.h>
4 : #include <fcntl.h>
5 : #include <inttypes.h>
6 : #include <limits.h>
7 : #include <poll.h>
8 : #include <signal.h>
9 : #include <stdbool.h>
10 : #include <stddef.h>
11 : #include <stdint.h>
12 : #include <stdio.h>
13 : #include <stdlib.h>
14 : #include <string.h>
15 : #include <sys/inotify.h>
16 : #include <sys/signalfd.h>
17 : #include <sys/socket.h>
18 : #include <sys/stat.h>
19 : #include <sys/time.h>
20 : #include <sys/uio.h>
21 : #include <sys/un.h>
22 : #include <termios.h>
23 : #include <unistd.h>
24 :
25 : #include "alloc-util.h"
26 : #include "ask-password-api.h"
27 : #include "fd-util.h"
28 : #include "fileio.h"
29 : #include "format-util.h"
30 : #include "fs-util.h"
31 : #include "io-util.h"
32 : #include "log.h"
33 : #include "macro.h"
34 : #include "memory-util.h"
35 : #include "missing.h"
36 : #include "mkdir.h"
37 : #include "process-util.h"
38 : #include "random-util.h"
39 : #include "signal-util.h"
40 : #include "socket-util.h"
41 : #include "string-util.h"
42 : #include "strv.h"
43 : #include "terminal-util.h"
44 : #include "time-util.h"
45 : #include "tmpfile-util.h"
46 : #include "umask-util.h"
47 : #include "utf8.h"
48 :
49 : #define KEYRING_TIMEOUT_USEC ((5 * USEC_PER_MINUTE) / 2)
50 :
51 0 : static int lookup_key(const char *keyname, key_serial_t *ret) {
52 : key_serial_t serial;
53 :
54 0 : assert(keyname);
55 0 : assert(ret);
56 :
57 0 : serial = request_key("user", keyname, NULL, 0);
58 0 : if (serial == -1)
59 0 : return negative_errno();
60 :
61 0 : *ret = serial;
62 0 : return 0;
63 : }
64 :
65 0 : static int retrieve_key(key_serial_t serial, char ***ret) {
66 0 : size_t nfinal, m = 100;
67 : char **l;
68 0 : _cleanup_(erase_and_freep) char *pfinal = NULL;
69 :
70 0 : assert(ret);
71 :
72 0 : for (;;) {
73 0 : _cleanup_(erase_and_freep) char *p = NULL;
74 : long n;
75 :
76 0 : p = new(char, m);
77 0 : if (!p)
78 0 : return -ENOMEM;
79 :
80 0 : n = keyctl(KEYCTL_READ, (unsigned long) serial, (unsigned long) p, (unsigned long) m, 0);
81 0 : if (n < 0)
82 0 : return -errno;
83 0 : if ((size_t) n < m) {
84 0 : nfinal = (size_t) n;
85 0 : pfinal = TAKE_PTR(p);
86 0 : break;
87 : }
88 :
89 0 : if (m > LONG_MAX / 2) /* overflow check */
90 0 : return -ENOMEM;
91 0 : m *= 2;
92 : }
93 :
94 0 : l = strv_parse_nulstr(pfinal, nfinal);
95 0 : if (!l)
96 0 : return -ENOMEM;
97 :
98 0 : *ret = l;
99 0 : return 0;
100 : }
101 :
102 0 : static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **passwords) {
103 0 : _cleanup_strv_free_erase_ char **l = NULL;
104 0 : _cleanup_(erase_and_freep) char *p = NULL;
105 : key_serial_t serial;
106 : size_t n;
107 : int r;
108 :
109 0 : assert(keyname);
110 0 : assert(passwords);
111 :
112 0 : if (!(flags & ASK_PASSWORD_PUSH_CACHE))
113 0 : return 0;
114 :
115 0 : r = lookup_key(keyname, &serial);
116 0 : if (r >= 0) {
117 0 : r = retrieve_key(serial, &l);
118 0 : if (r < 0)
119 0 : return r;
120 0 : } else if (r != -ENOKEY)
121 0 : return r;
122 :
123 0 : r = strv_extend_strv(&l, passwords, true);
124 0 : if (r <= 0)
125 0 : return r;
126 :
127 0 : r = strv_make_nulstr(l, &p, &n);
128 0 : if (r < 0)
129 0 : return r;
130 :
131 0 : serial = add_key("user", keyname, p, n, KEY_SPEC_USER_KEYRING);
132 0 : if (serial == -1)
133 0 : return -errno;
134 :
135 0 : if (keyctl(KEYCTL_SET_TIMEOUT,
136 : (unsigned long) serial,
137 0 : (unsigned long) DIV_ROUND_UP(KEYRING_TIMEOUT_USEC, USEC_PER_SEC), 0, 0) < 0)
138 0 : log_debug_errno(errno, "Failed to adjust timeout: %m");
139 :
140 : /* Tell everyone to check the keyring */
141 0 : (void) touch("/run/systemd/ask-password");
142 :
143 0 : log_debug("Added key to keyring as %" PRIi32 ".", serial);
144 :
145 0 : return 1;
146 : }
147 :
148 0 : static int add_to_keyring_and_log(const char *keyname, AskPasswordFlags flags, char **passwords) {
149 : int r;
150 :
151 0 : assert(keyname);
152 0 : assert(passwords);
153 :
154 0 : r = add_to_keyring(keyname, flags, passwords);
155 0 : if (r < 0)
156 0 : return log_debug_errno(r, "Failed to add password to keyring: %m");
157 :
158 0 : return 0;
159 : }
160 :
161 0 : static int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret) {
162 :
163 : key_serial_t serial;
164 : int r;
165 :
166 0 : assert(keyname);
167 0 : assert(ret);
168 :
169 0 : if (!(flags & ASK_PASSWORD_ACCEPT_CACHED))
170 0 : return -EUNATCH;
171 :
172 0 : r = lookup_key(keyname, &serial);
173 0 : if (r == -ENOSYS) /* when retrieving the distinction doesn't matter */
174 0 : return -ENOKEY;
175 0 : if (r < 0)
176 0 : return r;
177 :
178 0 : return retrieve_key(serial, ret);
179 : }
180 :
181 0 : static int backspace_chars(int ttyfd, size_t p) {
182 0 : if (ttyfd < 0)
183 0 : return 0;
184 :
185 0 : _cleanup_free_ char *buf = malloc_multiply(3, p);
186 0 : if (!buf)
187 0 : return log_oom();
188 :
189 0 : for (size_t i = 0; i < p; i++)
190 0 : memcpy(buf + 3 * i, "\b \b", 3);
191 :
192 0 : return loop_write(ttyfd, buf, 3*p, false);
193 : }
194 :
195 0 : static int backspace_string(int ttyfd, const char *str) {
196 0 : assert(str);
197 :
198 : /* Backspaces through enough characters to entirely undo printing of the specified string. */
199 :
200 0 : if (ttyfd < 0)
201 0 : return 0;
202 :
203 0 : size_t m = utf8_n_codepoints(str);
204 0 : if (m == (size_t) -1)
205 0 : m = strlen(str); /* Not a valid UTF-8 string? If so, let's backspace the number of bytes
206 : * output. Most likely this happened because we are not in an UTF-8 locale,
207 : * and in that case that is the correct thing to do. And even if it's not,
208 : * terminals tend to stop backspacing at the leftmost column, hence
209 : * backspacing too much should be mostly OK. */
210 :
211 0 : return backspace_chars(ttyfd, m);
212 : }
213 :
214 0 : int ask_password_tty(
215 : int ttyfd,
216 : const char *message,
217 : const char *keyname,
218 : usec_t until,
219 : AskPasswordFlags flags,
220 : const char *flag_file,
221 : char ***ret) {
222 :
223 : enum {
224 : POLL_TTY,
225 : POLL_INOTIFY,
226 : _POLL_MAX,
227 : };
228 :
229 0 : bool reset_tty = false, dirty = false, use_color = false;
230 0 : _cleanup_close_ int cttyfd = -1, notify = -1;
231 : struct termios old_termios, new_termios;
232 0 : char passphrase[LINE_MAX + 1] = {}, *x;
233 0 : _cleanup_strv_free_erase_ char **l = NULL;
234 : struct pollfd pollfd[_POLL_MAX];
235 0 : size_t p = 0, codepoint = 0;
236 : int r;
237 :
238 0 : assert(ret);
239 :
240 0 : if (flags & ASK_PASSWORD_NO_TTY)
241 0 : return -EUNATCH;
242 :
243 0 : if (!message)
244 0 : message = "Password:";
245 :
246 0 : if (flag_file || ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname)) {
247 0 : notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
248 0 : if (notify < 0)
249 0 : return -errno;
250 : }
251 0 : if (flag_file) {
252 0 : if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0)
253 0 : return -errno;
254 : }
255 0 : if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname) {
256 0 : r = ask_password_keyring(keyname, flags, ret);
257 0 : if (r >= 0)
258 0 : return 0;
259 0 : else if (r != -ENOKEY)
260 0 : return r;
261 :
262 0 : if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_ATTRIB /* for mtime */) < 0)
263 0 : return -errno;
264 : }
265 :
266 : /* If the caller didn't specify a TTY, then use the controlling tty, if we can. */
267 0 : if (ttyfd < 0)
268 0 : ttyfd = cttyfd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC);
269 :
270 0 : if (ttyfd >= 0) {
271 0 : if (tcgetattr(ttyfd, &old_termios) < 0)
272 0 : return -errno;
273 :
274 0 : if (flags & ASK_PASSWORD_CONSOLE_COLOR)
275 0 : use_color = dev_console_colors_enabled();
276 : else
277 0 : use_color = colors_enabled();
278 :
279 0 : if (use_color)
280 0 : (void) loop_write(ttyfd, ANSI_HIGHLIGHT, STRLEN(ANSI_HIGHLIGHT), false);
281 :
282 0 : (void) loop_write(ttyfd, message, strlen(message), false);
283 0 : (void) loop_write(ttyfd, " ", 1, false);
284 :
285 0 : if (use_color)
286 0 : (void) loop_write(ttyfd, ANSI_NORMAL, STRLEN(ANSI_NORMAL), false);
287 :
288 0 : new_termios = old_termios;
289 0 : new_termios.c_lflag &= ~(ICANON|ECHO);
290 0 : new_termios.c_cc[VMIN] = 1;
291 0 : new_termios.c_cc[VTIME] = 0;
292 :
293 0 : if (tcsetattr(ttyfd, TCSADRAIN, &new_termios) < 0) {
294 0 : r = -errno;
295 0 : goto finish;
296 : }
297 :
298 0 : reset_tty = true;
299 : }
300 :
301 0 : pollfd[POLL_TTY] = (struct pollfd) {
302 0 : .fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO,
303 : .events = POLLIN,
304 : };
305 0 : pollfd[POLL_INOTIFY] = (struct pollfd) {
306 : .fd = notify,
307 : .events = POLLIN,
308 : };
309 :
310 0 : for (;;) {
311 0 : _cleanup_(erase_char) char c;
312 0 : int sleep_for = -1, k;
313 : ssize_t n;
314 :
315 0 : if (until > 0) {
316 : usec_t y;
317 :
318 0 : y = now(CLOCK_MONOTONIC);
319 :
320 0 : if (y > until) {
321 0 : r = -ETIME;
322 0 : goto finish;
323 : }
324 :
325 0 : sleep_for = (int) DIV_ROUND_UP(until - y, USEC_PER_MSEC);
326 : }
327 :
328 0 : if (flag_file)
329 0 : if (access(flag_file, F_OK) < 0) {
330 0 : r = -errno;
331 0 : goto finish;
332 : }
333 :
334 0 : k = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for);
335 0 : if (k < 0) {
336 0 : if (errno == EINTR)
337 0 : continue;
338 :
339 0 : r = -errno;
340 0 : goto finish;
341 0 : } else if (k == 0) {
342 0 : r = -ETIME;
343 0 : goto finish;
344 : }
345 :
346 0 : if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0 && keyname) {
347 0 : (void) flush_fd(notify);
348 :
349 0 : r = ask_password_keyring(keyname, flags, ret);
350 0 : if (r >= 0) {
351 0 : r = 0;
352 0 : goto finish;
353 0 : } else if (r != -ENOKEY)
354 0 : goto finish;
355 : }
356 :
357 0 : if (pollfd[POLL_TTY].revents == 0)
358 0 : continue;
359 :
360 0 : n = read(ttyfd >= 0 ? ttyfd : STDIN_FILENO, &c, 1);
361 0 : if (n < 0) {
362 0 : if (IN_SET(errno, EINTR, EAGAIN))
363 0 : continue;
364 :
365 0 : r = -errno;
366 0 : goto finish;
367 :
368 : }
369 :
370 : /* We treat EOF, newline and NUL byte all as valid end markers */
371 0 : if (n == 0 || c == '\n' || c == 0)
372 : break;
373 :
374 0 : if (c == 21) { /* C-u */
375 :
376 0 : if (!(flags & ASK_PASSWORD_SILENT))
377 0 : (void) backspace_string(ttyfd, passphrase);
378 :
379 0 : explicit_bzero_safe(passphrase, sizeof(passphrase));
380 0 : p = codepoint = 0;
381 :
382 0 : } else if (IN_SET(c, '\b', 127)) {
383 :
384 0 : if (p > 0) {
385 : size_t q;
386 :
387 0 : if (!(flags & ASK_PASSWORD_SILENT))
388 0 : (void) backspace_chars(ttyfd, 1);
389 :
390 : /* Remove a full UTF-8 codepoint from the end. For that, figure out where the
391 : * last one begins */
392 0 : q = 0;
393 0 : for (;;) {
394 : size_t z;
395 :
396 0 : z = utf8_encoded_valid_unichar(passphrase + q, (size_t) -1);
397 0 : if (z == 0) {
398 0 : q = (size_t) -1; /* Invalid UTF8! */
399 0 : break;
400 : }
401 :
402 0 : if (q + z >= p) /* This one brings us over the edge */
403 0 : break;
404 :
405 0 : q += z;
406 : }
407 :
408 0 : p = codepoint = q == (size_t) -1 ? p - 1 : q;
409 0 : explicit_bzero_safe(passphrase + p, sizeof(passphrase) - p);
410 :
411 0 : } else if (!dirty && !(flags & ASK_PASSWORD_SILENT)) {
412 :
413 0 : flags |= ASK_PASSWORD_SILENT;
414 :
415 : /* There are two ways to enter silent mode. Either by pressing backspace as
416 : * first key (and only as first key), or ... */
417 :
418 0 : if (ttyfd >= 0)
419 0 : (void) loop_write(ttyfd, "(no echo) ", 10, false);
420 :
421 0 : } else if (ttyfd >= 0)
422 0 : (void) loop_write(ttyfd, "\a", 1, false);
423 :
424 0 : } else if (c == '\t' && !(flags & ASK_PASSWORD_SILENT)) {
425 :
426 0 : (void) backspace_string(ttyfd, passphrase);
427 0 : flags |= ASK_PASSWORD_SILENT;
428 :
429 : /* ... or by pressing TAB at any time. */
430 :
431 0 : if (ttyfd >= 0)
432 0 : (void) loop_write(ttyfd, "(no echo) ", 10, false);
433 :
434 0 : } else if (p >= sizeof(passphrase)-1) {
435 :
436 : /* Reached the size limit */
437 0 : if (ttyfd >= 0)
438 0 : (void) loop_write(ttyfd, "\a", 1, false);
439 :
440 : } else {
441 0 : passphrase[p++] = c;
442 :
443 0 : if (!(flags & ASK_PASSWORD_SILENT) && ttyfd >= 0) {
444 : /* Check if we got a complete UTF-8 character now. If so, let's output one '*'. */
445 0 : n = utf8_encoded_valid_unichar(passphrase + codepoint, (size_t) -1);
446 0 : if (n >= 0) {
447 0 : if (flags & ASK_PASSWORD_ECHO)
448 0 : (void) loop_write(ttyfd, passphrase + codepoint, n, false);
449 : else
450 0 : (void) loop_write(ttyfd, "*", 1, false);
451 0 : codepoint = p;
452 : }
453 : }
454 :
455 0 : dirty = true;
456 : }
457 : }
458 :
459 0 : x = strndup(passphrase, p);
460 0 : explicit_bzero_safe(passphrase, sizeof(passphrase));
461 0 : if (!x) {
462 0 : r = -ENOMEM;
463 0 : goto finish;
464 : }
465 :
466 0 : r = strv_consume(&l, x);
467 0 : if (r < 0)
468 0 : goto finish;
469 :
470 0 : if (keyname)
471 0 : (void) add_to_keyring_and_log(keyname, flags, l);
472 :
473 0 : *ret = TAKE_PTR(l);
474 0 : r = 0;
475 :
476 0 : finish:
477 0 : if (ttyfd >= 0 && reset_tty) {
478 0 : (void) loop_write(ttyfd, "\n", 1, false);
479 0 : (void) tcsetattr(ttyfd, TCSADRAIN, &old_termios);
480 : }
481 :
482 0 : return r;
483 : }
484 :
485 0 : static int create_socket(char **ret) {
486 0 : _cleanup_free_ char *path = NULL;
487 0 : union sockaddr_union sa = {};
488 0 : _cleanup_close_ int fd = -1;
489 : int salen, r;
490 :
491 0 : assert(ret);
492 :
493 0 : fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
494 0 : if (fd < 0)
495 0 : return -errno;
496 :
497 0 : if (asprintf(&path, "/run/systemd/ask-password/sck.%" PRIx64, random_u64()) < 0)
498 0 : return -ENOMEM;
499 :
500 0 : salen = sockaddr_un_set_path(&sa.un, path);
501 0 : if (salen < 0)
502 0 : return salen;
503 :
504 0 : RUN_WITH_UMASK(0177) {
505 0 : if (bind(fd, &sa.sa, salen) < 0)
506 0 : return -errno;
507 : }
508 :
509 0 : r = setsockopt_int(fd, SOL_SOCKET, SO_PASSCRED, true);
510 0 : if (r < 0)
511 0 : return r;
512 :
513 0 : *ret = TAKE_PTR(path);
514 0 : return TAKE_FD(fd);
515 : }
516 :
517 0 : int ask_password_agent(
518 : const char *message,
519 : const char *icon,
520 : const char *id,
521 : const char *keyname,
522 : usec_t until,
523 : AskPasswordFlags flags,
524 : char ***ret) {
525 :
526 : enum {
527 : FD_SOCKET,
528 : FD_SIGNAL,
529 : FD_INOTIFY,
530 : _FD_MAX
531 : };
532 :
533 0 : _cleanup_close_ int socket_fd = -1, signal_fd = -1, notify = -1, fd = -1;
534 0 : char temp[] = "/run/systemd/ask-password/tmp.XXXXXX";
535 0 : char final[sizeof(temp)] = "";
536 0 : _cleanup_free_ char *socket_name = NULL;
537 0 : _cleanup_strv_free_erase_ char **l = NULL;
538 0 : _cleanup_fclose_ FILE *f = NULL;
539 : struct pollfd pollfd[_FD_MAX];
540 : sigset_t mask, oldmask;
541 : int r;
542 :
543 0 : assert(ret);
544 :
545 0 : if (flags & ASK_PASSWORD_NO_AGENT)
546 0 : return -EUNATCH;
547 :
548 0 : assert_se(sigemptyset(&mask) >= 0);
549 0 : assert_se(sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0);
550 0 : assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) >= 0);
551 :
552 0 : (void) mkdir_p_label("/run/systemd/ask-password", 0755);
553 :
554 0 : if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname) {
555 0 : r = ask_password_keyring(keyname, flags, ret);
556 0 : if (r >= 0) {
557 0 : r = 0;
558 0 : goto finish;
559 0 : } else if (r != -ENOKEY)
560 0 : goto finish;
561 :
562 0 : notify = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
563 0 : if (notify < 0) {
564 0 : r = -errno;
565 0 : goto finish;
566 : }
567 0 : if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_ATTRIB /* for mtime */) < 0) {
568 0 : r = -errno;
569 0 : goto finish;
570 : }
571 : }
572 :
573 0 : fd = mkostemp_safe(temp);
574 0 : if (fd < 0) {
575 0 : r = fd;
576 0 : goto finish;
577 : }
578 :
579 0 : (void) fchmod(fd, 0644);
580 :
581 0 : f = fdopen(fd, "w");
582 0 : if (!f) {
583 0 : r = -errno;
584 0 : goto finish;
585 : }
586 :
587 0 : fd = -1;
588 :
589 0 : signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
590 0 : if (signal_fd < 0) {
591 0 : r = -errno;
592 0 : goto finish;
593 : }
594 :
595 0 : socket_fd = create_socket(&socket_name);
596 0 : if (socket_fd < 0) {
597 0 : r = socket_fd;
598 0 : goto finish;
599 : }
600 :
601 0 : fprintf(f,
602 : "[Ask]\n"
603 : "PID="PID_FMT"\n"
604 : "Socket=%s\n"
605 : "AcceptCached=%i\n"
606 : "Echo=%i\n"
607 : "NotAfter="USEC_FMT"\n",
608 : getpid_cached(),
609 : socket_name,
610 0 : (flags & ASK_PASSWORD_ACCEPT_CACHED) ? 1 : 0,
611 0 : (flags & ASK_PASSWORD_ECHO) ? 1 : 0,
612 : until);
613 :
614 0 : if (message)
615 0 : fprintf(f, "Message=%s\n", message);
616 :
617 0 : if (icon)
618 0 : fprintf(f, "Icon=%s\n", icon);
619 :
620 0 : if (id)
621 0 : fprintf(f, "Id=%s\n", id);
622 :
623 0 : r = fflush_and_check(f);
624 0 : if (r < 0)
625 0 : goto finish;
626 :
627 0 : memcpy(final, temp, sizeof(temp));
628 :
629 0 : final[sizeof(final)-11] = 'a';
630 0 : final[sizeof(final)-10] = 's';
631 0 : final[sizeof(final)-9] = 'k';
632 :
633 0 : if (rename(temp, final) < 0) {
634 0 : r = -errno;
635 0 : goto finish;
636 : }
637 :
638 0 : zero(pollfd);
639 0 : pollfd[FD_SOCKET].fd = socket_fd;
640 0 : pollfd[FD_SOCKET].events = POLLIN;
641 0 : pollfd[FD_SIGNAL].fd = signal_fd;
642 0 : pollfd[FD_SIGNAL].events = POLLIN;
643 0 : pollfd[FD_INOTIFY].fd = notify;
644 0 : pollfd[FD_INOTIFY].events = POLLIN;
645 :
646 0 : for (;;) {
647 : char passphrase[LINE_MAX+1];
648 : struct msghdr msghdr;
649 : struct iovec iovec;
650 : struct ucred *ucred;
651 : union {
652 : struct cmsghdr cmsghdr;
653 : uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
654 : } control;
655 : ssize_t n;
656 : int k;
657 : usec_t t;
658 :
659 0 : t = now(CLOCK_MONOTONIC);
660 :
661 0 : if (until > 0 && until <= t) {
662 0 : r = -ETIME;
663 0 : goto finish;
664 : }
665 :
666 0 : k = poll(pollfd, notify >= 0 ? _FD_MAX : _FD_MAX - 1, until > 0 ? (int) ((until-t)/USEC_PER_MSEC) : -1);
667 0 : if (k < 0) {
668 0 : if (errno == EINTR)
669 0 : continue;
670 :
671 0 : r = -errno;
672 0 : goto finish;
673 : }
674 :
675 0 : if (k <= 0) {
676 0 : r = -ETIME;
677 0 : goto finish;
678 : }
679 :
680 0 : if (pollfd[FD_SIGNAL].revents & POLLIN) {
681 0 : r = -EINTR;
682 0 : goto finish;
683 : }
684 :
685 0 : if (notify >= 0 && pollfd[FD_INOTIFY].revents != 0) {
686 0 : (void) flush_fd(notify);
687 :
688 0 : r = ask_password_keyring(keyname, flags, ret);
689 0 : if (r >= 0) {
690 0 : r = 0;
691 0 : goto finish;
692 0 : } else if (r != -ENOKEY)
693 0 : goto finish;
694 : }
695 :
696 0 : if (pollfd[FD_SOCKET].revents == 0)
697 0 : continue;
698 :
699 0 : if (pollfd[FD_SOCKET].revents != POLLIN) {
700 0 : r = -EIO;
701 0 : goto finish;
702 : }
703 :
704 0 : iovec = IOVEC_MAKE(passphrase, sizeof(passphrase));
705 :
706 0 : zero(control);
707 0 : zero(msghdr);
708 0 : msghdr.msg_iov = &iovec;
709 0 : msghdr.msg_iovlen = 1;
710 0 : msghdr.msg_control = &control;
711 0 : msghdr.msg_controllen = sizeof(control);
712 :
713 0 : n = recvmsg(socket_fd, &msghdr, 0);
714 0 : if (n < 0) {
715 0 : if (IN_SET(errno, EAGAIN, EINTR))
716 0 : continue;
717 :
718 0 : r = -errno;
719 0 : goto finish;
720 : }
721 :
722 0 : cmsg_close_all(&msghdr);
723 :
724 0 : if (n <= 0) {
725 0 : log_debug("Message too short");
726 0 : continue;
727 : }
728 :
729 0 : if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
730 0 : control.cmsghdr.cmsg_level != SOL_SOCKET ||
731 0 : control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
732 0 : control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
733 0 : log_debug("Received message without credentials. Ignoring.");
734 0 : continue;
735 : }
736 :
737 0 : ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
738 0 : if (ucred->uid != 0) {
739 0 : log_debug("Got request from unprivileged user. Ignoring.");
740 0 : continue;
741 : }
742 :
743 0 : if (passphrase[0] == '+') {
744 : /* An empty message refers to the empty password */
745 0 : if (n == 1)
746 0 : l = strv_new("");
747 : else
748 0 : l = strv_parse_nulstr(passphrase+1, n-1);
749 0 : explicit_bzero_safe(passphrase, n);
750 0 : if (!l) {
751 0 : r = -ENOMEM;
752 0 : goto finish;
753 : }
754 :
755 0 : if (strv_isempty(l)) {
756 0 : l = strv_free(l);
757 0 : log_debug("Invalid packet");
758 0 : continue;
759 : }
760 :
761 0 : break;
762 : }
763 :
764 0 : if (passphrase[0] == '-') {
765 0 : r = -ECANCELED;
766 0 : goto finish;
767 : }
768 :
769 0 : log_debug("Invalid packet");
770 : }
771 :
772 0 : if (keyname)
773 0 : (void) add_to_keyring_and_log(keyname, flags, l);
774 :
775 0 : *ret = TAKE_PTR(l);
776 0 : r = 0;
777 :
778 0 : finish:
779 0 : if (socket_name)
780 0 : (void) unlink(socket_name);
781 :
782 0 : (void) unlink(temp);
783 :
784 0 : if (final[0])
785 0 : (void) unlink(final);
786 :
787 0 : assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
788 0 : return r;
789 : }
790 :
791 0 : int ask_password_auto(
792 : const char *message,
793 : const char *icon,
794 : const char *id,
795 : const char *keyname,
796 : usec_t until,
797 : AskPasswordFlags flags,
798 : char ***ret) {
799 :
800 : int r;
801 :
802 0 : assert(ret);
803 :
804 0 : if ((flags & ASK_PASSWORD_ACCEPT_CACHED) &&
805 0 : keyname &&
806 0 : ((flags & ASK_PASSWORD_NO_TTY) || !isatty(STDIN_FILENO)) &&
807 0 : (flags & ASK_PASSWORD_NO_AGENT)) {
808 0 : r = ask_password_keyring(keyname, flags, ret);
809 0 : if (r != -ENOKEY)
810 0 : return r;
811 : }
812 :
813 0 : if (!(flags & ASK_PASSWORD_NO_TTY) && isatty(STDIN_FILENO))
814 0 : return ask_password_tty(-1, message, keyname, until, flags, NULL, ret);
815 :
816 0 : if (!(flags & ASK_PASSWORD_NO_AGENT))
817 0 : return ask_password_agent(message, icon, id, keyname, until, flags, ret);
818 :
819 0 : return -EUNATCH;
820 : }
|