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
);