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"
48 #include "bus-policy.h"
50 static const char *arg_address = DEFAULT_SYSTEM_BUS_PATH;
51 static char *arg_command_line_buffer = NULL;
52 static bool arg_drop_privileges = false;
53 static char **arg_configuration = NULL;
55 static int help(void) {
57 printf("%s [OPTIONS...]\n\n"
58 "Connect STDIO or a socket to a given bus address.\n\n"
59 " -h --help Show this help\n"
60 " --version Show package version\n"
61 " --drop-privileges Drop privileges\n"
62 " --configuration=PATH Configuration file or directory\n"
63 " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
64 " (default: " KERNEL_SYSTEM_BUS_PATH ")\n",
65 program_invocation_short_name);
70 static int parse_argv(int argc, char *argv[]) {
79 static const struct option options[] = {
80 { "help", no_argument, NULL, 'h' },
81 { "version", no_argument, NULL, ARG_VERSION },
82 { "address", required_argument, NULL, ARG_ADDRESS },
83 { "drop-privileges", no_argument, NULL, ARG_DROP_PRIVILEGES },
84 { "configuration", required_argument, NULL, ARG_CONFIGURATION },
93 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
102 puts(PACKAGE_STRING);
103 puts(SYSTEMD_FEATURES);
107 arg_address = optarg;
110 case ARG_DROP_PRIVILEGES:
111 arg_drop_privileges = true;
114 case ARG_CONFIGURATION:
115 r = strv_extend(&arg_configuration, optarg);
124 assert_not_reached("Unhandled option");
128 /* If the first command line argument is only "x" characters
129 * we'll write who we are talking to into it, so that "ps" is
131 arg_command_line_buffer = argv[optind];
132 if (argc > optind + 1 ||
133 (arg_command_line_buffer && arg_command_line_buffer[strspn(arg_command_line_buffer, "x")] != 0)) {
134 log_error("Too many arguments");
141 static int rename_service(sd_bus *a, sd_bus *b) {
142 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
143 _cleanup_free_ char *p = NULL, *name = NULL;
153 r = sd_bus_get_peer_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM, &creds);
157 r = sd_bus_creds_get_uid(creds, &uid);
161 r = sd_bus_creds_get_pid(creds, &pid);
165 r = sd_bus_creds_get_cmdline(creds, &cmdline);
169 r = sd_bus_creds_get_comm(creds, &comm);
173 name = uid_to_name(uid);
177 p = strv_join(cmdline, " ");
181 /* The status string gets the full command line ... */
183 "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
187 /* ... and the argv line only the short comm */
188 if (arg_command_line_buffer) {
191 m = strlen(arg_command_line_buffer);
192 w = snprintf(arg_command_line_buffer, m,
193 "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
198 memzero(arg_command_line_buffer + w, m - w);
201 log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
209 static int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
210 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
211 const char *name, *old_owner, *new_owner;
218 /* If we get NameOwnerChanged for our own name, we need to
219 * synthesize NameLost/NameAcquired, since socket clients need
220 * that, even though it is obsoleted on kdbus */
225 if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
226 !streq_ptr(m->path, "/org/freedesktop/DBus") ||
227 !streq_ptr(m->sender, "org.freedesktop.DBus"))
230 r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
234 r = sd_bus_message_rewind(m, true);
238 if (streq(old_owner, a->unique_name)) {
240 r = sd_bus_message_new_signal(
243 "/org/freedesktop/DBus",
244 "org.freedesktop.DBus",
247 } else if (streq(new_owner, a->unique_name)) {
249 r = sd_bus_message_new_signal(
252 "/org/freedesktop/DBus",
253 "org.freedesktop.DBus",
261 r = sd_bus_message_append(n, "s", name);
265 r = bus_message_append_sender(n, "org.freedesktop.DBus");
269 r = bus_seal_synthetic_message(b, n);
273 return sd_bus_send(b, n, NULL);
276 static int process_policy(sd_bus *a, sd_bus *b, sd_bus_message *m) {
277 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
287 if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll"))
290 if (!streq_ptr(m->path, "/org/gnome/DisplayManager/Slave"))
293 r = sd_bus_message_new_method_errorf(m, &n, SD_BUS_ERROR_ACCESS_DENIED, "gdm, you are stupid");
297 r = bus_message_append_sender(n, "org.freedesktop.DBus");
299 log_error("Failed to append sender to gdm reply: %s", strerror(-r));
303 r = bus_seal_synthetic_message(b, n);
305 log_error("Failed to seal gdm reply: %s", strerror(-r));
309 r = sd_bus_send(b, n, NULL);
311 log_error("Failed to send gdm reply: %s", strerror(-r));
318 static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
324 r = bus_message_append_sender(m, "org.freedesktop.DBus");
328 r = bus_seal_synthetic_message(b, m);
332 return sd_bus_send(b, m, NULL);
335 static int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
336 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
339 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
342 r = sd_bus_message_new_method_error(call, &m, e);
346 return synthetic_driver_send(call->bus, m);
349 static int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
351 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
353 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
356 if (sd_bus_error_is_set(p))
357 return synthetic_reply_method_error(call, p);
359 sd_bus_error_set_errno(&berror, error);
361 return synthetic_reply_method_error(call, &berror);
364 static int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
365 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
368 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
371 r = sd_bus_message_new_method_return(call, &m);
375 if (!isempty(types)) {
379 r = bus_message_append_ap(m, types, ap);
385 return synthetic_driver_send(call->bus, m);
388 static int synthetic_reply_return_strv(sd_bus_message *call, char **l) {
389 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
392 r = sd_bus_message_new_method_return(call, &m);
394 return synthetic_reply_method_errno(call, r, NULL);
396 r = sd_bus_message_append_strv(m, l);
398 return synthetic_reply_method_errno(call, r, NULL);
400 return synthetic_driver_send(call->bus, m);
403 static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
404 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
411 assert_return(service_name_is_valid(name), -EINVAL);
413 r = sd_bus_get_owner(bus, name, mask, &c);
414 if (r == -ESRCH || r == -ENXIO)
415 return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
419 if ((c->mask & mask) != mask)
428 static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
436 r = sd_bus_message_read(m, "s", &name);
440 return get_creds_by_name(bus, name, mask, _creds, error);
443 static int peer_is_privileged(sd_bus *bus, sd_bus_message *m) {
444 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
448 r = get_creds_by_message(bus, m, SD_BUS_CREDS_UID, &creds, NULL);
452 r = sd_bus_creds_get_uid(creds, &uid);
456 r = sd_bus_creds_has_effective_cap(creds, CAP_SYS_ADMIN);
466 static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
476 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
479 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
480 if (0 && !isempty(sd_bus_message_get_signature(m, true))) {
481 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
483 r = sd_bus_error_setf(&error, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
485 return synthetic_reply_method_errno(m, r, &error);
488 return synthetic_reply_method_return(m, "s",
489 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
490 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
492 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
493 " <method name=\"Introspect\">\n"
494 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
497 " <interface name=\"org.freedesktop.DBus\">\n"
498 " <method name=\"AddMatch\">\n"
499 " <arg type=\"s\" direction=\"in\"/>\n"
501 " <method name=\"RemoveMatch\">\n"
502 " <arg type=\"s\" direction=\"in\"/>\n"
504 " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
505 " <arg type=\"s\" direction=\"in\"/>\n"
506 " <arg type=\"ay\" direction=\"out\"/>\n"
508 " <method name=\"GetConnectionUnixProcessID\">\n"
509 " <arg type=\"s\" direction=\"in\"/>\n"
510 " <arg type=\"u\" direction=\"out\"/>\n"
512 " <method name=\"GetConnectionUnixUser\">\n"
513 " <arg type=\"s\" direction=\"in\"/>\n"
514 " <arg type=\"u\" direction=\"out\"/>\n"
516 " <method name=\"GetId\">\n"
517 " <arg type=\"s\" direction=\"out\"/>\n"
519 " <method name=\"GetNameOwner\">\n"
520 " <arg type=\"s\" direction=\"in\"/>\n"
521 " <arg type=\"s\" direction=\"out\"/>\n"
523 " <method name=\"Hello\">\n"
524 " <arg type=\"s\" direction=\"out\"/>\n"
526 " <method name=\"ListActivatableNames\">\n"
527 " <arg type=\"as\" direction=\"out\"/>\n"
529 " <method name=\"ListNames\">\n"
530 " <arg type=\"as\" direction=\"out\"/>\n"
532 " <method name=\"ListQueuedOwners\">\n"
533 " <arg type=\"s\" direction=\"in\"/>\n"
534 " <arg type=\"as\" direction=\"out\"/>\n"
536 " <method name=\"NameHasOwner\">\n"
537 " <arg type=\"s\" direction=\"in\"/>\n"
538 " <arg type=\"b\" direction=\"out\"/>\n"
540 " <method name=\"ReleaseName\">\n"
541 " <arg type=\"s\" direction=\"in\"/>\n"
542 " <arg type=\"u\" direction=\"out\"/>\n"
544 " <method name=\"ReloadConfig\">\n"
546 " <method name=\"RequestName\">\n"
547 " <arg type=\"s\" direction=\"in\"/>\n"
548 " <arg type=\"u\" direction=\"in\"/>\n"
549 " <arg type=\"u\" direction=\"out\"/>\n"
551 " <method name=\"StartServiceByName\">\n"
552 " <arg type=\"s\" direction=\"in\"/>\n"
553 " <arg type=\"u\" direction=\"in\"/>\n"
554 " <arg type=\"u\" direction=\"out\"/>\n"
556 " <method name=\"UpdateActivationEnvironment\">\n"
557 " <arg type=\"a{ss}\" direction=\"in\"/>\n"
559 " <signal name=\"NameAcquired\">\n"
560 " <arg type=\"s\"/>\n"
562 " <signal name=\"NameLost\">\n"
563 " <arg type=\"s\"/>\n"
565 " <signal name=\"NameOwnerChanged\">\n"
566 " <arg type=\"s\"/>\n"
567 " <arg type=\"s\"/>\n"
568 " <arg type=\"s\"/>\n"
573 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
576 r = sd_bus_message_read(m, "s", &match);
578 return synthetic_reply_method_errno(m, r, NULL);
580 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
582 return synthetic_reply_method_errno(m, r, NULL);
584 return synthetic_reply_method_return(m, NULL);
586 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
589 r = sd_bus_message_read(m, "s", &match);
591 return synthetic_reply_method_errno(m, r, NULL);
593 r = bus_remove_match_by_string(a, match, NULL, NULL);
595 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
597 return synthetic_reply_method_errno(m, r, NULL);
599 return synthetic_reply_method_return(m, NULL);
601 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
602 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
604 r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, NULL);
606 return synthetic_reply_method_errno(m, r, NULL);
608 return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
610 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
611 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
613 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, NULL);
615 return synthetic_reply_method_errno(m, r, NULL);
617 return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
619 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
620 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
622 r = get_creds_by_message(a, m, SD_BUS_CREDS_UID, &creds, NULL);
624 return synthetic_reply_method_errno(m, r, NULL);
626 return synthetic_reply_method_return(m, "u", (uint32_t) creds->uid);
628 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
629 sd_id128_t server_id;
630 char buf[SD_ID128_STRING_MAX];
632 r = sd_bus_get_server_id(a, &server_id);
634 return synthetic_reply_method_errno(m, r, NULL);
636 return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
638 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
640 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
641 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
643 r = sd_bus_message_read(m, "s", &name);
645 return synthetic_reply_method_errno(m, r, NULL);
647 if (streq(name, "org.freedesktop.DBus"))
648 return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
650 r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
652 return synthetic_reply_method_errno(m, r, &error);
654 return synthetic_reply_method_return(m, "s", creds->unique_name);
656 /* "Hello" is handled in process_hello() */
658 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
659 _cleanup_strv_free_ char **names = NULL;
661 r = sd_bus_list_names(a, NULL, &names);
663 return synthetic_reply_method_errno(m, r, NULL);
665 /* Let's sort the names list to make it stable */
668 return synthetic_reply_return_strv(m, names);
670 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
671 _cleanup_strv_free_ char **names = NULL;
673 r = sd_bus_list_names(a, &names, NULL);
675 return synthetic_reply_method_errno(m, r, NULL);
677 r = strv_extend(&names, "org.freedesktop.DBus");
679 return synthetic_reply_method_errno(m, r, NULL);
681 /* Let's sort the names list to make it stable */
684 return synthetic_reply_return_strv(m, names);
686 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
687 struct kdbus_cmd_name_list cmd = {};
688 struct kdbus_name_list *name_list;
689 struct kdbus_cmd_name *name;
690 _cleanup_strv_free_ char **owners = NULL;
694 r = sd_bus_message_read(m, "s", &arg0);
696 return synthetic_reply_method_errno(m, r, NULL);
698 if (service_name_is_valid(arg0) < 0)
699 return synthetic_reply_method_errno(m, -EINVAL, NULL);
701 cmd.flags = KDBUS_NAME_LIST_QUEUED;
702 r = ioctl(a->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
704 return synthetic_reply_method_errno(m, -errno, NULL);
706 name_list = (struct kdbus_name_list *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
708 KDBUS_ITEM_FOREACH(name, name_list, names) {
711 if (name->size <= sizeof(*name))
714 if (!streq(name->name, arg0))
717 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
722 r = strv_consume(&owners, n);
729 r = ioctl(a->input_fd, KDBUS_CMD_FREE, &cmd.offset);
731 return synthetic_reply_method_errno(m, r, NULL);
734 return synthetic_reply_method_errno(m, err, NULL);
736 return synthetic_reply_return_strv(m, owners);
738 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
741 r = sd_bus_message_read(m, "s", &name);
743 return synthetic_reply_method_errno(m, r, NULL);
745 if (service_name_is_valid(name) < 0)
746 return synthetic_reply_method_errno(m, -EINVAL, NULL);
748 if (streq(name, "org.freedesktop.DBus"))
749 return synthetic_reply_method_return(m, "b", true);
751 r = sd_bus_get_owner(a, name, 0, NULL);
752 if (r < 0 && r != -ESRCH && r != -ENXIO)
753 return synthetic_reply_method_errno(m, r, NULL);
755 return synthetic_reply_method_return(m, "b", r >= 0);
757 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
760 r = sd_bus_message_read(m, "s", &name);
762 return synthetic_reply_method_errno(m, r, NULL);
764 if (service_name_is_valid(name) < 0)
765 return synthetic_reply_method_errno(m, -EINVAL, NULL);
767 r = sd_bus_release_name(a, name);
770 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
771 if (r == -EADDRINUSE)
772 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
774 return synthetic_reply_method_errno(m, r, NULL);
777 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
779 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
780 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
782 r = sd_bus_error_setf(&error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
784 return synthetic_reply_method_errno(m, r, &error);
786 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
790 r = sd_bus_message_read(m, "su", &name, &flags);
792 return synthetic_reply_method_errno(m, r, NULL);
794 if (service_name_is_valid(name) < 0)
795 return synthetic_reply_method_errno(m, -EINVAL, NULL);
796 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
797 return synthetic_reply_method_errno(m, -EINVAL, NULL);
799 r = sd_bus_request_name(a, name, flags);
802 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
804 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
805 return synthetic_reply_method_errno(m, r, NULL);
809 return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
811 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
813 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
814 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
818 r = sd_bus_message_read(m, "su", &name, &flags);
820 return synthetic_reply_method_errno(m, r, NULL);
822 if (service_name_is_valid(name) < 0)
823 return synthetic_reply_method_errno(m, -EINVAL, NULL);
825 return synthetic_reply_method_errno(m, -EINVAL, NULL);
827 r = sd_bus_get_owner(a, name, 0, NULL);
828 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
829 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
831 return synthetic_reply_method_errno(m, r, NULL);
833 r = sd_bus_message_new_method_call(
838 "org.freedesktop.DBus.Peer",
841 return synthetic_reply_method_errno(m, r, NULL);
843 r = sd_bus_send(a, msg, NULL);
845 return synthetic_reply_method_errno(m, r, NULL);
847 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
849 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
850 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
851 _cleanup_strv_free_ char **args = NULL;
853 if (!peer_is_privileged(a, m))
854 return synthetic_reply_method_errno(m, -EPERM, NULL);
856 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
858 return synthetic_reply_method_errno(m, r, NULL);
860 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
861 _cleanup_free_ char *s = NULL;
865 r = sd_bus_message_read(m, "ss", &key, &value);
867 return synthetic_reply_method_errno(m, r, NULL);
869 s = strjoin(key, "=", value, NULL);
871 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
873 r = strv_extend(&args, s);
875 return synthetic_reply_method_errno(m, r, NULL);
877 r = sd_bus_message_exit_container(m);
879 return synthetic_reply_method_errno(m, r, NULL);
882 r = sd_bus_message_exit_container(m);
884 return synthetic_reply_method_errno(m, r, NULL);
887 return synthetic_reply_method_errno(m, -EINVAL, NULL);
889 r = sd_bus_message_new_method_call(
892 "org.freedesktop.systemd1",
893 "/org/freedesktop/systemd1",
894 "org.freedesktop.systemd1.Manager",
897 return synthetic_reply_method_errno(m, r, NULL);
899 r = sd_bus_message_append_strv(msg, args);
901 return synthetic_reply_method_errno(m, r, NULL);
903 r = sd_bus_call(a, msg, 0, NULL, NULL);
905 return synthetic_reply_method_errno(m, r, NULL);
907 return synthetic_reply_method_return(m, NULL);
910 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
912 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
914 return synthetic_reply_method_errno(m, r, &error);
918 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
919 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
928 /* As reaction to hello we need to respond with two messages:
929 * the callback reply and the NameAcquired for the unique
930 * name, since hello is otherwise obsolete on kdbus. */
933 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
934 streq_ptr(m->destination, "org.freedesktop.DBus");
941 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
946 log_error("Got duplicate hello, aborting.");
955 r = sd_bus_message_new_method_return(m, &n);
957 log_error("Failed to generate HELLO reply: %s", strerror(-r));
961 r = sd_bus_message_append(n, "s", a->unique_name);
963 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
967 r = bus_message_append_sender(n, "org.freedesktop.DBus");
969 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
973 r = bus_seal_synthetic_message(b, n);
975 log_error("Failed to seal HELLO reply: %s", strerror(-r));
979 r = sd_bus_send(b, n, NULL);
981 log_error("Failed to send HELLO reply: %s", strerror(-r));
985 n = sd_bus_message_unref(n);
986 r = sd_bus_message_new_signal(
989 "/org/freedesktop/DBus",
990 "org.freedesktop.DBus",
993 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
997 r = sd_bus_message_append(n, "s", a->unique_name);
999 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
1003 r = bus_message_append_sender(n, "org.freedesktop.DBus");
1005 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
1009 r = bus_seal_synthetic_message(b, n);
1011 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
1015 r = sd_bus_send(b, n, NULL);
1017 log_error("Failed to send NameAcquired message: %s", strerror(-r));
1024 static int patch_sender(sd_bus *a, sd_bus_message *m) {
1025 char **well_known = NULL;
1035 /* We will change the sender of messages from the bus driver
1036 * so that they originate from the bus driver. This is a
1037 * speciality originating from dbus1, where the bus driver did
1038 * not have a unique id, but only the well-known name. */
1040 c = sd_bus_message_get_creds(m);
1044 r = sd_bus_creds_get_well_known_names(c, &well_known);
1048 if (strv_contains(well_known, "org.freedesktop.DBus"))
1049 m->sender = "org.freedesktop.DBus";
1054 int main(int argc, char *argv[]) {
1056 _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
1057 sd_id128_t server_id;
1058 int r, in_fd, out_fd;
1059 bool got_hello = false;
1061 struct ucred ucred = {};
1062 _cleanup_free_ char *peersec = NULL;
1065 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
1066 log_parse_environment();
1069 r = parse_argv(argc, argv);
1073 r = policy_load(&policy, arg_configuration);
1075 log_error("Failed to load policy: %s", strerror(-r));
1079 /* policy_dump(&policy); */
1081 r = sd_listen_fds(0);
1083 in_fd = STDIN_FILENO;
1084 out_fd = STDOUT_FILENO;
1085 } else if (r == 1) {
1086 in_fd = SD_LISTEN_FDS_START;
1087 out_fd = SD_LISTEN_FDS_START;
1089 log_error("Illegal number of file descriptors passed");
1094 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
1095 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
1098 getpeercred(in_fd, &ucred);
1099 getpeersec(in_fd, &peersec);
1102 if (arg_drop_privileges) {
1103 const char *user = "systemd-bus-proxy";
1107 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
1109 log_error("Cannot resolve user name %s: %s", user, strerror(-r));
1113 r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
1120 log_error("Failed to allocate bus: %s", strerror(-r));
1124 r = sd_bus_set_name(a, "sd-proxy");
1126 log_error("Failed to set bus name: %s", strerror(-r));
1130 r = sd_bus_set_address(a, arg_address);
1132 log_error("Failed to set address to connect to: %s", strerror(-r));
1136 r = sd_bus_negotiate_fds(a, is_unix);
1138 log_error("Failed to set FD negotiation: %s", strerror(-r));
1142 if (ucred.pid > 0) {
1143 a->fake_creds.pid = ucred.pid;
1144 a->fake_creds.uid = ucred.uid;
1145 a->fake_creds.gid = ucred.gid;
1146 a->fake_creds_valid = true;
1150 a->fake_label = peersec;
1154 a->manual_peer_interface = true;
1156 r = sd_bus_start(a);
1158 log_error("Failed to start bus client: %s", strerror(-r));
1162 r = sd_bus_get_server_id(a, &server_id);
1164 log_error("Failed to get server ID: %s", strerror(-r));
1170 log_error("Failed to allocate bus: %s", strerror(-r));
1174 r = sd_bus_set_fd(b, in_fd, out_fd);
1176 log_error("Failed to set fds: %s", strerror(-r));
1180 r = sd_bus_set_server(b, 1, server_id);
1182 log_error("Failed to set server mode: %s", strerror(-r));
1186 r = sd_bus_negotiate_fds(b, is_unix);
1188 log_error("Failed to set FD negotiation: %s", strerror(-r));
1192 r = sd_bus_set_anonymous(b, true);
1194 log_error("Failed to set anonymous authentication: %s", strerror(-r));
1198 b->manual_peer_interface = true;
1200 r = sd_bus_start(b);
1202 log_error("Failed to start bus client: %s", strerror(-r));
1206 r = rename_service(a, b);
1208 log_debug("Failed to rename process: %s", strerror(-r));
1211 _cleanup_free_ char *match = NULL;
1214 r = sd_bus_get_unique_name(a, &unique);
1216 log_error("Failed to get unique name: %s", strerror(-r));
1220 match = strjoin("type='signal',"
1221 "sender='org.freedesktop.DBus',"
1222 "path='/org/freedesktop/DBus',"
1223 "interface='org.freedesktop.DBus',"
1224 "member='NameOwnerChanged',"
1234 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1236 log_error("Failed to add match for NameLost: %s", strerror(-r));
1241 match = strjoin("type='signal',"
1242 "sender='org.freedesktop.DBus',"
1243 "path='/org/freedesktop/DBus',"
1244 "interface='org.freedesktop.DBus',"
1245 "member='NameOwnerChanged',"
1255 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1257 log_error("Failed to add match for NameAcquired: %s", strerror(-r));
1263 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1264 int events_a, events_b, fd;
1265 uint64_t timeout_a, timeout_b, t;
1266 struct timespec _ts, *ts;
1267 struct pollfd *pollfd;
1271 r = sd_bus_process(a, &m);
1273 /* treat 'connection reset by peer' as clean exit condition */
1274 if (r == -ECONNRESET)
1277 log_error("Failed to process bus a: %s", strerror(-r));
1283 /* We officially got EOF, let's quit */
1284 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1289 k = synthesize_name_acquired(a, b, m);
1292 log_error("Failed to synthesize message: %s", strerror(-r));
1298 k = sd_bus_send(b, m, NULL);
1300 if (k == -ECONNRESET)
1304 log_error("Failed to send message: %s", strerror(-r));
1315 r = sd_bus_process(b, &m);
1317 /* treat 'connection reset by peer' as clean exit condition */
1318 if (r == -ECONNRESET)
1321 log_error("Failed to process bus b: %s", strerror(-r));
1327 /* We officially got EOF, let's quit */
1328 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1333 k = process_hello(a, b, m, &got_hello);
1336 log_error("Failed to process HELLO: %s", strerror(-r));
1343 k = process_policy(a, b, m);
1346 log_error("Failed to process policy: %s", strerror(-r));
1350 k = process_driver(a, b, m);
1353 log_error("Failed to process driver calls: %s", strerror(-r));
1360 k = sd_bus_send(a, m, NULL);
1362 if (r == -ECONNRESET)
1366 log_error("Failed to send message: %s", strerror(-r));
1378 fd = sd_bus_get_fd(a);
1380 log_error("Failed to get fd: %s", strerror(-r));
1384 events_a = sd_bus_get_events(a);
1386 log_error("Failed to get events mask: %s", strerror(-r));
1390 r = sd_bus_get_timeout(a, &timeout_a);
1392 log_error("Failed to get timeout: %s", strerror(-r));
1396 events_b = sd_bus_get_events(b);
1398 log_error("Failed to get events mask: %s", strerror(-r));
1402 r = sd_bus_get_timeout(b, &timeout_b);
1404 log_error("Failed to get timeout: %s", strerror(-r));
1409 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
1412 if (t == (uint64_t) -1)
1417 nw = now(CLOCK_MONOTONIC);
1423 ts = timespec_store(&_ts, t);
1426 pollfd = (struct pollfd[3]) {
1427 {.fd = fd, .events = events_a, },
1428 {.fd = in_fd, .events = events_b & POLLIN, },
1429 {.fd = out_fd, .events = events_b & POLLOUT, }
1432 r = ppoll(pollfd, 3, ts, NULL);
1434 log_error("ppoll() failed: %m");
1443 policy_free(&policy);
1444 strv_free(arg_configuration);
1446 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;