2 This file is part of systemd.
4 Copyright 2013 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include "bus-internal.h"
21 #include "bus-message.h"
22 #include "bus-signature.h"
25 #include "string-util.h"
27 _public_ int sd_bus_emit_signal(
30 const char *interface,
32 const char *types, ...) {
34 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
37 assert_return(bus, -EINVAL);
38 assert_return(!bus_pid_changed(bus), -ECHILD);
40 if (!BUS_IS_OPEN(bus->state))
43 r = sd_bus_message_new_signal(bus, &m, path, interface, member);
47 if (!isempty(types)) {
51 r = bus_message_append_ap(m, types, ap);
57 return sd_bus_send(bus, m, NULL);
60 #if 0 /// UNNEEDED by elogind
61 _public_ int sd_bus_call_method_async(
64 const char *destination,
66 const char *interface,
68 sd_bus_message_handler_t callback,
70 const char *types, ...) {
72 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
75 assert_return(bus, -EINVAL);
76 assert_return(!bus_pid_changed(bus), -ECHILD);
78 if (!BUS_IS_OPEN(bus->state))
81 r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
85 if (!isempty(types)) {
89 r = bus_message_append_ap(m, types, ap);
95 return sd_bus_call_async(bus, slot, m, callback, userdata, 0);
99 _public_ int sd_bus_call_method(
101 const char *destination,
103 const char *interface,
106 sd_bus_message **reply,
107 const char *types, ...) {
109 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
112 bus_assert_return(bus, -EINVAL, error);
113 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
115 if (!BUS_IS_OPEN(bus->state)) {
120 r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
124 if (!isempty(types)) {
128 r = bus_message_append_ap(m, types, ap);
134 return sd_bus_call(bus, m, 0, error, reply);
137 return sd_bus_error_set_errno(error, r);
140 _public_ int sd_bus_reply_method_return(
141 sd_bus_message *call,
142 const char *types, ...) {
144 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
147 assert_return(call, -EINVAL);
148 assert_return(call->sealed, -EPERM);
149 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
150 assert_return(call->bus, -EINVAL);
151 assert_return(!bus_pid_changed(call->bus), -ECHILD);
153 if (!BUS_IS_OPEN(call->bus->state))
156 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
159 r = sd_bus_message_new_method_return(call, &m);
163 if (!isempty(types)) {
167 r = bus_message_append_ap(m, types, ap);
173 return sd_bus_send(call->bus, m, NULL);
176 _public_ int sd_bus_reply_method_error(
177 sd_bus_message *call,
178 const sd_bus_error *e) {
180 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
183 assert_return(call, -EINVAL);
184 assert_return(call->sealed, -EPERM);
185 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
186 assert_return(sd_bus_error_is_set(e), -EINVAL);
187 assert_return(call->bus, -EINVAL);
188 assert_return(!bus_pid_changed(call->bus), -ECHILD);
190 if (!BUS_IS_OPEN(call->bus->state))
193 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
196 r = sd_bus_message_new_method_error(call, &m, e);
200 return sd_bus_send(call->bus, m, NULL);
203 _public_ int sd_bus_reply_method_errorf(
204 sd_bus_message *call,
209 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
212 assert_return(call, -EINVAL);
213 assert_return(call->sealed, -EPERM);
214 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
215 assert_return(call->bus, -EINVAL);
216 assert_return(!bus_pid_changed(call->bus), -ECHILD);
218 if (!BUS_IS_OPEN(call->bus->state))
221 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
224 va_start(ap, format);
225 bus_error_setfv(&error, name, format, ap);
228 return sd_bus_reply_method_error(call, &error);
231 _public_ int sd_bus_reply_method_errno(
232 sd_bus_message *call,
234 const sd_bus_error *p) {
236 _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
238 assert_return(call, -EINVAL);
239 assert_return(call->sealed, -EPERM);
240 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
241 assert_return(call->bus, -EINVAL);
242 assert_return(!bus_pid_changed(call->bus), -ECHILD);
244 if (!BUS_IS_OPEN(call->bus->state))
247 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
250 if (sd_bus_error_is_set(p))
251 return sd_bus_reply_method_error(call, p);
253 sd_bus_error_set_errno(&berror, error);
255 return sd_bus_reply_method_error(call, &berror);
258 #if 0 /// UNNEEDED by elogind
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);
288 _public_ int sd_bus_get_property(
290 const char *destination,
292 const char *interface,
295 sd_bus_message **reply,
298 sd_bus_message *rep = NULL;
301 bus_assert_return(bus, -EINVAL, error);
302 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
303 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
304 bus_assert_return(reply, -EINVAL, error);
305 bus_assert_return(signature_is_single(type, false), -EINVAL, error);
306 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
308 if (!BUS_IS_OPEN(bus->state)) {
313 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
317 r = sd_bus_message_enter_container(rep, 'v', type);
319 sd_bus_message_unref(rep);
327 return sd_bus_error_set_errno(error, r);
330 _public_ int sd_bus_get_property_trivial(
332 const char *destination,
334 const char *interface,
337 char type, void *ptr) {
339 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
342 bus_assert_return(bus, -EINVAL, error);
343 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
344 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
345 bus_assert_return(bus_type_is_trivial(type), -EINVAL, error);
346 bus_assert_return(ptr, -EINVAL, error);
347 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
349 if (!BUS_IS_OPEN(bus->state)) {
354 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
358 r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
362 r = sd_bus_message_read_basic(reply, type, ptr);
369 return sd_bus_error_set_errno(error, r);
372 _public_ int sd_bus_get_property_string(
374 const char *destination,
376 const char *interface,
381 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
386 bus_assert_return(bus, -EINVAL, error);
387 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
388 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
389 bus_assert_return(ret, -EINVAL, error);
390 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
392 if (!BUS_IS_OPEN(bus->state)) {
397 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
401 r = sd_bus_message_enter_container(reply, 'v', "s");
405 r = sd_bus_message_read_basic(reply, 's', &s);
419 return sd_bus_error_set_errno(error, r);
422 #if 0 /// UNNEEDED by elogind
423 _public_ int sd_bus_get_property_strv(
425 const char *destination,
427 const char *interface,
432 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
435 bus_assert_return(bus, -EINVAL, error);
436 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
437 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
438 bus_assert_return(ret, -EINVAL, error);
439 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
441 if (!BUS_IS_OPEN(bus->state)) {
446 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
450 r = sd_bus_message_enter_container(reply, 'v', NULL);
454 r = sd_bus_message_read_strv(reply, ret);
461 return sd_bus_error_set_errno(error, r);
464 _public_ int sd_bus_set_property(
466 const char *destination,
468 const char *interface,
471 const char *type, ...) {
473 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
477 bus_assert_return(bus, -EINVAL, error);
478 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
479 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
480 bus_assert_return(signature_is_single(type, false), -EINVAL, error);
481 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
483 if (!BUS_IS_OPEN(bus->state)) {
488 r = sd_bus_message_new_method_call(bus, &m, destination, path, "org.freedesktop.DBus.Properties", "Set");
492 r = sd_bus_message_append(m, "ss", strempty(interface), member);
496 r = sd_bus_message_open_container(m, 'v', type);
501 r = bus_message_append_ap(m, type, ap);
506 r = sd_bus_message_close_container(m);
510 return sd_bus_call(bus, m, 0, error, NULL);
513 return sd_bus_error_set_errno(error, r);
517 _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
520 assert_return(call, -EINVAL);
521 assert_return(call->sealed, -EPERM);
522 assert_return(call->bus, -EINVAL);
523 assert_return(!bus_pid_changed(call->bus), -ECHILD);
525 if (!BUS_IS_OPEN(call->bus->state))
528 c = sd_bus_message_get_creds(call);
530 /* All data we need? */
531 if (c && (mask & ~c->mask) == 0) {
532 *creds = sd_bus_creds_ref(c);
536 /* No data passed? Or not enough data passed to retrieve the missing bits? */
537 if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
538 /* We couldn't read anything from the call, let's try
539 * to get it from the sender or peer. */
542 /* There's a sender, but the creds are
543 * missing. This means we are talking via
544 * dbus1, or are getting a message that was
545 * sent to us via kdbus, but was converted
546 * from a dbus1 message by the bus-proxy and
547 * thus also lacks the creds. */
548 return sd_bus_get_name_creds(call->bus, call->sender, mask, creds);
550 /* There's no sender, hence we are on a dbus1
551 * direct connection. For direct connections
552 * the credentials of the AF_UNIX peer matter,
553 * which may be queried via
554 * sd_bus_get_owner_creds(). */
555 return sd_bus_get_owner_creds(call->bus, mask, creds);
558 return bus_creds_extend_by_pid(c, mask, creds);
561 _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
562 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
564 bool know_caps = false;
567 assert_return(call, -EINVAL);
568 assert_return(call->sealed, -EPERM);
569 assert_return(call->bus, -EINVAL);
570 assert_return(!bus_pid_changed(call->bus), -ECHILD);
572 if (!BUS_IS_OPEN(call->bus->state))
575 if (capability >= 0) {
577 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
581 /* We cannot use augmented caps for authorization,
582 * since then data is acquired raceful from
583 * /proc. This can never actually happen, but let's
584 * better be safe than sorry, and do an extra check
586 assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EFFECTIVE_CAPS) == 0, -EPERM);
588 /* Note that not even on kdbus we might have the caps
589 * field, due to faked identities, or namespace
590 * translation issues. */
591 r = sd_bus_creds_has_effective_cap(creds, capability);
597 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID, &creds);
602 /* Now, check the UID, but only if the capability check wasn't
605 if (our_uid != 0 || !know_caps || capability < 0) {
608 /* We cannot use augmented uid/euid for authorization,
609 * since then data is acquired raceful from
610 * /proc. This can never actually happen, but let's
611 * better be safe than sorry, and do an extra check
613 assert_return((sd_bus_creds_get_augmented_mask(creds) & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID)) == 0, -EPERM);
615 /* Try to use the EUID, if we have it. */
616 r = sd_bus_creds_get_euid(creds, &sender_uid);
618 r = sd_bus_creds_get_uid(creds, &sender_uid);
621 /* Sender has same UID as us, then let's grant access */
622 if (sender_uid == our_uid)
625 /* Sender is root, we are not root. */
626 if (our_uid != 0 && sender_uid == 0)