1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
7 Copyright 2013 Daniel Mack
8 Copyright 2014 Kay Sievers
10 systemd is free software; you can redistribute it and/or modify it
11 under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
15 systemd is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public License
21 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <sys/socket.h>
26 #include <sys/types.h>
37 #include "socket-util.h"
38 #include "sd-daemon.h"
40 #include "bus-internal.h"
41 #include "bus-message.h"
43 #include "bus-internal.h"
47 #include "capability.h"
48 #include "bus-policy.h"
50 static const char *arg_address = KERNEL_SYSTEM_BUS_PATH;
51 static char *arg_command_line_buffer = NULL;
52 static bool arg_drop_privileges = false;
53 static char **arg_configuration = NULL;
55 static int help(void) {
57 printf("%s [OPTIONS...]\n\n"
58 "Connect STDIO or a socket to a given bus address.\n\n"
59 " -h --help Show this help\n"
60 " --version Show package version\n"
61 " --drop-privileges Drop privileges\n"
62 " --configuration=PATH Configuration file or directory\n"
63 " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
64 " (default: " KERNEL_SYSTEM_BUS_PATH ")\n",
65 program_invocation_short_name);
70 static int parse_argv(int argc, char *argv[]) {
79 static const struct option options[] = {
80 { "help", no_argument, NULL, 'h' },
81 { "version", no_argument, NULL, ARG_VERSION },
82 { "address", required_argument, NULL, ARG_ADDRESS },
83 { "drop-privileges", no_argument, NULL, ARG_DROP_PRIVILEGES },
84 { "configuration", required_argument, NULL, ARG_CONFIGURATION },
93 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
102 puts(PACKAGE_STRING);
103 puts(SYSTEMD_FEATURES);
107 arg_address = optarg;
110 case ARG_DROP_PRIVILEGES:
111 arg_drop_privileges = true;
114 case ARG_CONFIGURATION:
115 r = strv_extend(&arg_configuration, optarg);
124 assert_not_reached("Unhandled option");
128 /* If the first command line argument is only "x" characters
129 * we'll write who we are talking to into it, so that "ps" is
131 arg_command_line_buffer = argv[optind];
132 if (argc > optind + 1 ||
133 (arg_command_line_buffer && arg_command_line_buffer[strspn(arg_command_line_buffer, "x")] != 0)) {
134 log_error("Too many arguments");
141 static int rename_service(sd_bus *a, sd_bus *b) {
142 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
143 _cleanup_free_ char *p = NULL, *name = NULL;
153 r = sd_bus_get_peer_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM, &creds);
157 r = sd_bus_creds_get_uid(creds, &uid);
161 r = sd_bus_creds_get_pid(creds, &pid);
165 r = sd_bus_creds_get_cmdline(creds, &cmdline);
169 r = sd_bus_creds_get_comm(creds, &comm);
173 name = uid_to_name(uid);
177 p = strv_join(cmdline, " ");
181 /* The status string gets the full command line ... */
183 "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
187 /* ... and the argv line only the short comm */
188 if (arg_command_line_buffer) {
191 m = strlen(arg_command_line_buffer);
192 w = snprintf(arg_command_line_buffer, m,
193 "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
198 memzero(arg_command_line_buffer + w, m - w);
201 log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
209 static int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
210 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
211 const char *name, *old_owner, *new_owner;
218 /* If we get NameOwnerChanged for our own name, we need to
219 * synthesize NameLost/NameAcquired, since socket clients need
220 * that, even though it is obsoleted on kdbus */
225 if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
226 !streq_ptr(m->path, "/org/freedesktop/DBus") ||
227 !streq_ptr(m->sender, "org.freedesktop.DBus"))
230 r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
234 r = sd_bus_message_rewind(m, true);
238 if (streq(old_owner, a->unique_name)) {
240 r = sd_bus_message_new_signal(
243 "/org/freedesktop/DBus",
244 "org.freedesktop.DBus",
247 } else if (streq(new_owner, a->unique_name)) {
249 r = sd_bus_message_new_signal(
252 "/org/freedesktop/DBus",
253 "org.freedesktop.DBus",
261 r = sd_bus_message_append(n, "s", name);
265 r = bus_message_append_sender(n, "org.freedesktop.DBus");
269 r = bus_seal_synthetic_message(b, n);
273 return sd_bus_send(b, n, NULL);
276 static int process_policy(sd_bus *a, sd_bus *b, sd_bus_message *m) {
277 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
284 if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll"))
287 if (!streq_ptr(m->path, "/org/gnome/DisplayManager/Slave"))
290 r = sd_bus_message_new_method_errorf(m, &n, SD_BUS_ERROR_ACCESS_DENIED, "gdm, you are stupid");
294 r = bus_message_append_sender(n, "org.freedesktop.DBus");
296 log_error("Failed to append sender to gdm reply: %s", strerror(-r));
300 r = bus_seal_synthetic_message(b, n);
302 log_error("Failed to seal gdm reply: %s", strerror(-r));
306 r = sd_bus_send(b, n, NULL);
308 log_error("Failed to send gdm reply: %s", strerror(-r));
315 static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
321 r = bus_message_append_sender(m, "org.freedesktop.DBus");
325 r = bus_seal_synthetic_message(b, m);
329 return sd_bus_send(b, m, NULL);
332 static int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
333 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
336 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
339 r = sd_bus_message_new_method_error(call, &m, e);
343 return synthetic_driver_send(call->bus, m);
346 static int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
348 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
350 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
353 if (sd_bus_error_is_set(p))
354 return synthetic_reply_method_error(call, p);
356 sd_bus_error_set_errno(&berror, error);
358 return synthetic_reply_method_error(call, &berror);
361 static int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
362 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
365 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
368 r = sd_bus_message_new_method_return(call, &m);
372 if (!isempty(types)) {
376 r = bus_message_append_ap(m, types, ap);
382 return synthetic_driver_send(call->bus, m);
385 static int synthetic_reply_return_strv(sd_bus_message *call, char **l) {
386 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
389 r = sd_bus_message_new_method_return(call, &m);
391 return synthetic_reply_method_errno(call, r, NULL);
393 r = sd_bus_message_append_strv(m, l);
395 return synthetic_reply_method_errno(call, r, NULL);
397 return synthetic_driver_send(call->bus, m);
400 static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
401 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
408 assert_return(service_name_is_valid(name), -EINVAL);
410 r = sd_bus_get_owner(bus, name, mask, &c);
411 if (r == -ESRCH || r == -ENXIO)
412 return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
416 if ((c->mask & mask) != mask)
425 static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
433 r = sd_bus_message_read(m, "s", &name);
437 return get_creds_by_name(bus, name, mask, _creds, error);
440 static int peer_is_privileged(sd_bus *bus, sd_bus_message *m) {
441 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
445 r = get_creds_by_message(bus, m, SD_BUS_CREDS_UID, &creds, NULL);
449 r = sd_bus_creds_get_uid(creds, &uid);
453 r = sd_bus_creds_has_effective_cap(creds, CAP_SYS_ADMIN);
463 static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
470 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
473 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
474 if (0 && !isempty(sd_bus_message_get_signature(m, true))) {
475 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
477 r = sd_bus_error_setf(&error, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
479 return synthetic_reply_method_errno(m, r, &error);
482 return synthetic_reply_method_return(m, "s",
483 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
484 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
486 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
487 " <method name=\"Introspect\">\n"
488 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
491 " <interface name=\"org.freedesktop.DBus\">\n"
492 " <method name=\"AddMatch\">\n"
493 " <arg type=\"s\" direction=\"in\"/>\n"
495 " <method name=\"RemoveMatch\">\n"
496 " <arg type=\"s\" direction=\"in\"/>\n"
498 " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
499 " <arg type=\"s\" direction=\"in\"/>\n"
500 " <arg type=\"ay\" direction=\"out\"/>\n"
502 " <method name=\"GetConnectionUnixProcessID\">\n"
503 " <arg type=\"s\" direction=\"in\"/>\n"
504 " <arg type=\"u\" direction=\"out\"/>\n"
506 " <method name=\"GetConnectionUnixUser\">\n"
507 " <arg type=\"s\" direction=\"in\"/>\n"
508 " <arg type=\"u\" direction=\"out\"/>\n"
510 " <method name=\"GetId\">\n"
511 " <arg type=\"s\" direction=\"out\"/>\n"
513 " <method name=\"GetNameOwner\">\n"
514 " <arg type=\"s\" direction=\"in\"/>\n"
515 " <arg type=\"s\" direction=\"out\"/>\n"
517 " <method name=\"Hello\">\n"
518 " <arg type=\"s\" direction=\"out\"/>\n"
520 " <method name=\"ListActivatableNames\">\n"
521 " <arg type=\"as\" direction=\"out\"/>\n"
523 " <method name=\"ListNames\">\n"
524 " <arg type=\"as\" direction=\"out\"/>\n"
526 " <method name=\"ListQueuedOwners\">\n"
527 " <arg type=\"s\" direction=\"in\"/>\n"
528 " <arg type=\"as\" direction=\"out\"/>\n"
530 " <method name=\"NameHasOwner\">\n"
531 " <arg type=\"s\" direction=\"in\"/>\n"
532 " <arg type=\"b\" direction=\"out\"/>\n"
534 " <method name=\"ReleaseName\">\n"
535 " <arg type=\"s\" direction=\"in\"/>\n"
536 " <arg type=\"u\" direction=\"out\"/>\n"
538 " <method name=\"ReloadConfig\">\n"
540 " <method name=\"RequestName\">\n"
541 " <arg type=\"s\" direction=\"in\"/>\n"
542 " <arg type=\"u\" direction=\"in\"/>\n"
543 " <arg type=\"u\" direction=\"out\"/>\n"
545 " <method name=\"StartServiceByName\">\n"
546 " <arg type=\"s\" direction=\"in\"/>\n"
547 " <arg type=\"u\" direction=\"in\"/>\n"
548 " <arg type=\"u\" direction=\"out\"/>\n"
550 " <method name=\"UpdateActivationEnvironment\">\n"
551 " <arg type=\"a{ss}\" direction=\"in\"/>\n"
553 " <signal name=\"NameAcquired\">\n"
554 " <arg type=\"s\"/>\n"
556 " <signal name=\"NameLost\">\n"
557 " <arg type=\"s\"/>\n"
559 " <signal name=\"NameOwnerChanged\">\n"
560 " <arg type=\"s\"/>\n"
561 " <arg type=\"s\"/>\n"
562 " <arg type=\"s\"/>\n"
567 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
570 r = sd_bus_message_read(m, "s", &match);
572 return synthetic_reply_method_errno(m, r, NULL);
574 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
576 return synthetic_reply_method_errno(m, r, NULL);
578 return synthetic_reply_method_return(m, NULL);
580 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
583 r = sd_bus_message_read(m, "s", &match);
585 return synthetic_reply_method_errno(m, r, NULL);
587 r = bus_remove_match_by_string(a, match, NULL, NULL);
589 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
591 return synthetic_reply_method_errno(m, r, NULL);
593 return synthetic_reply_method_return(m, NULL);
595 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
596 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
598 r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, NULL);
600 return synthetic_reply_method_errno(m, r, NULL);
602 return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
604 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
605 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
607 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, NULL);
609 return synthetic_reply_method_errno(m, r, NULL);
611 return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
613 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
614 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
616 r = get_creds_by_message(a, m, SD_BUS_CREDS_UID, &creds, NULL);
618 return synthetic_reply_method_errno(m, r, NULL);
620 return synthetic_reply_method_return(m, "u", (uint32_t) creds->uid);
622 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
623 sd_id128_t server_id;
624 char buf[SD_ID128_STRING_MAX];
626 r = sd_bus_get_server_id(a, &server_id);
628 return synthetic_reply_method_errno(m, r, NULL);
630 return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
632 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
634 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
635 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
637 r = sd_bus_message_read(m, "s", &name);
639 return synthetic_reply_method_errno(m, r, NULL);
641 if (streq(name, "org.freedesktop.DBus"))
642 return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
644 r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
646 return synthetic_reply_method_errno(m, r, &error);
648 return synthetic_reply_method_return(m, "s", creds->unique_name);
650 /* "Hello" is handled in process_hello() */
652 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
653 _cleanup_strv_free_ char **names = NULL;
655 r = sd_bus_list_names(a, NULL, &names);
657 return synthetic_reply_method_errno(m, r, NULL);
659 /* Let's sort the names list to make it stable */
662 return synthetic_reply_return_strv(m, names);
664 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
665 _cleanup_strv_free_ char **names = NULL;
667 r = sd_bus_list_names(a, &names, NULL);
669 return synthetic_reply_method_errno(m, r, NULL);
671 r = strv_extend(&names, "org.freedesktop.DBus");
673 return synthetic_reply_method_errno(m, r, NULL);
675 /* Let's sort the names list to make it stable */
678 return synthetic_reply_return_strv(m, names);
680 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
681 struct kdbus_cmd_name_list cmd = {};
682 struct kdbus_name_list *name_list;
683 struct kdbus_cmd_name *name;
684 _cleanup_strv_free_ char **owners = NULL;
688 r = sd_bus_message_read(m, "s", &arg0);
690 return synthetic_reply_method_errno(m, r, NULL);
692 if (service_name_is_valid(arg0) < 0)
693 return synthetic_reply_method_errno(m, -EINVAL, NULL);
695 cmd.flags = KDBUS_NAME_LIST_QUEUED;
696 r = ioctl(a->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
698 return synthetic_reply_method_errno(m, -errno, NULL);
700 name_list = (struct kdbus_name_list *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
702 KDBUS_ITEM_FOREACH(name, name_list, names) {
705 if (name->size <= sizeof(*name))
708 if (!streq(name->name, arg0))
711 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
716 r = strv_consume(&owners, n);
723 r = ioctl(a->input_fd, KDBUS_CMD_FREE, &cmd.offset);
725 return synthetic_reply_method_errno(m, r, NULL);
728 return synthetic_reply_method_errno(m, err, NULL);
730 return synthetic_reply_return_strv(m, owners);
732 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
735 r = sd_bus_message_read(m, "s", &name);
737 return synthetic_reply_method_errno(m, r, NULL);
739 if (service_name_is_valid(name) < 0)
740 return synthetic_reply_method_errno(m, -EINVAL, NULL);
742 if (streq(name, "org.freedesktop.DBus"))
743 return synthetic_reply_method_return(m, "b", true);
745 r = sd_bus_get_owner(a, name, 0, NULL);
746 if (r < 0 && r != -ESRCH && r != -ENXIO)
747 return synthetic_reply_method_errno(m, r, NULL);
749 return synthetic_reply_method_return(m, "b", r >= 0);
751 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
754 r = sd_bus_message_read(m, "s", &name);
756 return synthetic_reply_method_errno(m, r, NULL);
758 if (service_name_is_valid(name) < 0)
759 return synthetic_reply_method_errno(m, -EINVAL, NULL);
761 r = sd_bus_release_name(a, name);
764 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
765 if (r == -EADDRINUSE)
766 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
768 return synthetic_reply_method_errno(m, r, NULL);
771 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
773 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
774 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
776 r = sd_bus_error_setf(&error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
778 return synthetic_reply_method_errno(m, r, &error);
780 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
784 r = sd_bus_message_read(m, "su", &name, &flags);
786 return synthetic_reply_method_errno(m, r, NULL);
788 if (service_name_is_valid(name) < 0)
789 return synthetic_reply_method_errno(m, -EINVAL, NULL);
790 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
791 return synthetic_reply_method_errno(m, -EINVAL, NULL);
793 r = sd_bus_request_name(a, name, flags);
796 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
798 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
799 return synthetic_reply_method_errno(m, r, NULL);
803 return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
805 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
807 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
808 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
812 r = sd_bus_message_read(m, "su", &name, &flags);
814 return synthetic_reply_method_errno(m, r, NULL);
816 if (service_name_is_valid(name) < 0)
817 return synthetic_reply_method_errno(m, -EINVAL, NULL);
819 return synthetic_reply_method_errno(m, -EINVAL, NULL);
821 r = sd_bus_get_owner(a, name, 0, NULL);
822 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
823 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
825 return synthetic_reply_method_errno(m, r, NULL);
827 r = sd_bus_message_new_method_call(
832 "org.freedesktop.DBus.Peer",
835 return synthetic_reply_method_errno(m, r, NULL);
837 r = sd_bus_send(a, msg, NULL);
839 return synthetic_reply_method_errno(m, r, NULL);
841 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
843 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
844 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
845 _cleanup_strv_free_ char **args = NULL;
847 if (!peer_is_privileged(a, m))
848 return synthetic_reply_method_errno(m, -EPERM, NULL);
850 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
852 return synthetic_reply_method_errno(m, r, NULL);
854 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
855 _cleanup_free_ char *s = NULL;
859 r = sd_bus_message_read(m, "ss", &key, &value);
861 return synthetic_reply_method_errno(m, r, NULL);
863 s = strjoin(key, "=", value, NULL);
865 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
867 r = strv_extend(&args, s);
869 return synthetic_reply_method_errno(m, r, NULL);
871 r = sd_bus_message_exit_container(m);
873 return synthetic_reply_method_errno(m, r, NULL);
876 r = sd_bus_message_exit_container(m);
878 return synthetic_reply_method_errno(m, r, NULL);
881 return synthetic_reply_method_errno(m, -EINVAL, NULL);
883 r = sd_bus_message_new_method_call(
886 "org.freedesktop.systemd1",
887 "/org/freedesktop/systemd1",
888 "org.freedesktop.systemd1.Manager",
891 return synthetic_reply_method_errno(m, r, NULL);
893 r = sd_bus_message_append_strv(msg, args);
895 return synthetic_reply_method_errno(m, r, NULL);
897 r = sd_bus_call(a, msg, 0, NULL, NULL);
899 return synthetic_reply_method_errno(m, r, NULL);
901 return synthetic_reply_method_return(m, NULL);
904 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
906 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
908 return synthetic_reply_method_errno(m, r, &error);
912 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
913 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
922 /* As reaction to hello we need to respond with two messages:
923 * the callback reply and the NameAcquired for the unique
924 * name, since hello is otherwise obsolete on kdbus. */
927 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
928 streq_ptr(m->destination, "org.freedesktop.DBus");
935 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
940 log_error("Got duplicate hello, aborting.");
949 r = sd_bus_message_new_method_return(m, &n);
951 log_error("Failed to generate HELLO reply: %s", strerror(-r));
955 r = sd_bus_message_append(n, "s", a->unique_name);
957 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
961 r = bus_message_append_sender(n, "org.freedesktop.DBus");
963 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
967 r = bus_seal_synthetic_message(b, n);
969 log_error("Failed to seal HELLO reply: %s", strerror(-r));
973 r = sd_bus_send(b, n, NULL);
975 log_error("Failed to send HELLO reply: %s", strerror(-r));
979 n = sd_bus_message_unref(n);
980 r = sd_bus_message_new_signal(
983 "/org/freedesktop/DBus",
984 "org.freedesktop.DBus",
987 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
991 r = sd_bus_message_append(n, "s", a->unique_name);
993 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
997 r = bus_message_append_sender(n, "org.freedesktop.DBus");
999 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
1003 r = bus_seal_synthetic_message(b, n);
1005 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
1009 r = sd_bus_send(b, n, NULL);
1011 log_error("Failed to send NameAcquired message: %s", strerror(-r));
1018 static int patch_sender(sd_bus *a, sd_bus_message *m) {
1019 char **well_known = NULL;
1029 /* We will change the sender of messages from the bus driver
1030 * so that they originate from the bus driver. This is a
1031 * speciality originating from dbus1, where the bus driver did
1032 * not have a unique id, but only the well-known name. */
1034 c = sd_bus_message_get_creds(m);
1038 r = sd_bus_creds_get_well_known_names(c, &well_known);
1042 if (strv_contains(well_known, "org.freedesktop.DBus"))
1043 m->sender = "org.freedesktop.DBus";
1048 int main(int argc, char *argv[]) {
1050 _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
1051 sd_id128_t server_id;
1052 int r, in_fd, out_fd;
1053 bool got_hello = false;
1055 struct ucred ucred = {};
1056 _cleanup_free_ char *peersec = NULL;
1059 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
1060 log_parse_environment();
1063 r = parse_argv(argc, argv);
1067 r = policy_load(&policy, arg_configuration);
1069 log_error("Failed to load policy: %s", strerror(-r));
1073 /* policy_dump(&policy); */
1075 r = sd_listen_fds(0);
1077 in_fd = STDIN_FILENO;
1078 out_fd = STDOUT_FILENO;
1079 } else if (r == 1) {
1080 in_fd = SD_LISTEN_FDS_START;
1081 out_fd = SD_LISTEN_FDS_START;
1083 log_error("Illegal number of file descriptors passed");
1088 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
1089 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
1092 getpeercred(in_fd, &ucred);
1093 getpeersec(in_fd, &peersec);
1096 if (arg_drop_privileges) {
1097 const char *user = "systemd-bus-proxy";
1101 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
1103 log_error("Cannot resolve user name %s: %s", user, strerror(-r));
1107 r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
1114 log_error("Failed to allocate bus: %s", strerror(-r));
1118 r = sd_bus_set_name(a, "sd-proxy");
1120 log_error("Failed to set bus name: %s", strerror(-r));
1124 r = sd_bus_set_address(a, arg_address);
1126 log_error("Failed to set address to connect to: %s", strerror(-r));
1130 r = sd_bus_negotiate_fds(a, is_unix);
1132 log_error("Failed to set FD negotiation: %s", strerror(-r));
1136 if (ucred.pid > 0) {
1137 a->fake_creds.pid = ucred.pid;
1138 a->fake_creds.uid = ucred.uid;
1139 a->fake_creds.gid = ucred.gid;
1140 a->fake_creds_valid = true;
1144 a->fake_label = peersec;
1148 a->manual_peer_interface = true;
1150 r = sd_bus_start(a);
1152 log_error("Failed to start bus client: %s", strerror(-r));
1156 r = sd_bus_get_server_id(a, &server_id);
1158 log_error("Failed to get server ID: %s", strerror(-r));
1164 log_error("Failed to allocate bus: %s", strerror(-r));
1168 r = sd_bus_set_fd(b, in_fd, out_fd);
1170 log_error("Failed to set fds: %s", strerror(-r));
1174 r = sd_bus_set_server(b, 1, server_id);
1176 log_error("Failed to set server mode: %s", strerror(-r));
1180 r = sd_bus_negotiate_fds(b, is_unix);
1182 log_error("Failed to set FD negotiation: %s", strerror(-r));
1186 r = sd_bus_set_anonymous(b, true);
1188 log_error("Failed to set anonymous authentication: %s", strerror(-r));
1192 b->manual_peer_interface = true;
1194 r = sd_bus_start(b);
1196 log_error("Failed to start bus client: %s", strerror(-r));
1200 r = rename_service(a, b);
1202 log_debug("Failed to rename process: %s", strerror(-r));
1205 _cleanup_free_ char *match = NULL;
1208 r = sd_bus_get_unique_name(a, &unique);
1210 log_error("Failed to get unique name: %s", strerror(-r));
1214 match = strjoin("type='signal',"
1215 "sender='org.freedesktop.DBus',"
1216 "path='/org/freedesktop/DBus',"
1217 "interface='org.freedesktop.DBus',"
1218 "member='NameOwnerChanged',"
1228 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1230 log_error("Failed to add match for NameLost: %s", strerror(-r));
1235 match = strjoin("type='signal',"
1236 "sender='org.freedesktop.DBus',"
1237 "path='/org/freedesktop/DBus',"
1238 "interface='org.freedesktop.DBus',"
1239 "member='NameOwnerChanged',"
1249 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1251 log_error("Failed to add match for NameAcquired: %s", strerror(-r));
1257 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1258 int events_a, events_b, fd;
1259 uint64_t timeout_a, timeout_b, t;
1260 struct timespec _ts, *ts;
1261 struct pollfd *pollfd;
1265 r = sd_bus_process(a, &m);
1267 /* treat 'connection reset by peer' as clean exit condition */
1268 if (r == -ECONNRESET)
1271 log_error("Failed to process bus a: %s", strerror(-r));
1277 /* We officially got EOF, let's quit */
1278 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1283 k = synthesize_name_acquired(a, b, m);
1286 log_error("Failed to synthesize message: %s", strerror(-r));
1292 k = sd_bus_send(b, m, NULL);
1294 if (k == -ECONNRESET)
1298 log_error("Failed to send message: %s", strerror(-r));
1309 r = sd_bus_process(b, &m);
1311 /* treat 'connection reset by peer' as clean exit condition */
1312 if (r == -ECONNRESET)
1315 log_error("Failed to process bus b: %s", strerror(-r));
1321 /* We officially got EOF, let's quit */
1322 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1327 k = process_hello(a, b, m, &got_hello);
1330 log_error("Failed to process HELLO: %s", strerror(-r));
1337 k = process_policy(a, b, m);
1340 log_error("Failed to process policy: %s", strerror(-r));
1344 k = process_driver(a, b, m);
1347 log_error("Failed to process driver calls: %s", strerror(-r));
1354 k = sd_bus_send(a, m, NULL);
1356 if (r == -ECONNRESET)
1360 log_error("Failed to send message: %s", strerror(-r));
1372 fd = sd_bus_get_fd(a);
1374 log_error("Failed to get fd: %s", strerror(-r));
1378 events_a = sd_bus_get_events(a);
1380 log_error("Failed to get events mask: %s", strerror(-r));
1384 r = sd_bus_get_timeout(a, &timeout_a);
1386 log_error("Failed to get timeout: %s", strerror(-r));
1390 events_b = sd_bus_get_events(b);
1392 log_error("Failed to get events mask: %s", strerror(-r));
1396 r = sd_bus_get_timeout(b, &timeout_b);
1398 log_error("Failed to get timeout: %s", strerror(-r));
1403 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
1406 if (t == (uint64_t) -1)
1411 nw = now(CLOCK_MONOTONIC);
1417 ts = timespec_store(&_ts, t);
1420 pollfd = (struct pollfd[3]) {
1421 {.fd = fd, .events = events_a, },
1422 {.fd = in_fd, .events = events_b & POLLIN, },
1423 {.fd = out_fd, .events = events_b & POLLOUT, }
1426 r = ppoll(pollfd, 3, ts, NULL);
1428 log_error("ppoll() failed: %m");
1437 policy_free(&policy);
1438 strv_free(arg_configuration);
1440 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;