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_(sd_bus_message_unrefp) 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 #if 0 /// 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_(sd_bus_message_unrefp) 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_(sd_bus_message_unrefp) 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_(sd_bus_message_unrefp) 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_(sd_bus_message_unrefp) 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_(sd_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_(sd_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 #if 0 /// UNNEEDED by elogind
261 _public_ int sd_bus_reply_method_errnof(
262 sd_bus_message *call,
267 _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
270 assert_return(call, -EINVAL);
271 assert_return(call->sealed, -EPERM);
272 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
273 assert_return(call->bus, -EINVAL);
274 assert_return(!bus_pid_changed(call->bus), -ECHILD);
276 if (!BUS_IS_OPEN(call->bus->state))
279 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
282 va_start(ap, format);
283 sd_bus_error_set_errnofv(&berror, error, format, ap);
286 return sd_bus_reply_method_error(call, &berror);
290 _public_ int sd_bus_get_property(
292 const char *destination,
294 const char *interface,
297 sd_bus_message **reply,
300 sd_bus_message *rep = NULL;
303 bus_assert_return(bus, -EINVAL, error);
304 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
305 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
306 bus_assert_return(reply, -EINVAL, error);
307 bus_assert_return(signature_is_single(type, false), -EINVAL, error);
308 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
310 if (!BUS_IS_OPEN(bus->state)) {
315 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
319 r = sd_bus_message_enter_container(rep, 'v', type);
321 sd_bus_message_unref(rep);
329 return sd_bus_error_set_errno(error, r);
332 #if 0 /// UNNEEDED by elogind
333 _public_ int sd_bus_get_property_trivial(
335 const char *destination,
337 const char *interface,
340 char type, void *ptr) {
342 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
345 bus_assert_return(bus, -EINVAL, error);
346 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
347 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
348 bus_assert_return(bus_type_is_trivial(type), -EINVAL, error);
349 bus_assert_return(ptr, -EINVAL, error);
350 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
352 if (!BUS_IS_OPEN(bus->state)) {
357 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
361 r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
365 r = sd_bus_message_read_basic(reply, type, ptr);
372 return sd_bus_error_set_errno(error, r);
376 _public_ int sd_bus_get_property_string(
378 const char *destination,
380 const char *interface,
385 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
390 bus_assert_return(bus, -EINVAL, error);
391 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
392 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
393 bus_assert_return(ret, -EINVAL, error);
394 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
396 if (!BUS_IS_OPEN(bus->state)) {
401 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
405 r = sd_bus_message_enter_container(reply, 'v', "s");
409 r = sd_bus_message_read_basic(reply, 's', &s);
423 return sd_bus_error_set_errno(error, r);
426 #if 0 /// UNNEEDED by elogind
427 _public_ int sd_bus_get_property_strv(
429 const char *destination,
431 const char *interface,
436 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
439 bus_assert_return(bus, -EINVAL, error);
440 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
441 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
442 bus_assert_return(ret, -EINVAL, error);
443 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
445 if (!BUS_IS_OPEN(bus->state)) {
450 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
454 r = sd_bus_message_enter_container(reply, 'v', NULL);
458 r = sd_bus_message_read_strv(reply, ret);
465 return sd_bus_error_set_errno(error, r);
468 _public_ int sd_bus_set_property(
470 const char *destination,
472 const char *interface,
475 const char *type, ...) {
477 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
481 bus_assert_return(bus, -EINVAL, error);
482 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
483 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
484 bus_assert_return(signature_is_single(type, false), -EINVAL, error);
485 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
487 if (!BUS_IS_OPEN(bus->state)) {
492 r = sd_bus_message_new_method_call(bus, &m, destination, path, "org.freedesktop.DBus.Properties", "Set");
496 r = sd_bus_message_append(m, "ss", strempty(interface), member);
500 r = sd_bus_message_open_container(m, 'v', type);
505 r = bus_message_append_ap(m, type, ap);
510 r = sd_bus_message_close_container(m);
514 return sd_bus_call(bus, m, 0, error, NULL);
517 return sd_bus_error_set_errno(error, r);
521 _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
524 assert_return(call, -EINVAL);
525 assert_return(call->sealed, -EPERM);
526 assert_return(call->bus, -EINVAL);
527 assert_return(!bus_pid_changed(call->bus), -ECHILD);
529 if (!BUS_IS_OPEN(call->bus->state))
532 c = sd_bus_message_get_creds(call);
534 /* All data we need? */
535 if (c && (mask & ~c->mask) == 0) {
536 *creds = sd_bus_creds_ref(c);
540 /* No data passed? Or not enough data passed to retrieve the missing bits? */
541 if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
542 /* We couldn't read anything from the call, let's try
543 * to get it from the sender or peer. */
546 /* There's a sender, but the creds are
547 * missing. This means we are talking via
548 * dbus1, or are getting a message that was
549 * sent to us via kdbus, but was converted
550 * from a dbus1 message by the bus-proxy and
551 * thus also lacks the creds. */
552 return sd_bus_get_name_creds(call->bus, call->sender, mask, creds);
554 /* There's no sender, hence we are on a dbus1
555 * direct connection. For direct connections
556 * the credentials of the AF_UNIX peer matter,
557 * which may be queried via
558 * sd_bus_get_owner_creds(). */
559 return sd_bus_get_owner_creds(call->bus, mask, creds);
562 return bus_creds_extend_by_pid(c, mask, creds);
565 _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
566 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
568 bool know_caps = false;
571 assert_return(call, -EINVAL);
572 assert_return(call->sealed, -EPERM);
573 assert_return(call->bus, -EINVAL);
574 assert_return(!bus_pid_changed(call->bus), -ECHILD);
576 if (!BUS_IS_OPEN(call->bus->state))
579 if (capability >= 0) {
581 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
585 /* We cannot use augmented caps for authorization,
586 * since then data is acquired raceful from
587 * /proc. This can never actually happen, but let's
588 * better be safe than sorry, and do an extra check
590 assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EFFECTIVE_CAPS) == 0, -EPERM);
592 /* Note that not even on kdbus we might have the caps
593 * field, due to faked identities, or namespace
594 * translation issues. */
595 r = sd_bus_creds_has_effective_cap(creds, capability);
601 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID, &creds);
606 /* Now, check the UID, but only if the capability check wasn't
609 if (our_uid != 0 || !know_caps || capability < 0) {
612 /* We cannot use augmented uid/euid for authorization,
613 * since then data is acquired raceful from
614 * /proc. This can never actually happen, but let's
615 * better be safe than sorry, and do an extra check
617 assert_return((sd_bus_creds_get_augmented_mask(creds) & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID)) == 0, -EPERM);
619 /* Try to use the EUID, if we have it. */
620 r = sd_bus_creds_get_euid(creds, &sender_uid);
622 r = sd_bus_creds_get_uid(creds, &sender_uid);
625 /* Sender has same UID as us, then let's grant access */
626 if (sender_uid == our_uid)
629 /* Sender is root, we are not root. */
630 if (our_uid != 0 && sender_uid == 0)