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