]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/ask-password-api.c
ci: re-enable uefi secure boot
[thirdparty/systemd.git] / src / shared / ask-password-api.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
00843602 2
7f4e0805 3#include <fcntl.h>
69a283c5 4#include <poll.h>
a8fbdf54 5#include <stdio.h>
00843602 6#include <sys/inotify.h>
7f4e0805 7#include <sys/signalfd.h>
a8fbdf54 8#include <sys/stat.h>
00843602
LP
9#include <termios.h>
10#include <unistd.h>
7f4e0805 11
b5efdb8a 12#include "alloc-util.h"
b7120388 13#include "ansi-color.h"
3ffd4af2 14#include "ask-password-api.h"
8806bb4b 15#include "creds-util.h"
3ffd4af2 16#include "fd-util.h"
0d39fa9c 17#include "fileio.h"
f97b34a6 18#include "format-util.h"
c7b7d74e 19#include "fs-util.h"
d8e32c47 20#include "glyph-util.h"
4dd2748b 21#include "inotify-util.h"
c004493c 22#include "io-util.h"
bd1ae178 23#include "iovec-util.h"
cbae575e 24#include "keyring-util.h"
a8fbdf54 25#include "log.h"
08af3cc5 26#include "nulstr-util.h"
c94f6ab1 27#include "parse-util.h"
ec572753 28#include "path-lookup.h"
aa25e19b 29#include "plymouth-util.h"
df0ff127 30#include "process-util.h"
3df3e884 31#include "random-util.h"
24882e06 32#include "signal-util.h"
00843602 33#include "socket-util.h"
36c6c696 34#include "string-table.h"
07630cea 35#include "string-util.h"
00843602
LP
36#include "strv.h"
37#include "terminal-util.h"
a8fbdf54 38#include "time-util.h"
e4de7287 39#include "tmpfile-util.h"
affb60b1 40#include "umask-util.h"
f3149d57 41#include "utf8.h"
7f4e0805 42
e287086b
LP
43#define KEYRING_TIMEOUT_USEC ((5 * USEC_PER_MINUTE) / 2)
44
36c6c696
DDM
45static const char* keyring_table[] = {
46 [-KEY_SPEC_THREAD_KEYRING] = "thread",
47 [-KEY_SPEC_PROCESS_KEYRING] = "process",
48 [-KEY_SPEC_SESSION_KEYRING] = "session",
49 [-KEY_SPEC_USER_KEYRING] = "user",
50 [-KEY_SPEC_USER_SESSION_KEYRING] = "user-session",
51 [-KEY_SPEC_GROUP_KEYRING] = "group",
52};
53
54DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(keyring, int);
55
e287086b
LP
56static int lookup_key(const char *keyname, key_serial_t *ret) {
57 key_serial_t serial;
58
59 assert(keyname);
60 assert(ret);
61
d7e986b7 62 serial = request_key("user", keyname, /* callout_info= */ NULL, /* destringid= */ 0);
e287086b 63 if (serial == -1)
9c4615fb 64 return negative_errno();
e287086b
LP
65
66 *ret = serial;
67 return 0;
68}
69
70static int retrieve_key(key_serial_t serial, char ***ret) {
cbae575e 71 _cleanup_(erase_and_freep) void *p = NULL;
e287086b 72 char **l;
cbae575e
LP
73 size_t n;
74 int r;
e287086b
LP
75
76 assert(ret);
77
cbae575e
LP
78 r = keyring_read(serial, &p, &n);
79 if (r < 0)
80 return r;
81
82 l = strv_parse_nulstr(p, n);
e287086b
LP
83 if (!l)
84 return -ENOMEM;
85
86 *ret = l;
87 return 0;
88}
89
4dd2748b
LP
90static int get_ask_password_directory_for_flags(AskPasswordFlags flags, char **ret) {
91 if (FLAGS_SET(flags, ASK_PASSWORD_USER))
92 return acquire_user_ask_password_directory(ret);
93
94 return strdup_to_full(ret, "/run/systemd/ask-password/"); /* Returns 1, indicating there's a suitable directory */
95}
96
97static int touch_ask_password_directory(AskPasswordFlags flags) {
98 int r;
99
100 _cleanup_free_ char *p = NULL;
101 r = get_ask_password_directory_for_flags(flags, &p);
102 if (r <= 0)
103 return r;
104
2ee6fa55
LP
105 _cleanup_close_ int fd = open_mkdir(p, O_CLOEXEC, 0755);
106 if (fd < 0)
107 return fd;
108
109 r = touch_fd(fd, USEC_INFINITY);
4dd2748b
LP
110 if (r < 0)
111 return r;
112
113 return 1; /* did something */
114}
115
d9f4dad9 116static usec_t keyring_cache_timeout(void) {
b3bca11c 117 static usec_t saved_timeout = KEYRING_TIMEOUT_USEC;
d9f4dad9
DDM
118 static bool saved_timeout_set = false;
119 int r;
120
121 if (saved_timeout_set)
122 return saved_timeout;
123
124 const char *e = secure_getenv("SYSTEMD_ASK_PASSWORD_KEYRING_TIMEOUT_SEC");
01d138b9 125 if (e) {
d9f4dad9
DDM
126 r = parse_sec(e, &saved_timeout);
127 if (r < 0)
128 log_debug_errno(r, "Invalid value in $SYSTEMD_ASK_PASSWORD_KEYRING_TIMEOUT_SEC, ignoring: %s", e);
129 }
130
131 saved_timeout_set = true;
132
133 return saved_timeout;
134}
135
36c6c696
DDM
136static key_serial_t keyring_cache_type(void) {
137 static key_serial_t saved_keyring = KEY_SPEC_USER_KEYRING;
138 static bool saved_keyring_set = false;
139 int r;
140
141 if (saved_keyring_set)
142 return saved_keyring;
143
144 const char *e = secure_getenv("SYSTEMD_ASK_PASSWORD_KEYRING_TYPE");
145 if (e) {
146 key_serial_t keyring;
147
148 r = safe_atoi32(e, &keyring);
149 if (r >= 0)
150 if (keyring < 0)
151 log_debug_errno(keyring, "Invalid value in $SYSTEMD_ASK_PASSWORD_KEYRING_TYPE, ignoring: %s", e);
152 else
153 saved_keyring = keyring;
154 else {
155 keyring = keyring_from_string(e);
156 if (keyring < 0)
157 log_debug_errno(keyring, "Invalid value in $SYSTEMD_ASK_PASSWORD_KEYRING_TYPE, ignoring: %s", e);
158 else
159 saved_keyring = -keyring;
160 }
161 }
162
163 saved_keyring_set = true;
164
165 return saved_keyring;
166}
167
e287086b 168static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **passwords) {
ab84f5b9 169 _cleanup_strv_free_erase_ char **l = NULL;
e693a932 170 _cleanup_(erase_and_freep) char *p = NULL;
e287086b
LP
171 key_serial_t serial;
172 size_t n;
173 int r;
174
175 assert(keyname);
e287086b 176
d9f4dad9 177 if (!FLAGS_SET(flags, ASK_PASSWORD_PUSH_CACHE) || keyring_cache_timeout() == 0)
e287086b 178 return 0;
e013e10d
LP
179 if (strv_isempty(passwords))
180 return 0;
e287086b
LP
181
182 r = lookup_key(keyname, &serial);
183 if (r >= 0) {
184 r = retrieve_key(serial, &l);
185 if (r < 0)
186 return r;
187 } else if (r != -ENOKEY)
188 return r;
189
dbdec4b1 190 r = strv_extend_strv(&l, passwords, /* filter_duplicates= */ true);
e287086b
LP
191 if (r <= 0)
192 return r;
193
194 r = strv_make_nulstr(l, &p, &n);
195 if (r < 0)
196 return r;
197
76078ad8
LP
198 /* chop off the final NUL byte. We do this because we want to use the separator NUL bytes only if we
199 * have multiple passwords. */
200 n = LESS_BY(n, (size_t) 1);
201
36c6c696 202 serial = add_key("user", keyname, p, n, keyring_cache_type());
e287086b
LP
203 if (serial == -1)
204 return -errno;
205
d9f4dad9
DDM
206 if (keyring_cache_timeout() != USEC_INFINITY &&
207 keyctl(KEYCTL_SET_TIMEOUT,
208 (unsigned long) serial,
209 (unsigned long) DIV_ROUND_UP(keyring_cache_timeout(), USEC_PER_SEC), 0, 0) < 0)
e3ac53a2 210 log_debug_errno(errno, "Failed to adjust kernel keyring key timeout: %m");
e287086b 211
c7b7d74e 212 /* Tell everyone to check the keyring */
4dd2748b 213 (void) touch_ask_password_directory(flags);
c7b7d74e 214
e3ac53a2 215 log_debug("Added key to kernel keyring as %" PRIi32 ".", serial);
e287086b
LP
216
217 return 1;
218}
219
220static int add_to_keyring_and_log(const char *keyname, AskPasswordFlags flags, char **passwords) {
221 int r;
222
223 assert(keyname);
e287086b
LP
224
225 r = add_to_keyring(keyname, flags, passwords);
226 if (r < 0)
e3ac53a2 227 return log_debug_errno(r, "Failed to add password to kernel keyring: %m");
e287086b
LP
228
229 return 0;
230}
231
d08fd4c3 232static int ask_password_keyring(const AskPasswordRequest *req, AskPasswordFlags flags, char ***ret) {
e287086b
LP
233 key_serial_t serial;
234 int r;
235
d08fd4c3 236 assert(req);
e287086b
LP
237 assert(ret);
238
9cb5bf91 239 if (!FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED))
e287086b
LP
240 return -EUNATCH;
241
d08fd4c3 242 r = lookup_key(req->keyring, &serial);
5fe08a12 243 if (ERRNO_IS_NEG_NOT_SUPPORTED(r) || IN_SET(r, -EPERM, -ENOKEY))
bb44fd07
ZJS
244 /* When retrieving, the distinction between "kernel or container manager don't support or
245 * allow this" and "no matching key known" doesn't matter. Note that we propagate EACCESS
246 * here (even if EPERM not) since that is used if the keyring is available, but we lack
247 * access to the key. */
248 return -ENOKEY;
249 if (r < 0)
5fe08a12 250 return log_debug_errno(r, "Failed to look up key %s in keyring: %m", req->keyring);
e287086b 251
623a8b19
YW
252 _cleanup_strv_free_erase_ char **l = NULL;
253 r = retrieve_key(serial, &l);
254 if (r < 0)
255 return r;
256
257 if (strv_isempty(l))
258 return log_debug_errno(SYNTHETIC_ERRNO(ENOKEY), "Found an empty password from keyring.");
259
260 *ret = TAKE_PTR(l);
261 return 0;
e287086b
LP
262}
263
8e9d1eec 264static int backspace_chars(int ttyfd, size_t p) {
58fc840b 265 if (ttyfd < 0)
8e9d1eec 266 return 0;
58fc840b 267
8e9d1eec
ZJS
268 _cleanup_free_ char *buf = malloc_multiply(3, p);
269 if (!buf)
270 return log_oom();
58fc840b 271
8e9d1eec
ZJS
272 for (size_t i = 0; i < p; i++)
273 memcpy(buf + 3 * i, "\b \b", 3);
58fc840b 274
e22c60a9 275 return loop_write(ttyfd, buf, 3 * p);
8e9d1eec 276}
fd6ac62c 277
8e9d1eec 278static int backspace_string(int ttyfd, const char *str) {
fd6ac62c
LP
279 assert(str);
280
f95dbcc2 281 /* Backspaces through enough characters to entirely undo printing of the specified string. */
fd6ac62c 282
8e9d1eec
ZJS
283 if (ttyfd < 0)
284 return 0;
285
286 size_t m = utf8_n_codepoints(str);
f5fbe71d 287 if (m == SIZE_MAX)
8e9d1eec 288 m = strlen(str); /* Not a valid UTF-8 string? If so, let's backspace the number of bytes
5bc9ea07 289 * output. Most likely this happened because we are not in a UTF-8 locale,
8e9d1eec
ZJS
290 * and in that case that is the correct thing to do. And even if it's not,
291 * terminals tend to stop backspacing at the leftmost column, hence
292 * backspacing too much should be mostly OK. */
fd6ac62c 293
8e9d1eec 294 return backspace_chars(ttyfd, m);
fd6ac62c
LP
295}
296
6b2faba7 297int ask_password_plymouth(
d08fd4c3 298 const AskPasswordRequest *req,
6b2faba7 299 AskPasswordFlags flags,
6b2faba7
FB
300 char ***ret) {
301
dbdec4b1 302 _cleanup_close_ int fd = -EBADF, inotify_fd = -EBADF;
6b2faba7
FB
303 _cleanup_free_ char *packet = NULL;
304 ssize_t k;
305 int r, n;
6b2faba7
FB
306 char buffer[LINE_MAX];
307 size_t p = 0;
6b2faba7 308
05db3fe7 309 assert(req);
6b2faba7
FB
310 assert(ret);
311
b2ac9280
LP
312 if (FLAGS_SET(flags, ASK_PASSWORD_HEADLESS))
313 return -ENOEXEC;
314
05db3fe7 315 const char *message = req->message ?: "Password:";
66bff73b 316
4ff3689a 317 if (req->flag_file) {
dbdec4b1
LP
318 inotify_fd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
319 if (inotify_fd < 0)
6b2faba7
FB
320 return -errno;
321
4ff3689a 322 if (inotify_add_watch(inotify_fd, req->flag_file, IN_ATTRIB) < 0) /* for the link count */
6b2faba7
FB
323 return -errno;
324 }
325
aa25e19b 326 fd = plymouth_connect(SOCK_NONBLOCK);
6b2faba7 327 if (fd < 0)
aa25e19b 328 return fd;
6b2faba7 329
9cb5bf91 330 if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED)) {
6b2faba7
FB
331 packet = strdup("c");
332 n = 1;
333 } else if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0)
334 packet = NULL;
335 if (!packet)
336 return -ENOMEM;
337
e22c60a9 338 r = loop_write_full(fd, packet, n + 1, USEC_INFINITY);
6b2faba7
FB
339 if (r < 0)
340 return r;
341
692597c8
LP
342 CLEANUP_ERASE(buffer);
343
dbdec4b1
LP
344 enum {
345 POLL_SOCKET,
d66894a7
LP
346 POLL_TWO,
347 POLL_THREE,
dbdec4b1
LP
348 _POLL_MAX,
349 };
350
351 struct pollfd pollfd[_POLL_MAX] = {
d66894a7
LP
352 [POLL_SOCKET] = {
353 .fd = fd,
354 .events = POLLIN,
355 },
dbdec4b1 356 };
d66894a7
LP
357 size_t n_pollfd = POLL_SOCKET + 1, inotify_idx = SIZE_MAX, hup_fd_idx = SIZE_MAX;
358 if (inotify_fd >= 0)
359 pollfd[inotify_idx = n_pollfd++] = (struct pollfd) {
360 .fd = inotify_fd,
361 .events = POLLIN,
362 };
363 if (req->hup_fd >= 0)
364 pollfd[hup_fd_idx = n_pollfd++] = (struct pollfd) {
365 .fd = req->hup_fd,
366 .events = POLLHUP,
367 };
368
369 assert(n_pollfd <= _POLL_MAX);
6b2faba7
FB
370
371 for (;;) {
d9e2af0a 372 usec_t timeout;
6b2faba7 373
c4a02a52
LP
374 if (req->until > 0)
375 timeout = usec_sub_unsigned(req->until, now(CLOCK_MONOTONIC));
d9e2af0a
YW
376 else
377 timeout = USEC_INFINITY;
6b2faba7 378
4ff3689a 379 if (req->flag_file && access(req->flag_file, F_OK) < 0)
692597c8 380 return -errno;
6b2faba7 381
dbdec4b1 382 r = ppoll_usec(pollfd, n_pollfd, timeout);
d9e2af0a
YW
383 if (r == -EINTR)
384 continue;
385 if (r < 0)
692597c8
LP
386 return r;
387 if (r == 0)
388 return -ETIME;
6b2faba7 389
d66894a7
LP
390 if (req->hup_fd >= 0 && pollfd[hup_fd_idx].revents & POLLHUP)
391 return -ECONNRESET;
392
393 if (inotify_fd >= 0 && pollfd[inotify_idx].revents != 0)
dbdec4b1 394 (void) flush_fd(inotify_fd);
6b2faba7
FB
395
396 if (pollfd[POLL_SOCKET].revents == 0)
397 continue;
398
399 k = read(fd, buffer + p, sizeof(buffer) - p);
400 if (k < 0) {
8add30a0 401 if (ERRNO_IS_TRANSIENT(errno))
6b2faba7
FB
402 continue;
403
692597c8 404 return -errno;
6b2faba7 405 }
692597c8
LP
406 if (k == 0)
407 return -EIO;
6b2faba7
FB
408
409 p += k;
410
6b2faba7
FB
411 if (buffer[0] == 5) {
412
9cb5bf91 413 if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED)) {
6b2faba7
FB
414 /* Hmm, first try with cached
415 * passwords failed, so let's retry
416 * with a normal password request */
417 packet = mfree(packet);
418
692597c8
LP
419 if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0)
420 return -ENOMEM;
6b2faba7 421
e22c60a9 422 r = loop_write_full(fd, packet, n + 1, USEC_INFINITY);
6b2faba7 423 if (r < 0)
692597c8 424 return r;
6b2faba7
FB
425
426 flags &= ~ASK_PASSWORD_ACCEPT_CACHED;
427 p = 0;
428 continue;
429 }
430
431 /* No password, because UI not shown */
692597c8 432 return -ENOENT;
6b2faba7
FB
433
434 } else if (IN_SET(buffer[0], 2, 9)) {
623a8b19 435 _cleanup_strv_free_erase_ char **l = NULL;
6b2faba7 436 uint32_t size;
6b2faba7
FB
437
438 /* One or more answers */
439 if (p < 5)
440 continue;
441
442 memcpy(&size, buffer+1, sizeof(size));
443 size = le32toh(size);
692597c8
LP
444 if (size + 5 > sizeof(buffer))
445 return -EIO;
6b2faba7
FB
446
447 if (p-5 < size)
448 continue;
449
450 l = strv_parse_nulstr(buffer + 5, size);
692597c8
LP
451 if (!l)
452 return -ENOMEM;
6b2faba7 453
623a8b19
YW
454 if (strv_isempty(l))
455 return log_debug_errno(SYNTHETIC_ERRNO(ECANCELED), "Received an empty password.");
456
457 *ret = TAKE_PTR(l);
458 return 0;
6b2faba7 459
692597c8 460 } else
6b2faba7 461 /* Unknown packet */
692597c8 462 return -EIO;
6b2faba7 463 }
6b2faba7
FB
464}
465
8aaf18e0
ZJS
466#define NO_ECHO "(no echo) "
467#define PRESS_TAB "(press TAB for no echo) "
468#define SKIPPED "(skipped)"
469
7f4e0805 470int ask_password_tty(
d08fd4c3 471 const AskPasswordRequest *req,
e287086b 472 AskPasswordFlags flags,
c7b7d74e 473 char ***ret) {
7f4e0805 474
8aaf18e0 475 bool reset_tty = false, dirty = false, use_color = false, press_tab_visible = false;
dbdec4b1 476 _cleanup_close_ int cttyfd = -EBADF, inotify_fd = -EBADF;
7f4e0805 477 struct termios old_termios, new_termios;
f3149d57 478 char passphrase[LINE_MAX + 1] = {}, *x;
c7b7d74e 479 _cleanup_strv_free_erase_ char **l = NULL;
f3149d57 480 size_t p = 0, codepoint = 0;
088dcd8e 481 int r;
7f4e0805 482
05db3fe7 483 assert(req);
e287086b
LP
484 assert(ret);
485
b2ac9280
LP
486 if (FLAGS_SET(flags, ASK_PASSWORD_HEADLESS))
487 return -ENOEXEC;
488
9cb5bf91 489 if (FLAGS_SET(flags, ASK_PASSWORD_NO_TTY))
e287086b
LP
490 return -EUNATCH;
491
05db3fe7
YW
492 const char *message = req->message ?: "Password:";
493 const char *keyring = req->keyring;
7f4e0805 494
e390c34d 495 if (!FLAGS_SET(flags, ASK_PASSWORD_HIDE_EMOJI) && emoji_enabled())
1ae9b0cf 496 message = strjoina(glyph(GLYPH_LOCK_AND_KEY), " ", message);
52d199e3 497
4ff3689a 498 if (req->flag_file || (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && keyring)) {
dbdec4b1
LP
499 inotify_fd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
500 if (inotify_fd < 0)
a497a296 501 return -errno;
c7b7d74e 502 }
4ff3689a
LP
503 if (req->flag_file)
504 if (inotify_add_watch(inotify_fd, req->flag_file, IN_ATTRIB /* for the link count */) < 0)
a497a296 505 return -errno;
05db3fe7 506 if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && keyring) {
d08fd4c3 507 r = ask_password_keyring(req, flags, ret);
c7b7d74e
XF
508 if (r >= 0)
509 return 0;
dbdec4b1 510 if (r != -ENOKEY)
c7b7d74e
XF
511 return r;
512
4dd2748b
LP
513 /* Let's watch the askpw directory for mtime changes, which we issue above whenever the
514 * keyring changes */
515 _cleanup_free_ char *watch_path = NULL;
516 r = get_ask_password_directory_for_flags(flags, &watch_path);
517 if (r < 0)
518 return r;
519 if (r > 0) {
520 _cleanup_close_ int watch_fd = open_mkdir(watch_path, O_CLOEXEC|O_RDONLY, 0755);
521 if (watch_fd < 0)
522 return watch_fd;
523
524 r = inotify_add_watch_fd(inotify_fd, watch_fd, IN_ONLYDIR|IN_ATTRIB /* for mtime */);
525 if (r < 0)
526 return r;
527 }
c7b7d74e 528 }
7f4e0805 529
692597c8
LP
530 CLEANUP_ERASE(passphrase);
531
daa55720 532 /* If the caller didn't specify a TTY, then use the controlling tty, if we can. */
72068d9d
LP
533 int ttyfd;
534 if (req->tty_fd < 0)
daa55720 535 ttyfd = cttyfd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC);
72068d9d
LP
536 else
537 ttyfd = req->tty_fd;
7f4e0805 538
daa55720 539 if (ttyfd >= 0) {
a497a296
LP
540 if (tcgetattr(ttyfd, &old_termios) < 0)
541 return -errno;
7f4e0805 542
9cb5bf91 543 if (FLAGS_SET(flags, ASK_PASSWORD_CONSOLE_COLOR))
c2b32159
LP
544 use_color = dev_console_colors_enabled();
545 else
546 use_color = colors_enabled();
547
548 if (use_color)
e22c60a9 549 (void) loop_write(ttyfd, ANSI_HIGHLIGHT, SIZE_MAX);
ac7a9674 550
e22c60a9
MY
551 (void) loop_write(ttyfd, message, SIZE_MAX);
552 (void) loop_write(ttyfd, " ", 1);
ac7a9674 553
9cb5bf91 554 if (!FLAGS_SET(flags, ASK_PASSWORD_SILENT) && !FLAGS_SET(flags, ASK_PASSWORD_ECHO)) {
8aaf18e0 555 if (use_color)
e22c60a9
MY
556 (void) loop_write(ttyfd, ansi_grey(), SIZE_MAX);
557
558 (void) loop_write(ttyfd, PRESS_TAB, SIZE_MAX);
8aaf18e0
ZJS
559 press_tab_visible = true;
560 }
561
c2b32159 562 if (use_color)
e22c60a9 563 (void) loop_write(ttyfd, ANSI_NORMAL, SIZE_MAX);
7f4e0805
LP
564
565 new_termios = old_termios;
d02d4f83 566 termios_disable_echo(&new_termios);
7f4e0805 567
f789b17e 568 r = RET_NERRNO(tcsetattr(ttyfd, TCSANOW, &new_termios));
108dfff2 569 if (r < 0)
7f4e0805 570 goto finish;
7f4e0805
LP
571
572 reset_tty = true;
573 }
574
dbdec4b1
LP
575 enum {
576 POLL_TTY,
d66894a7
LP
577 POLL_TWO,
578 POLL_THREE,
dbdec4b1 579 _POLL_MAX,
70dee475 580 };
dbdec4b1
LP
581
582 struct pollfd pollfd[_POLL_MAX] = {
d66894a7
LP
583 [POLL_TTY] = {
584 .fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO,
585 .events = POLLIN,
586 },
70dee475 587 };
d66894a7
LP
588 size_t n_pollfd = POLL_TTY + 1, inotify_idx = SIZE_MAX, hup_fd_idx = SIZE_MAX;
589
590 if (inotify_fd >= 0)
591 pollfd[inotify_idx = n_pollfd++] = (struct pollfd) {
592 .fd = inotify_fd,
593 .events = POLLIN,
594 };
595 if (req->hup_fd >= 0)
596 pollfd[hup_fd_idx = n_pollfd++] = (struct pollfd) {
597 .fd = req->hup_fd,
598 .events = POLLHUP,
599 };
600
601 assert(n_pollfd <= _POLL_MAX);
7f4e0805
LP
602
603 for (;;) {
e1ed99c8 604 _cleanup_(erase_char) char c;
d9e2af0a 605 usec_t timeout;
7f4e0805
LP
606 ssize_t n;
607
c4a02a52
LP
608 if (req->until > 0)
609 timeout = usec_sub_unsigned(req->until, now(CLOCK_MONOTONIC));
d9e2af0a
YW
610 else
611 timeout = USEC_INFINITY;
7f4e0805 612
4ff3689a
LP
613 if (req->flag_file) {
614 r = RET_NERRNO(access(req->flag_file, F_OK));
108dfff2 615 if (r < 0)
7f4e0805 616 goto finish;
108dfff2 617 }
7f4e0805 618
dbdec4b1 619 r = ppoll_usec(pollfd, n_pollfd, timeout);
d9e2af0a
YW
620 if (r == -EINTR)
621 continue;
622 if (r < 0)
7f4e0805 623 goto finish;
d9e2af0a 624 if (r == 0) {
ccc80078 625 r = -ETIME;
7f4e0805
LP
626 goto finish;
627 }
628
d66894a7
LP
629 if (req->hup_fd >= 0 && pollfd[hup_fd_idx].revents & POLLHUP) {
630 r = -ECONNRESET;
631 goto finish;
632 }
633
634 if (inotify_fd >= 0 && pollfd[inotify_idx].revents != 0 && keyring) {
dbdec4b1 635 (void) flush_fd(inotify_fd);
7f4e0805 636
d08fd4c3 637 r = ask_password_keyring(req, flags, ret);
c7b7d74e
XF
638 if (r >= 0) {
639 r = 0;
640 goto finish;
641 } else if (r != -ENOKEY)
642 goto finish;
643 }
644
7f4e0805
LP
645 if (pollfd[POLL_TTY].revents == 0)
646 continue;
647
981e4cd3
LP
648 n = read(ttyfd >= 0 ? ttyfd : STDIN_FILENO, &c, 1);
649 if (n < 0) {
8add30a0 650 if (ERRNO_IS_TRANSIENT(errno))
7f4e0805
LP
651 continue;
652
653 r = -errno;
654 goto finish;
655
fd6ac62c 656 }
7f4e0805 657
8aaf18e0
ZJS
658 if (press_tab_visible) {
659 assert(ttyfd >= 0);
660 backspace_chars(ttyfd, strlen(PRESS_TAB));
661 press_tab_visible = false;
662 }
663
fd6ac62c
LP
664 /* We treat EOF, newline and NUL byte all as valid end markers */
665 if (n == 0 || c == '\n' || c == 0)
7f4e0805 666 break;
fd6ac62c 667
d325f244
FB
668 if (c == 4) { /* C-d also known as EOT */
669 if (ttyfd >= 0)
e22c60a9 670 (void) loop_write(ttyfd, SKIPPED, SIZE_MAX);
d325f244
FB
671
672 goto skipped;
673 }
674
fd6ac62c 675 if (c == 21) { /* C-u */
7f4e0805 676
9cb5bf91 677 if (!FLAGS_SET(flags, ASK_PASSWORD_SILENT))
8e9d1eec 678 (void) backspace_string(ttyfd, passphrase);
fd6ac62c 679
87f54463 680 explicit_bzero_safe(passphrase, sizeof(passphrase));
fd6ac62c 681 p = codepoint = 0;
7f4e0805 682
4c701096 683 } else if (IN_SET(c, '\b', 127)) {
58fc840b
LP
684
685 if (p > 0) {
fd6ac62c 686 size_t q;
58fc840b 687
9cb5bf91 688 if (!FLAGS_SET(flags, ASK_PASSWORD_SILENT))
8e9d1eec 689 (void) backspace_chars(ttyfd, 1);
58fc840b 690
92e068b4
ZJS
691 /* Remove a full UTF-8 codepoint from the end. For that, figure out where the
692 * last one begins */
fd6ac62c
LP
693 q = 0;
694 for (;;) {
37ca78a3 695 int z;
fd6ac62c 696
f5fbe71d 697 z = utf8_encoded_valid_unichar(passphrase + q, SIZE_MAX);
37ca78a3 698 if (z <= 0) {
f5fbe71d 699 q = SIZE_MAX; /* Invalid UTF8! */
fd6ac62c
LP
700 break;
701 }
702
703 if (q + z >= p) /* This one brings us over the edge */
704 break;
705
706 q += z;
707 }
708
f5fbe71d 709 p = codepoint = q == SIZE_MAX ? p - 1 : q;
87f54463 710 explicit_bzero_safe(passphrase + p, sizeof(passphrase) - p);
fd6ac62c 711
9cb5bf91 712 } else if (!dirty && !FLAGS_SET(flags, ASK_PASSWORD_SILENT)) {
441dfe09 713
e287086b 714 flags |= ASK_PASSWORD_SILENT;
441dfe09 715
92e068b4
ZJS
716 /* There are two ways to enter silent mode. Either by pressing backspace as
717 * first key (and only as first key), or ... */
fd6ac62c 718
441dfe09 719 if (ttyfd >= 0)
e22c60a9 720 (void) loop_write(ttyfd, NO_ECHO, SIZE_MAX);
441dfe09 721
58fc840b 722 } else if (ttyfd >= 0)
e22c60a9 723 (void) loop_write(ttyfd, "\a", 1);
7f4e0805 724
9cb5bf91 725 } else if (c == '\t' && !FLAGS_SET(flags, ASK_PASSWORD_SILENT)) {
58fc840b 726
8e9d1eec 727 (void) backspace_string(ttyfd, passphrase);
e287086b 728 flags |= ASK_PASSWORD_SILENT;
58fc840b 729
441dfe09
LP
730 /* ... or by pressing TAB at any time. */
731
58fc840b 732 if (ttyfd >= 0)
e22c60a9 733 (void) loop_write(ttyfd, NO_ECHO, SIZE_MAX);
036eeac5 734
4ba044eb
LP
735 } else if (char_is_cc(c) || p >= sizeof(passphrase)-1) {
736 /* Don't accept control chars or overly long passphrases */
fd6ac62c 737 if (ttyfd >= 0)
e22c60a9 738 (void) loop_write(ttyfd, "\a", 1);
fd6ac62c
LP
739
740 } else {
7f4e0805
LP
741 passphrase[p++] = c;
742
9cb5bf91 743 if (!FLAGS_SET(flags, ASK_PASSWORD_SILENT) && ttyfd >= 0) {
fd6ac62c 744 /* Check if we got a complete UTF-8 character now. If so, let's output one '*'. */
f5fbe71d 745 n = utf8_encoded_valid_unichar(passphrase + codepoint, SIZE_MAX);
f3149d57 746 if (n >= 0) {
9cb5bf91 747 if (FLAGS_SET(flags, ASK_PASSWORD_ECHO))
e22c60a9 748 (void) loop_write(ttyfd, passphrase + codepoint, n);
d26eef92 749 else
e22c60a9 750 (void) loop_write(ttyfd,
1ae9b0cf 751 glyph(GLYPH_BULLET),
e22c60a9 752 SIZE_MAX);
f3149d57 753 codepoint = p;
f3149d57
ZJS
754 }
755 }
441dfe09
LP
756
757 dirty = true;
7f4e0805
LP
758 }
759 }
760
981e4cd3
LP
761 x = strndup(passphrase, p);
762 if (!x) {
7f4e0805
LP
763 r = -ENOMEM;
764 goto finish;
765 }
766
0e28c86f
LP
767 r = strv_consume(&l, x);
768 if (r < 0)
c7b7d74e 769 goto finish;
c7b7d74e 770
d325f244 771skipped:
72c08a47
ZJS
772 if (strv_isempty(l))
773 r = log_debug_errno(SYNTHETIC_ERRNO(ECANCELED), "Password query was cancelled.");
774 else {
d08fd4c3
LP
775 if (keyring)
776 (void) add_to_keyring_and_log(keyring, flags, l);
72c08a47
ZJS
777
778 *ret = TAKE_PTR(l);
779 r = 0;
780 }
7f4e0805
LP
781
782finish:
981e4cd3 783 if (ttyfd >= 0 && reset_tty) {
e22c60a9 784 (void) loop_write(ttyfd, "\n", 1);
f789b17e 785 (void) tcsetattr(ttyfd, TCSANOW, &old_termios);
7f4e0805
LP
786 }
787
788 return r;
789}
790
4dd2748b 791static int create_socket(const char *askpwdir, char **ret) {
15a3e96f 792 _cleanup_free_ char *path = NULL;
f36a9d59
ZJS
793 union sockaddr_union sa;
794 socklen_t sa_len;
254d1313 795 _cleanup_close_ int fd = -EBADF;
f36a9d59 796 int r;
7f4e0805 797
4dd2748b 798 assert(askpwdir);
15a3e96f 799 assert(ret);
7f4e0805 800
e62d8c39 801 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
4a62c710 802 if (fd < 0)
00843602 803 return -errno;
7f4e0805 804
4dd2748b 805 if (asprintf(&path, "%s/sck.%" PRIx64, askpwdir, random_u64()) < 0)
15a3e96f
LP
806 return -ENOMEM;
807
f36a9d59
ZJS
808 r = sockaddr_un_set_path(&sa.un, path);
809 if (r < 0)
810 return r;
811 sa_len = r;
7f4e0805 812
2053593f 813 WITH_UMASK(0177)
f36a9d59 814 if (bind(fd, &sa.sa, sa_len) < 0)
00843602 815 return -errno;
1d6702e8 816
2ff48e98
LP
817 r = setsockopt_int(fd, SOL_SOCKET, SO_PASSCRED, true);
818 if (r < 0)
819 return r;
7f4e0805 820
85352c09
MY
821 (void) setsockopt_int(fd, SOL_SOCKET, SO_PASSRIGHTS, false);
822
15a3e96f
LP
823 *ret = TAKE_PTR(path);
824 return TAKE_FD(fd);
7f4e0805
LP
825}
826
7f4e0805 827int ask_password_agent(
d08fd4c3 828 const AskPasswordRequest *req,
e287086b
LP
829 AskPasswordFlags flags,
830 char ***ret) {
7f4e0805 831
4dd2748b 832 _cleanup_close_ int socket_fd = -EBADF, signal_fd = -EBADF, inotify_fd = -EBADF, dfd = -EBADF;
dbdec4b1 833 _cleanup_(unlink_and_freep) char *socket_name = NULL;
4dd2748b 834 _cleanup_free_ char *temp = NULL, *final = NULL;
c7b7d74e 835 _cleanup_strv_free_erase_ char **l = NULL;
e287086b 836 _cleanup_fclose_ FILE *f = NULL;
e287086b 837 sigset_t mask, oldmask;
981e4cd3 838 int r;
7f4e0805 839
05db3fe7 840 assert(req);
e287086b 841 assert(ret);
21bc923a 842
b2ac9280
LP
843 if (FLAGS_SET(flags, ASK_PASSWORD_HEADLESS))
844 return -ENOEXEC;
845
9cb5bf91 846 if (FLAGS_SET(flags, ASK_PASSWORD_NO_AGENT))
e287086b 847 return -EUNATCH;
00843602 848
4ff3689a
LP
849 /* We don't support the flag file concept for now when querying via the agent logic */
850 if (req->flag_file)
851 return -EOPNOTSUPP;
852
72c0a2c2 853 assert_se(sigemptyset(&mask) >= 0);
db7136ec 854 assert_se(sigset_add_many(&mask, SIGINT, SIGTERM) >= 0);
72c0a2c2 855 assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) >= 0);
f9b72cd8 856
4dd2748b
LP
857 _cleanup_free_ char *askpwdir = NULL;
858 r = get_ask_password_directory_for_flags(flags, &askpwdir);
859 if (r < 0)
860 goto finish;
861 if (r == 0) {
862 r = -ENXIO;
863 goto finish;
864 }
865
866 dfd = open_mkdir(askpwdir, O_RDONLY|O_CLOEXEC, 0755);
867 if (dfd < 0) {
868 r = log_debug_errno(dfd, "Failed to open directory '%s': %m", askpwdir);
869 goto finish;
870 }
7f4e0805 871
05db3fe7 872 if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && req->keyring) {
d08fd4c3 873 r = ask_password_keyring(req, flags, ret);
c7b7d74e
XF
874 if (r >= 0) {
875 r = 0;
876 goto finish;
877 } else if (r != -ENOKEY)
878 goto finish;
879
dbdec4b1
LP
880 inotify_fd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
881 if (inotify_fd < 0) {
c7b7d74e
XF
882 r = -errno;
883 goto finish;
884 }
108dfff2 885
4dd2748b 886 r = inotify_add_watch_fd(inotify_fd, dfd, IN_ONLYDIR|IN_ATTRIB /* for mtime */);
108dfff2 887 if (r < 0)
c7b7d74e 888 goto finish;
c7b7d74e
XF
889 }
890
4dd2748b
LP
891 if (asprintf(&final, "ask.%" PRIu64, random_u64()) < 0) {
892 r = -ENOMEM;
7f4e0805
LP
893 goto finish;
894 }
895
4dd2748b
LP
896 r = fopen_temporary_at(dfd, final, &f, &temp);
897 if (r < 0)
7f4e0805 898 goto finish;
7f4e0805 899
981e4cd3
LP
900 signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
901 if (signal_fd < 0) {
00843602 902 r = -errno;
7f4e0805
LP
903 goto finish;
904 }
905
4dd2748b 906 socket_fd = create_socket(askpwdir, &socket_name);
981e4cd3 907 if (socket_fd < 0) {
7f4e0805
LP
908 r = socket_fd;
909 goto finish;
910 }
911
912 fprintf(f,
913 "[Ask]\n"
de0671ee 914 "PID="PID_FMT"\n"
7f4e0805 915 "Socket=%s\n"
21bc923a 916 "AcceptCached=%i\n"
64845bdc 917 "Echo=%i\n"
1fa94a31
SB
918 "NotAfter="USEC_FMT"\n"
919 "Silent=%i\n",
df0ff127 920 getpid_cached(),
7f4e0805 921 socket_name,
9cb5bf91
CH
922 FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED),
923 FLAGS_SET(flags, ASK_PASSWORD_ECHO),
c4a02a52 924 req->until,
9cb5bf91 925 FLAGS_SET(flags, ASK_PASSWORD_SILENT));
7f4e0805 926
05db3fe7
YW
927 if (req->message)
928 fprintf(f, "Message=%s\n", req->message);
7f4e0805 929
05db3fe7
YW
930 if (req->icon)
931 fprintf(f, "Icon=%s\n", req->icon);
7f4e0805 932
05db3fe7
YW
933 if (req->id)
934 fprintf(f, "Id=%s\n", req->id);
9fa1de96 935
4dd2748b
LP
936 if (fchmod(fileno(f), 0644) < 0) {
937 r = -errno;
938 goto finish;
939 }
940
dacd6cee 941 r = fflush_and_check(f);
00843602 942 if (r < 0)
7f4e0805 943 goto finish;
7f4e0805 944
4dd2748b
LP
945 if (renameat(dfd, temp, dfd, final) < 0) {
946 r = -errno;
7f4e0805 947 goto finish;
4dd2748b
LP
948 }
949
950 temp = mfree(temp);
7f4e0805 951
dbdec4b1
LP
952 enum {
953 POLL_SOCKET,
954 POLL_SIGNAL,
d66894a7
LP
955 POLL_THREE,
956 POLL_FOUR,
dbdec4b1
LP
957 _POLL_MAX
958 };
959
960 struct pollfd pollfd[_POLL_MAX] = {
961 [POLL_SOCKET] = { .fd = socket_fd, .events = POLLIN },
962 [POLL_SIGNAL] = { .fd = signal_fd, .events = POLLIN },
dbdec4b1 963 };
d66894a7
LP
964 size_t n_pollfd = POLL_SIGNAL + 1, inotify_idx = SIZE_MAX, hup_fd_idx = SIZE_MAX;
965
966 if (inotify_fd >= 0)
967 pollfd[inotify_idx = n_pollfd++] = (struct pollfd) {
968 .fd = inotify_fd,
969 .events = POLLIN,
970 };
971 if (req->hup_fd >= 0)
972 pollfd[hup_fd_idx = n_pollfd ++] = (struct pollfd) {
973 .fd = req->hup_fd,
974 .events = POLLHUP,
975 };
976
977 assert(n_pollfd <= _POLL_MAX);
7f4e0805
LP
978
979 for (;;) {
fb29cdbe 980 CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
7f4e0805 981 char passphrase[LINE_MAX+1];
7f4e0805
LP
982 struct iovec iovec;
983 struct ucred *ucred;
d9e2af0a 984 usec_t timeout;
7f4e0805 985 ssize_t n;
7f4e0805 986
c4a02a52
LP
987 if (req->until > 0)
988 timeout = usec_sub_unsigned(req->until, now(CLOCK_MONOTONIC));
d9e2af0a
YW
989 else
990 timeout = USEC_INFINITY;
7f4e0805 991
dbdec4b1 992 r = ppoll_usec(pollfd, n_pollfd, timeout);
d9e2af0a
YW
993 if (r == -EINTR)
994 continue;
995 if (r < 0)
7f4e0805 996 goto finish;
d9e2af0a 997 if (r == 0) {
7f4e0805
LP
998 r = -ETIME;
999 goto finish;
1000 }
1001
dbdec4b1 1002 if (pollfd[POLL_SIGNAL].revents & POLLIN) {
21bc923a
LP
1003 r = -EINTR;
1004 goto finish;
1005 }
7f4e0805 1006
d66894a7
LP
1007 if (req->hup_fd >= 0 && pollfd[hup_fd_idx].revents & POLLHUP)
1008 return -ECONNRESET;
1009
1010 if (inotify_fd >= 0 && pollfd[inotify_idx].revents != 0) {
dbdec4b1 1011 (void) flush_fd(inotify_fd);
c7b7d74e 1012
05db3fe7 1013 if (req->keyring) {
d08fd4c3
LP
1014 r = ask_password_keyring(req, flags, ret);
1015 if (r >= 0) {
1016 r = 0;
1017 goto finish;
1018 } else if (r != -ENOKEY)
1019 goto finish;
1020 }
c7b7d74e
XF
1021 }
1022
dbdec4b1 1023 if (pollfd[POLL_SOCKET].revents == 0)
c7b7d74e
XF
1024 continue;
1025
dbdec4b1 1026 if (pollfd[POLL_SOCKET].revents != POLLIN) {
7f4e0805
LP
1027 r = -EIO;
1028 goto finish;
1029 }
1030
5cfa2c3d 1031 iovec = IOVEC_MAKE(passphrase, sizeof(passphrase));
7f4e0805 1032
41ab8c67
LP
1033 struct msghdr msghdr = {
1034 .msg_iov = &iovec,
1035 .msg_iovlen = 1,
1036 .msg_control = &control,
1037 .msg_controllen = sizeof(control),
1038 };
7f4e0805 1039
3691bcf3 1040 n = recvmsg_safe(socket_fd, &msghdr, 0);
bb44fd07
ZJS
1041 if (ERRNO_IS_NEG_TRANSIENT(n))
1042 continue;
ad501930
MY
1043 if (n == -ECHRNG) {
1044 log_debug_errno(n, "Got message with truncated control data (unexpected fds sent?), ignoring.");
bb44fd07 1045 continue;
ad501930
MY
1046 }
1047 if (n == -EXFULL) {
1048 log_debug_errno(n, "Got message with truncated payload data, ignoring.");
1049 continue;
1050 }
1051 if (n < 0) {
3691bcf3 1052 r = (int) n;
7f4e0805
LP
1053 goto finish;
1054 }
1055
692597c8
LP
1056 CLEANUP_ERASE(passphrase);
1057
1c8da044
LP
1058 cmsg_close_all(&msghdr);
1059
8add30a0 1060 if (n == 0) {
00843602 1061 log_debug("Message too short");
7f4e0805
LP
1062 continue;
1063 }
1064
371d72e0
LP
1065 ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
1066 if (!ucred) {
00843602 1067 log_debug("Received message without credentials. Ignoring.");
7f4e0805
LP
1068 continue;
1069 }
1070
4dd2748b
LP
1071 if (ucred->uid != getuid() && ucred->uid != 0) {
1072 log_debug("Got response from bad user. Ignoring.");
7f4e0805
LP
1073 continue;
1074 }
1075
1076 if (passphrase[0] == '+') {
e287086b 1077 /* An empty message refers to the empty password */
8254a475 1078 if (n == 1)
bea1a013 1079 l = strv_new("");
8254a475
LP
1080 else
1081 l = strv_parse_nulstr(passphrase+1, n-1);
8254a475 1082 if (!l) {
7f4e0805
LP
1083 r = -ENOMEM;
1084 goto finish;
1085 }
1086
58629001 1087 if (strv_isempty(l)) {
e287086b 1088 l = strv_free(l);
00843602 1089 log_debug("Invalid packet");
21bc923a
LP
1090 continue;
1091 }
1092
e287086b
LP
1093 break;
1094 }
21bc923a 1095
e287086b 1096 if (passphrase[0] == '-') {
7f4e0805
LP
1097 r = -ECANCELED;
1098 goto finish;
7f4e0805
LP
1099 }
1100
e287086b 1101 log_debug("Invalid packet");
7f4e0805
LP
1102 }
1103
05db3fe7 1104 if (req->keyring)
d08fd4c3 1105 (void) add_to_keyring_and_log(req->keyring, flags, l);
e287086b 1106
ae2a15bc 1107 *ret = TAKE_PTR(l);
7f4e0805
LP
1108 r = 0;
1109
1110finish:
4dd2748b
LP
1111 if (temp) {
1112 assert(dfd >= 0);
1113 (void) unlinkat(dfd, temp, 0);
1114 } else if (final) {
1115 assert(dfd >= 0);
1116 (void) unlinkat(dfd, final, 0);
1117 }
7f4e0805 1118
f9b72cd8 1119 assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
7f4e0805
LP
1120 return r;
1121}
260ab287 1122
d08fd4c3 1123static int ask_password_credential(const AskPasswordRequest *req, AskPasswordFlags flags, char ***ret) {
8806bb4b 1124 _cleanup_(erase_and_freep) char *buffer = NULL;
623a8b19 1125 _cleanup_strv_free_erase_ char **l = NULL;
8806bb4b 1126 size_t size;
8806bb4b
LP
1127 int r;
1128
d08fd4c3
LP
1129 assert(req);
1130 assert(req->credential);
8806bb4b
LP
1131 assert(ret);
1132
d08fd4c3 1133 r = read_credential(req->credential, (void**) &buffer, &size);
8806bb4b
LP
1134 if (IN_SET(r, -ENXIO, -ENOENT)) /* No credentials passed or this credential not defined? */
1135 return -ENOKEY;
1136
1137 l = strv_parse_nulstr(buffer, size);
1138 if (!l)
1139 return -ENOMEM;
1140
623a8b19
YW
1141 if (strv_isempty(l))
1142 return log_debug_errno(SYNTHETIC_ERRNO(ENOKEY), "Found an empty password in credential.");
1143
1144 *ret = TAKE_PTR(l);
8806bb4b
LP
1145 return 0;
1146}
1147
00843602 1148int ask_password_auto(
d08fd4c3 1149 const AskPasswordRequest *req,
e287086b
LP
1150 AskPasswordFlags flags,
1151 char ***ret) {
00843602
LP
1152
1153 int r;
1154
05db3fe7 1155 assert(req);
e287086b 1156 assert(ret);
21bc923a 1157
7fd0ea6c
LP
1158 /* Returns the following well-known errors:
1159 *
1160 * -ETIME → a timeout was specified and hit
1161 * -EUNATCH → couldn't ask interactively and no cached password available either
1162 * -ENOENT → the specified flag file disappeared
1163 * -ECANCELED → the user explicitly cancelled the request
1164 * -EINTR → SIGINT/SIGTERM where received during the query
1165 * -ENOEXEC → headless mode was requested but no password could be acquired non-interactively
1166 * -ECONNRESET → a POLLHUP has been seen on the specified hup_fd
1167 */
1168
05db3fe7 1169 if (!FLAGS_SET(flags, ASK_PASSWORD_NO_CREDENTIAL) && req->credential) {
d08fd4c3 1170 r = ask_password_credential(req, flags, ret);
8806bb4b
LP
1171 if (r != -ENOKEY)
1172 return r;
1173 }
1174
9cb5bf91 1175 if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) &&
05db3fe7 1176 req->keyring &&
300b7e76 1177 (FLAGS_SET(flags, ASK_PASSWORD_NO_TTY) || !isatty_safe(STDIN_FILENO)) &&
9cb5bf91 1178 FLAGS_SET(flags, ASK_PASSWORD_NO_AGENT)) {
d08fd4c3 1179 r = ask_password_keyring(req, flags, ret);
e287086b
LP
1180 if (r != -ENOKEY)
1181 return r;
1182 }
1183
300b7e76 1184 if (!FLAGS_SET(flags, ASK_PASSWORD_NO_TTY) && isatty_safe(STDIN_FILENO))
c4a02a52 1185 return ask_password_tty(req, flags, ret);
00843602 1186
9cb5bf91 1187 if (!FLAGS_SET(flags, ASK_PASSWORD_NO_AGENT))
c4a02a52 1188 return ask_password_agent(req, flags, ret);
e287086b
LP
1189
1190 return -EUNATCH;
260ab287 1191}
ec572753
LP
1192
1193int acquire_user_ask_password_directory(char **ret) {
1194 int r;
1195
1196 r = xdg_user_runtime_dir("systemd/ask-password", ret);
1197 if (r == -ENXIO) {
1198 if (ret)
1199 *ret = NULL;
1200 return 0;
1201 }
1202 if (r < 0)
1203 return r;
1204
1205 return 1;
1206}