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"
28 _public_
int sd_bus_emit_signal(
31 const char *interface
,
33 const char *types
, ...) {
35 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
38 assert_return(bus
, -EINVAL
);
39 assert_return(!bus_pid_changed(bus
), -ECHILD
);
41 if (!BUS_IS_OPEN(bus
->state
))
44 r
= sd_bus_message_new_signal(bus
, &m
, path
, interface
, member
);
48 if (!isempty(types
)) {
52 r
= bus_message_append_ap(m
, types
, ap
);
58 return sd_bus_send(bus
, m
, NULL
);
61 _public_
int sd_bus_call_method_async(
64 const char *destination
,
66 const char *interface
,
68 sd_bus_message_handler_t callback
,
70 const char *types
, ...) {
72 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
75 assert_return(bus
, -EINVAL
);
76 assert_return(!bus_pid_changed(bus
), -ECHILD
);
78 if (!BUS_IS_OPEN(bus
->state
))
81 r
= sd_bus_message_new_method_call(bus
, &m
, destination
, path
, interface
, member
);
85 if (!isempty(types
)) {
89 r
= bus_message_append_ap(m
, types
, ap
);
95 return sd_bus_call_async(bus
, slot
, m
, callback
, userdata
, 0);
98 _public_
int sd_bus_call_method(
100 const char *destination
,
102 const char *interface
,
105 sd_bus_message
**reply
,
106 const char *types
, ...) {
108 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
111 bus_assert_return(bus
, -EINVAL
, error
);
112 bus_assert_return(!bus_pid_changed(bus
), -ECHILD
, error
);
114 if (!BUS_IS_OPEN(bus
->state
)) {
119 r
= sd_bus_message_new_method_call(bus
, &m
, destination
, path
, interface
, member
);
123 if (!isempty(types
)) {
127 r
= bus_message_append_ap(m
, types
, ap
);
133 return sd_bus_call(bus
, m
, 0, error
, reply
);
136 return sd_bus_error_set_errno(error
, r
);
139 _public_
int sd_bus_reply_method_return(
140 sd_bus_message
*call
,
141 const char *types
, ...) {
143 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
146 assert_return(call
, -EINVAL
);
147 assert_return(call
->sealed
, -EPERM
);
148 assert_return(call
->header
->type
== SD_BUS_MESSAGE_METHOD_CALL
, -EINVAL
);
149 assert_return(call
->bus
, -EINVAL
);
150 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
152 if (!BUS_IS_OPEN(call
->bus
->state
))
155 if (call
->header
->flags
& BUS_MESSAGE_NO_REPLY_EXPECTED
)
158 r
= sd_bus_message_new_method_return(call
, &m
);
162 if (!isempty(types
)) {
166 r
= bus_message_append_ap(m
, types
, ap
);
172 return sd_bus_send(call
->bus
, m
, NULL
);
175 _public_
int sd_bus_reply_method_error(
176 sd_bus_message
*call
,
177 const sd_bus_error
*e
) {
179 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
182 assert_return(call
, -EINVAL
);
183 assert_return(call
->sealed
, -EPERM
);
184 assert_return(call
->header
->type
== SD_BUS_MESSAGE_METHOD_CALL
, -EINVAL
);
185 assert_return(sd_bus_error_is_set(e
), -EINVAL
);
186 assert_return(call
->bus
, -EINVAL
);
187 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
189 if (!BUS_IS_OPEN(call
->bus
->state
))
192 if (call
->header
->flags
& BUS_MESSAGE_NO_REPLY_EXPECTED
)
195 r
= sd_bus_message_new_method_error(call
, &m
, e
);
199 return sd_bus_send(call
->bus
, m
, NULL
);
202 _public_
int sd_bus_reply_method_errorf(
203 sd_bus_message
*call
,
208 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
211 assert_return(call
, -EINVAL
);
212 assert_return(call
->sealed
, -EPERM
);
213 assert_return(call
->header
->type
== SD_BUS_MESSAGE_METHOD_CALL
, -EINVAL
);
214 assert_return(call
->bus
, -EINVAL
);
215 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
217 if (!BUS_IS_OPEN(call
->bus
->state
))
220 if (call
->header
->flags
& BUS_MESSAGE_NO_REPLY_EXPECTED
)
223 va_start(ap
, format
);
224 bus_error_setfv(&error
, name
, format
, ap
);
227 return sd_bus_reply_method_error(call
, &error
);
230 _public_
int sd_bus_reply_method_errno(
231 sd_bus_message
*call
,
233 const sd_bus_error
*p
) {
235 _cleanup_bus_error_free_ sd_bus_error berror
= SD_BUS_ERROR_NULL
;
237 assert_return(call
, -EINVAL
);
238 assert_return(call
->sealed
, -EPERM
);
239 assert_return(call
->header
->type
== SD_BUS_MESSAGE_METHOD_CALL
, -EINVAL
);
240 assert_return(call
->bus
, -EINVAL
);
241 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
243 if (!BUS_IS_OPEN(call
->bus
->state
))
246 if (call
->header
->flags
& BUS_MESSAGE_NO_REPLY_EXPECTED
)
249 if (sd_bus_error_is_set(p
))
250 return sd_bus_reply_method_error(call
, p
);
252 sd_bus_error_set_errno(&berror
, error
);
254 return sd_bus_reply_method_error(call
, &berror
);
257 _public_
int sd_bus_reply_method_errnof(
258 sd_bus_message
*call
,
263 _cleanup_bus_error_free_ sd_bus_error berror
= SD_BUS_ERROR_NULL
;
266 assert_return(call
, -EINVAL
);
267 assert_return(call
->sealed
, -EPERM
);
268 assert_return(call
->header
->type
== SD_BUS_MESSAGE_METHOD_CALL
, -EINVAL
);
269 assert_return(call
->bus
, -EINVAL
);
270 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
272 if (!BUS_IS_OPEN(call
->bus
->state
))
275 if (call
->header
->flags
& BUS_MESSAGE_NO_REPLY_EXPECTED
)
278 va_start(ap
, format
);
279 sd_bus_error_set_errnofv(&berror
, error
, format
, ap
);
282 return sd_bus_reply_method_error(call
, &berror
);
285 _public_
int sd_bus_get_property(
287 const char *destination
,
289 const char *interface
,
292 sd_bus_message
**reply
,
295 sd_bus_message
*rep
= NULL
;
298 bus_assert_return(bus
, -EINVAL
, error
);
299 bus_assert_return(isempty(interface
) || interface_name_is_valid(interface
), -EINVAL
, error
);
300 bus_assert_return(member_name_is_valid(member
), -EINVAL
, error
);
301 bus_assert_return(reply
, -EINVAL
, error
);
302 bus_assert_return(signature_is_single(type
, false), -EINVAL
, error
);
303 bus_assert_return(!bus_pid_changed(bus
), -ECHILD
, error
);
305 if (!BUS_IS_OPEN(bus
->state
)) {
310 r
= sd_bus_call_method(bus
, destination
, path
, "org.freedesktop.DBus.Properties", "Get", error
, &rep
, "ss", strempty(interface
), member
);
314 r
= sd_bus_message_enter_container(rep
, 'v', type
);
316 sd_bus_message_unref(rep
);
324 return sd_bus_error_set_errno(error
, r
);
327 _public_
int sd_bus_get_property_trivial(
329 const char *destination
,
331 const char *interface
,
334 char type
, void *ptr
) {
336 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
339 bus_assert_return(bus
, -EINVAL
, error
);
340 bus_assert_return(isempty(interface
) || interface_name_is_valid(interface
), -EINVAL
, error
);
341 bus_assert_return(member_name_is_valid(member
), -EINVAL
, error
);
342 bus_assert_return(bus_type_is_trivial(type
), -EINVAL
, error
);
343 bus_assert_return(ptr
, -EINVAL
, error
);
344 bus_assert_return(!bus_pid_changed(bus
), -ECHILD
, error
);
346 if (!BUS_IS_OPEN(bus
->state
)) {
351 r
= sd_bus_call_method(bus
, destination
, path
, "org.freedesktop.DBus.Properties", "Get", error
, &reply
, "ss", strempty(interface
), member
);
355 r
= sd_bus_message_enter_container(reply
, 'v', CHAR_TO_STR(type
));
359 r
= sd_bus_message_read_basic(reply
, type
, ptr
);
366 return sd_bus_error_set_errno(error
, r
);
369 _public_
int sd_bus_get_property_string(
371 const char *destination
,
373 const char *interface
,
378 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
383 bus_assert_return(bus
, -EINVAL
, error
);
384 bus_assert_return(isempty(interface
) || interface_name_is_valid(interface
), -EINVAL
, error
);
385 bus_assert_return(member_name_is_valid(member
), -EINVAL
, error
);
386 bus_assert_return(ret
, -EINVAL
, error
);
387 bus_assert_return(!bus_pid_changed(bus
), -ECHILD
, error
);
389 if (!BUS_IS_OPEN(bus
->state
)) {
394 r
= sd_bus_call_method(bus
, destination
, path
, "org.freedesktop.DBus.Properties", "Get", error
, &reply
, "ss", strempty(interface
), member
);
398 r
= sd_bus_message_enter_container(reply
, 'v', "s");
402 r
= sd_bus_message_read_basic(reply
, 's', &s
);
416 return sd_bus_error_set_errno(error
, r
);
419 _public_
int sd_bus_get_property_strv(
421 const char *destination
,
423 const char *interface
,
428 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
431 bus_assert_return(bus
, -EINVAL
, error
);
432 bus_assert_return(isempty(interface
) || interface_name_is_valid(interface
), -EINVAL
, error
);
433 bus_assert_return(member_name_is_valid(member
), -EINVAL
, error
);
434 bus_assert_return(ret
, -EINVAL
, error
);
435 bus_assert_return(!bus_pid_changed(bus
), -ECHILD
, error
);
437 if (!BUS_IS_OPEN(bus
->state
)) {
442 r
= sd_bus_call_method(bus
, destination
, path
, "org.freedesktop.DBus.Properties", "Get", error
, &reply
, "ss", strempty(interface
), member
);
446 r
= sd_bus_message_enter_container(reply
, 'v', NULL
);
450 r
= sd_bus_message_read_strv(reply
, ret
);
457 return sd_bus_error_set_errno(error
, r
);
460 _public_
int sd_bus_set_property(
462 const char *destination
,
464 const char *interface
,
467 const char *type
, ...) {
469 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
473 bus_assert_return(bus
, -EINVAL
, error
);
474 bus_assert_return(isempty(interface
) || interface_name_is_valid(interface
), -EINVAL
, error
);
475 bus_assert_return(member_name_is_valid(member
), -EINVAL
, error
);
476 bus_assert_return(signature_is_single(type
, false), -EINVAL
, error
);
477 bus_assert_return(!bus_pid_changed(bus
), -ECHILD
, error
);
479 if (!BUS_IS_OPEN(bus
->state
)) {
484 r
= sd_bus_message_new_method_call(bus
, &m
, destination
, path
, "org.freedesktop.DBus.Properties", "Set");
488 r
= sd_bus_message_append(m
, "ss", strempty(interface
), member
);
492 r
= sd_bus_message_open_container(m
, 'v', type
);
497 r
= bus_message_append_ap(m
, type
, ap
);
502 r
= sd_bus_message_close_container(m
);
506 return sd_bus_call(bus
, m
, 0, error
, NULL
);
509 return sd_bus_error_set_errno(error
, r
);
512 _public_
int sd_bus_query_sender_creds(sd_bus_message
*call
, uint64_t mask
, sd_bus_creds
**creds
) {
515 assert_return(call
, -EINVAL
);
516 assert_return(call
->sealed
, -EPERM
);
517 assert_return(call
->bus
, -EINVAL
);
518 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
520 if (!BUS_IS_OPEN(call
->bus
->state
))
523 c
= sd_bus_message_get_creds(call
);
525 /* All data we need? */
526 if (c
&& (mask
& ~c
->mask
) == 0) {
527 *creds
= sd_bus_creds_ref(c
);
531 /* No data passed? Or not enough data passed to retrieve the missing bits? */
532 if (!c
|| !(c
->mask
& SD_BUS_CREDS_PID
)) {
533 /* We couldn't read anything from the call, let's try
534 * to get it from the sender or peer. */
537 /* There's a sender, but the creds are
538 * missing. This means we are talking via
539 * dbus1, or are getting a message that was
540 * sent to us via kdbus, but was converted
541 * from a dbus1 message by the bus-proxy and
542 * thus also lacks the creds. */
543 return sd_bus_get_name_creds(call
->bus
, call
->sender
, mask
, creds
);
545 /* There's no sender, hence we are on a dbus1
546 * direct connection. For direct connections
547 * the credentials of the AF_UNIX peer matter,
548 * which may be queried via
549 * sd_bus_get_owner_creds(). */
550 return sd_bus_get_owner_creds(call
->bus
, mask
, creds
);
553 return bus_creds_extend_by_pid(c
, mask
, creds
);
556 _public_
int sd_bus_query_sender_privilege(sd_bus_message
*call
, int capability
) {
557 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
559 bool know_caps
= false;
562 assert_return(call
, -EINVAL
);
563 assert_return(call
->sealed
, -EPERM
);
564 assert_return(call
->bus
, -EINVAL
);
565 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
567 if (!BUS_IS_OPEN(call
->bus
->state
))
570 if (capability
>= 0) {
572 r
= sd_bus_query_sender_creds(call
, SD_BUS_CREDS_UID
|SD_BUS_CREDS_EUID
|SD_BUS_CREDS_EFFECTIVE_CAPS
, &creds
);
576 /* We cannot use augmented caps for authorization,
577 * since then data is acquired raceful from
578 * /proc. This can never actually happen, but let's
579 * better be safe than sorry, and do an extra check
581 assert_return((sd_bus_creds_get_augmented_mask(creds
) & SD_BUS_CREDS_EFFECTIVE_CAPS
) == 0, -EPERM
);
583 /* Note that not even on kdbus we might have the caps
584 * field, due to faked identities, or namespace
585 * translation issues. */
586 r
= sd_bus_creds_has_effective_cap(creds
, capability
);
592 r
= sd_bus_query_sender_creds(call
, SD_BUS_CREDS_UID
|SD_BUS_CREDS_EUID
, &creds
);
597 /* Now, check the UID, but only if the capability check wasn't
600 if (our_uid
!= 0 || !know_caps
|| capability
< 0) {
603 /* We cannot use augmented uid/euid for authorization,
604 * since then data is acquired raceful from
605 * /proc. This can never actually happen, but let's
606 * better be safe than sorry, and do an extra check
608 assert_return((sd_bus_creds_get_augmented_mask(creds
) & (SD_BUS_CREDS_UID
|SD_BUS_CREDS_EUID
)) == 0, -EPERM
);
610 /* Try to use the EUID, if we have it. */
611 r
= sd_bus_creds_get_euid(creds
, &sender_uid
);
613 r
= sd_bus_creds_get_uid(creds
, &sender_uid
);
616 /* Sender has same UID as us, then let's grant access */
617 if (sender_uid
== our_uid
)
620 /* Sender is root, we are not root. */
621 if (our_uid
!= 0 && sender_uid
== 0)