From: Deepak Rawat Date: Mon, 25 Jan 2021 17:14:08 +0000 (-0800) Subject: logind: Introduce RebootWithFlags and others X-Git-Tag: v248-rc1~225 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8885fed4e3a52cf1bf105e42043203c485ed9d92;p=thirdparty%2Fsystemd.git 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. --- diff --git a/man/org.freedesktop.login1.xml b/man/org.freedesktop.login1.xml index ad27b226b8a..bf7a5fa3402 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 { + + + + + + + + + + + + + + @@ -525,8 +546,19 @@ node /org/freedesktop/login1 { using an RTC timer and hibernated. The only argument is the polkit interactivity boolean interactive (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. + 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 + PowerOffWithFlags(), RebootWithFlags(), + HaltWithFlags(), SuspendWithFlags(), + HibernateWithFlags(), HybridSleepWithFlags() and + SuspendThenHibernateWithFlags() add flags to allow for + extendability, defined as follows: + +#define SD_LOGIND_ROOT_CHECK_INHIBITORS (UINT64_C(1) << 0) + + When the flags is 0 then these methods behave just like the versions + without flags. When SD_LOGIND_ROOT_CHECK_INHIBITORS (0x01) is set, active + inhibitors are honoured for privileged users too. SetRebootParameter() sets a parameter for a subsequent reboot operation. See the description of reboot in diff --git a/src/basic/login-util.h b/src/basic/login-util.h index 00a124dc9fb..dff87697a64 100644 --- a/src/basic/login-util.h +++ b/src/basic/login-util.h @@ -4,6 +4,14 @@ #include #include +#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 b95af1a9fd6..8f27fe7ee9f 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 4070c642577..103f81647d2 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));