1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2013 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include "bus-internal.h"
22 #include "bus-message.h"
23 #include "bus-signature.h"
26 #include "string-util.h"
28 _public_
int sd_bus_emit_signal(
31 const char *interface
,
33 const char *types
, ...) {
35 _cleanup_(sd_bus_message_unrefp
) 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
= sd_bus_message_appendv(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_(sd_bus_message_unrefp
) 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
= sd_bus_message_appendv(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_(sd_bus_message_unrefp
) 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
= sd_bus_message_appendv(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_(sd_bus_message_unrefp
) 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
= sd_bus_message_appendv(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_(sd_bus_message_unrefp
) 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_(sd_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_(sd_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_(sd_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_(sd_bus_message_unrefp
) 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_(sd_bus_message_unrefp
) 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_(sd_bus_message_unrefp
) 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_(sd_bus_message_unrefp
) 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
= sd_bus_message_appendv(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 missing. */
538 return sd_bus_get_name_creds(call
->bus
, call
->sender
, mask
, creds
);
540 /* There's no sender. For direct connections
541 * the credentials of the AF_UNIX peer matter,
542 * which may be queried via sd_bus_get_owner_creds(). */
543 return sd_bus_get_owner_creds(call
->bus
, mask
, creds
);
546 return bus_creds_extend_by_pid(c
, mask
, creds
);
549 _public_
int sd_bus_query_sender_privilege(sd_bus_message
*call
, int capability
) {
550 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
552 bool know_caps
= false;
555 assert_return(call
, -EINVAL
);
556 assert_return(call
->sealed
, -EPERM
);
557 assert_return(call
->bus
, -EINVAL
);
558 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
560 if (!BUS_IS_OPEN(call
->bus
->state
))
563 if (capability
>= 0) {
565 r
= sd_bus_query_sender_creds(call
, SD_BUS_CREDS_UID
|SD_BUS_CREDS_EUID
|SD_BUS_CREDS_EFFECTIVE_CAPS
, &creds
);
569 /* We cannot use augmented caps for authorization,
570 * since then data is acquired raceful from
571 * /proc. This can never actually happen, but let's
572 * better be safe than sorry, and do an extra check
574 assert_return((sd_bus_creds_get_augmented_mask(creds
) & SD_BUS_CREDS_EFFECTIVE_CAPS
) == 0, -EPERM
);
576 r
= sd_bus_creds_has_effective_cap(creds
, capability
);
582 r
= sd_bus_query_sender_creds(call
, SD_BUS_CREDS_UID
|SD_BUS_CREDS_EUID
, &creds
);
587 /* Now, check the UID, but only if the capability check wasn't
590 if (our_uid
!= 0 || !know_caps
|| capability
< 0) {
593 /* We cannot use augmented uid/euid for authorization,
594 * since then data is acquired raceful from
595 * /proc. This can never actually happen, but let's
596 * better be safe than sorry, and do an extra check
598 assert_return((sd_bus_creds_get_augmented_mask(creds
) & (SD_BUS_CREDS_UID
|SD_BUS_CREDS_EUID
)) == 0, -EPERM
);
600 /* Try to use the EUID, if we have it. */
601 r
= sd_bus_creds_get_euid(creds
, &sender_uid
);
603 r
= sd_bus_creds_get_uid(creds
, &sender_uid
);
606 /* Sender has same UID as us, then let's grant access */
607 if (sender_uid
== our_uid
)
610 /* Sender is root, we are not root. */
611 if (our_uid
!= 0 && sender_uid
== 0)