]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/ask-password-api.c
test: move {test,fuzz}-fido-id-desc.c into src/udev/fido_id
[thirdparty/systemd.git] / src / shared / ask-password-api.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
00843602 2
7f4e0805
LP
3#include <errno.h>
4#include <fcntl.h>
a8fbdf54
TA
5#include <inttypes.h>
6#include <limits.h>
00843602 7#include <poll.h>
a8fbdf54 8#include <signal.h>
00843602 9#include <stdbool.h>
7f4e0805 10#include <stddef.h>
a8fbdf54
TA
11#include <stdint.h>
12#include <stdio.h>
13#include <stdlib.h>
00843602
LP
14#include <string.h>
15#include <sys/inotify.h>
7f4e0805 16#include <sys/signalfd.h>
00843602 17#include <sys/socket.h>
a8fbdf54
TA
18#include <sys/stat.h>
19#include <sys/time.h>
20#include <sys/uio.h>
00843602
LP
21#include <sys/un.h>
22#include <termios.h>
23#include <unistd.h>
7f4e0805 24
b5efdb8a 25#include "alloc-util.h"
3ffd4af2 26#include "ask-password-api.h"
0e7f5ad9 27#include "def.h"
3ffd4af2 28#include "fd-util.h"
0d39fa9c 29#include "fileio.h"
f97b34a6 30#include "format-util.h"
c7b7d74e 31#include "fs-util.h"
c004493c 32#include "io-util.h"
a8fbdf54
TA
33#include "log.h"
34#include "macro.h"
0a970718 35#include "memory-util.h"
e287086b 36#include "missing.h"
49e942b2 37#include "mkdir.h"
df0ff127 38#include "process-util.h"
3df3e884 39#include "random-util.h"
24882e06 40#include "signal-util.h"
00843602 41#include "socket-util.h"
07630cea 42#include "string-util.h"
00843602
LP
43#include "strv.h"
44#include "terminal-util.h"
a8fbdf54 45#include "time-util.h"
e4de7287 46#include "tmpfile-util.h"
affb60b1 47#include "umask-util.h"
f3149d57 48#include "utf8.h"
7f4e0805 49
e287086b
LP
50#define KEYRING_TIMEOUT_USEC ((5 * USEC_PER_MINUTE) / 2)
51
52static int lookup_key(const char *keyname, key_serial_t *ret) {
53 key_serial_t serial;
54
55 assert(keyname);
56 assert(ret);
57
58 serial = request_key("user", keyname, NULL, 0);
59 if (serial == -1)
9c4615fb 60 return negative_errno();
e287086b
LP
61
62 *ret = serial;
63 return 0;
64}
65
66static int retrieve_key(key_serial_t serial, char ***ret) {
e693a932 67 size_t nfinal, m = 100;
e287086b 68 char **l;
e693a932 69 _cleanup_(erase_and_freep) char *pfinal = NULL;
e287086b
LP
70
71 assert(ret);
72
73 for (;;) {
e693a932
ZJS
74 _cleanup_(erase_and_freep) char *p = NULL;
75 long n;
76
e287086b
LP
77 p = new(char, m);
78 if (!p)
79 return -ENOMEM;
80
81 n = keyctl(KEYCTL_READ, (unsigned long) serial, (unsigned long) p, (unsigned long) m, 0);
82 if (n < 0)
83 return -errno;
e693a932
ZJS
84 if ((size_t) n < m) {
85 nfinal = (size_t) n;
86 pfinal = TAKE_PTR(p);
e287086b 87 break;
e693a932 88 }
054b6be0
LP
89
90 if (m > LONG_MAX / 2) /* overflow check */
91 return -ENOMEM;
e287086b
LP
92 m *= 2;
93 }
94
e693a932 95 l = strv_parse_nulstr(pfinal, nfinal);
e287086b
LP
96 if (!l)
97 return -ENOMEM;
98
99 *ret = l;
100 return 0;
101}
102
103static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **passwords) {
ab84f5b9 104 _cleanup_strv_free_erase_ char **l = NULL;
e693a932 105 _cleanup_(erase_and_freep) char *p = NULL;
e287086b
LP
106 key_serial_t serial;
107 size_t n;
108 int r;
109
110 assert(keyname);
111 assert(passwords);
112
113 if (!(flags & ASK_PASSWORD_PUSH_CACHE))
114 return 0;
115
116 r = lookup_key(keyname, &serial);
117 if (r >= 0) {
118 r = retrieve_key(serial, &l);
119 if (r < 0)
120 return r;
121 } else if (r != -ENOKEY)
122 return r;
123
124 r = strv_extend_strv(&l, passwords, true);
125 if (r <= 0)
126 return r;
127
128 r = strv_make_nulstr(l, &p, &n);
129 if (r < 0)
130 return r;
131
b60df13b 132 serial = add_key("user", keyname, p, n, KEY_SPEC_USER_KEYRING);
e287086b
LP
133 if (serial == -1)
134 return -errno;
135
136 if (keyctl(KEYCTL_SET_TIMEOUT,
137 (unsigned long) serial,
138 (unsigned long) DIV_ROUND_UP(KEYRING_TIMEOUT_USEC, USEC_PER_SEC), 0, 0) < 0)
139 log_debug_errno(errno, "Failed to adjust timeout: %m");
140
c7b7d74e
XF
141 /* Tell everyone to check the keyring */
142 (void) touch("/run/systemd/ask-password");
143
e287086b
LP
144 log_debug("Added key to keyring as %" PRIi32 ".", serial);
145
146 return 1;
147}
148
149static int add_to_keyring_and_log(const char *keyname, AskPasswordFlags flags, char **passwords) {
150 int r;
151
152 assert(keyname);
153 assert(passwords);
154
155 r = add_to_keyring(keyname, flags, passwords);
156 if (r < 0)
157 return log_debug_errno(r, "Failed to add password to keyring: %m");
158
159 return 0;
160}
161
8a111277 162static int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret) {
e287086b
LP
163
164 key_serial_t serial;
165 int r;
166
167 assert(keyname);
168 assert(ret);
169
170 if (!(flags & ASK_PASSWORD_ACCEPT_CACHED))
171 return -EUNATCH;
172
173 r = lookup_key(keyname, &serial);
174 if (r == -ENOSYS) /* when retrieving the distinction doesn't matter */
175 return -ENOKEY;
176 if (r < 0)
177 return r;
178
179 return retrieve_key(serial, ret);
180}
181
8e9d1eec 182static int backspace_chars(int ttyfd, size_t p) {
58fc840b 183 if (ttyfd < 0)
8e9d1eec 184 return 0;
58fc840b 185
8e9d1eec
ZJS
186 _cleanup_free_ char *buf = malloc_multiply(3, p);
187 if (!buf)
188 return log_oom();
58fc840b 189
8e9d1eec
ZJS
190 for (size_t i = 0; i < p; i++)
191 memcpy(buf + 3 * i, "\b \b", 3);
58fc840b 192
8e9d1eec
ZJS
193 return loop_write(ttyfd, buf, 3*p, false);
194}
fd6ac62c 195
8e9d1eec 196static int backspace_string(int ttyfd, const char *str) {
fd6ac62c
LP
197 assert(str);
198
f95dbcc2 199 /* Backspaces through enough characters to entirely undo printing of the specified string. */
fd6ac62c 200
8e9d1eec
ZJS
201 if (ttyfd < 0)
202 return 0;
203
204 size_t m = utf8_n_codepoints(str);
fd6ac62c 205 if (m == (size_t) -1)
8e9d1eec
ZJS
206 m = strlen(str); /* Not a valid UTF-8 string? If so, let's backspace the number of bytes
207 * output. Most likely this happened because we are not in an UTF-8 locale,
208 * and in that case that is the correct thing to do. And even if it's not,
209 * terminals tend to stop backspacing at the leftmost column, hence
210 * backspacing too much should be mostly OK. */
fd6ac62c 211
8e9d1eec 212 return backspace_chars(ttyfd, m);
fd6ac62c
LP
213}
214
6b2faba7
FB
215int ask_password_plymouth(
216 const char *message,
217 usec_t until,
218 AskPasswordFlags flags,
219 const char *flag_file,
220 char ***ret) {
221
222 static const union sockaddr_union sa = PLYMOUTH_SOCKET;
223 _cleanup_close_ int fd = -1, notify = -1;
224 _cleanup_free_ char *packet = NULL;
225 ssize_t k;
226 int r, n;
227 struct pollfd pollfd[2] = {};
228 char buffer[LINE_MAX];
229 size_t p = 0;
230 enum {
231 POLL_SOCKET,
232 POLL_INOTIFY
233 };
234
235 assert(ret);
236
237 if (flag_file) {
238 notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
239 if (notify < 0)
240 return -errno;
241
242 r = inotify_add_watch(notify, flag_file, IN_ATTRIB); /* for the link count */
243 if (r < 0)
244 return -errno;
245 }
246
247 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
248 if (fd < 0)
249 return -errno;
250
251 r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
252 if (r < 0)
253 return -errno;
254
255 if (flags & ASK_PASSWORD_ACCEPT_CACHED) {
256 packet = strdup("c");
257 n = 1;
258 } else if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0)
259 packet = NULL;
260 if (!packet)
261 return -ENOMEM;
262
263 r = loop_write(fd, packet, n + 1, true);
264 if (r < 0)
265 return r;
266
267 pollfd[POLL_SOCKET].fd = fd;
268 pollfd[POLL_SOCKET].events = POLLIN;
269 pollfd[POLL_INOTIFY].fd = notify;
270 pollfd[POLL_INOTIFY].events = POLLIN;
271
272 for (;;) {
273 int sleep_for = -1, j;
274
275 if (until > 0) {
276 usec_t y;
277
278 y = now(CLOCK_MONOTONIC);
279
280 if (y > until) {
281 r = -ETIME;
282 goto finish;
283 }
284
285 sleep_for = (int) ((until - y) / USEC_PER_MSEC);
286 }
287
288 if (flag_file && access(flag_file, F_OK) < 0) {
289 r = -errno;
290 goto finish;
291 }
292
293 j = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for);
294 if (j < 0) {
295 if (errno == EINTR)
296 continue;
297
298 r = -errno;
299 goto finish;
300 } else if (j == 0) {
301 r = -ETIME;
302 goto finish;
303 }
304
305 if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0)
306 (void) flush_fd(notify);
307
308 if (pollfd[POLL_SOCKET].revents == 0)
309 continue;
310
311 k = read(fd, buffer + p, sizeof(buffer) - p);
312 if (k < 0) {
313 if (IN_SET(errno, EINTR, EAGAIN))
314 continue;
315
316 r = -errno;
317 goto finish;
318 } else if (k == 0) {
319 r = -EIO;
320 goto finish;
321 }
322
323 p += k;
324
325 if (p < 1)
326 continue;
327
328 if (buffer[0] == 5) {
329
330 if (flags & ASK_PASSWORD_ACCEPT_CACHED) {
331 /* Hmm, first try with cached
332 * passwords failed, so let's retry
333 * with a normal password request */
334 packet = mfree(packet);
335
336 if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) {
337 r = -ENOMEM;
338 goto finish;
339 }
340
341 r = loop_write(fd, packet, n+1, true);
342 if (r < 0)
343 goto finish;
344
345 flags &= ~ASK_PASSWORD_ACCEPT_CACHED;
346 p = 0;
347 continue;
348 }
349
350 /* No password, because UI not shown */
351 r = -ENOENT;
352 goto finish;
353
354 } else if (IN_SET(buffer[0], 2, 9)) {
355 uint32_t size;
356 char **l;
357
358 /* One or more answers */
359 if (p < 5)
360 continue;
361
362 memcpy(&size, buffer+1, sizeof(size));
363 size = le32toh(size);
364 if (size + 5 > sizeof(buffer)) {
365 r = -EIO;
366 goto finish;
367 }
368
369 if (p-5 < size)
370 continue;
371
372 l = strv_parse_nulstr(buffer + 5, size);
373 if (!l) {
374 r = -ENOMEM;
375 goto finish;
376 }
377
378 *ret = l;
379 break;
380
381 } else {
382 /* Unknown packet */
383 r = -EIO;
384 goto finish;
385 }
386 }
387
388 r = 0;
389
390finish:
391 explicit_bzero_safe(buffer, sizeof(buffer));
392 return r;
393}
394
7f4e0805 395int ask_password_tty(
daa55720 396 int ttyfd,
7f4e0805 397 const char *message,
e287086b 398 const char *keyname,
7f4e0805 399 usec_t until,
e287086b 400 AskPasswordFlags flags,
7f4e0805 401 const char *flag_file,
c7b7d74e 402 char ***ret) {
7f4e0805 403
088dcd8e
LP
404 enum {
405 POLL_TTY,
406 POLL_INOTIFY,
407 _POLL_MAX,
408 };
409
c2b32159 410 bool reset_tty = false, dirty = false, use_color = false;
daa55720 411 _cleanup_close_ int cttyfd = -1, notify = -1;
7f4e0805 412 struct termios old_termios, new_termios;
f3149d57 413 char passphrase[LINE_MAX + 1] = {}, *x;
c7b7d74e 414 _cleanup_strv_free_erase_ char **l = NULL;
088dcd8e 415 struct pollfd pollfd[_POLL_MAX];
f3149d57 416 size_t p = 0, codepoint = 0;
088dcd8e 417 int r;
7f4e0805 418
e287086b
LP
419 assert(ret);
420
421 if (flags & ASK_PASSWORD_NO_TTY)
422 return -EUNATCH;
423
424 if (!message)
425 message = "Password:";
7f4e0805 426
c7b7d74e 427 if (flag_file || ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname)) {
981e4cd3 428 notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
a497a296
LP
429 if (notify < 0)
430 return -errno;
c7b7d74e
XF
431 }
432 if (flag_file) {
a497a296
LP
433 if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0)
434 return -errno;
7f4e0805 435 }
c7b7d74e
XF
436 if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname) {
437 r = ask_password_keyring(keyname, flags, ret);
438 if (r >= 0)
439 return 0;
440 else if (r != -ENOKEY)
441 return r;
442
443 if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_ATTRIB /* for mtime */) < 0)
444 return -errno;
445 }
7f4e0805 446
daa55720
LP
447 /* If the caller didn't specify a TTY, then use the controlling tty, if we can. */
448 if (ttyfd < 0)
449 ttyfd = cttyfd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC);
7f4e0805 450
daa55720 451 if (ttyfd >= 0) {
a497a296
LP
452 if (tcgetattr(ttyfd, &old_termios) < 0)
453 return -errno;
7f4e0805 454
c2b32159
LP
455 if (flags & ASK_PASSWORD_CONSOLE_COLOR)
456 use_color = dev_console_colors_enabled();
457 else
458 use_color = colors_enabled();
459
460 if (use_color)
ac7a9674
LP
461 (void) loop_write(ttyfd, ANSI_HIGHLIGHT, STRLEN(ANSI_HIGHLIGHT), false);
462
463 (void) loop_write(ttyfd, message, strlen(message), false);
464 (void) loop_write(ttyfd, " ", 1, false);
465
c2b32159 466 if (use_color)
ac7a9674 467 (void) loop_write(ttyfd, ANSI_NORMAL, STRLEN(ANSI_NORMAL), false);
7f4e0805
LP
468
469 new_termios = old_termios;
470 new_termios.c_lflag &= ~(ICANON|ECHO);
471 new_termios.c_cc[VMIN] = 1;
472 new_termios.c_cc[VTIME] = 0;
473
474 if (tcsetattr(ttyfd, TCSADRAIN, &new_termios) < 0) {
475 r = -errno;
476 goto finish;
477 }
478
479 reset_tty = true;
480 }
481
70dee475
LP
482 pollfd[POLL_TTY] = (struct pollfd) {
483 .fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO,
484 .events = POLLIN,
485 };
486 pollfd[POLL_INOTIFY] = (struct pollfd) {
487 .fd = notify,
488 .events = POLLIN,
489 };
7f4e0805
LP
490
491 for (;;) {
e1ed99c8 492 _cleanup_(erase_char) char c;
7f4e0805
LP
493 int sleep_for = -1, k;
494 ssize_t n;
495
496 if (until > 0) {
497 usec_t y;
498
499 y = now(CLOCK_MONOTONIC);
500
501 if (y > until) {
7ded2e28 502 r = -ETIME;
7f4e0805
LP
503 goto finish;
504 }
505
c9eb4a00 506 sleep_for = (int) DIV_ROUND_UP(until - y, USEC_PER_MSEC);
7f4e0805
LP
507 }
508
509 if (flag_file)
510 if (access(flag_file, F_OK) < 0) {
511 r = -errno;
512 goto finish;
513 }
514
e287086b 515 k = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for);
981e4cd3 516 if (k < 0) {
7f4e0805
LP
517 if (errno == EINTR)
518 continue;
519
520 r = -errno;
521 goto finish;
522 } else if (k == 0) {
ccc80078 523 r = -ETIME;
7f4e0805
LP
524 goto finish;
525 }
526
1f00998c 527 if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0 && keyname) {
665dfe93 528 (void) flush_fd(notify);
7f4e0805 529
c7b7d74e
XF
530 r = ask_password_keyring(keyname, flags, ret);
531 if (r >= 0) {
532 r = 0;
533 goto finish;
534 } else if (r != -ENOKEY)
535 goto finish;
536 }
537
7f4e0805
LP
538 if (pollfd[POLL_TTY].revents == 0)
539 continue;
540
981e4cd3
LP
541 n = read(ttyfd >= 0 ? ttyfd : STDIN_FILENO, &c, 1);
542 if (n < 0) {
3742095b 543 if (IN_SET(errno, EINTR, EAGAIN))
7f4e0805
LP
544 continue;
545
546 r = -errno;
547 goto finish;
548
fd6ac62c 549 }
7f4e0805 550
fd6ac62c
LP
551 /* We treat EOF, newline and NUL byte all as valid end markers */
552 if (n == 0 || c == '\n' || c == 0)
7f4e0805 553 break;
fd6ac62c 554
d325f244
FB
555 if (c == 4) { /* C-d also known as EOT */
556 if (ttyfd >= 0)
557 (void) loop_write(ttyfd, "(skipped)", 9, false);
558
559 goto skipped;
560 }
561
fd6ac62c 562 if (c == 21) { /* C-u */
7f4e0805 563
e287086b 564 if (!(flags & ASK_PASSWORD_SILENT))
8e9d1eec 565 (void) backspace_string(ttyfd, passphrase);
fd6ac62c 566
87f54463 567 explicit_bzero_safe(passphrase, sizeof(passphrase));
fd6ac62c 568 p = codepoint = 0;
7f4e0805 569
4c701096 570 } else if (IN_SET(c, '\b', 127)) {
58fc840b
LP
571
572 if (p > 0) {
fd6ac62c 573 size_t q;
58fc840b 574
e287086b 575 if (!(flags & ASK_PASSWORD_SILENT))
8e9d1eec 576 (void) backspace_chars(ttyfd, 1);
58fc840b 577
92e068b4
ZJS
578 /* Remove a full UTF-8 codepoint from the end. For that, figure out where the
579 * last one begins */
fd6ac62c
LP
580 q = 0;
581 for (;;) {
582 size_t z;
583
92e068b4 584 z = utf8_encoded_valid_unichar(passphrase + q, (size_t) -1);
fd6ac62c
LP
585 if (z == 0) {
586 q = (size_t) -1; /* Invalid UTF8! */
587 break;
588 }
589
590 if (q + z >= p) /* This one brings us over the edge */
591 break;
592
593 q += z;
594 }
595
596 p = codepoint = q == (size_t) -1 ? p - 1 : q;
87f54463 597 explicit_bzero_safe(passphrase + p, sizeof(passphrase) - p);
fd6ac62c 598
e287086b 599 } else if (!dirty && !(flags & ASK_PASSWORD_SILENT)) {
441dfe09 600
e287086b 601 flags |= ASK_PASSWORD_SILENT;
441dfe09 602
92e068b4
ZJS
603 /* There are two ways to enter silent mode. Either by pressing backspace as
604 * first key (and only as first key), or ... */
fd6ac62c 605
441dfe09 606 if (ttyfd >= 0)
ac7a9674 607 (void) loop_write(ttyfd, "(no echo) ", 10, false);
441dfe09 608
58fc840b 609 } else if (ttyfd >= 0)
ac7a9674 610 (void) loop_write(ttyfd, "\a", 1, false);
7f4e0805 611
e287086b 612 } else if (c == '\t' && !(flags & ASK_PASSWORD_SILENT)) {
58fc840b 613
8e9d1eec 614 (void) backspace_string(ttyfd, passphrase);
e287086b 615 flags |= ASK_PASSWORD_SILENT;
58fc840b 616
441dfe09
LP
617 /* ... or by pressing TAB at any time. */
618
58fc840b 619 if (ttyfd >= 0)
ac7a9674 620 (void) loop_write(ttyfd, "(no echo) ", 10, false);
036eeac5 621
fd6ac62c
LP
622 } else if (p >= sizeof(passphrase)-1) {
623
624 /* Reached the size limit */
625 if (ttyfd >= 0)
626 (void) loop_write(ttyfd, "\a", 1, false);
627
628 } else {
7f4e0805
LP
629 passphrase[p++] = c;
630
f3149d57 631 if (!(flags & ASK_PASSWORD_SILENT) && ttyfd >= 0) {
fd6ac62c 632 /* Check if we got a complete UTF-8 character now. If so, let's output one '*'. */
92e068b4 633 n = utf8_encoded_valid_unichar(passphrase + codepoint, (size_t) -1);
f3149d57 634 if (n >= 0) {
d26eef92
ZJS
635 if (flags & ASK_PASSWORD_ECHO)
636 (void) loop_write(ttyfd, passphrase + codepoint, n, false);
637 else
638 (void) loop_write(ttyfd, "*", 1, false);
f3149d57 639 codepoint = p;
f3149d57
ZJS
640 }
641 }
441dfe09
LP
642
643 dirty = true;
7f4e0805
LP
644 }
645 }
646
981e4cd3 647 x = strndup(passphrase, p);
87f54463 648 explicit_bzero_safe(passphrase, sizeof(passphrase));
981e4cd3 649 if (!x) {
7f4e0805
LP
650 r = -ENOMEM;
651 goto finish;
652 }
653
0e28c86f
LP
654 r = strv_consume(&l, x);
655 if (r < 0)
c7b7d74e 656 goto finish;
c7b7d74e 657
d325f244 658skipped:
e287086b 659 if (keyname)
c7b7d74e 660 (void) add_to_keyring_and_log(keyname, flags, l);
e287086b 661
c7b7d74e 662 *ret = TAKE_PTR(l);
7f4e0805
LP
663 r = 0;
664
665finish:
981e4cd3 666 if (ttyfd >= 0 && reset_tty) {
ac7a9674
LP
667 (void) loop_write(ttyfd, "\n", 1, false);
668 (void) tcsetattr(ttyfd, TCSADRAIN, &old_termios);
7f4e0805
LP
669 }
670
671 return r;
672}
673
15a3e96f
LP
674static int create_socket(char **ret) {
675 _cleanup_free_ char *path = NULL;
676 union sockaddr_union sa = {};
00843602 677 _cleanup_close_ int fd = -1;
2ff48e98 678 int salen, r;
7f4e0805 679
15a3e96f 680 assert(ret);
7f4e0805 681
e62d8c39 682 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
4a62c710 683 if (fd < 0)
00843602 684 return -errno;
7f4e0805 685
15a3e96f
LP
686 if (asprintf(&path, "/run/systemd/ask-password/sck.%" PRIx64, random_u64()) < 0)
687 return -ENOMEM;
688
689 salen = sockaddr_un_set_path(&sa.un, path);
690 if (salen < 0)
691 return salen;
7f4e0805 692
5c0d398d 693 RUN_WITH_UMASK(0177) {
15a3e96f 694 if (bind(fd, &sa.sa, salen) < 0)
00843602 695 return -errno;
5c0d398d 696 }
1d6702e8 697
2ff48e98
LP
698 r = setsockopt_int(fd, SOL_SOCKET, SO_PASSCRED, true);
699 if (r < 0)
700 return r;
7f4e0805 701
15a3e96f
LP
702 *ret = TAKE_PTR(path);
703 return TAKE_FD(fd);
7f4e0805
LP
704}
705
7f4e0805
LP
706int ask_password_agent(
707 const char *message,
708 const char *icon,
9fa1de96 709 const char *id,
e287086b 710 const char *keyname,
7f4e0805 711 usec_t until,
e287086b
LP
712 AskPasswordFlags flags,
713 char ***ret) {
7f4e0805
LP
714
715 enum {
716 FD_SOCKET,
717 FD_SIGNAL,
c7b7d74e 718 FD_INOTIFY,
7f4e0805
LP
719 _FD_MAX
720 };
721
c7b7d74e 722 _cleanup_close_ int socket_fd = -1, signal_fd = -1, notify = -1, fd = -1;
2b583ce6 723 char temp[] = "/run/systemd/ask-password/tmp.XXXXXX";
7f4e0805 724 char final[sizeof(temp)] = "";
981e4cd3 725 _cleanup_free_ char *socket_name = NULL;
c7b7d74e 726 _cleanup_strv_free_erase_ char **l = NULL;
e287086b 727 _cleanup_fclose_ FILE *f = NULL;
7f4e0805 728 struct pollfd pollfd[_FD_MAX];
e287086b 729 sigset_t mask, oldmask;
981e4cd3 730 int r;
7f4e0805 731
e287086b 732 assert(ret);
21bc923a 733
e287086b
LP
734 if (flags & ASK_PASSWORD_NO_AGENT)
735 return -EUNATCH;
00843602 736
72c0a2c2
LP
737 assert_se(sigemptyset(&mask) >= 0);
738 assert_se(sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0);
739 assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) >= 0);
f9b72cd8 740
00843602 741 (void) mkdir_p_label("/run/systemd/ask-password", 0755);
7f4e0805 742
c7b7d74e
XF
743 if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname) {
744 r = ask_password_keyring(keyname, flags, ret);
745 if (r >= 0) {
746 r = 0;
747 goto finish;
748 } else if (r != -ENOKEY)
749 goto finish;
750
751 notify = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
752 if (notify < 0) {
753 r = -errno;
754 goto finish;
755 }
756 if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_ATTRIB /* for mtime */) < 0) {
757 r = -errno;
758 goto finish;
759 }
760 }
761
646853bd 762 fd = mkostemp_safe(temp);
1d6702e8 763 if (fd < 0) {
709f6e46 764 r = fd;
7f4e0805
LP
765 goto finish;
766 }
767
00843602 768 (void) fchmod(fd, 0644);
7f4e0805 769
981e4cd3
LP
770 f = fdopen(fd, "w");
771 if (!f) {
00843602 772 r = -errno;
7f4e0805
LP
773 goto finish;
774 }
775
776 fd = -1;
777
981e4cd3
LP
778 signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
779 if (signal_fd < 0) {
00843602 780 r = -errno;
7f4e0805
LP
781 goto finish;
782 }
783
981e4cd3
LP
784 socket_fd = create_socket(&socket_name);
785 if (socket_fd < 0) {
7f4e0805
LP
786 r = socket_fd;
787 goto finish;
788 }
789
790 fprintf(f,
791 "[Ask]\n"
de0671ee 792 "PID="PID_FMT"\n"
7f4e0805 793 "Socket=%s\n"
21bc923a 794 "AcceptCached=%i\n"
64845bdc 795 "Echo=%i\n"
de0671ee 796 "NotAfter="USEC_FMT"\n",
df0ff127 797 getpid_cached(),
7f4e0805 798 socket_name,
e287086b
LP
799 (flags & ASK_PASSWORD_ACCEPT_CACHED) ? 1 : 0,
800 (flags & ASK_PASSWORD_ECHO) ? 1 : 0,
de0671ee 801 until);
7f4e0805
LP
802
803 if (message)
804 fprintf(f, "Message=%s\n", message);
805
806 if (icon)
807 fprintf(f, "Icon=%s\n", icon);
808
9fa1de96
DH
809 if (id)
810 fprintf(f, "Id=%s\n", id);
811
dacd6cee 812 r = fflush_and_check(f);
00843602 813 if (r < 0)
7f4e0805 814 goto finish;
7f4e0805
LP
815
816 memcpy(final, temp, sizeof(temp));
817
818 final[sizeof(final)-11] = 'a';
819 final[sizeof(final)-10] = 's';
820 final[sizeof(final)-9] = 'k';
821
822 if (rename(temp, final) < 0) {
00843602 823 r = -errno;
7f4e0805
LP
824 goto finish;
825 }
826
827 zero(pollfd);
828 pollfd[FD_SOCKET].fd = socket_fd;
829 pollfd[FD_SOCKET].events = POLLIN;
830 pollfd[FD_SIGNAL].fd = signal_fd;
831 pollfd[FD_SIGNAL].events = POLLIN;
c7b7d74e
XF
832 pollfd[FD_INOTIFY].fd = notify;
833 pollfd[FD_INOTIFY].events = POLLIN;
7f4e0805
LP
834
835 for (;;) {
836 char passphrase[LINE_MAX+1];
837 struct msghdr msghdr;
838 struct iovec iovec;
839 struct ucred *ucred;
840 union {
841 struct cmsghdr cmsghdr;
842 uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
843 } control;
844 ssize_t n;
845 int k;
846 usec_t t;
847
848 t = now(CLOCK_MONOTONIC);
849
7dcda352 850 if (until > 0 && until <= t) {
7f4e0805
LP
851 r = -ETIME;
852 goto finish;
853 }
854
c7b7d74e 855 k = poll(pollfd, notify >= 0 ? _FD_MAX : _FD_MAX - 1, until > 0 ? (int) ((until-t)/USEC_PER_MSEC) : -1);
981e4cd3 856 if (k < 0) {
7f4e0805
LP
857 if (errno == EINTR)
858 continue;
859
00843602 860 r = -errno;
7f4e0805
LP
861 goto finish;
862 }
863
864 if (k <= 0) {
7f4e0805
LP
865 r = -ETIME;
866 goto finish;
867 }
868
21bc923a
LP
869 if (pollfd[FD_SIGNAL].revents & POLLIN) {
870 r = -EINTR;
871 goto finish;
872 }
7f4e0805 873
c7b7d74e
XF
874 if (notify >= 0 && pollfd[FD_INOTIFY].revents != 0) {
875 (void) flush_fd(notify);
876
877 r = ask_password_keyring(keyname, flags, ret);
878 if (r >= 0) {
879 r = 0;
880 goto finish;
881 } else if (r != -ENOKEY)
882 goto finish;
883 }
884
885 if (pollfd[FD_SOCKET].revents == 0)
886 continue;
887
7f4e0805 888 if (pollfd[FD_SOCKET].revents != POLLIN) {
7f4e0805
LP
889 r = -EIO;
890 goto finish;
891 }
892
5cfa2c3d 893 iovec = IOVEC_MAKE(passphrase, sizeof(passphrase));
7f4e0805
LP
894
895 zero(control);
896 zero(msghdr);
897 msghdr.msg_iov = &iovec;
898 msghdr.msg_iovlen = 1;
899 msghdr.msg_control = &control;
900 msghdr.msg_controllen = sizeof(control);
901
981e4cd3
LP
902 n = recvmsg(socket_fd, &msghdr, 0);
903 if (n < 0) {
3742095b 904 if (IN_SET(errno, EAGAIN, EINTR))
7f4e0805
LP
905 continue;
906
00843602 907 r = -errno;
7f4e0805
LP
908 goto finish;
909 }
910
1c8da044
LP
911 cmsg_close_all(&msghdr);
912
7f4e0805 913 if (n <= 0) {
00843602 914 log_debug("Message too short");
7f4e0805
LP
915 continue;
916 }
917
918 if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
919 control.cmsghdr.cmsg_level != SOL_SOCKET ||
920 control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
921 control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
00843602 922 log_debug("Received message without credentials. Ignoring.");
7f4e0805
LP
923 continue;
924 }
925
926 ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
927 if (ucred->uid != 0) {
00843602 928 log_debug("Got request from unprivileged user. Ignoring.");
7f4e0805
LP
929 continue;
930 }
931
932 if (passphrase[0] == '+') {
e287086b 933 /* An empty message refers to the empty password */
8254a475 934 if (n == 1)
bea1a013 935 l = strv_new("");
8254a475
LP
936 else
937 l = strv_parse_nulstr(passphrase+1, n-1);
87f54463 938 explicit_bzero_safe(passphrase, n);
8254a475 939 if (!l) {
7f4e0805
LP
940 r = -ENOMEM;
941 goto finish;
942 }
943
58629001 944 if (strv_isempty(l)) {
e287086b 945 l = strv_free(l);
00843602 946 log_debug("Invalid packet");
21bc923a
LP
947 continue;
948 }
949
e287086b
LP
950 break;
951 }
21bc923a 952
e287086b 953 if (passphrase[0] == '-') {
7f4e0805
LP
954 r = -ECANCELED;
955 goto finish;
7f4e0805
LP
956 }
957
e287086b 958 log_debug("Invalid packet");
7f4e0805
LP
959 }
960
e287086b
LP
961 if (keyname)
962 (void) add_to_keyring_and_log(keyname, flags, l);
963
ae2a15bc 964 *ret = TAKE_PTR(l);
7f4e0805
LP
965 r = 0;
966
967finish:
981e4cd3 968 if (socket_name)
00843602 969 (void) unlink(socket_name);
7f4e0805 970
00843602 971 (void) unlink(temp);
7f4e0805
LP
972
973 if (final[0])
00843602 974 (void) unlink(final);
7f4e0805 975
f9b72cd8 976 assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
7f4e0805
LP
977 return r;
978}
260ab287 979
00843602
LP
980int ask_password_auto(
981 const char *message,
982 const char *icon,
983 const char *id,
e287086b 984 const char *keyname,
00843602 985 usec_t until,
e287086b
LP
986 AskPasswordFlags flags,
987 char ***ret) {
00843602
LP
988
989 int r;
990
e287086b 991 assert(ret);
21bc923a 992
c7b7d74e
XF
993 if ((flags & ASK_PASSWORD_ACCEPT_CACHED) &&
994 keyname &&
995 ((flags & ASK_PASSWORD_NO_TTY) || !isatty(STDIN_FILENO)) &&
996 (flags & ASK_PASSWORD_NO_AGENT)) {
e287086b
LP
997 r = ask_password_keyring(keyname, flags, ret);
998 if (r != -ENOKEY)
999 return r;
1000 }
1001
c7b7d74e
XF
1002 if (!(flags & ASK_PASSWORD_NO_TTY) && isatty(STDIN_FILENO))
1003 return ask_password_tty(-1, message, keyname, until, flags, NULL, ret);
00843602 1004
e287086b
LP
1005 if (!(flags & ASK_PASSWORD_NO_AGENT))
1006 return ask_password_agent(message, icon, id, keyname, until, flags, ret);
1007
1008 return -EUNATCH;
260ab287 1009}