mirror of
https://github.com/systemd/systemd.git
synced 2026-06-30 19:57:29 +00:00
machined: allow privileged users to register other users machines (#39042)
Requires https://github.com/polkit-org/polkit/pull/591
This commit is contained in:
@@ -267,7 +267,8 @@ static int vl_method_ask(sd_varlink *link, sd_json_variant *parameters, sd_varli
|
||||
/* details= */ NULL,
|
||||
/* good_user= */ FLAGS_SET(arg_flags, ASK_PASSWORD_USER) ? getuid() : UID_INVALID,
|
||||
/* flags= */ 0,
|
||||
polkit_registry);
|
||||
polkit_registry,
|
||||
/* ret_admin= */ NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -109,6 +109,7 @@ static int home_verify_polkit_async(
|
||||
good_uid,
|
||||
/* flags= */ 0,
|
||||
&h->manager->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
}
|
||||
|
||||
@@ -196,6 +197,7 @@ int bus_home_method_activate(
|
||||
h->uid,
|
||||
/* flags= */ 0,
|
||||
&h->manager->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1431,6 +1431,7 @@ static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *
|
||||
/* good_user= */ UID_INVALID,
|
||||
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
|
||||
&c->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -1480,6 +1481,7 @@ static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_
|
||||
/* good_user= */ UID_INVALID,
|
||||
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
|
||||
&c->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -1557,6 +1559,7 @@ static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_mess
|
||||
/* good_user= */ UID_INVALID,
|
||||
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
|
||||
&c->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -1700,6 +1703,7 @@ static int method_set_tags(sd_bus_message *m, void *userdata, sd_bus_error *erro
|
||||
/* good_user= */ UID_INVALID,
|
||||
/* flags= */ 0,
|
||||
&c->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -1789,6 +1793,7 @@ static int method_add_and_remove_tags(sd_bus_message *m, void *userdata, sd_bus_
|
||||
/* good_user= */ UID_INVALID,
|
||||
/* flags= */ 0,
|
||||
&c->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -1821,6 +1826,7 @@ static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_err
|
||||
/* good_user= */ UID_INVALID,
|
||||
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
|
||||
&c->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -2242,7 +2248,8 @@ static int vl_method_describe(sd_varlink *link, sd_json_variant *parameters, sd_
|
||||
/* details= */ NULL,
|
||||
UID_INVALID,
|
||||
POLKIT_DONT_REPLY,
|
||||
&c->polkit_registry);
|
||||
&c->polkit_registry,
|
||||
/* ret_admin= */ NULL);
|
||||
if (r == 0)
|
||||
return 0; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
||||
|
||||
|
||||
@@ -280,6 +280,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er
|
||||
/* good_user= */ UID_INVALID,
|
||||
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
|
||||
&c->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -384,6 +385,7 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro
|
||||
/* good_user= */ UID_INVALID,
|
||||
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
|
||||
&c->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -503,6 +505,7 @@ static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_err
|
||||
/* good_user= */ UID_INVALID,
|
||||
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
|
||||
&c->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1645,6 +1645,7 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu
|
||||
/* good_user= */ UID_INVALID,
|
||||
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
|
||||
&m->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -1821,6 +1822,7 @@ static int method_attach_device(sd_bus_message *message, void *userdata, sd_bus_
|
||||
/* good_user= */ UID_INVALID,
|
||||
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
|
||||
&m->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -1851,6 +1853,7 @@ static int method_flush_devices(sd_bus_message *message, void *userdata, sd_bus_
|
||||
/* good_user= */ UID_INVALID,
|
||||
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
|
||||
&m->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -207,6 +207,7 @@ int bus_session_method_terminate(sd_bus_message *message, void *userdata, sd_bus
|
||||
s->user->user_record->uid,
|
||||
/* flags= */ 0,
|
||||
&s->manager->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -252,6 +253,7 @@ int bus_session_method_lock(sd_bus_message *message, void *userdata, sd_bus_erro
|
||||
s->user->user_record->uid,
|
||||
/* flags= */ 0,
|
||||
&s->manager->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -362,6 +364,7 @@ int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_erro
|
||||
s->user->user_record->uid,
|
||||
/* flags= */ 0,
|
||||
&s->manager->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -112,6 +112,7 @@ int manager_verify_shutdown_creds(
|
||||
/* good_user= */ UID_INVALID,
|
||||
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
|
||||
&m->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
else
|
||||
r = varlink_verify_polkit_async_full(
|
||||
@@ -121,7 +122,8 @@ int manager_verify_shutdown_creds(
|
||||
/* details= */ NULL,
|
||||
/* good_user= */ UID_INVALID,
|
||||
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
|
||||
&m->polkit_registry);
|
||||
&m->polkit_registry,
|
||||
/* ret_admin= */ NULL);
|
||||
|
||||
if (r < 0) {
|
||||
/* If we get -EBUSY, it means a polkit decision was made, but not for
|
||||
@@ -173,6 +175,7 @@ int manager_verify_shutdown_creds(
|
||||
/* good_user= */ UID_INVALID,
|
||||
polkit_flags,
|
||||
&m->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
else
|
||||
r = varlink_verify_polkit_async_full(
|
||||
@@ -182,7 +185,8 @@ int manager_verify_shutdown_creds(
|
||||
/* details= */ NULL,
|
||||
/* good_user= */ UID_INVALID,
|
||||
polkit_flags,
|
||||
&m->polkit_registry);
|
||||
&m->polkit_registry,
|
||||
/* ret_admin= */ NULL);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -199,6 +203,7 @@ int manager_verify_shutdown_creds(
|
||||
/* good_user= */ UID_INVALID,
|
||||
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
|
||||
&m->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
else
|
||||
r = varlink_verify_polkit_async_full(
|
||||
@@ -208,7 +213,8 @@ int manager_verify_shutdown_creds(
|
||||
/* details= */ NULL,
|
||||
/* good_user= */ UID_INVALID,
|
||||
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
|
||||
&m->polkit_registry);
|
||||
&m->polkit_registry,
|
||||
/* ret_admin= */ NULL);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -202,6 +202,7 @@ int bus_user_method_terminate(sd_bus_message *message, void *userdata, sd_bus_er
|
||||
u->user_record->uid,
|
||||
/* flags= */ 0,
|
||||
&u->manager->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -229,6 +230,7 @@ int bus_user_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *
|
||||
u->user_record->uid,
|
||||
/* flags= */ 0,
|
||||
&u->manager->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -70,6 +70,7 @@ int bus_machine_method_unregister(sd_bus_message *message, void *userdata, sd_bu
|
||||
m->uid,
|
||||
/* flags= */ 0,
|
||||
&m->manager->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -104,6 +105,7 @@ int bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus
|
||||
m->uid,
|
||||
/* flags= */ 0,
|
||||
&m->manager->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -156,6 +158,7 @@ int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_erro
|
||||
m->uid,
|
||||
/* flags= */ 0,
|
||||
&m->manager->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -299,6 +302,7 @@ int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_
|
||||
m->uid,
|
||||
/* flags= */ 0,
|
||||
&m->manager->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -344,6 +348,7 @@ int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bu
|
||||
m->uid,
|
||||
/* flags= */ 0,
|
||||
&m->manager->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -462,6 +467,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
|
||||
m->uid,
|
||||
/* flags= */ 0,
|
||||
&m->manager->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -126,6 +126,7 @@ static int machine_cid(const char *name, sd_json_variant *variant, sd_json_dispa
|
||||
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[] = {
|
||||
@@ -160,13 +161,16 @@ int vl_method_register(sd_varlink *link, sd_json_variant *parameters, sd_varlink
|
||||
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;
|
||||
}
|
||||
@@ -196,7 +200,7 @@ int vl_method_register(sd_varlink *link, sd_json_variant *parameters, sd_varlink
|
||||
/* 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;
|
||||
@@ -323,7 +327,8 @@ int vl_method_unregister_internal(sd_varlink *link, sd_json_variant *parameters,
|
||||
"verb", "unregister"),
|
||||
machine->uid,
|
||||
/* flags= */ 0,
|
||||
&manager->polkit_registry);
|
||||
&manager->polkit_registry,
|
||||
/* ret_admin= */ NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
}
|
||||
@@ -349,7 +354,8 @@ int vl_method_terminate_internal(sd_varlink *link, sd_json_variant *parameters,
|
||||
"verb", "terminate"),
|
||||
machine->uid,
|
||||
/* flags= */ 0,
|
||||
&manager->polkit_registry);
|
||||
&manager->polkit_registry,
|
||||
/* ret_admin= */ NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
}
|
||||
@@ -417,7 +423,8 @@ int vl_method_kill(sd_varlink *link, sd_json_variant *parameters, sd_varlink_met
|
||||
"verb", "kill"),
|
||||
machine->uid,
|
||||
/* flags= */ 0,
|
||||
&manager->polkit_registry);
|
||||
&manager->polkit_registry,
|
||||
/* ret_admin= */ NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
}
|
||||
@@ -583,7 +590,8 @@ int vl_method_open(sd_varlink *link, sd_json_variant *parameters, sd_varlink_met
|
||||
(const char**) polkit_details,
|
||||
machine->uid,
|
||||
/* flags= */ 0,
|
||||
&manager->polkit_registry);
|
||||
&manager->polkit_registry,
|
||||
/* ret_admin= */ NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -279,12 +279,33 @@ static int machine_add_from_params(
|
||||
/* 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;
|
||||
@@ -292,7 +313,8 @@ static int machine_add_from_params(
|
||||
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. */
|
||||
@@ -306,23 +328,6 @@ static int machine_add_from_params(
|
||||
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;
|
||||
|
||||
@@ -502,7 +502,8 @@ static int vl_method_mount_image(
|
||||
polkit_details,
|
||||
/* good_user= */ UID_INVALID,
|
||||
polkit_flags,
|
||||
polkit_registry);
|
||||
polkit_registry,
|
||||
/* ret_admin= */ NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
@@ -541,7 +542,7 @@ static int vl_method_mount_image(
|
||||
|
||||
/* Let's see if we have acquired the privilege to mount untrusted images already */
|
||||
bool polkit_have_untrusted_action =
|
||||
varlink_has_polkit_action(link, polkit_untrusted_action, polkit_details, polkit_registry);
|
||||
varlink_has_polkit_action(link, polkit_untrusted_action, polkit_details, polkit_registry, /* ret_admin= */ NULL);
|
||||
|
||||
for (;;) {
|
||||
use_policy = image_policy_free(use_policy);
|
||||
@@ -594,7 +595,8 @@ static int vl_method_mount_image(
|
||||
polkit_details,
|
||||
/* good_user= */ UID_INVALID,
|
||||
/* flags= */ 0, /* NB: the image cannot be authenticated, hence unless PK is around to allow this anyway, fail! */
|
||||
polkit_registry);
|
||||
polkit_registry,
|
||||
/* ret_admin= */ NULL);
|
||||
if (r <= 0 && !ERRNO_IS_NEG_PRIVILEGE(r))
|
||||
return r;
|
||||
if (r > 0) {
|
||||
@@ -672,7 +674,8 @@ static int vl_method_mount_image(
|
||||
polkit_details,
|
||||
/* good_user= */ UID_INVALID,
|
||||
/* flags= */ 0, /* NB: the image cannot be authenticated, hence unless PK is around to allow this anyway, fail! */
|
||||
polkit_registry);
|
||||
polkit_registry,
|
||||
/* ret_admin= */ NULL);
|
||||
if (r <= 0 && !ERRNO_IS_NEG_PRIVILEGE(r))
|
||||
return r;
|
||||
if (r > 0) {
|
||||
@@ -1167,7 +1170,8 @@ static int vl_method_mount_directory(
|
||||
polkit_details,
|
||||
/* good_user= */ UID_INVALID,
|
||||
trusted_directory ? polkit_flags : 0,
|
||||
polkit_registry);
|
||||
polkit_registry,
|
||||
/* ret_admin= */ NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
@@ -1400,7 +1404,8 @@ static int vl_method_make_directory(
|
||||
polkit_details,
|
||||
/* good_user= */ UID_INVALID,
|
||||
polkit_flags,
|
||||
polkit_registry);
|
||||
polkit_registry,
|
||||
/* ret_admin= */ NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -1427,7 +1427,8 @@ static int vl_method_allocate_user_range(sd_varlink *link, sd_json_variant *para
|
||||
polkit_details,
|
||||
/* good_user= */ UID_INVALID,
|
||||
POLKIT_DEFAULT_ALLOW, /* If no polkit is installed, allow unpriv userns namespace allocation */
|
||||
&c->polkit_registry);
|
||||
&c->polkit_registry,
|
||||
/* ret_admin= */ NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
@@ -1692,7 +1693,8 @@ static int vl_method_register_user_namespace(sd_varlink *link, sd_json_variant *
|
||||
polkit_details,
|
||||
/* good_user= */ UID_INVALID,
|
||||
POLKIT_DEFAULT_ALLOW, /* If no polkit is installed, allow unpriv userns namespace registration */
|
||||
&c->polkit_registry);
|
||||
&c->polkit_registry,
|
||||
/* ret_admin= */ NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
@@ -1839,7 +1841,8 @@ static int vl_method_add_mount_to_user_namespace(sd_varlink *link, sd_json_varia
|
||||
/* details= */ NULL,
|
||||
/* good_user= */ UID_INVALID,
|
||||
POLKIT_DEFAULT_ALLOW, /* If no polkit is installed, allow delegation of mounts to registered userns */
|
||||
&c->polkit_registry);
|
||||
&c->polkit_registry,
|
||||
/* ret_admin= */ NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
@@ -1998,7 +2001,8 @@ static int vl_method_add_cgroup_to_user_namespace(sd_varlink *link, sd_json_vari
|
||||
/* details= */ NULL,
|
||||
/* good_user= */ UID_INVALID,
|
||||
POLKIT_DEFAULT_ALLOW, /* If no polkit is installed, allow delegation of cgroups to registered userns */
|
||||
&c->polkit_registry);
|
||||
&c->polkit_registry,
|
||||
/* ret_admin= */ NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
@@ -2397,7 +2401,8 @@ static int vl_method_add_netif_to_user_namespace(sd_varlink *link, sd_json_varia
|
||||
polkit_details,
|
||||
/* good_user= */ UID_INVALID,
|
||||
POLKIT_DEFAULT_ALLOW, /* If no polkit is installed, allow delegation of network interfaces to registered userns */
|
||||
&c->polkit_registry);
|
||||
&c->polkit_registry,
|
||||
/* ret_admin= */ NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ int bus_dnssd_method_unregister(sd_bus_message *message, void *userdata, sd_bus_
|
||||
/* good_user= */ s->originator,
|
||||
/* flags= */ 0,
|
||||
&m->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -17,15 +17,18 @@
|
||||
#include "strv.h"
|
||||
#include "varlink-util.h"
|
||||
|
||||
static int bus_message_check_good_user(sd_bus_message *m, uid_t good_user) {
|
||||
static int bus_message_check_good_user(sd_bus_message *m, uid_t good_user, bool *ret_admin) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
uid_t sender_uid;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (good_user == UID_INVALID)
|
||||
if (good_user == UID_INVALID) {
|
||||
if (ret_admin)
|
||||
*ret_admin = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds);
|
||||
if (r < 0)
|
||||
@@ -38,6 +41,9 @@ static int bus_message_check_good_user(sd_bus_message *m, uid_t good_user) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret_admin)
|
||||
*ret_admin = sender_uid == 0;
|
||||
|
||||
return sender_uid == good_user;
|
||||
}
|
||||
|
||||
@@ -121,7 +127,7 @@ int bus_test_polkit(
|
||||
|
||||
/* Tests non-interactively! */
|
||||
|
||||
r = bus_message_check_good_user(call, good_user);
|
||||
r = bus_message_check_good_user(call, good_user, /* ret_admin= */ NULL);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
@@ -178,6 +184,7 @@ int bus_test_polkit(
|
||||
typedef struct AsyncPolkitQueryAction {
|
||||
char *action;
|
||||
char **details;
|
||||
bool admin; /* true when the action was authorized by auth_admin/auth_admin_keep (i.e.: by a privileged user) */
|
||||
|
||||
LIST_FIELDS(struct AsyncPolkitQueryAction, authorized);
|
||||
} AsyncPolkitQueryAction;
|
||||
@@ -312,8 +319,41 @@ static int async_polkit_read_reply(sd_bus_message *reply, AsyncPolkitQuery *q) {
|
||||
}
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
|
||||
if (r >= 0)
|
||||
r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'a', "{ss}");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (;;) {
|
||||
const char *k, *v;
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'e', "ss");
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
r = sd_bus_message_read(reply, "ss", &k, &v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0 && streq(k, "polkit.result") && STR_IN_SET(v, "auth_admin_keep", "auth_admin"))
|
||||
a->admin = true;
|
||||
|
||||
r = sd_bus_message_exit_container(reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_exit_container(reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_exit_container(reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -411,14 +451,22 @@ static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_e
|
||||
static bool async_polkit_query_have_action(
|
||||
AsyncPolkitQuery *q,
|
||||
const char *action,
|
||||
const char **details) {
|
||||
const char **details,
|
||||
/* Reports whether the subject authenticated as admin, instead of a regular user */
|
||||
bool *ret_admin) {
|
||||
|
||||
assert(q);
|
||||
assert(action);
|
||||
|
||||
LIST_FOREACH(authorized, a, q->authorized_actions)
|
||||
if (streq(a->action, action) && strv_equal(a->details, (char**) details))
|
||||
if (streq(a->action, action) && strv_equal(a->details, (char**) details)) {
|
||||
if (ret_admin)
|
||||
*ret_admin = a->admin;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ret_admin)
|
||||
*ret_admin = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -428,13 +476,19 @@ static int async_polkit_query_check_action(
|
||||
const char *action,
|
||||
const char **details,
|
||||
PolkitFlags flags,
|
||||
bool *ret_admin,
|
||||
sd_bus_error *reterr_error) {
|
||||
|
||||
bool admin = false; /* Not privileged until proven otherwise */
|
||||
|
||||
assert(q);
|
||||
assert(action);
|
||||
|
||||
if (async_polkit_query_have_action(q, action, details))
|
||||
if (async_polkit_query_have_action(q, action, details, &admin)) {
|
||||
if (ret_admin)
|
||||
*ret_admin = admin;
|
||||
return 1; /* Allow! */
|
||||
}
|
||||
|
||||
if (q->error_action && streq(q->error_action->action, action))
|
||||
return sd_bus_error_copy(reterr_error, &q->error);
|
||||
@@ -442,13 +496,21 @@ static int async_polkit_query_check_action(
|
||||
if (q->denied_action && streq(q->denied_action->action, action))
|
||||
return -EACCES; /* Deny! */
|
||||
|
||||
if (q->absent_action)
|
||||
return FLAGS_SET(flags, POLKIT_DEFAULT_ALLOW) ? 1 /* Allow! */ : -EACCES /* Deny! */;
|
||||
if (q->absent_action) {
|
||||
if (!FLAGS_SET(flags, POLKIT_DEFAULT_ALLOW))
|
||||
return -EACCES;
|
||||
if (ret_admin)
|
||||
*ret_admin = admin;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Also deny if we've got an auth. failure for a previous action */
|
||||
if (q->denied_action || q->error_action)
|
||||
return -EBUSY;
|
||||
|
||||
if (ret_admin)
|
||||
*ret_admin = admin;
|
||||
|
||||
return 0; /* no reply yet */
|
||||
}
|
||||
#endif
|
||||
@@ -541,8 +603,10 @@ int bus_verify_polkit_async_full(
|
||||
uid_t good_user,
|
||||
PolkitFlags flags,
|
||||
Hashmap **registry,
|
||||
bool *ret_admin,
|
||||
sd_bus_error *reterr_error) {
|
||||
|
||||
bool admin = false; /* Not privileged until proven otherwise */
|
||||
int r;
|
||||
|
||||
assert(call);
|
||||
@@ -551,9 +615,12 @@ int bus_verify_polkit_async_full(
|
||||
|
||||
log_debug("Trying to acquire polkit authentication for '%s'.", action);
|
||||
|
||||
r = bus_message_check_good_user(call, good_user);
|
||||
if (r != 0)
|
||||
r = bus_message_check_good_user(call, good_user, &admin);
|
||||
if (r != 0) {
|
||||
if (r > 0 && ret_admin)
|
||||
*ret_admin = admin;
|
||||
return r;
|
||||
}
|
||||
|
||||
#if ENABLE_POLKIT
|
||||
_cleanup_(async_polkit_query_unrefp) AsyncPolkitQuery *q = NULL;
|
||||
@@ -562,8 +629,10 @@ int bus_verify_polkit_async_full(
|
||||
/* This is a repeated invocation of this function, hence let's check if we've already got
|
||||
* a response from polkit for this action */
|
||||
if (q) {
|
||||
r = async_polkit_query_check_action(q, action, details, flags, reterr_error);
|
||||
r = async_polkit_query_check_action(q, action, details, flags, &admin, reterr_error);
|
||||
if (r != 0) {
|
||||
if (r > 0 && ret_admin)
|
||||
*ret_admin = admin;
|
||||
log_debug("Found matching previous polkit authentication for '%s'.", action);
|
||||
return r;
|
||||
}
|
||||
@@ -575,8 +644,11 @@ int bus_verify_polkit_async_full(
|
||||
r = sd_bus_query_sender_privilege(call, /* capability= */ -1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
if (r > 0) {
|
||||
if (ret_admin)
|
||||
*ret_admin = true;
|
||||
return 1;
|
||||
}
|
||||
#if ENABLE_POLKIT
|
||||
}
|
||||
|
||||
@@ -629,25 +701,38 @@ int bus_verify_polkit_async_full(
|
||||
|
||||
TAKE_PTR(q);
|
||||
|
||||
if (ret_admin)
|
||||
*ret_admin = admin;
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return FLAGS_SET(flags, POLKIT_DEFAULT_ALLOW) ? 1 : -EACCES;
|
||||
if (!FLAGS_SET(flags, POLKIT_DEFAULT_ALLOW))
|
||||
return -EACCES;
|
||||
if (ret_admin)
|
||||
*ret_admin = admin;
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int varlink_check_good_user(sd_varlink *link, uid_t good_user) {
|
||||
static int varlink_check_good_user(sd_varlink *link, uid_t good_user, bool *ret_admin) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
if (good_user == UID_INVALID)
|
||||
if (good_user == UID_INVALID) {
|
||||
if (ret_admin)
|
||||
*ret_admin = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
uid_t peer_uid;
|
||||
r = sd_varlink_get_peer_uid(link, &peer_uid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret_admin)
|
||||
*ret_admin = peer_uid == 0;
|
||||
|
||||
return good_user == peer_uid;
|
||||
}
|
||||
|
||||
@@ -762,8 +847,10 @@ int varlink_verify_polkit_async_full(
|
||||
const char **details,
|
||||
uid_t good_user,
|
||||
PolkitFlags flags,
|
||||
Hashmap **registry) {
|
||||
Hashmap **registry,
|
||||
bool *ret_admin) {
|
||||
|
||||
bool admin = false; /* Not privileged until proven otherwise */
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
@@ -774,16 +861,22 @@ int varlink_verify_polkit_async_full(
|
||||
/* This is the same as bus_verify_polkit_async_full(), but authenticates the peer of a varlink
|
||||
* connection rather than the sender of a bus message. */
|
||||
|
||||
r = varlink_check_good_user(link, good_user);
|
||||
if (r != 0)
|
||||
r = varlink_check_good_user(link, good_user, &admin);
|
||||
if (r != 0) {
|
||||
if (r > 0 && ret_admin)
|
||||
*ret_admin = admin;
|
||||
return r;
|
||||
}
|
||||
|
||||
#if ENABLE_POLKIT
|
||||
if (!FLAGS_SET(flags, POLKIT_ALWAYS_QUERY)) {
|
||||
#endif
|
||||
r = varlink_check_peer_privilege(link);
|
||||
if (r != 0)
|
||||
if (r != 0) {
|
||||
if (r > 0 && ret_admin)
|
||||
*ret_admin = true;
|
||||
return r;
|
||||
}
|
||||
#if ENABLE_POLKIT
|
||||
}
|
||||
|
||||
@@ -794,7 +887,7 @@ int varlink_verify_polkit_async_full(
|
||||
* a response from polkit for this action */
|
||||
if (q) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
r = async_polkit_query_check_action(q, action, details, flags, &error);
|
||||
r = async_polkit_query_check_action(q, action, details, flags, &admin, &error);
|
||||
if (r != 0)
|
||||
log_debug("Found matching previous polkit authentication for '%s'.", action);
|
||||
if (r < 0) {
|
||||
@@ -808,8 +901,11 @@ int varlink_verify_polkit_async_full(
|
||||
|
||||
return r;
|
||||
}
|
||||
if (r > 0)
|
||||
if (r > 0) {
|
||||
if (ret_admin)
|
||||
*ret_admin = admin;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
_cleanup_(sd_bus_unrefp) sd_bus *mybus = NULL;
|
||||
@@ -871,13 +967,20 @@ int varlink_verify_polkit_async_full(
|
||||
|
||||
TAKE_PTR(q);
|
||||
|
||||
if (ret_admin)
|
||||
*ret_admin = admin;
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return FLAGS_SET(flags, POLKIT_DEFAULT_ALLOW) ? 1 : -EACCES;
|
||||
if (!FLAGS_SET(flags, POLKIT_DEFAULT_ALLOW))
|
||||
return -EACCES;
|
||||
if (ret_admin)
|
||||
*ret_admin = admin;
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool varlink_has_polkit_action(sd_varlink *link, const char *action, const char **details, Hashmap **registry) {
|
||||
bool varlink_has_polkit_action(sd_varlink *link, const char *action, const char **details, Hashmap **registry, bool *ret_admin) {
|
||||
assert(link);
|
||||
assert(action);
|
||||
assert(registry);
|
||||
@@ -889,8 +992,10 @@ bool varlink_has_polkit_action(sd_varlink *link, const char *action, const char
|
||||
if (!q)
|
||||
return false;
|
||||
|
||||
return async_polkit_query_have_action(q, action, details);
|
||||
return async_polkit_query_have_action(q, action, details, ret_admin);
|
||||
#else
|
||||
if (ret_admin)
|
||||
*ret_admin = false; /* Not privileged until proven otherwise */
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@ typedef enum PolkitFlags {
|
||||
|
||||
int bus_test_polkit(sd_bus_message *call, const char *action, const char **details, uid_t good_user, bool *ret_challenge, sd_bus_error *reterr_error);
|
||||
|
||||
int bus_verify_polkit_async_full(sd_bus_message *call, const char *action, const char **details, uid_t good_user, PolkitFlags flags, Hashmap **registry, sd_bus_error *reterr_error);
|
||||
int bus_verify_polkit_async_full(sd_bus_message *call, const char *action, const char **details, uid_t good_user, PolkitFlags flags, Hashmap **registry, bool *ret_admin, sd_bus_error *reterr_error);
|
||||
static inline int bus_verify_polkit_async(sd_bus_message *call, const char *action, const char **details, Hashmap **registry, sd_bus_error *reterr_error) {
|
||||
return bus_verify_polkit_async_full(call, action, details, UID_INVALID, 0, registry, reterr_error);
|
||||
return bus_verify_polkit_async_full(call, action, details, UID_INVALID, 0, registry, NULL, reterr_error);
|
||||
}
|
||||
|
||||
int varlink_verify_polkit_async_full(sd_varlink *link, sd_bus *bus, const char *action, const char **details, uid_t good_user, PolkitFlags flags, Hashmap **registry);
|
||||
int varlink_verify_polkit_async_full(sd_varlink *link, sd_bus *bus, const char *action, const char **details, uid_t good_user, PolkitFlags flags, Hashmap **registry, bool *ret_admin);
|
||||
static inline int varlink_verify_polkit_async(sd_varlink *link, sd_bus *bus, const char *action, const char **details, Hashmap **registry) {
|
||||
return varlink_verify_polkit_async_full(link, bus, action, details, UID_INVALID, 0, registry);
|
||||
return varlink_verify_polkit_async_full(link, bus, action, details, UID_INVALID, 0, registry, NULL);
|
||||
}
|
||||
|
||||
/* A sd_json_dispatch_field initializer that makes sure the allowInteractiveAuthentication boolean field we want for
|
||||
@@ -43,4 +43,4 @@ extern const sd_json_dispatch_field dispatch_table_polkit_only[];
|
||||
SD_VARLINK_FIELD_COMMENT("Controls whether interactive authentication (via polkit) shall be allowed. If unspecified defaults to false."), \
|
||||
SD_VARLINK_DEFINE_INPUT(allowInteractiveAuthentication, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE)
|
||||
|
||||
bool varlink_has_polkit_action(sd_varlink *link, const char *action, const char **details, Hashmap **registry);
|
||||
bool varlink_has_polkit_action(sd_varlink *link, const char *action, const char **details, Hashmap **registry, bool *ret_admin);
|
||||
|
||||
@@ -693,6 +693,7 @@ static int method_set_timezone(sd_bus_message *m, void *userdata, sd_bus_error *
|
||||
/* good_user= */ UID_INVALID,
|
||||
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
|
||||
&c->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -768,6 +769,7 @@ static int method_set_local_rtc(sd_bus_message *m, void *userdata, sd_bus_error
|
||||
/* good_user= */ UID_INVALID,
|
||||
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
|
||||
&c->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -904,6 +906,7 @@ static int method_set_time(sd_bus_message *m, void *userdata, sd_bus_error *erro
|
||||
/* good_user= */ UID_INVALID,
|
||||
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
|
||||
&c->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -970,6 +973,7 @@ static int method_set_ntp(sd_bus_message *m, void *userdata, sd_bus_error *error
|
||||
/* good_user= */ UID_INVALID,
|
||||
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
|
||||
&c->polkit_registry,
|
||||
/* ret_admin= */ NULL,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
Reference in New Issue
Block a user