]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/ask-password-api.c
journal: fix incorrect errno reporting
[thirdparty/systemd.git] / src / shared / ask-password-api.c
CommitLineData
7f4e0805
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
7f4e0805
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
7f4e0805 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
7f4e0805
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
00843602 21
7f4e0805
LP
22#include <errno.h>
23#include <fcntl.h>
00843602
LP
24#include <poll.h>
25#include <stdbool.h>
7f4e0805 26#include <stddef.h>
00843602
LP
27#include <string.h>
28#include <sys/inotify.h>
7f4e0805 29#include <sys/signalfd.h>
00843602
LP
30#include <sys/socket.h>
31#include <sys/un.h>
32#include <termios.h>
33#include <unistd.h>
7f4e0805 34
b5efdb8a 35#include "alloc-util.h"
3ffd4af2
LP
36#include "ask-password-api.h"
37#include "fd-util.h"
0d39fa9c 38#include "fileio.h"
6482f626 39#include "formats-util.h"
c004493c 40#include "io-util.h"
e287086b 41#include "missing.h"
49e942b2 42#include "mkdir.h"
3df3e884 43#include "random-util.h"
24882e06 44#include "signal-util.h"
00843602 45#include "socket-util.h"
07630cea 46#include "string-util.h"
00843602
LP
47#include "strv.h"
48#include "terminal-util.h"
affb60b1 49#include "umask-util.h"
00843602 50#include "util.h"
7f4e0805 51
e287086b
LP
52#define KEYRING_TIMEOUT_USEC ((5 * USEC_PER_MINUTE) / 2)
53
54static int lookup_key(const char *keyname, key_serial_t *ret) {
55 key_serial_t serial;
56
57 assert(keyname);
58 assert(ret);
59
60 serial = request_key("user", keyname, NULL, 0);
61 if (serial == -1)
62 return -errno;
63
64 *ret = serial;
65 return 0;
66}
67
68static int retrieve_key(key_serial_t serial, char ***ret) {
69 _cleanup_free_ char *p = NULL;
70 long m = 100, n;
71 char **l;
72
73 assert(ret);
74
75 for (;;) {
76 p = new(char, m);
77 if (!p)
78 return -ENOMEM;
79
80 n = keyctl(KEYCTL_READ, (unsigned long) serial, (unsigned long) p, (unsigned long) m, 0);
81 if (n < 0)
82 return -errno;
83
84 if (n < m)
85 break;
86
1602b008 87 memory_erase(p, n);
e287086b
LP
88 free(p);
89 m *= 2;
90 }
91
92 l = strv_parse_nulstr(p, n);
93 if (!l)
94 return -ENOMEM;
95
1602b008
LP
96 memory_erase(p, n);
97
e287086b
LP
98 *ret = l;
99 return 0;
100}
101
102static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **passwords) {
ab84f5b9 103 _cleanup_strv_free_erase_ char **l = NULL;
e287086b
LP
104 _cleanup_free_ char *p = NULL;
105 key_serial_t serial;
106 size_t n;
107 int r;
108
109 assert(keyname);
110 assert(passwords);
111
112 if (!(flags & ASK_PASSWORD_PUSH_CACHE))
113 return 0;
114
115 r = lookup_key(keyname, &serial);
116 if (r >= 0) {
117 r = retrieve_key(serial, &l);
118 if (r < 0)
119 return r;
120 } else if (r != -ENOKEY)
121 return r;
122
123 r = strv_extend_strv(&l, passwords, true);
124 if (r <= 0)
125 return r;
126
127 r = strv_make_nulstr(l, &p, &n);
128 if (r < 0)
129 return r;
130
131 /* Truncate trailing NUL */
132 assert(n > 0);
133 assert(p[n-1] == 0);
134
135 serial = add_key("user", keyname, p, n-1, KEY_SPEC_USER_KEYRING);
1602b008 136 memory_erase(p, n);
e287086b
LP
137 if (serial == -1)
138 return -errno;
139
140 if (keyctl(KEYCTL_SET_TIMEOUT,
141 (unsigned long) serial,
142 (unsigned long) DIV_ROUND_UP(KEYRING_TIMEOUT_USEC, USEC_PER_SEC), 0, 0) < 0)
143 log_debug_errno(errno, "Failed to adjust timeout: %m");
144
145 log_debug("Added key to keyring as %" PRIi32 ".", serial);
146
147 return 1;
148}
149
150static int add_to_keyring_and_log(const char *keyname, AskPasswordFlags flags, char **passwords) {
151 int r;
152
153 assert(keyname);
154 assert(passwords);
155
156 r = add_to_keyring(keyname, flags, passwords);
157 if (r < 0)
158 return log_debug_errno(r, "Failed to add password to keyring: %m");
159
160 return 0;
161}
162
163int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret) {
164
165 key_serial_t serial;
166 int r;
167
168 assert(keyname);
169 assert(ret);
170
171 if (!(flags & ASK_PASSWORD_ACCEPT_CACHED))
172 return -EUNATCH;
173
174 r = lookup_key(keyname, &serial);
175 if (r == -ENOSYS) /* when retrieving the distinction doesn't matter */
176 return -ENOKEY;
177 if (r < 0)
178 return r;
179
180 return retrieve_key(serial, ret);
181}
182
58fc840b
LP
183static void backspace_chars(int ttyfd, size_t p) {
184
185 if (ttyfd < 0)
186 return;
187
188 while (p > 0) {
189 p--;
190
191 loop_write(ttyfd, "\b \b", 3, false);
192 }
193}
194
7f4e0805
LP
195int ask_password_tty(
196 const char *message,
e287086b 197 const char *keyname,
7f4e0805 198 usec_t until,
e287086b 199 AskPasswordFlags flags,
7f4e0805 200 const char *flag_file,
e287086b 201 char **ret) {
7f4e0805
LP
202
203 struct termios old_termios, new_termios;
981e4cd3 204 char passphrase[LINE_MAX], *x;
7f4e0805 205 size_t p = 0;
981e4cd3
LP
206 int r;
207 _cleanup_close_ int ttyfd = -1, notify = -1;
7f4e0805
LP
208 struct pollfd pollfd[2];
209 bool reset_tty = false;
441dfe09 210 bool dirty = false;
7f4e0805
LP
211 enum {
212 POLL_TTY,
213 POLL_INOTIFY
214 };
215
e287086b
LP
216 assert(ret);
217
218 if (flags & ASK_PASSWORD_NO_TTY)
219 return -EUNATCH;
220
221 if (!message)
222 message = "Password:";
7f4e0805
LP
223
224 if (flag_file) {
981e4cd3
LP
225 notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
226 if (notify < 0) {
7f4e0805
LP
227 r = -errno;
228 goto finish;
229 }
230
231 if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0) {
232 r = -errno;
233 goto finish;
234 }
235 }
236
981e4cd3
LP
237 ttyfd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC);
238 if (ttyfd >= 0) {
7f4e0805
LP
239
240 if (tcgetattr(ttyfd, &old_termios) < 0) {
241 r = -errno;
242 goto finish;
243 }
244
00843602 245 loop_write(ttyfd, ANSI_HIGHLIGHT, strlen(ANSI_HIGHLIGHT), false);
7f4e0805 246 loop_write(ttyfd, message, strlen(message), false);
bd1db33f 247 loop_write(ttyfd, " ", 1, false);
00843602 248 loop_write(ttyfd, ANSI_NORMAL, strlen(ANSI_NORMAL), false);
7f4e0805
LP
249
250 new_termios = old_termios;
251 new_termios.c_lflag &= ~(ICANON|ECHO);
252 new_termios.c_cc[VMIN] = 1;
253 new_termios.c_cc[VTIME] = 0;
254
255 if (tcsetattr(ttyfd, TCSADRAIN, &new_termios) < 0) {
256 r = -errno;
257 goto finish;
258 }
259
260 reset_tty = true;
261 }
262
263 zero(pollfd);
7f4e0805
LP
264 pollfd[POLL_TTY].fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO;
265 pollfd[POLL_TTY].events = POLLIN;
266 pollfd[POLL_INOTIFY].fd = notify;
267 pollfd[POLL_INOTIFY].events = POLLIN;
268
269 for (;;) {
270 char c;
271 int sleep_for = -1, k;
272 ssize_t n;
273
274 if (until > 0) {
275 usec_t y;
276
277 y = now(CLOCK_MONOTONIC);
278
279 if (y > until) {
7ded2e28 280 r = -ETIME;
7f4e0805
LP
281 goto finish;
282 }
283
284 sleep_for = (int) ((until - y) / USEC_PER_MSEC);
285 }
286
287 if (flag_file)
288 if (access(flag_file, F_OK) < 0) {
289 r = -errno;
290 goto finish;
291 }
292
e287086b 293 k = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for);
981e4cd3 294 if (k < 0) {
7f4e0805
LP
295 if (errno == EINTR)
296 continue;
297
298 r = -errno;
299 goto finish;
300 } else if (k == 0) {
ccc80078 301 r = -ETIME;
7f4e0805
LP
302 goto finish;
303 }
304
e287086b 305 if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0)
7f4e0805
LP
306 flush_fd(notify);
307
308 if (pollfd[POLL_TTY].revents == 0)
309 continue;
310
981e4cd3
LP
311 n = read(ttyfd >= 0 ? ttyfd : STDIN_FILENO, &c, 1);
312 if (n < 0) {
7f4e0805
LP
313 if (errno == EINTR || errno == EAGAIN)
314 continue;
315
316 r = -errno;
317 goto finish;
318
319 } else if (n == 0)
320 break;
321
322 if (c == '\n')
323 break;
58fc840b 324 else if (c == 21) { /* C-u */
7f4e0805 325
e287086b 326 if (!(flags & ASK_PASSWORD_SILENT))
58fc840b
LP
327 backspace_chars(ttyfd, p);
328 p = 0;
7f4e0805
LP
329
330 } else if (c == '\b' || c == 127) {
58fc840b
LP
331
332 if (p > 0) {
333
e287086b 334 if (!(flags & ASK_PASSWORD_SILENT))
58fc840b
LP
335 backspace_chars(ttyfd, 1);
336
7f4e0805 337 p--;
e287086b 338 } else if (!dirty && !(flags & ASK_PASSWORD_SILENT)) {
441dfe09 339
e287086b 340 flags |= ASK_PASSWORD_SILENT;
441dfe09
LP
341
342 /* There are two ways to enter silent
343 * mode. Either by pressing backspace
e287086b
LP
344 * as first key (and only as first
345 * key), or ... */
441dfe09
LP
346 if (ttyfd >= 0)
347 loop_write(ttyfd, "(no echo) ", 10, false);
348
58fc840b
LP
349 } else if (ttyfd >= 0)
350 loop_write(ttyfd, "\a", 1, false);
7f4e0805 351
e287086b 352 } else if (c == '\t' && !(flags & ASK_PASSWORD_SILENT)) {
58fc840b
LP
353
354 backspace_chars(ttyfd, p);
e287086b 355 flags |= ASK_PASSWORD_SILENT;
58fc840b 356
441dfe09
LP
357 /* ... or by pressing TAB at any time. */
358
58fc840b
LP
359 if (ttyfd >= 0)
360 loop_write(ttyfd, "(no echo) ", 10, false);
7f4e0805 361 } else {
036eeac5
LP
362 if (p >= sizeof(passphrase)-1) {
363 loop_write(ttyfd, "\a", 1, false);
364 continue;
365 }
366
7f4e0805
LP
367 passphrase[p++] = c;
368
e287086b
LP
369 if (!(flags & ASK_PASSWORD_SILENT) && ttyfd >= 0)
370 loop_write(ttyfd, (flags & ASK_PASSWORD_ECHO) ? &c : "*", 1, false);
441dfe09
LP
371
372 dirty = true;
7f4e0805 373 }
1602b008
LP
374
375 c = 'x';
7f4e0805
LP
376 }
377
981e4cd3 378 x = strndup(passphrase, p);
1602b008 379 memory_erase(passphrase, p);
981e4cd3 380 if (!x) {
7f4e0805
LP
381 r = -ENOMEM;
382 goto finish;
383 }
384
e287086b
LP
385 if (keyname)
386 (void) add_to_keyring_and_log(keyname, flags, STRV_MAKE(x));
387
388 *ret = x;
7f4e0805
LP
389 r = 0;
390
391finish:
981e4cd3
LP
392 if (ttyfd >= 0 && reset_tty) {
393 loop_write(ttyfd, "\n", 1, false);
394 tcsetattr(ttyfd, TCSADRAIN, &old_termios);
7f4e0805
LP
395 }
396
397 return r;
398}
399
400static int create_socket(char **name) {
00843602 401 union sockaddr_union sa = {
b92bea5d
ZJS
402 .un.sun_family = AF_UNIX,
403 };
00843602
LP
404 _cleanup_close_ int fd = -1;
405 static const int one = 1;
7f4e0805 406 char *c;
00843602 407 int r;
7f4e0805
LP
408
409 assert(name);
410
e62d8c39 411 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
4a62c710 412 if (fd < 0)
00843602 413 return -errno;
7f4e0805 414
9bf3b535 415 snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/run/systemd/ask-password/sck.%" PRIx64, random_u64());
7f4e0805 416
5c0d398d 417 RUN_WITH_UMASK(0177) {
00843602
LP
418 if (bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
419 return -errno;
5c0d398d 420 }
1d6702e8 421
00843602
LP
422 if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
423 return -errno;
7f4e0805 424
e62d8c39 425 c = strdup(sa.un.sun_path);
00843602
LP
426 if (!c)
427 return -ENOMEM;
7f4e0805
LP
428
429 *name = c;
7f4e0805 430
00843602
LP
431 r = fd;
432 fd = -1;
7f4e0805
LP
433
434 return r;
435}
436
7f4e0805
LP
437int ask_password_agent(
438 const char *message,
439 const char *icon,
9fa1de96 440 const char *id,
e287086b 441 const char *keyname,
7f4e0805 442 usec_t until,
e287086b
LP
443 AskPasswordFlags flags,
444 char ***ret) {
7f4e0805
LP
445
446 enum {
447 FD_SOCKET,
448 FD_SIGNAL,
449 _FD_MAX
450 };
451
e287086b 452 _cleanup_close_ int socket_fd = -1, signal_fd = -1, fd = -1;
2b583ce6 453 char temp[] = "/run/systemd/ask-password/tmp.XXXXXX";
7f4e0805 454 char final[sizeof(temp)] = "";
981e4cd3 455 _cleanup_free_ char *socket_name = NULL;
e287086b
LP
456 _cleanup_strv_free_ char **l = NULL;
457 _cleanup_fclose_ FILE *f = NULL;
7f4e0805 458 struct pollfd pollfd[_FD_MAX];
e287086b 459 sigset_t mask, oldmask;
981e4cd3 460 int r;
7f4e0805 461
e287086b 462 assert(ret);
21bc923a 463
e287086b
LP
464 if (flags & ASK_PASSWORD_NO_AGENT)
465 return -EUNATCH;
00843602 466
72c0a2c2
LP
467 assert_se(sigemptyset(&mask) >= 0);
468 assert_se(sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0);
469 assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) >= 0);
f9b72cd8 470
00843602 471 (void) mkdir_p_label("/run/systemd/ask-password", 0755);
7f4e0805 472
2d5bdf5b 473 fd = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC);
1d6702e8 474 if (fd < 0) {
00843602 475 r = -errno;
7f4e0805
LP
476 goto finish;
477 }
478
00843602 479 (void) fchmod(fd, 0644);
7f4e0805 480
981e4cd3
LP
481 f = fdopen(fd, "w");
482 if (!f) {
00843602 483 r = -errno;
7f4e0805
LP
484 goto finish;
485 }
486
487 fd = -1;
488
981e4cd3
LP
489 signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
490 if (signal_fd < 0) {
00843602 491 r = -errno;
7f4e0805
LP
492 goto finish;
493 }
494
981e4cd3
LP
495 socket_fd = create_socket(&socket_name);
496 if (socket_fd < 0) {
7f4e0805
LP
497 r = socket_fd;
498 goto finish;
499 }
500
501 fprintf(f,
502 "[Ask]\n"
de0671ee 503 "PID="PID_FMT"\n"
7f4e0805 504 "Socket=%s\n"
21bc923a 505 "AcceptCached=%i\n"
64845bdc 506 "Echo=%i\n"
de0671ee
ZJS
507 "NotAfter="USEC_FMT"\n",
508 getpid(),
7f4e0805 509 socket_name,
e287086b
LP
510 (flags & ASK_PASSWORD_ACCEPT_CACHED) ? 1 : 0,
511 (flags & ASK_PASSWORD_ECHO) ? 1 : 0,
de0671ee 512 until);
7f4e0805
LP
513
514 if (message)
515 fprintf(f, "Message=%s\n", message);
516
517 if (icon)
518 fprintf(f, "Icon=%s\n", icon);
519
9fa1de96
DH
520 if (id)
521 fprintf(f, "Id=%s\n", id);
522
dacd6cee 523 r = fflush_and_check(f);
00843602 524 if (r < 0)
7f4e0805 525 goto finish;
7f4e0805
LP
526
527 memcpy(final, temp, sizeof(temp));
528
529 final[sizeof(final)-11] = 'a';
530 final[sizeof(final)-10] = 's';
531 final[sizeof(final)-9] = 'k';
532
533 if (rename(temp, final) < 0) {
00843602 534 r = -errno;
7f4e0805
LP
535 goto finish;
536 }
537
538 zero(pollfd);
539 pollfd[FD_SOCKET].fd = socket_fd;
540 pollfd[FD_SOCKET].events = POLLIN;
541 pollfd[FD_SIGNAL].fd = signal_fd;
542 pollfd[FD_SIGNAL].events = POLLIN;
543
544 for (;;) {
545 char passphrase[LINE_MAX+1];
546 struct msghdr msghdr;
547 struct iovec iovec;
548 struct ucred *ucred;
549 union {
550 struct cmsghdr cmsghdr;
551 uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
552 } control;
553 ssize_t n;
554 int k;
555 usec_t t;
556
557 t = now(CLOCK_MONOTONIC);
558
7dcda352 559 if (until > 0 && until <= t) {
7f4e0805
LP
560 r = -ETIME;
561 goto finish;
562 }
563
981e4cd3
LP
564 k = poll(pollfd, _FD_MAX, until > 0 ? (int) ((until-t)/USEC_PER_MSEC) : -1);
565 if (k < 0) {
7f4e0805
LP
566 if (errno == EINTR)
567 continue;
568
00843602 569 r = -errno;
7f4e0805
LP
570 goto finish;
571 }
572
573 if (k <= 0) {
7f4e0805
LP
574 r = -ETIME;
575 goto finish;
576 }
577
21bc923a
LP
578 if (pollfd[FD_SIGNAL].revents & POLLIN) {
579 r = -EINTR;
580 goto finish;
581 }
7f4e0805
LP
582
583 if (pollfd[FD_SOCKET].revents != POLLIN) {
7f4e0805
LP
584 r = -EIO;
585 goto finish;
586 }
587
588 zero(iovec);
589 iovec.iov_base = passphrase;
21bc923a 590 iovec.iov_len = sizeof(passphrase);
7f4e0805
LP
591
592 zero(control);
593 zero(msghdr);
594 msghdr.msg_iov = &iovec;
595 msghdr.msg_iovlen = 1;
596 msghdr.msg_control = &control;
597 msghdr.msg_controllen = sizeof(control);
598
981e4cd3
LP
599 n = recvmsg(socket_fd, &msghdr, 0);
600 if (n < 0) {
7f4e0805
LP
601 if (errno == EAGAIN ||
602 errno == EINTR)
603 continue;
604
00843602 605 r = -errno;
7f4e0805
LP
606 goto finish;
607 }
608
1c8da044
LP
609 cmsg_close_all(&msghdr);
610
7f4e0805 611 if (n <= 0) {
00843602 612 log_debug("Message too short");
7f4e0805
LP
613 continue;
614 }
615
616 if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
617 control.cmsghdr.cmsg_level != SOL_SOCKET ||
618 control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
619 control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
00843602 620 log_debug("Received message without credentials. Ignoring.");
7f4e0805
LP
621 continue;
622 }
623
624 ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
625 if (ucred->uid != 0) {
00843602 626 log_debug("Got request from unprivileged user. Ignoring.");
7f4e0805
LP
627 continue;
628 }
629
630 if (passphrase[0] == '+') {
e287086b 631 /* An empty message refers to the empty password */
8254a475
LP
632 if (n == 1)
633 l = strv_new("", NULL);
634 else
635 l = strv_parse_nulstr(passphrase+1, n-1);
1602b008 636 memory_erase(passphrase, n);
8254a475 637 if (!l) {
7f4e0805
LP
638 r = -ENOMEM;
639 goto finish;
640 }
641
21bc923a 642 if (strv_length(l) <= 0) {
e287086b 643 l = strv_free(l);
00843602 644 log_debug("Invalid packet");
21bc923a
LP
645 continue;
646 }
647
e287086b
LP
648 break;
649 }
21bc923a 650
e287086b 651 if (passphrase[0] == '-') {
7f4e0805
LP
652 r = -ECANCELED;
653 goto finish;
7f4e0805
LP
654 }
655
e287086b 656 log_debug("Invalid packet");
7f4e0805
LP
657 }
658
e287086b
LP
659 if (keyname)
660 (void) add_to_keyring_and_log(keyname, flags, l);
661
662 *ret = l;
663 l = NULL;
7f4e0805
LP
664 r = 0;
665
666finish:
981e4cd3 667 if (socket_name)
00843602 668 (void) unlink(socket_name);
7f4e0805 669
00843602 670 (void) unlink(temp);
7f4e0805
LP
671
672 if (final[0])
00843602 673 (void) unlink(final);
7f4e0805 674
f9b72cd8 675 assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
7f4e0805
LP
676 return r;
677}
260ab287 678
00843602
LP
679int ask_password_auto(
680 const char *message,
681 const char *icon,
682 const char *id,
e287086b 683 const char *keyname,
00843602 684 usec_t until,
e287086b
LP
685 AskPasswordFlags flags,
686 char ***ret) {
00843602
LP
687
688 int r;
689
e287086b 690 assert(ret);
21bc923a 691
e287086b
LP
692 if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname) {
693 r = ask_password_keyring(keyname, flags, ret);
694 if (r != -ENOKEY)
695 return r;
696 }
697
698 if (!(flags & ASK_PASSWORD_NO_TTY) && isatty(STDIN_FILENO)) {
21bc923a
LP
699 char *s = NULL, **l = NULL;
700
e287086b 701 r = ask_password_tty(message, keyname, until, flags, NULL, &s);
981e4cd3 702 if (r < 0)
21bc923a
LP
703 return r;
704
1602b008
LP
705 r = strv_push(&l, s);
706 if (r < 0) {
707 string_erase(s);
708 free(s);
00843602 709 return -ENOMEM;
1602b008 710 }
21bc923a 711
e287086b 712 *ret = l;
00843602
LP
713 return 0;
714 }
715
e287086b
LP
716 if (!(flags & ASK_PASSWORD_NO_AGENT))
717 return ask_password_agent(message, icon, id, keyname, until, flags, ret);
718
719 return -EUNATCH;
260ab287 720}