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 /// UNNEEDED by elogind
64 _public_ int sd_bus_call_method_async(
67 const char *destination,
69 const char *interface,
71 sd_bus_message_handler_t callback,
73 const char *types, ...) {
75 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
78 assert_return(bus, -EINVAL);
79 assert_return(!bus_pid_changed(bus), -ECHILD);
81 if (!BUS_IS_OPEN(bus->state))
84 r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
88 if (!isempty(types)) {
92 r = bus_message_append_ap(m, types, ap);
98 return sd_bus_call_async(bus, slot, m, callback, userdata, 0);
102 _public_ int sd_bus_call_method(
104 const char *destination,
106 const char *interface,
109 sd_bus_message **reply,
110 const char *types, ...) {
112 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
115 bus_assert_return(bus, -EINVAL, error);
116 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
118 if (!BUS_IS_OPEN(bus->state)) {
123 r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
127 if (!isempty(types)) {
131 r = bus_message_append_ap(m, types, ap);
137 return sd_bus_call(bus, m, 0, error, reply);
140 return sd_bus_error_set_errno(error, r);
143 _public_ int sd_bus_reply_method_return(
144 sd_bus_message *call,
145 const char *types, ...) {
147 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
150 assert_return(call, -EINVAL);
151 assert_return(call->sealed, -EPERM);
152 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
153 assert_return(call->bus, -EINVAL);
154 assert_return(!bus_pid_changed(call->bus), -ECHILD);
156 if (!BUS_IS_OPEN(call->bus->state))
159 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
162 r = sd_bus_message_new_method_return(call, &m);
166 if (!isempty(types)) {
170 r = bus_message_append_ap(m, types, ap);
176 return sd_bus_send(call->bus, m, NULL);
179 _public_ int sd_bus_reply_method_error(
180 sd_bus_message *call,
181 const sd_bus_error *e) {
183 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
186 assert_return(call, -EINVAL);
187 assert_return(call->sealed, -EPERM);
188 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
189 assert_return(sd_bus_error_is_set(e), -EINVAL);
190 assert_return(call->bus, -EINVAL);
191 assert_return(!bus_pid_changed(call->bus), -ECHILD);
193 if (!BUS_IS_OPEN(call->bus->state))
196 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
199 r = sd_bus_message_new_method_error(call, &m, e);
203 return sd_bus_send(call->bus, m, NULL);
206 _public_ int sd_bus_reply_method_errorf(
207 sd_bus_message *call,
212 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
215 assert_return(call, -EINVAL);
216 assert_return(call->sealed, -EPERM);
217 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
218 assert_return(call->bus, -EINVAL);
219 assert_return(!bus_pid_changed(call->bus), -ECHILD);
221 if (!BUS_IS_OPEN(call->bus->state))
224 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
227 va_start(ap, format);
228 bus_error_setfv(&error, name, format, ap);
231 return sd_bus_reply_method_error(call, &error);
234 _public_ int sd_bus_reply_method_errno(
235 sd_bus_message *call,
237 const sd_bus_error *p) {
239 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
241 assert_return(call, -EINVAL);
242 assert_return(call->sealed, -EPERM);
243 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
244 assert_return(call->bus, -EINVAL);
245 assert_return(!bus_pid_changed(call->bus), -ECHILD);
247 if (!BUS_IS_OPEN(call->bus->state))
250 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
253 if (sd_bus_error_is_set(p))
254 return sd_bus_reply_method_error(call, p);
256 sd_bus_error_set_errno(&berror, error);
258 return sd_bus_reply_method_error(call, &berror);
261 /// UNNEEDED by elogind
263 _public_ int sd_bus_reply_method_errnof(
264 sd_bus_message *call,
269 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
272 assert_return(call, -EINVAL);
273 assert_return(call->sealed, -EPERM);
274 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
275 assert_return(call->bus, -EINVAL);
276 assert_return(!bus_pid_changed(call->bus), -ECHILD);
278 if (!BUS_IS_OPEN(call->bus->state))
281 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
284 va_start(ap, format);
285 sd_bus_error_set_errnofv(&berror, error, format, ap);
288 return sd_bus_reply_method_error(call, &berror);
292 _public_ int sd_bus_get_property(
294 const char *destination,
296 const char *interface,
299 sd_bus_message **reply,
302 sd_bus_message *rep = NULL;
305 bus_assert_return(bus, -EINVAL, error);
306 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
307 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
308 bus_assert_return(reply, -EINVAL, error);
309 bus_assert_return(signature_is_single(type, false), -EINVAL, error);
310 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
312 if (!BUS_IS_OPEN(bus->state)) {
317 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
321 r = sd_bus_message_enter_container(rep, 'v', type);
323 sd_bus_message_unref(rep);
331 return sd_bus_error_set_errno(error, r);
334 /// UNNEEDED by elogind
336 _public_ int sd_bus_get_property_trivial(
338 const char *destination,
340 const char *interface,
343 char type, void *ptr) {
345 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
348 bus_assert_return(bus, -EINVAL, error);
349 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
350 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
351 bus_assert_return(bus_type_is_trivial(type), -EINVAL, error);
352 bus_assert_return(ptr, -EINVAL, error);
353 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
355 if (!BUS_IS_OPEN(bus->state)) {
360 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
364 r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
368 r = sd_bus_message_read_basic(reply, type, ptr);
375 return sd_bus_error_set_errno(error, r);
379 _public_ int sd_bus_get_property_string(
381 const char *destination,
383 const char *interface,
388 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
393 bus_assert_return(bus, -EINVAL, error);
394 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
395 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
396 bus_assert_return(ret, -EINVAL, error);
397 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
399 if (!BUS_IS_OPEN(bus->state)) {
404 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
408 r = sd_bus_message_enter_container(reply, 'v', "s");
412 r = sd_bus_message_read_basic(reply, 's', &s);
426 return sd_bus_error_set_errno(error, r);
429 /// UNNEEDED by elogind
431 _public_ int sd_bus_get_property_strv(
433 const char *destination,
435 const char *interface,
440 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
443 bus_assert_return(bus, -EINVAL, error);
444 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
445 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
446 bus_assert_return(ret, -EINVAL, error);
447 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
449 if (!BUS_IS_OPEN(bus->state)) {
454 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
458 r = sd_bus_message_enter_container(reply, 'v', NULL);
462 r = sd_bus_message_read_strv(reply, ret);
469 return sd_bus_error_set_errno(error, r);
472 _public_ int sd_bus_set_property(
474 const char *destination,
476 const char *interface,
479 const char *type, ...) {
481 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
485 bus_assert_return(bus, -EINVAL, error);
486 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
487 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
488 bus_assert_return(signature_is_single(type, false), -EINVAL, error);
489 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
491 if (!BUS_IS_OPEN(bus->state)) {
496 r = sd_bus_message_new_method_call(bus, &m, destination, path, "org.freedesktop.DBus.Properties", "Set");
500 r = sd_bus_message_append(m, "ss", strempty(interface), member);
504 r = sd_bus_message_open_container(m, 'v', type);
509 r = bus_message_append_ap(m, type, ap);
514 r = sd_bus_message_close_container(m);
518 return sd_bus_call(bus, m, 0, error, NULL);
521 return sd_bus_error_set_errno(error, r);
525 _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
528 assert_return(call, -EINVAL);
529 assert_return(call->sealed, -EPERM);
530 assert_return(call->bus, -EINVAL);
531 assert_return(!bus_pid_changed(call->bus), -ECHILD);
533 if (!BUS_IS_OPEN(call->bus->state))
536 c = sd_bus_message_get_creds(call);
538 /* All data we need? */
539 if (c && (mask & ~c->mask) == 0) {
540 *creds = sd_bus_creds_ref(c);
544 /* No data passed? Or not enough data passed to retrieve the missing bits? */
545 if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
546 /* We couldn't read anything from the call, let's try
547 * to get it from the sender or peer. */
550 /* There's a sender, but the creds are
551 * missing. This means we are talking via
552 * dbus1, or are getting a message that was
553 * sent to us via kdbus, but was converted
554 * from a dbus1 message by the bus-proxy and
555 * thus also lacks the creds. */
556 return sd_bus_get_name_creds(call->bus, call->sender, mask, creds);
558 /* There's no sender, hence we are on a dbus1
559 * direct connection. For direct connections
560 * the credentials of the AF_UNIX peer matter,
561 * which may be queried via
562 * sd_bus_get_owner_creds(). */
563 return sd_bus_get_owner_creds(call->bus, mask, creds);
566 return bus_creds_extend_by_pid(c, mask, creds);
569 _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
570 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
572 bool know_caps = false;
575 assert_return(call, -EINVAL);
576 assert_return(call->sealed, -EPERM);
577 assert_return(call->bus, -EINVAL);
578 assert_return(!bus_pid_changed(call->bus), -ECHILD);
580 if (!BUS_IS_OPEN(call->bus->state))
583 if (capability >= 0) {
585 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
589 /* We cannot use augmented caps for authorization,
590 * since then data is acquired raceful from
591 * /proc. This can never actually happen, but let's
592 * better be safe than sorry, and do an extra check
594 assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EFFECTIVE_CAPS) == 0, -EPERM);
596 /* Note that not even on kdbus we might have the caps
597 * field, due to faked identities, or namespace
598 * translation issues. */
599 r = sd_bus_creds_has_effective_cap(creds, capability);
605 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID, &creds);
610 /* Now, check the UID, but only if the capability check wasn't
613 if (our_uid != 0 || !know_caps || capability < 0) {
616 /* We cannot use augmented uid/euid for authorization,
617 * since then data is acquired raceful from
618 * /proc. This can never actually happen, but let's
619 * better be safe than sorry, and do an extra check
621 assert_return((sd_bus_creds_get_augmented_mask(creds) & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID)) == 0, -EPERM);
623 /* Try to use the EUID, if we have it. */
624 r = sd_bus_creds_get_euid(creds, &sender_uid);
626 r = sd_bus_creds_get_uid(creds, &sender_uid);
629 /* Sender has same UID as us, then let's grant access */
630 if (sender_uid == our_uid)
633 /* Sender is root, we are not root. */
634 if (our_uid != 0 && sender_uid == 0)