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 assert_return(bus, -EINVAL);
115 assert_return(!bus_pid_changed(bus), -ECHILD);
117 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 _public_ int sd_bus_reply_method_return(
138 sd_bus_message *call,
139 const char *types, ...) {
141 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
144 assert_return(call, -EINVAL);
145 assert_return(call->sealed, -EPERM);
146 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
147 assert_return(call->bus, -EINVAL);
148 assert_return(!bus_pid_changed(call->bus), -ECHILD);
150 if (!BUS_IS_OPEN(call->bus->state))
153 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
156 r = sd_bus_message_new_method_return(call, &m);
160 if (!isempty(types)) {
164 r = bus_message_append_ap(m, types, ap);
170 return sd_bus_send(call->bus, m, NULL);
173 _public_ int sd_bus_reply_method_error(
174 sd_bus_message *call,
175 const sd_bus_error *e) {
177 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
180 assert_return(call, -EINVAL);
181 assert_return(call->sealed, -EPERM);
182 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
183 assert_return(sd_bus_error_is_set(e), -EINVAL);
184 assert_return(call->bus, -EINVAL);
185 assert_return(!bus_pid_changed(call->bus), -ECHILD);
187 if (!BUS_IS_OPEN(call->bus->state))
190 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
193 r = sd_bus_message_new_method_error(call, &m, e);
197 return sd_bus_send(call->bus, m, NULL);
200 _public_ int sd_bus_reply_method_errorf(
201 sd_bus_message *call,
206 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
209 assert_return(call, -EINVAL);
210 assert_return(call->sealed, -EPERM);
211 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
212 assert_return(call->bus, -EINVAL);
213 assert_return(!bus_pid_changed(call->bus), -ECHILD);
215 if (!BUS_IS_OPEN(call->bus->state))
218 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
221 va_start(ap, format);
222 bus_error_setfv(&error, name, format, ap);
225 return sd_bus_reply_method_error(call, &error);
228 _public_ int sd_bus_reply_method_errno(
229 sd_bus_message *call,
231 const sd_bus_error *p) {
233 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
235 assert_return(call, -EINVAL);
236 assert_return(call->sealed, -EPERM);
237 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
238 assert_return(call->bus, -EINVAL);
239 assert_return(!bus_pid_changed(call->bus), -ECHILD);
241 if (!BUS_IS_OPEN(call->bus->state))
244 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
247 if (sd_bus_error_is_set(p))
248 return sd_bus_reply_method_error(call, p);
250 sd_bus_error_set_errno(&berror, error);
252 return sd_bus_reply_method_error(call, &berror);
255 /// UNNEEDED by elogind
257 _public_ int sd_bus_reply_method_errnof(
258 sd_bus_message *call,
263 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
266 assert_return(call, -EINVAL);
267 assert_return(call->sealed, -EPERM);
268 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
269 assert_return(call->bus, -EINVAL);
270 assert_return(!bus_pid_changed(call->bus), -ECHILD);
272 if (!BUS_IS_OPEN(call->bus->state))
275 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
278 va_start(ap, format);
279 sd_bus_error_set_errnofv(&berror, error, format, ap);
282 return sd_bus_reply_method_error(call, &berror);
286 _public_ int sd_bus_get_property(
288 const char *destination,
290 const char *interface,
293 sd_bus_message **reply,
296 sd_bus_message *rep = NULL;
299 assert_return(bus, -EINVAL);
300 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
301 assert_return(member_name_is_valid(member), -EINVAL);
302 assert_return(reply, -EINVAL);
303 assert_return(signature_is_single(type, false), -EINVAL);
304 assert_return(!bus_pid_changed(bus), -ECHILD);
306 if (!BUS_IS_OPEN(bus->state))
309 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
313 r = sd_bus_message_enter_container(rep, 'v', type);
315 sd_bus_message_unref(rep);
323 /// UNNEEDED by elogind
325 _public_ int sd_bus_get_property_trivial(
327 const char *destination,
329 const char *interface,
332 char type, void *ptr) {
334 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
337 assert_return(bus, -EINVAL);
338 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
339 assert_return(member_name_is_valid(member), -EINVAL);
340 assert_return(bus_type_is_trivial(type), -EINVAL);
341 assert_return(ptr, -EINVAL);
342 assert_return(!bus_pid_changed(bus), -ECHILD);
344 if (!BUS_IS_OPEN(bus->state))
347 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
351 r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
355 r = sd_bus_message_read_basic(reply, type, ptr);
363 _public_ int sd_bus_get_property_string(
365 const char *destination,
367 const char *interface,
372 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
377 assert_return(bus, -EINVAL);
378 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
379 assert_return(member_name_is_valid(member), -EINVAL);
380 assert_return(ret, -EINVAL);
381 assert_return(!bus_pid_changed(bus), -ECHILD);
383 if (!BUS_IS_OPEN(bus->state))
386 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
390 r = sd_bus_message_enter_container(reply, 'v', "s");
394 r = sd_bus_message_read_basic(reply, 's', &s);
406 /// UNNEEDED by elogind
408 _public_ int sd_bus_get_property_strv(
410 const char *destination,
412 const char *interface,
417 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
420 assert_return(bus, -EINVAL);
421 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
422 assert_return(member_name_is_valid(member), -EINVAL);
423 assert_return(ret, -EINVAL);
424 assert_return(!bus_pid_changed(bus), -ECHILD);
426 if (!BUS_IS_OPEN(bus->state))
429 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
433 r = sd_bus_message_enter_container(reply, 'v', NULL);
437 r = sd_bus_message_read_strv(reply, ret);
444 _public_ int sd_bus_set_property(
446 const char *destination,
448 const char *interface,
451 const char *type, ...) {
453 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
457 assert_return(bus, -EINVAL);
458 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
459 assert_return(member_name_is_valid(member), -EINVAL);
460 assert_return(signature_is_single(type, false), -EINVAL);
461 assert_return(!bus_pid_changed(bus), -ECHILD);
463 if (!BUS_IS_OPEN(bus->state))
466 r = sd_bus_message_new_method_call(bus, &m, destination, path, "org.freedesktop.DBus.Properties", "Set");
470 r = sd_bus_message_append(m, "ss", strempty(interface), member);
474 r = sd_bus_message_open_container(m, 'v', type);
479 r = bus_message_append_ap(m, type, ap);
484 r = sd_bus_message_close_container(m);
488 return sd_bus_call(bus, m, 0, error, NULL);
492 _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
495 assert_return(call, -EINVAL);
496 assert_return(call->sealed, -EPERM);
497 assert_return(call->bus, -EINVAL);
498 assert_return(!bus_pid_changed(call->bus), -ECHILD);
500 if (!BUS_IS_OPEN(call->bus->state))
503 c = sd_bus_message_get_creds(call);
505 /* All data we need? */
506 if (c && (mask & ~c->mask) == 0) {
507 *creds = sd_bus_creds_ref(c);
511 /* No data passed? Or not enough data passed to retrieve the missing bits? */
512 if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
513 /* We couldn't read anything from the call, let's try
514 * to get it from the sender or peer. */
517 /* There's a sender, but the creds are
518 * missing. This means we are talking via
519 * dbus1, or are getting a message that was
520 * sent to us via kdbus, but was converted
521 * from a dbus1 message by the bus-proxy and
522 * thus also lacks the creds. */
523 return sd_bus_get_name_creds(call->bus, call->sender, mask, creds);
525 /* There's no sender, hence we are on a dbus1
526 * direct connection. For direct connections
527 * the credentials of the AF_UNIX peer matter,
528 * which may be queried via
529 * sd_bus_get_owner_creds(). */
530 return sd_bus_get_owner_creds(call->bus, mask, creds);
533 return bus_creds_extend_by_pid(c, mask, creds);
536 _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
537 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
539 bool know_caps = false;
542 assert_return(call, -EINVAL);
543 assert_return(call->sealed, -EPERM);
544 assert_return(call->bus, -EINVAL);
545 assert_return(!bus_pid_changed(call->bus), -ECHILD);
547 if (!BUS_IS_OPEN(call->bus->state))
550 if (capability >= 0) {
552 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
556 /* We cannot use augmented caps for authorization,
557 * since then data is acquired raceful from
558 * /proc. This can never actually happen, but let's
559 * better be safe than sorry, and do an extra check
561 assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EFFECTIVE_CAPS) == 0, -EPERM);
563 /* Note that not even on kdbus we might have the caps
564 * field, due to faked identities, or namespace
565 * translation issues. */
566 r = sd_bus_creds_has_effective_cap(creds, capability);
572 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID, &creds);
577 /* Now, check the UID, but only if the capability check wasn't
580 if (our_uid != 0 || !know_caps || capability < 0) {
583 /* We cannot use augmented uid/euid 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_UID|SD_BUS_CREDS_EUID)) == 0, -EPERM);
590 /* Try to use the EUID, if we have it. */
591 r = sd_bus_creds_get_euid(creds, &sender_uid);
593 r = sd_bus_creds_get_uid(creds, &sender_uid);
596 /* Sender has same UID as us, then let's grant access */
597 if (sender_uid == our_uid)
600 /* Sender is root, we are not root. */
601 if (our_uid != 0 && sender_uid == 0)