]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/ask-password-api.c
tree-wide: drop license boilerplate
[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
7f4e0805 6***/
00843602 7
7f4e0805
LP
8#include <errno.h>
9#include <fcntl.h>
a8fbdf54
TA
10#include <inttypes.h>
11#include <limits.h>
00843602 12#include <poll.h>
a8fbdf54 13#include <signal.h>
00843602 14#include <stdbool.h>
7f4e0805 15#include <stddef.h>
a8fbdf54
TA
16#include <stdint.h>
17#include <stdio.h>
18#include <stdlib.h>
00843602
LP
19#include <string.h>
20#include <sys/inotify.h>
7f4e0805 21#include <sys/signalfd.h>
00843602 22#include <sys/socket.h>
a8fbdf54
TA
23#include <sys/stat.h>
24#include <sys/time.h>
25#include <sys/uio.h>
00843602
LP
26#include <sys/un.h>
27#include <termios.h>
28#include <unistd.h>
7f4e0805 29
b5efdb8a 30#include "alloc-util.h"
3ffd4af2
LP
31#include "ask-password-api.h"
32#include "fd-util.h"
0d39fa9c 33#include "fileio.h"
f97b34a6 34#include "format-util.h"
c004493c 35#include "io-util.h"
a8fbdf54
TA
36#include "log.h"
37#include "macro.h"
e287086b 38#include "missing.h"
49e942b2 39#include "mkdir.h"
df0ff127 40#include "process-util.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"
a8fbdf54 47#include "time-util.h"
affb60b1 48#include "umask-util.h"
f3149d57 49#include "utf8.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)
9c4615fb 62 return negative_errno();
e287086b
LP
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
2d26d8e0 87 explicit_bzero(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
2d26d8e0 96 explicit_bzero(p, n);
1602b008 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
b60df13b 131 serial = add_key("user", keyname, p, n, KEY_SPEC_USER_KEYRING);
2d26d8e0 132 explicit_bzero(p, n);
e287086b
LP
133 if (serial == -1)
134 return -errno;
135
136 if (keyctl(KEYCTL_SET_TIMEOUT,
137 (unsigned long) serial,
138 (unsigned long) DIV_ROUND_UP(KEYRING_TIMEOUT_USEC, USEC_PER_SEC), 0, 0) < 0)
139 log_debug_errno(errno, "Failed to adjust timeout: %m");
140
141 log_debug("Added key to keyring as %" PRIi32 ".", serial);
142
143 return 1;
144}
145
146static int add_to_keyring_and_log(const char *keyname, AskPasswordFlags flags, char **passwords) {
147 int r;
148
149 assert(keyname);
150 assert(passwords);
151
152 r = add_to_keyring(keyname, flags, passwords);
153 if (r < 0)
154 return log_debug_errno(r, "Failed to add password to keyring: %m");
155
156 return 0;
157}
158
159int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret) {
160
161 key_serial_t serial;
162 int r;
163
164 assert(keyname);
165 assert(ret);
166
167 if (!(flags & ASK_PASSWORD_ACCEPT_CACHED))
168 return -EUNATCH;
169
170 r = lookup_key(keyname, &serial);
171 if (r == -ENOSYS) /* when retrieving the distinction doesn't matter */
172 return -ENOKEY;
173 if (r < 0)
174 return r;
175
176 return retrieve_key(serial, ret);
177}
178
58fc840b
LP
179static void backspace_chars(int ttyfd, size_t p) {
180
181 if (ttyfd < 0)
182 return;
183
184 while (p > 0) {
185 p--;
186
187 loop_write(ttyfd, "\b \b", 3, false);
188 }
189}
190
fd6ac62c
LP
191static void backspace_string(int ttyfd, const char *str) {
192 size_t m;
193
194 assert(str);
195
196 if (ttyfd < 0)
197 return;
198
f95dbcc2 199 /* Backspaces through enough characters to entirely undo printing of the specified string. */
fd6ac62c
LP
200
201 m = utf8_n_codepoints(str);
202 if (m == (size_t) -1)
203 m = strlen(str); /* Not a valid UTF-8 string? If so, let's backspace the number of bytes output. Most
204 * likely this happened because we are not in an UTF-8 locale, and in that case that
205 * is the correct thing to do. And even if it's not, terminals tend to stop
206 * backspacing at the leftmost column, hence backspacing too much should be mostly
207 * OK. */
208
209 backspace_chars(ttyfd, m);
210}
211
7f4e0805 212int ask_password_tty(
daa55720 213 int ttyfd,
7f4e0805 214 const char *message,
e287086b 215 const char *keyname,
7f4e0805 216 usec_t until,
e287086b 217 AskPasswordFlags flags,
7f4e0805 218 const char *flag_file,
e287086b 219 char **ret) {
7f4e0805 220
088dcd8e
LP
221 enum {
222 POLL_TTY,
223 POLL_INOTIFY,
224 _POLL_MAX,
225 };
226
c2b32159 227 bool reset_tty = false, dirty = false, use_color = false;
daa55720 228 _cleanup_close_ int cttyfd = -1, notify = -1;
7f4e0805 229 struct termios old_termios, new_termios;
f3149d57 230 char passphrase[LINE_MAX + 1] = {}, *x;
088dcd8e 231 struct pollfd pollfd[_POLL_MAX];
f3149d57 232 size_t p = 0, codepoint = 0;
088dcd8e 233 int r;
7f4e0805 234
e287086b
LP
235 assert(ret);
236
237 if (flags & ASK_PASSWORD_NO_TTY)
238 return -EUNATCH;
239
240 if (!message)
241 message = "Password:";
7f4e0805
LP
242
243 if (flag_file) {
981e4cd3 244 notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
a497a296
LP
245 if (notify < 0)
246 return -errno;
247
248 if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0)
249 return -errno;
7f4e0805
LP
250 }
251
daa55720
LP
252 /* If the caller didn't specify a TTY, then use the controlling tty, if we can. */
253 if (ttyfd < 0)
254 ttyfd = cttyfd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC);
7f4e0805 255
daa55720 256 if (ttyfd >= 0) {
a497a296
LP
257 if (tcgetattr(ttyfd, &old_termios) < 0)
258 return -errno;
7f4e0805 259
c2b32159
LP
260 if (flags & ASK_PASSWORD_CONSOLE_COLOR)
261 use_color = dev_console_colors_enabled();
262 else
263 use_color = colors_enabled();
264
265 if (use_color)
ac7a9674
LP
266 (void) loop_write(ttyfd, ANSI_HIGHLIGHT, STRLEN(ANSI_HIGHLIGHT), false);
267
268 (void) loop_write(ttyfd, message, strlen(message), false);
269 (void) loop_write(ttyfd, " ", 1, false);
270
c2b32159 271 if (use_color)
ac7a9674 272 (void) loop_write(ttyfd, ANSI_NORMAL, STRLEN(ANSI_NORMAL), false);
7f4e0805
LP
273
274 new_termios = old_termios;
275 new_termios.c_lflag &= ~(ICANON|ECHO);
276 new_termios.c_cc[VMIN] = 1;
277 new_termios.c_cc[VTIME] = 0;
278
279 if (tcsetattr(ttyfd, TCSADRAIN, &new_termios) < 0) {
280 r = -errno;
281 goto finish;
282 }
283
284 reset_tty = true;
285 }
286
70dee475
LP
287 pollfd[POLL_TTY] = (struct pollfd) {
288 .fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO,
289 .events = POLLIN,
290 };
291 pollfd[POLL_INOTIFY] = (struct pollfd) {
292 .fd = notify,
293 .events = POLLIN,
294 };
7f4e0805
LP
295
296 for (;;) {
7f4e0805
LP
297 int sleep_for = -1, k;
298 ssize_t n;
fd6ac62c 299 char c;
7f4e0805
LP
300
301 if (until > 0) {
302 usec_t y;
303
304 y = now(CLOCK_MONOTONIC);
305
306 if (y > until) {
7ded2e28 307 r = -ETIME;
7f4e0805
LP
308 goto finish;
309 }
310
c9eb4a00 311 sleep_for = (int) DIV_ROUND_UP(until - y, USEC_PER_MSEC);
7f4e0805
LP
312 }
313
314 if (flag_file)
315 if (access(flag_file, F_OK) < 0) {
316 r = -errno;
317 goto finish;
318 }
319
e287086b 320 k = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for);
981e4cd3 321 if (k < 0) {
7f4e0805
LP
322 if (errno == EINTR)
323 continue;
324
325 r = -errno;
326 goto finish;
327 } else if (k == 0) {
ccc80078 328 r = -ETIME;
7f4e0805
LP
329 goto finish;
330 }
331
e287086b 332 if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0)
665dfe93 333 (void) flush_fd(notify);
7f4e0805
LP
334
335 if (pollfd[POLL_TTY].revents == 0)
336 continue;
337
981e4cd3
LP
338 n = read(ttyfd >= 0 ? ttyfd : STDIN_FILENO, &c, 1);
339 if (n < 0) {
3742095b 340 if (IN_SET(errno, EINTR, EAGAIN))
7f4e0805
LP
341 continue;
342
343 r = -errno;
344 goto finish;
345
fd6ac62c 346 }
7f4e0805 347
fd6ac62c
LP
348 /* We treat EOF, newline and NUL byte all as valid end markers */
349 if (n == 0 || c == '\n' || c == 0)
7f4e0805 350 break;
fd6ac62c
LP
351
352 if (c == 21) { /* C-u */
7f4e0805 353
e287086b 354 if (!(flags & ASK_PASSWORD_SILENT))
fd6ac62c
LP
355 backspace_string(ttyfd, passphrase);
356
357 explicit_bzero(passphrase, sizeof(passphrase));
358 p = codepoint = 0;
7f4e0805 359
4c701096 360 } else if (IN_SET(c, '\b', 127)) {
58fc840b
LP
361
362 if (p > 0) {
fd6ac62c 363 size_t q;
58fc840b 364
e287086b 365 if (!(flags & ASK_PASSWORD_SILENT))
58fc840b
LP
366 backspace_chars(ttyfd, 1);
367
fd6ac62c
LP
368 /* Remove a full UTF-8 codepoint from the end. For that, figure out where the last one
369 * begins */
370 q = 0;
371 for (;;) {
372 size_t z;
373
374 z = utf8_encoded_valid_unichar(passphrase + q);
375 if (z == 0) {
376 q = (size_t) -1; /* Invalid UTF8! */
377 break;
378 }
379
380 if (q + z >= p) /* This one brings us over the edge */
381 break;
382
383 q += z;
384 }
385
386 p = codepoint = q == (size_t) -1 ? p - 1 : q;
387 explicit_bzero(passphrase + p, sizeof(passphrase) - p);
388
e287086b 389 } else if (!dirty && !(flags & ASK_PASSWORD_SILENT)) {
441dfe09 390
e287086b 391 flags |= ASK_PASSWORD_SILENT;
441dfe09 392
fd6ac62c
LP
393 /* There are two ways to enter silent mode. Either by pressing backspace as first key
394 * (and only as first key), or ... */
395
441dfe09 396 if (ttyfd >= 0)
ac7a9674 397 (void) loop_write(ttyfd, "(no echo) ", 10, false);
441dfe09 398
58fc840b 399 } else if (ttyfd >= 0)
ac7a9674 400 (void) loop_write(ttyfd, "\a", 1, false);
7f4e0805 401
e287086b 402 } else if (c == '\t' && !(flags & ASK_PASSWORD_SILENT)) {
58fc840b 403
fd6ac62c 404 backspace_string(ttyfd, passphrase);
e287086b 405 flags |= ASK_PASSWORD_SILENT;
58fc840b 406
441dfe09
LP
407 /* ... or by pressing TAB at any time. */
408
58fc840b 409 if (ttyfd >= 0)
ac7a9674 410 (void) loop_write(ttyfd, "(no echo) ", 10, false);
036eeac5 411
fd6ac62c
LP
412 } else if (p >= sizeof(passphrase)-1) {
413
414 /* Reached the size limit */
415 if (ttyfd >= 0)
416 (void) loop_write(ttyfd, "\a", 1, false);
417
418 } else {
7f4e0805
LP
419 passphrase[p++] = c;
420
f3149d57 421 if (!(flags & ASK_PASSWORD_SILENT) && ttyfd >= 0) {
fd6ac62c 422 /* Check if we got a complete UTF-8 character now. If so, let's output one '*'. */
f3149d57
ZJS
423 n = utf8_encoded_valid_unichar(passphrase + codepoint);
424 if (n >= 0) {
425 codepoint = p;
ac7a9674 426 (void) loop_write(ttyfd, (flags & ASK_PASSWORD_ECHO) ? &c : "*", 1, false);
f3149d57
ZJS
427 }
428 }
441dfe09
LP
429
430 dirty = true;
7f4e0805 431 }
1602b008 432
fd6ac62c 433 /* Let's forget this char, just to not keep needlessly copies of key material around */
1602b008 434 c = 'x';
7f4e0805
LP
435 }
436
981e4cd3 437 x = strndup(passphrase, p);
fd6ac62c 438 explicit_bzero(passphrase, sizeof(passphrase));
981e4cd3 439 if (!x) {
7f4e0805
LP
440 r = -ENOMEM;
441 goto finish;
442 }
443
e287086b
LP
444 if (keyname)
445 (void) add_to_keyring_and_log(keyname, flags, STRV_MAKE(x));
446
447 *ret = x;
7f4e0805
LP
448 r = 0;
449
450finish:
981e4cd3 451 if (ttyfd >= 0 && reset_tty) {
ac7a9674
LP
452 (void) loop_write(ttyfd, "\n", 1, false);
453 (void) tcsetattr(ttyfd, TCSADRAIN, &old_termios);
7f4e0805
LP
454 }
455
456 return r;
457}
458
459static int create_socket(char **name) {
00843602 460 union sockaddr_union sa = {
b92bea5d
ZJS
461 .un.sun_family = AF_UNIX,
462 };
00843602
LP
463 _cleanup_close_ int fd = -1;
464 static const int one = 1;
7f4e0805 465 char *c;
00843602 466 int r;
7f4e0805
LP
467
468 assert(name);
469
e62d8c39 470 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
4a62c710 471 if (fd < 0)
00843602 472 return -errno;
7f4e0805 473
9bf3b535 474 snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/run/systemd/ask-password/sck.%" PRIx64, random_u64());
7f4e0805 475
5c0d398d 476 RUN_WITH_UMASK(0177) {
fc2fffe7 477 if (bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
00843602 478 return -errno;
5c0d398d 479 }
1d6702e8 480
00843602
LP
481 if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
482 return -errno;
7f4e0805 483
e62d8c39 484 c = strdup(sa.un.sun_path);
00843602
LP
485 if (!c)
486 return -ENOMEM;
7f4e0805
LP
487
488 *name = c;
7f4e0805 489
00843602
LP
490 r = fd;
491 fd = -1;
7f4e0805
LP
492
493 return r;
494}
495
7f4e0805
LP
496int ask_password_agent(
497 const char *message,
498 const char *icon,
9fa1de96 499 const char *id,
e287086b 500 const char *keyname,
7f4e0805 501 usec_t until,
e287086b
LP
502 AskPasswordFlags flags,
503 char ***ret) {
7f4e0805
LP
504
505 enum {
506 FD_SOCKET,
507 FD_SIGNAL,
508 _FD_MAX
509 };
510
e287086b 511 _cleanup_close_ int socket_fd = -1, signal_fd = -1, fd = -1;
2b583ce6 512 char temp[] = "/run/systemd/ask-password/tmp.XXXXXX";
7f4e0805 513 char final[sizeof(temp)] = "";
981e4cd3 514 _cleanup_free_ char *socket_name = NULL;
e287086b
LP
515 _cleanup_strv_free_ char **l = NULL;
516 _cleanup_fclose_ FILE *f = NULL;
7f4e0805 517 struct pollfd pollfd[_FD_MAX];
e287086b 518 sigset_t mask, oldmask;
981e4cd3 519 int r;
7f4e0805 520
e287086b 521 assert(ret);
21bc923a 522
e287086b
LP
523 if (flags & ASK_PASSWORD_NO_AGENT)
524 return -EUNATCH;
00843602 525
72c0a2c2
LP
526 assert_se(sigemptyset(&mask) >= 0);
527 assert_se(sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0);
528 assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) >= 0);
f9b72cd8 529
00843602 530 (void) mkdir_p_label("/run/systemd/ask-password", 0755);
7f4e0805 531
646853bd 532 fd = mkostemp_safe(temp);
1d6702e8 533 if (fd < 0) {
709f6e46 534 r = fd;
7f4e0805
LP
535 goto finish;
536 }
537
00843602 538 (void) fchmod(fd, 0644);
7f4e0805 539
981e4cd3
LP
540 f = fdopen(fd, "w");
541 if (!f) {
00843602 542 r = -errno;
7f4e0805
LP
543 goto finish;
544 }
545
546 fd = -1;
547
981e4cd3
LP
548 signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
549 if (signal_fd < 0) {
00843602 550 r = -errno;
7f4e0805
LP
551 goto finish;
552 }
553
981e4cd3
LP
554 socket_fd = create_socket(&socket_name);
555 if (socket_fd < 0) {
7f4e0805
LP
556 r = socket_fd;
557 goto finish;
558 }
559
560 fprintf(f,
561 "[Ask]\n"
de0671ee 562 "PID="PID_FMT"\n"
7f4e0805 563 "Socket=%s\n"
21bc923a 564 "AcceptCached=%i\n"
64845bdc 565 "Echo=%i\n"
de0671ee 566 "NotAfter="USEC_FMT"\n",
df0ff127 567 getpid_cached(),
7f4e0805 568 socket_name,
e287086b
LP
569 (flags & ASK_PASSWORD_ACCEPT_CACHED) ? 1 : 0,
570 (flags & ASK_PASSWORD_ECHO) ? 1 : 0,
de0671ee 571 until);
7f4e0805
LP
572
573 if (message)
574 fprintf(f, "Message=%s\n", message);
575
576 if (icon)
577 fprintf(f, "Icon=%s\n", icon);
578
9fa1de96
DH
579 if (id)
580 fprintf(f, "Id=%s\n", id);
581
dacd6cee 582 r = fflush_and_check(f);
00843602 583 if (r < 0)
7f4e0805 584 goto finish;
7f4e0805
LP
585
586 memcpy(final, temp, sizeof(temp));
587
588 final[sizeof(final)-11] = 'a';
589 final[sizeof(final)-10] = 's';
590 final[sizeof(final)-9] = 'k';
591
592 if (rename(temp, final) < 0) {
00843602 593 r = -errno;
7f4e0805
LP
594 goto finish;
595 }
596
597 zero(pollfd);
598 pollfd[FD_SOCKET].fd = socket_fd;
599 pollfd[FD_SOCKET].events = POLLIN;
600 pollfd[FD_SIGNAL].fd = signal_fd;
601 pollfd[FD_SIGNAL].events = POLLIN;
602
603 for (;;) {
604 char passphrase[LINE_MAX+1];
605 struct msghdr msghdr;
606 struct iovec iovec;
607 struct ucred *ucred;
608 union {
609 struct cmsghdr cmsghdr;
610 uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
611 } control;
612 ssize_t n;
613 int k;
614 usec_t t;
615
616 t = now(CLOCK_MONOTONIC);
617
7dcda352 618 if (until > 0 && until <= t) {
7f4e0805
LP
619 r = -ETIME;
620 goto finish;
621 }
622
981e4cd3
LP
623 k = poll(pollfd, _FD_MAX, until > 0 ? (int) ((until-t)/USEC_PER_MSEC) : -1);
624 if (k < 0) {
7f4e0805
LP
625 if (errno == EINTR)
626 continue;
627
00843602 628 r = -errno;
7f4e0805
LP
629 goto finish;
630 }
631
632 if (k <= 0) {
7f4e0805
LP
633 r = -ETIME;
634 goto finish;
635 }
636
21bc923a
LP
637 if (pollfd[FD_SIGNAL].revents & POLLIN) {
638 r = -EINTR;
639 goto finish;
640 }
7f4e0805
LP
641
642 if (pollfd[FD_SOCKET].revents != POLLIN) {
7f4e0805
LP
643 r = -EIO;
644 goto finish;
645 }
646
647 zero(iovec);
648 iovec.iov_base = passphrase;
21bc923a 649 iovec.iov_len = sizeof(passphrase);
7f4e0805
LP
650
651 zero(control);
652 zero(msghdr);
653 msghdr.msg_iov = &iovec;
654 msghdr.msg_iovlen = 1;
655 msghdr.msg_control = &control;
656 msghdr.msg_controllen = sizeof(control);
657
981e4cd3
LP
658 n = recvmsg(socket_fd, &msghdr, 0);
659 if (n < 0) {
3742095b 660 if (IN_SET(errno, EAGAIN, EINTR))
7f4e0805
LP
661 continue;
662
00843602 663 r = -errno;
7f4e0805
LP
664 goto finish;
665 }
666
1c8da044
LP
667 cmsg_close_all(&msghdr);
668
7f4e0805 669 if (n <= 0) {
00843602 670 log_debug("Message too short");
7f4e0805
LP
671 continue;
672 }
673
674 if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
675 control.cmsghdr.cmsg_level != SOL_SOCKET ||
676 control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
677 control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
00843602 678 log_debug("Received message without credentials. Ignoring.");
7f4e0805
LP
679 continue;
680 }
681
682 ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
683 if (ucred->uid != 0) {
00843602 684 log_debug("Got request from unprivileged user. Ignoring.");
7f4e0805
LP
685 continue;
686 }
687
688 if (passphrase[0] == '+') {
e287086b 689 /* An empty message refers to the empty password */
8254a475
LP
690 if (n == 1)
691 l = strv_new("", NULL);
692 else
693 l = strv_parse_nulstr(passphrase+1, n-1);
2d26d8e0 694 explicit_bzero(passphrase, n);
8254a475 695 if (!l) {
7f4e0805
LP
696 r = -ENOMEM;
697 goto finish;
698 }
699
58629001 700 if (strv_isempty(l)) {
e287086b 701 l = strv_free(l);
00843602 702 log_debug("Invalid packet");
21bc923a
LP
703 continue;
704 }
705
e287086b
LP
706 break;
707 }
21bc923a 708
e287086b 709 if (passphrase[0] == '-') {
7f4e0805
LP
710 r = -ECANCELED;
711 goto finish;
7f4e0805
LP
712 }
713
e287086b 714 log_debug("Invalid packet");
7f4e0805
LP
715 }
716
e287086b
LP
717 if (keyname)
718 (void) add_to_keyring_and_log(keyname, flags, l);
719
ae2a15bc 720 *ret = TAKE_PTR(l);
7f4e0805
LP
721 r = 0;
722
723finish:
981e4cd3 724 if (socket_name)
00843602 725 (void) unlink(socket_name);
7f4e0805 726
00843602 727 (void) unlink(temp);
7f4e0805
LP
728
729 if (final[0])
00843602 730 (void) unlink(final);
7f4e0805 731
f9b72cd8 732 assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
7f4e0805
LP
733 return r;
734}
260ab287 735
00843602
LP
736int ask_password_auto(
737 const char *message,
738 const char *icon,
739 const char *id,
e287086b 740 const char *keyname,
00843602 741 usec_t until,
e287086b
LP
742 AskPasswordFlags flags,
743 char ***ret) {
00843602
LP
744
745 int r;
746
e287086b 747 assert(ret);
21bc923a 748
e287086b
LP
749 if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname) {
750 r = ask_password_keyring(keyname, flags, ret);
751 if (r != -ENOKEY)
752 return r;
753 }
754
755 if (!(flags & ASK_PASSWORD_NO_TTY) && isatty(STDIN_FILENO)) {
21bc923a
LP
756 char *s = NULL, **l = NULL;
757
daa55720 758 r = ask_password_tty(-1, message, keyname, until, flags, NULL, &s);
981e4cd3 759 if (r < 0)
21bc923a
LP
760 return r;
761
1602b008
LP
762 r = strv_push(&l, s);
763 if (r < 0) {
764 string_erase(s);
765 free(s);
00843602 766 return -ENOMEM;
1602b008 767 }
21bc923a 768
e287086b 769 *ret = l;
00843602
LP
770 return 0;
771 }
772
e287086b
LP
773 if (!(flags & ASK_PASSWORD_NO_AGENT))
774 return ask_password_agent(message, icon, id, keyname, until, flags, ret);
775
776 return -EUNATCH;
260ab287 777}