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(
63 const char *destination
,
65 const char *interface
,
68 sd_bus_message
**reply
,
69 const char *types
, ...) {
71 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
74 assert_return(bus
, -EINVAL
);
75 assert_return(!bus_pid_changed(bus
), -ECHILD
);
77 if (!BUS_IS_OPEN(bus
->state
))
80 r
= sd_bus_message_new_method_call(bus
, &m
, destination
, path
, interface
, member
);
84 if (!isempty(types
)) {
88 r
= bus_message_append_ap(m
, types
, ap
);
94 return sd_bus_call(bus
, m
, 0, error
, reply
);
97 _public_
int sd_bus_reply_method_return(
99 const char *types
, ...) {
101 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
104 assert_return(call
, -EINVAL
);
105 assert_return(call
->sealed
, -EPERM
);
106 assert_return(call
->header
->type
== SD_BUS_MESSAGE_METHOD_CALL
, -EINVAL
);
107 assert_return(call
->bus
, -EINVAL
);
108 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
110 if (!BUS_IS_OPEN(call
->bus
->state
))
113 if (call
->header
->flags
& BUS_MESSAGE_NO_REPLY_EXPECTED
)
116 r
= sd_bus_message_new_method_return(call
, &m
);
120 if (!isempty(types
)) {
124 r
= bus_message_append_ap(m
, types
, ap
);
130 return sd_bus_send(call
->bus
, m
, NULL
);
133 _public_
int sd_bus_reply_method_error(
134 sd_bus_message
*call
,
135 const sd_bus_error
*e
) {
137 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
140 assert_return(call
, -EINVAL
);
141 assert_return(call
->sealed
, -EPERM
);
142 assert_return(call
->header
->type
== SD_BUS_MESSAGE_METHOD_CALL
, -EINVAL
);
143 assert_return(sd_bus_error_is_set(e
), -EINVAL
);
144 assert_return(call
->bus
, -EINVAL
);
145 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
147 if (!BUS_IS_OPEN(call
->bus
->state
))
150 if (call
->header
->flags
& BUS_MESSAGE_NO_REPLY_EXPECTED
)
153 r
= sd_bus_message_new_method_error(call
, &m
, e
);
157 return sd_bus_send(call
->bus
, m
, NULL
);
160 _public_
int sd_bus_reply_method_errorf(
161 sd_bus_message
*call
,
166 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_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(call
->bus
, -EINVAL
);
173 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
175 if (!BUS_IS_OPEN(call
->bus
->state
))
178 if (call
->header
->flags
& BUS_MESSAGE_NO_REPLY_EXPECTED
)
181 va_start(ap
, format
);
182 bus_error_setfv(&error
, name
, format
, ap
);
185 return sd_bus_reply_method_error(call
, &error
);
188 _public_
int sd_bus_reply_method_errno(
189 sd_bus_message
*call
,
191 const sd_bus_error
*p
) {
193 _cleanup_bus_error_free_ sd_bus_error berror
= SD_BUS_ERROR_NULL
;
195 assert_return(call
, -EINVAL
);
196 assert_return(call
->sealed
, -EPERM
);
197 assert_return(call
->header
->type
== SD_BUS_MESSAGE_METHOD_CALL
, -EINVAL
);
198 assert_return(call
->bus
, -EINVAL
);
199 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
201 if (!BUS_IS_OPEN(call
->bus
->state
))
204 if (call
->header
->flags
& BUS_MESSAGE_NO_REPLY_EXPECTED
)
207 if (sd_bus_error_is_set(p
))
208 return sd_bus_reply_method_error(call
, p
);
210 sd_bus_error_set_errno(&berror
, error
);
212 return sd_bus_reply_method_error(call
, &berror
);
215 _public_
int sd_bus_reply_method_errnof(
216 sd_bus_message
*call
,
221 _cleanup_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 va_start(ap
, format
);
237 bus_error_set_errnofv(&berror
, error
, format
, ap
);
240 return sd_bus_reply_method_error(call
, &berror
);
243 _public_
int sd_bus_get_property(
245 const char *destination
,
247 const char *interface
,
250 sd_bus_message
**reply
,
253 sd_bus_message
*rep
= NULL
;
256 assert_return(bus
, -EINVAL
);
257 assert_return(isempty(interface
) || interface_name_is_valid(interface
), -EINVAL
);
258 assert_return(member_name_is_valid(member
), -EINVAL
);
259 assert_return(reply
, -EINVAL
);
260 assert_return(signature_is_single(type
, false), -EINVAL
);
261 assert_return(!bus_pid_changed(bus
), -ECHILD
);
263 if (!BUS_IS_OPEN(bus
->state
))
266 r
= sd_bus_call_method(bus
, destination
, path
, "org.freedesktop.DBus.Properties", "Get", error
, &rep
, "ss", strempty(interface
), member
);
270 r
= sd_bus_message_enter_container(rep
, 'v', type
);
272 sd_bus_message_unref(rep
);
280 _public_
int sd_bus_get_property_trivial(
282 const char *destination
,
284 const char *interface
,
287 char type
, void *ptr
) {
289 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
292 assert_return(bus
, -EINVAL
);
293 assert_return(isempty(interface
) || interface_name_is_valid(interface
), -EINVAL
);
294 assert_return(member_name_is_valid(member
), -EINVAL
);
295 assert_return(bus_type_is_trivial(type
), -EINVAL
);
296 assert_return(ptr
, -EINVAL
);
297 assert_return(!bus_pid_changed(bus
), -ECHILD
);
299 if (!BUS_IS_OPEN(bus
->state
))
302 r
= sd_bus_call_method(bus
, destination
, path
, "org.freedesktop.DBus.Properties", "Get", error
, &reply
, "ss", strempty(interface
), member
);
306 r
= sd_bus_message_enter_container(reply
, 'v', CHAR_TO_STR(type
));
310 r
= sd_bus_message_read_basic(reply
, type
, ptr
);
317 _public_
int sd_bus_get_property_string(
319 const char *destination
,
321 const char *interface
,
326 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
331 assert_return(bus
, -EINVAL
);
332 assert_return(isempty(interface
) || interface_name_is_valid(interface
), -EINVAL
);
333 assert_return(member_name_is_valid(member
), -EINVAL
);
334 assert_return(ret
, -EINVAL
);
335 assert_return(!bus_pid_changed(bus
), -ECHILD
);
337 if (!BUS_IS_OPEN(bus
->state
))
340 r
= sd_bus_call_method(bus
, destination
, path
, "org.freedesktop.DBus.Properties", "Get", error
, &reply
, "ss", strempty(interface
), member
);
344 r
= sd_bus_message_enter_container(reply
, 'v', "s");
348 r
= sd_bus_message_read_basic(reply
, 's', &s
);
360 _public_
int sd_bus_get_property_strv(
362 const char *destination
,
364 const char *interface
,
369 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
372 assert_return(bus
, -EINVAL
);
373 assert_return(isempty(interface
) || interface_name_is_valid(interface
), -EINVAL
);
374 assert_return(member_name_is_valid(member
), -EINVAL
);
375 assert_return(ret
, -EINVAL
);
376 assert_return(!bus_pid_changed(bus
), -ECHILD
);
378 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', NULL
);
389 r
= sd_bus_message_read_strv(reply
, ret
);
396 _public_
int sd_bus_set_property(
398 const char *destination
,
400 const char *interface
,
403 const char *type
, ...) {
405 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
409 assert_return(bus
, -EINVAL
);
410 assert_return(isempty(interface
) || interface_name_is_valid(interface
), -EINVAL
);
411 assert_return(member_name_is_valid(member
), -EINVAL
);
412 assert_return(signature_is_single(type
, false), -EINVAL
);
413 assert_return(!bus_pid_changed(bus
), -ECHILD
);
415 if (!BUS_IS_OPEN(bus
->state
))
418 r
= sd_bus_message_new_method_call(bus
, &m
, destination
, path
, "org.freedesktop.DBus.Properties", "Set");
422 r
= sd_bus_message_append(m
, "ss", strempty(interface
), member
);
426 r
= sd_bus_message_open_container(m
, 'v', type
);
431 r
= bus_message_append_ap(m
, type
, ap
);
436 r
= sd_bus_message_close_container(m
);
440 return sd_bus_call(bus
, m
, 0, error
, NULL
);
443 _public_
int sd_bus_query_sender_creds(sd_bus_message
*call
, uint64_t mask
, sd_bus_creds
**creds
) {
446 assert_return(call
, -EINVAL
);
447 assert_return(call
->sealed
, -EPERM
);
448 assert_return(call
->bus
, -EINVAL
);
449 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
451 if (!BUS_IS_OPEN(call
->bus
->state
))
454 c
= sd_bus_message_get_creds(call
);
456 /* All data we need? */
457 if (c
&& (mask
& ~c
->mask
) == 0) {
458 *creds
= sd_bus_creds_ref(c
);
462 /* No data passed? Or not enough data passed to retrieve the missing bits? */
463 if (!c
|| !(c
->mask
& SD_BUS_CREDS_PID
)) {
464 /* We couldn't read anything from the call, let's try
465 * to get it from the sender or peer */
468 return sd_bus_get_name_creds(call
->bus
, call
->sender
, mask
, creds
);
470 return sd_bus_get_owner_creds(call
->bus
, mask
, creds
);
473 return bus_creds_extend_by_pid(c
, mask
, creds
);
476 _public_
int sd_bus_query_sender_privilege(sd_bus_message
*call
, int capability
) {
477 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
479 bool know_caps
= false;
482 assert_return(call
, -EINVAL
);
483 assert_return(call
->sealed
, -EPERM
);
484 assert_return(call
->bus
, -EINVAL
);
485 assert_return(!bus_pid_changed(call
->bus
), -ECHILD
);
487 if (!BUS_IS_OPEN(call
->bus
->state
))
490 if (capability
>= 0) {
491 r
= sd_bus_query_sender_creds(call
, SD_BUS_CREDS_UID
|SD_BUS_CREDS_EUID
|SD_BUS_CREDS_EFFECTIVE_CAPS
, &creds
);
495 /* Note that not even on kdbus we might have the caps
496 * field, due to faked identities, or namespace
497 * translation issues. */
498 r
= sd_bus_creds_has_effective_cap(creds
, capability
);
504 r
= sd_bus_query_sender_creds(call
, SD_BUS_CREDS_UID
|SD_BUS_CREDS_EUID
, &creds
);
509 /* Now, check the UID, but only if the capability check wasn't
512 if (our_uid
!= 0 || !know_caps
|| capability
< 0) {
515 /* Try to use the EUID, if we have it. */
516 r
= sd_bus_creds_get_euid(creds
, &sender_uid
);
518 r
= sd_bus_creds_get_uid(creds
, &sender_uid
);
521 /* Sender has same UID as us, then let's grant access */
522 if (sender_uid
== our_uid
)
525 /* Sender is root, we are not root. */
526 if (our_uid
!= 0 && sender_uid
== 0)