1
0
mirror of https://github.com/systemd/systemd synced 2025-09-29 16:54:46 +02:00

Compare commits

...

7 Commits

Author SHA1 Message Date
Lennart Poettering
edf370af9e
Merge pull request #18432 from yuwata/libude-list-cleanups
libudev: cleanups for libudev-list
2021-02-02 15:05:46 +01:00
Deepak Rawat
8885fed4e3 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.
2021-02-02 11:55:16 +00:00
Yu Watanabe
ecf83c2429 libudev: add one more assertion 2021-02-02 03:23:31 +09:00
Yu Watanabe
65c637ad2c libudev: unset uptodate flag before free()ing entries
udev_list_entry_free() also removes the entry from LIST if the flag is
set. This slightly optimizes the cleanup logic.
2021-02-02 02:34:23 +09:00
Yu Watanabe
8e5ce38727 libudev: also drop the entry from LIST even if unique flag is set
Otherwise, the list becomes dirty when an entry is freed.

This also remove the entry from the hashmap only when its name is set.
The name should be always set, so that does not change anything. But
just for safety.
2021-02-02 02:28:33 +09:00
Yu Watanabe
140716a516 libudev: set entry->list after the entry is stored in the list
This should not change anything. As hashmap_remove() is called before
hashmap_ensure_put(). So, even if hashmap_ensure_put() fails, a wrong
entry will not removed from the hashmap by udev_list_entry_free().
But anyway, just for safety.
2021-02-02 02:22:59 +09:00
Yu Watanabe
eaef130d3f libudev: use hashmap_ensure_put() 2021-02-02 02:22:35 +09:00
5 changed files with 150 additions and 27 deletions

View File

@ -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) &lt;&lt; 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

View File

@ -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) {

View File

@ -39,9 +39,10 @@ static struct udev_list_entry *udev_list_entry_free(struct udev_list_entry *entr
return NULL;
if (entry->list) {
if (entry->list->unique)
if (entry->list->unique && entry->name)
hashmap_remove(entry->list->unique_entries, entry->name);
else
if (!entry->list->unique || entry->list->uptodate)
LIST_REMOVE(entries, entry->list->entries, entry);
}
@ -70,9 +71,9 @@ struct udev_list *udev_list_new(bool unique) {
struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *_name, const char *_value) {
_cleanup_(udev_list_entry_freep) struct udev_list_entry *entry = NULL;
_cleanup_free_ char *name = NULL, *value = NULL;
int r;
assert(list);
assert(_name);
name = strdup(_name);
if (!name)
@ -89,26 +90,22 @@ struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *
return NULL;
*entry = (struct udev_list_entry) {
.list = list,
.name = TAKE_PTR(name),
.value = TAKE_PTR(value),
};
if (list->unique) {
r = hashmap_ensure_allocated(&list->unique_entries, &string_hash_ops);
if (r < 0)
return NULL;
udev_list_entry_free(hashmap_get(list->unique_entries, entry->name));
r = hashmap_put(list->unique_entries, entry->name, entry);
if (r < 0)
if (hashmap_ensure_put(&list->unique_entries, &string_hash_ops, entry->name, entry) < 0)
return NULL;
list->uptodate = false;
} else
LIST_APPEND(entries, list->entries, entry);
entry->list = list;
return TAKE_PTR(entry);
}
@ -119,8 +116,8 @@ void udev_list_cleanup(struct udev_list *list) {
return;
if (list->unique) {
hashmap_clear_with_destructor(list->unique_entries, udev_list_entry_free);
list->uptodate = false;
hashmap_clear_with_destructor(list->unique_entries, udev_list_entry_free);
} else
LIST_FOREACH_SAFE(entries, i, n, list->entries)
udev_list_entry_free(i);

View File

@ -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",

View File

@ -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));