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 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;
379 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
382 r = sd_bus_message_new_method_error(call, &m, e);
386 return synthetic_driver_send(call->bus, m);
389 static int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
391 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
395 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
398 if (sd_bus_error_is_set(p))
399 return synthetic_reply_method_error(call, p);
401 sd_bus_error_set_errno(&berror, error);
403 return synthetic_reply_method_error(call, &berror);
406 static int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
407 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
412 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
415 r = sd_bus_message_new_method_return(call, &m);
419 if (!isempty(types)) {
423 r = bus_message_append_ap(m, types, ap);
429 return synthetic_driver_send(call->bus, m);
432 static int synthetic_reply_return_strv(sd_bus_message *call, char **l) {
433 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
438 r = sd_bus_message_new_method_return(call, &m);
440 return synthetic_reply_method_errno(call, r, NULL);
442 r = sd_bus_message_append_strv(m, l);
444 return synthetic_reply_method_errno(call, r, NULL);
446 return synthetic_driver_send(call->bus, m);
449 static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
450 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
457 assert_return(service_name_is_valid(name), -EINVAL);
459 r = sd_bus_get_name_creds(bus, name, mask, &c);
460 if (r == -ESRCH || r == -ENXIO)
461 return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
465 if ((c->mask & mask) != mask)
474 static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
482 r = sd_bus_message_read(m, "s", &name);
486 return get_creds_by_name(bus, name, mask, _creds, error);
489 static int peer_is_privileged(sd_bus *bus, sd_bus_message *m) {
490 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
494 r = get_creds_by_message(bus, m, SD_BUS_CREDS_UID, &creds, NULL);
498 r = sd_bus_creds_get_uid(creds, &uid);
502 r = sd_bus_creds_has_effective_cap(creds, CAP_SYS_ADMIN);
512 static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, Policy *policy, const struct ucred *ucred) {
522 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
525 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
526 if (0 && !isempty(sd_bus_message_get_signature(m, true))) {
527 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
529 r = sd_bus_error_setf(&error, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
531 return synthetic_reply_method_errno(m, r, &error);
534 return synthetic_reply_method_return(m, "s",
535 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
536 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
538 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
539 " <method name=\"Introspect\">\n"
540 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
543 " <interface name=\"org.freedesktop.DBus\">\n"
544 " <method name=\"AddMatch\">\n"
545 " <arg type=\"s\" direction=\"in\"/>\n"
547 " <method name=\"RemoveMatch\">\n"
548 " <arg type=\"s\" direction=\"in\"/>\n"
550 " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
551 " <arg type=\"s\" direction=\"in\"/>\n"
552 " <arg type=\"ay\" direction=\"out\"/>\n"
554 " <method name=\"GetConnectionUnixProcessID\">\n"
555 " <arg type=\"s\" direction=\"in\"/>\n"
556 " <arg type=\"u\" direction=\"out\"/>\n"
558 " <method name=\"GetConnectionUnixUser\">\n"
559 " <arg type=\"s\" direction=\"in\"/>\n"
560 " <arg type=\"u\" direction=\"out\"/>\n"
562 " <method name=\"GetId\">\n"
563 " <arg type=\"s\" direction=\"out\"/>\n"
565 " <method name=\"GetNameOwner\">\n"
566 " <arg type=\"s\" direction=\"in\"/>\n"
567 " <arg type=\"s\" direction=\"out\"/>\n"
569 " <method name=\"Hello\">\n"
570 " <arg type=\"s\" direction=\"out\"/>\n"
572 " <method name=\"ListActivatableNames\">\n"
573 " <arg type=\"as\" direction=\"out\"/>\n"
575 " <method name=\"ListNames\">\n"
576 " <arg type=\"as\" direction=\"out\"/>\n"
578 " <method name=\"ListQueuedOwners\">\n"
579 " <arg type=\"s\" direction=\"in\"/>\n"
580 " <arg type=\"as\" direction=\"out\"/>\n"
582 " <method name=\"NameHasOwner\">\n"
583 " <arg type=\"s\" direction=\"in\"/>\n"
584 " <arg type=\"b\" direction=\"out\"/>\n"
586 " <method name=\"ReleaseName\">\n"
587 " <arg type=\"s\" direction=\"in\"/>\n"
588 " <arg type=\"u\" direction=\"out\"/>\n"
590 " <method name=\"ReloadConfig\">\n"
592 " <method name=\"RequestName\">\n"
593 " <arg type=\"s\" direction=\"in\"/>\n"
594 " <arg type=\"u\" direction=\"in\"/>\n"
595 " <arg type=\"u\" direction=\"out\"/>\n"
597 " <method name=\"StartServiceByName\">\n"
598 " <arg type=\"s\" direction=\"in\"/>\n"
599 " <arg type=\"u\" direction=\"in\"/>\n"
600 " <arg type=\"u\" direction=\"out\"/>\n"
602 " <method name=\"UpdateActivationEnvironment\">\n"
603 " <arg type=\"a{ss}\" direction=\"in\"/>\n"
605 " <signal name=\"NameAcquired\">\n"
606 " <arg type=\"s\"/>\n"
608 " <signal name=\"NameLost\">\n"
609 " <arg type=\"s\"/>\n"
611 " <signal name=\"NameOwnerChanged\">\n"
612 " <arg type=\"s\"/>\n"
613 " <arg type=\"s\"/>\n"
614 " <arg type=\"s\"/>\n"
619 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
622 r = sd_bus_message_read(m, "s", &match);
624 return synthetic_reply_method_errno(m, r, NULL);
626 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
628 return synthetic_reply_method_errno(m, r, NULL);
630 return synthetic_reply_method_return(m, NULL);
632 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
635 r = sd_bus_message_read(m, "s", &match);
637 return synthetic_reply_method_errno(m, r, NULL);
639 r = bus_remove_match_by_string(a, match, NULL, NULL);
641 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
643 return synthetic_reply_method_errno(m, r, NULL);
645 return synthetic_reply_method_return(m, NULL);
647 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
648 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
649 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
651 r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error);
653 return synthetic_reply_method_errno(m, r, &error);
655 return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
657 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
658 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
659 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
661 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, &error);
663 return synthetic_reply_method_errno(m, r, &error);
665 return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
667 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
668 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
669 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
671 r = get_creds_by_message(a, m, SD_BUS_CREDS_UID, &creds, &error);
673 return synthetic_reply_method_errno(m, r, &error);
675 return synthetic_reply_method_return(m, "u", (uint32_t) creds->uid);
677 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
678 sd_id128_t server_id;
679 char buf[SD_ID128_STRING_MAX];
681 r = sd_bus_get_owner_id(a, &server_id);
683 return synthetic_reply_method_errno(m, r, NULL);
685 return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
687 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
689 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
690 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
692 r = sd_bus_message_read(m, "s", &name);
694 return synthetic_reply_method_errno(m, r, NULL);
696 if (streq(name, "org.freedesktop.DBus"))
697 return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
699 r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
701 return synthetic_reply_method_errno(m, r, &error);
703 return synthetic_reply_method_return(m, "s", creds->unique_name);
705 /* "Hello" is handled in process_hello() */
707 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
708 _cleanup_strv_free_ char **names = NULL;
710 r = sd_bus_list_names(a, NULL, &names);
712 return synthetic_reply_method_errno(m, r, NULL);
714 /* Let's sort the names list to make it stable */
717 return synthetic_reply_return_strv(m, names);
719 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
720 _cleanup_strv_free_ char **names = NULL;
722 r = sd_bus_list_names(a, &names, NULL);
724 return synthetic_reply_method_errno(m, r, NULL);
726 r = strv_extend(&names, "org.freedesktop.DBus");
728 return synthetic_reply_method_errno(m, r, NULL);
730 /* Let's sort the names list to make it stable */
733 return synthetic_reply_return_strv(m, names);
735 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
736 struct kdbus_cmd_name_list cmd = {};
737 struct kdbus_name_list *name_list;
738 struct kdbus_cmd_free cmd_free;
739 struct kdbus_name_info *name;
740 _cleanup_strv_free_ char **owners = NULL;
741 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
745 r = sd_bus_message_read(m, "s", &arg0);
747 return synthetic_reply_method_errno(m, r, NULL);
749 if (!service_name_is_valid(arg0))
750 return synthetic_reply_method_errno(m, -EINVAL, NULL);
752 r = sd_bus_get_name_creds(a, arg0, 0, NULL);
753 if (r == -ESRCH || r == -ENXIO) {
754 sd_bus_error_setf(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name.", arg0);
755 return synthetic_reply_method_errno(m, r, &error);
758 return synthetic_reply_method_errno(m, r, NULL);
760 cmd.flags = KDBUS_NAME_LIST_QUEUED;
761 r = ioctl(a->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
763 return synthetic_reply_method_errno(m, -errno, NULL);
765 name_list = (struct kdbus_name_list *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
767 KDBUS_ITEM_FOREACH(name, name_list, names) {
768 const char *entry_name = NULL;
769 struct kdbus_item *item;
772 KDBUS_ITEM_FOREACH(item, name, items)
773 if (item->type == KDBUS_ITEM_OWNED_NAME)
774 entry_name = item->name.name;
776 if (!streq_ptr(entry_name, arg0))
779 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
784 r = strv_consume(&owners, n);
792 cmd_free.offset = cmd.offset;
794 r = ioctl(a->input_fd, KDBUS_CMD_FREE, &cmd_free);
796 return synthetic_reply_method_errno(m, r, NULL);
799 return synthetic_reply_method_errno(m, err, NULL);
801 return synthetic_reply_return_strv(m, owners);
803 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
806 r = sd_bus_message_read(m, "s", &name);
808 return synthetic_reply_method_errno(m, r, NULL);
810 if (!service_name_is_valid(name))
811 return synthetic_reply_method_errno(m, -EINVAL, NULL);
813 if (streq(name, "org.freedesktop.DBus"))
814 return synthetic_reply_method_return(m, "b", true);
816 r = sd_bus_get_name_creds(a, name, 0, NULL);
817 if (r < 0 && r != -ESRCH && r != -ENXIO)
818 return synthetic_reply_method_errno(m, r, NULL);
820 return synthetic_reply_method_return(m, "b", r >= 0);
822 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
825 r = sd_bus_message_read(m, "s", &name);
827 return synthetic_reply_method_errno(m, r, NULL);
829 if (!service_name_is_valid(name))
830 return synthetic_reply_method_errno(m, -EINVAL, NULL);
832 r = sd_bus_release_name(a, name);
835 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
836 if (r == -EADDRINUSE)
837 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
839 return synthetic_reply_method_errno(m, r, NULL);
842 hashmap_remove(names_hash, name);
844 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
846 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
847 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
849 r = sd_bus_error_setf(&error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
851 return synthetic_reply_method_errno(m, r, &error);
853 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
855 uint32_t flags, param;
858 r = sd_bus_message_read(m, "su", &name, &flags);
860 return synthetic_reply_method_errno(m, r, NULL);
862 if (!policy_check_own(policy, ucred, name))
863 return synthetic_reply_method_errno(m, -EPERM, NULL);
865 if (!service_name_is_valid(name))
866 return synthetic_reply_method_errno(m, -EINVAL, NULL);
867 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
868 return synthetic_reply_method_errno(m, -EINVAL, NULL);
871 if (flags & BUS_NAME_ALLOW_REPLACEMENT)
872 param |= SD_BUS_NAME_ALLOW_REPLACEMENT;
873 if (flags & BUS_NAME_REPLACE_EXISTING)
874 param |= SD_BUS_NAME_REPLACE_EXISTING;
875 if (!(flags & BUS_NAME_DO_NOT_QUEUE))
876 param |= SD_BUS_NAME_QUEUE;
878 r = sd_bus_request_name(a, name, param);
881 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
883 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
884 return synthetic_reply_method_errno(m, r, NULL);
889 r = hashmap_put(names_hash, name, NULL);
891 return synthetic_reply_method_errno(m, r, NULL);
894 return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
896 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
898 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
899 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
903 r = sd_bus_message_read(m, "su", &name, &flags);
905 return synthetic_reply_method_errno(m, r, NULL);
907 if (!service_name_is_valid(name))
908 return synthetic_reply_method_errno(m, -EINVAL, NULL);
910 return synthetic_reply_method_errno(m, -EINVAL, NULL);
912 r = sd_bus_get_name_creds(a, name, 0, NULL);
913 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
914 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
916 return synthetic_reply_method_errno(m, r, NULL);
918 r = sd_bus_message_new_method_call(
923 "org.freedesktop.DBus.Peer",
926 return synthetic_reply_method_errno(m, r, NULL);
928 r = sd_bus_send(a, msg, NULL);
930 return synthetic_reply_method_errno(m, r, NULL);
932 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
934 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
935 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
936 _cleanup_strv_free_ char **args = NULL;
938 if (!peer_is_privileged(a, m))
939 return synthetic_reply_method_errno(m, -EPERM, NULL);
941 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
943 return synthetic_reply_method_errno(m, r, NULL);
945 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
946 _cleanup_free_ char *s = NULL;
950 r = sd_bus_message_read(m, "ss", &key, &value);
952 return synthetic_reply_method_errno(m, r, NULL);
954 s = strjoin(key, "=", value, NULL);
956 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
958 r = strv_extend(&args, s);
960 return synthetic_reply_method_errno(m, r, NULL);
962 r = sd_bus_message_exit_container(m);
964 return synthetic_reply_method_errno(m, r, NULL);
967 r = sd_bus_message_exit_container(m);
969 return synthetic_reply_method_errno(m, r, NULL);
972 return synthetic_reply_method_errno(m, -EINVAL, NULL);
974 r = sd_bus_message_new_method_call(
977 "org.freedesktop.systemd1",
978 "/org/freedesktop/systemd1",
979 "org.freedesktop.systemd1.Manager",
982 return synthetic_reply_method_errno(m, r, NULL);
984 r = sd_bus_message_append_strv(msg, args);
986 return synthetic_reply_method_errno(m, r, NULL);
988 r = sd_bus_call(a, msg, 0, NULL, NULL);
990 return synthetic_reply_method_errno(m, r, NULL);
992 return synthetic_reply_method_return(m, NULL);
995 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
997 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
999 return synthetic_reply_method_errno(m, r, &error);
1003 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, Policy *policy, const struct ucred *ucred, bool *got_hello) {
1004 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
1013 /* As reaction to hello we need to respond with two messages:
1014 * the callback reply and the NameAcquired for the unique
1015 * name, since hello is otherwise obsolete on kdbus. */
1018 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
1019 streq_ptr(m->destination, "org.freedesktop.DBus");
1026 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
1031 log_error("Got duplicate hello, aborting.");
1035 if (!policy_check_hello(policy, ucred)) {
1036 log_error("Policy denied HELLO");
1045 r = sd_bus_message_new_method_return(m, &n);
1047 log_error("Failed to generate HELLO reply: %s", strerror(-r));
1051 r = sd_bus_message_append(n, "s", a->unique_name);
1053 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
1057 r = bus_message_append_sender(n, "org.freedesktop.DBus");
1059 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
1063 r = bus_seal_synthetic_message(b, n);
1065 log_error("Failed to seal HELLO reply: %s", strerror(-r));
1069 r = sd_bus_send(b, n, NULL);
1071 log_error("Failed to send HELLO reply: %s", strerror(-r));
1075 n = sd_bus_message_unref(n);
1076 r = sd_bus_message_new_signal(
1079 "/org/freedesktop/DBus",
1080 "org.freedesktop.DBus",
1083 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
1087 r = sd_bus_message_append(n, "s", a->unique_name);
1089 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
1093 r = bus_message_append_sender(n, "org.freedesktop.DBus");
1095 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
1099 r = bus_seal_synthetic_message(b, n);
1101 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
1105 r = sd_bus_send(b, n, NULL);
1107 log_error("Failed to send NameAcquired message: %s", strerror(-r));
1114 static int patch_sender(sd_bus *a, sd_bus_message *m) {
1115 char **well_known = NULL;
1125 /* We will change the sender of messages from the bus driver
1126 * so that they originate from the bus driver. This is a
1127 * speciality originating from dbus1, where the bus driver did
1128 * not have a unique id, but only the well-known name. */
1130 c = sd_bus_message_get_creds(m);
1134 r = sd_bus_creds_get_well_known_names(c, &well_known);
1138 if (strv_contains(well_known, "org.freedesktop.DBus"))
1139 m->sender = "org.freedesktop.DBus";
1144 int main(int argc, char *argv[]) {
1146 _cleanup_bus_close_unref_ sd_bus *a = NULL, *b = NULL;
1147 sd_id128_t server_id;
1148 int r, in_fd, out_fd;
1149 bool got_hello = false;
1151 struct ucred ucred = {};
1152 _cleanup_free_ char *peersec = NULL;
1155 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
1156 log_parse_environment();
1159 r = parse_argv(argc, argv);
1163 r = policy_load(&policy, arg_configuration);
1165 log_error("Failed to load policy: %s", strerror(-r));
1169 /* policy_dump(&policy); */
1171 r = sd_listen_fds(0);
1173 in_fd = STDIN_FILENO;
1174 out_fd = STDOUT_FILENO;
1175 } else if (r == 1) {
1176 in_fd = SD_LISTEN_FDS_START;
1177 out_fd = SD_LISTEN_FDS_START;
1179 log_error("Illegal number of file descriptors passed");
1184 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
1185 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
1188 (void) getpeercred(in_fd, &ucred);
1189 (void) getpeersec(in_fd, &peersec);
1192 if (arg_drop_privileges) {
1193 const char *user = "systemd-bus-proxy";
1197 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
1199 log_error("Cannot resolve user name %s: %s", user, strerror(-r));
1203 r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
1208 names_hash = hashmap_new(&string_hash_ops);
1216 log_error("Failed to allocate bus: %s", strerror(-r));
1220 r = sd_bus_set_description(a, "sd-proxy");
1222 log_error("Failed to set bus name: %s", strerror(-r));
1226 r = sd_bus_set_address(a, arg_address);
1228 log_error("Failed to set address to connect to: %s", strerror(-r));
1232 r = sd_bus_negotiate_fds(a, is_unix);
1234 log_error("Failed to set FD negotiation: %s", strerror(-r));
1238 if (ucred.pid > 0) {
1239 a->fake_creds.pid = ucred.pid;
1240 a->fake_creds.uid = ucred.uid;
1241 a->fake_creds.gid = ucred.gid;
1242 a->fake_creds_valid = true;
1246 a->fake_label = peersec;
1250 a->manual_peer_interface = true;
1252 r = sd_bus_start(a);
1254 log_error("Failed to start bus client: %s", strerror(-r));
1258 r = sd_bus_get_owner_id(a, &server_id);
1260 log_error("Failed to get server ID: %s", strerror(-r));
1266 log_error("Failed to allocate bus: %s", strerror(-r));
1270 r = sd_bus_set_fd(b, in_fd, out_fd);
1272 log_error("Failed to set fds: %s", strerror(-r));
1276 r = sd_bus_set_server(b, 1, server_id);
1278 log_error("Failed to set server mode: %s", strerror(-r));
1282 r = sd_bus_negotiate_fds(b, is_unix);
1284 log_error("Failed to set FD negotiation: %s", strerror(-r));
1288 r = sd_bus_set_anonymous(b, true);
1290 log_error("Failed to set anonymous authentication: %s", strerror(-r));
1294 b->manual_peer_interface = true;
1296 r = sd_bus_start(b);
1298 log_error("Failed to start bus client: %s", strerror(-r));
1302 r = rename_service(a, b);
1304 log_debug("Failed to rename process: %s", strerror(-r));
1307 _cleanup_free_ char *match = NULL;
1310 r = sd_bus_get_unique_name(a, &unique);
1312 log_error("Failed to get unique name: %s", strerror(-r));
1316 match = strjoin("type='signal',"
1317 "sender='org.freedesktop.DBus',"
1318 "path='/org/freedesktop/DBus',"
1319 "interface='org.freedesktop.DBus',"
1320 "member='NameOwnerChanged',"
1330 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1332 log_error("Failed to add match for NameLost: %s", strerror(-r));
1337 match = strjoin("type='signal',"
1338 "sender='org.freedesktop.DBus',"
1339 "path='/org/freedesktop/DBus',"
1340 "interface='org.freedesktop.DBus',"
1341 "member='NameOwnerChanged',"
1351 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1353 log_error("Failed to add match for NameAcquired: %s", strerror(-r));
1359 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1360 int events_a, events_b, fd;
1361 uint64_t timeout_a, timeout_b, t;
1362 struct timespec _ts, *ts;
1363 struct pollfd *pollfd;
1367 r = sd_bus_process(a, &m);
1369 /* treat 'connection reset by peer' as clean exit condition */
1370 if (r == -ECONNRESET)
1373 log_error("Failed to process bus a: %s", strerror(-r));
1379 /* We officially got EOF, let's quit */
1380 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1385 k = synthesize_name_acquired(a, b, m);
1388 log_error("Failed to synthesize message: %s", strerror(-r));
1394 k = sd_bus_send(b, m, NULL);
1396 if (k == -ECONNRESET)
1400 log_error("Failed to send message: %s", strerror(-r));
1411 r = sd_bus_process(b, &m);
1413 /* treat 'connection reset by peer' as clean exit condition */
1414 if (r == -ECONNRESET)
1417 log_error("Failed to process bus b: %s", strerror(-r));
1423 /* We officially got EOF, let's quit */
1424 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1429 k = process_hello(a, b, m, &policy, &ucred, &got_hello);
1432 log_error("Failed to process HELLO: %s", strerror(-r));
1439 k = process_policy(a, b, m);
1442 log_error("Failed to process policy: %s", strerror(-r));
1446 k = process_driver(a, b, m, &policy, &ucred);
1449 log_error("Failed to process driver calls: %s", strerror(-r));
1456 k = sd_bus_send(a, m, NULL);
1458 if (k == -ECONNRESET)
1462 log_error("Failed to send message: %s", strerror(-r));
1474 fd = sd_bus_get_fd(a);
1476 log_error("Failed to get fd: %s", strerror(-r));
1480 events_a = sd_bus_get_events(a);
1482 log_error("Failed to get events mask: %s", strerror(-r));
1486 r = sd_bus_get_timeout(a, &timeout_a);
1488 log_error("Failed to get timeout: %s", strerror(-r));
1492 events_b = sd_bus_get_events(b);
1494 log_error("Failed to get events mask: %s", strerror(-r));
1498 r = sd_bus_get_timeout(b, &timeout_b);
1500 log_error("Failed to get timeout: %s", strerror(-r));
1505 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
1508 if (t == (uint64_t) -1)
1513 nw = now(CLOCK_MONOTONIC);
1519 ts = timespec_store(&_ts, t);
1522 pollfd = (struct pollfd[3]) {
1523 {.fd = fd, .events = events_a, },
1524 {.fd = in_fd, .events = events_b & POLLIN, },
1525 {.fd = out_fd, .events = events_b & POLLOUT, }
1528 r = ppoll(pollfd, 3, ts, NULL);
1530 log_error("ppoll() failed: %m");
1538 "STATUS=Shutting down.");
1540 policy_free(&policy);
1541 strv_free(arg_configuration);
1542 hashmap_free(names_hash);
1545 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;