diff options
author | Deepak Rawat <drawat.floss@gmail.com> | 2021-01-25 09:14:08 -0800 |
---|---|---|
committer | Luca Boccassi <luca.boccassi@gmail.com> | 2021-02-02 11:55:16 +0000 |
commit | 8885fed4e3a52cf1bf105e42043203c485ed9d92 (patch) | |
tree | 0f54d37eb8b4278cb6cf56a9533e9194c13d625b | |
parent | 77591e97327d6fc47f27599ba1937629afb6dd13 (diff) | |
download | systemd-8885fed4e3a52cf1bf105e42043203c485ed9d92.tar.gz |
logind: Introduce RebootWithFlags and others
Add new systemd-logind WithFlags version for Reboot and others. These
methods add a unit64 parameter, with which can send additional control flags.
-rw-r--r-- | man/org.freedesktop.login1.xml | 36 | ||||
-rw-r--r-- | src/basic/login-util.h | 8 | ||||
-rw-r--r-- | src/login/logind-dbus.c | 97 | ||||
-rw-r--r-- | src/systemctl/systemctl-logind.c | 17 |
4 files changed, 142 insertions, 16 deletions
diff --git a/man/org.freedesktop.login1.xml b/man/org.freedesktop.login1.xml index ad27b226b8..bf7a5fa340 100644 --- a/man/org.freedesktop.login1.xml +++ b/man/org.freedesktop.login1.xml @@ -102,12 +102,19 @@ node /org/freedesktop/login1 { in b interactive); FlushDevices(in b interactive); PowerOff(in b interactive); + PowerOffWithFlags(in t flags); Reboot(in b interactive); + RebootWithFlags(in t flags); Halt(in b interactive); + HaltWithFlags(in t flags); Suspend(in b interactive); + SuspendWithFlags(in t flags); Hibernate(in b interactive); + HibernateWithFlags(in t flags); HybridSleep(in b interactive); + HybridSleepWithFlags(in t flags); SuspendThenHibernate(in b interactive); + SuspendThenHibernateWithFlags(in t flags); CanPowerOff(out s result); CanReboot(out s result); CanHalt(out s result); @@ -291,18 +298,32 @@ node /org/freedesktop/login1 { <variablelist class="dbus-method" generated="True" extra-ref="PowerOff()"/> + <variablelist class="dbus-method" generated="True" extra-ref="PowerOffWithFlags()"/> + <variablelist class="dbus-method" generated="True" extra-ref="Reboot()"/> + <variablelist class="dbus-method" generated="True" extra-ref="RebootWithFlags()"/> + <variablelist class="dbus-method" generated="True" extra-ref="Halt()"/> + <variablelist class="dbus-method" generated="True" extra-ref="HaltWithFlags()"/> + <variablelist class="dbus-method" generated="True" extra-ref="Suspend()"/> + <variablelist class="dbus-method" generated="True" extra-ref="SuspendWithFlags()"/> + <variablelist class="dbus-method" generated="True" extra-ref="Hibernate()"/> + <variablelist class="dbus-method" generated="True" extra-ref="HibernateWithFlags()"/> + <variablelist class="dbus-method" generated="True" extra-ref="HybridSleep()"/> + <variablelist class="dbus-method" generated="True" extra-ref="HybridSleepWithFlags()"/> + <variablelist class="dbus-method" generated="True" extra-ref="SuspendThenHibernate()"/> + <variablelist class="dbus-method" generated="True" extra-ref="SuspendThenHibernateWithFlags()"/> + <variablelist class="dbus-method" generated="True" extra-ref="CanPowerOff()"/> <variablelist class="dbus-method" generated="True" extra-ref="CanReboot()"/> @@ -525,8 +546,19 @@ node /org/freedesktop/login1 { using an RTC timer and hibernated. The only argument is the polkit interactivity boolean <varname>interactive</varname> (see below). The main purpose of these calls is that they enforce polkit policy and hence allow powering off/rebooting/suspending/hibernating even by unprivileged - users. They also enforce inhibition locks. UIs should expose these calls as the primary mechanism to - poweroff/reboot/suspend/hibernate the machine.</para> + users. They also enforce inhibition locks for non-privileged users. UIs should expose these calls + as the primary mechanism to poweroff/reboot/suspend/hibernate the machine. Methods + <function>PowerOffWithFlags()</function>, <function>RebootWithFlags()</function>, + <function>HaltWithFlags()</function>, <function>SuspendWithFlags()</function>, + <function>HibernateWithFlags()</function>, <function>HybridSleepWithFlags()</function> and + <function>SuspendThenHibernateWithFlags()</function> add <varname>flags</varname> to allow for + extendability, defined as follows:</para> + <programlisting> +#define SD_LOGIND_ROOT_CHECK_INHIBITORS (UINT64_C(1) << 0) + </programlisting> + <para> When the <varname>flags</varname> is 0 then these methods behave just like the versions + without flags. When <constant>SD_LOGIND_ROOT_CHECK_INHIBITORS</constant> (0x01) is set, active + inhibitors are honoured for privileged users too.</para> <para><function>SetRebootParameter()</function> sets a parameter for a subsequent reboot operation. See the description of <command>reboot</command> in diff --git a/src/basic/login-util.h b/src/basic/login-util.h index 00a124dc9f..dff87697a6 100644 --- a/src/basic/login-util.h +++ b/src/basic/login-util.h @@ -4,6 +4,14 @@ #include <stdbool.h> #include <unistd.h> +#define SD_LOGIND_ROOT_CHECK_INHIBITORS (UINT64_C(1) << 0) + +/* For internal use only */ +#define SD_LOGIND_INTERACTIVE (UINT64_C(1) << 63) + +#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC (SD_LOGIND_ROOT_CHECK_INHIBITORS) +#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_ALL (SD_LOGIND_ROOT_CHECK_INHIBITORS|SD_LOGIND_INTERACTIVE) + bool session_id_valid(const char *id); static inline bool logind_running(void) { diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index b95af1a9fd..8f27fe7ee9 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1793,14 +1793,14 @@ static int verify_shutdown_creds( Manager *m, sd_bus_message *message, InhibitWhat w, - bool interactive, const char *action, const char *action_multiple_sessions, const char *action_ignore_inhibit, + uint64_t flags, sd_bus_error *error) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - bool multiple_sessions, blocked; + bool multiple_sessions, blocked, interactive; uid_t uid; int r; @@ -1823,6 +1823,7 @@ static int verify_shutdown_creds( multiple_sessions = r > 0; blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL); + interactive = flags & SD_LOGIND_INTERACTIVE; if (multiple_sessions && action_multiple_sessions) { r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_multiple_sessions, NULL, interactive, UID_INVALID, &m->polkit_registry, error); @@ -1832,12 +1833,19 @@ static int verify_shutdown_creds( return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ } - if (blocked && action_ignore_inhibit) { - r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, interactive, 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 */ + if (blocked) { + /* We don't check polkit for root here, because you can't be more privileged than root */ + if (uid == 0 && (flags & SD_LOGIND_ROOT_CHECK_INHIBITORS)) + return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, + "Access denied to root due to active block inhibitor"); + + if (action_ignore_inhibit) { + r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, interactive, 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 */ + } } if (!multiple_sessions && !blocked && action) { @@ -1860,9 +1868,11 @@ static int method_do_shutdown_or_sleep( const char *action_multiple_sessions, const char *action_ignore_inhibit, const char *sleep_verb, + bool with_flags, sd_bus_error *error) { - int interactive, r; + int interactive = false, r; + uint64_t flags = 0; assert(m); assert(message); @@ -1870,10 +1880,20 @@ static int method_do_shutdown_or_sleep( assert(w >= 0); assert(w <= _INHIBIT_WHAT_MAX); - r = sd_bus_message_read(message, "b", &interactive); + if (with_flags) + r = sd_bus_message_read(message, "t", &flags); + else + r = sd_bus_message_read(message, "b", &interactive); + if (r < 0) return r; + if (with_flags && (flags & ~SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Invalid flags parameter"); + + SET_FLAG(flags, SD_LOGIND_INTERACTIVE, interactive); + /* Don't allow multiple jobs being executed at the same time */ if (m->action_what > 0) return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, @@ -1891,8 +1911,8 @@ static int method_do_shutdown_or_sleep( return r; } - r = verify_shutdown_creds(m, message, w, interactive, action, action_multiple_sessions, - action_ignore_inhibit, error); + r = verify_shutdown_creds(m, message, w, action, action_multiple_sessions, + action_ignore_inhibit, flags, error); if (r != 0) return r; @@ -1914,6 +1934,7 @@ static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error "org.freedesktop.login1.power-off-multiple-sessions", "org.freedesktop.login1.power-off-ignore-inhibit", NULL, + sd_bus_message_is_method_call(message, NULL, "PowerOffWithFlags"), error); } @@ -1928,6 +1949,7 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error * "org.freedesktop.login1.reboot-multiple-sessions", "org.freedesktop.login1.reboot-ignore-inhibit", NULL, + sd_bus_message_is_method_call(message, NULL, "RebootWithFlags"), error); } @@ -1942,6 +1964,7 @@ static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *er "org.freedesktop.login1.halt-multiple-sessions", "org.freedesktop.login1.halt-ignore-inhibit", NULL, + sd_bus_message_is_method_call(message, NULL, "HaltWithFlags"), error); } @@ -1956,6 +1979,7 @@ static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error "org.freedesktop.login1.suspend-multiple-sessions", "org.freedesktop.login1.suspend-ignore-inhibit", "suspend", + sd_bus_message_is_method_call(message, NULL, "SuspendWithFlags"), error); } @@ -1970,6 +1994,7 @@ static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_erro "org.freedesktop.login1.hibernate-multiple-sessions", "org.freedesktop.login1.hibernate-ignore-inhibit", "hibernate", + sd_bus_message_is_method_call(message, NULL, "HibernateWithFlags"), error); } @@ -1984,6 +2009,7 @@ static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_e "org.freedesktop.login1.hibernate-multiple-sessions", "org.freedesktop.login1.hibernate-ignore-inhibit", "hybrid-sleep", + sd_bus_message_is_method_call(message, NULL, "HybridSleepWithFlags"), error); } @@ -1998,6 +2024,7 @@ static int method_suspend_then_hibernate(sd_bus_message *message, void *userdata "org.freedesktop.login1.hibernate-multiple-sessions", "org.freedesktop.login1.hibernate-ignore-inhibit", "hybrid-sleep", + sd_bus_message_is_method_call(message, NULL, "SuspendThenHibernateWithFlags"), error); } @@ -2185,8 +2212,8 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_ } else return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type"); - r = verify_shutdown_creds(m, message, INHIBIT_SHUTDOWN, false, - action, action_multiple_sessions, action_ignore_inhibit, error); + r = verify_shutdown_creds(m, message, INHIBIT_SHUTDOWN, action, action_multiple_sessions, + action_ignore_inhibit, 0, error); if (r != 0) return r; @@ -3538,42 +3565,84 @@ static const sd_bus_vtable manager_vtable[] = { NULL,, method_poweroff, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("PowerOffWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_poweroff, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("Reboot", "b", SD_BUS_PARAM(interactive), NULL,, method_reboot, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("RebootWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_reboot, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("Halt", "b", SD_BUS_PARAM(interactive), NULL,, method_halt, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("HaltWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_halt, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("Suspend", "b", SD_BUS_PARAM(interactive), NULL,, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("SuspendWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_suspend, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("Hibernate", "b", SD_BUS_PARAM(interactive), NULL,, method_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("HibernateWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_hibernate, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("HybridSleep", "b", SD_BUS_PARAM(interactive), NULL,, method_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("HybridSleepWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_hybrid_sleep, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("SuspendThenHibernate", "b", SD_BUS_PARAM(interactive), NULL,, method_suspend_then_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("SuspendThenHibernateWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_suspend_then_hibernate, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("CanPowerOff", NULL,, "s", diff --git a/src/systemctl/systemctl-logind.c b/src/systemctl/systemctl-logind.c index 4070c64257..103f81647d 100644 --- a/src/systemctl/systemctl-logind.c +++ b/src/systemctl/systemctl-logind.c @@ -6,6 +6,7 @@ #include "bus-error.h" #include "bus-locator.h" +#include "login-util.h" #include "process-util.h" #include "systemctl-logind.h" #include "systemctl-start-unit.h" @@ -57,6 +58,8 @@ int logind_reboot(enum action a) { }; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + const char *method_with_flags; + uint64_t flags = 0; sd_bus *bus; int r; @@ -75,6 +78,20 @@ int logind_reboot(enum action a) { if (arg_dry_run) return 0; + SET_FLAG(flags, SD_LOGIND_ROOT_CHECK_INHIBITORS, arg_check_inhibitors > 0); + + method_with_flags = strjoina(actions[a].method, "WithFlags"); + + r = bus_call_method(bus, bus_login_mgr, method_with_flags, &error, NULL, "t", flags); + if (r >= 0) + return 0; + if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) + return log_error_errno(r, "Failed to %s via logind: %s", actions[a].description, bus_error_message(&error, r)); + + /* Fallback to original methods in case there is older version of systemd-logind */ + log_debug("Method %s not available: %s. Falling back to %s", method_with_flags, bus_error_message(&error, r), actions[a].method); + sd_bus_error_free(&error); + r = bus_call_method(bus, bus_login_mgr, actions[a].method, &error, NULL, "b", arg_ask_password); if (r < 0) return log_error_errno(r, "Failed to %s via logind: %s", actions[a].description, bus_error_message(&error, r)); |