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 /// UNNEEDED by elogind
63 _public_ int sd_bus_call_method_async(
66 const char *destination,
68 const char *interface,
70 sd_bus_message_handler_t callback,
72 const char *types, ...) {
74 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
77 assert_return(bus, -EINVAL);
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 = bus_message_append_ap(m, types, ap);
97 return sd_bus_call_async(bus, slot, m, callback, userdata, 0);
101 _public_ int sd_bus_call_method(
103 const char *destination,
105 const char *interface,
108 sd_bus_message **reply,
109 const char *types, ...) {
111 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
114 bus_assert_return(bus, -EINVAL, error);
115 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
117 if (!BUS_IS_OPEN(bus->state)) {
122 r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
126 if (!isempty(types)) {
130 r = bus_message_append_ap(m, types, ap);
136 return sd_bus_call(bus, m, 0, error, reply);
139 return sd_bus_error_set_errno(error, r);
142 _public_ int sd_bus_reply_method_return(
143 sd_bus_message *call,
144 const char *types, ...) {
146 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
149 assert_return(call, -EINVAL);
150 assert_return(call->sealed, -EPERM);
151 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
152 assert_return(call->bus, -EINVAL);
153 assert_return(!bus_pid_changed(call->bus), -ECHILD);
155 if (!BUS_IS_OPEN(call->bus->state))
158 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
161 r = sd_bus_message_new_method_return(call, &m);
165 if (!isempty(types)) {
169 r = bus_message_append_ap(m, types, ap);
175 return sd_bus_send(call->bus, m, NULL);
178 _public_ int sd_bus_reply_method_error(
179 sd_bus_message *call,
180 const sd_bus_error *e) {
182 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
185 assert_return(call, -EINVAL);
186 assert_return(call->sealed, -EPERM);
187 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
188 assert_return(sd_bus_error_is_set(e), -EINVAL);
189 assert_return(call->bus, -EINVAL);
190 assert_return(!bus_pid_changed(call->bus), -ECHILD);
192 if (!BUS_IS_OPEN(call->bus->state))
195 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
198 r = sd_bus_message_new_method_error(call, &m, e);
202 return sd_bus_send(call->bus, m, NULL);
205 _public_ int sd_bus_reply_method_errorf(
206 sd_bus_message *call,
211 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
214 assert_return(call, -EINVAL);
215 assert_return(call->sealed, -EPERM);
216 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
217 assert_return(call->bus, -EINVAL);
218 assert_return(!bus_pid_changed(call->bus), -ECHILD);
220 if (!BUS_IS_OPEN(call->bus->state))
223 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
226 va_start(ap, format);
227 bus_error_setfv(&error, name, format, ap);
230 return sd_bus_reply_method_error(call, &error);
233 _public_ int sd_bus_reply_method_errno(
234 sd_bus_message *call,
236 const sd_bus_error *p) {
238 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
240 assert_return(call, -EINVAL);
241 assert_return(call->sealed, -EPERM);
242 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
243 assert_return(call->bus, -EINVAL);
244 assert_return(!bus_pid_changed(call->bus), -ECHILD);
246 if (!BUS_IS_OPEN(call->bus->state))
249 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
252 if (sd_bus_error_is_set(p))
253 return sd_bus_reply_method_error(call, p);
255 sd_bus_error_set_errno(&berror, error);
257 return sd_bus_reply_method_error(call, &berror);
260 /// UNNEEDED by elogind
262 _public_ int sd_bus_reply_method_errnof(
263 sd_bus_message *call,
268 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
271 assert_return(call, -EINVAL);
272 assert_return(call->sealed, -EPERM);
273 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
274 assert_return(call->bus, -EINVAL);
275 assert_return(!bus_pid_changed(call->bus), -ECHILD);
277 if (!BUS_IS_OPEN(call->bus->state))
280 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
283 va_start(ap, format);
284 sd_bus_error_set_errnofv(&berror, error, format, ap);
287 return sd_bus_reply_method_error(call, &berror);
291 _public_ int sd_bus_get_property(
293 const char *destination,
295 const char *interface,
298 sd_bus_message **reply,
301 sd_bus_message *rep = NULL;
304 bus_assert_return(bus, -EINVAL, error);
305 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
306 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
307 bus_assert_return(reply, -EINVAL, error);
308 bus_assert_return(signature_is_single(type, false), -EINVAL, error);
309 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
311 if (!BUS_IS_OPEN(bus->state)) {
316 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
320 r = sd_bus_message_enter_container(rep, 'v', type);
322 sd_bus_message_unref(rep);
330 return sd_bus_error_set_errno(error, r);
333 /// UNNEEDED by elogind
335 _public_ int sd_bus_get_property_trivial(
337 const char *destination,
339 const char *interface,
342 char type, void *ptr) {
344 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
347 bus_assert_return(bus, -EINVAL, error);
348 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
349 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
350 bus_assert_return(bus_type_is_trivial(type), -EINVAL, error);
351 bus_assert_return(ptr, -EINVAL, error);
352 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
354 if (!BUS_IS_OPEN(bus->state)) {
359 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
363 r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
367 r = sd_bus_message_read_basic(reply, type, ptr);
374 return sd_bus_error_set_errno(error, r);
378 _public_ int sd_bus_get_property_string(
380 const char *destination,
382 const char *interface,
387 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
392 bus_assert_return(bus, -EINVAL, error);
393 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
394 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
395 bus_assert_return(ret, -EINVAL, error);
396 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
398 if (!BUS_IS_OPEN(bus->state)) {
403 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
407 r = sd_bus_message_enter_container(reply, 'v', "s");
411 r = sd_bus_message_read_basic(reply, 's', &s);
425 return sd_bus_error_set_errno(error, r);
428 /// UNNEEDED by elogind
430 _public_ int sd_bus_get_property_strv(
432 const char *destination,
434 const char *interface,
439 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
442 bus_assert_return(bus, -EINVAL, error);
443 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
444 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
445 bus_assert_return(ret, -EINVAL, error);
446 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
448 if (!BUS_IS_OPEN(bus->state)) {
453 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
457 r = sd_bus_message_enter_container(reply, 'v', NULL);
461 r = sd_bus_message_read_strv(reply, ret);
468 return sd_bus_error_set_errno(error, r);
471 _public_ int sd_bus_set_property(
473 const char *destination,
475 const char *interface,
478 const char *type, ...) {
480 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
484 bus_assert_return(bus, -EINVAL, error);
485 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
486 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
487 bus_assert_return(signature_is_single(type, false), -EINVAL, error);
488 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
490 if (!BUS_IS_OPEN(bus->state)) {
495 r = sd_bus_message_new_method_call(bus, &m, destination, path, "org.freedesktop.DBus.Properties", "Set");
499 r = sd_bus_message_append(m, "ss", strempty(interface), member);
503 r = sd_bus_message_open_container(m, 'v', type);
508 r = bus_message_append_ap(m, type, ap);
513 r = sd_bus_message_close_container(m);
517 return sd_bus_call(bus, m, 0, error, NULL);
520 return sd_bus_error_set_errno(error, r);
524 _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
527 assert_return(call, -EINVAL);
528 assert_return(call->sealed, -EPERM);
529 assert_return(call->bus, -EINVAL);
530 assert_return(!bus_pid_changed(call->bus), -ECHILD);
532 if (!BUS_IS_OPEN(call->bus->state))
535 c = sd_bus_message_get_creds(call);
537 /* All data we need? */
538 if (c && (mask & ~c->mask) == 0) {
539 *creds = sd_bus_creds_ref(c);
543 /* No data passed? Or not enough data passed to retrieve the missing bits? */
544 if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
545 /* We couldn't read anything from the call, let's try
546 * to get it from the sender or peer. */
549 /* There's a sender, but the creds are
550 * missing. This means we are talking via
551 * dbus1, or are getting a message that was
552 * sent to us via kdbus, but was converted
553 * from a dbus1 message by the bus-proxy and
554 * thus also lacks the creds. */
555 return sd_bus_get_name_creds(call->bus, call->sender, mask, creds);
557 /* There's no sender, hence we are on a dbus1
558 * direct connection. For direct connections
559 * the credentials of the AF_UNIX peer matter,
560 * which may be queried via
561 * sd_bus_get_owner_creds(). */
562 return sd_bus_get_owner_creds(call->bus, mask, creds);
565 return bus_creds_extend_by_pid(c, mask, creds);
568 _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
569 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
571 bool know_caps = false;
574 assert_return(call, -EINVAL);
575 assert_return(call->sealed, -EPERM);
576 assert_return(call->bus, -EINVAL);
577 assert_return(!bus_pid_changed(call->bus), -ECHILD);
579 if (!BUS_IS_OPEN(call->bus->state))
582 if (capability >= 0) {
584 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
588 /* We cannot use augmented caps for authorization,
589 * since then data is acquired raceful from
590 * /proc. This can never actually happen, but let's
591 * better be safe than sorry, and do an extra check
593 assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EFFECTIVE_CAPS) == 0, -EPERM);
595 /* Note that not even on kdbus we might have the caps
596 * field, due to faked identities, or namespace
597 * translation issues. */
598 r = sd_bus_creds_has_effective_cap(creds, capability);
604 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID, &creds);
609 /* Now, check the UID, but only if the capability check wasn't
612 if (our_uid != 0 || !know_caps || capability < 0) {
615 /* We cannot use augmented uid/euid for authorization,
616 * since then data is acquired raceful from
617 * /proc. This can never actually happen, but let's
618 * better be safe than sorry, and do an extra check
620 assert_return((sd_bus_creds_get_augmented_mask(creds) & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID)) == 0, -EPERM);
622 /* Try to use the EUID, if we have it. */
623 r = sd_bus_creds_get_euid(creds, &sender_uid);
625 r = sd_bus_creds_get_uid(creds, &sender_uid);
628 /* Sender has same UID as us, then let's grant access */
629 if (sender_uid == our_uid)
632 /* Sender is root, we are not root. */
633 if (our_uid != 0 && sender_uid == 0)