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