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"
46 #include "capability.h"
47 #include "bus-policy.h"
49 static char *arg_address = NULL;
50 static char *arg_command_line_buffer = NULL;
51 static bool arg_drop_privileges = false;
52 static char **arg_configuration = NULL;
54 static int help(void) {
56 printf("%s [OPTIONS...]\n\n"
57 "Connect STDIO or a socket to a given bus address.\n\n"
58 " -h --help Show this help\n"
59 " --version Show package version\n"
60 " --drop-privileges Drop privileges\n"
61 " --configuration=PATH Configuration file or directory\n"
62 " --machine=MACHINE Connect to specified machine\n"
63 " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
64 " (default: " DEFAULT_SYSTEM_BUS_PATH ")\n",
65 program_invocation_short_name);
70 static int parse_argv(int argc, char *argv[]) {
80 static const struct option options[] = {
81 { "help", no_argument, NULL, 'h' },
82 { "version", no_argument, NULL, ARG_VERSION },
83 { "address", required_argument, NULL, ARG_ADDRESS },
84 { "drop-privileges", no_argument, NULL, ARG_DROP_PRIVILEGES },
85 { "configuration", required_argument, NULL, ARG_CONFIGURATION },
86 { "machine", required_argument, NULL, ARG_MACHINE },
95 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
104 puts(PACKAGE_STRING);
105 puts(SYSTEMD_FEATURES);
120 case ARG_DROP_PRIVILEGES:
121 arg_drop_privileges = true;
124 case ARG_CONFIGURATION:
125 r = strv_extend(&arg_configuration, optarg);
131 _cleanup_free_ char *e = NULL;
134 e = bus_address_escape(optarg);
139 a = strjoin("x-container-kernel:machine=", e, ";x-container-unix:machine=", e, NULL);
141 a = strjoin("x-container-unix:machine=", e, NULL);
156 assert_not_reached("Unhandled option");
159 /* If the first command line argument is only "x" characters
160 * we'll write who we are talking to into it, so that "ps" is
162 arg_command_line_buffer = argv[optind];
163 if (argc > optind + 1 || (arg_command_line_buffer && !in_charset(arg_command_line_buffer, "x"))) {
164 log_error("Too many arguments");
169 arg_address = strdup(DEFAULT_SYSTEM_BUS_PATH);
177 static int rename_service(sd_bus *a, sd_bus *b) {
178 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
179 _cleanup_free_ char *p = NULL, *name = NULL;
189 r = sd_bus_get_peer_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM, &creds);
193 r = sd_bus_creds_get_uid(creds, &uid);
197 r = sd_bus_creds_get_pid(creds, &pid);
201 r = sd_bus_creds_get_cmdline(creds, &cmdline);
205 r = sd_bus_creds_get_comm(creds, &comm);
209 name = uid_to_name(uid);
213 p = strv_join(cmdline, " ");
217 /* The status string gets the full command line ... */
219 "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
223 /* ... and the argv line only the short comm */
224 if (arg_command_line_buffer) {
227 m = strlen(arg_command_line_buffer);
228 w = snprintf(arg_command_line_buffer, m,
229 "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
234 memzero(arg_command_line_buffer + w, m - w);
237 log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
245 static int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
246 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
247 const char *name, *old_owner, *new_owner;
254 /* If we get NameOwnerChanged for our own name, we need to
255 * synthesize NameLost/NameAcquired, since socket clients need
256 * that, even though it is obsoleted on kdbus */
261 if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
262 !streq_ptr(m->path, "/org/freedesktop/DBus") ||
263 !streq_ptr(m->sender, "org.freedesktop.DBus"))
266 r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
270 r = sd_bus_message_rewind(m, true);
274 if (streq(old_owner, a->unique_name)) {
276 r = sd_bus_message_new_signal(
279 "/org/freedesktop/DBus",
280 "org.freedesktop.DBus",
283 } else if (streq(new_owner, a->unique_name)) {
285 r = sd_bus_message_new_signal(
288 "/org/freedesktop/DBus",
289 "org.freedesktop.DBus",
297 r = sd_bus_message_append(n, "s", name);
301 r = bus_message_append_sender(n, "org.freedesktop.DBus");
305 r = bus_seal_synthetic_message(b, n);
309 return sd_bus_send(b, n, NULL);
312 static int process_policy(sd_bus *a, sd_bus *b, sd_bus_message *m) {
313 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
323 if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll"))
326 if (!streq_ptr(m->path, "/org/gnome/DisplayManager/Slave"))
329 r = sd_bus_message_new_method_errorf(m, &n, SD_BUS_ERROR_ACCESS_DENIED, "gdm, you are stupid");
333 r = bus_message_append_sender(n, "org.freedesktop.DBus");
335 log_error("Failed to append sender to gdm reply: %s", strerror(-r));
339 r = bus_seal_synthetic_message(b, n);
341 log_error("Failed to seal gdm reply: %s", strerror(-r));
345 r = sd_bus_send(b, n, NULL);
347 log_error("Failed to send gdm reply: %s", strerror(-r));
354 static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
360 r = bus_message_append_sender(m, "org.freedesktop.DBus");
364 r = bus_seal_synthetic_message(b, m);
368 return sd_bus_send(b, m, NULL);
371 static int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
372 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
377 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
380 r = sd_bus_message_new_method_error(call, &m, e);
384 return synthetic_driver_send(call->bus, m);
387 static int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
389 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
393 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
396 if (sd_bus_error_is_set(p))
397 return synthetic_reply_method_error(call, p);
399 sd_bus_error_set_errno(&berror, error);
401 return synthetic_reply_method_error(call, &berror);
404 static int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
405 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
410 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
413 r = sd_bus_message_new_method_return(call, &m);
417 if (!isempty(types)) {
421 r = bus_message_append_ap(m, types, ap);
427 return synthetic_driver_send(call->bus, m);
430 static int synthetic_reply_return_strv(sd_bus_message *call, char **l) {
431 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
436 r = sd_bus_message_new_method_return(call, &m);
438 return synthetic_reply_method_errno(call, r, NULL);
440 r = sd_bus_message_append_strv(m, l);
442 return synthetic_reply_method_errno(call, r, NULL);
444 return synthetic_driver_send(call->bus, m);
447 static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
448 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
455 assert_return(service_name_is_valid(name), -EINVAL);
457 r = sd_bus_get_owner(bus, name, mask, &c);
458 if (r == -ESRCH || r == -ENXIO)
459 return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
463 if ((c->mask & mask) != mask)
472 static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
480 r = sd_bus_message_read(m, "s", &name);
484 return get_creds_by_name(bus, name, mask, _creds, error);
487 static int peer_is_privileged(sd_bus *bus, sd_bus_message *m) {
488 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
492 r = get_creds_by_message(bus, m, SD_BUS_CREDS_UID, &creds, NULL);
496 r = sd_bus_creds_get_uid(creds, &uid);
500 r = sd_bus_creds_has_effective_cap(creds, CAP_SYS_ADMIN);
510 static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
520 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
523 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
524 if (0 && !isempty(sd_bus_message_get_signature(m, true))) {
525 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
527 r = sd_bus_error_setf(&error, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
529 return synthetic_reply_method_errno(m, r, &error);
532 return synthetic_reply_method_return(m, "s",
533 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
534 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
536 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
537 " <method name=\"Introspect\">\n"
538 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
541 " <interface name=\"org.freedesktop.DBus\">\n"
542 " <method name=\"AddMatch\">\n"
543 " <arg type=\"s\" direction=\"in\"/>\n"
545 " <method name=\"RemoveMatch\">\n"
546 " <arg type=\"s\" direction=\"in\"/>\n"
548 " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
549 " <arg type=\"s\" direction=\"in\"/>\n"
550 " <arg type=\"ay\" direction=\"out\"/>\n"
552 " <method name=\"GetConnectionUnixProcessID\">\n"
553 " <arg type=\"s\" direction=\"in\"/>\n"
554 " <arg type=\"u\" direction=\"out\"/>\n"
556 " <method name=\"GetConnectionUnixUser\">\n"
557 " <arg type=\"s\" direction=\"in\"/>\n"
558 " <arg type=\"u\" direction=\"out\"/>\n"
560 " <method name=\"GetId\">\n"
561 " <arg type=\"s\" direction=\"out\"/>\n"
563 " <method name=\"GetNameOwner\">\n"
564 " <arg type=\"s\" direction=\"in\"/>\n"
565 " <arg type=\"s\" direction=\"out\"/>\n"
567 " <method name=\"Hello\">\n"
568 " <arg type=\"s\" direction=\"out\"/>\n"
570 " <method name=\"ListActivatableNames\">\n"
571 " <arg type=\"as\" direction=\"out\"/>\n"
573 " <method name=\"ListNames\">\n"
574 " <arg type=\"as\" direction=\"out\"/>\n"
576 " <method name=\"ListQueuedOwners\">\n"
577 " <arg type=\"s\" direction=\"in\"/>\n"
578 " <arg type=\"as\" direction=\"out\"/>\n"
580 " <method name=\"NameHasOwner\">\n"
581 " <arg type=\"s\" direction=\"in\"/>\n"
582 " <arg type=\"b\" direction=\"out\"/>\n"
584 " <method name=\"ReleaseName\">\n"
585 " <arg type=\"s\" direction=\"in\"/>\n"
586 " <arg type=\"u\" direction=\"out\"/>\n"
588 " <method name=\"ReloadConfig\">\n"
590 " <method name=\"RequestName\">\n"
591 " <arg type=\"s\" direction=\"in\"/>\n"
592 " <arg type=\"u\" direction=\"in\"/>\n"
593 " <arg type=\"u\" direction=\"out\"/>\n"
595 " <method name=\"StartServiceByName\">\n"
596 " <arg type=\"s\" direction=\"in\"/>\n"
597 " <arg type=\"u\" direction=\"in\"/>\n"
598 " <arg type=\"u\" direction=\"out\"/>\n"
600 " <method name=\"UpdateActivationEnvironment\">\n"
601 " <arg type=\"a{ss}\" direction=\"in\"/>\n"
603 " <signal name=\"NameAcquired\">\n"
604 " <arg type=\"s\"/>\n"
606 " <signal name=\"NameLost\">\n"
607 " <arg type=\"s\"/>\n"
609 " <signal name=\"NameOwnerChanged\">\n"
610 " <arg type=\"s\"/>\n"
611 " <arg type=\"s\"/>\n"
612 " <arg type=\"s\"/>\n"
617 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
620 r = sd_bus_message_read(m, "s", &match);
622 return synthetic_reply_method_errno(m, r, NULL);
624 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
626 return synthetic_reply_method_errno(m, r, NULL);
628 return synthetic_reply_method_return(m, NULL);
630 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
633 r = sd_bus_message_read(m, "s", &match);
635 return synthetic_reply_method_errno(m, r, NULL);
637 r = bus_remove_match_by_string(a, match, NULL, NULL);
639 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
641 return synthetic_reply_method_errno(m, r, NULL);
643 return synthetic_reply_method_return(m, NULL);
645 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
646 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
648 r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, NULL);
650 return synthetic_reply_method_errno(m, r, NULL);
652 return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
654 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
655 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
657 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, NULL);
659 return synthetic_reply_method_errno(m, r, NULL);
661 return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
663 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
664 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
666 r = get_creds_by_message(a, m, SD_BUS_CREDS_UID, &creds, NULL);
668 return synthetic_reply_method_errno(m, r, NULL);
670 return synthetic_reply_method_return(m, "u", (uint32_t) creds->uid);
672 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
673 sd_id128_t server_id;
674 char buf[SD_ID128_STRING_MAX];
676 r = sd_bus_get_server_id(a, &server_id);
678 return synthetic_reply_method_errno(m, r, NULL);
680 return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
682 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
684 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
685 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
687 r = sd_bus_message_read(m, "s", &name);
689 return synthetic_reply_method_errno(m, r, NULL);
691 if (streq(name, "org.freedesktop.DBus"))
692 return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
694 r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
696 return synthetic_reply_method_errno(m, r, &error);
698 return synthetic_reply_method_return(m, "s", creds->unique_name);
700 /* "Hello" is handled in process_hello() */
702 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
703 _cleanup_strv_free_ char **names = NULL;
705 r = sd_bus_list_names(a, NULL, &names);
707 return synthetic_reply_method_errno(m, r, NULL);
709 /* Let's sort the names list to make it stable */
712 return synthetic_reply_return_strv(m, names);
714 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
715 _cleanup_strv_free_ char **names = NULL;
717 r = sd_bus_list_names(a, &names, NULL);
719 return synthetic_reply_method_errno(m, r, NULL);
721 r = strv_extend(&names, "org.freedesktop.DBus");
723 return synthetic_reply_method_errno(m, r, NULL);
725 /* Let's sort the names list to make it stable */
728 return synthetic_reply_return_strv(m, names);
730 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
731 struct kdbus_cmd_name_list cmd = {};
732 struct kdbus_name_list *name_list;
733 struct kdbus_cmd_free cmd_free;
734 struct kdbus_cmd_name *name;
735 _cleanup_strv_free_ char **owners = NULL;
739 r = sd_bus_message_read(m, "s", &arg0);
741 return synthetic_reply_method_errno(m, r, NULL);
743 if (!service_name_is_valid(arg0))
744 return synthetic_reply_method_errno(m, -EINVAL, NULL);
746 cmd.flags = KDBUS_NAME_LIST_QUEUED;
747 r = ioctl(a->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
749 return synthetic_reply_method_errno(m, -errno, NULL);
751 name_list = (struct kdbus_name_list *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
753 KDBUS_ITEM_FOREACH(name, name_list, names) {
754 const char *entry_name = NULL;
755 struct kdbus_item *item;
758 KDBUS_ITEM_FOREACH(item, name, items)
759 if (item->type == KDBUS_ITEM_NAME)
760 entry_name = item->str;
762 if (!streq_ptr(entry_name, arg0))
765 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
770 r = strv_consume(&owners, n);
778 cmd_free.offset = cmd.offset;
780 r = ioctl(a->input_fd, KDBUS_CMD_FREE, &cmd_free);
782 return synthetic_reply_method_errno(m, r, NULL);
785 return synthetic_reply_method_errno(m, err, NULL);
787 return synthetic_reply_return_strv(m, owners);
789 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
792 r = sd_bus_message_read(m, "s", &name);
794 return synthetic_reply_method_errno(m, r, NULL);
796 if (!service_name_is_valid(name))
797 return synthetic_reply_method_errno(m, -EINVAL, NULL);
799 if (streq(name, "org.freedesktop.DBus"))
800 return synthetic_reply_method_return(m, "b", true);
802 r = sd_bus_get_owner(a, name, 0, NULL);
803 if (r < 0 && r != -ESRCH && r != -ENXIO)
804 return synthetic_reply_method_errno(m, r, NULL);
806 return synthetic_reply_method_return(m, "b", r >= 0);
808 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
811 r = sd_bus_message_read(m, "s", &name);
813 return synthetic_reply_method_errno(m, r, NULL);
815 if (!service_name_is_valid(name))
816 return synthetic_reply_method_errno(m, -EINVAL, NULL);
818 r = sd_bus_release_name(a, name);
821 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
822 if (r == -EADDRINUSE)
823 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
825 return synthetic_reply_method_errno(m, r, NULL);
828 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
830 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
831 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
833 r = sd_bus_error_setf(&error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
835 return synthetic_reply_method_errno(m, r, &error);
837 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
841 r = sd_bus_message_read(m, "su", &name, &flags);
843 return synthetic_reply_method_errno(m, r, NULL);
845 if (!service_name_is_valid(name))
846 return synthetic_reply_method_errno(m, -EINVAL, NULL);
847 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
848 return synthetic_reply_method_errno(m, -EINVAL, NULL);
850 r = sd_bus_request_name(a, name, flags);
853 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
855 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
856 return synthetic_reply_method_errno(m, r, NULL);
860 return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
862 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
864 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
865 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
869 r = sd_bus_message_read(m, "su", &name, &flags);
871 return synthetic_reply_method_errno(m, r, NULL);
873 if (!service_name_is_valid(name))
874 return synthetic_reply_method_errno(m, -EINVAL, NULL);
876 return synthetic_reply_method_errno(m, -EINVAL, NULL);
878 r = sd_bus_get_owner(a, name, 0, NULL);
879 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
880 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
882 return synthetic_reply_method_errno(m, r, NULL);
884 r = sd_bus_message_new_method_call(
889 "org.freedesktop.DBus.Peer",
892 return synthetic_reply_method_errno(m, r, NULL);
894 r = sd_bus_send(a, msg, NULL);
896 return synthetic_reply_method_errno(m, r, NULL);
898 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
900 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
901 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
902 _cleanup_strv_free_ char **args = NULL;
904 if (!peer_is_privileged(a, m))
905 return synthetic_reply_method_errno(m, -EPERM, NULL);
907 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
909 return synthetic_reply_method_errno(m, r, NULL);
911 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
912 _cleanup_free_ char *s = NULL;
916 r = sd_bus_message_read(m, "ss", &key, &value);
918 return synthetic_reply_method_errno(m, r, NULL);
920 s = strjoin(key, "=", value, NULL);
922 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
924 r = strv_extend(&args, s);
926 return synthetic_reply_method_errno(m, r, NULL);
928 r = sd_bus_message_exit_container(m);
930 return synthetic_reply_method_errno(m, r, NULL);
933 r = sd_bus_message_exit_container(m);
935 return synthetic_reply_method_errno(m, r, NULL);
938 return synthetic_reply_method_errno(m, -EINVAL, NULL);
940 r = sd_bus_message_new_method_call(
943 "org.freedesktop.systemd1",
944 "/org/freedesktop/systemd1",
945 "org.freedesktop.systemd1.Manager",
948 return synthetic_reply_method_errno(m, r, NULL);
950 r = sd_bus_message_append_strv(msg, args);
952 return synthetic_reply_method_errno(m, r, NULL);
954 r = sd_bus_call(a, msg, 0, NULL, NULL);
956 return synthetic_reply_method_errno(m, r, NULL);
958 return synthetic_reply_method_return(m, NULL);
961 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
963 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
965 return synthetic_reply_method_errno(m, r, &error);
969 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
970 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
979 /* As reaction to hello we need to respond with two messages:
980 * the callback reply and the NameAcquired for the unique
981 * name, since hello is otherwise obsolete on kdbus. */
984 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
985 streq_ptr(m->destination, "org.freedesktop.DBus");
992 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
997 log_error("Got duplicate hello, aborting.");
1006 r = sd_bus_message_new_method_return(m, &n);
1008 log_error("Failed to generate HELLO reply: %s", strerror(-r));
1012 r = sd_bus_message_append(n, "s", a->unique_name);
1014 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
1018 r = bus_message_append_sender(n, "org.freedesktop.DBus");
1020 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
1024 r = bus_seal_synthetic_message(b, n);
1026 log_error("Failed to seal HELLO reply: %s", strerror(-r));
1030 r = sd_bus_send(b, n, NULL);
1032 log_error("Failed to send HELLO reply: %s", strerror(-r));
1036 n = sd_bus_message_unref(n);
1037 r = sd_bus_message_new_signal(
1040 "/org/freedesktop/DBus",
1041 "org.freedesktop.DBus",
1044 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
1048 r = sd_bus_message_append(n, "s", a->unique_name);
1050 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
1054 r = bus_message_append_sender(n, "org.freedesktop.DBus");
1056 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
1060 r = bus_seal_synthetic_message(b, n);
1062 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
1066 r = sd_bus_send(b, n, NULL);
1068 log_error("Failed to send NameAcquired message: %s", strerror(-r));
1075 static int patch_sender(sd_bus *a, sd_bus_message *m) {
1076 char **well_known = NULL;
1086 /* We will change the sender of messages from the bus driver
1087 * so that they originate from the bus driver. This is a
1088 * speciality originating from dbus1, where the bus driver did
1089 * not have a unique id, but only the well-known name. */
1091 c = sd_bus_message_get_creds(m);
1095 r = sd_bus_creds_get_well_known_names(c, &well_known);
1099 if (strv_contains(well_known, "org.freedesktop.DBus"))
1100 m->sender = "org.freedesktop.DBus";
1105 int main(int argc, char *argv[]) {
1107 _cleanup_bus_close_unref_ sd_bus *a = NULL, *b = NULL;
1108 sd_id128_t server_id;
1109 int r, in_fd, out_fd;
1110 bool got_hello = false;
1112 struct ucred ucred = {};
1113 _cleanup_free_ char *peersec = NULL;
1116 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
1117 log_parse_environment();
1120 r = parse_argv(argc, argv);
1124 r = policy_load(&policy, arg_configuration);
1126 log_error("Failed to load policy: %s", strerror(-r));
1130 /* policy_dump(&policy); */
1132 r = sd_listen_fds(0);
1134 in_fd = STDIN_FILENO;
1135 out_fd = STDOUT_FILENO;
1136 } else if (r == 1) {
1137 in_fd = SD_LISTEN_FDS_START;
1138 out_fd = SD_LISTEN_FDS_START;
1140 log_error("Illegal number of file descriptors passed");
1145 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
1146 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
1149 r = getpeercred(in_fd, &ucred);
1151 log_error("Failed to get peer creds: %s", strerror(-r));
1155 (void) getpeersec(in_fd, &peersec);
1158 if (arg_drop_privileges) {
1159 const char *user = "systemd-bus-proxy";
1163 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
1165 log_error("Cannot resolve user name %s: %s", user, strerror(-r));
1169 r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
1176 log_error("Failed to allocate bus: %s", strerror(-r));
1180 r = sd_bus_set_name(a, "sd-proxy");
1182 log_error("Failed to set bus name: %s", strerror(-r));
1186 r = sd_bus_set_address(a, arg_address);
1188 log_error("Failed to set address to connect to: %s", strerror(-r));
1192 r = sd_bus_negotiate_fds(a, is_unix);
1194 log_error("Failed to set FD negotiation: %s", strerror(-r));
1198 if (ucred.pid > 0) {
1199 a->fake_creds.pid = ucred.pid;
1200 a->fake_creds.uid = ucred.uid;
1201 a->fake_creds.gid = ucred.gid;
1202 a->fake_creds_valid = true;
1206 a->fake_label = peersec;
1210 a->manual_peer_interface = true;
1212 r = sd_bus_start(a);
1214 log_error("Failed to start bus client: %s", strerror(-r));
1218 r = sd_bus_get_server_id(a, &server_id);
1220 log_error("Failed to get server ID: %s", strerror(-r));
1226 log_error("Failed to allocate bus: %s", strerror(-r));
1230 r = sd_bus_set_fd(b, in_fd, out_fd);
1232 log_error("Failed to set fds: %s", strerror(-r));
1236 r = sd_bus_set_server(b, 1, server_id);
1238 log_error("Failed to set server mode: %s", strerror(-r));
1242 r = sd_bus_negotiate_fds(b, is_unix);
1244 log_error("Failed to set FD negotiation: %s", strerror(-r));
1248 r = sd_bus_set_anonymous(b, true);
1250 log_error("Failed to set anonymous authentication: %s", strerror(-r));
1254 b->manual_peer_interface = true;
1256 r = sd_bus_start(b);
1258 log_error("Failed to start bus client: %s", strerror(-r));
1262 r = rename_service(a, b);
1264 log_debug("Failed to rename process: %s", strerror(-r));
1267 _cleanup_free_ char *match = NULL;
1270 r = sd_bus_get_unique_name(a, &unique);
1272 log_error("Failed to get unique name: %s", strerror(-r));
1276 match = strjoin("type='signal',"
1277 "sender='org.freedesktop.DBus',"
1278 "path='/org/freedesktop/DBus',"
1279 "interface='org.freedesktop.DBus',"
1280 "member='NameOwnerChanged',"
1290 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1292 log_error("Failed to add match for NameLost: %s", strerror(-r));
1297 match = strjoin("type='signal',"
1298 "sender='org.freedesktop.DBus',"
1299 "path='/org/freedesktop/DBus',"
1300 "interface='org.freedesktop.DBus',"
1301 "member='NameOwnerChanged',"
1311 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1313 log_error("Failed to add match for NameAcquired: %s", strerror(-r));
1319 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1320 int events_a, events_b, fd;
1321 uint64_t timeout_a, timeout_b, t;
1322 struct timespec _ts, *ts;
1323 struct pollfd *pollfd;
1327 r = sd_bus_process(a, &m);
1329 /* treat 'connection reset by peer' as clean exit condition */
1330 if (r == -ECONNRESET)
1333 log_error("Failed to process bus a: %s", strerror(-r));
1339 /* We officially got EOF, let's quit */
1340 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1345 k = synthesize_name_acquired(a, b, m);
1348 log_error("Failed to synthesize message: %s", strerror(-r));
1354 k = sd_bus_send(b, m, NULL);
1356 if (k == -ECONNRESET)
1360 log_error("Failed to send message: %s", strerror(-r));
1371 r = sd_bus_process(b, &m);
1373 /* treat 'connection reset by peer' as clean exit condition */
1374 if (r == -ECONNRESET)
1377 log_error("Failed to process bus b: %s", strerror(-r));
1383 /* We officially got EOF, let's quit */
1384 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1389 k = process_hello(a, b, m, &got_hello);
1392 log_error("Failed to process HELLO: %s", strerror(-r));
1399 k = process_policy(a, b, m);
1402 log_error("Failed to process policy: %s", strerror(-r));
1406 k = process_driver(a, b, m);
1409 log_error("Failed to process driver calls: %s", strerror(-r));
1416 k = sd_bus_send(a, m, NULL);
1418 if (k == -ECONNRESET)
1422 log_error("Failed to send message: %s", strerror(-r));
1434 fd = sd_bus_get_fd(a);
1436 log_error("Failed to get fd: %s", strerror(-r));
1440 events_a = sd_bus_get_events(a);
1442 log_error("Failed to get events mask: %s", strerror(-r));
1446 r = sd_bus_get_timeout(a, &timeout_a);
1448 log_error("Failed to get timeout: %s", strerror(-r));
1452 events_b = sd_bus_get_events(b);
1454 log_error("Failed to get events mask: %s", strerror(-r));
1458 r = sd_bus_get_timeout(b, &timeout_b);
1460 log_error("Failed to get timeout: %s", strerror(-r));
1465 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
1468 if (t == (uint64_t) -1)
1473 nw = now(CLOCK_MONOTONIC);
1479 ts = timespec_store(&_ts, t);
1482 pollfd = (struct pollfd[3]) {
1483 {.fd = fd, .events = events_a, },
1484 {.fd = in_fd, .events = events_b & POLLIN, },
1485 {.fd = out_fd, .events = events_b & POLLOUT, }
1488 r = ppoll(pollfd, 3, ts, NULL);
1490 log_error("ppoll() failed: %m");
1498 "STATUS=Shutting down.");
1500 policy_free(&policy);
1501 strv_free(arg_configuration);
1504 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;