diff --git a/src/core/emergency-action.c b/src/core/emergency-action.c index 9731aef5c4..09f8d74092 100644 --- a/src/core/emergency-action.c +++ b/src/core/emergency-action.c @@ -47,7 +47,7 @@ void emergency_action( case EMERGENCY_ACTION_REBOOT: log_and_status(m, warn, "Rebooting", reason); - (void) update_reboot_parameter_and_warn(reboot_arg); + (void) update_reboot_parameter_and_warn(reboot_arg, true); (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL); break; @@ -55,7 +55,7 @@ void emergency_action( case EMERGENCY_ACTION_REBOOT_FORCE: log_and_status(m, warn, "Forcibly rebooting", reason); - (void) update_reboot_parameter_and_warn(reboot_arg); + (void) update_reboot_parameter_and_warn(reboot_arg, true); m->objective = MANAGER_REBOOT; break; diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 003ab45461..5f82b21995 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -32,6 +32,7 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" +#include "reboot-util.h" #include "selinux-util.h" #include "sleep-config.h" #include "special.h" @@ -42,6 +43,7 @@ #include "unit-name.h" #include "user-util.h" #include "utmp-wtmp.h" +#include "virt.h" static int get_sender_session(Manager *m, sd_bus_message *message, sd_bus_error *error, Session **ret) { @@ -168,6 +170,32 @@ int manager_get_seat_from_creds(Manager *m, sd_bus_message *message, const char return 0; } +static int return_test_polkit( + sd_bus_message *message, + int capability, + const char *action, + const char **details, + uid_t good_user, + sd_bus_error *e) { + + const char *result; + bool challenge; + int r; + + r = bus_test_polkit(message, capability, action, details, good_user, &challenge, e); + if (r < 0) + return r; + + if (r > 0) + result = "yes"; + else if (challenge) + result = "challenge"; + else + result = "no"; + + return sd_bus_reply_method_return(message, "s", result); +} + static int property_get_idle_hint( sd_bus *bus, const char *path, @@ -2382,6 +2410,97 @@ static int method_can_suspend_then_hibernate(sd_bus_message *message, void *user error); } +static int property_get_reboot_parameter( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + _cleanup_free_ char *parameter = NULL; + int r; + + assert(bus); + assert(reply); + assert(userdata); + + r = read_reboot_parameter(¶meter); + if (r < 0) + return r; + + return sd_bus_message_append(reply, "s", parameter); +} + +static int method_set_reboot_parameter( + sd_bus_message *message, + void *userdata, + sd_bus_error *error) { + + Manager *m = userdata; + const char *arg; + int r; + + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &arg); + if (r < 0) + return r; + + r = detect_container(); + if (r < 0) + return r; + if (r > 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, + "Reboot parameter not supported in containers, refusing."); + + r = bus_verify_polkit_async(message, + CAP_SYS_ADMIN, + "org.freedesktop.login1.set-reboot-parameter", + NULL, + false, + UID_INVALID, + &m->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ + + r = update_reboot_parameter_and_warn(arg, false); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_can_reboot_parameter( + sd_bus_message *message, + void *userdata, + sd_bus_error *error) { + + Manager *m = userdata; + int r; + + assert(message); + assert(m); + + r = detect_container(); + if (r < 0) + return r; + if (r > 0) /* Inside containers, specifying a reboot parameter, doesn't make much sense */ + return sd_bus_reply_method_return(message, "s", "na"); + + return return_test_polkit( + message, + CAP_SYS_ADMIN, + "org.freedesktop.login1.set-reboot-parameter", + NULL, + UID_INVALID, + error); +} + static int property_get_reboot_to_firmware_setup( sd_bus *bus, const char *path, @@ -2488,32 +2607,6 @@ static int method_set_reboot_to_firmware_setup( return sd_bus_reply_method_return(message, NULL); } -static int return_test_polkit( - sd_bus_message *message, - int capability, - const char *action, - const char **details, - uid_t good_user, - sd_bus_error *e) { - - const char *result; - bool challenge; - int r; - - r = bus_test_polkit(message, capability, action, details, good_user, &challenge, e); - if (r < 0) - return r; - - if (r > 0) - result = "yes"; - else if (challenge) - result = "challenge"; - else - result = "no"; - - return sd_bus_reply_method_return(message, "s", result); -} - static int method_can_reboot_to_firmware_setup( sd_bus_message *message, void *userdata, @@ -3137,6 +3230,7 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_PROPERTY("KillOnlyUsers", "as", NULL, offsetof(Manager, kill_only_users), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("KillExcludeUsers", "as", NULL, offsetof(Manager, kill_exclude_users), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("KillUserProcesses", "b", NULL, offsetof(Manager, kill_user_processes), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RebootParameter", "s", property_get_reboot_parameter, 0, 0), SD_BUS_PROPERTY("RebootToFirmwareSetup", "b", property_get_reboot_to_firmware_setup, 0, 0), SD_BUS_PROPERTY("RebootToBootLoaderMenu", "t", property_get_reboot_to_boot_loader_menu, 0, 0), SD_BUS_PROPERTY("RebootToBootLoaderEntry", "s", property_get_reboot_to_boot_loader_entry, 0, 0), @@ -3213,6 +3307,8 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_METHOD("ScheduleShutdown", "st", NULL, method_schedule_shutdown, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CancelScheduledShutdown", NULL, "b", method_cancel_scheduled_shutdown, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Inhibit", "ssss", "h", method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("CanRebootParameter", NULL, "s", method_can_reboot_parameter, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetRebootParameter", "s", NULL, method_set_reboot_parameter, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanRebootToFirmwareSetup", NULL, "s", method_can_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetRebootToFirmwareSetup", "b", NULL, method_set_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanRebootToBootLoaderMenu", NULL, "s", method_can_reboot_to_boot_loader_menu, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf index 5677c15b8a..f3c13ad89a 100644 --- a/src/login/org.freedesktop.login1.conf +++ b/src/login/org.freedesktop.login1.conf @@ -190,6 +190,14 @@ send_interface="org.freedesktop.login1.Manager" send_member="CancelScheduledShutdown"/> + + + + diff --git a/src/login/org.freedesktop.login1.policy b/src/login/org.freedesktop.login1.policy index 671384d34e..6ad6512f5a 100644 --- a/src/login/org.freedesktop.login1.policy +++ b/src/login/org.freedesktop.login1.policy @@ -337,6 +337,17 @@ + + Configure reboot parameter for kernel's reboot reason driver + Authentication is required to configure reboot parameter for kernel's reboot reason driver. + + auth_admin_keep + auth_admin_keep + yes + + org.freedesktop.login1.reboot + + Indicate to the firmware to boot to setup interface Authentication is required to indicate to the firmware to boot to setup interface. diff --git a/src/shared/reboot-util.c b/src/shared/reboot-util.c index ca40159b96..08569e8bf3 100644 --- a/src/shared/reboot-util.c +++ b/src/shared/reboot-util.c @@ -12,10 +12,13 @@ #include "umask-util.h" #include "virt.h" -int update_reboot_parameter_and_warn(const char *parameter) { +int update_reboot_parameter_and_warn(const char *parameter, bool keep) { int r; if (isempty(parameter)) { + if (keep) + return 0; + if (unlink("/run/systemd/reboot-param") < 0) { if (errno == ENOENT) return 0; @@ -36,6 +39,18 @@ int update_reboot_parameter_and_warn(const char *parameter) { return 0; } +int read_reboot_parameter(char **parameter) { + int r; + + assert(parameter); + + r = read_one_line_file("/run/systemd/reboot-param", parameter); + if (r < 0 && r != -ENOENT) + return log_debug_errno(r, "Failed to read /run/systemd/reboot-param: %m"); + + return 0; +} + int reboot_with_parameter(RebootFlags flags) { int r; diff --git a/src/shared/reboot-util.h b/src/shared/reboot-util.h index d459333efc..7bddc91ea6 100644 --- a/src/shared/reboot-util.h +++ b/src/shared/reboot-util.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -int update_reboot_parameter_and_warn(const char *parameter); +int update_reboot_parameter_and_warn(const char *parameter, bool keep); typedef enum RebootFlags { REBOOT_LOG = 1 << 0, /* log about what we are going to do and all errors */ @@ -9,4 +9,5 @@ typedef enum RebootFlags { REBOOT_FALLBACK = 1 << 2, /* fallback to plain reboot() if argument-based reboot doesn't work, isn't configured or doesn't apply otherwise */ } RebootFlags; +int read_reboot_parameter(char **parameter); int reboot_with_parameter(RebootFlags flags); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 9d2115b712..948dacd190 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3734,7 +3734,7 @@ static int start_special(int argc, char *argv[], void *userdata) { return r; if (a == ACTION_REBOOT && argc > 1) { - r = update_reboot_parameter_and_warn(argv[1]); + r = update_reboot_parameter_and_warn(argv[1], false); if (r < 0) return r; @@ -8455,7 +8455,7 @@ static int halt_parse_argv(int argc, char *argv[]) { } if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) { - r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL); + r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL, false); if (r < 0) return r; } else if (optind < argc)