1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2013 Lennart Poettering
8 #include "bus-internal.h"
9 #include "bus-message.h"
10 #include "bus-signature.h"
13 #include "string-util.h"
15 _public_ int sd_bus_emit_signal(
18 const char *interface,
20 const char *types, ...) {
22 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
25 assert_return(bus, -EINVAL);
26 assert_return(bus = bus_resolve(bus), -ENOPKG);
27 assert_return(!bus_pid_changed(bus), -ECHILD);
29 if (!BUS_IS_OPEN(bus->state))
32 r = sd_bus_message_new_signal(bus, &m, path, interface, member);
36 if (!isempty(types)) {
40 r = sd_bus_message_appendv(m, types, ap);
46 return sd_bus_send(bus, m, NULL);
49 _public_ int sd_bus_call_method_async(
52 const char *destination,
54 const char *interface,
56 sd_bus_message_handler_t callback,
58 const char *types, ...) {
60 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
63 assert_return(bus, -EINVAL);
64 assert_return(bus = bus_resolve(bus), -ENOPKG);
65 assert_return(!bus_pid_changed(bus), -ECHILD);
67 if (!BUS_IS_OPEN(bus->state))
70 r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
74 if (!isempty(types)) {
78 r = sd_bus_message_appendv(m, types, ap);
84 return sd_bus_call_async(bus, slot, m, callback, userdata, 0);
87 _public_ int sd_bus_call_method(
89 const char *destination,
91 const char *interface,
94 sd_bus_message **reply,
95 const char *types, ...) {
97 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
100 bus_assert_return(bus, -EINVAL, error);
101 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
103 if (!BUS_IS_OPEN(bus->state)) {
108 r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
112 if (!isempty(types)) {
116 r = sd_bus_message_appendv(m, types, ap);
122 return sd_bus_call(bus, m, 0, error, reply);
125 return sd_bus_error_set_errno(error, r);
128 _public_ int sd_bus_reply_method_return(
129 sd_bus_message *call,
130 const char *types, ...) {
132 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
135 assert_return(call, -EINVAL);
136 assert_return(call->sealed, -EPERM);
137 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
138 assert_return(call->bus, -EINVAL);
139 assert_return(!bus_pid_changed(call->bus), -ECHILD);
141 if (!BUS_IS_OPEN(call->bus->state))
144 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
147 r = sd_bus_message_new_method_return(call, &m);
151 if (!isempty(types)) {
155 r = sd_bus_message_appendv(m, types, ap);
161 return sd_bus_send(call->bus, m, NULL);
164 _public_ int sd_bus_reply_method_error(
165 sd_bus_message *call,
166 const sd_bus_error *e) {
168 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
171 assert_return(call, -EINVAL);
172 assert_return(call->sealed, -EPERM);
173 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
174 assert_return(sd_bus_error_is_set(e), -EINVAL);
175 assert_return(call->bus, -EINVAL);
176 assert_return(!bus_pid_changed(call->bus), -ECHILD);
178 if (!BUS_IS_OPEN(call->bus->state))
181 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
184 r = sd_bus_message_new_method_error(call, &m, e);
188 return sd_bus_send(call->bus, m, NULL);
191 _public_ int sd_bus_reply_method_errorf(
192 sd_bus_message *call,
197 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
200 assert_return(call, -EINVAL);
201 assert_return(call->sealed, -EPERM);
202 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
203 assert_return(call->bus, -EINVAL);
204 assert_return(!bus_pid_changed(call->bus), -ECHILD);
206 if (!BUS_IS_OPEN(call->bus->state))
209 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
212 va_start(ap, format);
213 bus_error_setfv(&error, name, format, ap);
216 return sd_bus_reply_method_error(call, &error);
219 _public_ int sd_bus_reply_method_errno(
220 sd_bus_message *call,
222 const sd_bus_error *p) {
224 _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
226 assert_return(call, -EINVAL);
227 assert_return(call->sealed, -EPERM);
228 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
229 assert_return(call->bus, -EINVAL);
230 assert_return(!bus_pid_changed(call->bus), -ECHILD);
232 if (!BUS_IS_OPEN(call->bus->state))
235 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
238 if (sd_bus_error_is_set(p))
239 return sd_bus_reply_method_error(call, p);
241 sd_bus_error_set_errno(&berror, error);
243 return sd_bus_reply_method_error(call, &berror);
246 _public_ int sd_bus_reply_method_errnof(
247 sd_bus_message *call,
252 _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
255 assert_return(call, -EINVAL);
256 assert_return(call->sealed, -EPERM);
257 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
258 assert_return(call->bus, -EINVAL);
259 assert_return(!bus_pid_changed(call->bus), -ECHILD);
261 if (!BUS_IS_OPEN(call->bus->state))
264 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
267 va_start(ap, format);
268 sd_bus_error_set_errnofv(&berror, error, format, ap);
271 return sd_bus_reply_method_error(call, &berror);
274 _public_ int sd_bus_get_property(
276 const char *destination,
278 const char *interface,
281 sd_bus_message **reply,
284 sd_bus_message *rep = NULL;
287 bus_assert_return(bus, -EINVAL, error);
288 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
289 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
290 bus_assert_return(reply, -EINVAL, error);
291 bus_assert_return(signature_is_single(type, false), -EINVAL, error);
292 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
294 if (!BUS_IS_OPEN(bus->state)) {
299 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
303 r = sd_bus_message_enter_container(rep, 'v', type);
305 sd_bus_message_unref(rep);
313 return sd_bus_error_set_errno(error, r);
316 _public_ int sd_bus_get_property_trivial(
318 const char *destination,
320 const char *interface,
323 char type, void *ptr) {
325 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
328 bus_assert_return(bus, -EINVAL, error);
329 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
330 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
331 bus_assert_return(bus_type_is_trivial(type), -EINVAL, error);
332 bus_assert_return(ptr, -EINVAL, error);
333 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
335 if (!BUS_IS_OPEN(bus->state)) {
340 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
344 r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
348 r = sd_bus_message_read_basic(reply, type, ptr);
355 return sd_bus_error_set_errno(error, r);
358 _public_ int sd_bus_get_property_string(
360 const char *destination,
362 const char *interface,
367 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
372 bus_assert_return(bus, -EINVAL, error);
373 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
374 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
375 bus_assert_return(ret, -EINVAL, error);
376 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
378 if (!BUS_IS_OPEN(bus->state)) {
383 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
387 r = sd_bus_message_enter_container(reply, 'v', "s");
391 r = sd_bus_message_read_basic(reply, 's', &s);
405 return sd_bus_error_set_errno(error, r);
408 _public_ int sd_bus_get_property_strv(
410 const char *destination,
412 const char *interface,
417 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
420 bus_assert_return(bus, -EINVAL, error);
421 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
422 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
423 bus_assert_return(ret, -EINVAL, error);
424 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
426 if (!BUS_IS_OPEN(bus->state)) {
431 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
435 r = sd_bus_message_enter_container(reply, 'v', NULL);
439 r = sd_bus_message_read_strv(reply, ret);
446 return sd_bus_error_set_errno(error, r);
449 _public_ int sd_bus_set_property(
451 const char *destination,
453 const char *interface,
456 const char *type, ...) {
458 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
462 bus_assert_return(bus, -EINVAL, error);
463 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
464 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
465 bus_assert_return(signature_is_single(type, false), -EINVAL, error);
466 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
468 if (!BUS_IS_OPEN(bus->state)) {
473 r = sd_bus_message_new_method_call(bus, &m, destination, path, "org.freedesktop.DBus.Properties", "Set");
477 r = sd_bus_message_append(m, "ss", strempty(interface), member);
481 r = sd_bus_message_open_container(m, 'v', type);
486 r = sd_bus_message_appendv(m, type, ap);
491 r = sd_bus_message_close_container(m);
495 return sd_bus_call(bus, m, 0, error, NULL);
498 return sd_bus_error_set_errno(error, r);
501 _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
504 assert_return(call, -EINVAL);
505 assert_return(call->sealed, -EPERM);
506 assert_return(call->bus, -EINVAL);
507 assert_return(!bus_pid_changed(call->bus), -ECHILD);
509 if (!BUS_IS_OPEN(call->bus->state))
512 c = sd_bus_message_get_creds(call);
514 /* All data we need? */
515 if (c && (mask & ~c->mask) == 0) {
516 *creds = sd_bus_creds_ref(c);
520 /* No data passed? Or not enough data passed to retrieve the missing bits? */
521 if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
522 /* We couldn't read anything from the call, let's try
523 * to get it from the sender or peer. */
526 /* There's a sender, but the creds are missing. */
527 return sd_bus_get_name_creds(call->bus, call->sender, mask, creds);
529 /* There's no sender. For direct connections
530 * the credentials of the AF_UNIX peer matter,
531 * which may be queried via sd_bus_get_owner_creds(). */
532 return sd_bus_get_owner_creds(call->bus, mask, creds);
535 return bus_creds_extend_by_pid(c, mask, creds);
538 _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
539 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
541 bool know_caps = false;
544 assert_return(call, -EINVAL);
545 assert_return(call->sealed, -EPERM);
546 assert_return(call->bus, -EINVAL);
547 assert_return(!bus_pid_changed(call->bus), -ECHILD);
549 if (!BUS_IS_OPEN(call->bus->state))
552 if (capability >= 0) {
554 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
558 /* We cannot use augmented caps for authorization,
559 * since then data is acquired raceful from
560 * /proc. This can never actually happen, but let's
561 * better be safe than sorry, and do an extra check
563 assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EFFECTIVE_CAPS) == 0, -EPERM);
565 r = sd_bus_creds_has_effective_cap(creds, capability);
571 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID, &creds);
576 /* Now, check the UID, but only if the capability check wasn't
579 if (our_uid != 0 || !know_caps || capability < 0) {
582 /* We cannot use augmented uid/euid for authorization,
583 * since then data is acquired raceful from
584 * /proc. This can never actually happen, but let's
585 * better be safe than sorry, and do an extra check
587 assert_return((sd_bus_creds_get_augmented_mask(creds) & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID)) == 0, -EPERM);
589 /* Try to use the EUID, if we have it. */
590 r = sd_bus_creds_get_euid(creds, &sender_uid);
592 r = sd_bus_creds_get_uid(creds, &sender_uid);
595 /* Sender has same UID as us, then let's grant access */
596 if (sender_uid == our_uid)
599 /* Sender is root, we are not root. */
600 if (our_uid != 0 && sender_uid == 0)
608 #define make_expression(sender, path, interface, member) \
611 sender ? ",sender='" : "", \
614 path ? ",path='" : "", \
617 interface ? ",interface='" : "", \
619 interface ? "'" : "", \
620 member ? ",member='" : "", \
625 _public_ int sd_bus_match_signal(
630 const char *interface,
632 sd_bus_message_handler_t callback,
635 const char *expression;
637 assert_return(bus, -EINVAL);
638 assert_return(bus = bus_resolve(bus), -ENOPKG);
639 assert_return(!bus_pid_changed(bus), -ECHILD);
640 assert_return(!sender || service_name_is_valid(sender), -EINVAL);
641 assert_return(!path || object_path_is_valid(path), -EINVAL);
642 assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
643 assert_return(!member || member_name_is_valid(member), -EINVAL);
645 expression = make_expression(sender, path, interface, member);
647 return sd_bus_add_match(bus, ret, expression, callback, userdata);
650 _public_ int sd_bus_match_signal_async(
655 const char *interface,
657 sd_bus_message_handler_t callback,
658 sd_bus_message_handler_t install_callback,
661 const char *expression;
663 assert_return(bus, -EINVAL);
664 assert_return(bus = bus_resolve(bus), -ENOPKG);
665 assert_return(!bus_pid_changed(bus), -ECHILD);
666 assert_return(!sender || service_name_is_valid(sender), -EINVAL);
667 assert_return(!path || object_path_is_valid(path), -EINVAL);
668 assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
669 assert_return(!member || member_name_is_valid(member), -EINVAL);
671 expression = make_expression(sender, path, interface, member);
673 return sd_bus_add_match_async(bus, ret, expression, callback, install_callback, userdata);