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