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 = bus_resolve(bus), -ENOPKG);
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 = sd_bus_message_appendv(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_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
76 assert_return(bus, -EINVAL);
77 assert_return(bus = bus_resolve(bus), -ENOPKG);
78 assert_return(!bus_pid_changed(bus), -ECHILD);
80 if (!BUS_IS_OPEN(bus->state))
83 r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
87 if (!isempty(types)) {
91 r = sd_bus_message_appendv(m, types, ap);
97 return sd_bus_call_async(bus, slot, m, callback, userdata, 0);
100 _public_ int sd_bus_call_method(
102 const char *destination,
104 const char *interface,
107 sd_bus_message **reply,
108 const char *types, ...) {
110 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
113 bus_assert_return(bus, -EINVAL, error);
114 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
116 if (!BUS_IS_OPEN(bus->state)) {
121 r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
125 if (!isempty(types)) {
129 r = sd_bus_message_appendv(m, types, ap);
135 return sd_bus_call(bus, m, 0, error, reply);
138 return sd_bus_error_set_errno(error, r);
141 _public_ int sd_bus_reply_method_return(
142 sd_bus_message *call,
143 const char *types, ...) {
145 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
148 assert_return(call, -EINVAL);
149 assert_return(call->sealed, -EPERM);
150 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
151 assert_return(call->bus, -EINVAL);
152 assert_return(!bus_pid_changed(call->bus), -ECHILD);
154 if (!BUS_IS_OPEN(call->bus->state))
157 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
160 r = sd_bus_message_new_method_return(call, &m);
164 if (!isempty(types)) {
168 r = sd_bus_message_appendv(m, types, ap);
174 return sd_bus_send(call->bus, m, NULL);
177 _public_ int sd_bus_reply_method_error(
178 sd_bus_message *call,
179 const sd_bus_error *e) {
181 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
184 assert_return(call, -EINVAL);
185 assert_return(call->sealed, -EPERM);
186 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
187 assert_return(sd_bus_error_is_set(e), -EINVAL);
188 assert_return(call->bus, -EINVAL);
189 assert_return(!bus_pid_changed(call->bus), -ECHILD);
191 if (!BUS_IS_OPEN(call->bus->state))
194 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
197 r = sd_bus_message_new_method_error(call, &m, e);
201 return sd_bus_send(call->bus, m, NULL);
204 _public_ int sd_bus_reply_method_errorf(
205 sd_bus_message *call,
210 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
213 assert_return(call, -EINVAL);
214 assert_return(call->sealed, -EPERM);
215 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
216 assert_return(call->bus, -EINVAL);
217 assert_return(!bus_pid_changed(call->bus), -ECHILD);
219 if (!BUS_IS_OPEN(call->bus->state))
222 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
225 va_start(ap, format);
226 bus_error_setfv(&error, name, format, ap);
229 return sd_bus_reply_method_error(call, &error);
232 _public_ int sd_bus_reply_method_errno(
233 sd_bus_message *call,
235 const sd_bus_error *p) {
237 _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
239 assert_return(call, -EINVAL);
240 assert_return(call->sealed, -EPERM);
241 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
242 assert_return(call->bus, -EINVAL);
243 assert_return(!bus_pid_changed(call->bus), -ECHILD);
245 if (!BUS_IS_OPEN(call->bus->state))
248 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
251 if (sd_bus_error_is_set(p))
252 return sd_bus_reply_method_error(call, p);
254 sd_bus_error_set_errno(&berror, error);
256 return sd_bus_reply_method_error(call, &berror);
259 _public_ int sd_bus_reply_method_errnof(
260 sd_bus_message *call,
265 _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
268 assert_return(call, -EINVAL);
269 assert_return(call->sealed, -EPERM);
270 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
271 assert_return(call->bus, -EINVAL);
272 assert_return(!bus_pid_changed(call->bus), -ECHILD);
274 if (!BUS_IS_OPEN(call->bus->state))
277 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
280 va_start(ap, format);
281 sd_bus_error_set_errnofv(&berror, error, format, ap);
284 return sd_bus_reply_method_error(call, &berror);
287 _public_ int sd_bus_get_property(
289 const char *destination,
291 const char *interface,
294 sd_bus_message **reply,
297 sd_bus_message *rep = NULL;
300 bus_assert_return(bus, -EINVAL, error);
301 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
302 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
303 bus_assert_return(reply, -EINVAL, error);
304 bus_assert_return(signature_is_single(type, false), -EINVAL, error);
305 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
307 if (!BUS_IS_OPEN(bus->state)) {
312 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
316 r = sd_bus_message_enter_container(rep, 'v', type);
318 sd_bus_message_unref(rep);
326 return sd_bus_error_set_errno(error, r);
329 _public_ int sd_bus_get_property_trivial(
331 const char *destination,
333 const char *interface,
336 char type, void *ptr) {
338 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
341 bus_assert_return(bus, -EINVAL, error);
342 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
343 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
344 bus_assert_return(bus_type_is_trivial(type), -EINVAL, error);
345 bus_assert_return(ptr, -EINVAL, error);
346 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
348 if (!BUS_IS_OPEN(bus->state)) {
353 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
357 r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
361 r = sd_bus_message_read_basic(reply, type, ptr);
368 return sd_bus_error_set_errno(error, r);
371 _public_ int sd_bus_get_property_string(
373 const char *destination,
375 const char *interface,
380 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
385 bus_assert_return(bus, -EINVAL, error);
386 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
387 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
388 bus_assert_return(ret, -EINVAL, error);
389 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
391 if (!BUS_IS_OPEN(bus->state)) {
396 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
400 r = sd_bus_message_enter_container(reply, 'v', "s");
404 r = sd_bus_message_read_basic(reply, 's', &s);
418 return sd_bus_error_set_errno(error, r);
421 _public_ int sd_bus_get_property_strv(
423 const char *destination,
425 const char *interface,
430 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
433 bus_assert_return(bus, -EINVAL, error);
434 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
435 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
436 bus_assert_return(ret, -EINVAL, error);
437 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
439 if (!BUS_IS_OPEN(bus->state)) {
444 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
448 r = sd_bus_message_enter_container(reply, 'v', NULL);
452 r = sd_bus_message_read_strv(reply, ret);
459 return sd_bus_error_set_errno(error, r);
462 _public_ int sd_bus_set_property(
464 const char *destination,
466 const char *interface,
469 const char *type, ...) {
471 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
475 bus_assert_return(bus, -EINVAL, error);
476 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
477 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
478 bus_assert_return(signature_is_single(type, false), -EINVAL, error);
479 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
481 if (!BUS_IS_OPEN(bus->state)) {
486 r = sd_bus_message_new_method_call(bus, &m, destination, path, "org.freedesktop.DBus.Properties", "Set");
490 r = sd_bus_message_append(m, "ss", strempty(interface), member);
494 r = sd_bus_message_open_container(m, 'v', type);
499 r = sd_bus_message_appendv(m, type, ap);
504 r = sd_bus_message_close_container(m);
508 return sd_bus_call(bus, m, 0, error, NULL);
511 return sd_bus_error_set_errno(error, r);
514 _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
517 assert_return(call, -EINVAL);
518 assert_return(call->sealed, -EPERM);
519 assert_return(call->bus, -EINVAL);
520 assert_return(!bus_pid_changed(call->bus), -ECHILD);
522 if (!BUS_IS_OPEN(call->bus->state))
525 c = sd_bus_message_get_creds(call);
527 /* All data we need? */
528 if (c && (mask & ~c->mask) == 0) {
529 *creds = sd_bus_creds_ref(c);
533 /* No data passed? Or not enough data passed to retrieve the missing bits? */
534 if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
535 /* We couldn't read anything from the call, let's try
536 * to get it from the sender or peer. */
539 /* There's a sender, but the creds are missing. */
540 return sd_bus_get_name_creds(call->bus, call->sender, mask, creds);
542 /* There's no sender. For direct connections
543 * the credentials of the AF_UNIX peer matter,
544 * which may be queried via sd_bus_get_owner_creds(). */
545 return sd_bus_get_owner_creds(call->bus, mask, creds);
548 return bus_creds_extend_by_pid(c, mask, creds);
551 _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
552 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
554 bool know_caps = false;
557 assert_return(call, -EINVAL);
558 assert_return(call->sealed, -EPERM);
559 assert_return(call->bus, -EINVAL);
560 assert_return(!bus_pid_changed(call->bus), -ECHILD);
562 if (!BUS_IS_OPEN(call->bus->state))
565 if (capability >= 0) {
567 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
571 /* We cannot use augmented caps for authorization,
572 * since then data is acquired raceful from
573 * /proc. This can never actually happen, but let's
574 * better be safe than sorry, and do an extra check
576 assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EFFECTIVE_CAPS) == 0, -EPERM);
578 r = sd_bus_creds_has_effective_cap(creds, capability);
584 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID, &creds);
589 /* Now, check the UID, but only if the capability check wasn't
592 if (our_uid != 0 || !know_caps || capability < 0) {
595 /* We cannot use augmented uid/euid for authorization,
596 * since then data is acquired raceful from
597 * /proc. This can never actually happen, but let's
598 * better be safe than sorry, and do an extra check
600 assert_return((sd_bus_creds_get_augmented_mask(creds) & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID)) == 0, -EPERM);
602 /* Try to use the EUID, if we have it. */
603 r = sd_bus_creds_get_euid(creds, &sender_uid);
605 r = sd_bus_creds_get_uid(creds, &sender_uid);
608 /* Sender has same UID as us, then let's grant access */
609 if (sender_uid == our_uid)
612 /* Sender is root, we are not root. */
613 if (our_uid != 0 && sender_uid == 0)
621 #define make_expression(sender, path, interface, member) \
624 sender ? ",sender='" : "", \
627 path ? ",path='" : "", \
630 interface ? ",interface='" : "", \
632 interface ? "'" : "", \
633 member ? ",member='" : "", \
638 _public_ int sd_bus_match_signal(
643 const char *interface,
645 sd_bus_message_handler_t callback,
648 const char *expression;
650 assert_return(bus, -EINVAL);
651 assert_return(bus = bus_resolve(bus), -ENOPKG);
652 assert_return(!bus_pid_changed(bus), -ECHILD);
653 assert_return(!sender || service_name_is_valid(sender), -EINVAL);
654 assert_return(!path || object_path_is_valid(path), -EINVAL);
655 assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
656 assert_return(!member || member_name_is_valid(member), -EINVAL);
658 expression = make_expression(sender, path, interface, member);
660 return sd_bus_add_match(bus, ret, expression, callback, userdata);
663 _public_ int sd_bus_match_signal_async(
668 const char *interface,
670 sd_bus_message_handler_t callback,
671 sd_bus_message_handler_t install_callback,
674 const char *expression;
676 assert_return(bus, -EINVAL);
677 assert_return(bus = bus_resolve(bus), -ENOPKG);
678 assert_return(!bus_pid_changed(bus), -ECHILD);
679 assert_return(!sender || service_name_is_valid(sender), -EINVAL);
680 assert_return(!path || object_path_is_valid(path), -EINVAL);
681 assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
682 assert_return(!member || member_name_is_valid(member), -EINVAL);
684 expression = make_expression(sender, path, interface, member);
686 return sd_bus_add_match_async(bus, ret, expression, callback, install_callback, userdata);