1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
33 #include <sys/inotify.h>
34 #include <sys/signalfd.h>
35 #include <sys/socket.h>
43 #include "alloc-util.h"
44 #include "ask-password-api.h"
47 #include "format-util.h"
53 #include "process-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);
100 explicit_bzero(p
, n
);
105 l
= strv_parse_nulstr(p
, n
);
109 explicit_bzero(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 serial
= add_key("user", keyname
, p
, n
, KEY_SPEC_USER_KEYRING
);
145 explicit_bzero(p
, n
);
149 if (keyctl(KEYCTL_SET_TIMEOUT
,
150 (unsigned long) serial
,
151 (unsigned long) DIV_ROUND_UP(KEYRING_TIMEOUT_USEC
, USEC_PER_SEC
), 0, 0) < 0)
152 log_debug_errno(errno
, "Failed to adjust timeout: %m");
154 log_debug("Added key to keyring as %" PRIi32
".", serial
);
159 static int add_to_keyring_and_log(const char *keyname
, AskPasswordFlags flags
, char **passwords
) {
165 r
= add_to_keyring(keyname
, flags
, passwords
);
167 return log_debug_errno(r
, "Failed to add password to keyring: %m");
172 int ask_password_keyring(const char *keyname
, AskPasswordFlags flags
, char ***ret
) {
180 if (!(flags
& ASK_PASSWORD_ACCEPT_CACHED
))
183 r
= lookup_key(keyname
, &serial
);
184 if (r
== -ENOSYS
) /* when retrieving the distinction doesn't matter */
189 return retrieve_key(serial
, ret
);
192 static void backspace_chars(int ttyfd
, size_t p
) {
200 loop_write(ttyfd
, "\b \b", 3, false);
204 static void backspace_string(int ttyfd
, const char *str
) {
212 /* Backspaces through enough characters to entirely undo printing of the specified string. */
214 m
= utf8_n_codepoints(str
);
215 if (m
== (size_t) -1)
216 m
= strlen(str
); /* Not a valid UTF-8 string? If so, let's backspace the number of bytes output. Most
217 * likely this happened because we are not in an UTF-8 locale, and in that case that
218 * is the correct thing to do. And even if it's not, terminals tend to stop
219 * backspacing at the leftmost column, hence backspacing too much should be mostly
222 backspace_chars(ttyfd
, m
);
225 int ask_password_tty(
230 AskPasswordFlags flags
,
231 const char *flag_file
,
240 bool reset_tty
= false, dirty
= false, use_color
= false;
241 _cleanup_close_
int cttyfd
= -1, notify
= -1;
242 struct termios old_termios
, new_termios
;
243 char passphrase
[LINE_MAX
+ 1] = {}, *x
;
244 struct pollfd pollfd
[_POLL_MAX
];
245 size_t p
= 0, codepoint
= 0;
250 if (flags
& ASK_PASSWORD_NO_TTY
)
254 message
= "Password:";
257 notify
= inotify_init1(IN_CLOEXEC
|IN_NONBLOCK
);
261 if (inotify_add_watch(notify
, flag_file
, IN_ATTRIB
/* for the link count */) < 0)
265 /* If the caller didn't specify a TTY, then use the controlling tty, if we can. */
267 ttyfd
= cttyfd
= open("/dev/tty", O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
270 if (tcgetattr(ttyfd
, &old_termios
) < 0)
273 if (flags
& ASK_PASSWORD_CONSOLE_COLOR
)
274 use_color
= dev_console_colors_enabled();
276 use_color
= colors_enabled();
279 (void) loop_write(ttyfd
, ANSI_HIGHLIGHT
, STRLEN(ANSI_HIGHLIGHT
), false);
281 (void) loop_write(ttyfd
, message
, strlen(message
), false);
282 (void) loop_write(ttyfd
, " ", 1, false);
285 (void) loop_write(ttyfd
, ANSI_NORMAL
, STRLEN(ANSI_NORMAL
), false);
287 new_termios
= old_termios
;
288 new_termios
.c_lflag
&= ~(ICANON
|ECHO
);
289 new_termios
.c_cc
[VMIN
] = 1;
290 new_termios
.c_cc
[VTIME
] = 0;
292 if (tcsetattr(ttyfd
, TCSADRAIN
, &new_termios
) < 0) {
300 pollfd
[POLL_TTY
] = (struct pollfd
) {
301 .fd
= ttyfd
>= 0 ? ttyfd
: STDIN_FILENO
,
304 pollfd
[POLL_INOTIFY
] = (struct pollfd
) {
310 int sleep_for
= -1, k
;
317 y
= now(CLOCK_MONOTONIC
);
324 sleep_for
= (int) DIV_ROUND_UP(until
- y
, USEC_PER_MSEC
);
328 if (access(flag_file
, F_OK
) < 0) {
333 k
= poll(pollfd
, notify
>= 0 ? 2 : 1, sleep_for
);
345 if (notify
>= 0 && pollfd
[POLL_INOTIFY
].revents
!= 0)
346 (void) flush_fd(notify
);
348 if (pollfd
[POLL_TTY
].revents
== 0)
351 n
= read(ttyfd
>= 0 ? ttyfd
: STDIN_FILENO
, &c
, 1);
353 if (IN_SET(errno
, EINTR
, EAGAIN
))
361 /* We treat EOF, newline and NUL byte all as valid end markers */
362 if (n
== 0 || c
== '\n' || c
== 0)
365 if (c
== 21) { /* C-u */
367 if (!(flags
& ASK_PASSWORD_SILENT
))
368 backspace_string(ttyfd
, passphrase
);
370 explicit_bzero(passphrase
, sizeof(passphrase
));
373 } else if (IN_SET(c
, '\b', 127)) {
378 if (!(flags
& ASK_PASSWORD_SILENT
))
379 backspace_chars(ttyfd
, 1);
381 /* Remove a full UTF-8 codepoint from the end. For that, figure out where the last one
387 z
= utf8_encoded_valid_unichar(passphrase
+ q
);
389 q
= (size_t) -1; /* Invalid UTF8! */
393 if (q
+ z
>= p
) /* This one brings us over the edge */
399 p
= codepoint
= q
== (size_t) -1 ? p
- 1 : q
;
400 explicit_bzero(passphrase
+ p
, sizeof(passphrase
) - p
);
402 } else if (!dirty
&& !(flags
& ASK_PASSWORD_SILENT
)) {
404 flags
|= ASK_PASSWORD_SILENT
;
406 /* There are two ways to enter silent mode. Either by pressing backspace as first key
407 * (and only as first key), or ... */
410 (void) loop_write(ttyfd
, "(no echo) ", 10, false);
412 } else if (ttyfd
>= 0)
413 (void) loop_write(ttyfd
, "\a", 1, false);
415 } else if (c
== '\t' && !(flags
& ASK_PASSWORD_SILENT
)) {
417 backspace_string(ttyfd
, passphrase
);
418 flags
|= ASK_PASSWORD_SILENT
;
420 /* ... or by pressing TAB at any time. */
423 (void) loop_write(ttyfd
, "(no echo) ", 10, false);
425 } else if (p
>= sizeof(passphrase
)-1) {
427 /* Reached the size limit */
429 (void) loop_write(ttyfd
, "\a", 1, false);
434 if (!(flags
& ASK_PASSWORD_SILENT
) && ttyfd
>= 0) {
435 /* Check if we got a complete UTF-8 character now. If so, let's output one '*'. */
436 n
= utf8_encoded_valid_unichar(passphrase
+ codepoint
);
439 (void) loop_write(ttyfd
, (flags
& ASK_PASSWORD_ECHO
) ? &c
: "*", 1, false);
446 /* Let's forget this char, just to not keep needlessly copies of key material around */
450 x
= strndup(passphrase
, p
);
451 explicit_bzero(passphrase
, sizeof(passphrase
));
458 (void) add_to_keyring_and_log(keyname
, flags
, STRV_MAKE(x
));
464 if (ttyfd
>= 0 && reset_tty
) {
465 (void) loop_write(ttyfd
, "\n", 1, false);
466 (void) tcsetattr(ttyfd
, TCSADRAIN
, &old_termios
);
472 static int create_socket(char **name
) {
473 union sockaddr_union sa
= {
474 .un
.sun_family
= AF_UNIX
,
476 _cleanup_close_
int fd
= -1;
477 static const int one
= 1;
483 fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
487 snprintf(sa
.un
.sun_path
, sizeof(sa
.un
.sun_path
)-1, "/run/systemd/ask-password/sck.%" PRIx64
, random_u64());
489 RUN_WITH_UMASK(0177) {
490 if (bind(fd
, &sa
.sa
, SOCKADDR_UN_LEN(sa
.un
)) < 0)
494 if (setsockopt(fd
, SOL_SOCKET
, SO_PASSCRED
, &one
, sizeof(one
)) < 0)
497 c
= strdup(sa
.un
.sun_path
);
509 int ask_password_agent(
515 AskPasswordFlags flags
,
524 _cleanup_close_
int socket_fd
= -1, signal_fd
= -1, fd
= -1;
525 char temp
[] = "/run/systemd/ask-password/tmp.XXXXXX";
526 char final
[sizeof(temp
)] = "";
527 _cleanup_free_
char *socket_name
= NULL
;
528 _cleanup_strv_free_
char **l
= NULL
;
529 _cleanup_fclose_
FILE *f
= NULL
;
530 struct pollfd pollfd
[_FD_MAX
];
531 sigset_t mask
, oldmask
;
536 if (flags
& ASK_PASSWORD_NO_AGENT
)
539 assert_se(sigemptyset(&mask
) >= 0);
540 assert_se(sigset_add_many(&mask
, SIGINT
, SIGTERM
, -1) >= 0);
541 assert_se(sigprocmask(SIG_BLOCK
, &mask
, &oldmask
) >= 0);
543 (void) mkdir_p_label("/run/systemd/ask-password", 0755);
545 fd
= mkostemp_safe(temp
);
551 (void) fchmod(fd
, 0644);
561 signal_fd
= signalfd(-1, &mask
, SFD_NONBLOCK
|SFD_CLOEXEC
);
567 socket_fd
= create_socket(&socket_name
);
579 "NotAfter="USEC_FMT
"\n",
582 (flags
& ASK_PASSWORD_ACCEPT_CACHED
) ? 1 : 0,
583 (flags
& ASK_PASSWORD_ECHO
) ? 1 : 0,
587 fprintf(f
, "Message=%s\n", message
);
590 fprintf(f
, "Icon=%s\n", icon
);
593 fprintf(f
, "Id=%s\n", id
);
595 r
= fflush_and_check(f
);
599 memcpy(final
, temp
, sizeof(temp
));
601 final
[sizeof(final
)-11] = 'a';
602 final
[sizeof(final
)-10] = 's';
603 final
[sizeof(final
)-9] = 'k';
605 if (rename(temp
, final
) < 0) {
611 pollfd
[FD_SOCKET
].fd
= socket_fd
;
612 pollfd
[FD_SOCKET
].events
= POLLIN
;
613 pollfd
[FD_SIGNAL
].fd
= signal_fd
;
614 pollfd
[FD_SIGNAL
].events
= POLLIN
;
617 char passphrase
[LINE_MAX
+1];
618 struct msghdr msghdr
;
622 struct cmsghdr cmsghdr
;
623 uint8_t buf
[CMSG_SPACE(sizeof(struct ucred
))];
629 t
= now(CLOCK_MONOTONIC
);
631 if (until
> 0 && until
<= t
) {
636 k
= poll(pollfd
, _FD_MAX
, until
> 0 ? (int) ((until
-t
)/USEC_PER_MSEC
) : -1);
650 if (pollfd
[FD_SIGNAL
].revents
& POLLIN
) {
655 if (pollfd
[FD_SOCKET
].revents
!= POLLIN
) {
661 iovec
.iov_base
= passphrase
;
662 iovec
.iov_len
= sizeof(passphrase
);
666 msghdr
.msg_iov
= &iovec
;
667 msghdr
.msg_iovlen
= 1;
668 msghdr
.msg_control
= &control
;
669 msghdr
.msg_controllen
= sizeof(control
);
671 n
= recvmsg(socket_fd
, &msghdr
, 0);
673 if (IN_SET(errno
, EAGAIN
, EINTR
))
680 cmsg_close_all(&msghdr
);
683 log_debug("Message too short");
687 if (msghdr
.msg_controllen
< CMSG_LEN(sizeof(struct ucred
)) ||
688 control
.cmsghdr
.cmsg_level
!= SOL_SOCKET
||
689 control
.cmsghdr
.cmsg_type
!= SCM_CREDENTIALS
||
690 control
.cmsghdr
.cmsg_len
!= CMSG_LEN(sizeof(struct ucred
))) {
691 log_debug("Received message without credentials. Ignoring.");
695 ucred
= (struct ucred
*) CMSG_DATA(&control
.cmsghdr
);
696 if (ucred
->uid
!= 0) {
697 log_debug("Got request from unprivileged user. Ignoring.");
701 if (passphrase
[0] == '+') {
702 /* An empty message refers to the empty password */
704 l
= strv_new("", NULL
);
706 l
= strv_parse_nulstr(passphrase
+1, n
-1);
707 explicit_bzero(passphrase
, n
);
713 if (strv_isempty(l
)) {
715 log_debug("Invalid packet");
722 if (passphrase
[0] == '-') {
727 log_debug("Invalid packet");
731 (void) add_to_keyring_and_log(keyname
, flags
, l
);
738 (void) unlink(socket_name
);
743 (void) unlink(final
);
745 assert_se(sigprocmask(SIG_SETMASK
, &oldmask
, NULL
) == 0);
749 int ask_password_auto(
755 AskPasswordFlags flags
,
762 if ((flags
& ASK_PASSWORD_ACCEPT_CACHED
) && keyname
) {
763 r
= ask_password_keyring(keyname
, flags
, ret
);
768 if (!(flags
& ASK_PASSWORD_NO_TTY
) && isatty(STDIN_FILENO
)) {
769 char *s
= NULL
, **l
= NULL
;
771 r
= ask_password_tty(-1, message
, keyname
, until
, flags
, NULL
, &s
);
775 r
= strv_push(&l
, s
);
786 if (!(flags
& ASK_PASSWORD_NO_AGENT
))
787 return ask_password_agent(message
, icon
, id
, keyname
, until
, flags
, ret
);