Bug#956216: buster-pu: package systemd/241-7~deb10u3

Michael Biebl biebl at debian.org
Wed Apr 8 15:11:31 BST 2020


Package: release.debian.org
Severity: normal
Tags: buster
User: release.debian.org at packages.debian.org
Usertags: pu

Hi,

I'd like to make a stable/buster upload for systemd fixing CVE-2020-1712
https://security-tracker.debian.org/tracker/CVE-2020-1712
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=950732

After talking to the security team (namely Salvatore), we decided to fix
this issue via a stable upload.

The debdiff is a bit on the larger side, unfortunately.
Salvatore made a smaller backport avoiding some of the refactorings
that were done upstream
https://salsa.debian.org/systemd-team/systemd/-/merge_requests/69

I decided to go with the backport provided by upstream that was done for
the v241-stable branch mainly for two reasons:
- It makes potential future cherry-picks easier
- Doing our own backport has the potential to introduce Debian specific
  bugs

That said, if you prefer the more minimal backport from Salvatore,
please let me know and I'll redo the upload accordingly.

The changes are available at
https://salsa.debian.org/systemd-team/systemd/-/commits/debian/buster-proposed/

The debdiff is attached.

udev should not be affected (I've CCed kibi for his review/ACK)

Regards,
Michael


-- System Information:
Debian Release: bullseye/sid
  APT prefers unstable
  APT policy: (500, 'unstable'), (200, 'experimental')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 5.4.0-4-amd64 (SMP w/4 CPU cores)
Locale: LANG=de_DE.UTF-8, LC_CTYPE=de_DE.UTF-8 (charmap=UTF-8), LANGUAGE=de_DE.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled
-------------- next part --------------
diff --git a/debian/changelog b/debian/changelog
index 1d263f7..f8b017d 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,13 @@
+systemd (241-7~deb10u4) buster; urgency=medium
+
+  * polkit: when authorizing via PolicyKit re-resolve callback/userdata
+    instead of caching it.
+    This fixes a heap use-after-free vulnerability in systemd, when
+    asynchronous PolicyKit queries are performed while handling DBus messages.
+    (CVE-2020-1712, Closes: #950732)
+
+ -- Michael Biebl <biebl at debian.org>  Wed, 08 Apr 2020 15:58:24 +0200
+
 systemd (241-7~deb10u3) buster; urgency=medium
 
   * core: set fs.file-max sysctl to LONG_MAX rather than ULONG_MAX.
diff --git a/debian/patches/Fix-typo-in-function-name.patch b/debian/patches/Fix-typo-in-function-name.patch
new file mode 100644
index 0000000..4f3c521
--- /dev/null
+++ b/debian/patches/Fix-typo-in-function-name.patch
@@ -0,0 +1,77 @@
+From: =?utf-8?q?Zbigniew_J=C4=99drzejewski-Szmek?= <zbyszek at in.waw.pl>
+Date: Tue, 4 Feb 2020 18:39:04 +0100
+Subject: Fix typo in function name
+
+(cherry picked from commit bc130b6858327b382b07b3985cf48e2aa9016b2d)
+(cherry picked from commit b4eb8848240c3540180e4768216a0b884a5ed783)
+(cherry picked from commit f14fa558ae9e139c94ee3af4a1ef1df313b2ff66)
+(cherry picked from commit dd8aa0871d9cafa60a916d4ec01dd82d64edf7ed)
+---
+ TODO                                | 2 +-
+ src/libsystemd/sd-bus/bus-message.h | 2 +-
+ src/libsystemd/sd-bus/sd-bus.c      | 8 ++++----
+ src/shared/bus-polkit.c             | 2 +-
+ 4 files changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/TODO b/TODO
+index 462db57..327fead 100644
+--- a/TODO
++++ b/TODO
+@@ -138,7 +138,7 @@ Features:
+ 
+ * the a-posteriori stopping of units bound to units that disappeared logic
+   should be reworked: there should be a queue of units, and we should only
+-  enqeue stop jobs from a defer event that processes queue instead of
++  enqueue stop jobs from a defer event that processes queue instead of
+   right-away when we find a unit that is bound to one that doesn't exist
+   anymore. (similar to how the stop-unneeded queue has been reworked the same
+   way)
+diff --git a/src/libsystemd/sd-bus/bus-message.h b/src/libsystemd/sd-bus/bus-message.h
+index 7fd3f11..849d638 100644
+--- a/src/libsystemd/sd-bus/bus-message.h
++++ b/src/libsystemd/sd-bus/bus-message.h
+@@ -211,4 +211,4 @@ int bus_message_remarshal(sd_bus *bus, sd_bus_message **m);
+ 
+ void bus_message_set_sender_driver(sd_bus *bus, sd_bus_message *m);
+ void bus_message_set_sender_local(sd_bus *bus, sd_bus_message *m);
+-int sd_bus_enqeue_for_read(sd_bus *bus, sd_bus_message *m);
++int sd_bus_enqueue_for_read(sd_bus *bus, sd_bus_message *m);
+diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
+index 94380af..c20adcf 100644
+--- a/src/libsystemd/sd-bus/sd-bus.c
++++ b/src/libsystemd/sd-bus/sd-bus.c
+@@ -4145,7 +4145,7 @@ _public_ int sd_bus_get_close_on_exit(sd_bus *bus) {
+         return bus->close_on_exit;
+ }
+ 
+-int sd_bus_enqeue_for_read(sd_bus *bus, sd_bus_message *m) {
++int sd_bus_enqueue_for_read(sd_bus *bus, sd_bus_message *m) {
+         int r;
+ 
+         assert_return(bus, -EINVAL);
+@@ -4157,9 +4157,9 @@ int sd_bus_enqeue_for_read(sd_bus *bus, sd_bus_message *m) {
+         if (!BUS_IS_OPEN(bus->state))
+                 return -ENOTCONN;
+ 
+-        /* Re-enqeue a message for reading. This is primarily useful for PolicyKit-style authentication,
+-         * where we want accept a message, then determine we need to interactively authenticate the user, and
+-         * when we have that process the message again. */
++        /* Re-enqueue a message for reading. This is primarily useful for PolicyKit-style authentication,
++         * where we accept a message, then determine we need to interactively authenticate the user, and then
++         * we want to process the message again. */
+ 
+         r = bus_rqueue_make_room(bus);
+         if (r < 0)
+diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c
+index 02c11aa..d1d2456 100644
+--- a/src/shared/bus-polkit.c
++++ b/src/shared/bus-polkit.c
+@@ -236,7 +236,7 @@ static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_e
+         if (r < 0)
+                 goto fail;
+ 
+-        r = sd_bus_enqeue_for_read(sd_bus_message_get_bus(q->request), q->request);
++        r = sd_bus_enqueue_for_read(sd_bus_message_get_bus(q->request), q->request);
+         if (r < 0)
+                 goto fail;
+ 
diff --git a/debian/patches/bus-polkit-rename-return-error-parameter-to-ret_error.patch b/debian/patches/bus-polkit-rename-return-error-parameter-to-ret_error.patch
new file mode 100644
index 0000000..a7c9cc5
--- /dev/null
+++ b/debian/patches/bus-polkit-rename-return-error-parameter-to-ret_error.patch
@@ -0,0 +1,67 @@
+From: Lennart Poettering <lennart at poettering.net>
+Date: Wed, 22 Jan 2020 14:29:43 +0100
+Subject: bus-polkit: rename return error parameter to ret_error
+
+(cherry picked from commit 773b1a7916bfce3aa2a21ecf534d475032e8528e)
+(cherry picked from commit 5b2442d5c3ec1c86a3a8d1c1abe3234a570ba5e6)
+(cherry picked from commit 4441844d5889a39d9d059c30e5d94c916d9d6735)
+(cherry picked from commit 816d5e2d6dd83a3bd0ff56a352295831cb937198)
+---
+ src/shared/bus-polkit.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c
+index da4aee5..f93aa17 100644
+--- a/src/shared/bus-polkit.c
++++ b/src/shared/bus-polkit.c
+@@ -37,7 +37,7 @@ int bus_test_polkit(
+                 const char **details,
+                 uid_t good_user,
+                 bool *_challenge,
+-                sd_bus_error *e) {
++                sd_bus_error *ret_error) {
+ 
+         int r;
+ 
+@@ -102,11 +102,11 @@ int bus_test_polkit(
+                 if (r < 0)
+                         return r;
+ 
+-                r = sd_bus_call(call->bus, request, 0, e, &reply);
++                r = sd_bus_call(call->bus, request, 0, ret_error, &reply);
+                 if (r < 0) {
+                         /* Treat no PK available as access denied */
+-                        if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
+-                                sd_bus_error_free(e);
++                        if (sd_bus_error_has_name(ret_error, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
++                                sd_bus_error_free(ret_error);
+                                 return -EACCES;
+                         }
+ 
+@@ -196,7 +196,7 @@ int bus_verify_polkit_async(
+                 bool interactive,
+                 uid_t good_user,
+                 Hashmap **registry,
+-                sd_bus_error *error) {
++                sd_bus_error *ret_error) {
+ 
+ #if ENABLE_POLKIT
+         _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL;
+@@ -237,7 +237,7 @@ int bus_verify_polkit_async(
+                                 return -EACCES;
+ 
+                         /* Copy error from polkit reply */
+-                        sd_bus_error_copy(error, e);
++                        sd_bus_error_copy(ret_error, e);
+                         return -sd_bus_error_get_errno(e);
+                 }
+ 
+@@ -251,7 +251,7 @@ int bus_verify_polkit_async(
+                         return 1;
+ 
+                 if (challenge)
+-                        return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
++                        return sd_bus_error_set(ret_error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
+ 
+                 return -EACCES;
+         }
diff --git a/debian/patches/bus-util-treat-org.freedesktop.DBus.Error.ServiceUnknown-.patch b/debian/patches/bus-util-treat-org.freedesktop.DBus.Error.ServiceUnknown-.patch
new file mode 100644
index 0000000..ffd349f
--- /dev/null
+++ b/debian/patches/bus-util-treat-org.freedesktop.DBus.Error.ServiceUnknown-.patch
@@ -0,0 +1,34 @@
+From: Yu Watanabe <watanabe.yu+github at gmail.com>
+Date: Thu, 4 Apr 2019 13:35:29 +0900
+Subject: bus-util: treat org.freedesktop.DBus.Error.ServiceUnknown nicely
+ when polkit does not exist
+
+Fixes #12209.
+
+(cherry picked from commit 8c69fe79df6394f6b8b8d0bb536a265caf417868)
+(cherry picked from commit 0bb488b22144aeb87d93e97123f71babe116261f)
+---
+ src/shared/bus-util.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
+index 9d31fba..a406dd8 100644
+--- a/src/shared/bus-util.c
++++ b/src/shared/bus-util.c
+@@ -410,14 +410,14 @@ int bus_verify_polkit_async(
+                 if (sd_bus_message_is_method_error(q->reply, NULL)) {
+                         const sd_bus_error *e;
+ 
+-                        /* Copy error from polkit reply */
+                         e = sd_bus_message_get_error(q->reply);
+-                        sd_bus_error_copy(error, e);
+ 
+                         /* Treat no PK available as access denied */
+                         if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
+                                 return -EACCES;
+ 
++                        /* Copy error from polkit reply */
++                        sd_bus_error_copy(error, e);
+                         return -sd_bus_error_get_errno(e);
+                 }
+ 
diff --git a/debian/patches/debian/Use-Debian-specific-config-files.patch b/debian/patches/debian/Use-Debian-specific-config-files.patch
index ba4d9ba..1ad2608 100644
--- a/debian/patches/debian/Use-Debian-specific-config-files.patch
+++ b/debian/patches/debian/Use-Debian-specific-config-files.patch
@@ -80,10 +80,10 @@ index aa4a89c..8f36bbe 100644
                  char *s;
  
 diff --git a/src/locale/keymap-util.c b/src/locale/keymap-util.c
-index 6b6b32a..cb63d45 100644
+index c203c7a..f4ee123 100644
 --- a/src/locale/keymap-util.c
 +++ b/src/locale/keymap-util.c
-@@ -95,6 +95,7 @@ void locale_simplify(char *locale[_VARIABLE_LC_MAX]) {
+@@ -97,6 +97,7 @@ void locale_simplify(char *locale[_VARIABLE_LC_MAX]) {
  int locale_read_data(Context *c, sd_bus_message *m) {
          struct stat st;
          int r;
@@ -91,7 +91,7 @@ index 6b6b32a..cb63d45 100644
  
          /* Do not try to re-read the file within single bus operation. */
          if (m) {
-@@ -105,7 +106,11 @@ int locale_read_data(Context *c, sd_bus_message *m) {
+@@ -107,7 +108,11 @@ int locale_read_data(Context *c, sd_bus_message *m) {
                  c->locale_cache = sd_bus_message_ref(m);
          }
  
@@ -104,7 +104,7 @@ index 6b6b32a..cb63d45 100644
          if (r < 0 && errno != ENOENT)
                  return -errno;
  
-@@ -120,7 +125,7 @@ int locale_read_data(Context *c, sd_bus_message *m) {
+@@ -122,7 +127,7 @@ int locale_read_data(Context *c, sd_bus_message *m) {
                  c->locale_mtime = t;
                  context_free_locale(c);
  
@@ -113,7 +113,7 @@ index 6b6b32a..cb63d45 100644
                                     "LANG",              &c->locale[VARIABLE_LANG],
                                     "LANGUAGE",          &c->locale[VARIABLE_LANGUAGE],
                                     "LC_CTYPE",          &c->locale[VARIABLE_LC_CTYPE],
-@@ -201,8 +206,6 @@ int vconsole_read_data(Context *c, sd_bus_message *m) {
+@@ -203,8 +208,6 @@ int vconsole_read_data(Context *c, sd_bus_message *m) {
  }
  
  int x11_read_data(Context *c, sd_bus_message *m) {
@@ -122,7 +122,7 @@ index 6b6b32a..cb63d45 100644
          struct stat st;
          usec_t t;
          int r;
-@@ -216,7 +219,7 @@ int x11_read_data(Context *c, sd_bus_message *m) {
+@@ -218,7 +221,7 @@ int x11_read_data(Context *c, sd_bus_message *m) {
                  c->x11_cache = sd_bus_message_ref(m);
          }
  
@@ -131,7 +131,7 @@ index 6b6b32a..cb63d45 100644
                  if (errno != ENOENT)
                          return -errno;
  
-@@ -233,61 +236,14 @@ int x11_read_data(Context *c, sd_bus_message *m) {
+@@ -235,61 +238,14 @@ int x11_read_data(Context *c, sd_bus_message *m) {
          c->x11_mtime = t;
          context_free_x11(c);
  
@@ -200,7 +200,7 @@ index 6b6b32a..cb63d45 100644
  
          return 0;
  }
-@@ -296,9 +252,18 @@ int locale_write_data(Context *c, char ***settings) {
+@@ -298,9 +254,18 @@ int locale_write_data(Context *c, char ***settings) {
          _cleanup_strv_free_ char **l = NULL;
          struct stat st;
          int r, p;
@@ -219,7 +219,7 @@ index 6b6b32a..cb63d45 100644
          for (p = 0; p < _VARIABLE_LC_MAX; p++) {
                  _cleanup_free_ char *t = NULL;
                  char **u;
-@@ -321,20 +286,20 @@ int locale_write_data(Context *c, char ***settings) {
+@@ -323,20 +288,20 @@ int locale_write_data(Context *c, char ***settings) {
          }
  
          if (strv_isempty(l)) {
@@ -243,7 +243,7 @@ index 6b6b32a..cb63d45 100644
                  c->locale_mtime = timespec_load(&st.st_mtim);
  
          return 0;
-@@ -402,70 +367,104 @@ int vconsole_write_data(Context *c) {
+@@ -404,70 +369,104 @@ int vconsole_write_data(Context *c) {
  }
  
  int x11_write_data(Context *c) {
@@ -392,7 +392,7 @@ index 6b6b32a..cb63d45 100644
          return r;
  }
 diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c
-index 324d4a4..4d54ac3 100644
+index 398d4f4..d681d58 100644
 --- a/src/timedate/timedated.c
 +++ b/src/timedate/timedated.c
 @@ -215,6 +215,7 @@ static int context_read_data(Context *c) {
diff --git a/debian/patches/polkit-on-async-pk-requests-re-validate-action-details.patch b/debian/patches/polkit-on-async-pk-requests-re-validate-action-details.patch
new file mode 100644
index 0000000..c6ffacf
--- /dev/null
+++ b/debian/patches/polkit-on-async-pk-requests-re-validate-action-details.patch
@@ -0,0 +1,81 @@
+From: Lennart Poettering <lennart at poettering.net>
+Date: Wed, 22 Jan 2020 16:52:10 +0100
+Subject: polkit: on async pk requests, re-validate action/details
+
+When we do an async pk request, let's store which action/details we used
+for the original request, and when we are called for the second time,
+let's compare. If the action/details changed, let's not allow the access
+to go through.
+
+(cherry picked from commit 7f56982289275ce84e20f0554475864953e6aaab)
+(cherry picked from commit 0697d0d972c8d91395eb539a8e87e4aec8b37b75)
+(cherry picked from commit 54791aff01aa93a8b621808d80ab506b54f245c8)
+(cherry picked from commit 70d0f5ea5952a0cedd84c352070613df4ba5fc8f)
+---
+ src/shared/bus-polkit.c | 30 +++++++++++++++++++++++++++---
+ 1 file changed, 27 insertions(+), 3 deletions(-)
+
+diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c
+index 81193b8..6343dd6 100644
+--- a/src/shared/bus-polkit.c
++++ b/src/shared/bus-polkit.c
+@@ -155,6 +155,9 @@ int bus_test_polkit(
+ #if ENABLE_POLKIT
+ 
+ typedef struct AsyncPolkitQuery {
++        char *action;
++        char **details;
++
+         sd_bus_message *request, *reply;
+         sd_bus_message_handler_t callback;
+         void *userdata;
+@@ -175,6 +178,9 @@ static void async_polkit_query_free(AsyncPolkitQuery *q) {
+         sd_bus_message_unref(q->request);
+         sd_bus_message_unref(q->reply);
+ 
++        free(q->action);
++        strv_free(q->details);
++
+         free(q);
+ }
+ 
+@@ -239,11 +245,17 @@ int bus_verify_polkit_async(
+         if (q) {
+                 int authorized, challenge;
+ 
+-                /* This is the second invocation of this function, and
+-                 * there's already a response from polkit, let's
+-                 * process it */
++                /* This is the second invocation of this function, and there's already a response from
++                 * polkit, let's process it */
+                 assert(q->reply);
+ 
++                /* If the operation we want to authenticate changed between the first and the second time,
++                 * let's not use this authentication, it might be out of date as the object and context we
++                 * operate on might have changed. */
++                if (!streq(q->action, action) ||
++                    !strv_equal(q->details, (char**) details))
++                        return -ESTALE;
++
+                 if (sd_bus_message_is_method_error(q->reply, NULL)) {
+                         const sd_bus_error *e;
+ 
+@@ -339,6 +351,18 @@ int bus_verify_polkit_async(
+         q->callback = callback;
+         q->userdata = userdata;
+ 
++        q->action = strdup(action);
++        if (!q->action) {
++                async_polkit_query_free(q);
++                return -ENOMEM;
++        }
++
++        q->details = strv_copy((char**) details);
++        if (!q->details) {
++                async_polkit_query_free(q);
++                return -ENOMEM;
++        }
++
+         r = hashmap_put(*registry, call, q);
+         if (r < 0) {
+                 async_polkit_query_free(q);
diff --git a/debian/patches/polkit-reuse-some-common-bus-message-appending-code.patch b/debian/patches/polkit-reuse-some-common-bus-message-appending-code.patch
new file mode 100644
index 0000000..98e43ca
--- /dev/null
+++ b/debian/patches/polkit-reuse-some-common-bus-message-appending-code.patch
@@ -0,0 +1,107 @@
+From: Lennart Poettering <lennart at poettering.net>
+Date: Wed, 22 Jan 2020 16:44:43 +0100
+Subject: polkit: reuse some common bus message appending code
+
+(cherry picked from commit 95f82ae9d774f3508ce89dcbdd0714ef7385df59)
+(cherry picked from commit 2589995acdb297a073270b54d8fff54b98fa57e9)
+(cherry picked from commit 81532beddcc3b7946a573e15641742c452c66db7)
+(cherry picked from commit 18b7b7fe307f03928bfea3ef0663048b7be6e4fb)
+---
+ src/shared/bus-polkit.c | 56 ++++++++++++++++++++++++++++---------------------
+ 1 file changed, 32 insertions(+), 24 deletions(-)
+
+diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c
+index f93aa17..81193b8 100644
+--- a/src/shared/bus-polkit.c
++++ b/src/shared/bus-polkit.c
+@@ -30,6 +30,34 @@ static int check_good_user(sd_bus_message *m, uid_t good_user) {
+         return sender_uid == good_user;
+ }
+ 
++#if ENABLE_POLKIT
++static int bus_message_append_strv_key_value(
++                sd_bus_message *m,
++                const char **l) {
++
++        const char **k, **v;
++        int r;
++
++        assert(m);
++
++        r = sd_bus_message_open_container(m, 'a', "{ss}");
++        if (r < 0)
++                return r;
++
++        STRV_FOREACH_PAIR(k, v, l) {
++                r = sd_bus_message_append(m, "{ss}", *k, *v);
++                if (r < 0)
++                        return r;
++        }
++
++        r = sd_bus_message_close_container(m);
++        if (r < 0)
++                return r;
++
++        return r;
++}
++#endif
++
+ int bus_test_polkit(
+                 sd_bus_message *call,
+                 int capability,
+@@ -60,7 +88,7 @@ int bus_test_polkit(
+                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *request = NULL;
+                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+                 int authorized = false, challenge = false;
+-                const char *sender, **k, **v;
++                const char *sender;
+ 
+                 sender = sd_bus_message_get_sender(call);
+                 if (!sender)
+@@ -84,17 +112,7 @@ int bus_test_polkit(
+                 if (r < 0)
+                         return r;
+ 
+-                r = sd_bus_message_open_container(request, 'a', "{ss}");
+-                if (r < 0)
+-                        return r;
+-
+-                STRV_FOREACH_PAIR(k, v, details) {
+-                        r = sd_bus_message_append(request, "{ss}", *k, *v);
+-                        if (r < 0)
+-                                return r;
+-                }
+-
+-                r = sd_bus_message_close_container(request);
++                r = bus_message_append_strv_key_value(request, details);
+                 if (r < 0)
+                         return r;
+ 
+@@ -201,7 +219,7 @@ int bus_verify_polkit_async(
+ #if ENABLE_POLKIT
+         _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL;
+         AsyncPolkitQuery *q;
+-        const char *sender, **k, **v;
++        const char *sender;
+         sd_bus_message_handler_t callback;
+         void *userdata;
+         int c;
+@@ -305,17 +323,7 @@ int bus_verify_polkit_async(
+         if (r < 0)
+                 return r;
+ 
+-        r = sd_bus_message_open_container(pk, 'a', "{ss}");
+-        if (r < 0)
+-                return r;
+-
+-        STRV_FOREACH_PAIR(k, v, details) {
+-                r = sd_bus_message_append(pk, "{ss}", *k, *v);
+-                if (r < 0)
+-                        return r;
+-        }
+-
+-        r = sd_bus_message_close_container(pk);
++        r = bus_message_append_strv_key_value(pk, details);
+         if (r < 0)
+                 return r;
+ 
diff --git a/debian/patches/polkit-use-structured-initialization.patch b/debian/patches/polkit-use-structured-initialization.patch
new file mode 100644
index 0000000..683fb3b
--- /dev/null
+++ b/debian/patches/polkit-use-structured-initialization.patch
@@ -0,0 +1,36 @@
+From: Lennart Poettering <lennart at poettering.net>
+Date: Wed, 22 Jan 2020 16:53:59 +0100
+Subject: polkit: use structured initialization
+
+(cherry picked from commit f4425c72c7395ec93ae00052916a66e2f60f200b)
+(cherry picked from commit 5926f9f1723fd753a0c524ed96a13538c851395e)
+(cherry picked from commit 4d80c8f158333117dabb0e6f7592059cddb1d6d0)
+(cherry picked from commit 9131bb3d45e6384309eea42affd1aa757ef28cd7)
+---
+ src/shared/bus-polkit.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c
+index 6343dd6..c42c39a 100644
+--- a/src/shared/bus-polkit.c
++++ b/src/shared/bus-polkit.c
+@@ -343,13 +343,15 @@ int bus_verify_polkit_async(
+         if (r < 0)
+                 return r;
+ 
+-        q = new0(AsyncPolkitQuery, 1);
++        q = new(AsyncPolkitQuery, 1);
+         if (!q)
+                 return -ENOMEM;
+ 
+-        q->request = sd_bus_message_ref(call);
+-        q->callback = callback;
+-        q->userdata = userdata;
++        *q = (AsyncPolkitQuery) {
++                .request = sd_bus_message_ref(call),
++                .callback = callback,
++                .userdata = userdata,
++        };
+ 
+         q->action = strdup(action);
+         if (!q->action) {
diff --git a/debian/patches/polkit-when-authorizing-via-PK-let-s-re-resolve-callback-.patch b/debian/patches/polkit-when-authorizing-via-PK-let-s-re-resolve-callback-.patch
new file mode 100644
index 0000000..2175b78
--- /dev/null
+++ b/debian/patches/polkit-when-authorizing-via-PK-let-s-re-resolve-callback-.patch
@@ -0,0 +1,166 @@
+From: Lennart Poettering <lennart at poettering.net>
+Date: Wed, 22 Jan 2020 17:07:47 +0100
+Subject: polkit: when authorizing via PK let's re-resolve callback/userdata
+ instead of caching it
+
+Previously, when doing an async PK query we'd store the original
+callback/userdata pair and call it again after the PK request is
+complete. This is problematic, since PK queries might be slow and in the
+meantime the userdata might be released and re-acquired. Let's avoid
+this by always traversing through the message handlers so that we always
+re-resolve the callback and userdata pair and thus can be sure it's
+up-to-date and properly valid.
+
+(cherry picked from commit 637486261528e8aa3da9f26a4487dc254f4b7abb)
+(cherry picked from commit e2d4cb9843c50eff76e9104fec6b448c0d7c8814)
+(cherry picked from commit fb21e13e8ecbe25d80c1219b14e6495795df18ef)
+(cherry picked from commit c3141774dfb84b1526c4991bb775457c739eb179)
+---
+ src/shared/bus-polkit.c | 78 ++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 52 insertions(+), 26 deletions(-)
+
+diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c
+index c42c39a..02c11aa 100644
+--- a/src/shared/bus-polkit.c
++++ b/src/shared/bus-polkit.c
+@@ -159,14 +159,13 @@ typedef struct AsyncPolkitQuery {
+         char **details;
+ 
+         sd_bus_message *request, *reply;
+-        sd_bus_message_handler_t callback;
+-        void *userdata;
+         sd_bus_slot *slot;
++
+         Hashmap *registry;
++        sd_event_source *defer_event_source;
+ } AsyncPolkitQuery;
+ 
+ static void async_polkit_query_free(AsyncPolkitQuery *q) {
+-
+         if (!q)
+                 return;
+ 
+@@ -181,9 +180,24 @@ static void async_polkit_query_free(AsyncPolkitQuery *q) {
+         free(q->action);
+         strv_free(q->details);
+ 
++        if (q->defer_event_source)
++                (void) sd_event_source_set_enabled(q->defer_event_source, SD_EVENT_OFF);
++        sd_event_source_unref(q->defer_event_source);
+         free(q);
+ }
+ 
++static int async_polkit_defer(sd_event_source *s, void *userdata) {
++        AsyncPolkitQuery *q = userdata;
++
++        assert(s);
++
++        /* This is called as idle event source after we processed the async polkit reply, hopefully after the
++         * method call we re-enqueued has been properly processed. */
++
++        async_polkit_query_free(q);
++        return 0;
++}
++
+ static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
+         _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+         AsyncPolkitQuery *q = userdata;
+@@ -192,21 +206,46 @@ static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_e
+         assert(reply);
+         assert(q);
+ 
++        assert(q->slot);
+         q->slot = sd_bus_slot_unref(q->slot);
++
++        assert(!q->reply);
+         q->reply = sd_bus_message_ref(reply);
+ 
++        /* Now, let's dispatch the original message a second time be re-enqueing. This will then traverse the
++         * whole message processing again, and thus re-validating and re-retrieving the "userdata" field
++         * again.
++         *
++         * We install an idle event loop event to clean-up the PolicyKit request data when we are idle again,
++         * i.e. after the second time the message is processed is complete. */
++
++        assert(!q->defer_event_source);
++        r = sd_event_add_defer(sd_bus_get_event(sd_bus_message_get_bus(reply)), &q->defer_event_source, async_polkit_defer, q);
++        if (r < 0)
++                goto fail;
++
++        r = sd_event_source_set_priority(q->defer_event_source, SD_EVENT_PRIORITY_IDLE);
++        if (r < 0)
++                goto fail;
++
++        r = sd_event_source_set_enabled(q->defer_event_source, SD_EVENT_ONESHOT);
++        if (r < 0)
++                goto fail;
++
+         r = sd_bus_message_rewind(q->request, true);
+-        if (r < 0) {
+-                r = sd_bus_reply_method_errno(q->request, r, NULL);
+-                goto finish;
+-        }
++        if (r < 0)
++                goto fail;
++
++        r = sd_bus_enqeue_for_read(sd_bus_message_get_bus(q->request), q->request);
++        if (r < 0)
++                goto fail;
+ 
+-        r = q->callback(q->request, q->userdata, &error_buffer);
+-        r = bus_maybe_reply_error(q->request, r, &error_buffer);
++        return 1;
+ 
+-finish:
++fail:
++        log_debug_errno(r, "Processing asynchronous PolicyKit reply failed, ignoring: %m");
++        (void) sd_bus_reply_method_errno(q->request, r, NULL);
+         async_polkit_query_free(q);
+-
+         return r;
+ }
+ 
+@@ -225,11 +264,9 @@ int bus_verify_polkit_async(
+ #if ENABLE_POLKIT
+         _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL;
+         AsyncPolkitQuery *q;
+-        const char *sender;
+-        sd_bus_message_handler_t callback;
+-        void *userdata;
+         int c;
+ #endif
++        const char *sender;
+         int r;
+ 
+         assert(call);
+@@ -293,20 +330,11 @@ int bus_verify_polkit_async(
+         else if (r > 0)
+                 return 1;
+ 
+-#if ENABLE_POLKIT
+-        if (sd_bus_get_current_message(call->bus) != call)
+-                return -EINVAL;
+-
+-        callback = sd_bus_get_current_handler(call->bus);
+-        if (!callback)
+-                return -EINVAL;
+-
+-        userdata = sd_bus_get_current_userdata(call->bus);
+-
+         sender = sd_bus_message_get_sender(call);
+         if (!sender)
+                 return -EBADMSG;
+ 
++#if ENABLE_POLKIT
+         c = sd_bus_message_get_allow_interactive_authorization(call);
+         if (c < 0)
+                 return c;
+@@ -349,8 +377,6 @@ int bus_verify_polkit_async(
+ 
+         *q = (AsyncPolkitQuery) {
+                 .request = sd_bus_message_ref(call),
+-                .callback = callback,
+-                .userdata = userdata,
+         };
+ 
+         q->action = strdup(action);
diff --git a/debian/patches/resolve-fix-memleak.patch b/debian/patches/resolve-fix-memleak.patch
new file mode 100644
index 0000000..f37f322
--- /dev/null
+++ b/debian/patches/resolve-fix-memleak.patch
@@ -0,0 +1,32 @@
+From: Yu Watanabe <watanabe.yu+github at gmail.com>
+Date: Fri, 12 Jul 2019 14:19:36 +0900
+Subject: resolve: fix memleak
+
+(cherry picked from commit 2400ae29a55aab8659fa778f02d1884b86a95062)
+(cherry picked from commit 7727e6c0ae1769ba7ea9959aa721236c025adbdf)
+(cherry picked from commit 9755ac0744f858cfa952033552ac6f2401e0f2d0)
+---
+ src/resolve/resolved-manager.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
+index b3d35c8..2017b0e 100644
+--- a/src/resolve/resolved-manager.c
++++ b/src/resolve/resolved-manager.c
+@@ -11,6 +11,7 @@
+ 
+ #include "af-list.h"
+ #include "alloc-util.h"
++#include "bus-util.h"
+ #include "dirent-util.h"
+ #include "dns-domain.h"
+ #include "fd-util.h"
+@@ -689,6 +690,8 @@ Manager *manager_free(Manager *m) {
+         manager_mdns_stop(m);
+         manager_dns_stub_stop(m);
+ 
++        bus_verify_polkit_async_registry_free(m->polkit_registry);
++
+         sd_bus_flush_close_unref(m->bus);
+ 
+         sd_event_source_unref(m->sigusr1_event_source);
diff --git a/debian/patches/sd-bus-introduce-API-for-re-enqueuing-incoming-messages.patch b/debian/patches/sd-bus-introduce-API-for-re-enqueuing-incoming-messages.patch
new file mode 100644
index 0000000..a628fdd
--- /dev/null
+++ b/debian/patches/sd-bus-introduce-API-for-re-enqueuing-incoming-messages.patch
@@ -0,0 +1,65 @@
+From: Lennart Poettering <lennart at poettering.net>
+Date: Wed, 22 Jan 2020 17:05:17 +0100
+Subject: sd-bus: introduce API for re-enqueuing incoming messages
+
+When authorizing via PolicyKit we want to process incoming method calls
+twice: once to process and figure out that we need PK authentication,
+and a second time after we aquired PK authentication to actually execute
+the operation. With this new call sd_bus_enqueue_for_read() we have a
+way to put an incoming message back into the read queue for this
+purpose.
+
+This might have other uses too, for example debugging.
+
+(cherry picked from commit 1068447e6954dc6ce52f099ed174c442cb89ed54)
+
+zjs: patch modified to not make the function public
+(cherry picked from commit 83bfc0d8dd026814d23e3fdfa46806394f775526)
+(cherry picked from commit 2e504c92d195d407cec3ba9ed156b195c31a5f3f)
+(cherry picked from commit 351627d4bfa39dd05f28d889967383af2372de6d)
+---
+ src/libsystemd/sd-bus/bus-message.h |  1 +
+ src/libsystemd/sd-bus/sd-bus.c      | 24 ++++++++++++++++++++++++
+ 2 files changed, 25 insertions(+)
+
+diff --git a/src/libsystemd/sd-bus/bus-message.h b/src/libsystemd/sd-bus/bus-message.h
+index 0115437..7fd3f11 100644
+--- a/src/libsystemd/sd-bus/bus-message.h
++++ b/src/libsystemd/sd-bus/bus-message.h
+@@ -211,3 +211,4 @@ int bus_message_remarshal(sd_bus *bus, sd_bus_message **m);
+ 
+ void bus_message_set_sender_driver(sd_bus *bus, sd_bus_message *m);
+ void bus_message_set_sender_local(sd_bus *bus, sd_bus_message *m);
++int sd_bus_enqeue_for_read(sd_bus *bus, sd_bus_message *m);
+diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
+index 1ff858f..94380af 100644
+--- a/src/libsystemd/sd-bus/sd-bus.c
++++ b/src/libsystemd/sd-bus/sd-bus.c
+@@ -4144,3 +4144,27 @@ _public_ int sd_bus_get_close_on_exit(sd_bus *bus) {
+ 
+         return bus->close_on_exit;
+ }
++
++int sd_bus_enqeue_for_read(sd_bus *bus, sd_bus_message *m) {
++        int r;
++
++        assert_return(bus, -EINVAL);
++        assert_return(bus = bus_resolve(bus), -ENOPKG);
++        assert_return(m, -EINVAL);
++        assert_return(m->sealed, -EINVAL);
++        assert_return(!bus_pid_changed(bus), -ECHILD);
++
++        if (!BUS_IS_OPEN(bus->state))
++                return -ENOTCONN;
++
++        /* Re-enqeue a message for reading. This is primarily useful for PolicyKit-style authentication,
++         * where we want accept a message, then determine we need to interactively authenticate the user, and
++         * when we have that process the message again. */
++
++        r = bus_rqueue_make_room(bus);
++        if (r < 0)
++                return r;
++
++        bus->rqueue[bus->rqueue_size++] = sd_bus_message_ref(m);
++        return 0;
++}
diff --git a/debian/patches/series b/debian/patches/series
index d1a5bd2..1f3cd3d 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -42,6 +42,8 @@ mount-remove-unused-mount_is_auto-and-mount_is_automount.patch
 core-set-fs.file-max-sysctl-to-LONG_MAX-rather-than-ULONG.patch
 execute-remove-one-redundant-comparison-check.patch
 core-change-ownership-mode-of-the-execution-directories-a.patch
+bus-util-treat-org.freedesktop.DBus.Error.ServiceUnknown-.patch
+resolve-fix-memleak.patch
 debian/Use-Debian-specific-config-files.patch
 debian/Bring-tmpfiles.d-tmp.conf-in-line-with-Debian-defaul.patch
 debian/Make-run-lock-tmpfs-an-API-fs.patch
diff --git a/debian/patches/shared-split-out-polkit-stuff-from-bus-util.c-bus-polkit..patch b/debian/patches/shared-split-out-polkit-stuff-from-bus-util.c-bus-polkit..patch
new file mode 100644
index 0000000..3a14551
--- /dev/null
+++ b/debian/patches/shared-split-out-polkit-stuff-from-bus-util.c-bus-polkit..patch
@@ -0,0 +1,1190 @@
+From: Lennart Poettering <lennart at poettering.net>
+Date: Wed, 22 Jan 2020 11:39:22 +0100
+Subject: =?utf-8?q?shared=3A_split_out_polkit_stuff_from_bus-util=2Ec_?=
+ =?utf-8?q?=E2=86=92_bus-polkit=2Ec?=
+
+It's enough, complex stuff to warrant its own source file.
+
+No other changes, just splitting out.
+
+(cherry picked from commit 269e4d2d6b75329ae39a71ebe2c14500e03cda95)
+(cherry picked from commit 0a19ff7004e4a567566a0a7be6b050cf34c0bfe5)
+(cherry picked from commit 31a1d569db43af04669ec487f3e741ddc6d12969)
+(cherry picked from commit a4722a8df23f6612c47f1bb848a6a7c81dcbdccb)
+---
+ src/core/dbus-unit.c               |   1 +
+ src/core/dbus.c                    |   2 +-
+ src/hostname/hostnamed.c           |   2 +-
+ src/import/importd.c               |   2 +-
+ src/locale/keymap-util.c           |   2 +
+ src/locale/localed.c               |   2 +-
+ src/login/logind-dbus.c            |   1 +
+ src/login/logind-seat-dbus.c       |   1 +
+ src/login/logind-session-dbus.c    |   1 +
+ src/login/logind-user-dbus.c       |   1 +
+ src/login/logind.c                 |   2 +-
+ src/machine/image-dbus.c           |   1 +
+ src/machine/machine-dbus.c         |   1 +
+ src/machine/machined-dbus.c        |   1 +
+ src/machine/machined.c             |   2 +-
+ src/network/networkd-link-bus.c    |   2 +
+ src/network/networkd-manager-bus.c |   3 +
+ src/network/networkd-manager.c     |   1 +
+ src/portable/portabled-bus.c       |   2 +-
+ src/portable/portabled-image-bus.c |   1 +
+ src/portable/portabled.c           |   2 +-
+ src/resolve/resolved-bus.c         |   1 +
+ src/resolve/resolved-dnssd-bus.c   |   5 +-
+ src/resolve/resolved-link-bus.c    |   1 +
+ src/resolve/resolved-manager.c     |   2 +-
+ src/shared/bus-polkit.c            | 358 +++++++++++++++++++++++++++++++++++++
+ src/shared/bus-polkit.h            |  11 ++
+ src/shared/bus-util.c              | 357 +-----------------------------------
+ src/shared/bus-util.h              |   7 +-
+ src/shared/meson.build             |   2 +
+ src/timedate/timedated.c           |   2 +-
+ 31 files changed, 406 insertions(+), 373 deletions(-)
+ create mode 100644 src/shared/bus-polkit.c
+ create mode 100644 src/shared/bus-polkit.h
+
+diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
+index 17c2003..ce0fbdb 100644
+--- a/src/core/dbus-unit.c
++++ b/src/core/dbus-unit.c
+@@ -5,6 +5,7 @@
+ #include "alloc-util.h"
+ #include "bpf-firewall.h"
+ #include "bus-common-errors.h"
++#include "bus-polkit.h"
+ #include "cgroup-util.h"
+ #include "condition.h"
+ #include "dbus-job.h"
+diff --git a/src/core/dbus.c b/src/core/dbus.c
+index 255b86e..91c06ce 100644
+--- a/src/core/dbus.c
++++ b/src/core/dbus.c
+@@ -10,7 +10,7 @@
+ #include "bus-common-errors.h"
+ #include "bus-error.h"
+ #include "bus-internal.h"
+-#include "bus-util.h"
++#include "bus-polkit.h"
+ #include "dbus-automount.h"
+ #include "dbus-cgroup.h"
+ #include "dbus-device.h"
+diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c
+index 7777450..9b98f32 100644
+--- a/src/hostname/hostnamed.c
++++ b/src/hostname/hostnamed.c
+@@ -7,7 +7,7 @@
+ 
+ #include "alloc-util.h"
+ #include "bus-common-errors.h"
+-#include "bus-util.h"
++#include "bus-polkit.h"
+ #include "def.h"
+ #include "env-file-label.h"
+ #include "env-file.h"
+diff --git a/src/import/importd.c b/src/import/importd.c
+index 2426933..15430d8 100644
+--- a/src/import/importd.c
++++ b/src/import/importd.c
+@@ -7,7 +7,7 @@
+ 
+ #include "alloc-util.h"
+ #include "bus-common-errors.h"
+-#include "bus-util.h"
++#include "bus-polkit.h"
+ #include "def.h"
+ #include "fd-util.h"
+ #include "float.h"
+diff --git a/src/locale/keymap-util.c b/src/locale/keymap-util.c
+index 6b6b32a..c203c7a 100644
+--- a/src/locale/keymap-util.c
++++ b/src/locale/keymap-util.c
+@@ -6,7 +6,9 @@
+ #include <unistd.h>
+ 
+ #include "bus-util.h"
++#include "bus-polkit.h"
+ #include "def.h"
++#include "env-file-label.h"
+ #include "env-file.h"
+ #include "env-file-label.h"
+ #include "env-util.h"
+diff --git a/src/locale/localed.c b/src/locale/localed.c
+index f851d35..0bc02a0 100644
+--- a/src/locale/localed.c
++++ b/src/locale/localed.c
+@@ -14,7 +14,7 @@
+ #include "alloc-util.h"
+ #include "bus-error.h"
+ #include "bus-message.h"
+-#include "bus-util.h"
++#include "bus-polkit.h"
+ #include "def.h"
+ #include "keymap-util.h"
+ #include "locale-util.h"
+diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
+index b9ea370..91350fd 100644
+--- a/src/login/logind-dbus.c
++++ b/src/login/logind-dbus.c
+@@ -12,6 +12,7 @@
+ #include "audit-util.h"
+ #include "bus-common-errors.h"
+ #include "bus-error.h"
++#include "bus-polkit.h"
+ #include "bus-unit-util.h"
+ #include "bus-util.h"
+ #include "cgroup-util.h"
+diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c
+index 6ee5a1c..28ea5b7 100644
+--- a/src/login/logind-seat-dbus.c
++++ b/src/login/logind-seat-dbus.c
+@@ -6,6 +6,7 @@
+ #include "alloc-util.h"
+ #include "bus-common-errors.h"
+ #include "bus-label.h"
++#include "bus-polkit.h"
+ #include "bus-util.h"
+ #include "logind-seat.h"
+ #include "logind.h"
+diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c
+index df5bfba..bd5c1fe 100644
+--- a/src/login/logind-session-dbus.c
++++ b/src/login/logind-session-dbus.c
+@@ -6,6 +6,7 @@
+ #include "alloc-util.h"
+ #include "bus-common-errors.h"
+ #include "bus-label.h"
++#include "bus-polkit.h"
+ #include "bus-util.h"
+ #include "fd-util.h"
+ #include "logind-session-device.h"
+diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c
+index fcaeba1..129696e 100644
+--- a/src/login/logind-user-dbus.c
++++ b/src/login/logind-user-dbus.c
+@@ -4,6 +4,7 @@
+ #include <string.h>
+ 
+ #include "alloc-util.h"
++#include "bus-polkit.h"
+ #include "bus-util.h"
+ #include "format-util.h"
+ #include "logind-user.h"
+diff --git a/src/login/logind.c b/src/login/logind.c
+index 95ec0a5..171b898 100644
+--- a/src/login/logind.c
++++ b/src/login/logind.c
+@@ -10,7 +10,7 @@
+ 
+ #include "alloc-util.h"
+ #include "bus-error.h"
+-#include "bus-util.h"
++#include "bus-polkit.h"
+ #include "cgroup-util.h"
+ #include "def.h"
+ #include "device-util.h"
+diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c
+index 7e7f0d5..1322f3e 100644
+--- a/src/machine/image-dbus.c
++++ b/src/machine/image-dbus.c
+@@ -5,6 +5,7 @@
+ 
+ #include "alloc-util.h"
+ #include "bus-label.h"
++#include "bus-polkit.h"
+ #include "bus-util.h"
+ #include "copy.h"
+ #include "dissect-image.h"
+diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c
+index 7a558df..39905e5 100644
+--- a/src/machine/machine-dbus.c
++++ b/src/machine/machine-dbus.c
+@@ -15,6 +15,7 @@
+ #include "bus-common-errors.h"
+ #include "bus-internal.h"
+ #include "bus-label.h"
++#include "bus-polkit.h"
+ #include "bus-util.h"
+ #include "copy.h"
+ #include "env-file.h"
+diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c
+index fea9cc2..f00be23 100644
+--- a/src/machine/machined-dbus.c
++++ b/src/machine/machined-dbus.c
+@@ -9,6 +9,7 @@
+ #include "alloc-util.h"
+ #include "btrfs-util.h"
+ #include "bus-common-errors.h"
++#include "bus-polkit.h"
+ #include "bus-util.h"
+ #include "cgroup-util.h"
+ #include "fd-util.h"
+diff --git a/src/machine/machined.c b/src/machine/machined.c
+index 0b92b1c..e3456d8 100644
+--- a/src/machine/machined.c
++++ b/src/machine/machined.c
+@@ -8,7 +8,7 @@
+ 
+ #include "alloc-util.h"
+ #include "bus-error.h"
+-#include "bus-util.h"
++#include "bus-polkit.h"
+ #include "cgroup-util.h"
+ #include "dirent-util.h"
+ #include "fd-util.h"
+diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c
+index 0dbcd86..beee910 100644
+--- a/src/network/networkd-link-bus.c
++++ b/src/network/networkd-link-bus.c
+@@ -1,6 +1,8 @@
+ /* SPDX-License-Identifier: LGPL-2.1+ */
+ 
+ #include "alloc-util.h"
++#include "bus-common-errors.h"
++#include "bus-polkit.h"
+ #include "bus-util.h"
+ #include "networkd-link.h"
+ #include "networkd-manager.h"
+diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c
+index 8c52783..7628878 100644
+--- a/src/network/networkd-manager-bus.c
++++ b/src/network/networkd-manager-bus.c
+@@ -1,7 +1,10 @@
+ /* SPDX-License-Identifier: LGPL-2.1+ */
+ 
+ #include "alloc-util.h"
++#include "bus-common-errors.h"
++#include "bus-polkit.h"
+ #include "bus-util.h"
++#include "networkd-link.h"
+ #include "networkd-manager.h"
+ #include "strv.h"
+ 
+diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
+index acb9a75..bd29fd0 100644
+--- a/src/network/networkd-manager.c
++++ b/src/network/networkd-manager.c
+@@ -9,6 +9,7 @@
+ #include "sd-netlink.h"
+ 
+ #include "alloc-util.h"
++#include "bus-polkit.h"
+ #include "bus-util.h"
+ #include "conf-parser.h"
+ #include "def.h"
+diff --git a/src/portable/portabled-bus.c b/src/portable/portabled-bus.c
+index 3cbdb0b..708ec94 100644
+--- a/src/portable/portabled-bus.c
++++ b/src/portable/portabled-bus.c
+@@ -3,7 +3,7 @@
+ #include "alloc-util.h"
+ #include "btrfs-util.h"
+ #include "bus-common-errors.h"
+-#include "bus-util.h"
++#include "bus-polkit.h"
+ #include "fd-util.h"
+ #include "io-util.h"
+ #include "machine-image.h"
+diff --git a/src/portable/portabled-image-bus.c b/src/portable/portabled-image-bus.c
+index 3605598..beebcf8 100644
+--- a/src/portable/portabled-image-bus.c
++++ b/src/portable/portabled-image-bus.c
+@@ -3,6 +3,7 @@
+ #include "alloc-util.h"
+ #include "bus-common-errors.h"
+ #include "bus-label.h"
++#include "bus-polkit.h"
+ #include "bus-util.h"
+ #include "fd-util.h"
+ #include "fileio.h"
+diff --git a/src/portable/portabled.c b/src/portable/portabled.c
+index 49a359f..f5a34ff 100644
+--- a/src/portable/portabled.c
++++ b/src/portable/portabled.c
+@@ -4,7 +4,7 @@
+ #include "sd-daemon.h"
+ 
+ #include "alloc-util.h"
+-#include "bus-util.h"
++#include "bus-polkit.h"
+ #include "def.h"
+ #include "main-func.h"
+ #include "portabled-bus.h"
+diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
+index 5b547ba..1638d3b 100644
+--- a/src/resolve/resolved-bus.c
++++ b/src/resolve/resolved-bus.c
+@@ -2,6 +2,7 @@
+ 
+ #include "alloc-util.h"
+ #include "bus-common-errors.h"
++#include "bus-polkit.h"
+ #include "bus-util.h"
+ #include "dns-domain.h"
+ #include "missing_capability.h"
+diff --git a/src/resolve/resolved-dnssd-bus.c b/src/resolve/resolved-dnssd-bus.c
+index 24bb37b..f7dcb3b 100644
+--- a/src/resolve/resolved-dnssd-bus.c
++++ b/src/resolve/resolved-dnssd-bus.c
+@@ -1,9 +1,10 @@
++/* SPDX-License-Identifier: LGPL-2.1+ */
+ 
+ #include "alloc-util.h"
+-#include "bus-util.h"
++#include "bus-polkit.h"
+ #include "missing_capability.h"
+-#include "resolved-dnssd.h"
+ #include "resolved-dnssd-bus.h"
++#include "resolved-dnssd.h"
+ #include "resolved-link.h"
+ #include "strv.h"
+ #include "user-util.h"
+diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c
+index 96093ff..53f017c 100644
+--- a/src/resolve/resolved-link-bus.c
++++ b/src/resolve/resolved-link-bus.c
+@@ -2,6 +2,7 @@
+ 
+ #include "alloc-util.h"
+ #include "bus-common-errors.h"
++#include "bus-polkit.h"
+ #include "bus-util.h"
+ #include "parse-util.h"
+ #include "resolve-util.h"
+diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
+index 2017b0e..422ec23 100644
+--- a/src/resolve/resolved-manager.c
++++ b/src/resolve/resolved-manager.c
+@@ -11,7 +11,7 @@
+ 
+ #include "af-list.h"
+ #include "alloc-util.h"
+-#include "bus-util.h"
++#include "bus-polkit.h"
+ #include "dirent-util.h"
+ #include "dns-domain.h"
+ #include "fd-util.h"
+diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c
+new file mode 100644
+index 0000000..da4aee5
+--- /dev/null
++++ b/src/shared/bus-polkit.c
+@@ -0,0 +1,358 @@
++/* SPDX-License-Identifier: LGPL-2.1+ */
++
++#include "bus-internal.h"
++#include "bus-message.h"
++#include "bus-polkit.h"
++#include "strv.h"
++#include "user-util.h"
++
++static int check_good_user(sd_bus_message *m, uid_t good_user) {
++        _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
++        uid_t sender_uid;
++        int r;
++
++        assert(m);
++
++        if (good_user == UID_INVALID)
++                return 0;
++
++        r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds);
++        if (r < 0)
++                return r;
++
++        /* Don't trust augmented credentials for authorization */
++        assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EUID) == 0, -EPERM);
++
++        r = sd_bus_creds_get_euid(creds, &sender_uid);
++        if (r < 0)
++                return r;
++
++        return sender_uid == good_user;
++}
++
++int bus_test_polkit(
++                sd_bus_message *call,
++                int capability,
++                const char *action,
++                const char **details,
++                uid_t good_user,
++                bool *_challenge,
++                sd_bus_error *e) {
++
++        int r;
++
++        assert(call);
++        assert(action);
++
++        /* Tests non-interactively! */
++
++        r = check_good_user(call, good_user);
++        if (r != 0)
++                return r;
++
++        r = sd_bus_query_sender_privilege(call, capability);
++        if (r < 0)
++                return r;
++        else if (r > 0)
++                return 1;
++#if ENABLE_POLKIT
++        else {
++                _cleanup_(sd_bus_message_unrefp) sd_bus_message *request = NULL;
++                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
++                int authorized = false, challenge = false;
++                const char *sender, **k, **v;
++
++                sender = sd_bus_message_get_sender(call);
++                if (!sender)
++                        return -EBADMSG;
++
++                r = sd_bus_message_new_method_call(
++                                call->bus,
++                                &request,
++                                "org.freedesktop.PolicyKit1",
++                                "/org/freedesktop/PolicyKit1/Authority",
++                                "org.freedesktop.PolicyKit1.Authority",
++                                "CheckAuthorization");
++                if (r < 0)
++                        return r;
++
++                r = sd_bus_message_append(
++                                request,
++                                "(sa{sv})s",
++                                "system-bus-name", 1, "name", "s", sender,
++                                action);
++                if (r < 0)
++                        return r;
++
++                r = sd_bus_message_open_container(request, 'a', "{ss}");
++                if (r < 0)
++                        return r;
++
++                STRV_FOREACH_PAIR(k, v, details) {
++                        r = sd_bus_message_append(request, "{ss}", *k, *v);
++                        if (r < 0)
++                                return r;
++                }
++
++                r = sd_bus_message_close_container(request);
++                if (r < 0)
++                        return r;
++
++                r = sd_bus_message_append(request, "us", 0, NULL);
++                if (r < 0)
++                        return r;
++
++                r = sd_bus_call(call->bus, request, 0, e, &reply);
++                if (r < 0) {
++                        /* Treat no PK available as access denied */
++                        if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
++                                sd_bus_error_free(e);
++                                return -EACCES;
++                        }
++
++                        return r;
++                }
++
++                r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
++                if (r < 0)
++                        return r;
++
++                r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
++                if (r < 0)
++                        return r;
++
++                if (authorized)
++                        return 1;
++
++                if (_challenge) {
++                        *_challenge = challenge;
++                        return 0;
++                }
++        }
++#endif
++
++        return -EACCES;
++}
++
++#if ENABLE_POLKIT
++
++typedef struct AsyncPolkitQuery {
++        sd_bus_message *request, *reply;
++        sd_bus_message_handler_t callback;
++        void *userdata;
++        sd_bus_slot *slot;
++        Hashmap *registry;
++} AsyncPolkitQuery;
++
++static void async_polkit_query_free(AsyncPolkitQuery *q) {
++
++        if (!q)
++                return;
++
++        sd_bus_slot_unref(q->slot);
++
++        if (q->registry && q->request)
++                hashmap_remove(q->registry, q->request);
++
++        sd_bus_message_unref(q->request);
++        sd_bus_message_unref(q->reply);
++
++        free(q);
++}
++
++static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
++        _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
++        AsyncPolkitQuery *q = userdata;
++        int r;
++
++        assert(reply);
++        assert(q);
++
++        q->slot = sd_bus_slot_unref(q->slot);
++        q->reply = sd_bus_message_ref(reply);
++
++        r = sd_bus_message_rewind(q->request, true);
++        if (r < 0) {
++                r = sd_bus_reply_method_errno(q->request, r, NULL);
++                goto finish;
++        }
++
++        r = q->callback(q->request, q->userdata, &error_buffer);
++        r = bus_maybe_reply_error(q->request, r, &error_buffer);
++
++finish:
++        async_polkit_query_free(q);
++
++        return r;
++}
++
++#endif
++
++int bus_verify_polkit_async(
++                sd_bus_message *call,
++                int capability,
++                const char *action,
++                const char **details,
++                bool interactive,
++                uid_t good_user,
++                Hashmap **registry,
++                sd_bus_error *error) {
++
++#if ENABLE_POLKIT
++        _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL;
++        AsyncPolkitQuery *q;
++        const char *sender, **k, **v;
++        sd_bus_message_handler_t callback;
++        void *userdata;
++        int c;
++#endif
++        int r;
++
++        assert(call);
++        assert(action);
++        assert(registry);
++
++        r = check_good_user(call, good_user);
++        if (r != 0)
++                return r;
++
++#if ENABLE_POLKIT
++        q = hashmap_get(*registry, call);
++        if (q) {
++                int authorized, challenge;
++
++                /* This is the second invocation of this function, and
++                 * there's already a response from polkit, let's
++                 * process it */
++                assert(q->reply);
++
++                if (sd_bus_message_is_method_error(q->reply, NULL)) {
++                        const sd_bus_error *e;
++
++                        e = sd_bus_message_get_error(q->reply);
++
++                        /* Treat no PK available as access denied */
++                        if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN) ||
++                            sd_bus_error_has_name(e, SD_BUS_ERROR_NAME_HAS_NO_OWNER))
++                                return -EACCES;
++
++                        /* Copy error from polkit reply */
++                        sd_bus_error_copy(error, e);
++                        return -sd_bus_error_get_errno(e);
++                }
++
++                r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
++                if (r >= 0)
++                        r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
++                if (r < 0)
++                        return r;
++
++                if (authorized)
++                        return 1;
++
++                if (challenge)
++                        return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
++
++                return -EACCES;
++        }
++#endif
++
++        r = sd_bus_query_sender_privilege(call, capability);
++        if (r < 0)
++                return r;
++        else if (r > 0)
++                return 1;
++
++#if ENABLE_POLKIT
++        if (sd_bus_get_current_message(call->bus) != call)
++                return -EINVAL;
++
++        callback = sd_bus_get_current_handler(call->bus);
++        if (!callback)
++                return -EINVAL;
++
++        userdata = sd_bus_get_current_userdata(call->bus);
++
++        sender = sd_bus_message_get_sender(call);
++        if (!sender)
++                return -EBADMSG;
++
++        c = sd_bus_message_get_allow_interactive_authorization(call);
++        if (c < 0)
++                return c;
++        if (c > 0)
++                interactive = true;
++
++        r = hashmap_ensure_allocated(registry, NULL);
++        if (r < 0)
++                return r;
++
++        r = sd_bus_message_new_method_call(
++                        call->bus,
++                        &pk,
++                        "org.freedesktop.PolicyKit1",
++                        "/org/freedesktop/PolicyKit1/Authority",
++                        "org.freedesktop.PolicyKit1.Authority",
++                        "CheckAuthorization");
++        if (r < 0)
++                return r;
++
++        r = sd_bus_message_append(
++                        pk,
++                        "(sa{sv})s",
++                        "system-bus-name", 1, "name", "s", sender,
++                        action);
++        if (r < 0)
++                return r;
++
++        r = sd_bus_message_open_container(pk, 'a', "{ss}");
++        if (r < 0)
++                return r;
++
++        STRV_FOREACH_PAIR(k, v, details) {
++                r = sd_bus_message_append(pk, "{ss}", *k, *v);
++                if (r < 0)
++                        return r;
++        }
++
++        r = sd_bus_message_close_container(pk);
++        if (r < 0)
++                return r;
++
++        r = sd_bus_message_append(pk, "us", interactive, NULL);
++        if (r < 0)
++                return r;
++
++        q = new0(AsyncPolkitQuery, 1);
++        if (!q)
++                return -ENOMEM;
++
++        q->request = sd_bus_message_ref(call);
++        q->callback = callback;
++        q->userdata = userdata;
++
++        r = hashmap_put(*registry, call, q);
++        if (r < 0) {
++                async_polkit_query_free(q);
++                return r;
++        }
++
++        q->registry = *registry;
++
++        r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0);
++        if (r < 0) {
++                async_polkit_query_free(q);
++                return r;
++        }
++
++        return 0;
++#endif
++
++        return -EACCES;
++}
++
++void bus_verify_polkit_async_registry_free(Hashmap *registry) {
++#if ENABLE_POLKIT
++        hashmap_free_with_destructor(registry, async_polkit_query_free);
++#endif
++}
+diff --git a/src/shared/bus-polkit.h b/src/shared/bus-polkit.h
+new file mode 100644
+index 0000000..29b3923
+--- /dev/null
++++ b/src/shared/bus-polkit.h
+@@ -0,0 +1,11 @@
++/* SPDX-License-Identifier: LGPL-2.1+ */
++#pragma once
++
++#include "sd-bus.h"
++
++#include "hashmap.h"
++
++int bus_test_polkit(sd_bus_message *call, int capability, const char *action, const char **details, uid_t good_user, bool *_challenge, sd_bus_error *e);
++
++int bus_verify_polkit_async(sd_bus_message *call, int capability, const char *action, const char **details, bool interactive, uid_t good_user, Hashmap **registry, sd_bus_error *error);
++void bus_verify_polkit_async_registry_free(Hashmap *registry);
+diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
+index a406dd8..c9d7e76 100644
+--- a/src/shared/bus-util.c
++++ b/src/shared/bus-util.c
+@@ -11,7 +11,6 @@
+ #include <sys/socket.h>
+ #include <unistd.h>
+ 
+-#include "sd-bus-protocol.h"
+ #include "sd-bus.h"
+ #include "sd-daemon.h"
+ #include "sd-event.h"
+@@ -24,15 +23,14 @@
+ #include "bus-util.h"
+ #include "cap-list.h"
+ #include "cgroup-util.h"
+-#include "def.h"
+-#include "escape.h"
+-#include "fd-util.h"
+ #include "missing.h"
+ #include "mountpoint-util.h"
+ #include "nsflags.h"
+ #include "parse-util.h"
+ #include "proc-cmdline.h"
++#include "path-util.h"
+ #include "rlimit-util.h"
++#include "socket-util.h"
+ #include "stdio-util.h"
+ #include "strv.h"
+ #include "user-util.h"
+@@ -187,357 +185,6 @@ int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
+         return has_owner;
+ }
+ 
+-static int check_good_user(sd_bus_message *m, uid_t good_user) {
+-        _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
+-        uid_t sender_uid;
+-        int r;
+-
+-        assert(m);
+-
+-        if (good_user == UID_INVALID)
+-                return 0;
+-
+-        r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds);
+-        if (r < 0)
+-                return r;
+-
+-        /* Don't trust augmented credentials for authorization */
+-        assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EUID) == 0, -EPERM);
+-
+-        r = sd_bus_creds_get_euid(creds, &sender_uid);
+-        if (r < 0)
+-                return r;
+-
+-        return sender_uid == good_user;
+-}
+-
+-int bus_test_polkit(
+-                sd_bus_message *call,
+-                int capability,
+-                const char *action,
+-                const char **details,
+-                uid_t good_user,
+-                bool *_challenge,
+-                sd_bus_error *e) {
+-
+-        int r;
+-
+-        assert(call);
+-        assert(action);
+-
+-        /* Tests non-interactively! */
+-
+-        r = check_good_user(call, good_user);
+-        if (r != 0)
+-                return r;
+-
+-        r = sd_bus_query_sender_privilege(call, capability);
+-        if (r < 0)
+-                return r;
+-        else if (r > 0)
+-                return 1;
+-#if ENABLE_POLKIT
+-        else {
+-                _cleanup_(sd_bus_message_unrefp) sd_bus_message *request = NULL;
+-                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+-                int authorized = false, challenge = false;
+-                const char *sender, **k, **v;
+-
+-                sender = sd_bus_message_get_sender(call);
+-                if (!sender)
+-                        return -EBADMSG;
+-
+-                r = sd_bus_message_new_method_call(
+-                                call->bus,
+-                                &request,
+-                                "org.freedesktop.PolicyKit1",
+-                                "/org/freedesktop/PolicyKit1/Authority",
+-                                "org.freedesktop.PolicyKit1.Authority",
+-                                "CheckAuthorization");
+-                if (r < 0)
+-                        return r;
+-
+-                r = sd_bus_message_append(
+-                                request,
+-                                "(sa{sv})s",
+-                                "system-bus-name", 1, "name", "s", sender,
+-                                action);
+-                if (r < 0)
+-                        return r;
+-
+-                r = sd_bus_message_open_container(request, 'a', "{ss}");
+-                if (r < 0)
+-                        return r;
+-
+-                STRV_FOREACH_PAIR(k, v, details) {
+-                        r = sd_bus_message_append(request, "{ss}", *k, *v);
+-                        if (r < 0)
+-                                return r;
+-                }
+-
+-                r = sd_bus_message_close_container(request);
+-                if (r < 0)
+-                        return r;
+-
+-                r = sd_bus_message_append(request, "us", 0, NULL);
+-                if (r < 0)
+-                        return r;
+-
+-                r = sd_bus_call(call->bus, request, 0, e, &reply);
+-                if (r < 0) {
+-                        /* Treat no PK available as access denied */
+-                        if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
+-                                sd_bus_error_free(e);
+-                                return -EACCES;
+-                        }
+-
+-                        return r;
+-                }
+-
+-                r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
+-                if (r < 0)
+-                        return r;
+-
+-                r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
+-                if (r < 0)
+-                        return r;
+-
+-                if (authorized)
+-                        return 1;
+-
+-                if (_challenge) {
+-                        *_challenge = challenge;
+-                        return 0;
+-                }
+-        }
+-#endif
+-
+-        return -EACCES;
+-}
+-
+-#if ENABLE_POLKIT
+-
+-typedef struct AsyncPolkitQuery {
+-        sd_bus_message *request, *reply;
+-        sd_bus_message_handler_t callback;
+-        void *userdata;
+-        sd_bus_slot *slot;
+-        Hashmap *registry;
+-} AsyncPolkitQuery;
+-
+-static void async_polkit_query_free(AsyncPolkitQuery *q) {
+-
+-        if (!q)
+-                return;
+-
+-        sd_bus_slot_unref(q->slot);
+-
+-        if (q->registry && q->request)
+-                hashmap_remove(q->registry, q->request);
+-
+-        sd_bus_message_unref(q->request);
+-        sd_bus_message_unref(q->reply);
+-
+-        free(q);
+-}
+-
+-static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
+-        _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+-        AsyncPolkitQuery *q = userdata;
+-        int r;
+-
+-        assert(reply);
+-        assert(q);
+-
+-        q->slot = sd_bus_slot_unref(q->slot);
+-        q->reply = sd_bus_message_ref(reply);
+-
+-        r = sd_bus_message_rewind(q->request, true);
+-        if (r < 0) {
+-                r = sd_bus_reply_method_errno(q->request, r, NULL);
+-                goto finish;
+-        }
+-
+-        r = q->callback(q->request, q->userdata, &error_buffer);
+-        r = bus_maybe_reply_error(q->request, r, &error_buffer);
+-
+-finish:
+-        async_polkit_query_free(q);
+-
+-        return r;
+-}
+-
+-#endif
+-
+-int bus_verify_polkit_async(
+-                sd_bus_message *call,
+-                int capability,
+-                const char *action,
+-                const char **details,
+-                bool interactive,
+-                uid_t good_user,
+-                Hashmap **registry,
+-                sd_bus_error *error) {
+-
+-#if ENABLE_POLKIT
+-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL;
+-        AsyncPolkitQuery *q;
+-        const char *sender, **k, **v;
+-        sd_bus_message_handler_t callback;
+-        void *userdata;
+-        int c;
+-#endif
+-        int r;
+-
+-        assert(call);
+-        assert(action);
+-        assert(registry);
+-
+-        r = check_good_user(call, good_user);
+-        if (r != 0)
+-                return r;
+-
+-#if ENABLE_POLKIT
+-        q = hashmap_get(*registry, call);
+-        if (q) {
+-                int authorized, challenge;
+-
+-                /* This is the second invocation of this function, and
+-                 * there's already a response from polkit, let's
+-                 * process it */
+-                assert(q->reply);
+-
+-                if (sd_bus_message_is_method_error(q->reply, NULL)) {
+-                        const sd_bus_error *e;
+-
+-                        e = sd_bus_message_get_error(q->reply);
+-
+-                        /* Treat no PK available as access denied */
+-                        if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
+-                                return -EACCES;
+-
+-                        /* Copy error from polkit reply */
+-                        sd_bus_error_copy(error, e);
+-                        return -sd_bus_error_get_errno(e);
+-                }
+-
+-                r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
+-                if (r >= 0)
+-                        r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
+-
+-                if (r < 0)
+-                        return r;
+-
+-                if (authorized)
+-                        return 1;
+-
+-                if (challenge)
+-                        return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
+-
+-                return -EACCES;
+-        }
+-#endif
+-
+-        r = sd_bus_query_sender_privilege(call, capability);
+-        if (r < 0)
+-                return r;
+-        else if (r > 0)
+-                return 1;
+-
+-#if ENABLE_POLKIT
+-        if (sd_bus_get_current_message(call->bus) != call)
+-                return -EINVAL;
+-
+-        callback = sd_bus_get_current_handler(call->bus);
+-        if (!callback)
+-                return -EINVAL;
+-
+-        userdata = sd_bus_get_current_userdata(call->bus);
+-
+-        sender = sd_bus_message_get_sender(call);
+-        if (!sender)
+-                return -EBADMSG;
+-
+-        c = sd_bus_message_get_allow_interactive_authorization(call);
+-        if (c < 0)
+-                return c;
+-        if (c > 0)
+-                interactive = true;
+-
+-        r = hashmap_ensure_allocated(registry, NULL);
+-        if (r < 0)
+-                return r;
+-
+-        r = sd_bus_message_new_method_call(
+-                        call->bus,
+-                        &pk,
+-                        "org.freedesktop.PolicyKit1",
+-                        "/org/freedesktop/PolicyKit1/Authority",
+-                        "org.freedesktop.PolicyKit1.Authority",
+-                        "CheckAuthorization");
+-        if (r < 0)
+-                return r;
+-
+-        r = sd_bus_message_append(
+-                        pk,
+-                        "(sa{sv})s",
+-                        "system-bus-name", 1, "name", "s", sender,
+-                        action);
+-        if (r < 0)
+-                return r;
+-
+-        r = sd_bus_message_open_container(pk, 'a', "{ss}");
+-        if (r < 0)
+-                return r;
+-
+-        STRV_FOREACH_PAIR(k, v, details) {
+-                r = sd_bus_message_append(pk, "{ss}", *k, *v);
+-                if (r < 0)
+-                        return r;
+-        }
+-
+-        r = sd_bus_message_close_container(pk);
+-        if (r < 0)
+-                return r;
+-
+-        r = sd_bus_message_append(pk, "us", interactive, NULL);
+-        if (r < 0)
+-                return r;
+-
+-        q = new0(AsyncPolkitQuery, 1);
+-        if (!q)
+-                return -ENOMEM;
+-
+-        q->request = sd_bus_message_ref(call);
+-        q->callback = callback;
+-        q->userdata = userdata;
+-
+-        r = hashmap_put(*registry, call, q);
+-        if (r < 0) {
+-                async_polkit_query_free(q);
+-                return r;
+-        }
+-
+-        q->registry = *registry;
+-
+-        r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0);
+-        if (r < 0) {
+-                async_polkit_query_free(q);
+-                return r;
+-        }
+-
+-        return 0;
+-#endif
+-
+-        return -EACCES;
+-}
+-
+-void bus_verify_polkit_async_registry_free(Hashmap *registry) {
+-#if ENABLE_POLKIT
+-        hashmap_free_with_destructor(registry, async_polkit_query_free);
+-#endif
+-}
+-
+ int bus_check_peercred(sd_bus *c) {
+         struct ucred ucred;
+         int fd, r;
+diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h
+index 71c248f..c9cbf76 100644
+--- a/src/shared/bus-util.h
++++ b/src/shared/bus-util.h
+@@ -9,8 +9,8 @@
+ #include "sd-bus.h"
+ #include "sd-event.h"
+ 
+-#include "hashmap.h"
+ #include "macro.h"
++#include "set.h"
+ #include "string-util.h"
+ 
+ typedef enum BusTransport {
+@@ -51,11 +51,6 @@ int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error);
+ 
+ int bus_check_peercred(sd_bus *c);
+ 
+-int bus_test_polkit(sd_bus_message *call, int capability, const char *action, const char **details, uid_t good_user, bool *_challenge, sd_bus_error *e);
+-
+-int bus_verify_polkit_async(sd_bus_message *call, int capability, const char *action, const char **details, bool interactive, uid_t good_user, Hashmap **registry, sd_bus_error *error);
+-void bus_verify_polkit_async_registry_free(Hashmap *registry);
+-
+ int bus_connect_system_systemd(sd_bus **_bus);
+ int bus_connect_user_systemd(sd_bus **_bus);
+ 
+diff --git a/src/shared/meson.build b/src/shared/meson.build
+index 99d6ba1..f6d1092 100644
+--- a/src/shared/meson.build
++++ b/src/shared/meson.build
+@@ -25,6 +25,8 @@ shared_sources = files('''
+         bus-unit-util.h
+         bus-util.c
+         bus-util.h
++        bus-polkit.c
++        bus-polkit.h
+         calendarspec.c
+         calendarspec.h
+         cgroup-show.c
+diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c
+index 324d4a4..398d4f4 100644
+--- a/src/timedate/timedated.c
++++ b/src/timedate/timedated.c
+@@ -11,7 +11,7 @@
+ #include "alloc-util.h"
+ #include "bus-common-errors.h"
+ #include "bus-error.h"
+-#include "bus-util.h"
++#include "bus-polkit.h"
+ #include "clock-util.h"
+ #include "def.h"
+ #include "fileio-label.h"


More information about the Pkg-systemd-maintainers mailing list