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"
43 #include "bus-internal.h"
48 static const char *arg_address = DEFAULT_SYSTEM_BUS_PATH;
49 static char *arg_command_line_buffer = NULL;
51 static int help(void) {
53 printf("%s [OPTIONS...]\n\n"
54 "Connect STDIO or a socket to a given bus address.\n\n"
55 " -h --help Show this help\n"
56 " --version Show package version\n"
57 " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
58 " (default: " DEFAULT_SYSTEM_BUS_PATH ")\n",
59 program_invocation_short_name);
64 static int parse_argv(int argc, char *argv[]) {
71 static const struct option options[] = {
72 { "help", no_argument, NULL, 'h' },
73 { "version", no_argument, NULL, ARG_VERSION },
74 { "address", required_argument, NULL, ARG_ADDRESS },
83 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
93 puts(SYSTEMD_FEATURES);
104 assert_not_reached("Unhandled option");
108 /* If the first command line argument is only "x" characters
109 * we'll write who we are talking to into it, so that "ps" is
111 arg_command_line_buffer = argv[optind];
112 if (argc > optind + 1 ||
113 (arg_command_line_buffer && arg_command_line_buffer[strspn(arg_command_line_buffer, "x")] != 0)) {
114 log_error("Too many arguments");
121 static int rename_service(sd_bus *a, sd_bus *b) {
122 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
123 _cleanup_free_ char *p = NULL, *name = NULL;
133 r = sd_bus_get_peer_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM, &creds);
137 r = sd_bus_creds_get_uid(creds, &uid);
141 r = sd_bus_creds_get_pid(creds, &pid);
145 r = sd_bus_creds_get_cmdline(creds, &cmdline);
149 r = sd_bus_creds_get_comm(creds, &comm);
153 name = uid_to_name(uid);
157 p = strv_join(cmdline, " ");
161 /* The status string gets the full command line ... */
163 "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
167 /* ... and the argv line only the short comm */
168 if (arg_command_line_buffer) {
171 m = strlen(arg_command_line_buffer);
172 w = snprintf(arg_command_line_buffer, m,
173 "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
178 memzero(arg_command_line_buffer + w, m - w);
181 log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
189 static int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
190 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
191 const char *name, *old_owner, *new_owner;
198 /* If we get NameOwnerChanged for our own name, we need to
199 * synthesize NameLost/NameAcquired, since socket clients need
200 * that, even though it is obsoleted on kdbus */
205 if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
206 !streq_ptr(m->path, "/org/freedesktop/DBus") ||
207 !streq_ptr(m->sender, "org.freedesktop.DBus"))
210 r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
214 r = sd_bus_message_rewind(m, true);
218 if (streq(old_owner, a->unique_name)) {
220 r = sd_bus_message_new_signal(
223 "/org/freedesktop/DBus",
224 "org.freedesktop.DBus",
227 } else if (streq(new_owner, a->unique_name)) {
229 r = sd_bus_message_new_signal(
232 "/org/freedesktop/DBus",
233 "org.freedesktop.DBus",
241 r = sd_bus_message_append(n, "s", name);
245 r = bus_message_append_sender(n, "org.freedesktop.DBus");
249 r = bus_seal_synthetic_message(b, n);
253 return sd_bus_send(b, n, NULL);
256 static int process_policy(sd_bus *a, sd_bus *b, sd_bus_message *m) {
257 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
264 if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll"))
267 if (!streq_ptr(m->path, "/org/gnome/DisplayManager/Slave"))
270 r = sd_bus_message_new_method_errorf(m, &n, SD_BUS_ERROR_ACCESS_DENIED, "gdm, you are stupid");
274 r = bus_message_append_sender(n, "org.freedesktop.DBus");
276 log_error("Failed to append sender to gdm reply: %s", strerror(-r));
280 r = bus_seal_synthetic_message(b, n);
282 log_error("Failed to seal gdm reply: %s", strerror(-r));
286 r = sd_bus_send(b, n, NULL);
288 log_error("Failed to send gdm reply: %s", strerror(-r));
295 static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
301 r = bus_message_append_sender(m, "org.freedesktop.DBus");
305 r = bus_seal_synthetic_message(b, m);
309 return sd_bus_send(b, m, NULL);
312 static int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
313 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
316 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
319 r = sd_bus_message_new_method_error(call, &m, e);
323 return synthetic_driver_send(call->bus, m);
326 static int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
328 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
330 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
333 if (sd_bus_error_is_set(p))
334 return synthetic_reply_method_error(call, p);
336 sd_bus_error_set_errno(&berror, error);
338 return synthetic_reply_method_error(call, &berror);
341 static int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
342 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
345 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
348 r = sd_bus_message_new_method_return(call, &m);
352 if (!isempty(types)) {
356 r = bus_message_append_ap(m, types, ap);
362 return synthetic_driver_send(call->bus, m);
365 static int synthetic_reply_return_strv(sd_bus_message *call, char **l) {
366 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
369 r = sd_bus_message_new_method_return(call, &m);
371 return synthetic_reply_method_errno(call, r, NULL);
373 r = sd_bus_message_append_strv(m, l);
375 return synthetic_reply_method_errno(call, r, NULL);
377 return synthetic_driver_send(call->bus, m);
380 static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
381 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
388 assert_return(service_name_is_valid(name), -EINVAL);
390 r = sd_bus_get_owner(bus, name, mask, &c);
391 if (r == -ESRCH || r == -ENXIO)
392 return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
396 if ((c->mask & mask) != mask)
405 static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
413 r = sd_bus_message_read(m, "s", &name);
417 return get_creds_by_name(bus, name, mask, _creds, error);
420 static int peer_is_privileged(sd_bus *bus, sd_bus_message *m) {
421 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
425 r = get_creds_by_message(bus, m, SD_BUS_CREDS_UID, &creds, NULL);
429 r = sd_bus_creds_get_uid(creds, &uid);
433 r = sd_bus_creds_has_effective_cap(creds, CAP_SYS_ADMIN);
444 static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
451 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
454 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
455 if (0 && !isempty(sd_bus_message_get_signature(m, true))) {
456 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
458 r = sd_bus_error_setf(&error, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
460 return synthetic_reply_method_errno(m, r, &error);
463 return synthetic_reply_method_return(m, "s",
464 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
465 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
467 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
468 " <method name=\"Introspect\">\n"
469 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
472 " <interface name=\"org.freedesktop.DBus\">\n"
473 " <method name=\"AddMatch\">\n"
474 " <arg type=\"s\" direction=\"in\"/>\n"
476 " <method name=\"RemoveMatch\">\n"
477 " <arg type=\"s\" direction=\"in\"/>\n"
479 " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
480 " <arg type=\"s\" direction=\"in\"/>\n"
481 " <arg type=\"ay\" direction=\"out\"/>\n"
483 " <method name=\"GetConnectionUnixProcessID\">\n"
484 " <arg type=\"s\" direction=\"in\"/>\n"
485 " <arg type=\"u\" direction=\"out\"/>\n"
487 " <method name=\"GetConnectionUnixUser\">\n"
488 " <arg type=\"s\" direction=\"in\"/>\n"
489 " <arg type=\"u\" direction=\"out\"/>\n"
491 " <method name=\"GetId\">\n"
492 " <arg type=\"s\" direction=\"out\"/>\n"
494 " <method name=\"GetNameOwner\">\n"
495 " <arg type=\"s\" direction=\"in\"/>\n"
496 " <arg type=\"s\" direction=\"out\"/>\n"
498 " <method name=\"Hello\">\n"
499 " <arg type=\"s\" direction=\"out\"/>\n"
501 " <method name=\"ListActivatableNames\">\n"
502 " <arg type=\"as\" direction=\"out\"/>\n"
504 " <method name=\"ListNames\">\n"
505 " <arg type=\"as\" direction=\"out\"/>\n"
507 " <method name=\"ListQueuedOwners\">\n"
508 " <arg type=\"s\" direction=\"in\"/>\n"
509 " <arg type=\"as\" direction=\"out\"/>\n"
511 " <method name=\"NameHasOwner\">\n"
512 " <arg type=\"s\" direction=\"in\"/>\n"
513 " <arg type=\"b\" direction=\"out\"/>\n"
515 " <method name=\"ReleaseName\">\n"
516 " <arg type=\"s\" direction=\"in\"/>\n"
517 " <arg type=\"u\" direction=\"out\"/>\n"
519 " <method name=\"ReloadConfig\">\n"
521 " <method name=\"RequestName\">\n"
522 " <arg type=\"s\" direction=\"in\"/>\n"
523 " <arg type=\"u\" direction=\"in\"/>\n"
524 " <arg type=\"u\" direction=\"out\"/>\n"
526 " <method name=\"StartServiceByName\">\n"
527 " <arg type=\"s\" direction=\"in\"/>\n"
528 " <arg type=\"u\" direction=\"in\"/>\n"
529 " <arg type=\"u\" direction=\"out\"/>\n"
531 " <method name=\"UpdateActivationEnvironment\">\n"
532 " <arg type=\"a{ss}\" direction=\"in\"/>\n"
534 " <signal name=\"NameAcquired\">\n"
535 " <arg type=\"s\"/>\n"
537 " <signal name=\"NameLost\">\n"
538 " <arg type=\"s\"/>\n"
540 " <signal name=\"NameOwnerChanged\">\n"
541 " <arg type=\"s\"/>\n"
542 " <arg type=\"s\"/>\n"
543 " <arg type=\"s\"/>\n"
548 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
551 r = sd_bus_message_read(m, "s", &match);
553 return synthetic_reply_method_errno(m, r, NULL);
555 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
557 return synthetic_reply_method_errno(m, r, NULL);
559 return synthetic_reply_method_return(m, NULL);
561 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
564 r = sd_bus_message_read(m, "s", &match);
566 return synthetic_reply_method_errno(m, r, NULL);
568 r = bus_remove_match_by_string(a, match, NULL, NULL);
570 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
572 return synthetic_reply_method_errno(m, r, NULL);
574 return synthetic_reply_method_return(m, NULL);
576 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
577 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
579 r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, NULL);
581 return synthetic_reply_method_errno(m, r, NULL);
583 return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
585 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
586 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
588 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, NULL);
590 return synthetic_reply_method_errno(m, r, NULL);
592 return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
594 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
595 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
597 r = get_creds_by_message(a, m, SD_BUS_CREDS_UID, &creds, NULL);
599 return synthetic_reply_method_errno(m, r, NULL);
601 return synthetic_reply_method_return(m, "u", (uint32_t) creds->uid);
603 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
604 sd_id128_t server_id;
605 char buf[SD_ID128_STRING_MAX];
607 r = sd_bus_get_server_id(a, &server_id);
609 return synthetic_reply_method_errno(m, r, NULL);
611 return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
613 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
615 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
616 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
618 r = sd_bus_message_read(m, "s", &name);
620 return synthetic_reply_method_errno(m, r, NULL);
622 if (streq(name, "org.freedesktop.DBus"))
623 return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
625 r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
627 return synthetic_reply_method_errno(m, r, &error);
629 return synthetic_reply_method_return(m, "s", creds->unique_name);
631 /* "Hello" is handled in process_hello() */
633 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
634 _cleanup_strv_free_ char **names = NULL;
636 r = sd_bus_list_names(a, NULL, &names);
638 return synthetic_reply_method_errno(m, r, NULL);
640 /* Let's sort the names list to make it stable */
643 return synthetic_reply_return_strv(m, names);
645 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
646 _cleanup_strv_free_ char **names = NULL;
648 r = sd_bus_list_names(a, &names, NULL);
650 return synthetic_reply_method_errno(m, r, NULL);
652 r = strv_extend(&names, "org.freedesktop.DBus");
654 return synthetic_reply_method_errno(m, r, NULL);
656 /* Let's sort the names list to make it stable */
659 return synthetic_reply_return_strv(m, names);
661 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
662 struct kdbus_cmd_name_list cmd = {};
663 struct kdbus_name_list *name_list;
664 struct kdbus_cmd_name *name;
665 _cleanup_strv_free_ char **owners = NULL;
669 r = sd_bus_message_read(m, "s", &arg0);
671 return synthetic_reply_method_errno(m, r, NULL);
673 if (service_name_is_valid(arg0) < 0)
674 return synthetic_reply_method_errno(m, -EINVAL, NULL);
676 cmd.flags = KDBUS_NAME_LIST_QUEUED;
677 r = ioctl(a->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
679 return synthetic_reply_method_errno(m, -errno, NULL);
681 name_list = (struct kdbus_name_list *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
683 KDBUS_ITEM_FOREACH(name, name_list, names) {
686 if (name->size <= sizeof(*name))
689 if (!streq(name->name, arg0))
692 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
697 r = strv_consume(&owners, n);
704 r = ioctl(a->input_fd, KDBUS_CMD_FREE, &cmd.offset);
706 return synthetic_reply_method_errno(m, r, NULL);
709 return synthetic_reply_method_errno(m, err, NULL);
711 return synthetic_reply_return_strv(m, owners);
713 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
716 r = sd_bus_message_read(m, "s", &name);
718 return synthetic_reply_method_errno(m, r, NULL);
720 if (service_name_is_valid(name) < 0)
721 return synthetic_reply_method_errno(m, -EINVAL, NULL);
723 if (streq(name, "org.freedesktop.DBus"))
724 return synthetic_reply_method_return(m, "b", true);
726 r = sd_bus_get_owner(a, name, 0, NULL);
727 if (r < 0 && r != -ESRCH && r != -ENXIO)
728 return synthetic_reply_method_errno(m, r, NULL);
730 return synthetic_reply_method_return(m, "b", r >= 0);
732 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
735 r = sd_bus_message_read(m, "s", &name);
737 return synthetic_reply_method_errno(m, r, NULL);
739 if (service_name_is_valid(name) < 0)
740 return synthetic_reply_method_errno(m, -EINVAL, NULL);
742 r = sd_bus_release_name(a, name);
745 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
746 if (r == -EADDRINUSE)
747 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
749 return synthetic_reply_method_errno(m, r, NULL);
752 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
754 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
755 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
757 r = sd_bus_error_setf(&error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
759 return synthetic_reply_method_errno(m, r, &error);
761 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
765 r = sd_bus_message_read(m, "su", &name, &flags);
767 return synthetic_reply_method_errno(m, r, NULL);
769 if (service_name_is_valid(name) < 0)
770 return synthetic_reply_method_errno(m, -EINVAL, NULL);
771 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
772 return synthetic_reply_method_errno(m, -EINVAL, NULL);
774 r = sd_bus_request_name(a, name, flags);
777 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
779 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
780 return synthetic_reply_method_errno(m, r, NULL);
784 return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
786 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
788 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
789 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
793 r = sd_bus_message_read(m, "su", &name, &flags);
795 return synthetic_reply_method_errno(m, r, NULL);
797 if (service_name_is_valid(name) < 0)
798 return synthetic_reply_method_errno(m, -EINVAL, NULL);
800 return synthetic_reply_method_errno(m, -EINVAL, NULL);
802 r = sd_bus_get_owner(a, name, 0, NULL);
803 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
804 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
806 return synthetic_reply_method_errno(m, r, NULL);
808 r = sd_bus_message_new_method_call(
813 "org.freedesktop.DBus.Peer",
816 return synthetic_reply_method_errno(m, r, NULL);
818 r = sd_bus_send(a, msg, NULL);
820 return synthetic_reply_method_errno(m, r, NULL);
822 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
824 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
825 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
826 _cleanup_strv_free_ char **args = NULL;
828 if (!peer_is_privileged(a, m))
829 return synthetic_reply_method_errno(m, -EPERM, NULL);
831 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
833 return synthetic_reply_method_errno(m, r, NULL);
835 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
836 _cleanup_free_ char *s = NULL;
840 r = sd_bus_message_read(m, "ss", &key, &value);
842 return synthetic_reply_method_errno(m, r, NULL);
844 s = strjoin(key, "=", value, NULL);
846 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
848 r = strv_extend(&args, s);
850 return synthetic_reply_method_errno(m, r, NULL);
852 r = sd_bus_message_exit_container(m);
854 return synthetic_reply_method_errno(m, r, NULL);
857 r = sd_bus_message_exit_container(m);
859 return synthetic_reply_method_errno(m, r, NULL);
862 return synthetic_reply_method_errno(m, -EINVAL, NULL);
864 r = sd_bus_message_new_method_call(
867 "org.freedesktop.systemd1",
868 "/org/freedesktop/systemd1",
869 "org.freedesktop.systemd1.Manager",
872 return synthetic_reply_method_errno(m, r, NULL);
874 r = sd_bus_message_append_strv(msg, args);
876 return synthetic_reply_method_errno(m, r, NULL);
878 r = sd_bus_call(a, msg, 0, NULL, NULL);
880 return synthetic_reply_method_errno(m, r, NULL);
882 return synthetic_reply_method_return(m, NULL);
885 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
887 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
889 return synthetic_reply_method_errno(m, r, &error);
893 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
894 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
903 /* As reaction to hello we need to respond with two messages:
904 * the callback reply and the NameAcquired for the unique
905 * name, since hello is otherwise obsolete on kdbus. */
908 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
909 streq_ptr(m->destination, "org.freedesktop.DBus");
916 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
921 log_error("Got duplicate hello, aborting.");
930 r = sd_bus_message_new_method_return(m, &n);
932 log_error("Failed to generate HELLO reply: %s", strerror(-r));
936 r = sd_bus_message_append(n, "s", a->unique_name);
938 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
942 r = bus_message_append_sender(n, "org.freedesktop.DBus");
944 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
948 r = bus_seal_synthetic_message(b, n);
950 log_error("Failed to seal HELLO reply: %s", strerror(-r));
954 r = sd_bus_send(b, n, NULL);
956 log_error("Failed to send HELLO reply: %s", strerror(-r));
960 n = sd_bus_message_unref(n);
961 r = sd_bus_message_new_signal(
964 "/org/freedesktop/DBus",
965 "org.freedesktop.DBus",
968 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
972 r = sd_bus_message_append(n, "s", a->unique_name);
974 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
978 r = bus_message_append_sender(n, "org.freedesktop.DBus");
980 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
984 r = bus_seal_synthetic_message(b, n);
986 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
990 r = sd_bus_send(b, n, NULL);
992 log_error("Failed to send NameAcquired message: %s", strerror(-r));
999 static int patch_sender(sd_bus *a, sd_bus_message *m) {
1000 char **well_known = NULL;
1010 /* We will change the sender of messages from the bus driver
1011 * so that they originate from the bus driver. This is a
1012 * speciality originating from dbus1, where the bus driver did
1013 * not have a unique id, but only the well-known name. */
1015 c = sd_bus_message_get_creds(m);
1019 r = sd_bus_creds_get_well_known_names(c, &well_known);
1023 if (strv_contains(well_known, "org.freedesktop.DBus"))
1024 m->sender = "org.freedesktop.DBus";
1029 int main(int argc, char *argv[]) {
1031 _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
1032 sd_id128_t server_id;
1033 int r, in_fd, out_fd;
1034 bool got_hello = false;
1036 struct ucred ucred = {};
1037 _cleanup_free_ char *peersec = NULL;
1039 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
1040 log_parse_environment();
1043 r = parse_argv(argc, argv);
1047 r = sd_listen_fds(0);
1049 in_fd = STDIN_FILENO;
1050 out_fd = STDOUT_FILENO;
1051 } else if (r == 1) {
1052 in_fd = SD_LISTEN_FDS_START;
1053 out_fd = SD_LISTEN_FDS_START;
1055 log_error("Illegal number of file descriptors passed");
1060 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
1061 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
1064 getpeercred(in_fd, &ucred);
1065 getpeersec(in_fd, &peersec);
1070 log_error("Failed to allocate bus: %s", strerror(-r));
1074 r = sd_bus_set_name(a, "sd-proxy");
1076 log_error("Failed to set bus name: %s", strerror(-r));
1080 r = sd_bus_set_address(a, arg_address);
1082 log_error("Failed to set address to connect to: %s", strerror(-r));
1086 r = sd_bus_negotiate_fds(a, is_unix);
1088 log_error("Failed to set FD negotiation: %s", strerror(-r));
1092 if (ucred.pid > 0) {
1093 a->fake_creds.pid = ucred.pid;
1094 a->fake_creds.uid = ucred.uid;
1095 a->fake_creds.gid = ucred.gid;
1096 a->fake_creds_valid = true;
1100 a->fake_label = peersec;
1104 a->manual_peer_interface = true;
1106 r = sd_bus_start(a);
1108 log_error("Failed to start bus client: %s", strerror(-r));
1112 r = sd_bus_get_server_id(a, &server_id);
1114 log_error("Failed to get server ID: %s", strerror(-r));
1120 log_error("Failed to allocate bus: %s", strerror(-r));
1124 r = sd_bus_set_fd(b, in_fd, out_fd);
1126 log_error("Failed to set fds: %s", strerror(-r));
1130 r = sd_bus_set_server(b, 1, server_id);
1132 log_error("Failed to set server mode: %s", strerror(-r));
1136 r = sd_bus_negotiate_fds(b, is_unix);
1138 log_error("Failed to set FD negotiation: %s", strerror(-r));
1142 r = sd_bus_set_anonymous(b, true);
1144 log_error("Failed to set anonymous authentication: %s", strerror(-r));
1148 b->manual_peer_interface = true;
1150 r = sd_bus_start(b);
1152 log_error("Failed to start bus client: %s", strerror(-r));
1156 r = rename_service(a, b);
1158 log_debug("Failed to rename process: %s", strerror(-r));
1161 _cleanup_free_ char *match = NULL;
1164 r = sd_bus_get_unique_name(a, &unique);
1166 log_error("Failed to get unique name: %s", strerror(-r));
1170 match = strjoin("type='signal',"
1171 "sender='org.freedesktop.DBus',"
1172 "path='/org/freedesktop/DBus',"
1173 "interface='org.freedesktop.DBus',"
1174 "member='NameOwnerChanged',"
1184 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1186 log_error("Failed to add match for NameLost: %s", strerror(-r));
1191 match = strjoin("type='signal',"
1192 "sender='org.freedesktop.DBus',"
1193 "path='/org/freedesktop/DBus',"
1194 "interface='org.freedesktop.DBus',"
1195 "member='NameOwnerChanged',"
1205 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1207 log_error("Failed to add match for NameAcquired: %s", strerror(-r));
1213 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1214 int events_a, events_b, fd;
1215 uint64_t timeout_a, timeout_b, t;
1216 struct timespec _ts, *ts;
1217 struct pollfd *pollfd;
1221 r = sd_bus_process(a, &m);
1223 /* treat 'connection reset by peer' as clean exit condition */
1224 if (r == -ECONNRESET)
1227 log_error("Failed to process bus a: %s", strerror(-r));
1233 /* We officially got EOF, let's quit */
1234 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1239 k = synthesize_name_acquired(a, b, m);
1242 log_error("Failed to synthesize message: %s", strerror(-r));
1248 k = sd_bus_send(b, m, NULL);
1250 if (k == -ECONNRESET)
1254 log_error("Failed to send message: %s", strerror(-r));
1265 r = sd_bus_process(b, &m);
1267 /* treat 'connection reset by peer' as clean exit condition */
1268 if (r == -ECONNRESET)
1271 log_error("Failed to process bus b: %s", strerror(-r));
1277 /* We officially got EOF, let's quit */
1278 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1283 k = process_hello(a, b, m, &got_hello);
1286 log_error("Failed to process HELLO: %s", strerror(-r));
1293 k = process_policy(a, b, m);
1296 log_error("Failed to process policy: %s", strerror(-r));
1300 k = process_driver(a, b, m);
1303 log_error("Failed to process driver calls: %s", strerror(-r));
1310 k = sd_bus_send(a, m, NULL);
1312 if (r == -ECONNRESET)
1316 log_error("Failed to send message: %s", strerror(-r));
1328 fd = sd_bus_get_fd(a);
1330 log_error("Failed to get fd: %s", strerror(-r));
1334 events_a = sd_bus_get_events(a);
1336 log_error("Failed to get events mask: %s", strerror(-r));
1340 r = sd_bus_get_timeout(a, &timeout_a);
1342 log_error("Failed to get timeout: %s", strerror(-r));
1346 events_b = sd_bus_get_events(b);
1348 log_error("Failed to get events mask: %s", strerror(-r));
1352 r = sd_bus_get_timeout(b, &timeout_b);
1354 log_error("Failed to get timeout: %s", strerror(-r));
1359 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
1362 if (t == (uint64_t) -1)
1367 nw = now(CLOCK_MONOTONIC);
1373 ts = timespec_store(&_ts, t);
1376 pollfd = (struct pollfd[3]) {
1377 {.fd = fd, .events = events_a, },
1378 {.fd = in_fd, .events = events_b & POLLIN, },
1379 {.fd = out_fd, .events = events_b & POLLOUT, }
1382 r = ppoll(pollfd, 3, ts, NULL);
1384 log_error("ppoll() failed: %m");
1393 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;