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