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/>.
34 #include <sys/inotify.h>
35 #include <sys/signalfd.h>
36 #include <sys/socket.h>
44 #include "alloc-util.h"
45 #include "ask-password-api.h"
48 #include "formats-util.h"
54 #include "random-util.h"
55 #include "signal-util.h"
56 #include "socket-util.h"
57 #include "string-util.h"
59 #include "terminal-util.h"
60 #include "time-util.h"
61 #include "umask-util.h"
65 #define KEYRING_TIMEOUT_USEC ((5 * USEC_PER_MINUTE) / 2)
67 static int lookup_key(const char *keyname
, key_serial_t
*ret
) {
73 serial
= request_key("user", keyname
, NULL
, 0);
75 return negative_errno();
81 static int retrieve_key(key_serial_t serial
, char ***ret
) {
82 _cleanup_free_
char *p
= NULL
;
93 n
= keyctl(KEYCTL_READ
, (unsigned long) serial
, (unsigned long) p
, (unsigned long) m
, 0);
105 l
= strv_parse_nulstr(p
, n
);
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
;
125 if (!(flags
& ASK_PASSWORD_PUSH_CACHE
))
128 r
= lookup_key(keyname
, &serial
);
130 r
= retrieve_key(serial
, &l
);
133 } else if (r
!= -ENOKEY
)
136 r
= strv_extend_strv(&l
, passwords
, true);
140 r
= strv_make_nulstr(l
, &p
, &n
);
144 /* Truncate trailing NUL */
148 serial
= add_key("user", keyname
, p
, n
-1, KEY_SPEC_USER_KEYRING
);
153 if (keyctl(KEYCTL_SET_TIMEOUT
,
154 (unsigned long) serial
,
155 (unsigned long) DIV_ROUND_UP(KEYRING_TIMEOUT_USEC
, USEC_PER_SEC
), 0, 0) < 0)
156 log_debug_errno(errno
, "Failed to adjust timeout: %m");
158 log_debug("Added key to keyring as %" PRIi32
".", serial
);
163 static int add_to_keyring_and_log(const char *keyname
, AskPasswordFlags flags
, char **passwords
) {
169 r
= add_to_keyring(keyname
, flags
, passwords
);
171 return log_debug_errno(r
, "Failed to add password to keyring: %m");
176 int ask_password_keyring(const char *keyname
, AskPasswordFlags flags
, char ***ret
) {
184 if (!(flags
& ASK_PASSWORD_ACCEPT_CACHED
))
187 r
= lookup_key(keyname
, &serial
);
188 if (r
== -ENOSYS
) /* when retrieving the distinction doesn't matter */
193 return retrieve_key(serial
, ret
);
196 static void backspace_chars(int ttyfd
, size_t p
) {
204 loop_write(ttyfd
, "\b \b", 3, false);
208 int ask_password_tty(
212 AskPasswordFlags flags
,
213 const char *flag_file
,
216 struct termios old_termios
, new_termios
;
217 char passphrase
[LINE_MAX
+ 1] = {}, *x
;
218 size_t p
= 0, codepoint
= 0;
220 _cleanup_close_
int ttyfd
= -1, notify
= -1;
221 struct pollfd pollfd
[2];
222 bool reset_tty
= false;
231 if (flags
& ASK_PASSWORD_NO_TTY
)
235 message
= "Password:";
238 notify
= inotify_init1(IN_CLOEXEC
|IN_NONBLOCK
);
244 if (inotify_add_watch(notify
, flag_file
, IN_ATTRIB
/* for the link count */) < 0) {
250 ttyfd
= open("/dev/tty", O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
253 if (tcgetattr(ttyfd
, &old_termios
) < 0) {
258 loop_write(ttyfd
, ANSI_HIGHLIGHT
, strlen(ANSI_HIGHLIGHT
), false);
259 loop_write(ttyfd
, message
, strlen(message
), false);
260 loop_write(ttyfd
, " ", 1, false);
261 loop_write(ttyfd
, ANSI_NORMAL
, strlen(ANSI_NORMAL
), false);
263 new_termios
= old_termios
;
264 new_termios
.c_lflag
&= ~(ICANON
|ECHO
);
265 new_termios
.c_cc
[VMIN
] = 1;
266 new_termios
.c_cc
[VTIME
] = 0;
268 if (tcsetattr(ttyfd
, TCSADRAIN
, &new_termios
) < 0) {
277 pollfd
[POLL_TTY
].fd
= ttyfd
>= 0 ? ttyfd
: STDIN_FILENO
;
278 pollfd
[POLL_TTY
].events
= POLLIN
;
279 pollfd
[POLL_INOTIFY
].fd
= notify
;
280 pollfd
[POLL_INOTIFY
].events
= POLLIN
;
284 int sleep_for
= -1, k
;
290 y
= now(CLOCK_MONOTONIC
);
297 sleep_for
= (int) ((until
- y
) / USEC_PER_MSEC
);
301 if (access(flag_file
, F_OK
) < 0) {
306 k
= poll(pollfd
, notify
>= 0 ? 2 : 1, sleep_for
);
318 if (notify
>= 0 && pollfd
[POLL_INOTIFY
].revents
!= 0)
321 if (pollfd
[POLL_TTY
].revents
== 0)
324 n
= read(ttyfd
>= 0 ? ttyfd
: STDIN_FILENO
, &c
, 1);
326 if (errno
== EINTR
|| errno
== EAGAIN
)
337 else if (c
== 21) { /* C-u */
339 if (!(flags
& ASK_PASSWORD_SILENT
))
340 backspace_chars(ttyfd
, p
);
343 } else if (c
== '\b' || c
== 127) {
347 if (!(flags
& ASK_PASSWORD_SILENT
))
348 backspace_chars(ttyfd
, 1);
351 } else if (!dirty
&& !(flags
& ASK_PASSWORD_SILENT
)) {
353 flags
|= ASK_PASSWORD_SILENT
;
355 /* There are two ways to enter silent
356 * mode. Either by pressing backspace
357 * as first key (and only as first
360 loop_write(ttyfd
, "(no echo) ", 10, false);
362 } else if (ttyfd
>= 0)
363 loop_write(ttyfd
, "\a", 1, false);
365 } else if (c
== '\t' && !(flags
& ASK_PASSWORD_SILENT
)) {
367 backspace_chars(ttyfd
, p
);
368 flags
|= ASK_PASSWORD_SILENT
;
370 /* ... or by pressing TAB at any time. */
373 loop_write(ttyfd
, "(no echo) ", 10, false);
375 if (p
>= sizeof(passphrase
)-1) {
376 loop_write(ttyfd
, "\a", 1, false);
382 if (!(flags
& ASK_PASSWORD_SILENT
) && ttyfd
>= 0) {
383 n
= utf8_encoded_valid_unichar(passphrase
+ codepoint
);
386 loop_write(ttyfd
, (flags
& ASK_PASSWORD_ECHO
) ? &c
: "*", 1, false);
396 x
= strndup(passphrase
, p
);
397 memory_erase(passphrase
, p
);
404 (void) add_to_keyring_and_log(keyname
, flags
, STRV_MAKE(x
));
410 if (ttyfd
>= 0 && reset_tty
) {
411 loop_write(ttyfd
, "\n", 1, false);
412 tcsetattr(ttyfd
, TCSADRAIN
, &old_termios
);
418 static int create_socket(char **name
) {
419 union sockaddr_union sa
= {
420 .un
.sun_family
= AF_UNIX
,
422 _cleanup_close_
int fd
= -1;
423 static const int one
= 1;
429 fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
433 snprintf(sa
.un
.sun_path
, sizeof(sa
.un
.sun_path
)-1, "/run/systemd/ask-password/sck.%" PRIx64
, random_u64());
435 RUN_WITH_UMASK(0177) {
436 if (bind(fd
, &sa
.sa
, offsetof(struct sockaddr_un
, sun_path
) + strlen(sa
.un
.sun_path
)) < 0)
440 if (setsockopt(fd
, SOL_SOCKET
, SO_PASSCRED
, &one
, sizeof(one
)) < 0)
443 c
= strdup(sa
.un
.sun_path
);
455 int ask_password_agent(
461 AskPasswordFlags flags
,
470 _cleanup_close_
int socket_fd
= -1, signal_fd
= -1, fd
= -1;
471 char temp
[] = "/run/systemd/ask-password/tmp.XXXXXX";
472 char final
[sizeof(temp
)] = "";
473 _cleanup_free_
char *socket_name
= NULL
;
474 _cleanup_strv_free_
char **l
= NULL
;
475 _cleanup_fclose_
FILE *f
= NULL
;
476 struct pollfd pollfd
[_FD_MAX
];
477 sigset_t mask
, oldmask
;
482 if (flags
& ASK_PASSWORD_NO_AGENT
)
485 assert_se(sigemptyset(&mask
) >= 0);
486 assert_se(sigset_add_many(&mask
, SIGINT
, SIGTERM
, -1) >= 0);
487 assert_se(sigprocmask(SIG_BLOCK
, &mask
, &oldmask
) >= 0);
489 (void) mkdir_p_label("/run/systemd/ask-password", 0755);
491 fd
= mkostemp_safe(temp
, O_WRONLY
|O_CLOEXEC
);
497 (void) fchmod(fd
, 0644);
507 signal_fd
= signalfd(-1, &mask
, SFD_NONBLOCK
|SFD_CLOEXEC
);
513 socket_fd
= create_socket(&socket_name
);
525 "NotAfter="USEC_FMT
"\n",
528 (flags
& ASK_PASSWORD_ACCEPT_CACHED
) ? 1 : 0,
529 (flags
& ASK_PASSWORD_ECHO
) ? 1 : 0,
533 fprintf(f
, "Message=%s\n", message
);
536 fprintf(f
, "Icon=%s\n", icon
);
539 fprintf(f
, "Id=%s\n", id
);
541 r
= fflush_and_check(f
);
545 memcpy(final
, temp
, sizeof(temp
));
547 final
[sizeof(final
)-11] = 'a';
548 final
[sizeof(final
)-10] = 's';
549 final
[sizeof(final
)-9] = 'k';
551 if (rename(temp
, final
) < 0) {
557 pollfd
[FD_SOCKET
].fd
= socket_fd
;
558 pollfd
[FD_SOCKET
].events
= POLLIN
;
559 pollfd
[FD_SIGNAL
].fd
= signal_fd
;
560 pollfd
[FD_SIGNAL
].events
= POLLIN
;
563 char passphrase
[LINE_MAX
+1];
564 struct msghdr msghdr
;
568 struct cmsghdr cmsghdr
;
569 uint8_t buf
[CMSG_SPACE(sizeof(struct ucred
))];
575 t
= now(CLOCK_MONOTONIC
);
577 if (until
> 0 && until
<= t
) {
582 k
= poll(pollfd
, _FD_MAX
, until
> 0 ? (int) ((until
-t
)/USEC_PER_MSEC
) : -1);
596 if (pollfd
[FD_SIGNAL
].revents
& POLLIN
) {
601 if (pollfd
[FD_SOCKET
].revents
!= POLLIN
) {
607 iovec
.iov_base
= passphrase
;
608 iovec
.iov_len
= sizeof(passphrase
);
612 msghdr
.msg_iov
= &iovec
;
613 msghdr
.msg_iovlen
= 1;
614 msghdr
.msg_control
= &control
;
615 msghdr
.msg_controllen
= sizeof(control
);
617 n
= recvmsg(socket_fd
, &msghdr
, 0);
619 if (errno
== EAGAIN
||
627 cmsg_close_all(&msghdr
);
630 log_debug("Message too short");
634 if (msghdr
.msg_controllen
< CMSG_LEN(sizeof(struct ucred
)) ||
635 control
.cmsghdr
.cmsg_level
!= SOL_SOCKET
||
636 control
.cmsghdr
.cmsg_type
!= SCM_CREDENTIALS
||
637 control
.cmsghdr
.cmsg_len
!= CMSG_LEN(sizeof(struct ucred
))) {
638 log_debug("Received message without credentials. Ignoring.");
642 ucred
= (struct ucred
*) CMSG_DATA(&control
.cmsghdr
);
643 if (ucred
->uid
!= 0) {
644 log_debug("Got request from unprivileged user. Ignoring.");
648 if (passphrase
[0] == '+') {
649 /* An empty message refers to the empty password */
651 l
= strv_new("", NULL
);
653 l
= strv_parse_nulstr(passphrase
+1, n
-1);
654 memory_erase(passphrase
, n
);
660 if (strv_length(l
) <= 0) {
662 log_debug("Invalid packet");
669 if (passphrase
[0] == '-') {
674 log_debug("Invalid packet");
678 (void) add_to_keyring_and_log(keyname
, flags
, l
);
686 (void) unlink(socket_name
);
691 (void) unlink(final
);
693 assert_se(sigprocmask(SIG_SETMASK
, &oldmask
, NULL
) == 0);
697 int ask_password_auto(
703 AskPasswordFlags flags
,
710 if ((flags
& ASK_PASSWORD_ACCEPT_CACHED
) && keyname
) {
711 r
= ask_password_keyring(keyname
, flags
, ret
);
716 if (!(flags
& ASK_PASSWORD_NO_TTY
) && isatty(STDIN_FILENO
)) {
717 char *s
= NULL
, **l
= NULL
;
719 r
= ask_password_tty(message
, keyname
, until
, flags
, NULL
, &s
);
723 r
= strv_push(&l
, s
);
734 if (!(flags
& ASK_PASSWORD_NO_AGENT
))
735 return ask_password_agent(message
, icon
, id
, keyname
, until
, flags
, ret
);