From 773b1a7916bfce3aa2a21ecf534d475032e8528e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Jan 2020 14:29:43 +0100 Subject: [PATCH 1/8] bus-polkit: rename return error parameter to ret_error --- 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 da4aee5086..f93aa17046 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; } From 95f82ae9d774f3508ce89dcbdd0714ef7385df59 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Jan 2020 16:44:43 +0100 Subject: [PATCH 2/8] polkit: reuse some common bus message appending code --- 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 f93aa17046..81193b89fc 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; From 7f56982289275ce84e20f0554475864953e6aaab Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Jan 2020 16:52:10 +0100 Subject: [PATCH 3/8] 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. --- 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 81193b89fc..6343dd66aa 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); From f4425c72c7395ec93ae00052916a66e2f60f200b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Jan 2020 16:53:59 +0100 Subject: [PATCH 4/8] polkit: use structured initialization --- 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 6343dd66aa..c42c39afea 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) { From 1068447e6954dc6ce52f099ed174c442cb89ed54 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Jan 2020 17:05:17 +0100 Subject: [PATCH 5/8] 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. --- src/libsystemd/libsystemd.sym | 1 + src/libsystemd/sd-bus/sd-bus.c | 24 ++++++++++++++++++++++++ src/systemd/sd-bus.h | 1 + 3 files changed, 26 insertions(+) diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index ccc23e1257..08b915cf7c 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -685,6 +685,7 @@ global: LIBSYSTEMD_245 { global: + sd_bus_enqeue_for_read; sd_bus_message_dump; sd_bus_message_sensitive; sd_event_add_child_pidfd; diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index b53d4dd854..c1db48f47a 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -4207,3 +4207,27 @@ _public_ int sd_bus_get_close_on_exit(sd_bus *bus) { return bus->close_on_exit; } + +_public_ 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++] = bus_message_ref_queued(m, bus); + return 0; +} diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h index ff2c0e9ef0..821b06ea92 100644 --- a/src/systemd/sd-bus.h +++ b/src/systemd/sd-bus.h @@ -207,6 +207,7 @@ int sd_bus_process(sd_bus *bus, sd_bus_message **r); int sd_bus_process_priority(sd_bus *bus, int64_t max_priority, sd_bus_message **r); int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec); int sd_bus_flush(sd_bus *bus); +int sd_bus_enqeue_for_read(sd_bus *bus, sd_bus_message *m); sd_bus_slot* sd_bus_get_current_slot(sd_bus *bus); sd_bus_message* sd_bus_get_current_message(sd_bus *bus); From 637486261528e8aa3da9f26a4487dc254f4b7abb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Jan 2020 17:07:47 +0100 Subject: [PATCH 6/8] 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. --- src/shared/bus-polkit.c | 76 +++++++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 26 deletions(-) diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c index c42c39afea..bd88e337b7 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,22 @@ static void async_polkit_query_free(AsyncPolkitQuery *q) { free(q->action); strv_free(q->details); + sd_event_source_disable_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 +204,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 = q->callback(q->request, q->userdata, &error_buffer); - r = bus_maybe_reply_error(q->request, r, &error_buffer); + r = sd_bus_enqeue_for_read(sd_bus_message_get_bus(q->request), q->request); + if (r < 0) + goto fail; -finish: + return 1; + +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 +262,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 +328,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 +375,6 @@ int bus_verify_polkit_async( *q = (AsyncPolkitQuery) { .request = sd_bus_message_ref(call), - .callback = callback, - .userdata = userdata, }; q->action = strdup(action); From 5c1163273569809742c164260cfd9f096520cb82 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Jan 2020 17:44:33 +0100 Subject: [PATCH 7/8] man: document the new sd_bus_enqueue_for_read() API call --- man/rules/meson.build | 1 + man/sd_bus_enqueue_for_read.xml | 88 +++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 man/sd_bus_enqueue_for_read.xml diff --git a/man/rules/meson.build b/man/rules/meson.build index 591d7c48b5..98316b33b2 100644 --- a/man/rules/meson.build +++ b/man/rules/meson.build @@ -195,6 +195,7 @@ manpages = [ 'sd_bus_open_user_with_description', 'sd_bus_open_with_description'], ''], + ['sd_bus_enqueue_for_read', '3', [], ''], ['sd_bus_error', '3', ['SD_BUS_ERROR_MAKE_CONST', diff --git a/man/sd_bus_enqueue_for_read.xml b/man/sd_bus_enqueue_for_read.xml new file mode 100644 index 0000000000..30ccee2ef2 --- /dev/null +++ b/man/sd_bus_enqueue_for_read.xml @@ -0,0 +1,88 @@ + + + + + + + + sd_bus_enqueue_for_read + systemd + + + + sd_bus_enqueue_for_read + 3 + + + + sd_bus_enqueue_for_read + + Re-enqueue a bus message on a bus connection, for reading. + + + + + #include <systemd/sd-bus.h> + + + int sd_bus_enqueue_for_read + sd_bus *bus + sd_bus_message *message + + + + + + + Description + + sd_bus_enqueue_for_read() may be used to re-enqueue an incoming bus message on + the local read queue, so that it is processed and dispatched locally again, similar to how an incoming + message from the peer is processed. Takes a bus connection object and the message to enqueue. A reference + is taken of the message and the caller's reference thus remains in possession of the caller. The message + is enqueued at the end of the queue, thus will be dispatched after all other already queued messages are + dispatched. + + This call is primarily useful for dealing with incoming method calls that may be processed only + after an additional asynchronous operation completes. One example are PolicyKit authorization requests + that are determined to be necessary to autorize a newly incoming method call: when the PolicyKit response + is received the original method call may be re-enqueued to process it again, this time with the + authorization result known. + + + + Return Value + + On success, this function return 0 or a positive integer. On failure, it returns a negative errno-style + error code. + + + Errors + + Returned errors may indicate the following problems: + + + + -ECHILD + + The bus connection has been created in a different process. + + + + + + + + + See Also + + + systemd1, + sd-bus3, + sd_bus_send3, + + + + From bc130b6858327b382b07b3985cf48e2aa9016b2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 4 Feb 2020 18:39:04 +0100 Subject: [PATCH 8/8] Fix typo in function name --- TODO | 2 +- man/sd_bus_enqueue_for_read.xml | 2 +- src/libsystemd/libsystemd.sym | 2 +- src/libsystemd/sd-bus/sd-bus.c | 8 ++++---- src/shared/bus-polkit.c | 2 +- src/systemd/sd-bus.h | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/TODO b/TODO index 4a6c8d3512..d26b1be408 100644 --- a/TODO +++ b/TODO @@ -328,7 +328,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/man/sd_bus_enqueue_for_read.xml b/man/sd_bus_enqueue_for_read.xml index 30ccee2ef2..3318a3031b 100644 --- a/man/sd_bus_enqueue_for_read.xml +++ b/man/sd_bus_enqueue_for_read.xml @@ -47,7 +47,7 @@ This call is primarily useful for dealing with incoming method calls that may be processed only after an additional asynchronous operation completes. One example are PolicyKit authorization requests - that are determined to be necessary to autorize a newly incoming method call: when the PolicyKit response + that are determined to be necessary to authorize a newly incoming method call: when the PolicyKit response is received the original method call may be re-enqueued to process it again, this time with the authorization result known. diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 08b915cf7c..8b6ebbcf8b 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -685,7 +685,7 @@ global: LIBSYSTEMD_245 { global: - sd_bus_enqeue_for_read; + sd_bus_enqueue_for_read; sd_bus_message_dump; sd_bus_message_sensitive; sd_event_add_child_pidfd; diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index c1db48f47a..7ad03680f4 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -4208,7 +4208,7 @@ _public_ int sd_bus_get_close_on_exit(sd_bus *bus) { return bus->close_on_exit; } -_public_ int sd_bus_enqeue_for_read(sd_bus *bus, sd_bus_message *m) { +_public_ int sd_bus_enqueue_for_read(sd_bus *bus, sd_bus_message *m) { int r; assert_return(bus, -EINVAL); @@ -4220,9 +4220,9 @@ _public_ 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 bd88e337b7..0dbf3f60c8 100644 --- a/src/shared/bus-polkit.c +++ b/src/shared/bus-polkit.c @@ -234,7 +234,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/src/systemd/sd-bus.h b/src/systemd/sd-bus.h index 821b06ea92..e6f3298745 100644 --- a/src/systemd/sd-bus.h +++ b/src/systemd/sd-bus.h @@ -207,7 +207,7 @@ int sd_bus_process(sd_bus *bus, sd_bus_message **r); int sd_bus_process_priority(sd_bus *bus, int64_t max_priority, sd_bus_message **r); int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec); int sd_bus_flush(sd_bus *bus); -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); sd_bus_slot* sd_bus_get_current_slot(sd_bus *bus); sd_bus_message* sd_bus_get_current_message(sd_bus *bus);