2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
5 Copyright 2015 Werner Fink
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/>.
29 #include <sys/inotify.h>
30 #include <sys/prctl.h>
31 #include <sys/signalfd.h>
32 #include <sys/socket.h>
37 #include "alloc-util.h"
38 #include "ask-password-api.h"
39 #include "conf-parser.h"
41 #include "dirent-util.h"
42 #include "exit-status.h"
49 #include "path-util.h"
50 #include "process-util.h"
51 #include "signal-util.h"
52 #include "socket-util.h"
53 #include "string-util.h"
55 #include "terminal-util.h"
57 #include "utmp-wtmp.h"
64 } arg_action
= ACTION_QUERY
;
66 static bool arg_plymouth
= false;
67 static bool arg_console
= false;
68 static const char *arg_device
= NULL
;
70 static int ask_password_plymouth(
73 AskPasswordFlags flags
,
74 const char *flag_file
,
77 static const union sockaddr_union sa
= PLYMOUTH_SOCKET
;
78 _cleanup_close_
int fd
= -1, notify
= -1;
79 _cleanup_free_
char *packet
= NULL
;
82 struct pollfd pollfd
[2] = {};
83 char buffer
[LINE_MAX
];
93 notify
= inotify_init1(IN_CLOEXEC
|IN_NONBLOCK
);
97 r
= inotify_add_watch(notify
, flag_file
, IN_ATTRIB
); /* for the link count */
102 fd
= socket(AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
106 r
= connect(fd
, &sa
.sa
, SOCKADDR_UN_LEN(sa
.un
));
110 if (flags
& ASK_PASSWORD_ACCEPT_CACHED
) {
111 packet
= strdup("c");
113 } else if (asprintf(&packet
, "*\002%c%s%n", (int) (strlen(message
) + 1), message
, &n
) < 0)
118 r
= loop_write(fd
, packet
, n
+ 1, true);
122 pollfd
[POLL_SOCKET
].fd
= fd
;
123 pollfd
[POLL_SOCKET
].events
= POLLIN
;
124 pollfd
[POLL_INOTIFY
].fd
= notify
;
125 pollfd
[POLL_INOTIFY
].events
= POLLIN
;
128 int sleep_for
= -1, j
;
133 y
= now(CLOCK_MONOTONIC
);
140 sleep_for
= (int) ((until
- y
) / USEC_PER_MSEC
);
143 if (flag_file
&& access(flag_file
, F_OK
) < 0) {
148 j
= poll(pollfd
, notify
>= 0 ? 2 : 1, sleep_for
);
160 if (notify
>= 0 && pollfd
[POLL_INOTIFY
].revents
!= 0)
163 if (pollfd
[POLL_SOCKET
].revents
== 0)
166 k
= read(fd
, buffer
+ p
, sizeof(buffer
) - p
);
168 if (IN_SET(errno
, EINTR
, EAGAIN
))
183 if (buffer
[0] == 5) {
185 if (flags
& ASK_PASSWORD_ACCEPT_CACHED
) {
186 /* Hmm, first try with cached
187 * passwords failed, so let's retry
188 * with a normal password request */
189 packet
= mfree(packet
);
191 if (asprintf(&packet
, "*\002%c%s%n", (int) (strlen(message
) + 1), message
, &n
) < 0) {
196 r
= loop_write(fd
, packet
, n
+1, true);
200 flags
&= ~ASK_PASSWORD_ACCEPT_CACHED
;
205 /* No password, because UI not shown */
209 } else if (IN_SET(buffer
[0], 2, 9)) {
213 /* One or more answers */
217 memcpy(&size
, buffer
+1, sizeof(size
));
218 size
= le32toh(size
);
219 if (size
+ 5 > sizeof(buffer
)) {
227 l
= strv_parse_nulstr(buffer
+ 5, size
);
246 explicit_bzero(buffer
, sizeof(buffer
));
250 static int send_passwords(const char *socket_name
, char **passwords
) {
251 _cleanup_free_
char *packet
= NULL
;
252 _cleanup_close_
int socket_fd
= -1;
253 union sockaddr_union sa
= { .un
.sun_family
= AF_UNIX
};
254 size_t packet_length
= 1;
260 STRV_FOREACH(p
, passwords
)
261 packet_length
+= strlen(*p
) + 1;
263 packet
= new(char, packet_length
);
270 STRV_FOREACH(p
, passwords
)
271 d
= stpcpy(d
, *p
) + 1;
273 socket_fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0);
275 r
= log_debug_errno(errno
, "socket(): %m");
279 strncpy(sa
.un
.sun_path
, socket_name
, sizeof(sa
.un
.sun_path
));
281 r
= sendto(socket_fd
, packet
, packet_length
, MSG_NOSIGNAL
, &sa
.sa
, SOCKADDR_UN_LEN(sa
.un
));
283 r
= log_debug_errno(errno
, "sendto(): %m");
286 explicit_bzero(packet
, packet_length
);
290 static int parse_password(const char *filename
, char **wall
) {
291 _cleanup_free_
char *socket_name
= NULL
, *message
= NULL
;
292 bool accept_cached
= false, echo
= false;
293 uint64_t not_after
= 0;
296 const ConfigTableItem items
[] = {
297 { "Ask", "Socket", config_parse_string
, 0, &socket_name
},
298 { "Ask", "NotAfter", config_parse_uint64
, 0, ¬_after
},
299 { "Ask", "Message", config_parse_string
, 0, &message
},
300 { "Ask", "PID", config_parse_unsigned
, 0, &pid
},
301 { "Ask", "AcceptCached", config_parse_bool
, 0, &accept_cached
},
302 { "Ask", "Echo", config_parse_bool
, 0, &echo
},
310 r
= config_parse(NULL
, filename
, NULL
,
312 config_item_table_lookup
, items
,
313 CONFIG_PARSE_RELAXED
|CONFIG_PARSE_WARN
, NULL
);
318 log_error("Invalid password file %s", filename
);
322 if (not_after
> 0 && now(CLOCK_MONOTONIC
) > not_after
)
325 if (pid
> 0 && !pid_is_alive(pid
))
328 if (arg_action
== ACTION_LIST
)
329 printf("'%s' (PID %u)\n", message
, pid
);
331 else if (arg_action
== ACTION_WALL
) {
335 "%s%sPassword entry required for \'%s\' (PID %u).\r\n"
336 "Please enter password with the systemd-tty-ask-password-agent tool!",
338 *wall
? "\r\n\r\n" : "",
347 _cleanup_strv_free_erase_
char **passwords
= NULL
;
349 assert(IN_SET(arg_action
, ACTION_QUERY
, ACTION_WATCH
));
351 if (access(socket_name
, W_OK
) < 0) {
352 if (arg_action
== ACTION_QUERY
)
353 log_info("Not querying '%s' (PID %u), lacking privileges.", message
, pid
);
359 r
= ask_password_plymouth(message
, not_after
, accept_cached
? ASK_PASSWORD_ACCEPT_CACHED
: 0, filename
, &passwords
);
361 char *password
= NULL
;
365 const char *con
= arg_device
? arg_device
: "/dev/console";
367 tty_fd
= acquire_terminal(con
, false, false, false, USEC_INFINITY
);
369 return log_error_errno(tty_fd
, "Failed to acquire /dev/console: %m");
371 r
= reset_terminal_fd(tty_fd
, true);
373 log_warning_errno(r
, "Failed to reset terminal, ignoring: %m");
376 r
= ask_password_tty(message
, NULL
, not_after
, echo
? ASK_PASSWORD_ECHO
: 0, filename
, &password
);
379 tty_fd
= safe_close(tty_fd
);
384 r
= strv_push(&passwords
, password
);
387 string_free_erase(password
);
390 /* If the query went away, that's OK */
391 if (IN_SET(r
, -ETIME
, -ENOENT
))
395 return log_error_errno(r
, "Failed to query password: %m");
397 r
= send_passwords(socket_name
, passwords
);
399 return log_error_errno(r
, "Failed to send: %m");
405 static int wall_tty_block(void) {
406 _cleanup_free_
char *p
= NULL
;
410 r
= get_ctty_devnr(0, &devnr
);
411 if (r
== -ENXIO
) /* We have no controlling tty */
414 return log_error_errno(r
, "Failed to get controlling TTY: %m");
416 if (asprintf(&p
, "/run/systemd/ask-password-block/%u:%u", major(devnr
), minor(devnr
)) < 0)
419 mkdir_parents_label(p
, 0700);
422 fd
= open(p
, O_RDONLY
|O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
);
424 return log_debug_errno(errno
, "Failed to open %s: %m", p
);
429 static bool wall_tty_match(const char *path
, void *userdata
) {
430 _cleanup_free_
char *p
= NULL
;
431 _cleanup_close_
int fd
= -1;
434 if (!path_is_absolute(path
))
435 path
= strjoina("/dev/", path
);
437 if (lstat(path
, &st
) < 0) {
438 log_debug_errno(errno
, "Failed to stat %s: %m", path
);
442 if (!S_ISCHR(st
.st_mode
)) {
443 log_debug("%s is not a character device.", path
);
447 /* We use named pipes to ensure that wall messages suggesting
448 * password entry are not printed over password prompts
449 * already shown. We use the fact here that opening a pipe in
450 * non-blocking mode for write-only will succeed only if
451 * there's some writer behind it. Using pipes has the
452 * advantage that the block will automatically go away if the
455 if (asprintf(&p
, "/run/systemd/ask-password-block/%u:%u", major(st
.st_rdev
), minor(st
.st_rdev
)) < 0) {
460 fd
= open(p
, O_WRONLY
|O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
);
462 log_debug_errno(errno
, "Failed top open the wall pipe: %m");
466 /* What, we managed to open the pipe? Then this tty is filtered. */
470 static int show_passwords(void) {
471 _cleanup_closedir_
DIR *d
;
475 d
= opendir("/run/systemd/ask-password");
480 return log_error_errno(errno
, "Failed to open /run/systemd/ask-password: %m");
483 FOREACH_DIRENT_ALL(de
, d
, return log_error_errno(errno
, "Failed to read directory: %m")) {
484 _cleanup_free_
char *p
= NULL
, *wall
= NULL
;
487 /* We only support /dev on tmpfs, hence we can rely on
488 * d_type to be reliable */
490 if (de
->d_type
!= DT_REG
)
493 if (hidden_or_backup_file(de
->d_name
))
496 if (!startswith(de
->d_name
, "ask."))
499 p
= strappend("/run/systemd/ask-password/", de
->d_name
);
503 q
= parse_password(p
, &wall
);
508 (void) utmp_wall(wall
, NULL
, NULL
, wall_tty_match
, NULL
);
514 static int watch_passwords(void) {
521 _cleanup_close_
int notify
= -1, signal_fd
= -1, tty_block_fd
= -1;
522 struct pollfd pollfd
[_FD_MAX
] = {};
526 tty_block_fd
= wall_tty_block();
528 (void) mkdir_p_label("/run/systemd/ask-password", 0755);
530 notify
= inotify_init1(IN_CLOEXEC
);
532 return log_error_errno(errno
, "Failed to allocate directory watch: %m");
534 if (inotify_add_watch(notify
, "/run/systemd/ask-password", IN_CLOSE_WRITE
|IN_MOVED_TO
) < 0)
535 return log_error_errno(errno
, "Failed to add /run/systemd/ask-password to directory watch: %m");
537 assert_se(sigemptyset(&mask
) >= 0);
538 assert_se(sigset_add_many(&mask
, SIGINT
, SIGTERM
, -1) >= 0);
539 assert_se(sigprocmask(SIG_SETMASK
, &mask
, NULL
) >= 0);
541 signal_fd
= signalfd(-1, &mask
, SFD_NONBLOCK
|SFD_CLOEXEC
);
543 return log_error_errno(errno
, "Failed to allocate signal file descriptor: %m");
545 pollfd
[FD_INOTIFY
].fd
= notify
;
546 pollfd
[FD_INOTIFY
].events
= POLLIN
;
547 pollfd
[FD_SIGNAL
].fd
= signal_fd
;
548 pollfd
[FD_SIGNAL
].events
= POLLIN
;
551 r
= show_passwords();
553 log_error_errno(r
, "Failed to show password: %m");
555 if (poll(pollfd
, _FD_MAX
, -1) < 0) {
562 if (pollfd
[FD_INOTIFY
].revents
!= 0)
563 (void) flush_fd(notify
);
565 if (pollfd
[FD_SIGNAL
].revents
!= 0)
572 static void help(void) {
573 printf("%s [OPTIONS...]\n\n"
574 "Process system password requests.\n\n"
575 " -h --help Show this help\n"
576 " --version Show package version\n"
577 " --list Show pending password requests\n"
578 " --query Process pending password requests\n"
579 " --watch Continuously process password requests\n"
580 " --wall Continuously forward password requests to wall\n"
581 " --plymouth Ask question with Plymouth instead of on TTY\n"
582 " --console Ask question on /dev/console instead of current TTY\n",
583 program_invocation_short_name
);
586 static int parse_argv(int argc
, char *argv
[]) {
598 static const struct option options
[] = {
599 { "help", no_argument
, NULL
, 'h' },
600 { "version", no_argument
, NULL
, ARG_VERSION
},
601 { "list", no_argument
, NULL
, ARG_LIST
},
602 { "query", no_argument
, NULL
, ARG_QUERY
},
603 { "watch", no_argument
, NULL
, ARG_WATCH
},
604 { "wall", no_argument
, NULL
, ARG_WALL
},
605 { "plymouth", no_argument
, NULL
, ARG_PLYMOUTH
},
606 { "console", optional_argument
, NULL
, ARG_CONSOLE
},
615 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
627 arg_action
= ACTION_LIST
;
631 arg_action
= ACTION_QUERY
;
635 arg_action
= ACTION_WATCH
;
639 arg_action
= ACTION_WALL
;
650 if (isempty(optarg
)) {
651 log_error("Empty console device path is not allowed.");
663 assert_not_reached("Unhandled option");
666 if (optind
!= argc
) {
667 log_error("%s takes no arguments.", program_invocation_short_name
);
671 if (arg_plymouth
|| arg_console
) {
673 if (!IN_SET(arg_action
, ACTION_QUERY
, ACTION_WATCH
)) {
674 log_error("Options --query and --watch conflict.");
678 if (arg_plymouth
&& arg_console
) {
679 log_error("Options --plymouth and --console conflict.");
688 * To be able to ask on all terminal devices of /dev/console
689 * the devices are collected. If more than one device is found,
690 * then on each of the terminals a inquiring task is forked.
691 * Every task has its own session and its own controlling terminal.
692 * If one of the tasks does handle a password, the remaining tasks
693 * will be terminated.
695 static int ask_on_this_console(const char *tty
, pid_t
*pid
, int argc
, char *argv
[]) {
696 struct sigaction sig
= {
697 .sa_handler
= nop_signal_handler
,
698 .sa_flags
= SA_NOCLDSTOP
| SA_RESTART
,
701 assert_se(sigprocmask_many(SIG_UNBLOCK
, NULL
, SIGHUP
, SIGCHLD
, -1) >= 0);
703 assert_se(sigemptyset(&sig
.sa_mask
) >= 0);
704 assert_se(sigaction(SIGCHLD
, &sig
, NULL
) >= 0);
706 sig
.sa_handler
= SIG_DFL
;
707 assert_se(sigaction(SIGHUP
, &sig
, NULL
) >= 0);
711 return log_error_errno(errno
, "Failed to fork process: %m");
716 assert_se(prctl(PR_SET_PDEATHSIG
, SIGHUP
) >= 0);
719 reset_all_signal_handlers();
721 for (ac
= 0; ac
< argc
; ac
++) {
722 if (streq(argv
[ac
], "--console")) {
723 argv
[ac
] = strjoina("--console=", tty
, NULL
);
730 execv(SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH
, argv
);
736 static void terminate_agents(Set
*pids
) {
738 siginfo_t status
= {};
745 * Request termination of the remaining processes as those
746 * are not required anymore.
748 SET_FOREACH(p
, pids
, i
)
749 (void) kill(PTR_TO_PID(p
), SIGTERM
);
752 * Collect the processes which have go away.
754 assert_se(sigemptyset(&set
) >= 0);
755 assert_se(sigaddset(&set
, SIGCHLD
) >= 0);
756 timespec_store(&ts
, 50 * USEC_PER_MSEC
);
758 while (!set_isempty(pids
)) {
761 r
= waitid(P_ALL
, 0, &status
, WEXITED
|WNOHANG
);
762 if (r
< 0 && errno
== EINTR
)
765 if (r
== 0 && status
.si_pid
> 0) {
766 set_remove(pids
, PID_TO_PTR(status
.si_pid
));
770 signum
= sigtimedwait(&set
, NULL
, &ts
);
773 log_error_errno(errno
, "sigtimedwait() failed: %m");
776 assert(signum
== SIGCHLD
);
780 * Kill hanging processes.
782 SET_FOREACH(p
, pids
, i
) {
783 log_warning("Failed to terminate child %d, killing it", PTR_TO_PID(p
));
784 (void) kill(PTR_TO_PID(p
), SIGKILL
);
788 static int ask_on_consoles(int argc
, char *argv
[]) {
789 _cleanup_set_free_ Set
*pids
= NULL
;
790 _cleanup_strv_free_
char **consoles
= NULL
;
791 siginfo_t status
= {};
796 r
= get_kernel_consoles(&consoles
);
798 return log_error_errno(r
, "Failed to determine devices of /dev/console: %m");
800 pids
= set_new(NULL
);
804 /* Start an agent on each console. */
805 STRV_FOREACH(tty
, consoles
) {
806 r
= ask_on_this_console(*tty
, &pid
, argc
, argv
);
810 if (set_put(pids
, PID_TO_PTR(pid
)) < 0)
814 /* Wait for an agent to exit. */
818 if (waitid(P_ALL
, 0, &status
, WEXITED
) < 0) {
822 return log_error_errno(errno
, "waitid() failed: %m");
825 set_remove(pids
, PID_TO_PTR(status
.si_pid
));
829 if (!is_clean_exit(status
.si_code
, status
.si_status
, EXIT_CLEAN_DAEMON
, NULL
))
830 log_error("Password agent failed with: %d", status
.si_status
);
832 terminate_agents(pids
);
836 int main(int argc
, char *argv
[]) {
839 log_set_target(LOG_TARGET_AUTO
);
840 log_parse_environment();
845 r
= parse_argv(argc
, argv
);
849 if (arg_console
&& !arg_device
)
851 * Spawn for each console device a separate process.
853 r
= ask_on_consoles(argc
, argv
);
858 * Later on, a controlling terminal will be acquired,
859 * therefore the current process has to become a session
860 * leader and should not have a controlling terminal already.
863 (void) release_terminal();
866 if (IN_SET(arg_action
, ACTION_WATCH
, ACTION_WALL
))
867 r
= watch_passwords();
869 r
= show_passwords();
873 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;