1 /* SPDX-License-Identifier: LGPL-2.1+ */
5 #include "bus-internal.h"
6 #include "bus-message.h"
7 #include "bus-signature.h"
10 #include "string-util.h"
12 _public_ int sd_bus_emit_signal(
15 const char *interface,
17 const char *types, ...) {
19 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
22 assert_return(bus, -EINVAL);
23 assert_return(bus = bus_resolve(bus), -ENOPKG);
24 assert_return(!bus_pid_changed(bus), -ECHILD);
26 if (!BUS_IS_OPEN(bus->state))
29 r = sd_bus_message_new_signal(bus, &m, path, interface, member);
33 if (!isempty(types)) {
37 r = sd_bus_message_appendv(m, types, ap);
43 return sd_bus_send(bus, m, NULL);
46 _public_ int sd_bus_call_method_async(
49 const char *destination,
51 const char *interface,
53 sd_bus_message_handler_t callback,
55 const char *types, ...) {
57 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
60 assert_return(bus, -EINVAL);
61 assert_return(bus = bus_resolve(bus), -ENOPKG);
62 assert_return(!bus_pid_changed(bus), -ECHILD);
64 if (!BUS_IS_OPEN(bus->state))
67 r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
71 if (!isempty(types)) {
75 r = sd_bus_message_appendv(m, types, ap);
81 return sd_bus_call_async(bus, slot, m, callback, userdata, 0);
84 _public_ int sd_bus_call_method(
86 const char *destination,
88 const char *interface,
91 sd_bus_message **reply,
92 const char *types, ...) {
94 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
97 bus_assert_return(bus, -EINVAL, error);
98 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
100 if (!BUS_IS_OPEN(bus->state)) {
105 r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
109 if (!isempty(types)) {
113 r = sd_bus_message_appendv(m, types, ap);
119 return sd_bus_call(bus, m, 0, error, reply);
122 return sd_bus_error_set_errno(error, r);
125 _public_ int sd_bus_reply_method_return(
126 sd_bus_message *call,
127 const char *types, ...) {
129 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
132 assert_return(call, -EINVAL);
133 assert_return(call->sealed, -EPERM);
134 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
135 assert_return(call->bus, -EINVAL);
136 assert_return(!bus_pid_changed(call->bus), -ECHILD);
138 if (!BUS_IS_OPEN(call->bus->state))
141 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
144 r = sd_bus_message_new_method_return(call, &m);
148 if (!isempty(types)) {
152 r = sd_bus_message_appendv(m, types, ap);
158 return sd_bus_send(call->bus, m, NULL);
161 _public_ int sd_bus_reply_method_error(
162 sd_bus_message *call,
163 const sd_bus_error *e) {
165 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
168 assert_return(call, -EINVAL);
169 assert_return(call->sealed, -EPERM);
170 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
171 assert_return(sd_bus_error_is_set(e), -EINVAL);
172 assert_return(call->bus, -EINVAL);
173 assert_return(!bus_pid_changed(call->bus), -ECHILD);
175 if (!BUS_IS_OPEN(call->bus->state))
178 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
181 r = sd_bus_message_new_method_error(call, &m, e);
185 return sd_bus_send(call->bus, m, NULL);
188 _public_ int sd_bus_reply_method_errorf(
189 sd_bus_message *call,
194 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
197 assert_return(call, -EINVAL);
198 assert_return(call->sealed, -EPERM);
199 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
200 assert_return(call->bus, -EINVAL);
201 assert_return(!bus_pid_changed(call->bus), -ECHILD);
203 if (!BUS_IS_OPEN(call->bus->state))
206 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
209 va_start(ap, format);
210 bus_error_setfv(&error, name, format, ap);
213 return sd_bus_reply_method_error(call, &error);
216 _public_ int sd_bus_reply_method_errno(
217 sd_bus_message *call,
219 const sd_bus_error *p) {
221 _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
223 assert_return(call, -EINVAL);
224 assert_return(call->sealed, -EPERM);
225 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
226 assert_return(call->bus, -EINVAL);
227 assert_return(!bus_pid_changed(call->bus), -ECHILD);
229 if (!BUS_IS_OPEN(call->bus->state))
232 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
235 if (sd_bus_error_is_set(p))
236 return sd_bus_reply_method_error(call, p);
238 sd_bus_error_set_errno(&berror, error);
240 return sd_bus_reply_method_error(call, &berror);
243 _public_ int sd_bus_reply_method_errnof(
244 sd_bus_message *call,
249 _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
252 assert_return(call, -EINVAL);
253 assert_return(call->sealed, -EPERM);
254 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
255 assert_return(call->bus, -EINVAL);
256 assert_return(!bus_pid_changed(call->bus), -ECHILD);
258 if (!BUS_IS_OPEN(call->bus->state))
261 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
264 va_start(ap, format);
265 sd_bus_error_set_errnofv(&berror, error, format, ap);
268 return sd_bus_reply_method_error(call, &berror);
271 _public_ int sd_bus_get_property(
273 const char *destination,
275 const char *interface,
278 sd_bus_message **reply,
281 sd_bus_message *rep = NULL;
284 bus_assert_return(bus, -EINVAL, error);
285 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
286 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
287 bus_assert_return(reply, -EINVAL, error);
288 bus_assert_return(signature_is_single(type, false), -EINVAL, error);
289 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
291 if (!BUS_IS_OPEN(bus->state)) {
296 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
300 r = sd_bus_message_enter_container(rep, 'v', type);
302 sd_bus_message_unref(rep);
310 return sd_bus_error_set_errno(error, r);
313 _public_ int sd_bus_get_property_trivial(
315 const char *destination,
317 const char *interface,
320 char type, void *ptr) {
322 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
325 bus_assert_return(bus, -EINVAL, error);
326 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
327 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
328 bus_assert_return(bus_type_is_trivial(type), -EINVAL, error);
329 bus_assert_return(ptr, -EINVAL, error);
330 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
332 if (!BUS_IS_OPEN(bus->state)) {
337 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
341 r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
345 r = sd_bus_message_read_basic(reply, type, ptr);
352 return sd_bus_error_set_errno(error, r);
355 _public_ int sd_bus_get_property_string(
357 const char *destination,
359 const char *interface,
364 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
369 bus_assert_return(bus, -EINVAL, error);
370 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
371 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
372 bus_assert_return(ret, -EINVAL, error);
373 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
375 if (!BUS_IS_OPEN(bus->state)) {
380 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
384 r = sd_bus_message_enter_container(reply, 'v', "s");
388 r = sd_bus_message_read_basic(reply, 's', &s);
402 return sd_bus_error_set_errno(error, r);
405 _public_ int sd_bus_get_property_strv(
407 const char *destination,
409 const char *interface,
414 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
417 bus_assert_return(bus, -EINVAL, error);
418 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
419 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
420 bus_assert_return(ret, -EINVAL, error);
421 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
423 if (!BUS_IS_OPEN(bus->state)) {
428 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
432 r = sd_bus_message_enter_container(reply, 'v', NULL);
436 r = sd_bus_message_read_strv(reply, ret);
443 return sd_bus_error_set_errno(error, r);
446 _public_ int sd_bus_set_property(
448 const char *destination,
450 const char *interface,
453 const char *type, ...) {
455 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
459 bus_assert_return(bus, -EINVAL, error);
460 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
461 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
462 bus_assert_return(signature_is_single(type, false), -EINVAL, error);
463 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
465 if (!BUS_IS_OPEN(bus->state)) {
470 r = sd_bus_message_new_method_call(bus, &m, destination, path, "org.freedesktop.DBus.Properties", "Set");
474 r = sd_bus_message_append(m, "ss", strempty(interface), member);
478 r = sd_bus_message_open_container(m, 'v', type);
483 r = sd_bus_message_appendv(m, type, ap);
488 r = sd_bus_message_close_container(m);
492 return sd_bus_call(bus, m, 0, error, NULL);
495 return sd_bus_error_set_errno(error, r);
498 _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
501 assert_return(call, -EINVAL);
502 assert_return(call->sealed, -EPERM);
503 assert_return(call->bus, -EINVAL);
504 assert_return(!bus_pid_changed(call->bus), -ECHILD);
506 if (!BUS_IS_OPEN(call->bus->state))
509 c = sd_bus_message_get_creds(call);
511 /* All data we need? */
512 if (c && (mask & ~c->mask) == 0) {
513 *creds = sd_bus_creds_ref(c);
517 /* No data passed? Or not enough data passed to retrieve the missing bits? */
518 if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
519 /* We couldn't read anything from the call, let's try
520 * to get it from the sender or peer. */
523 /* There's a sender, but the creds are missing. */
524 return sd_bus_get_name_creds(call->bus, call->sender, mask, creds);
526 /* There's no sender. For direct connections
527 * the credentials of the AF_UNIX peer matter,
528 * which may be queried via sd_bus_get_owner_creds(). */
529 return sd_bus_get_owner_creds(call->bus, mask, creds);
532 log_debug_elogind("Called by UID %u ; %s [%s] (%s)", c->uid,
533 c->unique_name ? c->unique_name : "no name",
534 c->label ? c->label : "no label",
535 c->description ? c->description : "no desc");
537 return bus_creds_extend_by_pid(c, mask, creds);
540 _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
541 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
543 bool know_caps = false;
546 assert_return(call, -EINVAL);
547 assert_return(call->sealed, -EPERM);
548 assert_return(call->bus, -EINVAL);
549 assert_return(!bus_pid_changed(call->bus), -ECHILD);
551 if (!BUS_IS_OPEN(call->bus->state))
554 if (capability >= 0) {
556 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
560 /* We cannot use augmented caps for authorization,
561 * since then data is acquired raceful from
562 * /proc. This can never actually happen, but let's
563 * better be safe than sorry, and do an extra check
565 assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EFFECTIVE_CAPS) == 0, -EPERM);
567 r = sd_bus_creds_has_effective_cap(creds, capability);
573 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID, &creds);
578 /* Now, check the UID, but only if the capability check wasn't
581 if (our_uid != 0 || !know_caps || capability < 0) {
584 /* We cannot use augmented uid/euid for authorization,
585 * since then data is acquired raceful from
586 * /proc. This can never actually happen, but let's
587 * better be safe than sorry, and do an extra check
589 assert_return((sd_bus_creds_get_augmented_mask(creds) & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID)) == 0, -EPERM);
591 /* Try to use the EUID, if we have it. */
592 r = sd_bus_creds_get_euid(creds, &sender_uid);
594 r = sd_bus_creds_get_uid(creds, &sender_uid);
597 /* Sender has same UID as us, then let's grant access */
598 if (sender_uid == our_uid)
601 /* Sender is root, we are not root. */
602 if (our_uid != 0 && sender_uid == 0)
610 #define make_expression(sender, path, interface, member) \
613 sender ? ",sender='" : "", \
616 path ? ",path='" : "", \
619 interface ? ",interface='" : "", \
621 interface ? "'" : "", \
622 member ? ",member='" : "", \
627 _public_ int sd_bus_match_signal(
632 const char *interface,
634 sd_bus_message_handler_t callback,
637 const char *expression;
639 assert_return(bus, -EINVAL);
640 assert_return(bus = bus_resolve(bus), -ENOPKG);
641 assert_return(!bus_pid_changed(bus), -ECHILD);
642 assert_return(!sender || service_name_is_valid(sender), -EINVAL);
643 assert_return(!path || object_path_is_valid(path), -EINVAL);
644 assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
645 assert_return(!member || member_name_is_valid(member), -EINVAL);
647 expression = make_expression(sender, path, interface, member);
649 return sd_bus_add_match(bus, ret, expression, callback, userdata);
652 _public_ int sd_bus_match_signal_async(
657 const char *interface,
659 sd_bus_message_handler_t callback,
660 sd_bus_message_handler_t install_callback,
663 const char *expression;
665 assert_return(bus, -EINVAL);
666 assert_return(bus = bus_resolve(bus), -ENOPKG);
667 assert_return(!bus_pid_changed(bus), -ECHILD);
668 assert_return(!sender || service_name_is_valid(sender), -EINVAL);
669 assert_return(!path || object_path_is_valid(path), -EINVAL);
670 assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
671 assert_return(!member || member_name_is_valid(member), -EINVAL);
673 expression = make_expression(sender, path, interface, member);
675 return sd_bus_add_match_async(bus, ret, expression, callback, install_callback, userdata);