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"
47 #include "capability.h"
49 static const char *arg_address = DEFAULT_SYSTEM_BUS_PATH;
50 static char *arg_command_line_buffer = NULL;
51 static bool arg_drop_privileges = false;
53 static int help(void) {
55 printf("%s [OPTIONS...]\n\n"
56 "Connect STDIO or a socket to a given bus address.\n\n"
57 " -h --help Show this help\n"
58 " --version Show package version\n"
59 " --drop-privileges Drop privileges\n"
60 " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
61 " (default: " DEFAULT_SYSTEM_BUS_PATH ")\n",
62 program_invocation_short_name);
67 static int parse_argv(int argc, char *argv[]) {
75 static const struct option options[] = {
76 { "help", no_argument, NULL, 'h' },
77 { "version", no_argument, NULL, ARG_VERSION },
78 { "address", required_argument, NULL, ARG_ADDRESS },
79 { "drop-privileges", no_argument, NULL, ARG_DROP_PRIVILEGES },
88 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
98 puts(SYSTEMD_FEATURES);
102 arg_address = optarg;
105 case ARG_DROP_PRIVILEGES:
106 arg_drop_privileges = true;
113 assert_not_reached("Unhandled option");
117 /* If the first command line argument is only "x" characters
118 * we'll write who we are talking to into it, so that "ps" is
120 arg_command_line_buffer = argv[optind];
121 if (argc > optind + 1 ||
122 (arg_command_line_buffer && arg_command_line_buffer[strspn(arg_command_line_buffer, "x")] != 0)) {
123 log_error("Too many arguments");
130 static int rename_service(sd_bus *a, sd_bus *b) {
131 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
132 _cleanup_free_ char *p = NULL, *name = NULL;
142 r = sd_bus_get_peer_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM, &creds);
146 r = sd_bus_creds_get_uid(creds, &uid);
150 r = sd_bus_creds_get_pid(creds, &pid);
154 r = sd_bus_creds_get_cmdline(creds, &cmdline);
158 r = sd_bus_creds_get_comm(creds, &comm);
162 name = uid_to_name(uid);
166 p = strv_join(cmdline, " ");
170 /* The status string gets the full command line ... */
172 "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
176 /* ... and the argv line only the short comm */
177 if (arg_command_line_buffer) {
180 m = strlen(arg_command_line_buffer);
181 w = snprintf(arg_command_line_buffer, m,
182 "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
187 memzero(arg_command_line_buffer + w, m - w);
190 log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
198 static int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
199 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
200 const char *name, *old_owner, *new_owner;
207 /* If we get NameOwnerChanged for our own name, we need to
208 * synthesize NameLost/NameAcquired, since socket clients need
209 * that, even though it is obsoleted on kdbus */
214 if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
215 !streq_ptr(m->path, "/org/freedesktop/DBus") ||
216 !streq_ptr(m->sender, "org.freedesktop.DBus"))
219 r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
223 r = sd_bus_message_rewind(m, true);
227 if (streq(old_owner, a->unique_name)) {
229 r = sd_bus_message_new_signal(
232 "/org/freedesktop/DBus",
233 "org.freedesktop.DBus",
236 } else if (streq(new_owner, a->unique_name)) {
238 r = sd_bus_message_new_signal(
241 "/org/freedesktop/DBus",
242 "org.freedesktop.DBus",
250 r = sd_bus_message_append(n, "s", name);
254 r = bus_message_append_sender(n, "org.freedesktop.DBus");
258 r = bus_seal_synthetic_message(b, n);
262 return sd_bus_send(b, n, NULL);
265 static int process_policy(sd_bus *a, sd_bus *b, sd_bus_message *m) {
266 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
273 if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll"))
276 if (!streq_ptr(m->path, "/org/gnome/DisplayManager/Slave"))
279 r = sd_bus_message_new_method_errorf(m, &n, SD_BUS_ERROR_ACCESS_DENIED, "gdm, you are stupid");
283 r = bus_message_append_sender(n, "org.freedesktop.DBus");
285 log_error("Failed to append sender to gdm reply: %s", strerror(-r));
289 r = bus_seal_synthetic_message(b, n);
291 log_error("Failed to seal gdm reply: %s", strerror(-r));
295 r = sd_bus_send(b, n, NULL);
297 log_error("Failed to send gdm reply: %s", strerror(-r));
304 static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
310 r = bus_message_append_sender(m, "org.freedesktop.DBus");
314 r = bus_seal_synthetic_message(b, m);
318 return sd_bus_send(b, m, NULL);
321 static int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
322 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
325 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
328 r = sd_bus_message_new_method_error(call, &m, e);
332 return synthetic_driver_send(call->bus, m);
335 static int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
337 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
339 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
342 if (sd_bus_error_is_set(p))
343 return synthetic_reply_method_error(call, p);
345 sd_bus_error_set_errno(&berror, error);
347 return synthetic_reply_method_error(call, &berror);
350 static int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
351 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
354 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
357 r = sd_bus_message_new_method_return(call, &m);
361 if (!isempty(types)) {
365 r = bus_message_append_ap(m, types, ap);
371 return synthetic_driver_send(call->bus, m);
374 static int synthetic_reply_return_strv(sd_bus_message *call, char **l) {
375 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
378 r = sd_bus_message_new_method_return(call, &m);
380 return synthetic_reply_method_errno(call, r, NULL);
382 r = sd_bus_message_append_strv(m, l);
384 return synthetic_reply_method_errno(call, r, NULL);
386 return synthetic_driver_send(call->bus, m);
389 static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
390 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
397 assert_return(service_name_is_valid(name), -EINVAL);
399 r = sd_bus_get_owner(bus, name, mask, &c);
400 if (r == -ESRCH || r == -ENXIO)
401 return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
405 if ((c->mask & mask) != mask)
414 static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
422 r = sd_bus_message_read(m, "s", &name);
426 return get_creds_by_name(bus, name, mask, _creds, error);
429 static int peer_is_privileged(sd_bus *bus, sd_bus_message *m) {
430 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
434 r = get_creds_by_message(bus, m, SD_BUS_CREDS_UID, &creds, NULL);
438 r = sd_bus_creds_get_uid(creds, &uid);
442 r = sd_bus_creds_has_effective_cap(creds, CAP_SYS_ADMIN);
452 static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
459 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
462 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
463 if (0 && !isempty(sd_bus_message_get_signature(m, true))) {
464 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
466 r = sd_bus_error_setf(&error, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
468 return synthetic_reply_method_errno(m, r, &error);
471 return synthetic_reply_method_return(m, "s",
472 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
473 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
475 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
476 " <method name=\"Introspect\">\n"
477 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
480 " <interface name=\"org.freedesktop.DBus\">\n"
481 " <method name=\"AddMatch\">\n"
482 " <arg type=\"s\" direction=\"in\"/>\n"
484 " <method name=\"RemoveMatch\">\n"
485 " <arg type=\"s\" direction=\"in\"/>\n"
487 " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
488 " <arg type=\"s\" direction=\"in\"/>\n"
489 " <arg type=\"ay\" direction=\"out\"/>\n"
491 " <method name=\"GetConnectionUnixProcessID\">\n"
492 " <arg type=\"s\" direction=\"in\"/>\n"
493 " <arg type=\"u\" direction=\"out\"/>\n"
495 " <method name=\"GetConnectionUnixUser\">\n"
496 " <arg type=\"s\" direction=\"in\"/>\n"
497 " <arg type=\"u\" direction=\"out\"/>\n"
499 " <method name=\"GetId\">\n"
500 " <arg type=\"s\" direction=\"out\"/>\n"
502 " <method name=\"GetNameOwner\">\n"
503 " <arg type=\"s\" direction=\"in\"/>\n"
504 " <arg type=\"s\" direction=\"out\"/>\n"
506 " <method name=\"Hello\">\n"
507 " <arg type=\"s\" direction=\"out\"/>\n"
509 " <method name=\"ListActivatableNames\">\n"
510 " <arg type=\"as\" direction=\"out\"/>\n"
512 " <method name=\"ListNames\">\n"
513 " <arg type=\"as\" direction=\"out\"/>\n"
515 " <method name=\"ListQueuedOwners\">\n"
516 " <arg type=\"s\" direction=\"in\"/>\n"
517 " <arg type=\"as\" direction=\"out\"/>\n"
519 " <method name=\"NameHasOwner\">\n"
520 " <arg type=\"s\" direction=\"in\"/>\n"
521 " <arg type=\"b\" direction=\"out\"/>\n"
523 " <method name=\"ReleaseName\">\n"
524 " <arg type=\"s\" direction=\"in\"/>\n"
525 " <arg type=\"u\" direction=\"out\"/>\n"
527 " <method name=\"ReloadConfig\">\n"
529 " <method name=\"RequestName\">\n"
530 " <arg type=\"s\" direction=\"in\"/>\n"
531 " <arg type=\"u\" direction=\"in\"/>\n"
532 " <arg type=\"u\" direction=\"out\"/>\n"
534 " <method name=\"StartServiceByName\">\n"
535 " <arg type=\"s\" direction=\"in\"/>\n"
536 " <arg type=\"u\" direction=\"in\"/>\n"
537 " <arg type=\"u\" direction=\"out\"/>\n"
539 " <method name=\"UpdateActivationEnvironment\">\n"
540 " <arg type=\"a{ss}\" direction=\"in\"/>\n"
542 " <signal name=\"NameAcquired\">\n"
543 " <arg type=\"s\"/>\n"
545 " <signal name=\"NameLost\">\n"
546 " <arg type=\"s\"/>\n"
548 " <signal name=\"NameOwnerChanged\">\n"
549 " <arg type=\"s\"/>\n"
550 " <arg type=\"s\"/>\n"
551 " <arg type=\"s\"/>\n"
556 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
559 r = sd_bus_message_read(m, "s", &match);
561 return synthetic_reply_method_errno(m, r, NULL);
563 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
565 return synthetic_reply_method_errno(m, r, NULL);
567 return synthetic_reply_method_return(m, NULL);
569 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
572 r = sd_bus_message_read(m, "s", &match);
574 return synthetic_reply_method_errno(m, r, NULL);
576 r = bus_remove_match_by_string(a, match, NULL, NULL);
578 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
580 return synthetic_reply_method_errno(m, r, NULL);
582 return synthetic_reply_method_return(m, NULL);
584 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
585 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
587 r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, NULL);
589 return synthetic_reply_method_errno(m, r, NULL);
591 return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
593 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
594 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
596 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, NULL);
598 return synthetic_reply_method_errno(m, r, NULL);
600 return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
602 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
603 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
605 r = get_creds_by_message(a, m, SD_BUS_CREDS_UID, &creds, NULL);
607 return synthetic_reply_method_errno(m, r, NULL);
609 return synthetic_reply_method_return(m, "u", (uint32_t) creds->uid);
611 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
612 sd_id128_t server_id;
613 char buf[SD_ID128_STRING_MAX];
615 r = sd_bus_get_server_id(a, &server_id);
617 return synthetic_reply_method_errno(m, r, NULL);
619 return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
621 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
623 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
624 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
626 r = sd_bus_message_read(m, "s", &name);
628 return synthetic_reply_method_errno(m, r, NULL);
630 if (streq(name, "org.freedesktop.DBus"))
631 return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
633 r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
635 return synthetic_reply_method_errno(m, r, &error);
637 return synthetic_reply_method_return(m, "s", creds->unique_name);
639 /* "Hello" is handled in process_hello() */
641 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
642 _cleanup_strv_free_ char **names = NULL;
644 r = sd_bus_list_names(a, NULL, &names);
646 return synthetic_reply_method_errno(m, r, NULL);
648 /* Let's sort the names list to make it stable */
651 return synthetic_reply_return_strv(m, names);
653 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
654 _cleanup_strv_free_ char **names = NULL;
656 r = sd_bus_list_names(a, &names, NULL);
658 return synthetic_reply_method_errno(m, r, NULL);
660 r = strv_extend(&names, "org.freedesktop.DBus");
662 return synthetic_reply_method_errno(m, r, NULL);
664 /* Let's sort the names list to make it stable */
667 return synthetic_reply_return_strv(m, names);
669 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
670 struct kdbus_cmd_name_list cmd = {};
671 struct kdbus_name_list *name_list;
672 struct kdbus_cmd_name *name;
673 _cleanup_strv_free_ char **owners = NULL;
677 r = sd_bus_message_read(m, "s", &arg0);
679 return synthetic_reply_method_errno(m, r, NULL);
681 if (service_name_is_valid(arg0) < 0)
682 return synthetic_reply_method_errno(m, -EINVAL, NULL);
684 cmd.flags = KDBUS_NAME_LIST_QUEUED;
685 r = ioctl(a->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
687 return synthetic_reply_method_errno(m, -errno, NULL);
689 name_list = (struct kdbus_name_list *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
691 KDBUS_ITEM_FOREACH(name, name_list, names) {
694 if (name->size <= sizeof(*name))
697 if (!streq(name->name, arg0))
700 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
705 r = strv_consume(&owners, n);
712 r = ioctl(a->input_fd, KDBUS_CMD_FREE, &cmd.offset);
714 return synthetic_reply_method_errno(m, r, NULL);
717 return synthetic_reply_method_errno(m, err, NULL);
719 return synthetic_reply_return_strv(m, owners);
721 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
724 r = sd_bus_message_read(m, "s", &name);
726 return synthetic_reply_method_errno(m, r, NULL);
728 if (service_name_is_valid(name) < 0)
729 return synthetic_reply_method_errno(m, -EINVAL, NULL);
731 if (streq(name, "org.freedesktop.DBus"))
732 return synthetic_reply_method_return(m, "b", true);
734 r = sd_bus_get_owner(a, name, 0, NULL);
735 if (r < 0 && r != -ESRCH && r != -ENXIO)
736 return synthetic_reply_method_errno(m, r, NULL);
738 return synthetic_reply_method_return(m, "b", r >= 0);
740 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
743 r = sd_bus_message_read(m, "s", &name);
745 return synthetic_reply_method_errno(m, r, NULL);
747 if (service_name_is_valid(name) < 0)
748 return synthetic_reply_method_errno(m, -EINVAL, NULL);
750 r = sd_bus_release_name(a, name);
753 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
754 if (r == -EADDRINUSE)
755 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
757 return synthetic_reply_method_errno(m, r, NULL);
760 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
762 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
763 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
765 r = sd_bus_error_setf(&error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
767 return synthetic_reply_method_errno(m, r, &error);
769 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
773 r = sd_bus_message_read(m, "su", &name, &flags);
775 return synthetic_reply_method_errno(m, r, NULL);
777 if (service_name_is_valid(name) < 0)
778 return synthetic_reply_method_errno(m, -EINVAL, NULL);
779 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
780 return synthetic_reply_method_errno(m, -EINVAL, NULL);
782 r = sd_bus_request_name(a, name, flags);
785 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
787 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
788 return synthetic_reply_method_errno(m, r, NULL);
792 return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
794 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
796 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
797 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
801 r = sd_bus_message_read(m, "su", &name, &flags);
803 return synthetic_reply_method_errno(m, r, NULL);
805 if (service_name_is_valid(name) < 0)
806 return synthetic_reply_method_errno(m, -EINVAL, NULL);
808 return synthetic_reply_method_errno(m, -EINVAL, NULL);
810 r = sd_bus_get_owner(a, name, 0, NULL);
811 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
812 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
814 return synthetic_reply_method_errno(m, r, NULL);
816 r = sd_bus_message_new_method_call(
821 "org.freedesktop.DBus.Peer",
824 return synthetic_reply_method_errno(m, r, NULL);
826 r = sd_bus_send(a, msg, NULL);
828 return synthetic_reply_method_errno(m, r, NULL);
830 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
832 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
833 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
834 _cleanup_strv_free_ char **args = NULL;
836 if (!peer_is_privileged(a, m))
837 return synthetic_reply_method_errno(m, -EPERM, NULL);
839 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
841 return synthetic_reply_method_errno(m, r, NULL);
843 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
844 _cleanup_free_ char *s = NULL;
848 r = sd_bus_message_read(m, "ss", &key, &value);
850 return synthetic_reply_method_errno(m, r, NULL);
852 s = strjoin(key, "=", value, NULL);
854 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
856 r = strv_extend(&args, s);
858 return synthetic_reply_method_errno(m, r, NULL);
860 r = sd_bus_message_exit_container(m);
862 return synthetic_reply_method_errno(m, r, NULL);
865 r = sd_bus_message_exit_container(m);
867 return synthetic_reply_method_errno(m, r, NULL);
870 return synthetic_reply_method_errno(m, -EINVAL, NULL);
872 r = sd_bus_message_new_method_call(
875 "org.freedesktop.systemd1",
876 "/org/freedesktop/systemd1",
877 "org.freedesktop.systemd1.Manager",
880 return synthetic_reply_method_errno(m, r, NULL);
882 r = sd_bus_message_append_strv(msg, args);
884 return synthetic_reply_method_errno(m, r, NULL);
886 r = sd_bus_call(a, msg, 0, NULL, NULL);
888 return synthetic_reply_method_errno(m, r, NULL);
890 return synthetic_reply_method_return(m, NULL);
893 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
895 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
897 return synthetic_reply_method_errno(m, r, &error);
901 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
902 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
911 /* As reaction to hello we need to respond with two messages:
912 * the callback reply and the NameAcquired for the unique
913 * name, since hello is otherwise obsolete on kdbus. */
916 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
917 streq_ptr(m->destination, "org.freedesktop.DBus");
924 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
929 log_error("Got duplicate hello, aborting.");
938 r = sd_bus_message_new_method_return(m, &n);
940 log_error("Failed to generate HELLO reply: %s", strerror(-r));
944 r = sd_bus_message_append(n, "s", a->unique_name);
946 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
950 r = bus_message_append_sender(n, "org.freedesktop.DBus");
952 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
956 r = bus_seal_synthetic_message(b, n);
958 log_error("Failed to seal HELLO reply: %s", strerror(-r));
962 r = sd_bus_send(b, n, NULL);
964 log_error("Failed to send HELLO reply: %s", strerror(-r));
968 n = sd_bus_message_unref(n);
969 r = sd_bus_message_new_signal(
972 "/org/freedesktop/DBus",
973 "org.freedesktop.DBus",
976 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
980 r = sd_bus_message_append(n, "s", a->unique_name);
982 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
986 r = bus_message_append_sender(n, "org.freedesktop.DBus");
988 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
992 r = bus_seal_synthetic_message(b, n);
994 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
998 r = sd_bus_send(b, n, NULL);
1000 log_error("Failed to send NameAcquired message: %s", strerror(-r));
1007 static int patch_sender(sd_bus *a, sd_bus_message *m) {
1008 char **well_known = NULL;
1018 /* We will change the sender of messages from the bus driver
1019 * so that they originate from the bus driver. This is a
1020 * speciality originating from dbus1, where the bus driver did
1021 * not have a unique id, but only the well-known name. */
1023 c = sd_bus_message_get_creds(m);
1027 r = sd_bus_creds_get_well_known_names(c, &well_known);
1031 if (strv_contains(well_known, "org.freedesktop.DBus"))
1032 m->sender = "org.freedesktop.DBus";
1037 int main(int argc, char *argv[]) {
1039 _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
1040 sd_id128_t server_id;
1041 int r, in_fd, out_fd;
1042 bool got_hello = false;
1044 struct ucred ucred = {};
1045 _cleanup_free_ char *peersec = NULL;
1047 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
1048 log_parse_environment();
1051 r = parse_argv(argc, argv);
1055 r = sd_listen_fds(0);
1057 in_fd = STDIN_FILENO;
1058 out_fd = STDOUT_FILENO;
1059 } else if (r == 1) {
1060 in_fd = SD_LISTEN_FDS_START;
1061 out_fd = SD_LISTEN_FDS_START;
1063 log_error("Illegal number of file descriptors passed");
1068 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
1069 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
1072 getpeercred(in_fd, &ucred);
1073 getpeersec(in_fd, &peersec);
1076 if (arg_drop_privileges) {
1077 const char *user = "systemd-bus-proxy";
1081 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
1083 log_error("Cannot resolve user name %s: %s", user, strerror(-r));
1087 r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
1094 log_error("Failed to allocate bus: %s", strerror(-r));
1098 r = sd_bus_set_name(a, "sd-proxy");
1100 log_error("Failed to set bus name: %s", strerror(-r));
1104 r = sd_bus_set_address(a, arg_address);
1106 log_error("Failed to set address to connect to: %s", strerror(-r));
1110 r = sd_bus_negotiate_fds(a, is_unix);
1112 log_error("Failed to set FD negotiation: %s", strerror(-r));
1116 if (ucred.pid > 0) {
1117 a->fake_creds.pid = ucred.pid;
1118 a->fake_creds.uid = ucred.uid;
1119 a->fake_creds.gid = ucred.gid;
1120 a->fake_creds_valid = true;
1124 a->fake_label = peersec;
1128 a->manual_peer_interface = true;
1130 r = sd_bus_start(a);
1132 log_error("Failed to start bus client: %s", strerror(-r));
1136 r = sd_bus_get_server_id(a, &server_id);
1138 log_error("Failed to get server ID: %s", strerror(-r));
1144 log_error("Failed to allocate bus: %s", strerror(-r));
1148 r = sd_bus_set_fd(b, in_fd, out_fd);
1150 log_error("Failed to set fds: %s", strerror(-r));
1154 r = sd_bus_set_server(b, 1, server_id);
1156 log_error("Failed to set server mode: %s", strerror(-r));
1160 r = sd_bus_negotiate_fds(b, is_unix);
1162 log_error("Failed to set FD negotiation: %s", strerror(-r));
1166 r = sd_bus_set_anonymous(b, true);
1168 log_error("Failed to set anonymous authentication: %s", strerror(-r));
1172 b->manual_peer_interface = true;
1174 r = sd_bus_start(b);
1176 log_error("Failed to start bus client: %s", strerror(-r));
1180 r = rename_service(a, b);
1182 log_debug("Failed to rename process: %s", strerror(-r));
1185 _cleanup_free_ char *match = NULL;
1188 r = sd_bus_get_unique_name(a, &unique);
1190 log_error("Failed to get unique name: %s", strerror(-r));
1194 match = strjoin("type='signal',"
1195 "sender='org.freedesktop.DBus',"
1196 "path='/org/freedesktop/DBus',"
1197 "interface='org.freedesktop.DBus',"
1198 "member='NameOwnerChanged',"
1208 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1210 log_error("Failed to add match for NameLost: %s", strerror(-r));
1215 match = strjoin("type='signal',"
1216 "sender='org.freedesktop.DBus',"
1217 "path='/org/freedesktop/DBus',"
1218 "interface='org.freedesktop.DBus',"
1219 "member='NameOwnerChanged',"
1229 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1231 log_error("Failed to add match for NameAcquired: %s", strerror(-r));
1237 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1238 int events_a, events_b, fd;
1239 uint64_t timeout_a, timeout_b, t;
1240 struct timespec _ts, *ts;
1241 struct pollfd *pollfd;
1245 r = sd_bus_process(a, &m);
1247 /* treat 'connection reset by peer' as clean exit condition */
1248 if (r == -ECONNRESET)
1251 log_error("Failed to process bus a: %s", strerror(-r));
1257 /* We officially got EOF, let's quit */
1258 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1263 k = synthesize_name_acquired(a, b, m);
1266 log_error("Failed to synthesize message: %s", strerror(-r));
1272 k = sd_bus_send(b, m, NULL);
1274 if (k == -ECONNRESET)
1278 log_error("Failed to send message: %s", strerror(-r));
1289 r = sd_bus_process(b, &m);
1291 /* treat 'connection reset by peer' as clean exit condition */
1292 if (r == -ECONNRESET)
1295 log_error("Failed to process bus b: %s", strerror(-r));
1301 /* We officially got EOF, let's quit */
1302 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1307 k = process_hello(a, b, m, &got_hello);
1310 log_error("Failed to process HELLO: %s", strerror(-r));
1317 k = process_policy(a, b, m);
1320 log_error("Failed to process policy: %s", strerror(-r));
1324 k = process_driver(a, b, m);
1327 log_error("Failed to process driver calls: %s", strerror(-r));
1334 k = sd_bus_send(a, m, NULL);
1336 if (r == -ECONNRESET)
1340 log_error("Failed to send message: %s", strerror(-r));
1352 fd = sd_bus_get_fd(a);
1354 log_error("Failed to get fd: %s", strerror(-r));
1358 events_a = sd_bus_get_events(a);
1360 log_error("Failed to get events mask: %s", strerror(-r));
1364 r = sd_bus_get_timeout(a, &timeout_a);
1366 log_error("Failed to get timeout: %s", strerror(-r));
1370 events_b = sd_bus_get_events(b);
1372 log_error("Failed to get events mask: %s", strerror(-r));
1376 r = sd_bus_get_timeout(b, &timeout_b);
1378 log_error("Failed to get timeout: %s", strerror(-r));
1383 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
1386 if (t == (uint64_t) -1)
1391 nw = now(CLOCK_MONOTONIC);
1397 ts = timespec_store(&_ts, t);
1400 pollfd = (struct pollfd[3]) {
1401 {.fd = fd, .events = events_a, },
1402 {.fd = in_fd, .events = events_b & POLLIN, },
1403 {.fd = out_fd, .events = events_b & POLLOUT, }
1406 r = ppoll(pollfd, 3, ts, NULL);
1408 log_error("ppoll() failed: %m");
1417 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;