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 Hashmap *names_hash = NULL;
56 static int help(void) {
58 printf("%s [OPTIONS...]\n\n"
59 "Connect STDIO or a socket to a given bus address.\n\n"
60 " -h --help Show this help\n"
61 " --version Show package version\n"
62 " --drop-privileges Drop privileges\n"
63 " --configuration=PATH Configuration file or directory\n"
64 " --machine=MACHINE Connect to specified machine\n"
65 " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
66 " (default: " DEFAULT_SYSTEM_BUS_PATH ")\n",
67 program_invocation_short_name);
72 static int parse_argv(int argc, char *argv[]) {
82 static const struct option options[] = {
83 { "help", no_argument, NULL, 'h' },
84 { "version", no_argument, NULL, ARG_VERSION },
85 { "address", required_argument, NULL, ARG_ADDRESS },
86 { "drop-privileges", no_argument, NULL, ARG_DROP_PRIVILEGES },
87 { "configuration", required_argument, NULL, ARG_CONFIGURATION },
88 { "machine", required_argument, NULL, ARG_MACHINE },
97 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
106 puts(PACKAGE_STRING);
107 puts(SYSTEMD_FEATURES);
122 case ARG_DROP_PRIVILEGES:
123 arg_drop_privileges = true;
126 case ARG_CONFIGURATION:
127 r = strv_extend(&arg_configuration, optarg);
133 _cleanup_free_ char *e = NULL;
136 e = bus_address_escape(optarg);
141 a = strjoin("x-container-kernel:machine=", e, ";x-container-unix:machine=", e, NULL);
143 a = strjoin("x-container-unix:machine=", e, NULL);
158 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_owner_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 synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
320 r = bus_message_append_sender(m, "org.freedesktop.DBus");
324 r = bus_seal_synthetic_message(b, m);
328 return sd_bus_send(b, m, NULL);
331 static int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
332 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
337 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
340 r = sd_bus_message_new_method_error(call, &m, e);
344 return synthetic_driver_send(call->bus, m);
347 static int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
349 _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;
370 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
373 r = sd_bus_message_new_method_return(call, &m);
377 if (!isempty(types)) {
381 r = bus_message_append_ap(m, types, ap);
387 return synthetic_driver_send(call->bus, m);
390 static int synthetic_reply_return_strv(sd_bus_message *call, char **l) {
391 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
396 r = sd_bus_message_new_method_return(call, &m);
398 return synthetic_reply_method_errno(call, r, NULL);
400 r = sd_bus_message_append_strv(m, l);
402 return synthetic_reply_method_errno(call, r, NULL);
404 return synthetic_driver_send(call->bus, m);
407 static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
408 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
415 assert_return(service_name_is_valid(name), -EINVAL);
417 r = sd_bus_get_name_creds(bus, name, mask, &c);
418 if (r == -ESRCH || r == -ENXIO)
419 return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
423 if ((c->mask & mask) != mask)
432 static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
440 r = sd_bus_message_read(m, "s", &name);
444 return get_creds_by_name(bus, name, mask, _creds, error);
447 static int peer_is_privileged(sd_bus *bus, sd_bus_message *m) {
448 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
452 r = get_creds_by_message(bus, m, SD_BUS_CREDS_UID, &creds, NULL);
456 r = sd_bus_creds_get_uid(creds, &uid);
460 r = sd_bus_creds_has_effective_cap(creds, CAP_SYS_ADMIN);
470 static int process_policy(sd_bus *a, sd_bus *b, sd_bus_message *m, Policy *policy, const struct ucred *ucred) {
474 bool granted = false;
486 /* The message came from the kernel, and is sent to our legacy client. */
487 r = sd_bus_creds_get_well_known_names(&m->creds, &names_strv);
491 STRV_FOREACH(name, names_strv) {
492 if (policy_check_send(policy, ucred, m->header->type, *name, m->path, m->interface, m->member)) {
493 r = free_and_strdup(&m->destination_ptr, *name);
510 HASHMAP_FOREACH(name, names_hash, i) {
511 if (policy_check_recv(policy, ucred, m->header->type, *name, m->path, m->interface, m->member))
517 sd_bus_creds *bus_creds;
519 /* The message came from the legacy client, and is sent to kdbus. */
520 r = sd_bus_get_name_creds(a, m->destination, SD_BUS_CREDS_WELL_KNOWN_NAMES, &bus_creds);
524 STRV_FOREACH(name, names_strv) {
525 if (policy_check_send(policy, ucred, m->header->type, *name, m->path, m->interface, m->member)) {
526 r = free_and_strdup(&m->destination_ptr, *name);
530 r = bus_kernel_parse_unique_name(m->sender, &m->verify_destination_id);
547 HASHMAP_FOREACH(name, names_hash, i) {
548 if (policy_check_recv(policy, ucred, m->header->type, *name, m->path, m->interface, m->member))
558 static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, Policy *policy, const struct ucred *ucred) {
568 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
571 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
572 if (0 && !isempty(sd_bus_message_get_signature(m, true))) {
573 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
575 r = sd_bus_error_setf(&error, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
577 return synthetic_reply_method_errno(m, r, &error);
580 return synthetic_reply_method_return(m, "s",
581 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
582 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
584 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
585 " <method name=\"Introspect\">\n"
586 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
589 " <interface name=\"org.freedesktop.DBus\">\n"
590 " <method name=\"AddMatch\">\n"
591 " <arg type=\"s\" direction=\"in\"/>\n"
593 " <method name=\"RemoveMatch\">\n"
594 " <arg type=\"s\" direction=\"in\"/>\n"
596 " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
597 " <arg type=\"s\" direction=\"in\"/>\n"
598 " <arg type=\"ay\" direction=\"out\"/>\n"
600 " <method name=\"GetConnectionUnixProcessID\">\n"
601 " <arg type=\"s\" direction=\"in\"/>\n"
602 " <arg type=\"u\" direction=\"out\"/>\n"
604 " <method name=\"GetConnectionUnixUser\">\n"
605 " <arg type=\"s\" direction=\"in\"/>\n"
606 " <arg type=\"u\" direction=\"out\"/>\n"
608 " <method name=\"GetId\">\n"
609 " <arg type=\"s\" direction=\"out\"/>\n"
611 " <method name=\"GetNameOwner\">\n"
612 " <arg type=\"s\" direction=\"in\"/>\n"
613 " <arg type=\"s\" direction=\"out\"/>\n"
615 " <method name=\"Hello\">\n"
616 " <arg type=\"s\" direction=\"out\"/>\n"
618 " <method name=\"ListActivatableNames\">\n"
619 " <arg type=\"as\" direction=\"out\"/>\n"
621 " <method name=\"ListNames\">\n"
622 " <arg type=\"as\" direction=\"out\"/>\n"
624 " <method name=\"ListQueuedOwners\">\n"
625 " <arg type=\"s\" direction=\"in\"/>\n"
626 " <arg type=\"as\" direction=\"out\"/>\n"
628 " <method name=\"NameHasOwner\">\n"
629 " <arg type=\"s\" direction=\"in\"/>\n"
630 " <arg type=\"b\" direction=\"out\"/>\n"
632 " <method name=\"ReleaseName\">\n"
633 " <arg type=\"s\" direction=\"in\"/>\n"
634 " <arg type=\"u\" direction=\"out\"/>\n"
636 " <method name=\"ReloadConfig\">\n"
638 " <method name=\"RequestName\">\n"
639 " <arg type=\"s\" direction=\"in\"/>\n"
640 " <arg type=\"u\" direction=\"in\"/>\n"
641 " <arg type=\"u\" direction=\"out\"/>\n"
643 " <method name=\"StartServiceByName\">\n"
644 " <arg type=\"s\" direction=\"in\"/>\n"
645 " <arg type=\"u\" direction=\"in\"/>\n"
646 " <arg type=\"u\" direction=\"out\"/>\n"
648 " <method name=\"UpdateActivationEnvironment\">\n"
649 " <arg type=\"a{ss}\" direction=\"in\"/>\n"
651 " <signal name=\"NameAcquired\">\n"
652 " <arg type=\"s\"/>\n"
654 " <signal name=\"NameLost\">\n"
655 " <arg type=\"s\"/>\n"
657 " <signal name=\"NameOwnerChanged\">\n"
658 " <arg type=\"s\"/>\n"
659 " <arg type=\"s\"/>\n"
660 " <arg type=\"s\"/>\n"
665 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
668 r = sd_bus_message_read(m, "s", &match);
670 return synthetic_reply_method_errno(m, r, NULL);
672 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
674 return synthetic_reply_method_errno(m, r, NULL);
676 return synthetic_reply_method_return(m, NULL);
678 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
681 r = sd_bus_message_read(m, "s", &match);
683 return synthetic_reply_method_errno(m, r, NULL);
685 r = bus_remove_match_by_string(a, match, NULL, NULL);
687 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
689 return synthetic_reply_method_errno(m, r, NULL);
691 return synthetic_reply_method_return(m, NULL);
693 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
694 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
695 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
697 r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error);
699 return synthetic_reply_method_errno(m, r, &error);
701 return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
703 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
704 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
705 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
707 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, &error);
709 return synthetic_reply_method_errno(m, r, &error);
711 return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
713 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
714 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
715 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
717 r = get_creds_by_message(a, m, SD_BUS_CREDS_UID, &creds, &error);
719 return synthetic_reply_method_errno(m, r, &error);
721 return synthetic_reply_method_return(m, "u", (uint32_t) creds->uid);
723 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
724 sd_id128_t server_id;
725 char buf[SD_ID128_STRING_MAX];
727 r = sd_bus_get_owner_id(a, &server_id);
729 return synthetic_reply_method_errno(m, r, NULL);
731 return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
733 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
735 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
736 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
738 r = sd_bus_message_read(m, "s", &name);
740 return synthetic_reply_method_errno(m, r, NULL);
742 if (streq(name, "org.freedesktop.DBus"))
743 return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
745 r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
747 return synthetic_reply_method_errno(m, r, &error);
749 return synthetic_reply_method_return(m, "s", creds->unique_name);
751 /* "Hello" is handled in process_hello() */
753 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
754 _cleanup_strv_free_ char **names = NULL;
756 r = sd_bus_list_names(a, NULL, &names);
758 return synthetic_reply_method_errno(m, r, NULL);
760 /* Let's sort the names list to make it stable */
763 return synthetic_reply_return_strv(m, names);
765 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
766 _cleanup_strv_free_ char **names = NULL;
768 r = sd_bus_list_names(a, &names, NULL);
770 return synthetic_reply_method_errno(m, r, NULL);
772 r = strv_extend(&names, "org.freedesktop.DBus");
774 return synthetic_reply_method_errno(m, r, NULL);
776 /* Let's sort the names list to make it stable */
779 return synthetic_reply_return_strv(m, names);
781 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
782 struct kdbus_cmd_name_list cmd = {};
783 struct kdbus_name_list *name_list;
784 struct kdbus_cmd_free cmd_free;
785 struct kdbus_name_info *name;
786 _cleanup_strv_free_ char **owners = NULL;
787 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
791 r = sd_bus_message_read(m, "s", &arg0);
793 return synthetic_reply_method_errno(m, r, NULL);
795 if (!service_name_is_valid(arg0))
796 return synthetic_reply_method_errno(m, -EINVAL, NULL);
798 r = sd_bus_get_name_creds(a, arg0, 0, NULL);
799 if (r == -ESRCH || r == -ENXIO) {
800 sd_bus_error_setf(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name.", arg0);
801 return synthetic_reply_method_errno(m, r, &error);
804 return synthetic_reply_method_errno(m, r, NULL);
806 cmd.flags = KDBUS_NAME_LIST_QUEUED;
807 r = ioctl(a->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
809 return synthetic_reply_method_errno(m, -errno, NULL);
811 name_list = (struct kdbus_name_list *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
813 KDBUS_ITEM_FOREACH(name, name_list, names) {
814 const char *entry_name = NULL;
815 struct kdbus_item *item;
818 KDBUS_ITEM_FOREACH(item, name, items)
819 if (item->type == KDBUS_ITEM_OWNED_NAME)
820 entry_name = item->name.name;
822 if (!streq_ptr(entry_name, arg0))
825 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
830 r = strv_consume(&owners, n);
838 cmd_free.offset = cmd.offset;
840 r = ioctl(a->input_fd, KDBUS_CMD_FREE, &cmd_free);
842 return synthetic_reply_method_errno(m, r, NULL);
845 return synthetic_reply_method_errno(m, err, NULL);
847 return synthetic_reply_return_strv(m, owners);
849 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
852 r = sd_bus_message_read(m, "s", &name);
854 return synthetic_reply_method_errno(m, r, NULL);
856 if (!service_name_is_valid(name))
857 return synthetic_reply_method_errno(m, -EINVAL, NULL);
859 if (streq(name, "org.freedesktop.DBus"))
860 return synthetic_reply_method_return(m, "b", true);
862 r = sd_bus_get_name_creds(a, name, 0, NULL);
863 if (r < 0 && r != -ESRCH && r != -ENXIO)
864 return synthetic_reply_method_errno(m, r, NULL);
866 return synthetic_reply_method_return(m, "b", r >= 0);
868 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
871 r = sd_bus_message_read(m, "s", &name);
873 return synthetic_reply_method_errno(m, r, NULL);
875 if (!service_name_is_valid(name))
876 return synthetic_reply_method_errno(m, -EINVAL, NULL);
878 r = sd_bus_release_name(a, name);
881 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
882 if (r == -EADDRINUSE)
883 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
885 return synthetic_reply_method_errno(m, r, NULL);
888 hashmap_remove(names_hash, name);
890 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
892 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
893 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
895 r = sd_bus_error_setf(&error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
897 return synthetic_reply_method_errno(m, r, &error);
899 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
901 uint32_t flags, param;
904 r = sd_bus_message_read(m, "su", &name, &flags);
906 return synthetic_reply_method_errno(m, r, NULL);
908 if (policy && !policy_check_own(policy, ucred, name))
909 return synthetic_reply_method_errno(m, -EPERM, NULL);
911 if (!service_name_is_valid(name))
912 return synthetic_reply_method_errno(m, -EINVAL, NULL);
913 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
914 return synthetic_reply_method_errno(m, -EINVAL, NULL);
917 if (flags & BUS_NAME_ALLOW_REPLACEMENT)
918 param |= SD_BUS_NAME_ALLOW_REPLACEMENT;
919 if (flags & BUS_NAME_REPLACE_EXISTING)
920 param |= SD_BUS_NAME_REPLACE_EXISTING;
921 if (!(flags & BUS_NAME_DO_NOT_QUEUE))
922 param |= SD_BUS_NAME_QUEUE;
924 r = sd_bus_request_name(a, name, param);
927 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
929 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
930 return synthetic_reply_method_errno(m, r, NULL);
935 r = hashmap_put(names_hash, name, NULL);
937 return synthetic_reply_method_errno(m, r, NULL);
940 return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
942 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
944 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
945 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
949 r = sd_bus_message_read(m, "su", &name, &flags);
951 return synthetic_reply_method_errno(m, r, NULL);
953 if (!service_name_is_valid(name))
954 return synthetic_reply_method_errno(m, -EINVAL, NULL);
956 return synthetic_reply_method_errno(m, -EINVAL, NULL);
958 r = sd_bus_get_name_creds(a, name, 0, NULL);
959 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
960 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
962 return synthetic_reply_method_errno(m, r, NULL);
964 r = sd_bus_message_new_method_call(
969 "org.freedesktop.DBus.Peer",
972 return synthetic_reply_method_errno(m, r, NULL);
974 r = sd_bus_send(a, msg, NULL);
976 return synthetic_reply_method_errno(m, r, NULL);
978 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
980 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
981 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
982 _cleanup_strv_free_ char **args = NULL;
984 if (!peer_is_privileged(a, m))
985 return synthetic_reply_method_errno(m, -EPERM, NULL);
987 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
989 return synthetic_reply_method_errno(m, r, NULL);
991 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
992 _cleanup_free_ char *s = NULL;
996 r = sd_bus_message_read(m, "ss", &key, &value);
998 return synthetic_reply_method_errno(m, r, NULL);
1000 s = strjoin(key, "=", value, NULL);
1002 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
1004 r = strv_extend(&args, s);
1006 return synthetic_reply_method_errno(m, r, NULL);
1008 r = sd_bus_message_exit_container(m);
1010 return synthetic_reply_method_errno(m, r, NULL);
1013 r = sd_bus_message_exit_container(m);
1015 return synthetic_reply_method_errno(m, r, NULL);
1018 return synthetic_reply_method_errno(m, -EINVAL, NULL);
1020 r = sd_bus_message_new_method_call(
1023 "org.freedesktop.systemd1",
1024 "/org/freedesktop/systemd1",
1025 "org.freedesktop.systemd1.Manager",
1028 return synthetic_reply_method_errno(m, r, NULL);
1030 r = sd_bus_message_append_strv(msg, args);
1032 return synthetic_reply_method_errno(m, r, NULL);
1034 r = sd_bus_call(a, msg, 0, NULL, NULL);
1036 return synthetic_reply_method_errno(m, r, NULL);
1038 return synthetic_reply_method_return(m, NULL);
1041 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1043 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
1045 return synthetic_reply_method_errno(m, r, &error);
1049 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, Policy *policy, const struct ucred *ucred, bool *got_hello) {
1050 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
1059 /* As reaction to hello we need to respond with two messages:
1060 * the callback reply and the NameAcquired for the unique
1061 * name, since hello is otherwise obsolete on kdbus. */
1064 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
1065 streq_ptr(m->destination, "org.freedesktop.DBus");
1072 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
1077 log_error("Got duplicate hello, aborting.");
1081 if (policy && !policy_check_hello(policy, ucred)) {
1082 log_error("Policy denied HELLO");
1091 r = sd_bus_message_new_method_return(m, &n);
1093 log_error("Failed to generate HELLO reply: %s", strerror(-r));
1097 r = sd_bus_message_append(n, "s", a->unique_name);
1099 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
1103 r = bus_message_append_sender(n, "org.freedesktop.DBus");
1105 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
1109 r = bus_seal_synthetic_message(b, n);
1111 log_error("Failed to seal HELLO reply: %s", strerror(-r));
1115 r = sd_bus_send(b, n, NULL);
1117 log_error("Failed to send HELLO reply: %s", strerror(-r));
1121 n = sd_bus_message_unref(n);
1122 r = sd_bus_message_new_signal(
1125 "/org/freedesktop/DBus",
1126 "org.freedesktop.DBus",
1129 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
1133 r = sd_bus_message_append(n, "s", a->unique_name);
1135 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
1139 r = bus_message_append_sender(n, "org.freedesktop.DBus");
1141 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
1145 r = bus_seal_synthetic_message(b, n);
1147 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
1151 r = sd_bus_send(b, n, NULL);
1153 log_error("Failed to send NameAcquired message: %s", strerror(-r));
1160 static int patch_sender(sd_bus *a, sd_bus_message *m) {
1161 char **well_known = NULL;
1171 /* We will change the sender of messages from the bus driver
1172 * so that they originate from the bus driver. This is a
1173 * speciality originating from dbus1, where the bus driver did
1174 * not have a unique id, but only the well-known name. */
1176 c = sd_bus_message_get_creds(m);
1180 r = sd_bus_creds_get_well_known_names(c, &well_known);
1184 if (strv_contains(well_known, "org.freedesktop.DBus"))
1185 m->sender = "org.freedesktop.DBus";
1190 int main(int argc, char *argv[]) {
1192 _cleanup_bus_creds_unref_ sd_bus_creds *bus_creds = NULL;
1193 _cleanup_bus_close_unref_ sd_bus *a = NULL, *b = NULL;
1194 sd_id128_t server_id;
1195 int r, in_fd, out_fd;
1196 bool got_hello = false;
1198 struct ucred ucred = {};
1199 _cleanup_free_ char *peersec = NULL;
1202 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
1203 log_parse_environment();
1206 r = parse_argv(argc, argv);
1210 r = policy_load(&policy, arg_configuration);
1212 log_error("Failed to load policy: %s", strerror(-r));
1216 /* policy_dump(&policy); */
1218 r = sd_listen_fds(0);
1220 in_fd = STDIN_FILENO;
1221 out_fd = STDOUT_FILENO;
1222 } else if (r == 1) {
1223 in_fd = SD_LISTEN_FDS_START;
1224 out_fd = SD_LISTEN_FDS_START;
1226 log_error("Illegal number of file descriptors passed");
1231 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
1232 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
1235 (void) getpeercred(in_fd, &ucred);
1236 (void) getpeersec(in_fd, &peersec);
1239 if (arg_drop_privileges) {
1240 const char *user = "systemd-bus-proxy";
1244 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
1246 log_error("Cannot resolve user name %s: %s", user, strerror(-r));
1250 r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
1255 names_hash = hashmap_new(&string_hash_ops);
1263 log_error("Failed to allocate bus: %s", strerror(-r));
1267 r = sd_bus_set_description(a, "sd-proxy");
1269 log_error("Failed to set bus name: %s", strerror(-r));
1273 r = sd_bus_set_address(a, arg_address);
1275 log_error("Failed to set address to connect to: %s", strerror(-r));
1279 r = sd_bus_negotiate_fds(a, is_unix);
1281 log_error("Failed to set FD negotiation: %s", strerror(-r));
1285 if (ucred.pid > 0) {
1286 a->fake_creds.pid = ucred.pid;
1287 a->fake_creds.uid = ucred.uid;
1288 a->fake_creds.gid = ucred.gid;
1289 a->fake_creds_valid = true;
1293 a->fake_label = peersec;
1297 a->manual_peer_interface = true;
1299 r = sd_bus_start(a);
1301 log_error("Failed to start bus client: %s", strerror(-r));
1305 r = sd_bus_get_owner_id(a, &server_id);
1307 log_error("Failed to get server ID: %s", strerror(-r));
1311 r = sd_bus_get_owner_creds(a, SD_BUS_CREDS_UID, &bus_creds);
1313 log_error("Failed to get bus creds: %s", strerror(-r));
1319 log_error("Failed to allocate bus: %s", strerror(-r));
1323 r = sd_bus_set_fd(b, in_fd, out_fd);
1325 log_error("Failed to set fds: %s", strerror(-r));
1329 r = sd_bus_set_server(b, 1, server_id);
1331 log_error("Failed to set server mode: %s", strerror(-r));
1335 r = sd_bus_negotiate_fds(b, is_unix);
1337 log_error("Failed to set FD negotiation: %s", strerror(-r));
1341 r = sd_bus_set_anonymous(b, true);
1343 log_error("Failed to set anonymous authentication: %s", strerror(-r));
1347 b->manual_peer_interface = true;
1349 r = sd_bus_start(b);
1351 log_error("Failed to start bus client: %s", strerror(-r));
1355 r = rename_service(a, b);
1357 log_debug("Failed to rename process: %s", strerror(-r));
1360 _cleanup_free_ char *match = NULL;
1363 r = sd_bus_get_unique_name(a, &unique);
1365 log_error("Failed to get unique name: %s", strerror(-r));
1369 match = strjoin("type='signal',"
1370 "sender='org.freedesktop.DBus',"
1371 "path='/org/freedesktop/DBus',"
1372 "interface='org.freedesktop.DBus',"
1373 "member='NameOwnerChanged',"
1383 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1385 log_error("Failed to add match for NameLost: %s", strerror(-r));
1390 match = strjoin("type='signal',"
1391 "sender='org.freedesktop.DBus',"
1392 "path='/org/freedesktop/DBus',"
1393 "interface='org.freedesktop.DBus',"
1394 "member='NameOwnerChanged',"
1404 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1406 log_error("Failed to add match for NameAcquired: %s", strerror(-r));
1412 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1413 int events_a, events_b, fd;
1414 uint64_t timeout_a, timeout_b, t;
1415 struct timespec _ts, *ts;
1416 struct pollfd *pollfd;
1420 r = sd_bus_process(a, &m);
1422 /* treat 'connection reset by peer' as clean exit condition */
1423 if (r == -ECONNRESET)
1426 log_error("Failed to process bus a: %s", strerror(-r));
1432 /* We officially got EOF, let's quit */
1433 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1438 k = synthesize_name_acquired(a, b, m);
1441 log_error("Failed to synthesize message: %s", strerror(-r));
1447 k = sd_bus_send(b, m, NULL);
1449 if (k == -ECONNRESET)
1453 log_error("Failed to send message: %s", strerror(-r));
1464 r = sd_bus_process(b, &m);
1466 /* treat 'connection reset by peer' as clean exit condition */
1467 if (r == -ECONNRESET)
1470 log_error("Failed to process bus b: %s", strerror(-r));
1479 assert_se(sd_bus_creds_get_uid(bus_creds, &uid) == 0);
1481 if (uid == 0 || uid != ucred.uid)
1484 /* We officially got EOF, let's quit */
1485 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1490 k = process_hello(a, b, m, p, &ucred, &got_hello);
1493 log_error("Failed to process HELLO: %s", strerror(-r));
1500 k = process_driver(a, b, m, p, &ucred);
1503 log_error("Failed to process driver calls: %s", strerror(-r));
1515 k = process_policy(a, b, m, p, &ucred);
1518 log_error("Failed to process policy: %s", strerror(-r));
1522 k = sd_bus_send(a, m, NULL);
1524 if (k == -ECONNRESET)
1526 else if (k == -EREMCHG)
1530 log_error("Failed to send message: %s", strerror(-r));
1544 fd = sd_bus_get_fd(a);
1546 log_error("Failed to get fd: %s", strerror(-r));
1550 events_a = sd_bus_get_events(a);
1552 log_error("Failed to get events mask: %s", strerror(-r));
1556 r = sd_bus_get_timeout(a, &timeout_a);
1558 log_error("Failed to get timeout: %s", strerror(-r));
1562 events_b = sd_bus_get_events(b);
1564 log_error("Failed to get events mask: %s", strerror(-r));
1568 r = sd_bus_get_timeout(b, &timeout_b);
1570 log_error("Failed to get timeout: %s", strerror(-r));
1575 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
1578 if (t == (uint64_t) -1)
1583 nw = now(CLOCK_MONOTONIC);
1589 ts = timespec_store(&_ts, t);
1592 pollfd = (struct pollfd[3]) {
1593 {.fd = fd, .events = events_a, },
1594 {.fd = in_fd, .events = events_b & POLLIN, },
1595 {.fd = out_fd, .events = events_b & POLLOUT, }
1598 r = ppoll(pollfd, 3, ts, NULL);
1600 log_error("ppoll() failed: %m");
1608 "STATUS=Shutting down.");
1610 policy_free(&policy);
1611 strv_free(arg_configuration);
1612 hashmap_free(names_hash);
1615 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;