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 "formats-util.h"
38 #include "random-util.h"
39 #include "signal-util.h"
40 #include "socket-util.h"
42 #include "terminal-util.h"
44 #include "ask-password-api.h"
46 #define KEYRING_TIMEOUT_USEC ((5 * USEC_PER_MINUTE) / 2)
48 static int lookup_key(const char *keyname
, key_serial_t
*ret
) {
54 serial
= request_key("user", keyname
, NULL
, 0);
62 static int retrieve_key(key_serial_t serial
, char ***ret
) {
63 _cleanup_free_
char *p
= NULL
;
74 n
= keyctl(KEYCTL_READ
, (unsigned long) serial
, (unsigned long) p
, (unsigned long) m
, 0);
85 l
= strv_parse_nulstr(p
, n
);
93 static int add_to_keyring(const char *keyname
, AskPasswordFlags flags
, char **passwords
) {
94 _cleanup_strv_free_
char **l
= NULL
;
95 _cleanup_free_
char *p
= NULL
;
103 if (!(flags
& ASK_PASSWORD_PUSH_CACHE
))
106 r
= lookup_key(keyname
, &serial
);
108 r
= retrieve_key(serial
, &l
);
111 } else if (r
!= -ENOKEY
)
114 r
= strv_extend_strv(&l
, passwords
, true);
118 r
= strv_make_nulstr(l
, &p
, &n
);
122 /* Truncate trailing NUL */
126 serial
= add_key("user", keyname
, p
, n
-1, KEY_SPEC_USER_KEYRING
);
130 if (keyctl(KEYCTL_SET_TIMEOUT
,
131 (unsigned long) serial
,
132 (unsigned long) DIV_ROUND_UP(KEYRING_TIMEOUT_USEC
, USEC_PER_SEC
), 0, 0) < 0)
133 log_debug_errno(errno
, "Failed to adjust timeout: %m");
135 log_debug("Added key to keyring as %" PRIi32
".", serial
);
140 static int add_to_keyring_and_log(const char *keyname
, AskPasswordFlags flags
, char **passwords
) {
146 r
= add_to_keyring(keyname
, flags
, passwords
);
148 return log_debug_errno(r
, "Failed to add password to keyring: %m");
153 int ask_password_keyring(const char *keyname
, AskPasswordFlags flags
, char ***ret
) {
161 if (!(flags
& ASK_PASSWORD_ACCEPT_CACHED
))
164 r
= lookup_key(keyname
, &serial
);
165 if (r
== -ENOSYS
) /* when retrieving the distinction doesn't matter */
170 return retrieve_key(serial
, ret
);
173 static void backspace_chars(int ttyfd
, size_t p
) {
181 loop_write(ttyfd
, "\b \b", 3, false);
185 int ask_password_tty(
189 AskPasswordFlags flags
,
190 const char *flag_file
,
193 struct termios old_termios
, new_termios
;
194 char passphrase
[LINE_MAX
], *x
;
197 _cleanup_close_
int ttyfd
= -1, notify
= -1;
198 struct pollfd pollfd
[2];
199 bool reset_tty
= false;
208 if (flags
& ASK_PASSWORD_NO_TTY
)
212 message
= "Password:";
215 notify
= inotify_init1(IN_CLOEXEC
|IN_NONBLOCK
);
221 if (inotify_add_watch(notify
, flag_file
, IN_ATTRIB
/* for the link count */) < 0) {
227 ttyfd
= open("/dev/tty", O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
230 if (tcgetattr(ttyfd
, &old_termios
) < 0) {
235 loop_write(ttyfd
, ANSI_HIGHLIGHT
, strlen(ANSI_HIGHLIGHT
), false);
236 loop_write(ttyfd
, message
, strlen(message
), false);
237 loop_write(ttyfd
, " ", 1, false);
238 loop_write(ttyfd
, ANSI_NORMAL
, strlen(ANSI_NORMAL
), false);
240 new_termios
= old_termios
;
241 new_termios
.c_lflag
&= ~(ICANON
|ECHO
);
242 new_termios
.c_cc
[VMIN
] = 1;
243 new_termios
.c_cc
[VTIME
] = 0;
245 if (tcsetattr(ttyfd
, TCSADRAIN
, &new_termios
) < 0) {
254 pollfd
[POLL_TTY
].fd
= ttyfd
>= 0 ? ttyfd
: STDIN_FILENO
;
255 pollfd
[POLL_TTY
].events
= POLLIN
;
256 pollfd
[POLL_INOTIFY
].fd
= notify
;
257 pollfd
[POLL_INOTIFY
].events
= POLLIN
;
261 int sleep_for
= -1, k
;
267 y
= now(CLOCK_MONOTONIC
);
274 sleep_for
= (int) ((until
- y
) / USEC_PER_MSEC
);
278 if (access(flag_file
, F_OK
) < 0) {
283 k
= poll(pollfd
, notify
>= 0 ? 2 : 1, sleep_for
);
295 if (notify
>= 0 && pollfd
[POLL_INOTIFY
].revents
!= 0)
298 if (pollfd
[POLL_TTY
].revents
== 0)
301 n
= read(ttyfd
>= 0 ? ttyfd
: STDIN_FILENO
, &c
, 1);
303 if (errno
== EINTR
|| errno
== EAGAIN
)
314 else if (c
== 21) { /* C-u */
316 if (!(flags
& ASK_PASSWORD_SILENT
))
317 backspace_chars(ttyfd
, p
);
320 } else if (c
== '\b' || c
== 127) {
324 if (!(flags
& ASK_PASSWORD_SILENT
))
325 backspace_chars(ttyfd
, 1);
328 } else if (!dirty
&& !(flags
& ASK_PASSWORD_SILENT
)) {
330 flags
|= ASK_PASSWORD_SILENT
;
332 /* There are two ways to enter silent
333 * mode. Either by pressing backspace
334 * as first key (and only as first
337 loop_write(ttyfd
, "(no echo) ", 10, false);
339 } else if (ttyfd
>= 0)
340 loop_write(ttyfd
, "\a", 1, false);
342 } else if (c
== '\t' && !(flags
& ASK_PASSWORD_SILENT
)) {
344 backspace_chars(ttyfd
, p
);
345 flags
|= ASK_PASSWORD_SILENT
;
347 /* ... or by pressing TAB at any time. */
350 loop_write(ttyfd
, "(no echo) ", 10, false);
352 if (p
>= sizeof(passphrase
)-1) {
353 loop_write(ttyfd
, "\a", 1, false);
359 if (!(flags
& ASK_PASSWORD_SILENT
) && ttyfd
>= 0)
360 loop_write(ttyfd
, (flags
& ASK_PASSWORD_ECHO
) ? &c
: "*", 1, false);
366 x
= strndup(passphrase
, p
);
373 (void) add_to_keyring_and_log(keyname
, flags
, STRV_MAKE(x
));
379 if (ttyfd
>= 0 && reset_tty
) {
380 loop_write(ttyfd
, "\n", 1, false);
381 tcsetattr(ttyfd
, TCSADRAIN
, &old_termios
);
387 static int create_socket(char **name
) {
388 union sockaddr_union sa
= {
389 .un
.sun_family
= AF_UNIX
,
391 _cleanup_close_
int fd
= -1;
392 static const int one
= 1;
398 fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
402 snprintf(sa
.un
.sun_path
, sizeof(sa
.un
.sun_path
)-1, "/run/systemd/ask-password/sck.%" PRIx64
, random_u64());
404 RUN_WITH_UMASK(0177) {
405 if (bind(fd
, &sa
.sa
, offsetof(struct sockaddr_un
, sun_path
) + strlen(sa
.un
.sun_path
)) < 0)
409 if (setsockopt(fd
, SOL_SOCKET
, SO_PASSCRED
, &one
, sizeof(one
)) < 0)
412 c
= strdup(sa
.un
.sun_path
);
424 int ask_password_agent(
430 AskPasswordFlags flags
,
439 _cleanup_close_
int socket_fd
= -1, signal_fd
= -1, fd
= -1;
440 char temp
[] = "/run/systemd/ask-password/tmp.XXXXXX";
441 char final
[sizeof(temp
)] = "";
442 _cleanup_free_
char *socket_name
= NULL
;
443 _cleanup_strv_free_
char **l
= NULL
;
444 _cleanup_fclose_
FILE *f
= NULL
;
445 struct pollfd pollfd
[_FD_MAX
];
446 sigset_t mask
, oldmask
;
451 if (flags
& ASK_PASSWORD_NO_AGENT
)
454 assert_se(sigemptyset(&mask
) >= 0);
455 assert_se(sigset_add_many(&mask
, SIGINT
, SIGTERM
, -1) >= 0);
456 assert_se(sigprocmask(SIG_BLOCK
, &mask
, &oldmask
) >= 0);
458 (void) mkdir_p_label("/run/systemd/ask-password", 0755);
460 fd
= mkostemp_safe(temp
, O_WRONLY
|O_CLOEXEC
);
466 (void) fchmod(fd
, 0644);
476 signal_fd
= signalfd(-1, &mask
, SFD_NONBLOCK
|SFD_CLOEXEC
);
482 socket_fd
= create_socket(&socket_name
);
494 "NotAfter="USEC_FMT
"\n",
497 (flags
& ASK_PASSWORD_ACCEPT_CACHED
) ? 1 : 0,
498 (flags
& ASK_PASSWORD_ECHO
) ? 1 : 0,
502 fprintf(f
, "Message=%s\n", message
);
505 fprintf(f
, "Icon=%s\n", icon
);
508 fprintf(f
, "Id=%s\n", id
);
510 r
= fflush_and_check(f
);
514 memcpy(final
, temp
, sizeof(temp
));
516 final
[sizeof(final
)-11] = 'a';
517 final
[sizeof(final
)-10] = 's';
518 final
[sizeof(final
)-9] = 'k';
520 if (rename(temp
, final
) < 0) {
526 pollfd
[FD_SOCKET
].fd
= socket_fd
;
527 pollfd
[FD_SOCKET
].events
= POLLIN
;
528 pollfd
[FD_SIGNAL
].fd
= signal_fd
;
529 pollfd
[FD_SIGNAL
].events
= POLLIN
;
532 char passphrase
[LINE_MAX
+1];
533 struct msghdr msghdr
;
537 struct cmsghdr cmsghdr
;
538 uint8_t buf
[CMSG_SPACE(sizeof(struct ucred
))];
544 t
= now(CLOCK_MONOTONIC
);
546 if (until
> 0 && until
<= t
) {
551 k
= poll(pollfd
, _FD_MAX
, until
> 0 ? (int) ((until
-t
)/USEC_PER_MSEC
) : -1);
565 if (pollfd
[FD_SIGNAL
].revents
& POLLIN
) {
570 if (pollfd
[FD_SOCKET
].revents
!= POLLIN
) {
576 iovec
.iov_base
= passphrase
;
577 iovec
.iov_len
= sizeof(passphrase
);
581 msghdr
.msg_iov
= &iovec
;
582 msghdr
.msg_iovlen
= 1;
583 msghdr
.msg_control
= &control
;
584 msghdr
.msg_controllen
= sizeof(control
);
586 n
= recvmsg(socket_fd
, &msghdr
, 0);
588 if (errno
== EAGAIN
||
596 cmsg_close_all(&msghdr
);
599 log_debug("Message too short");
603 if (msghdr
.msg_controllen
< CMSG_LEN(sizeof(struct ucred
)) ||
604 control
.cmsghdr
.cmsg_level
!= SOL_SOCKET
||
605 control
.cmsghdr
.cmsg_type
!= SCM_CREDENTIALS
||
606 control
.cmsghdr
.cmsg_len
!= CMSG_LEN(sizeof(struct ucred
))) {
607 log_debug("Received message without credentials. Ignoring.");
611 ucred
= (struct ucred
*) CMSG_DATA(&control
.cmsghdr
);
612 if (ucred
->uid
!= 0) {
613 log_debug("Got request from unprivileged user. Ignoring.");
617 if (passphrase
[0] == '+') {
618 /* An empty message refers to the empty password */
620 l
= strv_new("", NULL
);
622 l
= strv_parse_nulstr(passphrase
+1, n
-1);
628 if (strv_length(l
) <= 0) {
630 log_debug("Invalid packet");
637 if (passphrase
[0] == '-') {
642 log_debug("Invalid packet");
646 (void) add_to_keyring_and_log(keyname
, flags
, l
);
654 (void) unlink(socket_name
);
659 (void) unlink(final
);
661 assert_se(sigprocmask(SIG_SETMASK
, &oldmask
, NULL
) == 0);
665 int ask_password_auto(
671 AskPasswordFlags flags
,
678 if ((flags
& ASK_PASSWORD_ACCEPT_CACHED
) && keyname
) {
679 r
= ask_password_keyring(keyname
, flags
, ret
);
684 if (!(flags
& ASK_PASSWORD_NO_TTY
) && isatty(STDIN_FILENO
)) {
685 char *s
= NULL
, **l
= NULL
;
687 r
= ask_password_tty(message
, keyname
, until
, flags
, NULL
, &s
);
691 r
= strv_consume(&l
, s
);
699 if (!(flags
& ASK_PASSWORD_NO_AGENT
))
700 return ask_password_agent(message
, icon
, id
, keyname
, until
, flags
, ret
);