1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include "bus-internal.h"
23 #include "bus-message.h"
24 #include "bus-signature.h"
27 #include "string-util.h"
29 _public_
int sd_bus_emit_signal(
32 const char *interface
,
34 const char *types
, ...) {
36 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
39 assert_return(bus
, -EINVAL
);
40 assert_return(!bus_pid_changed(bus
), -ECHILD
);
42 if (!BUS_IS_OPEN(bus
->state
))
45 r
= sd_bus_message_new_signal(bus
, &m
, path
, interface
, member
);
49 if (!isempty(types
)) {
53 r
= bus_message_append_ap(m
, types
, ap
);
59 return sd_bus_send(bus
, m
, NULL
);
62 _public_
int sd_bus_call_method_async(
65 const char *destination
,
67 const char *interface
,
69 sd_bus_message_handler_t callback
,
71 const char *types
, ...) {
73 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
76 assert_return(bus
, -EINVAL
);
77 assert_return(!bus_pid_changed(bus
), -ECHILD
);
79 if (!BUS_IS_OPEN(bus
->state
))
82 r
= sd_bus_message_new_method_call(bus
, &m
, destination
, path
, interface
, member
);
86 if (!isempty(types
)) {
90 r
= bus_message_append_ap(m
, types
, ap
);
96 return sd_bus_call_async(bus
, slot
, m
, callback
, userdata
, 0);
99 _public_
int sd_bus_call_method(
101 const char *destination
,
103 const char *interface
,
106 sd_bus_message
**reply
,
107 const char *types
, ...) {
109 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
112 bus_assert_return(bus
, -EINVAL
, error
);
113 bus_assert_return(!bus_pid_changed(bus
), -ECHILD
, error
);
115 if (!BUS_IS_OPEN(bus
->state
)) {
120 r
= sd_bus_message_new_method_call(bus
, &m
, destination
, path
, interface
, member
);
124 if (!isempty(types
)) {
128 r
= bus_message_append_ap(m
, types
, ap
);
134 return sd_bus_call(bus
, m
, 0, error
, reply
);
137 return sd_bus_error_set_errno(error
, r
);
140 _public_
int sd_bus_reply_method_return(
141 sd_bus_message
*call
,
142 const char *types
, ...) {
144 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
147 assert_return(call
, -EINVAL
);
148 assert_return(call
->sealed
, -EPERM
);
149 assert_return(call
->header
->type
== SD_BUS_MESSAGE_METHOD_CALL
, -EINVAL
);
150 assert_return(call
->bus
, -EINVAL
);
151 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
153 if (!BUS_IS_OPEN(call
->bus
->state
))
156 if (call
->header
->flags
& BUS_MESSAGE_NO_REPLY_EXPECTED
)
159 r
= sd_bus_message_new_method_return(call
, &m
);
163 if (!isempty(types
)) {
167 r
= bus_message_append_ap(m
, types
, ap
);
173 return sd_bus_send(call
->bus
, m
, NULL
);
176 _public_
int sd_bus_reply_method_error(
177 sd_bus_message
*call
,
178 const sd_bus_error
*e
) {
180 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
183 assert_return(call
, -EINVAL
);
184 assert_return(call
->sealed
, -EPERM
);
185 assert_return(call
->header
->type
== SD_BUS_MESSAGE_METHOD_CALL
, -EINVAL
);
186 assert_return(sd_bus_error_is_set(e
), -EINVAL
);
187 assert_return(call
->bus
, -EINVAL
);
188 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
190 if (!BUS_IS_OPEN(call
->bus
->state
))
193 if (call
->header
->flags
& BUS_MESSAGE_NO_REPLY_EXPECTED
)
196 r
= sd_bus_message_new_method_error(call
, &m
, e
);
200 return sd_bus_send(call
->bus
, m
, NULL
);
203 _public_
int sd_bus_reply_method_errorf(
204 sd_bus_message
*call
,
209 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
212 assert_return(call
, -EINVAL
);
213 assert_return(call
->sealed
, -EPERM
);
214 assert_return(call
->header
->type
== SD_BUS_MESSAGE_METHOD_CALL
, -EINVAL
);
215 assert_return(call
->bus
, -EINVAL
);
216 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
218 if (!BUS_IS_OPEN(call
->bus
->state
))
221 if (call
->header
->flags
& BUS_MESSAGE_NO_REPLY_EXPECTED
)
224 va_start(ap
, format
);
225 bus_error_setfv(&error
, name
, format
, ap
);
228 return sd_bus_reply_method_error(call
, &error
);
231 _public_
int sd_bus_reply_method_errno(
232 sd_bus_message
*call
,
234 const sd_bus_error
*p
) {
236 _cleanup_bus_error_free_ sd_bus_error berror
= SD_BUS_ERROR_NULL
;
238 assert_return(call
, -EINVAL
);
239 assert_return(call
->sealed
, -EPERM
);
240 assert_return(call
->header
->type
== SD_BUS_MESSAGE_METHOD_CALL
, -EINVAL
);
241 assert_return(call
->bus
, -EINVAL
);
242 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
244 if (!BUS_IS_OPEN(call
->bus
->state
))
247 if (call
->header
->flags
& BUS_MESSAGE_NO_REPLY_EXPECTED
)
250 if (sd_bus_error_is_set(p
))
251 return sd_bus_reply_method_error(call
, p
);
253 sd_bus_error_set_errno(&berror
, error
);
255 return sd_bus_reply_method_error(call
, &berror
);
258 _public_
int sd_bus_reply_method_errnof(
259 sd_bus_message
*call
,
264 _cleanup_bus_error_free_ sd_bus_error berror
= SD_BUS_ERROR_NULL
;
267 assert_return(call
, -EINVAL
);
268 assert_return(call
->sealed
, -EPERM
);
269 assert_return(call
->header
->type
== SD_BUS_MESSAGE_METHOD_CALL
, -EINVAL
);
270 assert_return(call
->bus
, -EINVAL
);
271 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
273 if (!BUS_IS_OPEN(call
->bus
->state
))
276 if (call
->header
->flags
& BUS_MESSAGE_NO_REPLY_EXPECTED
)
279 va_start(ap
, format
);
280 sd_bus_error_set_errnofv(&berror
, error
, format
, ap
);
283 return sd_bus_reply_method_error(call
, &berror
);
286 _public_
int sd_bus_get_property(
288 const char *destination
,
290 const char *interface
,
293 sd_bus_message
**reply
,
296 sd_bus_message
*rep
= NULL
;
299 bus_assert_return(bus
, -EINVAL
, error
);
300 bus_assert_return(isempty(interface
) || interface_name_is_valid(interface
), -EINVAL
, error
);
301 bus_assert_return(member_name_is_valid(member
), -EINVAL
, error
);
302 bus_assert_return(reply
, -EINVAL
, error
);
303 bus_assert_return(signature_is_single(type
, false), -EINVAL
, error
);
304 bus_assert_return(!bus_pid_changed(bus
), -ECHILD
, error
);
306 if (!BUS_IS_OPEN(bus
->state
)) {
311 r
= sd_bus_call_method(bus
, destination
, path
, "org.freedesktop.DBus.Properties", "Get", error
, &rep
, "ss", strempty(interface
), member
);
315 r
= sd_bus_message_enter_container(rep
, 'v', type
);
317 sd_bus_message_unref(rep
);
325 return sd_bus_error_set_errno(error
, r
);
328 _public_
int sd_bus_get_property_trivial(
330 const char *destination
,
332 const char *interface
,
335 char type
, void *ptr
) {
337 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
340 bus_assert_return(bus
, -EINVAL
, error
);
341 bus_assert_return(isempty(interface
) || interface_name_is_valid(interface
), -EINVAL
, error
);
342 bus_assert_return(member_name_is_valid(member
), -EINVAL
, error
);
343 bus_assert_return(bus_type_is_trivial(type
), -EINVAL
, error
);
344 bus_assert_return(ptr
, -EINVAL
, error
);
345 bus_assert_return(!bus_pid_changed(bus
), -ECHILD
, error
);
347 if (!BUS_IS_OPEN(bus
->state
)) {
352 r
= sd_bus_call_method(bus
, destination
, path
, "org.freedesktop.DBus.Properties", "Get", error
, &reply
, "ss", strempty(interface
), member
);
356 r
= sd_bus_message_enter_container(reply
, 'v', CHAR_TO_STR(type
));
360 r
= sd_bus_message_read_basic(reply
, type
, ptr
);
367 return sd_bus_error_set_errno(error
, r
);
370 _public_
int sd_bus_get_property_string(
372 const char *destination
,
374 const char *interface
,
379 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
384 bus_assert_return(bus
, -EINVAL
, error
);
385 bus_assert_return(isempty(interface
) || interface_name_is_valid(interface
), -EINVAL
, error
);
386 bus_assert_return(member_name_is_valid(member
), -EINVAL
, error
);
387 bus_assert_return(ret
, -EINVAL
, error
);
388 bus_assert_return(!bus_pid_changed(bus
), -ECHILD
, error
);
390 if (!BUS_IS_OPEN(bus
->state
)) {
395 r
= sd_bus_call_method(bus
, destination
, path
, "org.freedesktop.DBus.Properties", "Get", error
, &reply
, "ss", strempty(interface
), member
);
399 r
= sd_bus_message_enter_container(reply
, 'v', "s");
403 r
= sd_bus_message_read_basic(reply
, 's', &s
);
417 return sd_bus_error_set_errno(error
, r
);
420 _public_
int sd_bus_get_property_strv(
422 const char *destination
,
424 const char *interface
,
429 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
432 bus_assert_return(bus
, -EINVAL
, error
);
433 bus_assert_return(isempty(interface
) || interface_name_is_valid(interface
), -EINVAL
, error
);
434 bus_assert_return(member_name_is_valid(member
), -EINVAL
, error
);
435 bus_assert_return(ret
, -EINVAL
, error
);
436 bus_assert_return(!bus_pid_changed(bus
), -ECHILD
, error
);
438 if (!BUS_IS_OPEN(bus
->state
)) {
443 r
= sd_bus_call_method(bus
, destination
, path
, "org.freedesktop.DBus.Properties", "Get", error
, &reply
, "ss", strempty(interface
), member
);
447 r
= sd_bus_message_enter_container(reply
, 'v', NULL
);
451 r
= sd_bus_message_read_strv(reply
, ret
);
458 return sd_bus_error_set_errno(error
, r
);
461 _public_
int sd_bus_set_property(
463 const char *destination
,
465 const char *interface
,
468 const char *type
, ...) {
470 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
474 bus_assert_return(bus
, -EINVAL
, error
);
475 bus_assert_return(isempty(interface
) || interface_name_is_valid(interface
), -EINVAL
, error
);
476 bus_assert_return(member_name_is_valid(member
), -EINVAL
, error
);
477 bus_assert_return(signature_is_single(type
, false), -EINVAL
, error
);
478 bus_assert_return(!bus_pid_changed(bus
), -ECHILD
, error
);
480 if (!BUS_IS_OPEN(bus
->state
)) {
485 r
= sd_bus_message_new_method_call(bus
, &m
, destination
, path
, "org.freedesktop.DBus.Properties", "Set");
489 r
= sd_bus_message_append(m
, "ss", strempty(interface
), member
);
493 r
= sd_bus_message_open_container(m
, 'v', type
);
498 r
= bus_message_append_ap(m
, type
, ap
);
503 r
= sd_bus_message_close_container(m
);
507 return sd_bus_call(bus
, m
, 0, error
, NULL
);
510 return sd_bus_error_set_errno(error
, r
);
513 _public_
int sd_bus_query_sender_creds(sd_bus_message
*call
, uint64_t mask
, sd_bus_creds
**creds
) {
516 assert_return(call
, -EINVAL
);
517 assert_return(call
->sealed
, -EPERM
);
518 assert_return(call
->bus
, -EINVAL
);
519 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
521 if (!BUS_IS_OPEN(call
->bus
->state
))
524 c
= sd_bus_message_get_creds(call
);
526 /* All data we need? */
527 if (c
&& (mask
& ~c
->mask
) == 0) {
528 *creds
= sd_bus_creds_ref(c
);
532 /* No data passed? Or not enough data passed to retrieve the missing bits? */
533 if (!c
|| !(c
->mask
& SD_BUS_CREDS_PID
)) {
534 /* We couldn't read anything from the call, let's try
535 * to get it from the sender or peer. */
538 /* There's a sender, but the creds are
539 * missing. This means we are talking via
540 * dbus1, or are getting a message that was
541 * sent to us via kdbus, but was converted
542 * from a dbus1 message by the bus-proxy and
543 * thus also lacks the creds. */
544 return sd_bus_get_name_creds(call
->bus
, call
->sender
, mask
, creds
);
546 /* There's no sender, hence we are on a dbus1
547 * direct connection. For direct connections
548 * the credentials of the AF_UNIX peer matter,
549 * which may be queried via
550 * sd_bus_get_owner_creds(). */
551 return sd_bus_get_owner_creds(call
->bus
, mask
, creds
);
554 return bus_creds_extend_by_pid(c
, mask
, creds
);
557 _public_
int sd_bus_query_sender_privilege(sd_bus_message
*call
, int capability
) {
558 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
560 bool know_caps
= false;
563 assert_return(call
, -EINVAL
);
564 assert_return(call
->sealed
, -EPERM
);
565 assert_return(call
->bus
, -EINVAL
);
566 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
568 if (!BUS_IS_OPEN(call
->bus
->state
))
571 if (capability
>= 0) {
573 r
= sd_bus_query_sender_creds(call
, SD_BUS_CREDS_UID
|SD_BUS_CREDS_EUID
|SD_BUS_CREDS_EFFECTIVE_CAPS
, &creds
);
577 /* We cannot use augmented caps for authorization,
578 * since then data is acquired raceful from
579 * /proc. This can never actually happen, but let's
580 * better be safe than sorry, and do an extra check
582 assert_return((sd_bus_creds_get_augmented_mask(creds
) & SD_BUS_CREDS_EFFECTIVE_CAPS
) == 0, -EPERM
);
584 /* Note that not even on kdbus we might have the caps
585 * field, due to faked identities, or namespace
586 * translation issues. */
587 r
= sd_bus_creds_has_effective_cap(creds
, capability
);
593 r
= sd_bus_query_sender_creds(call
, SD_BUS_CREDS_UID
|SD_BUS_CREDS_EUID
, &creds
);
598 /* Now, check the UID, but only if the capability check wasn't
601 if (our_uid
!= 0 || !know_caps
|| capability
< 0) {
604 /* We cannot use augmented uid/euid for authorization,
605 * since then data is acquired raceful from
606 * /proc. This can never actually happen, but let's
607 * better be safe than sorry, and do an extra check
609 assert_return((sd_bus_creds_get_augmented_mask(creds
) & (SD_BUS_CREDS_UID
|SD_BUS_CREDS_EUID
)) == 0, -EPERM
);
611 /* Try to use the EUID, if we have it. */
612 r
= sd_bus_creds_get_euid(creds
, &sender_uid
);
614 r
= sd_bus_creds_get_uid(creds
, &sender_uid
);
617 /* Sender has same UID as us, then let's grant access */
618 if (sender_uid
== our_uid
)
621 /* Sender is root, we are not root. */
622 if (our_uid
!= 0 && sender_uid
== 0)