1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
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.
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.
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/>.
28 #include <sys/inotify.h>
29 #include <sys/signalfd.h>
30 #include <sys/socket.h>
35 #include "alloc-util.h"
36 #include "ask-password-api.h"
39 #include "formats-util.h"
43 #include "random-util.h"
44 #include "signal-util.h"
45 #include "socket-util.h"
46 #include "string-util.h"
48 #include "terminal-util.h"
49 #include "umask-util.h"
52 #define KEYRING_TIMEOUT_USEC ((5 * USEC_PER_MINUTE) / 2)
54 static int lookup_key(const char *keyname
, key_serial_t
*ret
) {
60 serial
= request_key("user", keyname
, NULL
, 0);
68 static int retrieve_key(key_serial_t serial
, char ***ret
) {
69 _cleanup_free_
char *p
= NULL
;
80 n
= keyctl(KEYCTL_READ
, (unsigned long) serial
, (unsigned long) p
, (unsigned long) m
, 0);
92 l
= strv_parse_nulstr(p
, n
);
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
;
112 if (!(flags
& ASK_PASSWORD_PUSH_CACHE
))
115 r
= lookup_key(keyname
, &serial
);
117 r
= retrieve_key(serial
, &l
);
120 } else if (r
!= -ENOKEY
)
123 r
= strv_extend_strv(&l
, passwords
, true);
127 r
= strv_make_nulstr(l
, &p
, &n
);
131 /* Truncate trailing NUL */
135 serial
= add_key("user", keyname
, p
, n
-1, KEY_SPEC_USER_KEYRING
);
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");
145 log_debug("Added key to keyring as %" PRIi32
".", serial
);
150 static int add_to_keyring_and_log(const char *keyname
, AskPasswordFlags flags
, char **passwords
) {
156 r
= add_to_keyring(keyname
, flags
, passwords
);
158 return log_debug_errno(r
, "Failed to add password to keyring: %m");
163 int ask_password_keyring(const char *keyname
, AskPasswordFlags flags
, char ***ret
) {
171 if (!(flags
& ASK_PASSWORD_ACCEPT_CACHED
))
174 r
= lookup_key(keyname
, &serial
);
175 if (r
== -ENOSYS
) /* when retrieving the distinction doesn't matter */
180 return retrieve_key(serial
, ret
);
183 static void backspace_chars(int ttyfd
, size_t p
) {
191 loop_write(ttyfd
, "\b \b", 3, false);
195 int ask_password_tty(
199 AskPasswordFlags flags
,
200 const char *flag_file
,
203 struct termios old_termios
, new_termios
;
204 char passphrase
[LINE_MAX
], *x
;
207 _cleanup_close_
int ttyfd
= -1, notify
= -1;
208 struct pollfd pollfd
[2];
209 bool reset_tty
= false;
218 if (flags
& ASK_PASSWORD_NO_TTY
)
222 message
= "Password:";
225 notify
= inotify_init1(IN_CLOEXEC
|IN_NONBLOCK
);
231 if (inotify_add_watch(notify
, flag_file
, IN_ATTRIB
/* for the link count */) < 0) {
237 ttyfd
= open("/dev/tty", O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
240 if (tcgetattr(ttyfd
, &old_termios
) < 0) {
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);
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;
255 if (tcsetattr(ttyfd
, TCSADRAIN
, &new_termios
) < 0) {
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
;
271 int sleep_for
= -1, k
;
277 y
= now(CLOCK_MONOTONIC
);
284 sleep_for
= (int) ((until
- y
) / USEC_PER_MSEC
);
288 if (access(flag_file
, F_OK
) < 0) {
293 k
= poll(pollfd
, notify
>= 0 ? 2 : 1, sleep_for
);
305 if (notify
>= 0 && pollfd
[POLL_INOTIFY
].revents
!= 0)
308 if (pollfd
[POLL_TTY
].revents
== 0)
311 n
= read(ttyfd
>= 0 ? ttyfd
: STDIN_FILENO
, &c
, 1);
313 if (errno
== EINTR
|| errno
== EAGAIN
)
324 else if (c
== 21) { /* C-u */
326 if (!(flags
& ASK_PASSWORD_SILENT
))
327 backspace_chars(ttyfd
, p
);
330 } else if (c
== '\b' || c
== 127) {
334 if (!(flags
& ASK_PASSWORD_SILENT
))
335 backspace_chars(ttyfd
, 1);
338 } else if (!dirty
&& !(flags
& ASK_PASSWORD_SILENT
)) {
340 flags
|= ASK_PASSWORD_SILENT
;
342 /* There are two ways to enter silent
343 * mode. Either by pressing backspace
344 * as first key (and only as first
347 loop_write(ttyfd
, "(no echo) ", 10, false);
349 } else if (ttyfd
>= 0)
350 loop_write(ttyfd
, "\a", 1, false);
352 } else if (c
== '\t' && !(flags
& ASK_PASSWORD_SILENT
)) {
354 backspace_chars(ttyfd
, p
);
355 flags
|= ASK_PASSWORD_SILENT
;
357 /* ... or by pressing TAB at any time. */
360 loop_write(ttyfd
, "(no echo) ", 10, false);
362 if (p
>= sizeof(passphrase
)-1) {
363 loop_write(ttyfd
, "\a", 1, false);
369 if (!(flags
& ASK_PASSWORD_SILENT
) && ttyfd
>= 0)
370 loop_write(ttyfd
, (flags
& ASK_PASSWORD_ECHO
) ? &c
: "*", 1, false);
378 x
= strndup(passphrase
, p
);
379 memory_erase(passphrase
, p
);
386 (void) add_to_keyring_and_log(keyname
, flags
, STRV_MAKE(x
));
392 if (ttyfd
>= 0 && reset_tty
) {
393 loop_write(ttyfd
, "\n", 1, false);
394 tcsetattr(ttyfd
, TCSADRAIN
, &old_termios
);
400 static int create_socket(char **name
) {
401 union sockaddr_union sa
= {
402 .un
.sun_family
= AF_UNIX
,
404 _cleanup_close_
int fd
= -1;
405 static const int one
= 1;
411 fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
415 snprintf(sa
.un
.sun_path
, sizeof(sa
.un
.sun_path
)-1, "/run/systemd/ask-password/sck.%" PRIx64
, random_u64());
417 RUN_WITH_UMASK(0177) {
418 if (bind(fd
, &sa
.sa
, offsetof(struct sockaddr_un
, sun_path
) + strlen(sa
.un
.sun_path
)) < 0)
422 if (setsockopt(fd
, SOL_SOCKET
, SO_PASSCRED
, &one
, sizeof(one
)) < 0)
425 c
= strdup(sa
.un
.sun_path
);
437 int ask_password_agent(
443 AskPasswordFlags flags
,
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
;
464 if (flags
& ASK_PASSWORD_NO_AGENT
)
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);
471 (void) mkdir_p_label("/run/systemd/ask-password", 0755);
473 fd
= mkostemp_safe(temp
, O_WRONLY
|O_CLOEXEC
);
479 (void) fchmod(fd
, 0644);
489 signal_fd
= signalfd(-1, &mask
, SFD_NONBLOCK
|SFD_CLOEXEC
);
495 socket_fd
= create_socket(&socket_name
);
507 "NotAfter="USEC_FMT
"\n",
510 (flags
& ASK_PASSWORD_ACCEPT_CACHED
) ? 1 : 0,
511 (flags
& ASK_PASSWORD_ECHO
) ? 1 : 0,
515 fprintf(f
, "Message=%s\n", message
);
518 fprintf(f
, "Icon=%s\n", icon
);
521 fprintf(f
, "Id=%s\n", id
);
523 r
= fflush_and_check(f
);
527 memcpy(final
, temp
, sizeof(temp
));
529 final
[sizeof(final
)-11] = 'a';
530 final
[sizeof(final
)-10] = 's';
531 final
[sizeof(final
)-9] = 'k';
533 if (rename(temp
, final
) < 0) {
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
;
545 char passphrase
[LINE_MAX
+1];
546 struct msghdr msghdr
;
550 struct cmsghdr cmsghdr
;
551 uint8_t buf
[CMSG_SPACE(sizeof(struct ucred
))];
557 t
= now(CLOCK_MONOTONIC
);
559 if (until
> 0 && until
<= t
) {
564 k
= poll(pollfd
, _FD_MAX
, until
> 0 ? (int) ((until
-t
)/USEC_PER_MSEC
) : -1);
578 if (pollfd
[FD_SIGNAL
].revents
& POLLIN
) {
583 if (pollfd
[FD_SOCKET
].revents
!= POLLIN
) {
589 iovec
.iov_base
= passphrase
;
590 iovec
.iov_len
= sizeof(passphrase
);
594 msghdr
.msg_iov
= &iovec
;
595 msghdr
.msg_iovlen
= 1;
596 msghdr
.msg_control
= &control
;
597 msghdr
.msg_controllen
= sizeof(control
);
599 n
= recvmsg(socket_fd
, &msghdr
, 0);
601 if (errno
== EAGAIN
||
609 cmsg_close_all(&msghdr
);
612 log_debug("Message too short");
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.");
624 ucred
= (struct ucred
*) CMSG_DATA(&control
.cmsghdr
);
625 if (ucred
->uid
!= 0) {
626 log_debug("Got request from unprivileged user. Ignoring.");
630 if (passphrase
[0] == '+') {
631 /* An empty message refers to the empty password */
633 l
= strv_new("", NULL
);
635 l
= strv_parse_nulstr(passphrase
+1, n
-1);
636 memory_erase(passphrase
, n
);
642 if (strv_length(l
) <= 0) {
644 log_debug("Invalid packet");
651 if (passphrase
[0] == '-') {
656 log_debug("Invalid packet");
660 (void) add_to_keyring_and_log(keyname
, flags
, l
);
668 (void) unlink(socket_name
);
673 (void) unlink(final
);
675 assert_se(sigprocmask(SIG_SETMASK
, &oldmask
, NULL
) == 0);
679 int ask_password_auto(
685 AskPasswordFlags flags
,
692 if ((flags
& ASK_PASSWORD_ACCEPT_CACHED
) && keyname
) {
693 r
= ask_password_keyring(keyname
, flags
, ret
);
698 if (!(flags
& ASK_PASSWORD_NO_TTY
) && isatty(STDIN_FILENO
)) {
699 char *s
= NULL
, **l
= NULL
;
701 r
= ask_password_tty(message
, keyname
, until
, flags
, NULL
, &s
);
705 r
= strv_push(&l
, s
);
716 if (!(flags
& ASK_PASSWORD_NO_AGENT
))
717 return ask_password_agent(message
, icon
, id
, keyname
, until
, flags
, ret
);