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