]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
polkit: check if user authenticated as admin
authorLuca Boccassi <luca.boccassi@gmail.com>
Fri, 19 Sep 2025 23:49:00 +0000 (00:49 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Thu, 25 Jun 2026 09:39:11 +0000 (10:39 +0100)
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.

16 files changed:
src/ask-password/ask-password.c
src/home/homed-home-bus.c
src/hostname/hostnamed.c
src/locale/localed.c
src/login/logind-dbus.c
src/login/logind-session-dbus.c
src/login/logind-shutdown.c
src/login/logind-user-dbus.c
src/machine/machine-dbus.c
src/machine/machine-varlink.c
src/mountfsd/mountwork.c
src/nsresourced/nsresourcework.c
src/resolve/resolved-dnssd-bus.c
src/shared/bus-polkit.c
src/shared/bus-polkit.h
src/timedate/timedated.c

index 17d839e98dd489800253b47a49d4999e47e460e6..fd0def44f1f8845fe55f70a89b56b090f393bdd4 100644 (file)
@@ -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;
 
index 10b9af8e026fc1ebe67cefbd3e3b6d30526ba0db..ec26b63f1dd5a31c7d76d5358346b449fc713180 100644 (file)
@@ -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;
index 31afe1ebfcd6b65da212900f32c0bf1fcc517681..99de3f23f6f48ae2308d5d61477ad9f5312a8a31 100644 (file)
@@ -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 */
 
index 041ba29cd8a3986efe00caa31219e2be04ec4be4..4296db6f2f9b4fa9fca9b26397424c8f3d4a8b79 100644 (file)
@@ -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;
index 4afc4952b0184346df4c5217c4f02317a103ae89..7472cf8ec41c4fcdc273538dcf72cfe2e8cf7c86 100644 (file)
@@ -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;
index 90cc576fec716982d13c7bf05f95595ef917e8dc..2c8207f054e10dd50f819f84a96b2623462aae9d 100644 (file)
@@ -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;
index 064ebf8e2ff8fb22fbc2dfe534637a29923b64ce..a0a30951cc147ed51caf153d6c7948a0a3a0e8dc 100644 (file)
@@ -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;
index ca32e8b05602b3097e9c841460e57a342da4f486..a6cab9ee653e15597265d1c58d24a3d8715918a0 100644 (file)
@@ -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;
index 624ec4848ae0853b0f033ce9523ccffb06af4080..cf1d3d6bdbc305bca8cd76925bef0af3c03606a2 100644 (file)
@@ -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;
index d9524c75e17471e5886ef357307cc4bcd1e64d6d..7c4c05865b818eeae66d395d60f74885c5c6f333 100644 (file)
@@ -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;
         }
index 9f469d6061fdecb26d59412f2e109cb853f7fcdf..4cd4e4abdd244427740c6ef8f4bd9661cd75168f 100644 (file)
@@ -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;
 
index 9595a2e3f5249a4e5b640c776ae6a0bebef93da0..b8d68cbb427e1737d670f9dfeed1017b9611b63e 100644 (file)
@@ -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;
 
index 4459b0444c3adef6f9b27dac21f6e099e451ffb1..17eab683b77dff88f30cc06e415e318ddafef097 100644 (file)
@@ -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;
index 9c1b11a274fc52c12d612db3fb70a909e667b3aa..73fae1140ba7d66d2fa414c6dc885c3dedfa80c5 100644 (file)
 #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
 }
index 9ce8de4f0227b429a4da770c22c72fe01794d883..887ed2a55bc886eda19deca057049a905b37b166 100644 (file)
@@ -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);
index 43cf3fddb9da69438148dac1588f8f9de16275f9..5d20e6ca0616f5c5efe79039e5be9b8b46c125b2 100644 (file)
@@ -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;