From: Luca Boccassi Date: Fri, 19 Sep 2025 23:49:00 +0000 (+0100) Subject: polkit: check if user authenticated as admin X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5ce1786227bad8481169cbf9101b2cff56bd297b;p=thirdparty%2Fsystemd.git polkit: check if user authenticated as admin The new polkit will return a new detail regarding a successful authentication: the actual result type, which we can use to see whether the user authenticated as admin. This can be used to grant additional privileges. --- diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c index 17d839e98dd..fd0def44f1f 100644 --- a/src/ask-password/ask-password.c +++ b/src/ask-password/ask-password.c @@ -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; diff --git a/src/home/homed-home-bus.c b/src/home/homed-home-bus.c index 10b9af8e026..ec26b63f1dd 100644 --- a/src/home/homed-home-bus.c +++ b/src/home/homed-home-bus.c @@ -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; diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index 31afe1ebfcd..99de3f23f6f 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -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 */ diff --git a/src/locale/localed.c b/src/locale/localed.c index 041ba29cd8a..4296db6f2f9 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -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; diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 4afc4952b01..7472cf8ec41 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -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; diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index 90cc576fec7..2c8207f054e 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -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; diff --git a/src/login/logind-shutdown.c b/src/login/logind-shutdown.c index 064ebf8e2ff..a0a30951cc1 100644 --- a/src/login/logind-shutdown.c +++ b/src/login/logind-shutdown.c @@ -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; diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c index ca32e8b0560..a6cab9ee653 100644 --- a/src/login/logind-user-dbus.c +++ b/src/login/logind-user-dbus.c @@ -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; diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index 624ec4848ae..cf1d3d6bdbc 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -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; diff --git a/src/machine/machine-varlink.c b/src/machine/machine-varlink.c index d9524c75e17..7c4c05865b8 100644 --- a/src/machine/machine-varlink.c +++ b/src/machine/machine-varlink.c @@ -323,7 +323,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 +350,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 +419,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 +586,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; } diff --git a/src/mountfsd/mountwork.c b/src/mountfsd/mountwork.c index 9f469d6061f..4cd4e4abdd2 100644 --- a/src/mountfsd/mountwork.c +++ b/src/mountfsd/mountwork.c @@ -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; diff --git a/src/nsresourced/nsresourcework.c b/src/nsresourced/nsresourcework.c index 9595a2e3f52..b8d68cbb427 100644 --- a/src/nsresourced/nsresourcework.c +++ b/src/nsresourced/nsresourcework.c @@ -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; diff --git a/src/resolve/resolved-dnssd-bus.c b/src/resolve/resolved-dnssd-bus.c index 4459b0444c3..17eab683b77 100644 --- a/src/resolve/resolved-dnssd-bus.c +++ b/src/resolve/resolved-dnssd-bus.c @@ -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; diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c index 9c1b11a274f..73fae1140ba 100644 --- a/src/shared/bus-polkit.c +++ b/src/shared/bus-polkit.c @@ -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 } diff --git a/src/shared/bus-polkit.h b/src/shared/bus-polkit.h index 9ce8de4f022..887ed2a55bc 100644 --- a/src/shared/bus-polkit.h +++ b/src/shared/bus-polkit.h @@ -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); diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 43cf3fddb9d..5d20e6ca061 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -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;