1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
7 Copyright 2013 Daniel Mack
8 Copyright 2014 Kay Sievers
10 systemd is free software; you can redistribute it and/or modify it
11 under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
15 systemd is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public License
21 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <sys/socket.h>
26 #include <sys/types.h>
37 #include "socket-util.h"
38 #include "sd-daemon.h"
40 #include "bus-internal.h"
41 #include "bus-message.h"
47 static const char *arg_address = DEFAULT_SYSTEM_BUS_PATH;
48 static char *arg_command_line_buffer = NULL;
50 static int help(void) {
52 printf("%s [OPTIONS...]\n\n"
53 "Connect STDIO or a socket to a given bus address.\n\n"
54 " -h --help Show this help\n"
55 " --version Show package version\n"
56 " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
57 " (default: " DEFAULT_SYSTEM_BUS_PATH ")\n",
58 program_invocation_short_name);
63 static int parse_argv(int argc, char *argv[]) {
70 static const struct option options[] = {
71 { "help", no_argument, NULL, 'h' },
72 { "version", no_argument, NULL, ARG_VERSION },
73 { "address", required_argument, NULL, ARG_ADDRESS },
82 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
92 puts(SYSTEMD_FEATURES);
103 assert_not_reached("Unhandled option");
107 /* If the first command line argument is only "x" characters
108 * we'll write who we are talking to into it, so that "ps" is
110 arg_command_line_buffer = argv[optind];
111 if (argc > optind + 1 ||
112 (arg_command_line_buffer && arg_command_line_buffer[strspn(arg_command_line_buffer, "x")] != 0)) {
113 log_error("Too many arguments");
120 static int rename_service(sd_bus *a, sd_bus *b) {
121 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
122 _cleanup_free_ char *p = NULL, *name = NULL;
132 r = sd_bus_get_peer_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM, &creds);
136 r = sd_bus_creds_get_uid(creds, &uid);
140 r = sd_bus_creds_get_pid(creds, &pid);
144 r = sd_bus_creds_get_cmdline(creds, &cmdline);
148 r = sd_bus_creds_get_comm(creds, &comm);
152 name = uid_to_name(uid);
156 p = strv_join(cmdline, " ");
160 /* The status string gets the full command line ... */
162 "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
166 /* ... and the argv line only the short comm */
167 if (arg_command_line_buffer) {
170 m = strlen(arg_command_line_buffer);
171 w = snprintf(arg_command_line_buffer, m,
172 "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
177 memzero(arg_command_line_buffer + w, m - w);
180 log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
188 static int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
189 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
190 const char *name, *old_owner, *new_owner;
197 /* If we get NameOwnerChanged for our own name, we need to
198 * synthesize NameLost/NameAcquired, since socket clients need
199 * that, even though it is obsoleted on kdbus */
204 if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
205 !streq_ptr(m->path, "/org/freedesktop/DBus") ||
206 !streq_ptr(m->sender, "org.freedesktop.DBus"))
209 r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
213 r = sd_bus_message_rewind(m, true);
217 if (streq(old_owner, a->unique_name)) {
219 r = sd_bus_message_new_signal(
222 "/org/freedesktop/DBus",
223 "org.freedesktop.DBus",
226 } else if (streq(new_owner, a->unique_name)) {
228 r = sd_bus_message_new_signal(
231 "/org/freedesktop/DBus",
232 "org.freedesktop.DBus",
240 r = sd_bus_message_append(n, "s", name);
244 r = bus_message_append_sender(n, "org.freedesktop.DBus");
248 r = bus_seal_synthetic_message(b, n);
252 return sd_bus_send(b, n, NULL);
255 static int process_policy(sd_bus *a, sd_bus *b, sd_bus_message *m) {
256 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
263 if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll"))
266 if (!streq_ptr(m->path, "/org/gnome/DisplayManager/Slave"))
269 r = sd_bus_message_new_method_errorf(m, &n, SD_BUS_ERROR_ACCESS_DENIED, "gdm, you are stupid");
273 r = bus_message_append_sender(n, "org.freedesktop.DBus");
275 log_error("Failed to append sender to gdm reply: %s", strerror(-r));
279 r = bus_seal_synthetic_message(b, n);
281 log_error("Failed to seal gdm reply: %s", strerror(-r));
285 r = sd_bus_send(b, n, NULL);
287 log_error("Failed to send gdm reply: %s", strerror(-r));
294 static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
300 r = bus_message_append_sender(m, "org.freedesktop.DBus");
304 r = bus_seal_synthetic_message(b, m);
308 return sd_bus_send(b, m, NULL);
311 static int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
312 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
315 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
318 r = sd_bus_message_new_method_error(call, &m, e);
322 return synthetic_driver_send(call->bus, m);
325 static int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
327 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
329 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
332 if (sd_bus_error_is_set(p))
333 return synthetic_reply_method_error(call, p);
335 sd_bus_error_set_errno(&berror, error);
337 return synthetic_reply_method_error(call, &berror);
340 static int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
341 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
344 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
347 r = sd_bus_message_new_method_return(call, &m);
351 if (!isempty(types)) {
355 r = bus_message_append_ap(m, types, ap);
361 return synthetic_driver_send(call->bus, m);
364 static int synthetic_reply_return_strv(sd_bus_message *call, char **l) {
365 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
368 r = sd_bus_message_new_method_return(call, &m);
370 return synthetic_reply_method_errno(call, r, NULL);
372 r = sd_bus_message_append_strv(m, l);
374 return synthetic_reply_method_errno(call, r, NULL);
376 return synthetic_driver_send(call->bus, m);
379 static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
380 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
387 assert_return(service_name_is_valid(name), -EINVAL);
389 r = sd_bus_get_owner(bus, name, mask, &c);
390 if (r == -ESRCH || r == -ENXIO)
391 return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
395 if ((c->mask & mask) != mask)
404 static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
412 r = sd_bus_message_read(m, "s", &name);
416 return get_creds_by_name(bus, name, mask, _creds, error);
419 static int peer_is_privileged(sd_bus *bus, sd_bus_message *m) {
420 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
424 r = get_creds_by_message(bus, m, SD_BUS_CREDS_UID, &creds, NULL);
428 r = sd_bus_creds_get_uid(creds, &uid);
432 r = sd_bus_creds_has_effective_cap(creds, CAP_SYS_ADMIN);
443 static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
450 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
453 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
454 if (0 && !isempty(sd_bus_message_get_signature(m, true))) {
455 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
457 r = sd_bus_error_setf(&error, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
459 return synthetic_reply_method_errno(m, r, &error);
462 return synthetic_reply_method_return(m, "s",
463 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
464 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
466 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
467 " <method name=\"Introspect\">\n"
468 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
471 " <interface name=\"org.freedesktop.DBus\">\n"
472 " <method name=\"AddMatch\">\n"
473 " <arg type=\"s\" direction=\"in\"/>\n"
475 " <method name=\"RemoveMatch\">\n"
476 " <arg type=\"s\" direction=\"in\"/>\n"
478 " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
479 " <arg type=\"s\" direction=\"in\"/>\n"
480 " <arg type=\"ay\" direction=\"out\"/>\n"
482 " <method name=\"GetConnectionUnixProcessID\">\n"
483 " <arg type=\"s\" direction=\"in\"/>\n"
484 " <arg type=\"u\" direction=\"out\"/>\n"
486 " <method name=\"GetConnectionUnixUser\">\n"
487 " <arg type=\"s\" direction=\"in\"/>\n"
488 " <arg type=\"u\" direction=\"out\"/>\n"
490 " <method name=\"GetId\">\n"
491 " <arg type=\"s\" direction=\"out\"/>\n"
493 " <method name=\"GetNameOwner\">\n"
494 " <arg type=\"s\" direction=\"in\"/>\n"
495 " <arg type=\"s\" direction=\"out\"/>\n"
497 " <method name=\"Hello\">\n"
498 " <arg type=\"s\" direction=\"out\"/>\n"
500 " <method name=\"ListActivatableNames\">\n"
501 " <arg type=\"as\" direction=\"out\"/>\n"
503 " <method name=\"ListNames\">\n"
504 " <arg type=\"as\" direction=\"out\"/>\n"
506 " <method name=\"ListQueuedOwners\">\n"
507 " <arg type=\"s\" direction=\"in\"/>\n"
508 " <arg type=\"as\" direction=\"out\"/>\n"
510 " <method name=\"NameHasOwner\">\n"
511 " <arg type=\"s\" direction=\"in\"/>\n"
512 " <arg type=\"b\" direction=\"out\"/>\n"
514 " <method name=\"ReleaseName\">\n"
515 " <arg type=\"s\" direction=\"in\"/>\n"
516 " <arg type=\"u\" direction=\"out\"/>\n"
518 " <method name=\"ReloadConfig\">\n"
520 " <method name=\"RequestName\">\n"
521 " <arg type=\"s\" direction=\"in\"/>\n"
522 " <arg type=\"u\" direction=\"in\"/>\n"
523 " <arg type=\"u\" direction=\"out\"/>\n"
525 " <method name=\"StartServiceByName\">\n"
526 " <arg type=\"s\" direction=\"in\"/>\n"
527 " <arg type=\"u\" direction=\"in\"/>\n"
528 " <arg type=\"u\" direction=\"out\"/>\n"
530 " <method name=\"UpdateActivationEnvironment\">\n"
531 " <arg type=\"a{ss}\" direction=\"in\"/>\n"
533 " <signal name=\"NameAcquired\">\n"
534 " <arg type=\"s\"/>\n"
536 " <signal name=\"NameLost\">\n"
537 " <arg type=\"s\"/>\n"
539 " <signal name=\"NameOwnerChanged\">\n"
540 " <arg type=\"s\"/>\n"
541 " <arg type=\"s\"/>\n"
542 " <arg type=\"s\"/>\n"
547 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
550 r = sd_bus_message_read(m, "s", &match);
552 return synthetic_reply_method_errno(m, r, NULL);
554 r = sd_bus_add_match(a, match, NULL, NULL);
556 return synthetic_reply_method_errno(m, r, NULL);
558 return synthetic_reply_method_return(m, NULL);
560 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
563 r = sd_bus_message_read(m, "s", &match);
565 return synthetic_reply_method_errno(m, r, NULL);
567 r = sd_bus_remove_match(a, match, NULL, NULL);
569 return synthetic_reply_method_errno(m, r, NULL);
571 return synthetic_reply_method_return(m, NULL);
573 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
574 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
576 r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, NULL);
578 return synthetic_reply_method_errno(m, r, NULL);
580 return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
582 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
583 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
585 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, NULL);
587 return synthetic_reply_method_errno(m, r, NULL);
589 return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
591 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
592 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
594 r = get_creds_by_message(a, m, SD_BUS_CREDS_UID, &creds, NULL);
596 return synthetic_reply_method_errno(m, r, NULL);
598 return synthetic_reply_method_return(m, "u", (uint32_t) creds->uid);
600 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
601 sd_id128_t server_id;
602 char buf[SD_ID128_STRING_MAX];
604 r = sd_bus_get_server_id(a, &server_id);
606 return synthetic_reply_method_errno(m, r, NULL);
608 return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
610 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
612 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
613 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
615 r = sd_bus_message_read(m, "s", &name);
617 return synthetic_reply_method_errno(m, r, NULL);
619 if (streq(name, "org.freedesktop.DBus"))
620 return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
622 r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
624 return synthetic_reply_method_errno(m, r, &error);
626 return synthetic_reply_method_return(m, "s", creds->unique_name);
628 /* "Hello" is handled in process_hello() */
630 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
631 _cleanup_strv_free_ char **names = NULL;
633 r = sd_bus_list_names(a, NULL, &names);
635 return synthetic_reply_method_errno(m, r, NULL);
637 /* Let's sort the names list to make it stable */
640 return synthetic_reply_return_strv(m, names);
642 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
643 _cleanup_strv_free_ char **names = NULL;
645 r = sd_bus_list_names(a, &names, NULL);
647 return synthetic_reply_method_errno(m, r, NULL);
649 r = strv_extend(&names, "org.freedesktop.DBus");
651 return synthetic_reply_method_errno(m, r, NULL);
653 /* Let's sort the names list to make it stable */
656 return synthetic_reply_return_strv(m, names);
658 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
659 struct kdbus_cmd_name_list cmd = {};
660 struct kdbus_name_list *name_list;
661 struct kdbus_cmd_name *name;
662 _cleanup_strv_free_ char **owners = NULL;
666 r = sd_bus_message_read(m, "s", &arg0);
668 return synthetic_reply_method_errno(m, r, NULL);
670 if (service_name_is_valid(arg0) < 0)
671 return synthetic_reply_method_errno(m, -EINVAL, NULL);
673 cmd.flags = KDBUS_NAME_LIST_QUEUED;
674 r = ioctl(a->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
676 return synthetic_reply_method_errno(m, -errno, NULL);
678 name_list = (struct kdbus_name_list *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
680 KDBUS_ITEM_FOREACH(name, name_list, names) {
683 if (name->size <= sizeof(*name))
686 if (!streq(name->name, arg0))
689 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
694 r = strv_consume(&owners, n);
701 r = ioctl(a->input_fd, KDBUS_CMD_FREE, &cmd.offset);
703 return synthetic_reply_method_errno(m, r, NULL);
706 return synthetic_reply_method_errno(m, err, NULL);
708 return synthetic_reply_return_strv(m, owners);
710 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
713 r = sd_bus_message_read(m, "s", &name);
715 return synthetic_reply_method_errno(m, r, NULL);
717 if (service_name_is_valid(name) < 0)
718 return synthetic_reply_method_errno(m, -EINVAL, NULL);
720 if (streq(name, "org.freedesktop.DBus"))
721 return synthetic_reply_method_return(m, "b", true);
723 r = sd_bus_get_owner(a, name, 0, NULL);
724 if (r < 0 && r != -ESRCH && r != -ENXIO)
725 return synthetic_reply_method_errno(m, r, NULL);
727 return synthetic_reply_method_return(m, "b", r >= 0);
729 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
732 r = sd_bus_message_read(m, "s", &name);
734 return synthetic_reply_method_errno(m, r, NULL);
736 if (service_name_is_valid(name) < 0)
737 return synthetic_reply_method_errno(m, -EINVAL, NULL);
739 r = sd_bus_release_name(a, name);
742 synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
743 if (r == -EADDRINUSE)
744 synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
745 return synthetic_reply_method_errno(m, r, NULL);
748 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
750 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
751 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
753 r = sd_bus_error_setf(&error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
755 return synthetic_reply_method_errno(m, r, &error);
757 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
761 r = sd_bus_message_read(m, "su", &name, &flags);
763 return synthetic_reply_method_errno(m, r, NULL);
765 if (service_name_is_valid(name) < 0)
766 return synthetic_reply_method_errno(m, -EINVAL, NULL);
767 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
768 return synthetic_reply_method_errno(m, -EINVAL, NULL);
770 r = sd_bus_request_name(a, name, flags);
773 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
775 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
776 return synthetic_reply_method_errno(m, r, NULL);
780 return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
782 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
784 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
785 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
789 r = sd_bus_message_read(m, "su", &name, &flags);
791 return synthetic_reply_method_errno(m, r, NULL);
793 if (service_name_is_valid(name) < 0)
794 return synthetic_reply_method_errno(m, -EINVAL, NULL);
796 return synthetic_reply_method_errno(m, -EINVAL, NULL);
798 r = sd_bus_get_owner(a, name, 0, NULL);
799 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
800 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
802 return synthetic_reply_method_errno(m, r, NULL);
804 r = sd_bus_message_new_method_call(
809 "org.freedesktop.DBus.Peer",
812 return synthetic_reply_method_errno(m, r, NULL);
814 r = sd_bus_send(a, msg, NULL);
816 return synthetic_reply_method_errno(m, r, NULL);
818 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
820 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
821 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
822 _cleanup_strv_free_ char **args = NULL;
824 if (!peer_is_privileged(a, m))
825 return synthetic_reply_method_errno(m, -EPERM, NULL);
827 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
829 return synthetic_reply_method_errno(m, r, NULL);
831 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
832 _cleanup_free_ char *s = NULL;
836 r = sd_bus_message_read(m, "ss", &key, &value);
838 return synthetic_reply_method_errno(m, r, NULL);
840 s = strjoin(key, "=", value, NULL);
842 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
844 r = strv_extend(&args, s);
846 return synthetic_reply_method_errno(m, r, NULL);
848 r = sd_bus_message_exit_container(m);
850 return synthetic_reply_method_errno(m, r, NULL);
853 r = sd_bus_message_exit_container(m);
855 return synthetic_reply_method_errno(m, r, NULL);
858 return synthetic_reply_method_errno(m, -EINVAL, NULL);
860 r = sd_bus_message_new_method_call(
863 "org.freedesktop.systemd1",
864 "/org/freedesktop/systemd1",
865 "org.freedesktop.systemd1.Manager",
868 return synthetic_reply_method_errno(m, r, NULL);
870 r = sd_bus_message_append_strv(msg, args);
872 return synthetic_reply_method_errno(m, r, NULL);
874 r = sd_bus_call(a, msg, 0, NULL, NULL);
876 return synthetic_reply_method_errno(m, r, NULL);
878 return synthetic_reply_method_return(m, NULL);
881 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
883 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
885 return synthetic_reply_method_errno(m, r, &error);
889 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
890 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
899 /* As reaction to hello we need to respond with two messages:
900 * the callback reply and the NameAcquired for the unique
901 * name, since hello is otherwise obsolete on kdbus. */
904 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
905 streq_ptr(m->destination, "org.freedesktop.DBus");
912 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
917 log_error("Got duplicate hello, aborting.");
926 r = sd_bus_message_new_method_return(m, &n);
928 log_error("Failed to generate HELLO reply: %s", strerror(-r));
932 r = sd_bus_message_append(n, "s", a->unique_name);
934 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
938 r = bus_message_append_sender(n, "org.freedesktop.DBus");
940 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
944 r = bus_seal_synthetic_message(b, n);
946 log_error("Failed to seal HELLO reply: %s", strerror(-r));
950 r = sd_bus_send(b, n, NULL);
952 log_error("Failed to send HELLO reply: %s", strerror(-r));
956 n = sd_bus_message_unref(n);
957 r = sd_bus_message_new_signal(
960 "/org/freedesktop/DBus",
961 "org.freedesktop.DBus",
964 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
968 r = sd_bus_message_append(n, "s", a->unique_name);
970 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
974 r = bus_message_append_sender(n, "org.freedesktop.DBus");
976 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
980 r = bus_seal_synthetic_message(b, n);
982 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
986 r = sd_bus_send(b, n, NULL);
988 log_error("Failed to send NameAcquired message: %s", strerror(-r));
995 static int patch_sender(sd_bus *a, sd_bus_message *m) {
996 char **well_known = NULL;
1006 /* We will change the sender of messages from the bus driver
1007 * so that they originate from the bus driver. This is a
1008 * speciality originating from dbus1, where the bus driver did
1009 * not have a unique id, but only the well-known name. */
1011 c = sd_bus_message_get_creds(m);
1015 r = sd_bus_creds_get_well_known_names(c, &well_known);
1019 if (strv_contains(well_known, "org.freedesktop.DBus"))
1020 m->sender = "org.freedesktop.DBus";
1025 int main(int argc, char *argv[]) {
1027 _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
1028 sd_id128_t server_id;
1029 int r, in_fd, out_fd;
1030 bool got_hello = false;
1032 struct ucred ucred = {};
1033 _cleanup_free_ char *peersec = NULL;
1035 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
1036 log_parse_environment();
1039 r = parse_argv(argc, argv);
1043 r = sd_listen_fds(0);
1045 in_fd = STDIN_FILENO;
1046 out_fd = STDOUT_FILENO;
1047 } else if (r == 1) {
1048 in_fd = SD_LISTEN_FDS_START;
1049 out_fd = SD_LISTEN_FDS_START;
1051 log_error("Illegal number of file descriptors passed");
1056 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
1057 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
1060 getpeercred(in_fd, &ucred);
1061 getpeersec(in_fd, &peersec);
1066 log_error("Failed to allocate bus: %s", strerror(-r));
1070 r = sd_bus_set_name(a, "sd-proxy");
1072 log_error("Failed to set bus name: %s", strerror(-r));
1076 r = sd_bus_set_address(a, arg_address);
1078 log_error("Failed to set address to connect to: %s", strerror(-r));
1082 r = sd_bus_negotiate_fds(a, is_unix);
1084 log_error("Failed to set FD negotiation: %s", strerror(-r));
1088 if (ucred.pid > 0) {
1089 a->fake_creds.pid = ucred.pid;
1090 a->fake_creds.uid = ucred.uid;
1091 a->fake_creds.gid = ucred.gid;
1092 a->fake_creds_valid = true;
1096 a->fake_label = peersec;
1100 a->manual_peer_interface = true;
1102 r = sd_bus_start(a);
1104 log_error("Failed to start bus client: %s", strerror(-r));
1108 r = sd_bus_get_server_id(a, &server_id);
1110 log_error("Failed to get server ID: %s", strerror(-r));
1116 log_error("Failed to allocate bus: %s", strerror(-r));
1120 r = sd_bus_set_fd(b, in_fd, out_fd);
1122 log_error("Failed to set fds: %s", strerror(-r));
1126 r = sd_bus_set_server(b, 1, server_id);
1128 log_error("Failed to set server mode: %s", strerror(-r));
1132 r = sd_bus_negotiate_fds(b, is_unix);
1134 log_error("Failed to set FD negotiation: %s", strerror(-r));
1138 r = sd_bus_set_anonymous(b, true);
1140 log_error("Failed to set anonymous authentication: %s", strerror(-r));
1144 b->manual_peer_interface = true;
1146 r = sd_bus_start(b);
1148 log_error("Failed to start bus client: %s", strerror(-r));
1152 r = rename_service(a, b);
1154 log_debug("Failed to rename process: %s", strerror(-r));
1157 _cleanup_free_ char *match = NULL;
1160 r = sd_bus_get_unique_name(a, &unique);
1162 log_error("Failed to get unique name: %s", strerror(-r));
1166 match = strjoin("type='signal',"
1167 "sender='org.freedesktop.DBus',"
1168 "path='/org/freedesktop/DBus',"
1169 "interface='org.freedesktop.DBus',"
1170 "member='NameOwnerChanged',"
1180 r = sd_bus_add_match(a, match, NULL, NULL);
1182 log_error("Failed to add match for NameLost: %s", strerror(-r));
1187 match = strjoin("type='signal',"
1188 "sender='org.freedesktop.DBus',"
1189 "path='/org/freedesktop/DBus',"
1190 "interface='org.freedesktop.DBus',"
1191 "member='NameOwnerChanged',"
1201 r = sd_bus_add_match(a, match, NULL, NULL);
1203 log_error("Failed to add match for NameAcquired: %s", strerror(-r));
1209 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1210 int events_a, events_b, fd;
1211 uint64_t timeout_a, timeout_b, t;
1212 struct timespec _ts, *ts;
1213 struct pollfd *pollfd;
1217 r = sd_bus_process(a, &m);
1219 /* treat 'connection reset by peer' as clean exit condition */
1220 if (r == -ECONNRESET)
1223 log_error("Failed to process bus a: %s", strerror(-r));
1229 /* We officially got EOF, let's quit */
1230 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1235 k = synthesize_name_acquired(a, b, m);
1238 log_error("Failed to synthesize message: %s", strerror(-r));
1244 k = sd_bus_send(b, m, NULL);
1246 if (k == -ECONNRESET)
1250 log_error("Failed to send message: %s", strerror(-r));
1261 r = sd_bus_process(b, &m);
1263 /* treat 'connection reset by peer' as clean exit condition */
1264 if (r == -ECONNRESET)
1267 log_error("Failed to process bus b: %s", strerror(-r));
1273 /* We officially got EOF, let's quit */
1274 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1279 k = process_hello(a, b, m, &got_hello);
1282 log_error("Failed to process HELLO: %s", strerror(-r));
1289 k = process_policy(a, b, m);
1292 log_error("Failed to process policy: %s", strerror(-r));
1296 k = process_driver(a, b, m);
1299 log_error("Failed to process driver calls: %s", strerror(-r));
1306 k = sd_bus_send(a, m, NULL);
1308 if (r == -ECONNRESET)
1312 log_error("Failed to send message: %s", strerror(-r));
1324 fd = sd_bus_get_fd(a);
1326 log_error("Failed to get fd: %s", strerror(-r));
1330 events_a = sd_bus_get_events(a);
1332 log_error("Failed to get events mask: %s", strerror(-r));
1336 r = sd_bus_get_timeout(a, &timeout_a);
1338 log_error("Failed to get timeout: %s", strerror(-r));
1342 events_b = sd_bus_get_events(b);
1344 log_error("Failed to get events mask: %s", strerror(-r));
1348 r = sd_bus_get_timeout(b, &timeout_b);
1350 log_error("Failed to get timeout: %s", strerror(-r));
1355 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
1358 if (t == (uint64_t) -1)
1363 nw = now(CLOCK_MONOTONIC);
1369 ts = timespec_store(&_ts, t);
1372 pollfd = (struct pollfd[3]) {
1373 {.fd = fd, .events = events_a, },
1374 {.fd = in_fd, .events = events_b & POLLIN, },
1375 {.fd = out_fd, .events = events_b & POLLOUT, }
1378 r = ppoll(pollfd, 3, ts, NULL);
1380 log_error("ppoll() failed: %m");
1389 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;