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