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 #if 0 /// UNNEEDED by elogind
331 _public_ int sd_bus_get_property_trivial(
333 const char *destination,
335 const char *interface,
338 char type, void *ptr) {
340 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
343 bus_assert_return(bus, -EINVAL, error);
344 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
345 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
346 bus_assert_return(bus_type_is_trivial(type), -EINVAL, error);
347 bus_assert_return(ptr, -EINVAL, error);
348 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
350 if (!BUS_IS_OPEN(bus->state)) {
355 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
359 r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
363 r = sd_bus_message_read_basic(reply, type, ptr);
370 return sd_bus_error_set_errno(error, r);
374 _public_ int sd_bus_get_property_string(
376 const char *destination,
378 const char *interface,
383 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
388 bus_assert_return(bus, -EINVAL, error);
389 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
390 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
391 bus_assert_return(ret, -EINVAL, error);
392 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
394 if (!BUS_IS_OPEN(bus->state)) {
399 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
403 r = sd_bus_message_enter_container(reply, 'v', "s");
407 r = sd_bus_message_read_basic(reply, 's', &s);
421 return sd_bus_error_set_errno(error, r);
424 #if 0 /// UNNEEDED by elogind
425 _public_ int sd_bus_get_property_strv(
427 const char *destination,
429 const char *interface,
434 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
437 bus_assert_return(bus, -EINVAL, error);
438 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
439 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
440 bus_assert_return(ret, -EINVAL, error);
441 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
443 if (!BUS_IS_OPEN(bus->state)) {
448 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
452 r = sd_bus_message_enter_container(reply, 'v', NULL);
456 r = sd_bus_message_read_strv(reply, ret);
463 return sd_bus_error_set_errno(error, r);
466 _public_ int sd_bus_set_property(
468 const char *destination,
470 const char *interface,
473 const char *type, ...) {
475 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
479 bus_assert_return(bus, -EINVAL, error);
480 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
481 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
482 bus_assert_return(signature_is_single(type, false), -EINVAL, error);
483 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
485 if (!BUS_IS_OPEN(bus->state)) {
490 r = sd_bus_message_new_method_call(bus, &m, destination, path, "org.freedesktop.DBus.Properties", "Set");
494 r = sd_bus_message_append(m, "ss", strempty(interface), member);
498 r = sd_bus_message_open_container(m, 'v', type);
503 r = bus_message_append_ap(m, type, ap);
508 r = sd_bus_message_close_container(m);
512 return sd_bus_call(bus, m, 0, error, NULL);
515 return sd_bus_error_set_errno(error, r);
519 _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
522 assert_return(call, -EINVAL);
523 assert_return(call->sealed, -EPERM);
524 assert_return(call->bus, -EINVAL);
525 assert_return(!bus_pid_changed(call->bus), -ECHILD);
527 if (!BUS_IS_OPEN(call->bus->state))
530 c = sd_bus_message_get_creds(call);
532 /* All data we need? */
533 if (c && (mask & ~c->mask) == 0) {
534 *creds = sd_bus_creds_ref(c);
538 /* No data passed? Or not enough data passed to retrieve the missing bits? */
539 if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
540 /* We couldn't read anything from the call, let's try
541 * to get it from the sender or peer. */
544 /* There's a sender, but the creds are
545 * missing. This means we are talking via
546 * dbus1, or are getting a message that was
547 * sent to us via kdbus, but was converted
548 * from a dbus1 message by the bus-proxy and
549 * thus also lacks the creds. */
550 return sd_bus_get_name_creds(call->bus, call->sender, mask, creds);
552 /* There's no sender, hence we are on a dbus1
553 * direct connection. For direct connections
554 * the credentials of the AF_UNIX peer matter,
555 * which may be queried via
556 * sd_bus_get_owner_creds(). */
557 return sd_bus_get_owner_creds(call->bus, mask, creds);
560 return bus_creds_extend_by_pid(c, mask, creds);
563 _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
564 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
566 bool know_caps = false;
569 assert_return(call, -EINVAL);
570 assert_return(call->sealed, -EPERM);
571 assert_return(call->bus, -EINVAL);
572 assert_return(!bus_pid_changed(call->bus), -ECHILD);
574 if (!BUS_IS_OPEN(call->bus->state))
577 if (capability >= 0) {
579 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
583 /* We cannot use augmented caps for authorization,
584 * since then data is acquired raceful from
585 * /proc. This can never actually happen, but let's
586 * better be safe than sorry, and do an extra check
588 assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EFFECTIVE_CAPS) == 0, -EPERM);
590 /* Note that not even on kdbus we might have the caps
591 * field, due to faked identities, or namespace
592 * translation issues. */
593 r = sd_bus_creds_has_effective_cap(creds, capability);
599 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID, &creds);
604 /* Now, check the UID, but only if the capability check wasn't
607 if (our_uid != 0 || !know_caps || capability < 0) {
610 /* We cannot use augmented uid/euid for authorization,
611 * since then data is acquired raceful from
612 * /proc. This can never actually happen, but let's
613 * better be safe than sorry, and do an extra check
615 assert_return((sd_bus_creds_get_augmented_mask(creds) & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID)) == 0, -EPERM);
617 /* Try to use the EUID, if we have it. */
618 r = sd_bus_creds_get_euid(creds, &sender_uid);
620 r = sd_bus_creds_get_uid(creds, &sender_uid);
623 /* Sender has same UID as us, then let's grant access */
624 if (sender_uid == our_uid)
627 /* Sender is root, we are not root. */
628 if (our_uid != 0 && sender_uid == 0)