int vl_method_register(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
Manager *manager = ASSERT_PTR(userdata);
_cleanup_(machine_freep) Machine *machine = NULL;
+ bool sender_is_admin = false;
int r;
static const sd_json_dispatch_field dispatch_table[] = {
return sd_varlink_error_invalid_parameter_name(link, "class");
if (manager->runtime_scope != RUNTIME_SCOPE_USER) {
- r = varlink_verify_polkit_async(
+ r = varlink_verify_polkit_async_full(
link,
manager->system_bus,
machine->allocate_unit ? "org.freedesktop.machine1.create-machine" : "org.freedesktop.machine1.register-machine",
(const char**) STRV_MAKE("name", machine->name,
"class", machine_class_to_string(machine->class)),
- &manager->polkit_registry);
+ /* good_user= */ UID_INVALID,
+ /* flags= */ 0,
+ &manager->polkit_registry,
+ &sender_is_admin);
if (r <= 0)
return r;
}
/* In system scope, ensure an unprivileged user cannot claim any process they don't
* control as their own machine. In user scope the varlink socket is already
* protected by $XDG_RUNTIME_DIR permissions. */
- if (manager->runtime_scope != RUNTIME_SCOPE_USER && machine->uid != 0) {
+ if (manager->runtime_scope != RUNTIME_SCOPE_USER && machine->uid != 0 && !sender_is_admin) {
r = process_is_owned_by_uid(&machine->leader, machine->uid);
if (r < 0)
return r;
/* Ensure an unprivileged user cannot claim any process they don't control as their own machine */
switch (manager->runtime_scope) {
- case RUNTIME_SCOPE_SYSTEM:
- /* In system mode root may register anything */
- if (uid == 0)
+ case RUNTIME_SCOPE_SYSTEM: {
+ const char *details[] = {
+ "name", name,
+ "class", machine_class_to_string(c),
+ NULL
+ };
+ bool sender_is_admin = false;
+
+ r = bus_verify_polkit_async_full(
+ message,
+ polkit_action,
+ details,
+ /* good_user= */ UID_INVALID,
+ /* flags= */ 0,
+ &manager->polkit_registry,
+ &sender_is_admin,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 0; /* Will call us back */
+
+ /* In system mode root/admin may register anything */
+ if (uid == 0 || sender_is_admin)
break;
- /* And non-root may only register things if they own the userns */
+ /* And non-root/admin may only register things if they own the userns */
r = process_is_owned_by_uid(leader_pidref, uid);
if (r < 0)
return r;
break;
/* Nothing else may */
- return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only root may register machines for other users");
+ return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only privileged users may register machines for other users");
+ }
case RUNTIME_SCOPE_USER:
/* In user mode the user owning our instance may register anything. */
assert_not_reached();
}
- if (manager->runtime_scope != RUNTIME_SCOPE_USER) {
- const char *details[] = {
- "name", name,
- "class", machine_class_to_string(c),
- NULL
- };
-
- r = bus_verify_polkit_async(
- message,
- polkit_action,
- details,
- &manager->polkit_registry,
- error);
- if (r <= 0)
- return r; /* 0 means Polkit will call us back, see method_create_machine() */
- }
-
r = manager_add_machine(manager, name, &m);
if (r < 0)
return r;