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 _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_bus_message_unref_ 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);
98 _public_ int sd_bus_call_method(
100 const char *destination,
102 const char *interface,
105 sd_bus_message **reply,
106 const char *types, ...) {
108 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
111 assert_return(bus, -EINVAL);
112 assert_return(!bus_pid_changed(bus), -ECHILD);
114 if (!BUS_IS_OPEN(bus->state))
117 r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
121 if (!isempty(types)) {
125 r = bus_message_append_ap(m, types, ap);
131 return sd_bus_call(bus, m, 0, error, reply);
134 _public_ int sd_bus_reply_method_return(
135 sd_bus_message *call,
136 const char *types, ...) {
138 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
141 assert_return(call, -EINVAL);
142 assert_return(call->sealed, -EPERM);
143 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
144 assert_return(call->bus, -EINVAL);
145 assert_return(!bus_pid_changed(call->bus), -ECHILD);
147 if (!BUS_IS_OPEN(call->bus->state))
150 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
153 r = sd_bus_message_new_method_return(call, &m);
157 if (!isempty(types)) {
161 r = bus_message_append_ap(m, types, ap);
167 return sd_bus_send(call->bus, m, NULL);
170 _public_ int sd_bus_reply_method_error(
171 sd_bus_message *call,
172 const sd_bus_error *e) {
174 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
177 assert_return(call, -EINVAL);
178 assert_return(call->sealed, -EPERM);
179 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
180 assert_return(sd_bus_error_is_set(e), -EINVAL);
181 assert_return(call->bus, -EINVAL);
182 assert_return(!bus_pid_changed(call->bus), -ECHILD);
184 if (!BUS_IS_OPEN(call->bus->state))
187 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
190 r = sd_bus_message_new_method_error(call, &m, e);
194 return sd_bus_send(call->bus, m, NULL);
197 _public_ int sd_bus_reply_method_errorf(
198 sd_bus_message *call,
203 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
206 assert_return(call, -EINVAL);
207 assert_return(call->sealed, -EPERM);
208 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
209 assert_return(call->bus, -EINVAL);
210 assert_return(!bus_pid_changed(call->bus), -ECHILD);
212 if (!BUS_IS_OPEN(call->bus->state))
215 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
218 va_start(ap, format);
219 bus_error_setfv(&error, name, format, ap);
222 return sd_bus_reply_method_error(call, &error);
225 _public_ int sd_bus_reply_method_errno(
226 sd_bus_message *call,
228 const sd_bus_error *p) {
230 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
232 assert_return(call, -EINVAL);
233 assert_return(call->sealed, -EPERM);
234 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
235 assert_return(call->bus, -EINVAL);
236 assert_return(!bus_pid_changed(call->bus), -ECHILD);
238 if (!BUS_IS_OPEN(call->bus->state))
241 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
244 if (sd_bus_error_is_set(p))
245 return sd_bus_reply_method_error(call, p);
247 sd_bus_error_set_errno(&berror, error);
249 return sd_bus_reply_method_error(call, &berror);
252 _public_ int sd_bus_reply_method_errnof(
253 sd_bus_message *call,
258 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
261 assert_return(call, -EINVAL);
262 assert_return(call->sealed, -EPERM);
263 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
264 assert_return(call->bus, -EINVAL);
265 assert_return(!bus_pid_changed(call->bus), -ECHILD);
267 if (!BUS_IS_OPEN(call->bus->state))
270 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
273 va_start(ap, format);
274 sd_bus_error_set_errnofv(&berror, error, format, ap);
277 return sd_bus_reply_method_error(call, &berror);
280 _public_ int sd_bus_get_property(
282 const char *destination,
284 const char *interface,
287 sd_bus_message **reply,
290 sd_bus_message *rep = NULL;
293 assert_return(bus, -EINVAL);
294 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
295 assert_return(member_name_is_valid(member), -EINVAL);
296 assert_return(reply, -EINVAL);
297 assert_return(signature_is_single(type, false), -EINVAL);
298 assert_return(!bus_pid_changed(bus), -ECHILD);
300 if (!BUS_IS_OPEN(bus->state))
303 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
307 r = sd_bus_message_enter_container(rep, 'v', type);
309 sd_bus_message_unref(rep);
317 _public_ int sd_bus_get_property_trivial(
319 const char *destination,
321 const char *interface,
324 char type, void *ptr) {
326 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
329 assert_return(bus, -EINVAL);
330 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
331 assert_return(member_name_is_valid(member), -EINVAL);
332 assert_return(bus_type_is_trivial(type), -EINVAL);
333 assert_return(ptr, -EINVAL);
334 assert_return(!bus_pid_changed(bus), -ECHILD);
336 if (!BUS_IS_OPEN(bus->state))
339 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
343 r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
347 r = sd_bus_message_read_basic(reply, type, ptr);
354 _public_ int sd_bus_get_property_string(
356 const char *destination,
358 const char *interface,
363 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
368 assert_return(bus, -EINVAL);
369 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
370 assert_return(member_name_is_valid(member), -EINVAL);
371 assert_return(ret, -EINVAL);
372 assert_return(!bus_pid_changed(bus), -ECHILD);
374 if (!BUS_IS_OPEN(bus->state))
377 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
381 r = sd_bus_message_enter_container(reply, 'v', "s");
385 r = sd_bus_message_read_basic(reply, 's', &s);
397 _public_ int sd_bus_get_property_strv(
399 const char *destination,
401 const char *interface,
406 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
409 assert_return(bus, -EINVAL);
410 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
411 assert_return(member_name_is_valid(member), -EINVAL);
412 assert_return(ret, -EINVAL);
413 assert_return(!bus_pid_changed(bus), -ECHILD);
415 if (!BUS_IS_OPEN(bus->state))
418 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
422 r = sd_bus_message_enter_container(reply, 'v', NULL);
426 r = sd_bus_message_read_strv(reply, ret);
433 _public_ int sd_bus_set_property(
435 const char *destination,
437 const char *interface,
440 const char *type, ...) {
442 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
446 assert_return(bus, -EINVAL);
447 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
448 assert_return(member_name_is_valid(member), -EINVAL);
449 assert_return(signature_is_single(type, false), -EINVAL);
450 assert_return(!bus_pid_changed(bus), -ECHILD);
452 if (!BUS_IS_OPEN(bus->state))
455 r = sd_bus_message_new_method_call(bus, &m, destination, path, "org.freedesktop.DBus.Properties", "Set");
459 r = sd_bus_message_append(m, "ss", strempty(interface), member);
463 r = sd_bus_message_open_container(m, 'v', type);
468 r = bus_message_append_ap(m, type, ap);
473 r = sd_bus_message_close_container(m);
477 return sd_bus_call(bus, m, 0, error, NULL);
480 _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
483 assert_return(call, -EINVAL);
484 assert_return(call->sealed, -EPERM);
485 assert_return(call->bus, -EINVAL);
486 assert_return(!bus_pid_changed(call->bus), -ECHILD);
488 if (!BUS_IS_OPEN(call->bus->state))
491 c = sd_bus_message_get_creds(call);
493 /* All data we need? */
494 if (c && (mask & ~c->mask) == 0) {
495 *creds = sd_bus_creds_ref(c);
499 /* No data passed? Or not enough data passed to retrieve the missing bits? */
500 if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
501 /* We couldn't read anything from the call, let's try
502 * to get it from the sender or peer. */
505 /* There's a sender, but the creds are
506 * missing. This means we are talking via
507 * dbus1, or are getting a message that was
508 * sent to us via kdbus, but was converted
509 * from a dbus1 message by the bus-proxy and
510 * thus also lacks the creds. */
511 return sd_bus_get_name_creds(call->bus, call->sender, mask, creds);
513 /* There's no sender, hence we are on a dbus1
514 * direct connection. For direct connections
515 * the credentials of the AF_UNIX peer matter,
516 * which may be queried via
517 * sd_bus_get_owner_creds(). */
518 return sd_bus_get_owner_creds(call->bus, mask, creds);
521 return bus_creds_extend_by_pid(c, mask, creds);
524 _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
525 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
527 bool know_caps = false;
530 assert_return(call, -EINVAL);
531 assert_return(call->sealed, -EPERM);
532 assert_return(call->bus, -EINVAL);
533 assert_return(!bus_pid_changed(call->bus), -ECHILD);
535 if (!BUS_IS_OPEN(call->bus->state))
538 if (capability >= 0) {
540 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
544 /* We cannot use augmented caps for authorization,
545 * since then data is acquired raceful from
546 * /proc. This can never actually happen, but let's
547 * better be safe than sorry, and do an extra check
549 assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EFFECTIVE_CAPS) == 0, -EPERM);
551 /* Note that not even on kdbus we might have the caps
552 * field, due to faked identities, or namespace
553 * translation issues. */
554 r = sd_bus_creds_has_effective_cap(creds, capability);
560 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID, &creds);
565 /* Now, check the UID, but only if the capability check wasn't
568 if (our_uid != 0 || !know_caps || capability < 0) {
571 /* We cannot use augmented uid/euid 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_UID|SD_BUS_CREDS_EUID)) == 0, -EPERM);
578 /* Try to use the EUID, if we have it. */
579 r = sd_bus_creds_get_euid(creds, &sender_uid);
581 r = sd_bus_creds_get_uid(creds, &sender_uid);
584 /* Sender has same UID as us, then let's grant access */
585 if (sender_uid == our_uid)
588 /* Sender is root, we are not root. */
589 if (our_uid != 0 && sender_uid == 0)