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 r = sd_bus_get_name_creds(bus, name, mask, &c);
416 if (r == -ESRCH || r == -ENXIO)
417 return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
421 if ((c->mask & mask) != mask)
430 static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
438 r = sd_bus_message_read(m, "s", &name);
442 return get_creds_by_name(bus, name, mask, _creds, error);
445 static int process_policy(sd_bus *a, sd_bus *b, sd_bus_message *m, Policy *policy, const struct ucred *ucred) {
449 bool granted = false;
461 /* The message came from the kernel, and is sent to our legacy client. */
462 r = sd_bus_creds_get_well_known_names(&m->creds, &names_strv);
466 STRV_FOREACH(name, names_strv) {
467 if (policy_check_send(policy, ucred, m->header->type, *name, m->path, m->interface, m->member)) {
468 r = free_and_strdup(&m->destination_ptr, *name);
485 HASHMAP_FOREACH(name, names_hash, i) {
486 if (policy_check_recv(policy, ucred, m->header->type, *name, m->path, m->interface, m->member))
492 sd_bus_creds *bus_creds;
494 /* The message came from the legacy client, and is sent to kdbus. */
495 r = sd_bus_get_name_creds(a, m->destination, SD_BUS_CREDS_WELL_KNOWN_NAMES, &bus_creds);
499 STRV_FOREACH(name, names_strv) {
500 if (policy_check_send(policy, ucred, m->header->type, *name, m->path, m->interface, m->member)) {
501 r = free_and_strdup(&m->destination_ptr, *name);
505 r = bus_kernel_parse_unique_name(m->sender, &m->verify_destination_id);
522 HASHMAP_FOREACH(name, names_hash, i) {
523 if (policy_check_recv(policy, ucred, m->header->type, *name, m->path, m->interface, m->member))
533 static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, Policy *policy, const struct ucred *ucred) {
543 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
546 /* The "Hello()" call is is handled in process_hello() */
548 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
550 if (!sd_bus_message_has_signature(m, ""))
551 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
553 return synthetic_reply_method_return(m, "s",
554 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
555 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
557 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
558 " <method name=\"Introspect\">\n"
559 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
562 " <interface name=\"org.freedesktop.DBus\">\n"
563 " <method name=\"AddMatch\">\n"
564 " <arg type=\"s\" direction=\"in\"/>\n"
566 " <method name=\"RemoveMatch\">\n"
567 " <arg type=\"s\" direction=\"in\"/>\n"
569 " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
570 " <arg type=\"s\" direction=\"in\"/>\n"
571 " <arg type=\"ay\" direction=\"out\"/>\n"
573 " <method name=\"GetConnectionUnixProcessID\">\n"
574 " <arg type=\"s\" direction=\"in\"/>\n"
575 " <arg type=\"u\" direction=\"out\"/>\n"
577 " <method name=\"GetConnectionUnixUser\">\n"
578 " <arg type=\"s\" direction=\"in\"/>\n"
579 " <arg type=\"u\" direction=\"out\"/>\n"
581 " <method name=\"GetId\">\n"
582 " <arg type=\"s\" direction=\"out\"/>\n"
584 " <method name=\"GetNameOwner\">\n"
585 " <arg type=\"s\" direction=\"in\"/>\n"
586 " <arg type=\"s\" direction=\"out\"/>\n"
588 " <method name=\"Hello\">\n"
589 " <arg type=\"s\" direction=\"out\"/>\n"
591 " <method name=\"ListActivatableNames\">\n"
592 " <arg type=\"as\" direction=\"out\"/>\n"
594 " <method name=\"ListNames\">\n"
595 " <arg type=\"as\" direction=\"out\"/>\n"
597 " <method name=\"ListQueuedOwners\">\n"
598 " <arg type=\"s\" direction=\"in\"/>\n"
599 " <arg type=\"as\" direction=\"out\"/>\n"
601 " <method name=\"NameHasOwner\">\n"
602 " <arg type=\"s\" direction=\"in\"/>\n"
603 " <arg type=\"b\" direction=\"out\"/>\n"
605 " <method name=\"ReleaseName\">\n"
606 " <arg type=\"s\" direction=\"in\"/>\n"
607 " <arg type=\"u\" direction=\"out\"/>\n"
609 " <method name=\"ReloadConfig\">\n"
611 " <method name=\"RequestName\">\n"
612 " <arg type=\"s\" direction=\"in\"/>\n"
613 " <arg type=\"u\" direction=\"in\"/>\n"
614 " <arg type=\"u\" direction=\"out\"/>\n"
616 " <method name=\"StartServiceByName\">\n"
617 " <arg type=\"s\" direction=\"in\"/>\n"
618 " <arg type=\"u\" direction=\"in\"/>\n"
619 " <arg type=\"u\" direction=\"out\"/>\n"
621 " <method name=\"UpdateActivationEnvironment\">\n"
622 " <arg type=\"a{ss}\" direction=\"in\"/>\n"
624 " <signal name=\"NameAcquired\">\n"
625 " <arg type=\"s\"/>\n"
627 " <signal name=\"NameLost\">\n"
628 " <arg type=\"s\"/>\n"
630 " <signal name=\"NameOwnerChanged\">\n"
631 " <arg type=\"s\"/>\n"
632 " <arg type=\"s\"/>\n"
633 " <arg type=\"s\"/>\n"
638 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
641 if (!sd_bus_message_has_signature(m, "s"))
642 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
644 r = sd_bus_message_read(m, "s", &match);
646 return synthetic_reply_method_errno(m, r, NULL);
648 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
650 return synthetic_reply_method_errno(m, r, NULL);
652 return synthetic_reply_method_return(m, NULL);
654 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
657 if (!sd_bus_message_has_signature(m, "s"))
658 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
660 r = sd_bus_message_read(m, "s", &match);
662 return synthetic_reply_method_errno(m, r, NULL);
664 r = bus_remove_match_by_string(a, match, NULL, NULL);
666 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
668 return synthetic_reply_method_errno(m, r, NULL);
670 return synthetic_reply_method_return(m, NULL);
672 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
673 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
674 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
676 if (!sd_bus_message_has_signature(m, "s"))
677 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
679 r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error);
681 return synthetic_reply_method_errno(m, r, &error);
683 return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
685 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
686 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
687 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
689 if (!sd_bus_message_has_signature(m, "s"))
690 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
692 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, &error);
694 return synthetic_reply_method_errno(m, r, &error);
696 return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
698 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
699 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
700 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
702 if (!sd_bus_message_has_signature(m, "s"))
703 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
705 r = get_creds_by_message(a, m, SD_BUS_CREDS_UID, &creds, &error);
707 return synthetic_reply_method_errno(m, r, &error);
709 return synthetic_reply_method_return(m, "u", (uint32_t) creds->uid);
711 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
712 sd_id128_t server_id;
713 char buf[SD_ID128_STRING_MAX];
715 if (!sd_bus_message_has_signature(m, ""))
716 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
718 r = sd_bus_get_owner_id(a, &server_id);
720 return synthetic_reply_method_errno(m, r, NULL);
722 return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
724 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
726 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
727 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
729 if (!sd_bus_message_has_signature(m, "s"))
730 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
732 r = sd_bus_message_read(m, "s", &name);
734 return synthetic_reply_method_errno(m, r, NULL);
736 if (streq(name, "org.freedesktop.DBus"))
737 return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
739 r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
741 return synthetic_reply_method_errno(m, r, &error);
743 return synthetic_reply_method_return(m, "s", creds->unique_name);
745 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
746 _cleanup_strv_free_ char **names = NULL;
748 if (!sd_bus_message_has_signature(m, ""))
749 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
751 r = sd_bus_list_names(a, NULL, &names);
753 return synthetic_reply_method_errno(m, r, NULL);
755 /* Let's sort the names list to make it stable */
758 return synthetic_reply_return_strv(m, names);
760 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
761 _cleanup_strv_free_ char **names = NULL;
763 if (!sd_bus_message_has_signature(m, ""))
764 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
766 r = sd_bus_list_names(a, &names, NULL);
768 return synthetic_reply_method_errno(m, r, NULL);
770 r = strv_extend(&names, "org.freedesktop.DBus");
772 return synthetic_reply_method_errno(m, r, NULL);
774 /* Let's sort the names list to make it stable */
777 return synthetic_reply_return_strv(m, names);
779 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
780 struct kdbus_cmd_name_list cmd = {};
781 struct kdbus_name_list *name_list;
782 struct kdbus_cmd_free cmd_free;
783 struct kdbus_name_info *name;
784 _cleanup_strv_free_ char **owners = NULL;
785 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
789 if (!sd_bus_message_has_signature(m, "s"))
790 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
792 r = sd_bus_message_read(m, "s", &arg0);
794 return synthetic_reply_method_errno(m, r, NULL);
796 r = sd_bus_get_name_creds(a, arg0, 0, NULL);
797 if (r == -ESRCH || r == -ENXIO) {
798 sd_bus_error_setf(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name.", arg0);
799 return synthetic_reply_method_errno(m, r, &error);
802 return synthetic_reply_method_errno(m, r, NULL);
804 cmd.flags = KDBUS_NAME_LIST_QUEUED;
805 r = ioctl(a->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
807 return synthetic_reply_method_errno(m, -errno, NULL);
809 name_list = (struct kdbus_name_list *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
811 KDBUS_ITEM_FOREACH(name, name_list, names) {
812 const char *entry_name = NULL;
813 struct kdbus_item *item;
816 KDBUS_ITEM_FOREACH(item, name, items)
817 if (item->type == KDBUS_ITEM_OWNED_NAME)
818 entry_name = item->name.name;
820 if (!streq_ptr(entry_name, arg0))
823 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
828 r = strv_consume(&owners, n);
836 cmd_free.offset = cmd.offset;
838 r = ioctl(a->input_fd, KDBUS_CMD_FREE, &cmd_free);
840 return synthetic_reply_method_errno(m, r, NULL);
843 return synthetic_reply_method_errno(m, err, NULL);
845 return synthetic_reply_return_strv(m, owners);
847 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
850 if (!sd_bus_message_has_signature(m, "s"))
851 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
853 r = sd_bus_message_read(m, "s", &name);
855 return synthetic_reply_method_errno(m, r, NULL);
857 if (streq(name, "org.freedesktop.DBus"))
858 return synthetic_reply_method_return(m, "b", true);
860 r = sd_bus_get_name_creds(a, name, 0, NULL);
861 if (r < 0 && r != -ESRCH && r != -ENXIO)
862 return synthetic_reply_method_errno(m, r, NULL);
864 return synthetic_reply_method_return(m, "b", r >= 0);
866 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
869 if (!sd_bus_message_has_signature(m, "s"))
870 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
872 r = sd_bus_message_read(m, "s", &name);
874 return synthetic_reply_method_errno(m, r, NULL);
876 r = sd_bus_release_name(a, name);
879 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
880 if (r == -EADDRINUSE)
881 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
883 return synthetic_reply_method_errno(m, r, NULL);
886 hashmap_remove(names_hash, name);
888 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
890 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
891 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
893 if (!sd_bus_message_has_signature(m, ""))
894 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
896 r = sd_bus_error_setf(&error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
898 return synthetic_reply_method_errno(m, r, &error);
900 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
902 uint32_t flags, param;
905 if (!sd_bus_message_has_signature(m, "su"))
906 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
908 r = sd_bus_message_read(m, "su", &name, &flags);
910 return synthetic_reply_method_errno(m, r, NULL);
912 if (policy && !policy_check_own(policy, ucred, name))
913 return synthetic_reply_method_errno(m, -EPERM, NULL);
915 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
916 return synthetic_reply_method_errno(m, -EINVAL, NULL);
919 if (flags & BUS_NAME_ALLOW_REPLACEMENT)
920 param |= SD_BUS_NAME_ALLOW_REPLACEMENT;
921 if (flags & BUS_NAME_REPLACE_EXISTING)
922 param |= SD_BUS_NAME_REPLACE_EXISTING;
923 if (!(flags & BUS_NAME_DO_NOT_QUEUE))
924 param |= SD_BUS_NAME_QUEUE;
926 r = sd_bus_request_name(a, name, param);
929 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
931 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
932 return synthetic_reply_method_errno(m, r, NULL);
937 r = hashmap_put(names_hash, name, NULL);
939 return synthetic_reply_method_errno(m, r, NULL);
942 return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
944 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
946 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
947 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
951 if (!sd_bus_message_has_signature(m, "su"))
952 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
954 r = sd_bus_message_read(m, "su", &name, &flags);
956 return synthetic_reply_method_errno(m, r, NULL);
959 return synthetic_reply_method_errno(m, -EINVAL, NULL);
961 r = sd_bus_get_name_creds(a, name, 0, NULL);
962 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
963 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
965 return synthetic_reply_method_errno(m, r, NULL);
967 r = sd_bus_message_new_method_call(
972 "org.freedesktop.DBus.Peer",
975 return synthetic_reply_method_errno(m, r, NULL);
977 r = sd_bus_send(a, msg, NULL);
979 return synthetic_reply_method_errno(m, r, NULL);
981 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
983 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
984 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
985 _cleanup_strv_free_ char **args = NULL;
987 if (!sd_bus_message_has_signature(m, "a{ss}"))
988 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
990 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
992 return synthetic_reply_method_errno(m, r, NULL);
994 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
995 _cleanup_free_ char *s = NULL;
999 r = sd_bus_message_read(m, "ss", &key, &value);
1001 return synthetic_reply_method_errno(m, r, NULL);
1003 s = strjoin(key, "=", value, NULL);
1005 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
1007 r = strv_extend(&args, s);
1009 return synthetic_reply_method_errno(m, r, NULL);
1011 r = sd_bus_message_exit_container(m);
1013 return synthetic_reply_method_errno(m, r, NULL);
1016 r = sd_bus_message_exit_container(m);
1018 return synthetic_reply_method_errno(m, r, NULL);
1021 return synthetic_reply_method_errno(m, -EINVAL, NULL);
1023 r = sd_bus_message_new_method_call(
1026 "org.freedesktop.systemd1",
1027 "/org/freedesktop/systemd1",
1028 "org.freedesktop.systemd1.Manager",
1031 return synthetic_reply_method_errno(m, r, NULL);
1033 r = sd_bus_message_append_strv(msg, args);
1035 return synthetic_reply_method_errno(m, r, NULL);
1037 r = sd_bus_call(a, msg, 0, NULL, NULL);
1039 return synthetic_reply_method_errno(m, r, NULL);
1041 return synthetic_reply_method_return(m, NULL);
1044 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1046 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
1048 return synthetic_reply_method_errno(m, r, &error);
1052 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, Policy *policy, const struct ucred *ucred, bool *got_hello) {
1053 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
1062 /* As reaction to hello we need to respond with two messages:
1063 * the callback reply and the NameAcquired for the unique
1064 * name, since hello is otherwise obsolete on kdbus. */
1067 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
1068 streq_ptr(m->destination, "org.freedesktop.DBus");
1075 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
1080 log_error("Got duplicate hello, aborting.");
1084 if (policy && !policy_check_hello(policy, ucred)) {
1085 log_error("Policy denied HELLO");
1094 r = sd_bus_message_new_method_return(m, &n);
1096 log_error("Failed to generate HELLO reply: %s", strerror(-r));
1100 r = sd_bus_message_append(n, "s", a->unique_name);
1102 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
1106 r = bus_message_append_sender(n, "org.freedesktop.DBus");
1108 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
1112 r = bus_seal_synthetic_message(b, n);
1114 log_error("Failed to seal HELLO reply: %s", strerror(-r));
1118 r = sd_bus_send(b, n, NULL);
1120 log_error("Failed to send HELLO reply: %s", strerror(-r));
1124 n = sd_bus_message_unref(n);
1125 r = sd_bus_message_new_signal(
1128 "/org/freedesktop/DBus",
1129 "org.freedesktop.DBus",
1132 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
1136 r = sd_bus_message_append(n, "s", a->unique_name);
1138 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
1142 r = bus_message_append_sender(n, "org.freedesktop.DBus");
1144 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
1148 r = bus_seal_synthetic_message(b, n);
1150 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
1154 r = sd_bus_send(b, n, NULL);
1156 log_error("Failed to send NameAcquired message: %s", strerror(-r));
1163 static int patch_sender(sd_bus *a, sd_bus_message *m) {
1164 char **well_known = NULL;
1174 /* We will change the sender of messages from the bus driver
1175 * so that they originate from the bus driver. This is a
1176 * speciality originating from dbus1, where the bus driver did
1177 * not have a unique id, but only the well-known name. */
1179 c = sd_bus_message_get_creds(m);
1183 r = sd_bus_creds_get_well_known_names(c, &well_known);
1187 if (strv_contains(well_known, "org.freedesktop.DBus"))
1188 m->sender = "org.freedesktop.DBus";
1193 int main(int argc, char *argv[]) {
1195 _cleanup_bus_creds_unref_ sd_bus_creds *bus_creds = NULL;
1196 _cleanup_bus_close_unref_ sd_bus *a = NULL, *b = NULL;
1197 sd_id128_t server_id;
1198 int r, in_fd, out_fd;
1199 bool got_hello = false;
1201 struct ucred ucred = {};
1202 _cleanup_free_ char *peersec = NULL;
1205 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
1206 log_parse_environment();
1209 r = parse_argv(argc, argv);
1213 r = policy_load(&policy, arg_configuration);
1215 log_error("Failed to load policy: %s", strerror(-r));
1219 /* policy_dump(&policy); */
1221 r = sd_listen_fds(0);
1223 in_fd = STDIN_FILENO;
1224 out_fd = STDOUT_FILENO;
1225 } else if (r == 1) {
1226 in_fd = SD_LISTEN_FDS_START;
1227 out_fd = SD_LISTEN_FDS_START;
1229 log_error("Illegal number of file descriptors passed");
1234 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
1235 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
1238 (void) getpeercred(in_fd, &ucred);
1239 (void) getpeersec(in_fd, &peersec);
1242 if (arg_drop_privileges) {
1243 const char *user = "systemd-bus-proxy";
1247 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
1249 log_error("Cannot resolve user name %s: %s", user, strerror(-r));
1253 r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
1258 names_hash = hashmap_new(&string_hash_ops);
1266 log_error("Failed to allocate bus: %s", strerror(-r));
1270 r = sd_bus_set_description(a, "sd-proxy");
1272 log_error("Failed to set bus name: %s", strerror(-r));
1276 r = sd_bus_set_address(a, arg_address);
1278 log_error("Failed to set address to connect to: %s", strerror(-r));
1282 r = sd_bus_negotiate_fds(a, is_unix);
1284 log_error("Failed to set FD negotiation: %s", strerror(-r));
1288 if (ucred.pid > 0) {
1289 a->fake_pids.pid = ucred.pid;
1290 a->fake_pids_valid = true;
1292 a->fake_creds.uid = ucred.uid;
1293 a->fake_creds.euid = (uid_t) -1;
1294 a->fake_creds.suid = (uid_t) -1;
1295 a->fake_creds.fsuid = (uid_t) -1;
1296 a->fake_creds.gid = ucred.gid;
1297 a->fake_creds.egid = (gid_t) -1;
1298 a->fake_creds.sgid = (gid_t) -1;
1299 a->fake_creds.fsgid = (gid_t) -1;
1300 a->fake_creds_valid = true;
1304 a->fake_label = peersec;
1308 a->manual_peer_interface = true;
1310 r = sd_bus_start(a);
1312 log_error("Failed to start bus client: %s", strerror(-r));
1316 r = sd_bus_get_owner_id(a, &server_id);
1318 log_error("Failed to get server ID: %s", strerror(-r));
1322 r = sd_bus_get_owner_creds(a, SD_BUS_CREDS_UID, &bus_creds);
1324 log_error("Failed to get bus creds: %s", strerror(-r));
1330 log_error("Failed to allocate bus: %s", strerror(-r));
1334 r = sd_bus_set_fd(b, in_fd, out_fd);
1336 log_error("Failed to set fds: %s", strerror(-r));
1340 r = sd_bus_set_server(b, 1, server_id);
1342 log_error("Failed to set server mode: %s", strerror(-r));
1346 r = sd_bus_negotiate_fds(b, is_unix);
1348 log_error("Failed to set FD negotiation: %s", strerror(-r));
1352 r = sd_bus_set_anonymous(b, true);
1354 log_error("Failed to set anonymous authentication: %s", strerror(-r));
1358 b->manual_peer_interface = true;
1360 r = sd_bus_start(b);
1362 log_error("Failed to start bus client: %s", strerror(-r));
1366 r = rename_service(a, b);
1368 log_debug("Failed to rename process: %s", strerror(-r));
1371 _cleanup_free_ char *match = NULL;
1374 r = sd_bus_get_unique_name(a, &unique);
1376 log_error("Failed to get unique name: %s", strerror(-r));
1380 match = strjoin("type='signal',"
1381 "sender='org.freedesktop.DBus',"
1382 "path='/org/freedesktop/DBus',"
1383 "interface='org.freedesktop.DBus',"
1384 "member='NameOwnerChanged',"
1394 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1396 log_error("Failed to add match for NameLost: %s", strerror(-r));
1401 match = strjoin("type='signal',"
1402 "sender='org.freedesktop.DBus',"
1403 "path='/org/freedesktop/DBus',"
1404 "interface='org.freedesktop.DBus',"
1405 "member='NameOwnerChanged',"
1415 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1417 log_error("Failed to add match for NameAcquired: %s", strerror(-r));
1423 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1424 int events_a, events_b, fd;
1425 uint64_t timeout_a, timeout_b, t;
1426 struct timespec _ts, *ts;
1427 struct pollfd *pollfd;
1431 r = sd_bus_process(a, &m);
1433 /* treat 'connection reset by peer' as clean exit condition */
1434 if (r == -ECONNRESET)
1437 log_error("Failed to process bus a: %s", strerror(-r));
1443 /* We officially got EOF, let's quit */
1444 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1449 k = synthesize_name_acquired(a, b, m);
1452 log_error("Failed to synthesize message: %s", strerror(-r));
1458 k = sd_bus_send(b, m, NULL);
1460 if (k == -ECONNRESET)
1464 log_error("Failed to send message: %s", strerror(-r));
1475 r = sd_bus_process(b, &m);
1477 /* treat 'connection reset by peer' as clean exit condition */
1478 if (r == -ECONNRESET)
1481 log_error("Failed to process bus b: %s", strerror(-r));
1490 assert_se(sd_bus_creds_get_uid(bus_creds, &uid) == 0);
1493 if (uid == 0 || uid != ucred.uid)
1497 /* We officially got EOF, let's quit */
1498 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1503 k = process_hello(a, b, m, p, &ucred, &got_hello);
1506 log_error("Failed to process HELLO: %s", strerror(-r));
1513 k = process_driver(a, b, m, p, &ucred);
1516 log_error("Failed to process driver calls: %s", strerror(-r));
1528 k = process_policy(a, b, m, p, &ucred);
1531 log_error("Failed to process policy: %s", strerror(-r));
1535 k = sd_bus_send(a, m, NULL);
1537 if (k == -ECONNRESET)
1539 else if (k == -EREMCHG)
1543 log_error("Failed to send message: %s", strerror(-r));
1557 fd = sd_bus_get_fd(a);
1559 log_error("Failed to get fd: %s", strerror(-r));
1563 events_a = sd_bus_get_events(a);
1565 log_error("Failed to get events mask: %s", strerror(-r));
1569 r = sd_bus_get_timeout(a, &timeout_a);
1571 log_error("Failed to get timeout: %s", strerror(-r));
1575 events_b = sd_bus_get_events(b);
1577 log_error("Failed to get events mask: %s", strerror(-r));
1581 r = sd_bus_get_timeout(b, &timeout_b);
1583 log_error("Failed to get timeout: %s", strerror(-r));
1588 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
1591 if (t == (uint64_t) -1)
1596 nw = now(CLOCK_MONOTONIC);
1602 ts = timespec_store(&_ts, t);
1605 pollfd = (struct pollfd[3]) {
1606 {.fd = fd, .events = events_a, },
1607 {.fd = in_fd, .events = events_b & POLLIN, },
1608 {.fd = out_fd, .events = events_b & POLLOUT, }
1611 r = ppoll(pollfd, 3, ts, NULL);
1613 log_error("ppoll() failed: %m");
1621 "STATUS=Shutting down.");
1623 policy_free(&policy);
1624 strv_free(arg_configuration);
1625 hashmap_free(names_hash);
1628 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;