1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright 2013 Lennart Poettering
6 #include "bus-internal.h"
7 #include "bus-message.h"
8 #include "bus-signature.h"
11 #include "string-util.h"
13 _public_ int sd_bus_emit_signal(
16 const char *interface,
18 const char *types, ...) {
20 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
23 assert_return(bus, -EINVAL);
24 assert_return(bus = bus_resolve(bus), -ENOPKG);
25 assert_return(!bus_pid_changed(bus), -ECHILD);
27 if (!BUS_IS_OPEN(bus->state))
30 r = sd_bus_message_new_signal(bus, &m, path, interface, member);
34 if (!isempty(types)) {
38 r = sd_bus_message_appendv(m, types, ap);
44 return sd_bus_send(bus, m, NULL);
47 _public_ int sd_bus_call_method_async(
50 const char *destination,
52 const char *interface,
54 sd_bus_message_handler_t callback,
56 const char *types, ...) {
58 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
61 assert_return(bus, -EINVAL);
62 assert_return(bus = bus_resolve(bus), -ENOPKG);
63 assert_return(!bus_pid_changed(bus), -ECHILD);
65 if (!BUS_IS_OPEN(bus->state))
68 r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
72 if (!isempty(types)) {
76 r = sd_bus_message_appendv(m, types, ap);
82 return sd_bus_call_async(bus, slot, m, callback, userdata, 0);
85 _public_ int sd_bus_call_method(
87 const char *destination,
89 const char *interface,
92 sd_bus_message **reply,
93 const char *types, ...) {
95 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
98 bus_assert_return(bus, -EINVAL, error);
99 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
101 if (!BUS_IS_OPEN(bus->state)) {
106 r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
110 if (!isempty(types)) {
114 r = sd_bus_message_appendv(m, types, ap);
120 return sd_bus_call(bus, m, 0, error, reply);
123 return sd_bus_error_set_errno(error, r);
126 _public_ int sd_bus_reply_method_return(
127 sd_bus_message *call,
128 const char *types, ...) {
130 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
133 assert_return(call, -EINVAL);
134 assert_return(call->sealed, -EPERM);
135 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
136 assert_return(call->bus, -EINVAL);
137 assert_return(!bus_pid_changed(call->bus), -ECHILD);
139 if (!BUS_IS_OPEN(call->bus->state))
142 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
145 r = sd_bus_message_new_method_return(call, &m);
149 if (!isempty(types)) {
153 r = sd_bus_message_appendv(m, types, ap);
159 return sd_bus_send(call->bus, m, NULL);
162 _public_ int sd_bus_reply_method_error(
163 sd_bus_message *call,
164 const sd_bus_error *e) {
166 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
169 assert_return(call, -EINVAL);
170 assert_return(call->sealed, -EPERM);
171 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
172 assert_return(sd_bus_error_is_set(e), -EINVAL);
173 assert_return(call->bus, -EINVAL);
174 assert_return(!bus_pid_changed(call->bus), -ECHILD);
176 if (!BUS_IS_OPEN(call->bus->state))
179 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
182 r = sd_bus_message_new_method_error(call, &m, e);
186 return sd_bus_send(call->bus, m, NULL);
189 _public_ int sd_bus_reply_method_errorf(
190 sd_bus_message *call,
195 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
198 assert_return(call, -EINVAL);
199 assert_return(call->sealed, -EPERM);
200 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
201 assert_return(call->bus, -EINVAL);
202 assert_return(!bus_pid_changed(call->bus), -ECHILD);
204 if (!BUS_IS_OPEN(call->bus->state))
207 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
210 va_start(ap, format);
211 bus_error_setfv(&error, name, format, ap);
214 return sd_bus_reply_method_error(call, &error);
217 _public_ int sd_bus_reply_method_errno(
218 sd_bus_message *call,
220 const sd_bus_error *p) {
222 _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
224 assert_return(call, -EINVAL);
225 assert_return(call->sealed, -EPERM);
226 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
227 assert_return(call->bus, -EINVAL);
228 assert_return(!bus_pid_changed(call->bus), -ECHILD);
230 if (!BUS_IS_OPEN(call->bus->state))
233 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
236 if (sd_bus_error_is_set(p))
237 return sd_bus_reply_method_error(call, p);
239 sd_bus_error_set_errno(&berror, error);
241 return sd_bus_reply_method_error(call, &berror);
244 _public_ int sd_bus_reply_method_errnof(
245 sd_bus_message *call,
250 _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
253 assert_return(call, -EINVAL);
254 assert_return(call->sealed, -EPERM);
255 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
256 assert_return(call->bus, -EINVAL);
257 assert_return(!bus_pid_changed(call->bus), -ECHILD);
259 if (!BUS_IS_OPEN(call->bus->state))
262 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
265 va_start(ap, format);
266 sd_bus_error_set_errnofv(&berror, error, format, ap);
269 return sd_bus_reply_method_error(call, &berror);
272 _public_ int sd_bus_get_property(
274 const char *destination,
276 const char *interface,
279 sd_bus_message **reply,
282 sd_bus_message *rep = NULL;
285 bus_assert_return(bus, -EINVAL, error);
286 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
287 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
288 bus_assert_return(reply, -EINVAL, error);
289 bus_assert_return(signature_is_single(type, false), -EINVAL, error);
290 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
292 if (!BUS_IS_OPEN(bus->state)) {
297 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
301 r = sd_bus_message_enter_container(rep, 'v', type);
303 sd_bus_message_unref(rep);
311 return sd_bus_error_set_errno(error, r);
314 _public_ int sd_bus_get_property_trivial(
316 const char *destination,
318 const char *interface,
321 char type, void *ptr) {
323 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
326 bus_assert_return(bus, -EINVAL, error);
327 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
328 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
329 bus_assert_return(bus_type_is_trivial(type), -EINVAL, error);
330 bus_assert_return(ptr, -EINVAL, error);
331 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
333 if (!BUS_IS_OPEN(bus->state)) {
338 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
342 r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
346 r = sd_bus_message_read_basic(reply, type, ptr);
353 return sd_bus_error_set_errno(error, r);
356 _public_ int sd_bus_get_property_string(
358 const char *destination,
360 const char *interface,
365 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
370 bus_assert_return(bus, -EINVAL, error);
371 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
372 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
373 bus_assert_return(ret, -EINVAL, error);
374 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
376 if (!BUS_IS_OPEN(bus->state)) {
381 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
385 r = sd_bus_message_enter_container(reply, 'v', "s");
389 r = sd_bus_message_read_basic(reply, 's', &s);
403 return sd_bus_error_set_errno(error, r);
406 _public_ int sd_bus_get_property_strv(
408 const char *destination,
410 const char *interface,
415 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
418 bus_assert_return(bus, -EINVAL, error);
419 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
420 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
421 bus_assert_return(ret, -EINVAL, error);
422 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
424 if (!BUS_IS_OPEN(bus->state)) {
429 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
433 r = sd_bus_message_enter_container(reply, 'v', NULL);
437 r = sd_bus_message_read_strv(reply, ret);
444 return sd_bus_error_set_errno(error, r);
447 _public_ int sd_bus_set_property(
449 const char *destination,
451 const char *interface,
454 const char *type, ...) {
456 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
460 bus_assert_return(bus, -EINVAL, error);
461 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
462 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
463 bus_assert_return(signature_is_single(type, false), -EINVAL, error);
464 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
466 if (!BUS_IS_OPEN(bus->state)) {
471 r = sd_bus_message_new_method_call(bus, &m, destination, path, "org.freedesktop.DBus.Properties", "Set");
475 r = sd_bus_message_append(m, "ss", strempty(interface), member);
479 r = sd_bus_message_open_container(m, 'v', type);
484 r = sd_bus_message_appendv(m, type, ap);
489 r = sd_bus_message_close_container(m);
493 return sd_bus_call(bus, m, 0, error, NULL);
496 return sd_bus_error_set_errno(error, r);
499 _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
502 assert_return(call, -EINVAL);
503 assert_return(call->sealed, -EPERM);
504 assert_return(call->bus, -EINVAL);
505 assert_return(!bus_pid_changed(call->bus), -ECHILD);
507 if (!BUS_IS_OPEN(call->bus->state))
510 c = sd_bus_message_get_creds(call);
512 /* All data we need? */
513 if (c && (mask & ~c->mask) == 0) {
514 *creds = sd_bus_creds_ref(c);
518 /* No data passed? Or not enough data passed to retrieve the missing bits? */
519 if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
520 /* We couldn't read anything from the call, let's try
521 * to get it from the sender or peer. */
524 /* There's a sender, but the creds are missing. */
525 return sd_bus_get_name_creds(call->bus, call->sender, mask, creds);
527 /* There's no sender. For direct connections
528 * the credentials of the AF_UNIX peer matter,
529 * which may be queried via sd_bus_get_owner_creds(). */
530 return sd_bus_get_owner_creds(call->bus, mask, creds);
533 return bus_creds_extend_by_pid(c, mask, creds);
536 _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
537 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
539 bool know_caps = false;
542 assert_return(call, -EINVAL);
543 assert_return(call->sealed, -EPERM);
544 assert_return(call->bus, -EINVAL);
545 assert_return(!bus_pid_changed(call->bus), -ECHILD);
547 if (!BUS_IS_OPEN(call->bus->state))
550 if (capability >= 0) {
552 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
556 /* We cannot use augmented caps for authorization,
557 * since then data is acquired raceful from
558 * /proc. This can never actually happen, but let's
559 * better be safe than sorry, and do an extra check
561 assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EFFECTIVE_CAPS) == 0, -EPERM);
563 r = sd_bus_creds_has_effective_cap(creds, capability);
569 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID, &creds);
574 /* Now, check the UID, but only if the capability check wasn't
577 if (our_uid != 0 || !know_caps || capability < 0) {
580 /* We cannot use augmented uid/euid for authorization,
581 * since then data is acquired raceful from
582 * /proc. This can never actually happen, but let's
583 * better be safe than sorry, and do an extra check
585 assert_return((sd_bus_creds_get_augmented_mask(creds) & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID)) == 0, -EPERM);
587 /* Try to use the EUID, if we have it. */
588 r = sd_bus_creds_get_euid(creds, &sender_uid);
590 r = sd_bus_creds_get_uid(creds, &sender_uid);
593 /* Sender has same UID as us, then let's grant access */
594 if (sender_uid == our_uid)
597 /* Sender is root, we are not root. */
598 if (our_uid != 0 && sender_uid == 0)
606 #define make_expression(sender, path, interface, member) \
609 sender ? ",sender='" : "", \
612 path ? ",path='" : "", \
615 interface ? ",interface='" : "", \
617 interface ? "'" : "", \
618 member ? ",member='" : "", \
623 _public_ int sd_bus_match_signal(
628 const char *interface,
630 sd_bus_message_handler_t callback,
633 const char *expression;
635 assert_return(bus, -EINVAL);
636 assert_return(bus = bus_resolve(bus), -ENOPKG);
637 assert_return(!bus_pid_changed(bus), -ECHILD);
638 assert_return(!sender || service_name_is_valid(sender), -EINVAL);
639 assert_return(!path || object_path_is_valid(path), -EINVAL);
640 assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
641 assert_return(!member || member_name_is_valid(member), -EINVAL);
643 expression = make_expression(sender, path, interface, member);
645 return sd_bus_add_match(bus, ret, expression, callback, userdata);
648 _public_ int sd_bus_match_signal_async(
653 const char *interface,
655 sd_bus_message_handler_t callback,
656 sd_bus_message_handler_t install_callback,
659 const char *expression;
661 assert_return(bus, -EINVAL);
662 assert_return(bus = bus_resolve(bus), -ENOPKG);
663 assert_return(!bus_pid_changed(bus), -ECHILD);
664 assert_return(!sender || service_name_is_valid(sender), -EINVAL);
665 assert_return(!path || object_path_is_valid(path), -EINVAL);
666 assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
667 assert_return(!member || member_name_is_valid(member), -EINVAL);
669 expression = make_expression(sender, path, interface, member);
671 return sd_bus_add_match_async(bus, ret, expression, callback, install_callback, userdata);