/* SPDX-License-Identifier: LGPL-2.1+ */
/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
- Copyright 2015 Werner Fink
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ Copyright © 2015 Werner Fink
***/
#include <errno.h>
#include "hashmap.h"
#include "io-util.h"
#include "macro.h"
+#include "main-func.h"
#include "mkdir.h"
#include "path-util.h"
+#include "pretty-print.h"
#include "process-util.h"
#include "signal-util.h"
#include "socket-util.h"
r = 0;
finish:
- explicit_bzero(buffer, sizeof(buffer));
+ explicit_bzero_safe(buffer, sizeof(buffer));
return r;
}
static int send_passwords(const char *socket_name, char **passwords) {
_cleanup_free_ char *packet = NULL;
_cleanup_close_ int socket_fd = -1;
- union sockaddr_union sa = { .un.sun_family = AF_UNIX };
+ union sockaddr_union sa = {};
size_t packet_length = 1;
char **p, *d;
- int r;
+ ssize_t n;
+ int r, salen;
assert(socket_name);
+ salen = sockaddr_un_set_path(&sa.un, socket_name);
+ if (salen < 0)
+ return salen;
+
STRV_FOREACH(p, passwords)
packet_length += strlen(*p) + 1;
goto finish;
}
- strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path));
-
- r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, SOCKADDR_UN_LEN(sa.un));
- if (r < 0)
+ n = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, salen);
+ if (n < 0) {
r = log_debug_errno(errno, "sendto(): %m");
+ goto finish;
+ }
+
+ r = (int) n;
finish:
- explicit_bzero(packet, packet_length);
+ explicit_bzero_safe(packet, packet_length);
return r;
}
if (r < 0)
return r;
- if (!socket_name) {
- log_error("Invalid password file %s", filename);
- return -EBADMSG;
- }
+ if (!socket_name)
+ return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
+ "Invalid password file %s", filename);
if (not_after > 0 && now(CLOCK_MONOTONIC) > not_after)
return 0;
if (asprintf(&_wall,
"%s%sPassword entry required for \'%s\' (PID %u).\r\n"
- "Please enter password with the systemd-tty-ask-password-agent tool!",
+ "Please enter password with the systemd-tty-ask-password-agent tool:",
strempty(*wall),
*wall ? "\r\n\r\n" : "",
message,
if (arg_plymouth)
r = ask_password_plymouth(message, not_after, accept_cached ? ASK_PASSWORD_ACCEPT_CACHED : 0, filename, &passwords);
else {
- char *password = NULL;
int tty_fd = -1;
if (arg_console) {
- const char *con = arg_device ? arg_device : "/dev/console";
+ const char *con = arg_device ?: "/dev/console";
- tty_fd = acquire_terminal(con, false, false, false, USEC_INFINITY);
+ tty_fd = acquire_terminal(con, ACQUIRE_TERMINAL_WAIT, USEC_INFINITY);
if (tty_fd < 0)
- return log_error_errno(tty_fd, "Failed to acquire /dev/console: %m");
+ return log_error_errno(tty_fd, "Failed to acquire %s: %m", con);
r = reset_terminal_fd(tty_fd, true);
if (r < 0)
log_warning_errno(r, "Failed to reset terminal, ignoring: %m");
}
- r = ask_password_tty(message, NULL, not_after, echo ? ASK_PASSWORD_ECHO : 0, filename, &password);
+ r = ask_password_tty(tty_fd, message, NULL, not_after,
+ (echo ? ASK_PASSWORD_ECHO : 0) |
+ (arg_console ? ASK_PASSWORD_CONSOLE_COLOR : 0),
+ filename, &passwords);
if (arg_console) {
tty_fd = safe_close(tty_fd);
release_terminal();
}
-
- if (r >= 0)
- r = strv_push(&passwords, password);
-
- if (r < 0)
- string_free_erase(password);
}
/* If the query went away, that's OK */
fd = open(p, O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
if (fd < 0) {
- log_debug_errno(errno, "Failed top open the wall pipe: %m");
+ log_debug_errno(errno, "Failed to open the wall pipe: %m");
return 1;
}
if (notify < 0)
return log_error_errno(errno, "Failed to allocate directory watch: %m");
- if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO) < 0)
- return log_error_errno(errno, "Failed to add /run/systemd/ask-password to directory watch: %m");
+ if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO) < 0) {
+ if (errno == ENOSPC)
+ return log_error_errno(errno, "Failed to add /run/systemd/ask-password to directory watch: inotify watch limit reached");
+ else
+ return log_error_errno(errno, "Failed to add /run/systemd/ask-password to directory watch: %m");
+ }
assert_se(sigemptyset(&mask) >= 0);
assert_se(sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0);
return 0;
}
-static void help(void) {
+static int help(void) {
+ _cleanup_free_ char *link = NULL;
+ int r;
+
+ r = terminal_urlify_man("systemd-tty-ask-password-agent", "1", &link);
+ if (r < 0)
+ return log_oom();
+
printf("%s [OPTIONS...]\n\n"
"Process system password requests.\n\n"
" -h --help Show this help\n"
" --watch Continuously process password requests\n"
" --wall Continuously forward password requests to wall\n"
" --plymouth Ask question with Plymouth instead of on TTY\n"
- " --console Ask question on /dev/console instead of current TTY\n",
- program_invocation_short_name);
+ " --console Ask question on /dev/console instead of current TTY\n"
+ "\nSee the %s for details.\n"
+ , program_invocation_short_name
+ , link
+ );
+
+ return 0;
}
static int parse_argv(int argc, char *argv[]) {
switch (c) {
case 'h':
- help();
- return 0;
+ return help();
case ARG_VERSION:
return version();
arg_console = true;
if (optarg) {
- if (isempty(optarg)) {
- log_error("Empty console device path is not allowed.");
- return -EINVAL;
- }
+ if (isempty(optarg))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Empty console device path is not allowed.");
arg_device = optarg;
}
assert_not_reached("Unhandled option");
}
- if (optind != argc) {
- log_error("%s takes no arguments.", program_invocation_short_name);
- return -EINVAL;
- }
+ if (optind != argc)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s takes no arguments.", program_invocation_short_name);
if (arg_plymouth || arg_console) {
- if (!IN_SET(arg_action, ACTION_QUERY, ACTION_WATCH)) {
- log_error("Options --query and --watch conflict.");
- return -EINVAL;
- }
+ if (!IN_SET(arg_action, ACTION_QUERY, ACTION_WATCH))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Options --query and --watch conflict.");
- if (arg_plymouth && arg_console) {
- log_error("Options --plymouth and --console conflict.");
- return -EINVAL;
- }
+ if (arg_plymouth && arg_console)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Options --plymouth and --console conflict.");
}
return 1;
return 0;
}
-int main(int argc, char *argv[]) {
+static int run(int argc, char *argv[]) {
int r;
- log_set_target(LOG_TARGET_AUTO);
- log_parse_environment();
- log_open();
+ log_setup_service();
umask(0022);
r = parse_argv(argc, argv);
if (r <= 0)
- goto finish;
+ return r;
if (arg_console && !arg_device)
/*
- * Spawn for each console device a separate process.
+ * Spawn a separate process for each console device.
*/
- r = ask_on_consoles(argc, argv);
- else {
-
- if (arg_device) {
- /*
- * Later on, a controlling terminal will be acquired,
- * therefore the current process has to become a session
- * leader and should not have a controlling terminal already.
- */
- (void) setsid();
- (void) release_terminal();
- }
+ return ask_on_consoles(argc, argv);
- if (IN_SET(arg_action, ACTION_WATCH, ACTION_WALL))
- r = watch_passwords();
- else
- r = show_passwords();
+ if (arg_device) {
+ /*
+ * Later on, a controlling terminal will be acquired,
+ * therefore the current process has to become a session
+ * leader and should not have a controlling terminal already.
+ */
+ (void) setsid();
+ (void) release_terminal();
}
-finish:
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+ if (IN_SET(arg_action, ACTION_WATCH, ACTION_WALL))
+ return watch_passwords();
+ else
+ return show_passwords();
}
+
+DEFINE_MAIN_FUNCTION(run);