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 char *arg_address = NULL;
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 " --machine=MACHINE Connect to specified machine\n"
64 " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
65 " (default: " DEFAULT_SYSTEM_BUS_PATH ")\n",
66 program_invocation_short_name);
71 static int parse_argv(int argc, char *argv[]) {
81 static const struct option options[] = {
82 { "help", no_argument, NULL, 'h' },
83 { "version", no_argument, NULL, ARG_VERSION },
84 { "address", required_argument, NULL, ARG_ADDRESS },
85 { "drop-privileges", no_argument, NULL, ARG_DROP_PRIVILEGES },
86 { "configuration", required_argument, NULL, ARG_CONFIGURATION },
87 { "machine", required_argument, NULL, ARG_MACHINE },
96 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
105 puts(PACKAGE_STRING);
106 puts(SYSTEMD_FEATURES);
121 case ARG_DROP_PRIVILEGES:
122 arg_drop_privileges = true;
125 case ARG_CONFIGURATION:
126 r = strv_extend(&arg_configuration, optarg);
132 _cleanup_free_ char *e = NULL;
135 e = bus_address_escape(optarg);
140 a = strjoin("x-container-kernel:machine=", e, ";x-container-unix:machine=", e, NULL);
142 a = strjoin("x-container-unix:machine=", e, NULL);
157 assert_not_reached("Unhandled option");
161 /* If the first command line argument is only "x" characters
162 * we'll write who we are talking to into it, so that "ps" is
164 arg_command_line_buffer = argv[optind];
165 if (argc > optind + 1 || (arg_command_line_buffer && !in_charset(arg_command_line_buffer, "x"))) {
166 log_error("Too many arguments");
171 arg_address = strdup(DEFAULT_SYSTEM_BUS_PATH);
179 static int rename_service(sd_bus *a, sd_bus *b) {
180 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
181 _cleanup_free_ char *p = NULL, *name = NULL;
191 r = sd_bus_get_peer_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM, &creds);
195 r = sd_bus_creds_get_uid(creds, &uid);
199 r = sd_bus_creds_get_pid(creds, &pid);
203 r = sd_bus_creds_get_cmdline(creds, &cmdline);
207 r = sd_bus_creds_get_comm(creds, &comm);
211 name = uid_to_name(uid);
215 p = strv_join(cmdline, " ");
219 /* The status string gets the full command line ... */
221 "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
225 /* ... and the argv line only the short comm */
226 if (arg_command_line_buffer) {
229 m = strlen(arg_command_line_buffer);
230 w = snprintf(arg_command_line_buffer, m,
231 "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
236 memzero(arg_command_line_buffer + w, m - w);
239 log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
247 static int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
248 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
249 const char *name, *old_owner, *new_owner;
256 /* If we get NameOwnerChanged for our own name, we need to
257 * synthesize NameLost/NameAcquired, since socket clients need
258 * that, even though it is obsoleted on kdbus */
263 if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
264 !streq_ptr(m->path, "/org/freedesktop/DBus") ||
265 !streq_ptr(m->sender, "org.freedesktop.DBus"))
268 r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
272 r = sd_bus_message_rewind(m, true);
276 if (streq(old_owner, a->unique_name)) {
278 r = sd_bus_message_new_signal(
281 "/org/freedesktop/DBus",
282 "org.freedesktop.DBus",
285 } else if (streq(new_owner, a->unique_name)) {
287 r = sd_bus_message_new_signal(
290 "/org/freedesktop/DBus",
291 "org.freedesktop.DBus",
299 r = sd_bus_message_append(n, "s", name);
303 r = bus_message_append_sender(n, "org.freedesktop.DBus");
307 r = bus_seal_synthetic_message(b, n);
311 return sd_bus_send(b, n, NULL);
314 static int process_policy(sd_bus *a, sd_bus *b, sd_bus_message *m) {
315 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
325 if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll"))
328 if (!streq_ptr(m->path, "/org/gnome/DisplayManager/Slave"))
331 r = sd_bus_message_new_method_errorf(m, &n, SD_BUS_ERROR_ACCESS_DENIED, "gdm, you are stupid");
335 r = bus_message_append_sender(n, "org.freedesktop.DBus");
337 log_error("Failed to append sender to gdm reply: %s", strerror(-r));
341 r = bus_seal_synthetic_message(b, n);
343 log_error("Failed to seal gdm reply: %s", strerror(-r));
347 r = sd_bus_send(b, n, NULL);
349 log_error("Failed to send gdm reply: %s", strerror(-r));
356 static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
362 r = bus_message_append_sender(m, "org.freedesktop.DBus");
366 r = bus_seal_synthetic_message(b, m);
370 return sd_bus_send(b, m, NULL);
373 static int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
374 _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;
391 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
394 if (sd_bus_error_is_set(p))
395 return synthetic_reply_method_error(call, p);
397 sd_bus_error_set_errno(&berror, error);
399 return synthetic_reply_method_error(call, &berror);
402 static int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
403 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
406 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
409 r = sd_bus_message_new_method_return(call, &m);
413 if (!isempty(types)) {
417 r = bus_message_append_ap(m, types, ap);
423 return synthetic_driver_send(call->bus, m);
426 static int synthetic_reply_return_strv(sd_bus_message *call, char **l) {
427 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
430 r = sd_bus_message_new_method_return(call, &m);
432 return synthetic_reply_method_errno(call, r, NULL);
434 r = sd_bus_message_append_strv(m, l);
436 return synthetic_reply_method_errno(call, r, NULL);
438 return synthetic_driver_send(call->bus, m);
441 static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
442 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
449 assert_return(service_name_is_valid(name), -EINVAL);
451 r = sd_bus_get_owner(bus, name, mask, &c);
452 if (r == -ESRCH || r == -ENXIO)
453 return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
457 if ((c->mask & mask) != mask)
466 static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
474 r = sd_bus_message_read(m, "s", &name);
478 return get_creds_by_name(bus, name, mask, _creds, error);
481 static int peer_is_privileged(sd_bus *bus, sd_bus_message *m) {
482 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
486 r = get_creds_by_message(bus, m, SD_BUS_CREDS_UID, &creds, NULL);
490 r = sd_bus_creds_get_uid(creds, &uid);
494 r = sd_bus_creds_has_effective_cap(creds, CAP_SYS_ADMIN);
504 static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
514 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
517 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
518 if (0 && !isempty(sd_bus_message_get_signature(m, true))) {
519 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
521 r = sd_bus_error_setf(&error, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
523 return synthetic_reply_method_errno(m, r, &error);
526 return synthetic_reply_method_return(m, "s",
527 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
528 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
530 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
531 " <method name=\"Introspect\">\n"
532 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
535 " <interface name=\"org.freedesktop.DBus\">\n"
536 " <method name=\"AddMatch\">\n"
537 " <arg type=\"s\" direction=\"in\"/>\n"
539 " <method name=\"RemoveMatch\">\n"
540 " <arg type=\"s\" direction=\"in\"/>\n"
542 " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
543 " <arg type=\"s\" direction=\"in\"/>\n"
544 " <arg type=\"ay\" direction=\"out\"/>\n"
546 " <method name=\"GetConnectionUnixProcessID\">\n"
547 " <arg type=\"s\" direction=\"in\"/>\n"
548 " <arg type=\"u\" direction=\"out\"/>\n"
550 " <method name=\"GetConnectionUnixUser\">\n"
551 " <arg type=\"s\" direction=\"in\"/>\n"
552 " <arg type=\"u\" direction=\"out\"/>\n"
554 " <method name=\"GetId\">\n"
555 " <arg type=\"s\" direction=\"out\"/>\n"
557 " <method name=\"GetNameOwner\">\n"
558 " <arg type=\"s\" direction=\"in\"/>\n"
559 " <arg type=\"s\" direction=\"out\"/>\n"
561 " <method name=\"Hello\">\n"
562 " <arg type=\"s\" direction=\"out\"/>\n"
564 " <method name=\"ListActivatableNames\">\n"
565 " <arg type=\"as\" direction=\"out\"/>\n"
567 " <method name=\"ListNames\">\n"
568 " <arg type=\"as\" direction=\"out\"/>\n"
570 " <method name=\"ListQueuedOwners\">\n"
571 " <arg type=\"s\" direction=\"in\"/>\n"
572 " <arg type=\"as\" direction=\"out\"/>\n"
574 " <method name=\"NameHasOwner\">\n"
575 " <arg type=\"s\" direction=\"in\"/>\n"
576 " <arg type=\"b\" direction=\"out\"/>\n"
578 " <method name=\"ReleaseName\">\n"
579 " <arg type=\"s\" direction=\"in\"/>\n"
580 " <arg type=\"u\" direction=\"out\"/>\n"
582 " <method name=\"ReloadConfig\">\n"
584 " <method name=\"RequestName\">\n"
585 " <arg type=\"s\" direction=\"in\"/>\n"
586 " <arg type=\"u\" direction=\"in\"/>\n"
587 " <arg type=\"u\" direction=\"out\"/>\n"
589 " <method name=\"StartServiceByName\">\n"
590 " <arg type=\"s\" direction=\"in\"/>\n"
591 " <arg type=\"u\" direction=\"in\"/>\n"
592 " <arg type=\"u\" direction=\"out\"/>\n"
594 " <method name=\"UpdateActivationEnvironment\">\n"
595 " <arg type=\"a{ss}\" direction=\"in\"/>\n"
597 " <signal name=\"NameAcquired\">\n"
598 " <arg type=\"s\"/>\n"
600 " <signal name=\"NameLost\">\n"
601 " <arg type=\"s\"/>\n"
603 " <signal name=\"NameOwnerChanged\">\n"
604 " <arg type=\"s\"/>\n"
605 " <arg type=\"s\"/>\n"
606 " <arg type=\"s\"/>\n"
611 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
614 r = sd_bus_message_read(m, "s", &match);
616 return synthetic_reply_method_errno(m, r, NULL);
618 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
620 return synthetic_reply_method_errno(m, r, NULL);
622 return synthetic_reply_method_return(m, NULL);
624 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
627 r = sd_bus_message_read(m, "s", &match);
629 return synthetic_reply_method_errno(m, r, NULL);
631 r = bus_remove_match_by_string(a, match, NULL, NULL);
633 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
635 return synthetic_reply_method_errno(m, r, NULL);
637 return synthetic_reply_method_return(m, NULL);
639 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
640 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
642 r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, NULL);
644 return synthetic_reply_method_errno(m, r, NULL);
646 return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
648 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
649 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
651 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, NULL);
653 return synthetic_reply_method_errno(m, r, NULL);
655 return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
657 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
658 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
660 r = get_creds_by_message(a, m, SD_BUS_CREDS_UID, &creds, NULL);
662 return synthetic_reply_method_errno(m, r, NULL);
664 return synthetic_reply_method_return(m, "u", (uint32_t) creds->uid);
666 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
667 sd_id128_t server_id;
668 char buf[SD_ID128_STRING_MAX];
670 r = sd_bus_get_server_id(a, &server_id);
672 return synthetic_reply_method_errno(m, r, NULL);
674 return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
676 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
678 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
679 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
681 r = sd_bus_message_read(m, "s", &name);
683 return synthetic_reply_method_errno(m, r, NULL);
685 if (streq(name, "org.freedesktop.DBus"))
686 return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
688 r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
690 return synthetic_reply_method_errno(m, r, &error);
692 return synthetic_reply_method_return(m, "s", creds->unique_name);
694 /* "Hello" is handled in process_hello() */
696 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
697 _cleanup_strv_free_ char **names = NULL;
699 r = sd_bus_list_names(a, NULL, &names);
701 return synthetic_reply_method_errno(m, r, NULL);
703 /* Let's sort the names list to make it stable */
706 return synthetic_reply_return_strv(m, names);
708 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
709 _cleanup_strv_free_ char **names = NULL;
711 r = sd_bus_list_names(a, &names, NULL);
713 return synthetic_reply_method_errno(m, r, NULL);
715 r = strv_extend(&names, "org.freedesktop.DBus");
717 return synthetic_reply_method_errno(m, r, NULL);
719 /* Let's sort the names list to make it stable */
722 return synthetic_reply_return_strv(m, names);
724 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
725 struct kdbus_cmd_name_list cmd = {};
726 struct kdbus_name_list *name_list;
727 struct kdbus_cmd_name *name;
728 _cleanup_strv_free_ char **owners = NULL;
732 r = sd_bus_message_read(m, "s", &arg0);
734 return synthetic_reply_method_errno(m, r, NULL);
736 if (service_name_is_valid(arg0) < 0)
737 return synthetic_reply_method_errno(m, -EINVAL, NULL);
739 cmd.flags = KDBUS_NAME_LIST_QUEUED;
740 r = ioctl(a->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
742 return synthetic_reply_method_errno(m, -errno, NULL);
744 name_list = (struct kdbus_name_list *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
746 KDBUS_ITEM_FOREACH(name, name_list, names) {
749 if (name->size <= sizeof(*name))
752 if (!streq(name->name, arg0))
755 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
760 r = strv_consume(&owners, n);
767 r = ioctl(a->input_fd, KDBUS_CMD_FREE, &cmd.offset);
769 return synthetic_reply_method_errno(m, r, NULL);
772 return synthetic_reply_method_errno(m, err, NULL);
774 return synthetic_reply_return_strv(m, owners);
776 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
779 r = sd_bus_message_read(m, "s", &name);
781 return synthetic_reply_method_errno(m, r, NULL);
783 if (service_name_is_valid(name) < 0)
784 return synthetic_reply_method_errno(m, -EINVAL, NULL);
786 if (streq(name, "org.freedesktop.DBus"))
787 return synthetic_reply_method_return(m, "b", true);
789 r = sd_bus_get_owner(a, name, 0, NULL);
790 if (r < 0 && r != -ESRCH && r != -ENXIO)
791 return synthetic_reply_method_errno(m, r, NULL);
793 return synthetic_reply_method_return(m, "b", r >= 0);
795 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
798 r = sd_bus_message_read(m, "s", &name);
800 return synthetic_reply_method_errno(m, r, NULL);
802 if (service_name_is_valid(name) < 0)
803 return synthetic_reply_method_errno(m, -EINVAL, NULL);
805 r = sd_bus_release_name(a, name);
808 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
809 if (r == -EADDRINUSE)
810 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
812 return synthetic_reply_method_errno(m, r, NULL);
815 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
817 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
818 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
820 r = sd_bus_error_setf(&error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
822 return synthetic_reply_method_errno(m, r, &error);
824 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
828 r = sd_bus_message_read(m, "su", &name, &flags);
830 return synthetic_reply_method_errno(m, r, NULL);
832 if (service_name_is_valid(name) < 0)
833 return synthetic_reply_method_errno(m, -EINVAL, NULL);
834 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
835 return synthetic_reply_method_errno(m, -EINVAL, NULL);
837 r = sd_bus_request_name(a, name, flags);
840 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
842 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
843 return synthetic_reply_method_errno(m, r, NULL);
847 return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
849 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
851 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
852 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
856 r = sd_bus_message_read(m, "su", &name, &flags);
858 return synthetic_reply_method_errno(m, r, NULL);
860 if (service_name_is_valid(name) < 0)
861 return synthetic_reply_method_errno(m, -EINVAL, NULL);
863 return synthetic_reply_method_errno(m, -EINVAL, NULL);
865 r = sd_bus_get_owner(a, name, 0, NULL);
866 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
867 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
869 return synthetic_reply_method_errno(m, r, NULL);
871 r = sd_bus_message_new_method_call(
876 "org.freedesktop.DBus.Peer",
879 return synthetic_reply_method_errno(m, r, NULL);
881 r = sd_bus_send(a, msg, NULL);
883 return synthetic_reply_method_errno(m, r, NULL);
885 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
887 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
888 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
889 _cleanup_strv_free_ char **args = NULL;
891 if (!peer_is_privileged(a, m))
892 return synthetic_reply_method_errno(m, -EPERM, NULL);
894 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
896 return synthetic_reply_method_errno(m, r, NULL);
898 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
899 _cleanup_free_ char *s = NULL;
903 r = sd_bus_message_read(m, "ss", &key, &value);
905 return synthetic_reply_method_errno(m, r, NULL);
907 s = strjoin(key, "=", value, NULL);
909 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
911 r = strv_extend(&args, s);
913 return synthetic_reply_method_errno(m, r, NULL);
915 r = sd_bus_message_exit_container(m);
917 return synthetic_reply_method_errno(m, r, NULL);
920 r = sd_bus_message_exit_container(m);
922 return synthetic_reply_method_errno(m, r, NULL);
925 return synthetic_reply_method_errno(m, -EINVAL, NULL);
927 r = sd_bus_message_new_method_call(
930 "org.freedesktop.systemd1",
931 "/org/freedesktop/systemd1",
932 "org.freedesktop.systemd1.Manager",
935 return synthetic_reply_method_errno(m, r, NULL);
937 r = sd_bus_message_append_strv(msg, args);
939 return synthetic_reply_method_errno(m, r, NULL);
941 r = sd_bus_call(a, msg, 0, NULL, NULL);
943 return synthetic_reply_method_errno(m, r, NULL);
945 return synthetic_reply_method_return(m, NULL);
948 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
950 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
952 return synthetic_reply_method_errno(m, r, &error);
956 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
957 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
966 /* As reaction to hello we need to respond with two messages:
967 * the callback reply and the NameAcquired for the unique
968 * name, since hello is otherwise obsolete on kdbus. */
971 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
972 streq_ptr(m->destination, "org.freedesktop.DBus");
979 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
984 log_error("Got duplicate hello, aborting.");
993 r = sd_bus_message_new_method_return(m, &n);
995 log_error("Failed to generate HELLO reply: %s", strerror(-r));
999 r = sd_bus_message_append(n, "s", a->unique_name);
1001 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
1005 r = bus_message_append_sender(n, "org.freedesktop.DBus");
1007 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
1011 r = bus_seal_synthetic_message(b, n);
1013 log_error("Failed to seal HELLO reply: %s", strerror(-r));
1017 r = sd_bus_send(b, n, NULL);
1019 log_error("Failed to send HELLO reply: %s", strerror(-r));
1023 n = sd_bus_message_unref(n);
1024 r = sd_bus_message_new_signal(
1027 "/org/freedesktop/DBus",
1028 "org.freedesktop.DBus",
1031 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
1035 r = sd_bus_message_append(n, "s", a->unique_name);
1037 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
1041 r = bus_message_append_sender(n, "org.freedesktop.DBus");
1043 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
1047 r = bus_seal_synthetic_message(b, n);
1049 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
1053 r = sd_bus_send(b, n, NULL);
1055 log_error("Failed to send NameAcquired message: %s", strerror(-r));
1062 static int patch_sender(sd_bus *a, sd_bus_message *m) {
1063 char **well_known = NULL;
1073 /* We will change the sender of messages from the bus driver
1074 * so that they originate from the bus driver. This is a
1075 * speciality originating from dbus1, where the bus driver did
1076 * not have a unique id, but only the well-known name. */
1078 c = sd_bus_message_get_creds(m);
1082 r = sd_bus_creds_get_well_known_names(c, &well_known);
1086 if (strv_contains(well_known, "org.freedesktop.DBus"))
1087 m->sender = "org.freedesktop.DBus";
1092 int main(int argc, char *argv[]) {
1094 _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
1095 sd_id128_t server_id;
1096 int r, in_fd, out_fd;
1097 bool got_hello = false;
1099 struct ucred ucred = {};
1100 _cleanup_free_ char *peersec = NULL;
1103 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
1104 log_parse_environment();
1107 r = parse_argv(argc, argv);
1111 r = policy_load(&policy, arg_configuration);
1113 log_error("Failed to load policy: %s", strerror(-r));
1117 /* policy_dump(&policy); */
1119 r = sd_listen_fds(0);
1121 in_fd = STDIN_FILENO;
1122 out_fd = STDOUT_FILENO;
1123 } else if (r == 1) {
1124 in_fd = SD_LISTEN_FDS_START;
1125 out_fd = SD_LISTEN_FDS_START;
1127 log_error("Illegal number of file descriptors passed");
1132 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
1133 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
1136 getpeercred(in_fd, &ucred);
1137 getpeersec(in_fd, &peersec);
1140 if (arg_drop_privileges) {
1141 const char *user = "systemd-bus-proxy";
1145 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
1147 log_error("Cannot resolve user name %s: %s", user, strerror(-r));
1151 r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
1158 log_error("Failed to allocate bus: %s", strerror(-r));
1162 r = sd_bus_set_name(a, "sd-proxy");
1164 log_error("Failed to set bus name: %s", strerror(-r));
1168 r = sd_bus_set_address(a, arg_address);
1170 log_error("Failed to set address to connect to: %s", strerror(-r));
1174 r = sd_bus_negotiate_fds(a, is_unix);
1176 log_error("Failed to set FD negotiation: %s", strerror(-r));
1180 if (ucred.pid > 0) {
1181 a->fake_creds.pid = ucred.pid;
1182 a->fake_creds.uid = ucred.uid;
1183 a->fake_creds.gid = ucred.gid;
1184 a->fake_creds_valid = true;
1188 a->fake_label = peersec;
1192 a->manual_peer_interface = true;
1194 r = sd_bus_start(a);
1196 log_error("Failed to start bus client: %s", strerror(-r));
1200 r = sd_bus_get_server_id(a, &server_id);
1202 log_error("Failed to get server ID: %s", strerror(-r));
1208 log_error("Failed to allocate bus: %s", strerror(-r));
1212 r = sd_bus_set_fd(b, in_fd, out_fd);
1214 log_error("Failed to set fds: %s", strerror(-r));
1218 r = sd_bus_set_server(b, 1, server_id);
1220 log_error("Failed to set server mode: %s", strerror(-r));
1224 r = sd_bus_negotiate_fds(b, is_unix);
1226 log_error("Failed to set FD negotiation: %s", strerror(-r));
1230 r = sd_bus_set_anonymous(b, true);
1232 log_error("Failed to set anonymous authentication: %s", strerror(-r));
1236 b->manual_peer_interface = true;
1238 r = sd_bus_start(b);
1240 log_error("Failed to start bus client: %s", strerror(-r));
1244 r = rename_service(a, b);
1246 log_debug("Failed to rename process: %s", strerror(-r));
1249 _cleanup_free_ char *match = NULL;
1252 r = sd_bus_get_unique_name(a, &unique);
1254 log_error("Failed to get unique name: %s", strerror(-r));
1258 match = strjoin("type='signal',"
1259 "sender='org.freedesktop.DBus',"
1260 "path='/org/freedesktop/DBus',"
1261 "interface='org.freedesktop.DBus',"
1262 "member='NameOwnerChanged',"
1272 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1274 log_error("Failed to add match for NameLost: %s", strerror(-r));
1279 match = strjoin("type='signal',"
1280 "sender='org.freedesktop.DBus',"
1281 "path='/org/freedesktop/DBus',"
1282 "interface='org.freedesktop.DBus',"
1283 "member='NameOwnerChanged',"
1293 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1295 log_error("Failed to add match for NameAcquired: %s", strerror(-r));
1301 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1302 int events_a, events_b, fd;
1303 uint64_t timeout_a, timeout_b, t;
1304 struct timespec _ts, *ts;
1305 struct pollfd *pollfd;
1309 r = sd_bus_process(a, &m);
1311 /* treat 'connection reset by peer' as clean exit condition */
1312 if (r == -ECONNRESET)
1315 log_error("Failed to process bus a: %s", strerror(-r));
1321 /* We officially got EOF, let's quit */
1322 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1327 k = synthesize_name_acquired(a, b, m);
1330 log_error("Failed to synthesize message: %s", strerror(-r));
1336 k = sd_bus_send(b, m, NULL);
1338 if (k == -ECONNRESET)
1342 log_error("Failed to send message: %s", strerror(-r));
1353 r = sd_bus_process(b, &m);
1355 /* treat 'connection reset by peer' as clean exit condition */
1356 if (r == -ECONNRESET)
1359 log_error("Failed to process bus b: %s", strerror(-r));
1365 /* We officially got EOF, let's quit */
1366 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1371 k = process_hello(a, b, m, &got_hello);
1374 log_error("Failed to process HELLO: %s", strerror(-r));
1381 k = process_policy(a, b, m);
1384 log_error("Failed to process policy: %s", strerror(-r));
1388 k = process_driver(a, b, m);
1391 log_error("Failed to process driver calls: %s", strerror(-r));
1398 k = sd_bus_send(a, m, NULL);
1400 if (r == -ECONNRESET)
1404 log_error("Failed to send message: %s", strerror(-r));
1416 fd = sd_bus_get_fd(a);
1418 log_error("Failed to get fd: %s", strerror(-r));
1422 events_a = sd_bus_get_events(a);
1424 log_error("Failed to get events mask: %s", strerror(-r));
1428 r = sd_bus_get_timeout(a, &timeout_a);
1430 log_error("Failed to get timeout: %s", strerror(-r));
1434 events_b = sd_bus_get_events(b);
1436 log_error("Failed to get events mask: %s", strerror(-r));
1440 r = sd_bus_get_timeout(b, &timeout_b);
1442 log_error("Failed to get timeout: %s", strerror(-r));
1447 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
1450 if (t == (uint64_t) -1)
1455 nw = now(CLOCK_MONOTONIC);
1461 ts = timespec_store(&_ts, t);
1464 pollfd = (struct pollfd[3]) {
1465 {.fd = fd, .events = events_a, },
1466 {.fd = in_fd, .events = events_b & POLLIN, },
1467 {.fd = out_fd, .events = events_b & POLLOUT, }
1470 r = ppoll(pollfd, 3, ts, NULL);
1472 log_error("ppoll() failed: %m");
1483 policy_free(&policy);
1484 strv_free(arg_configuration);
1487 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;