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");
160 /* If the first command line argument is only "x" characters
161 * we'll write who we are talking to into it, so that "ps" is
163 arg_command_line_buffer = argv[optind];
164 if (argc > optind + 1 || (arg_command_line_buffer && !in_charset(arg_command_line_buffer, "x"))) {
165 log_error("Too many arguments");
170 arg_address = strdup(DEFAULT_SYSTEM_BUS_PATH);
178 static int rename_service(sd_bus *a, sd_bus *b) {
179 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
180 _cleanup_free_ char *p = NULL, *name = NULL;
190 r = sd_bus_get_peer_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM, &creds);
194 r = sd_bus_creds_get_uid(creds, &uid);
198 r = sd_bus_creds_get_pid(creds, &pid);
202 r = sd_bus_creds_get_cmdline(creds, &cmdline);
206 r = sd_bus_creds_get_comm(creds, &comm);
210 name = uid_to_name(uid);
214 p = strv_join(cmdline, " ");
218 /* The status string gets the full command line ... */
220 "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
224 /* ... and the argv line only the short comm */
225 if (arg_command_line_buffer) {
228 m = strlen(arg_command_line_buffer);
229 w = snprintf(arg_command_line_buffer, m,
230 "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
235 memzero(arg_command_line_buffer + w, m - w);
238 log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
246 static int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
247 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
248 const char *name, *old_owner, *new_owner;
255 /* If we get NameOwnerChanged for our own name, we need to
256 * synthesize NameLost/NameAcquired, since socket clients need
257 * that, even though it is obsoleted on kdbus */
262 if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
263 !streq_ptr(m->path, "/org/freedesktop/DBus") ||
264 !streq_ptr(m->sender, "org.freedesktop.DBus"))
267 r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
271 r = sd_bus_message_rewind(m, true);
275 if (streq(old_owner, a->unique_name)) {
277 r = sd_bus_message_new_signal(
280 "/org/freedesktop/DBus",
281 "org.freedesktop.DBus",
284 } else if (streq(new_owner, a->unique_name)) {
286 r = sd_bus_message_new_signal(
289 "/org/freedesktop/DBus",
290 "org.freedesktop.DBus",
298 r = sd_bus_message_append(n, "s", name);
302 r = bus_message_append_sender(n, "org.freedesktop.DBus");
306 r = bus_seal_synthetic_message(b, n);
310 return sd_bus_send(b, n, NULL);
313 static int process_policy(sd_bus *a, sd_bus *b, sd_bus_message *m) {
314 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
324 if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll"))
327 if (!streq_ptr(m->path, "/org/gnome/DisplayManager/Slave"))
330 r = sd_bus_message_new_method_errorf(m, &n, SD_BUS_ERROR_ACCESS_DENIED, "gdm, you are stupid");
334 r = bus_message_append_sender(n, "org.freedesktop.DBus");
336 log_error("Failed to append sender to gdm reply: %s", strerror(-r));
340 r = bus_seal_synthetic_message(b, n);
342 log_error("Failed to seal gdm reply: %s", strerror(-r));
346 r = sd_bus_send(b, n, NULL);
348 log_error("Failed to send gdm reply: %s", strerror(-r));
355 static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
361 r = bus_message_append_sender(m, "org.freedesktop.DBus");
365 r = bus_seal_synthetic_message(b, m);
369 return sd_bus_send(b, m, NULL);
372 static int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
373 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
376 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
379 r = sd_bus_message_new_method_error(call, &m, e);
383 return synthetic_driver_send(call->bus, m);
386 static int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
388 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
390 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
393 if (sd_bus_error_is_set(p))
394 return synthetic_reply_method_error(call, p);
396 sd_bus_error_set_errno(&berror, error);
398 return synthetic_reply_method_error(call, &berror);
401 static int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
402 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
405 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
408 r = sd_bus_message_new_method_return(call, &m);
412 if (!isempty(types)) {
416 r = bus_message_append_ap(m, types, ap);
422 return synthetic_driver_send(call->bus, m);
425 static int synthetic_reply_return_strv(sd_bus_message *call, char **l) {
426 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
429 r = sd_bus_message_new_method_return(call, &m);
431 return synthetic_reply_method_errno(call, r, NULL);
433 r = sd_bus_message_append_strv(m, l);
435 return synthetic_reply_method_errno(call, r, NULL);
437 return synthetic_driver_send(call->bus, m);
440 static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
441 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
448 assert_return(service_name_is_valid(name), -EINVAL);
450 r = sd_bus_get_owner(bus, name, mask, &c);
451 if (r == -ESRCH || r == -ENXIO)
452 return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
456 if ((c->mask & mask) != mask)
465 static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
473 r = sd_bus_message_read(m, "s", &name);
477 return get_creds_by_name(bus, name, mask, _creds, error);
480 static int peer_is_privileged(sd_bus *bus, sd_bus_message *m) {
481 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
485 r = get_creds_by_message(bus, m, SD_BUS_CREDS_UID, &creds, NULL);
489 r = sd_bus_creds_get_uid(creds, &uid);
493 r = sd_bus_creds_has_effective_cap(creds, CAP_SYS_ADMIN);
503 static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
513 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
516 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
517 if (0 && !isempty(sd_bus_message_get_signature(m, true))) {
518 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
520 r = sd_bus_error_setf(&error, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
522 return synthetic_reply_method_errno(m, r, &error);
525 return synthetic_reply_method_return(m, "s",
526 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
527 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
529 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
530 " <method name=\"Introspect\">\n"
531 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
534 " <interface name=\"org.freedesktop.DBus\">\n"
535 " <method name=\"AddMatch\">\n"
536 " <arg type=\"s\" direction=\"in\"/>\n"
538 " <method name=\"RemoveMatch\">\n"
539 " <arg type=\"s\" direction=\"in\"/>\n"
541 " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
542 " <arg type=\"s\" direction=\"in\"/>\n"
543 " <arg type=\"ay\" direction=\"out\"/>\n"
545 " <method name=\"GetConnectionUnixProcessID\">\n"
546 " <arg type=\"s\" direction=\"in\"/>\n"
547 " <arg type=\"u\" direction=\"out\"/>\n"
549 " <method name=\"GetConnectionUnixUser\">\n"
550 " <arg type=\"s\" direction=\"in\"/>\n"
551 " <arg type=\"u\" direction=\"out\"/>\n"
553 " <method name=\"GetId\">\n"
554 " <arg type=\"s\" direction=\"out\"/>\n"
556 " <method name=\"GetNameOwner\">\n"
557 " <arg type=\"s\" direction=\"in\"/>\n"
558 " <arg type=\"s\" direction=\"out\"/>\n"
560 " <method name=\"Hello\">\n"
561 " <arg type=\"s\" direction=\"out\"/>\n"
563 " <method name=\"ListActivatableNames\">\n"
564 " <arg type=\"as\" direction=\"out\"/>\n"
566 " <method name=\"ListNames\">\n"
567 " <arg type=\"as\" direction=\"out\"/>\n"
569 " <method name=\"ListQueuedOwners\">\n"
570 " <arg type=\"s\" direction=\"in\"/>\n"
571 " <arg type=\"as\" direction=\"out\"/>\n"
573 " <method name=\"NameHasOwner\">\n"
574 " <arg type=\"s\" direction=\"in\"/>\n"
575 " <arg type=\"b\" direction=\"out\"/>\n"
577 " <method name=\"ReleaseName\">\n"
578 " <arg type=\"s\" direction=\"in\"/>\n"
579 " <arg type=\"u\" direction=\"out\"/>\n"
581 " <method name=\"ReloadConfig\">\n"
583 " <method name=\"RequestName\">\n"
584 " <arg type=\"s\" direction=\"in\"/>\n"
585 " <arg type=\"u\" direction=\"in\"/>\n"
586 " <arg type=\"u\" direction=\"out\"/>\n"
588 " <method name=\"StartServiceByName\">\n"
589 " <arg type=\"s\" direction=\"in\"/>\n"
590 " <arg type=\"u\" direction=\"in\"/>\n"
591 " <arg type=\"u\" direction=\"out\"/>\n"
593 " <method name=\"UpdateActivationEnvironment\">\n"
594 " <arg type=\"a{ss}\" direction=\"in\"/>\n"
596 " <signal name=\"NameAcquired\">\n"
597 " <arg type=\"s\"/>\n"
599 " <signal name=\"NameLost\">\n"
600 " <arg type=\"s\"/>\n"
602 " <signal name=\"NameOwnerChanged\">\n"
603 " <arg type=\"s\"/>\n"
604 " <arg type=\"s\"/>\n"
605 " <arg type=\"s\"/>\n"
610 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
613 r = sd_bus_message_read(m, "s", &match);
615 return synthetic_reply_method_errno(m, r, NULL);
617 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
619 return synthetic_reply_method_errno(m, r, NULL);
621 return synthetic_reply_method_return(m, NULL);
623 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
626 r = sd_bus_message_read(m, "s", &match);
628 return synthetic_reply_method_errno(m, r, NULL);
630 r = bus_remove_match_by_string(a, match, NULL, NULL);
632 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
634 return synthetic_reply_method_errno(m, r, NULL);
636 return synthetic_reply_method_return(m, NULL);
638 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
639 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
641 r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, NULL);
643 return synthetic_reply_method_errno(m, r, NULL);
645 return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
647 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
648 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
650 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, NULL);
652 return synthetic_reply_method_errno(m, r, NULL);
654 return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
656 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
657 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
659 r = get_creds_by_message(a, m, SD_BUS_CREDS_UID, &creds, NULL);
661 return synthetic_reply_method_errno(m, r, NULL);
663 return synthetic_reply_method_return(m, "u", (uint32_t) creds->uid);
665 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
666 sd_id128_t server_id;
667 char buf[SD_ID128_STRING_MAX];
669 r = sd_bus_get_server_id(a, &server_id);
671 return synthetic_reply_method_errno(m, r, NULL);
673 return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
675 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
677 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
678 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
680 r = sd_bus_message_read(m, "s", &name);
682 return synthetic_reply_method_errno(m, r, NULL);
684 if (streq(name, "org.freedesktop.DBus"))
685 return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
687 r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
689 return synthetic_reply_method_errno(m, r, &error);
691 return synthetic_reply_method_return(m, "s", creds->unique_name);
693 /* "Hello" is handled in process_hello() */
695 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
696 _cleanup_strv_free_ char **names = NULL;
698 r = sd_bus_list_names(a, NULL, &names);
700 return synthetic_reply_method_errno(m, r, NULL);
702 /* Let's sort the names list to make it stable */
705 return synthetic_reply_return_strv(m, names);
707 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
708 _cleanup_strv_free_ char **names = NULL;
710 r = sd_bus_list_names(a, &names, NULL);
712 return synthetic_reply_method_errno(m, r, NULL);
714 r = strv_extend(&names, "org.freedesktop.DBus");
716 return synthetic_reply_method_errno(m, r, NULL);
718 /* Let's sort the names list to make it stable */
721 return synthetic_reply_return_strv(m, names);
723 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
724 struct kdbus_cmd_name_list cmd = {};
725 struct kdbus_name_list *name_list;
726 struct kdbus_cmd_name *name;
727 _cleanup_strv_free_ char **owners = NULL;
731 r = sd_bus_message_read(m, "s", &arg0);
733 return synthetic_reply_method_errno(m, r, NULL);
735 if (!service_name_is_valid(arg0))
736 return synthetic_reply_method_errno(m, -EINVAL, NULL);
738 cmd.flags = KDBUS_NAME_LIST_QUEUED;
739 r = ioctl(a->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
741 return synthetic_reply_method_errno(m, -errno, NULL);
743 name_list = (struct kdbus_name_list *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
745 KDBUS_ITEM_FOREACH(name, name_list, names) {
748 if (name->size <= sizeof(*name))
751 if (!streq(name->name, arg0))
754 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
759 r = strv_consume(&owners, n);
766 r = ioctl(a->input_fd, KDBUS_CMD_FREE, &cmd.offset);
768 return synthetic_reply_method_errno(m, r, NULL);
771 return synthetic_reply_method_errno(m, err, NULL);
773 return synthetic_reply_return_strv(m, owners);
775 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
778 r = sd_bus_message_read(m, "s", &name);
780 return synthetic_reply_method_errno(m, r, NULL);
782 if (!service_name_is_valid(name))
783 return synthetic_reply_method_errno(m, -EINVAL, NULL);
785 if (streq(name, "org.freedesktop.DBus"))
786 return synthetic_reply_method_return(m, "b", true);
788 r = sd_bus_get_owner(a, name, 0, NULL);
789 if (r < 0 && r != -ESRCH && r != -ENXIO)
790 return synthetic_reply_method_errno(m, r, NULL);
792 return synthetic_reply_method_return(m, "b", r >= 0);
794 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
797 r = sd_bus_message_read(m, "s", &name);
799 return synthetic_reply_method_errno(m, r, NULL);
801 if (!service_name_is_valid(name))
802 return synthetic_reply_method_errno(m, -EINVAL, NULL);
804 r = sd_bus_release_name(a, name);
807 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
808 if (r == -EADDRINUSE)
809 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
811 return synthetic_reply_method_errno(m, r, NULL);
814 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
816 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
817 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
819 r = sd_bus_error_setf(&error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
821 return synthetic_reply_method_errno(m, r, &error);
823 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
827 r = sd_bus_message_read(m, "su", &name, &flags);
829 return synthetic_reply_method_errno(m, r, NULL);
831 if (!service_name_is_valid(name))
832 return synthetic_reply_method_errno(m, -EINVAL, NULL);
833 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
834 return synthetic_reply_method_errno(m, -EINVAL, NULL);
836 r = sd_bus_request_name(a, name, flags);
839 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
841 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
842 return synthetic_reply_method_errno(m, r, NULL);
846 return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
848 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
850 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
851 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
855 r = sd_bus_message_read(m, "su", &name, &flags);
857 return synthetic_reply_method_errno(m, r, NULL);
859 if (!service_name_is_valid(name))
860 return synthetic_reply_method_errno(m, -EINVAL, NULL);
862 return synthetic_reply_method_errno(m, -EINVAL, NULL);
864 r = sd_bus_get_owner(a, name, 0, NULL);
865 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
866 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
868 return synthetic_reply_method_errno(m, r, NULL);
870 r = sd_bus_message_new_method_call(
875 "org.freedesktop.DBus.Peer",
878 return synthetic_reply_method_errno(m, r, NULL);
880 r = sd_bus_send(a, msg, NULL);
882 return synthetic_reply_method_errno(m, r, NULL);
884 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
886 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
887 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
888 _cleanup_strv_free_ char **args = NULL;
890 if (!peer_is_privileged(a, m))
891 return synthetic_reply_method_errno(m, -EPERM, NULL);
893 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
895 return synthetic_reply_method_errno(m, r, NULL);
897 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
898 _cleanup_free_ char *s = NULL;
902 r = sd_bus_message_read(m, "ss", &key, &value);
904 return synthetic_reply_method_errno(m, r, NULL);
906 s = strjoin(key, "=", value, NULL);
908 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
910 r = strv_extend(&args, s);
912 return synthetic_reply_method_errno(m, r, NULL);
914 r = sd_bus_message_exit_container(m);
916 return synthetic_reply_method_errno(m, r, NULL);
919 r = sd_bus_message_exit_container(m);
921 return synthetic_reply_method_errno(m, r, NULL);
924 return synthetic_reply_method_errno(m, -EINVAL, NULL);
926 r = sd_bus_message_new_method_call(
929 "org.freedesktop.systemd1",
930 "/org/freedesktop/systemd1",
931 "org.freedesktop.systemd1.Manager",
934 return synthetic_reply_method_errno(m, r, NULL);
936 r = sd_bus_message_append_strv(msg, args);
938 return synthetic_reply_method_errno(m, r, NULL);
940 r = sd_bus_call(a, msg, 0, NULL, NULL);
942 return synthetic_reply_method_errno(m, r, NULL);
944 return synthetic_reply_method_return(m, NULL);
947 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
949 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
951 return synthetic_reply_method_errno(m, r, &error);
955 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
956 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
965 /* As reaction to hello we need to respond with two messages:
966 * the callback reply and the NameAcquired for the unique
967 * name, since hello is otherwise obsolete on kdbus. */
970 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
971 streq_ptr(m->destination, "org.freedesktop.DBus");
978 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
983 log_error("Got duplicate hello, aborting.");
992 r = sd_bus_message_new_method_return(m, &n);
994 log_error("Failed to generate HELLO reply: %s", strerror(-r));
998 r = sd_bus_message_append(n, "s", a->unique_name);
1000 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
1004 r = bus_message_append_sender(n, "org.freedesktop.DBus");
1006 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
1010 r = bus_seal_synthetic_message(b, n);
1012 log_error("Failed to seal HELLO reply: %s", strerror(-r));
1016 r = sd_bus_send(b, n, NULL);
1018 log_error("Failed to send HELLO reply: %s", strerror(-r));
1022 n = sd_bus_message_unref(n);
1023 r = sd_bus_message_new_signal(
1026 "/org/freedesktop/DBus",
1027 "org.freedesktop.DBus",
1030 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
1034 r = sd_bus_message_append(n, "s", a->unique_name);
1036 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
1040 r = bus_message_append_sender(n, "org.freedesktop.DBus");
1042 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
1046 r = bus_seal_synthetic_message(b, n);
1048 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
1052 r = sd_bus_send(b, n, NULL);
1054 log_error("Failed to send NameAcquired message: %s", strerror(-r));
1061 static int patch_sender(sd_bus *a, sd_bus_message *m) {
1062 char **well_known = NULL;
1072 /* We will change the sender of messages from the bus driver
1073 * so that they originate from the bus driver. This is a
1074 * speciality originating from dbus1, where the bus driver did
1075 * not have a unique id, but only the well-known name. */
1077 c = sd_bus_message_get_creds(m);
1081 r = sd_bus_creds_get_well_known_names(c, &well_known);
1085 if (strv_contains(well_known, "org.freedesktop.DBus"))
1086 m->sender = "org.freedesktop.DBus";
1091 int main(int argc, char *argv[]) {
1093 _cleanup_bus_close_unref_ sd_bus *a = NULL, *b = NULL;
1094 sd_id128_t server_id;
1095 int r, in_fd, out_fd;
1096 bool got_hello = false;
1098 struct ucred ucred = {};
1099 _cleanup_free_ char *peersec = NULL;
1102 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
1103 log_parse_environment();
1106 r = parse_argv(argc, argv);
1110 r = policy_load(&policy, arg_configuration);
1112 log_error("Failed to load policy: %s", strerror(-r));
1116 /* policy_dump(&policy); */
1118 r = sd_listen_fds(0);
1120 in_fd = STDIN_FILENO;
1121 out_fd = STDOUT_FILENO;
1122 } else if (r == 1) {
1123 in_fd = SD_LISTEN_FDS_START;
1124 out_fd = SD_LISTEN_FDS_START;
1126 log_error("Illegal number of file descriptors passed");
1131 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
1132 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
1135 getpeercred(in_fd, &ucred);
1136 getpeersec(in_fd, &peersec);
1139 if (arg_drop_privileges) {
1140 const char *user = "systemd-bus-proxy";
1144 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
1146 log_error("Cannot resolve user name %s: %s", user, strerror(-r));
1150 r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
1157 log_error("Failed to allocate bus: %s", strerror(-r));
1161 r = sd_bus_set_name(a, "sd-proxy");
1163 log_error("Failed to set bus name: %s", strerror(-r));
1167 r = sd_bus_set_address(a, arg_address);
1169 log_error("Failed to set address to connect to: %s", strerror(-r));
1173 r = sd_bus_negotiate_fds(a, is_unix);
1175 log_error("Failed to set FD negotiation: %s", strerror(-r));
1179 if (ucred.pid > 0) {
1180 a->fake_creds.pid = ucred.pid;
1181 a->fake_creds.uid = ucred.uid;
1182 a->fake_creds.gid = ucred.gid;
1183 a->fake_creds_valid = true;
1187 a->fake_label = peersec;
1191 a->manual_peer_interface = true;
1193 r = sd_bus_start(a);
1195 log_error("Failed to start bus client: %s", strerror(-r));
1199 r = sd_bus_get_server_id(a, &server_id);
1201 log_error("Failed to get server ID: %s", strerror(-r));
1207 log_error("Failed to allocate bus: %s", strerror(-r));
1211 r = sd_bus_set_fd(b, in_fd, out_fd);
1213 log_error("Failed to set fds: %s", strerror(-r));
1217 r = sd_bus_set_server(b, 1, server_id);
1219 log_error("Failed to set server mode: %s", strerror(-r));
1223 r = sd_bus_negotiate_fds(b, is_unix);
1225 log_error("Failed to set FD negotiation: %s", strerror(-r));
1229 r = sd_bus_set_anonymous(b, true);
1231 log_error("Failed to set anonymous authentication: %s", strerror(-r));
1235 b->manual_peer_interface = true;
1237 r = sd_bus_start(b);
1239 log_error("Failed to start bus client: %s", strerror(-r));
1243 r = rename_service(a, b);
1245 log_debug("Failed to rename process: %s", strerror(-r));
1248 _cleanup_free_ char *match = NULL;
1251 r = sd_bus_get_unique_name(a, &unique);
1253 log_error("Failed to get unique name: %s", strerror(-r));
1257 match = strjoin("type='signal',"
1258 "sender='org.freedesktop.DBus',"
1259 "path='/org/freedesktop/DBus',"
1260 "interface='org.freedesktop.DBus',"
1261 "member='NameOwnerChanged',"
1271 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1273 log_error("Failed to add match for NameLost: %s", strerror(-r));
1278 match = strjoin("type='signal',"
1279 "sender='org.freedesktop.DBus',"
1280 "path='/org/freedesktop/DBus',"
1281 "interface='org.freedesktop.DBus',"
1282 "member='NameOwnerChanged',"
1292 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1294 log_error("Failed to add match for NameAcquired: %s", strerror(-r));
1300 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1301 int events_a, events_b, fd;
1302 uint64_t timeout_a, timeout_b, t;
1303 struct timespec _ts, *ts;
1304 struct pollfd *pollfd;
1308 r = sd_bus_process(a, &m);
1310 /* treat 'connection reset by peer' as clean exit condition */
1311 if (r == -ECONNRESET)
1314 log_error("Failed to process bus a: %s", strerror(-r));
1320 /* We officially got EOF, let's quit */
1321 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1326 k = synthesize_name_acquired(a, b, m);
1329 log_error("Failed to synthesize message: %s", strerror(-r));
1335 k = sd_bus_send(b, m, NULL);
1337 if (k == -ECONNRESET)
1341 log_error("Failed to send message: %s", strerror(-r));
1352 r = sd_bus_process(b, &m);
1354 /* treat 'connection reset by peer' as clean exit condition */
1355 if (r == -ECONNRESET)
1358 log_error("Failed to process bus b: %s", strerror(-r));
1364 /* We officially got EOF, let's quit */
1365 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1370 k = process_hello(a, b, m, &got_hello);
1373 log_error("Failed to process HELLO: %s", strerror(-r));
1380 k = process_policy(a, b, m);
1383 log_error("Failed to process policy: %s", strerror(-r));
1387 k = process_driver(a, b, m);
1390 log_error("Failed to process driver calls: %s", strerror(-r));
1397 k = sd_bus_send(a, m, NULL);
1399 if (k == -ECONNRESET)
1403 log_error("Failed to send message: %s", strerror(-r));
1415 fd = sd_bus_get_fd(a);
1417 log_error("Failed to get fd: %s", strerror(-r));
1421 events_a = sd_bus_get_events(a);
1423 log_error("Failed to get events mask: %s", strerror(-r));
1427 r = sd_bus_get_timeout(a, &timeout_a);
1429 log_error("Failed to get timeout: %s", strerror(-r));
1433 events_b = sd_bus_get_events(b);
1435 log_error("Failed to get events mask: %s", strerror(-r));
1439 r = sd_bus_get_timeout(b, &timeout_b);
1441 log_error("Failed to get timeout: %s", strerror(-r));
1446 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
1449 if (t == (uint64_t) -1)
1454 nw = now(CLOCK_MONOTONIC);
1460 ts = timespec_store(&_ts, t);
1463 pollfd = (struct pollfd[3]) {
1464 {.fd = fd, .events = events_a, },
1465 {.fd = in_fd, .events = events_b & POLLIN, },
1466 {.fd = out_fd, .events = events_b & POLLOUT, }
1469 r = ppoll(pollfd, 3, ts, NULL);
1471 log_error("ppoll() failed: %m");
1479 "STATUS=Shutting down.");
1481 policy_free(&policy);
1482 strv_free(arg_configuration);
1485 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;