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 "ask-password-api.h"
38 #include "formats-util.h"
42 #include "random-util.h"
43 #include "signal-util.h"
44 #include "socket-util.h"
45 #include "string-util.h"
47 #include "terminal-util.h"
48 #include "umask-util.h"
51 #define KEYRING_TIMEOUT_USEC ((5 * USEC_PER_MINUTE) / 2)
53 static int lookup_key(const char *keyname
, key_serial_t
*ret
) {
59 serial
= request_key("user", keyname
, NULL
, 0);
67 static int retrieve_key(key_serial_t serial
, char ***ret
) {
68 _cleanup_free_
char *p
= NULL
;
79 n
= keyctl(KEYCTL_READ
, (unsigned long) serial
, (unsigned long) p
, (unsigned long) m
, 0);
91 l
= strv_parse_nulstr(p
, n
);
101 static int add_to_keyring(const char *keyname
, AskPasswordFlags flags
, char **passwords
) {
102 _cleanup_strv_free_erase_
char **l
= NULL
;
103 _cleanup_free_
char *p
= NULL
;
111 if (!(flags
& ASK_PASSWORD_PUSH_CACHE
))
114 r
= lookup_key(keyname
, &serial
);
116 r
= retrieve_key(serial
, &l
);
119 } else if (r
!= -ENOKEY
)
122 r
= strv_extend_strv(&l
, passwords
, true);
126 r
= strv_make_nulstr(l
, &p
, &n
);
130 /* Truncate trailing NUL */
134 serial
= add_key("user", keyname
, p
, n
-1, KEY_SPEC_USER_KEYRING
);
139 if (keyctl(KEYCTL_SET_TIMEOUT
,
140 (unsigned long) serial
,
141 (unsigned long) DIV_ROUND_UP(KEYRING_TIMEOUT_USEC
, USEC_PER_SEC
), 0, 0) < 0)
142 log_debug_errno(errno
, "Failed to adjust timeout: %m");
144 log_debug("Added key to keyring as %" PRIi32
".", serial
);
149 static int add_to_keyring_and_log(const char *keyname
, AskPasswordFlags flags
, char **passwords
) {
155 r
= add_to_keyring(keyname
, flags
, passwords
);
157 return log_debug_errno(r
, "Failed to add password to keyring: %m");
162 int ask_password_keyring(const char *keyname
, AskPasswordFlags flags
, char ***ret
) {
170 if (!(flags
& ASK_PASSWORD_ACCEPT_CACHED
))
173 r
= lookup_key(keyname
, &serial
);
174 if (r
== -ENOSYS
) /* when retrieving the distinction doesn't matter */
179 return retrieve_key(serial
, ret
);
182 static void backspace_chars(int ttyfd
, size_t p
) {
190 loop_write(ttyfd
, "\b \b", 3, false);
194 int ask_password_tty(
198 AskPasswordFlags flags
,
199 const char *flag_file
,
202 struct termios old_termios
, new_termios
;
203 char passphrase
[LINE_MAX
], *x
;
206 _cleanup_close_
int ttyfd
= -1, notify
= -1;
207 struct pollfd pollfd
[2];
208 bool reset_tty
= false;
217 if (flags
& ASK_PASSWORD_NO_TTY
)
221 message
= "Password:";
224 notify
= inotify_init1(IN_CLOEXEC
|IN_NONBLOCK
);
230 if (inotify_add_watch(notify
, flag_file
, IN_ATTRIB
/* for the link count */) < 0) {
236 ttyfd
= open("/dev/tty", O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
239 if (tcgetattr(ttyfd
, &old_termios
) < 0) {
244 loop_write(ttyfd
, ANSI_HIGHLIGHT
, strlen(ANSI_HIGHLIGHT
), false);
245 loop_write(ttyfd
, message
, strlen(message
), false);
246 loop_write(ttyfd
, " ", 1, false);
247 loop_write(ttyfd
, ANSI_NORMAL
, strlen(ANSI_NORMAL
), false);
249 new_termios
= old_termios
;
250 new_termios
.c_lflag
&= ~(ICANON
|ECHO
);
251 new_termios
.c_cc
[VMIN
] = 1;
252 new_termios
.c_cc
[VTIME
] = 0;
254 if (tcsetattr(ttyfd
, TCSADRAIN
, &new_termios
) < 0) {
263 pollfd
[POLL_TTY
].fd
= ttyfd
>= 0 ? ttyfd
: STDIN_FILENO
;
264 pollfd
[POLL_TTY
].events
= POLLIN
;
265 pollfd
[POLL_INOTIFY
].fd
= notify
;
266 pollfd
[POLL_INOTIFY
].events
= POLLIN
;
270 int sleep_for
= -1, k
;
276 y
= now(CLOCK_MONOTONIC
);
283 sleep_for
= (int) ((until
- y
) / USEC_PER_MSEC
);
287 if (access(flag_file
, F_OK
) < 0) {
292 k
= poll(pollfd
, notify
>= 0 ? 2 : 1, sleep_for
);
304 if (notify
>= 0 && pollfd
[POLL_INOTIFY
].revents
!= 0)
307 if (pollfd
[POLL_TTY
].revents
== 0)
310 n
= read(ttyfd
>= 0 ? ttyfd
: STDIN_FILENO
, &c
, 1);
312 if (errno
== EINTR
|| errno
== EAGAIN
)
323 else if (c
== 21) { /* C-u */
325 if (!(flags
& ASK_PASSWORD_SILENT
))
326 backspace_chars(ttyfd
, p
);
329 } else if (c
== '\b' || c
== 127) {
333 if (!(flags
& ASK_PASSWORD_SILENT
))
334 backspace_chars(ttyfd
, 1);
337 } else if (!dirty
&& !(flags
& ASK_PASSWORD_SILENT
)) {
339 flags
|= ASK_PASSWORD_SILENT
;
341 /* There are two ways to enter silent
342 * mode. Either by pressing backspace
343 * as first key (and only as first
346 loop_write(ttyfd
, "(no echo) ", 10, false);
348 } else if (ttyfd
>= 0)
349 loop_write(ttyfd
, "\a", 1, false);
351 } else if (c
== '\t' && !(flags
& ASK_PASSWORD_SILENT
)) {
353 backspace_chars(ttyfd
, p
);
354 flags
|= ASK_PASSWORD_SILENT
;
356 /* ... or by pressing TAB at any time. */
359 loop_write(ttyfd
, "(no echo) ", 10, false);
361 if (p
>= sizeof(passphrase
)-1) {
362 loop_write(ttyfd
, "\a", 1, false);
368 if (!(flags
& ASK_PASSWORD_SILENT
) && ttyfd
>= 0)
369 loop_write(ttyfd
, (flags
& ASK_PASSWORD_ECHO
) ? &c
: "*", 1, false);
377 x
= strndup(passphrase
, p
);
378 memory_erase(passphrase
, p
);
385 (void) add_to_keyring_and_log(keyname
, flags
, STRV_MAKE(x
));
391 if (ttyfd
>= 0 && reset_tty
) {
392 loop_write(ttyfd
, "\n", 1, false);
393 tcsetattr(ttyfd
, TCSADRAIN
, &old_termios
);
399 static int create_socket(char **name
) {
400 union sockaddr_union sa
= {
401 .un
.sun_family
= AF_UNIX
,
403 _cleanup_close_
int fd
= -1;
404 static const int one
= 1;
410 fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
414 snprintf(sa
.un
.sun_path
, sizeof(sa
.un
.sun_path
)-1, "/run/systemd/ask-password/sck.%" PRIx64
, random_u64());
416 RUN_WITH_UMASK(0177) {
417 if (bind(fd
, &sa
.sa
, offsetof(struct sockaddr_un
, sun_path
) + strlen(sa
.un
.sun_path
)) < 0)
421 if (setsockopt(fd
, SOL_SOCKET
, SO_PASSCRED
, &one
, sizeof(one
)) < 0)
424 c
= strdup(sa
.un
.sun_path
);
436 int ask_password_agent(
442 AskPasswordFlags flags
,
451 _cleanup_close_
int socket_fd
= -1, signal_fd
= -1, fd
= -1;
452 char temp
[] = "/run/systemd/ask-password/tmp.XXXXXX";
453 char final
[sizeof(temp
)] = "";
454 _cleanup_free_
char *socket_name
= NULL
;
455 _cleanup_strv_free_
char **l
= NULL
;
456 _cleanup_fclose_
FILE *f
= NULL
;
457 struct pollfd pollfd
[_FD_MAX
];
458 sigset_t mask
, oldmask
;
463 if (flags
& ASK_PASSWORD_NO_AGENT
)
466 assert_se(sigemptyset(&mask
) >= 0);
467 assert_se(sigset_add_many(&mask
, SIGINT
, SIGTERM
, -1) >= 0);
468 assert_se(sigprocmask(SIG_BLOCK
, &mask
, &oldmask
) >= 0);
470 (void) mkdir_p_label("/run/systemd/ask-password", 0755);
472 fd
= mkostemp_safe(temp
, O_WRONLY
|O_CLOEXEC
);
478 (void) fchmod(fd
, 0644);
488 signal_fd
= signalfd(-1, &mask
, SFD_NONBLOCK
|SFD_CLOEXEC
);
494 socket_fd
= create_socket(&socket_name
);
506 "NotAfter="USEC_FMT
"\n",
509 (flags
& ASK_PASSWORD_ACCEPT_CACHED
) ? 1 : 0,
510 (flags
& ASK_PASSWORD_ECHO
) ? 1 : 0,
514 fprintf(f
, "Message=%s\n", message
);
517 fprintf(f
, "Icon=%s\n", icon
);
520 fprintf(f
, "Id=%s\n", id
);
522 r
= fflush_and_check(f
);
526 memcpy(final
, temp
, sizeof(temp
));
528 final
[sizeof(final
)-11] = 'a';
529 final
[sizeof(final
)-10] = 's';
530 final
[sizeof(final
)-9] = 'k';
532 if (rename(temp
, final
) < 0) {
538 pollfd
[FD_SOCKET
].fd
= socket_fd
;
539 pollfd
[FD_SOCKET
].events
= POLLIN
;
540 pollfd
[FD_SIGNAL
].fd
= signal_fd
;
541 pollfd
[FD_SIGNAL
].events
= POLLIN
;
544 char passphrase
[LINE_MAX
+1];
545 struct msghdr msghdr
;
549 struct cmsghdr cmsghdr
;
550 uint8_t buf
[CMSG_SPACE(sizeof(struct ucred
))];
556 t
= now(CLOCK_MONOTONIC
);
558 if (until
> 0 && until
<= t
) {
563 k
= poll(pollfd
, _FD_MAX
, until
> 0 ? (int) ((until
-t
)/USEC_PER_MSEC
) : -1);
577 if (pollfd
[FD_SIGNAL
].revents
& POLLIN
) {
582 if (pollfd
[FD_SOCKET
].revents
!= POLLIN
) {
588 iovec
.iov_base
= passphrase
;
589 iovec
.iov_len
= sizeof(passphrase
);
593 msghdr
.msg_iov
= &iovec
;
594 msghdr
.msg_iovlen
= 1;
595 msghdr
.msg_control
= &control
;
596 msghdr
.msg_controllen
= sizeof(control
);
598 n
= recvmsg(socket_fd
, &msghdr
, 0);
600 if (errno
== EAGAIN
||
608 cmsg_close_all(&msghdr
);
611 log_debug("Message too short");
615 if (msghdr
.msg_controllen
< CMSG_LEN(sizeof(struct ucred
)) ||
616 control
.cmsghdr
.cmsg_level
!= SOL_SOCKET
||
617 control
.cmsghdr
.cmsg_type
!= SCM_CREDENTIALS
||
618 control
.cmsghdr
.cmsg_len
!= CMSG_LEN(sizeof(struct ucred
))) {
619 log_debug("Received message without credentials. Ignoring.");
623 ucred
= (struct ucred
*) CMSG_DATA(&control
.cmsghdr
);
624 if (ucred
->uid
!= 0) {
625 log_debug("Got request from unprivileged user. Ignoring.");
629 if (passphrase
[0] == '+') {
630 /* An empty message refers to the empty password */
632 l
= strv_new("", NULL
);
634 l
= strv_parse_nulstr(passphrase
+1, n
-1);
635 memory_erase(passphrase
, n
);
641 if (strv_length(l
) <= 0) {
643 log_debug("Invalid packet");
650 if (passphrase
[0] == '-') {
655 log_debug("Invalid packet");
659 (void) add_to_keyring_and_log(keyname
, flags
, l
);
667 (void) unlink(socket_name
);
672 (void) unlink(final
);
674 assert_se(sigprocmask(SIG_SETMASK
, &oldmask
, NULL
) == 0);
678 int ask_password_auto(
684 AskPasswordFlags flags
,
691 if ((flags
& ASK_PASSWORD_ACCEPT_CACHED
) && keyname
) {
692 r
= ask_password_keyring(keyname
, flags
, ret
);
697 if (!(flags
& ASK_PASSWORD_NO_TTY
) && isatty(STDIN_FILENO
)) {
698 char *s
= NULL
, **l
= NULL
;
700 r
= ask_password_tty(message
, keyname
, until
, flags
, NULL
, &s
);
704 r
= strv_push(&l
, s
);
715 if (!(flags
& ASK_PASSWORD_NO_AGENT
))
716 return ask_password_agent(message
, icon
, id
, keyname
, until
, flags
, ret
);