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 = DEFAULT_SYSTEM_BUS_PATH;
51 static char *arg_command_line_buffer = NULL;
52 static bool arg_drop_privileges = false;
54 static int help(void) {
56 printf("%s [OPTIONS...]\n\n"
57 "Connect STDIO or a socket to a given bus address.\n\n"
58 " -h --help Show this help\n"
59 " --version Show package version\n"
60 " --drop-privileges Drop privileges\n"
61 " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
62 " (default: " DEFAULT_SYSTEM_BUS_PATH ")\n",
63 program_invocation_short_name);
68 static int parse_argv(int argc, char *argv[]) {
76 static const struct option options[] = {
77 { "help", no_argument, NULL, 'h' },
78 { "version", no_argument, NULL, ARG_VERSION },
79 { "address", required_argument, NULL, ARG_ADDRESS },
80 { "drop-privileges", no_argument, NULL, ARG_DROP_PRIVILEGES },
89 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
99 puts(SYSTEMD_FEATURES);
103 arg_address = optarg;
106 case ARG_DROP_PRIVILEGES:
107 arg_drop_privileges = true;
114 assert_not_reached("Unhandled option");
118 /* If the first command line argument is only "x" characters
119 * we'll write who we are talking to into it, so that "ps" is
121 arg_command_line_buffer = argv[optind];
122 if (argc > optind + 1 ||
123 (arg_command_line_buffer && arg_command_line_buffer[strspn(arg_command_line_buffer, "x")] != 0)) {
124 log_error("Too many arguments");
131 static int rename_service(sd_bus *a, sd_bus *b) {
132 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
133 _cleanup_free_ char *p = NULL, *name = NULL;
143 r = sd_bus_get_peer_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM, &creds);
147 r = sd_bus_creds_get_uid(creds, &uid);
151 r = sd_bus_creds_get_pid(creds, &pid);
155 r = sd_bus_creds_get_cmdline(creds, &cmdline);
159 r = sd_bus_creds_get_comm(creds, &comm);
163 name = uid_to_name(uid);
167 p = strv_join(cmdline, " ");
171 /* The status string gets the full command line ... */
173 "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
177 /* ... and the argv line only the short comm */
178 if (arg_command_line_buffer) {
181 m = strlen(arg_command_line_buffer);
182 w = snprintf(arg_command_line_buffer, m,
183 "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
188 memzero(arg_command_line_buffer + w, m - w);
191 log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
199 static int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
200 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
201 const char *name, *old_owner, *new_owner;
208 /* If we get NameOwnerChanged for our own name, we need to
209 * synthesize NameLost/NameAcquired, since socket clients need
210 * that, even though it is obsoleted on kdbus */
215 if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
216 !streq_ptr(m->path, "/org/freedesktop/DBus") ||
217 !streq_ptr(m->sender, "org.freedesktop.DBus"))
220 r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
224 r = sd_bus_message_rewind(m, true);
228 if (streq(old_owner, a->unique_name)) {
230 r = sd_bus_message_new_signal(
233 "/org/freedesktop/DBus",
234 "org.freedesktop.DBus",
237 } else if (streq(new_owner, a->unique_name)) {
239 r = sd_bus_message_new_signal(
242 "/org/freedesktop/DBus",
243 "org.freedesktop.DBus",
251 r = sd_bus_message_append(n, "s", name);
255 r = bus_message_append_sender(n, "org.freedesktop.DBus");
259 r = bus_seal_synthetic_message(b, n);
263 return sd_bus_send(b, n, NULL);
266 static int process_policy(sd_bus *a, sd_bus *b, sd_bus_message *m) {
267 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
274 if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll"))
277 if (!streq_ptr(m->path, "/org/gnome/DisplayManager/Slave"))
280 r = sd_bus_message_new_method_errorf(m, &n, SD_BUS_ERROR_ACCESS_DENIED, "gdm, you are stupid");
284 r = bus_message_append_sender(n, "org.freedesktop.DBus");
286 log_error("Failed to append sender to gdm reply: %s", strerror(-r));
290 r = bus_seal_synthetic_message(b, n);
292 log_error("Failed to seal gdm reply: %s", strerror(-r));
296 r = sd_bus_send(b, n, NULL);
298 log_error("Failed to send gdm reply: %s", strerror(-r));
305 static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
311 r = bus_message_append_sender(m, "org.freedesktop.DBus");
315 r = bus_seal_synthetic_message(b, m);
319 return sd_bus_send(b, m, NULL);
322 static int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
323 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
326 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
329 r = sd_bus_message_new_method_error(call, &m, e);
333 return synthetic_driver_send(call->bus, m);
336 static int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
338 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
340 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
343 if (sd_bus_error_is_set(p))
344 return synthetic_reply_method_error(call, p);
346 sd_bus_error_set_errno(&berror, error);
348 return synthetic_reply_method_error(call, &berror);
351 static int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
352 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
355 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
358 r = sd_bus_message_new_method_return(call, &m);
362 if (!isempty(types)) {
366 r = bus_message_append_ap(m, types, ap);
372 return synthetic_driver_send(call->bus, m);
375 static int synthetic_reply_return_strv(sd_bus_message *call, char **l) {
376 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
379 r = sd_bus_message_new_method_return(call, &m);
381 return synthetic_reply_method_errno(call, r, NULL);
383 r = sd_bus_message_append_strv(m, l);
385 return synthetic_reply_method_errno(call, r, NULL);
387 return synthetic_driver_send(call->bus, m);
390 static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
391 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
398 assert_return(service_name_is_valid(name), -EINVAL);
400 r = sd_bus_get_owner(bus, name, mask, &c);
401 if (r == -ESRCH || r == -ENXIO)
402 return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
406 if ((c->mask & mask) != mask)
415 static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
423 r = sd_bus_message_read(m, "s", &name);
427 return get_creds_by_name(bus, name, mask, _creds, error);
430 static int peer_is_privileged(sd_bus *bus, sd_bus_message *m) {
431 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
435 r = get_creds_by_message(bus, m, SD_BUS_CREDS_UID, &creds, NULL);
439 r = sd_bus_creds_get_uid(creds, &uid);
443 r = sd_bus_creds_has_effective_cap(creds, CAP_SYS_ADMIN);
453 static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
460 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
463 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
464 if (0 && !isempty(sd_bus_message_get_signature(m, true))) {
465 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
467 r = sd_bus_error_setf(&error, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
469 return synthetic_reply_method_errno(m, r, &error);
472 return synthetic_reply_method_return(m, "s",
473 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
474 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
476 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
477 " <method name=\"Introspect\">\n"
478 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
481 " <interface name=\"org.freedesktop.DBus\">\n"
482 " <method name=\"AddMatch\">\n"
483 " <arg type=\"s\" direction=\"in\"/>\n"
485 " <method name=\"RemoveMatch\">\n"
486 " <arg type=\"s\" direction=\"in\"/>\n"
488 " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
489 " <arg type=\"s\" direction=\"in\"/>\n"
490 " <arg type=\"ay\" direction=\"out\"/>\n"
492 " <method name=\"GetConnectionUnixProcessID\">\n"
493 " <arg type=\"s\" direction=\"in\"/>\n"
494 " <arg type=\"u\" direction=\"out\"/>\n"
496 " <method name=\"GetConnectionUnixUser\">\n"
497 " <arg type=\"s\" direction=\"in\"/>\n"
498 " <arg type=\"u\" direction=\"out\"/>\n"
500 " <method name=\"GetId\">\n"
501 " <arg type=\"s\" direction=\"out\"/>\n"
503 " <method name=\"GetNameOwner\">\n"
504 " <arg type=\"s\" direction=\"in\"/>\n"
505 " <arg type=\"s\" direction=\"out\"/>\n"
507 " <method name=\"Hello\">\n"
508 " <arg type=\"s\" direction=\"out\"/>\n"
510 " <method name=\"ListActivatableNames\">\n"
511 " <arg type=\"as\" direction=\"out\"/>\n"
513 " <method name=\"ListNames\">\n"
514 " <arg type=\"as\" direction=\"out\"/>\n"
516 " <method name=\"ListQueuedOwners\">\n"
517 " <arg type=\"s\" direction=\"in\"/>\n"
518 " <arg type=\"as\" direction=\"out\"/>\n"
520 " <method name=\"NameHasOwner\">\n"
521 " <arg type=\"s\" direction=\"in\"/>\n"
522 " <arg type=\"b\" direction=\"out\"/>\n"
524 " <method name=\"ReleaseName\">\n"
525 " <arg type=\"s\" direction=\"in\"/>\n"
526 " <arg type=\"u\" direction=\"out\"/>\n"
528 " <method name=\"ReloadConfig\">\n"
530 " <method name=\"RequestName\">\n"
531 " <arg type=\"s\" direction=\"in\"/>\n"
532 " <arg type=\"u\" direction=\"in\"/>\n"
533 " <arg type=\"u\" direction=\"out\"/>\n"
535 " <method name=\"StartServiceByName\">\n"
536 " <arg type=\"s\" direction=\"in\"/>\n"
537 " <arg type=\"u\" direction=\"in\"/>\n"
538 " <arg type=\"u\" direction=\"out\"/>\n"
540 " <method name=\"UpdateActivationEnvironment\">\n"
541 " <arg type=\"a{ss}\" direction=\"in\"/>\n"
543 " <signal name=\"NameAcquired\">\n"
544 " <arg type=\"s\"/>\n"
546 " <signal name=\"NameLost\">\n"
547 " <arg type=\"s\"/>\n"
549 " <signal name=\"NameOwnerChanged\">\n"
550 " <arg type=\"s\"/>\n"
551 " <arg type=\"s\"/>\n"
552 " <arg type=\"s\"/>\n"
557 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
560 r = sd_bus_message_read(m, "s", &match);
562 return synthetic_reply_method_errno(m, r, NULL);
564 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
566 return synthetic_reply_method_errno(m, r, NULL);
568 return synthetic_reply_method_return(m, NULL);
570 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
573 r = sd_bus_message_read(m, "s", &match);
575 return synthetic_reply_method_errno(m, r, NULL);
577 r = bus_remove_match_by_string(a, match, NULL, NULL);
579 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
581 return synthetic_reply_method_errno(m, r, NULL);
583 return synthetic_reply_method_return(m, NULL);
585 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
586 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
588 r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, NULL);
590 return synthetic_reply_method_errno(m, r, NULL);
592 return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
594 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
595 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
597 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, NULL);
599 return synthetic_reply_method_errno(m, r, NULL);
601 return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
603 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
604 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
606 r = get_creds_by_message(a, m, SD_BUS_CREDS_UID, &creds, NULL);
608 return synthetic_reply_method_errno(m, r, NULL);
610 return synthetic_reply_method_return(m, "u", (uint32_t) creds->uid);
612 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
613 sd_id128_t server_id;
614 char buf[SD_ID128_STRING_MAX];
616 r = sd_bus_get_server_id(a, &server_id);
618 return synthetic_reply_method_errno(m, r, NULL);
620 return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
622 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
624 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
625 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
627 r = sd_bus_message_read(m, "s", &name);
629 return synthetic_reply_method_errno(m, r, NULL);
631 if (streq(name, "org.freedesktop.DBus"))
632 return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
634 r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
636 return synthetic_reply_method_errno(m, r, &error);
638 return synthetic_reply_method_return(m, "s", creds->unique_name);
640 /* "Hello" is handled in process_hello() */
642 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
643 _cleanup_strv_free_ char **names = NULL;
645 r = sd_bus_list_names(a, NULL, &names);
647 return synthetic_reply_method_errno(m, r, NULL);
649 /* Let's sort the names list to make it stable */
652 return synthetic_reply_return_strv(m, names);
654 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
655 _cleanup_strv_free_ char **names = NULL;
657 r = sd_bus_list_names(a, &names, NULL);
659 return synthetic_reply_method_errno(m, r, NULL);
661 r = strv_extend(&names, "org.freedesktop.DBus");
663 return synthetic_reply_method_errno(m, r, NULL);
665 /* Let's sort the names list to make it stable */
668 return synthetic_reply_return_strv(m, names);
670 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
671 struct kdbus_cmd_name_list cmd = {};
672 struct kdbus_name_list *name_list;
673 struct kdbus_cmd_name *name;
674 _cleanup_strv_free_ char **owners = NULL;
678 r = sd_bus_message_read(m, "s", &arg0);
680 return synthetic_reply_method_errno(m, r, NULL);
682 if (service_name_is_valid(arg0) < 0)
683 return synthetic_reply_method_errno(m, -EINVAL, NULL);
685 cmd.flags = KDBUS_NAME_LIST_QUEUED;
686 r = ioctl(a->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
688 return synthetic_reply_method_errno(m, -errno, NULL);
690 name_list = (struct kdbus_name_list *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
692 KDBUS_ITEM_FOREACH(name, name_list, names) {
695 if (name->size <= sizeof(*name))
698 if (!streq(name->name, arg0))
701 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
706 r = strv_consume(&owners, n);
713 r = ioctl(a->input_fd, KDBUS_CMD_FREE, &cmd.offset);
715 return synthetic_reply_method_errno(m, r, NULL);
718 return synthetic_reply_method_errno(m, err, NULL);
720 return synthetic_reply_return_strv(m, owners);
722 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
725 r = sd_bus_message_read(m, "s", &name);
727 return synthetic_reply_method_errno(m, r, NULL);
729 if (service_name_is_valid(name) < 0)
730 return synthetic_reply_method_errno(m, -EINVAL, NULL);
732 if (streq(name, "org.freedesktop.DBus"))
733 return synthetic_reply_method_return(m, "b", true);
735 r = sd_bus_get_owner(a, name, 0, NULL);
736 if (r < 0 && r != -ESRCH && r != -ENXIO)
737 return synthetic_reply_method_errno(m, r, NULL);
739 return synthetic_reply_method_return(m, "b", r >= 0);
741 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
744 r = sd_bus_message_read(m, "s", &name);
746 return synthetic_reply_method_errno(m, r, NULL);
748 if (service_name_is_valid(name) < 0)
749 return synthetic_reply_method_errno(m, -EINVAL, NULL);
751 r = sd_bus_release_name(a, name);
754 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
755 if (r == -EADDRINUSE)
756 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
758 return synthetic_reply_method_errno(m, r, NULL);
761 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
763 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
764 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
766 r = sd_bus_error_setf(&error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
768 return synthetic_reply_method_errno(m, r, &error);
770 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
774 r = sd_bus_message_read(m, "su", &name, &flags);
776 return synthetic_reply_method_errno(m, r, NULL);
778 if (service_name_is_valid(name) < 0)
779 return synthetic_reply_method_errno(m, -EINVAL, NULL);
780 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
781 return synthetic_reply_method_errno(m, -EINVAL, NULL);
783 r = sd_bus_request_name(a, name, flags);
786 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
788 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
789 return synthetic_reply_method_errno(m, r, NULL);
793 return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
795 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
797 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
798 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
802 r = sd_bus_message_read(m, "su", &name, &flags);
804 return synthetic_reply_method_errno(m, r, NULL);
806 if (service_name_is_valid(name) < 0)
807 return synthetic_reply_method_errno(m, -EINVAL, NULL);
809 return synthetic_reply_method_errno(m, -EINVAL, NULL);
811 r = sd_bus_get_owner(a, name, 0, NULL);
812 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
813 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
815 return synthetic_reply_method_errno(m, r, NULL);
817 r = sd_bus_message_new_method_call(
822 "org.freedesktop.DBus.Peer",
825 return synthetic_reply_method_errno(m, r, NULL);
827 r = sd_bus_send(a, msg, NULL);
829 return synthetic_reply_method_errno(m, r, NULL);
831 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
833 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
834 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
835 _cleanup_strv_free_ char **args = NULL;
837 if (!peer_is_privileged(a, m))
838 return synthetic_reply_method_errno(m, -EPERM, NULL);
840 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
842 return synthetic_reply_method_errno(m, r, NULL);
844 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
845 _cleanup_free_ char *s = NULL;
849 r = sd_bus_message_read(m, "ss", &key, &value);
851 return synthetic_reply_method_errno(m, r, NULL);
853 s = strjoin(key, "=", value, NULL);
855 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
857 r = strv_extend(&args, s);
859 return synthetic_reply_method_errno(m, r, NULL);
861 r = sd_bus_message_exit_container(m);
863 return synthetic_reply_method_errno(m, r, NULL);
866 r = sd_bus_message_exit_container(m);
868 return synthetic_reply_method_errno(m, r, NULL);
871 return synthetic_reply_method_errno(m, -EINVAL, NULL);
873 r = sd_bus_message_new_method_call(
876 "org.freedesktop.systemd1",
877 "/org/freedesktop/systemd1",
878 "org.freedesktop.systemd1.Manager",
881 return synthetic_reply_method_errno(m, r, NULL);
883 r = sd_bus_message_append_strv(msg, args);
885 return synthetic_reply_method_errno(m, r, NULL);
887 r = sd_bus_call(a, msg, 0, NULL, NULL);
889 return synthetic_reply_method_errno(m, r, NULL);
891 return synthetic_reply_method_return(m, NULL);
894 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
896 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
898 return synthetic_reply_method_errno(m, r, &error);
902 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
903 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
912 /* As reaction to hello we need to respond with two messages:
913 * the callback reply and the NameAcquired for the unique
914 * name, since hello is otherwise obsolete on kdbus. */
917 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
918 streq_ptr(m->destination, "org.freedesktop.DBus");
925 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
930 log_error("Got duplicate hello, aborting.");
939 r = sd_bus_message_new_method_return(m, &n);
941 log_error("Failed to generate HELLO reply: %s", strerror(-r));
945 r = sd_bus_message_append(n, "s", a->unique_name);
947 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
951 r = bus_message_append_sender(n, "org.freedesktop.DBus");
953 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
957 r = bus_seal_synthetic_message(b, n);
959 log_error("Failed to seal HELLO reply: %s", strerror(-r));
963 r = sd_bus_send(b, n, NULL);
965 log_error("Failed to send HELLO reply: %s", strerror(-r));
969 n = sd_bus_message_unref(n);
970 r = sd_bus_message_new_signal(
973 "/org/freedesktop/DBus",
974 "org.freedesktop.DBus",
977 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
981 r = sd_bus_message_append(n, "s", a->unique_name);
983 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
987 r = bus_message_append_sender(n, "org.freedesktop.DBus");
989 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
993 r = bus_seal_synthetic_message(b, n);
995 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
999 r = sd_bus_send(b, n, NULL);
1001 log_error("Failed to send NameAcquired message: %s", strerror(-r));
1008 static int patch_sender(sd_bus *a, sd_bus_message *m) {
1009 char **well_known = NULL;
1019 /* We will change the sender of messages from the bus driver
1020 * so that they originate from the bus driver. This is a
1021 * speciality originating from dbus1, where the bus driver did
1022 * not have a unique id, but only the well-known name. */
1024 c = sd_bus_message_get_creds(m);
1028 r = sd_bus_creds_get_well_known_names(c, &well_known);
1032 if (strv_contains(well_known, "org.freedesktop.DBus"))
1033 m->sender = "org.freedesktop.DBus";
1038 int main(int argc, char *argv[]) {
1040 _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
1041 sd_id128_t server_id;
1042 int r, in_fd, out_fd;
1043 bool got_hello = false;
1045 struct ucred ucred = {};
1046 _cleanup_free_ char *peersec = NULL;
1049 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
1050 log_parse_environment();
1053 r = parse_argv(argc, argv);
1057 r = policy_load(&policy);
1059 log_error("Failed to load policy: %s", strerror(-r));
1063 /* policy_dump(&policy); */
1065 r = sd_listen_fds(0);
1067 in_fd = STDIN_FILENO;
1068 out_fd = STDOUT_FILENO;
1069 } else if (r == 1) {
1070 in_fd = SD_LISTEN_FDS_START;
1071 out_fd = SD_LISTEN_FDS_START;
1073 log_error("Illegal number of file descriptors passed");
1078 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
1079 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
1082 getpeercred(in_fd, &ucred);
1083 getpeersec(in_fd, &peersec);
1086 if (arg_drop_privileges) {
1087 const char *user = "systemd-bus-proxy";
1091 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
1093 log_error("Cannot resolve user name %s: %s", user, strerror(-r));
1097 r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
1104 log_error("Failed to allocate bus: %s", strerror(-r));
1108 r = sd_bus_set_name(a, "sd-proxy");
1110 log_error("Failed to set bus name: %s", strerror(-r));
1114 r = sd_bus_set_address(a, arg_address);
1116 log_error("Failed to set address to connect to: %s", strerror(-r));
1120 r = sd_bus_negotiate_fds(a, is_unix);
1122 log_error("Failed to set FD negotiation: %s", strerror(-r));
1126 if (ucred.pid > 0) {
1127 a->fake_creds.pid = ucred.pid;
1128 a->fake_creds.uid = ucred.uid;
1129 a->fake_creds.gid = ucred.gid;
1130 a->fake_creds_valid = true;
1134 a->fake_label = peersec;
1138 a->manual_peer_interface = true;
1140 r = sd_bus_start(a);
1142 log_error("Failed to start bus client: %s", strerror(-r));
1146 r = sd_bus_get_server_id(a, &server_id);
1148 log_error("Failed to get server ID: %s", strerror(-r));
1154 log_error("Failed to allocate bus: %s", strerror(-r));
1158 r = sd_bus_set_fd(b, in_fd, out_fd);
1160 log_error("Failed to set fds: %s", strerror(-r));
1164 r = sd_bus_set_server(b, 1, server_id);
1166 log_error("Failed to set server mode: %s", strerror(-r));
1170 r = sd_bus_negotiate_fds(b, is_unix);
1172 log_error("Failed to set FD negotiation: %s", strerror(-r));
1176 r = sd_bus_set_anonymous(b, true);
1178 log_error("Failed to set anonymous authentication: %s", strerror(-r));
1182 b->manual_peer_interface = true;
1184 r = sd_bus_start(b);
1186 log_error("Failed to start bus client: %s", strerror(-r));
1190 r = rename_service(a, b);
1192 log_debug("Failed to rename process: %s", strerror(-r));
1195 _cleanup_free_ char *match = NULL;
1198 r = sd_bus_get_unique_name(a, &unique);
1200 log_error("Failed to get unique name: %s", strerror(-r));
1204 match = strjoin("type='signal',"
1205 "sender='org.freedesktop.DBus',"
1206 "path='/org/freedesktop/DBus',"
1207 "interface='org.freedesktop.DBus',"
1208 "member='NameOwnerChanged',"
1218 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1220 log_error("Failed to add match for NameLost: %s", strerror(-r));
1225 match = strjoin("type='signal',"
1226 "sender='org.freedesktop.DBus',"
1227 "path='/org/freedesktop/DBus',"
1228 "interface='org.freedesktop.DBus',"
1229 "member='NameOwnerChanged',"
1239 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1241 log_error("Failed to add match for NameAcquired: %s", strerror(-r));
1247 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1248 int events_a, events_b, fd;
1249 uint64_t timeout_a, timeout_b, t;
1250 struct timespec _ts, *ts;
1251 struct pollfd *pollfd;
1255 r = sd_bus_process(a, &m);
1257 /* treat 'connection reset by peer' as clean exit condition */
1258 if (r == -ECONNRESET)
1261 log_error("Failed to process bus a: %s", strerror(-r));
1267 /* We officially got EOF, let's quit */
1268 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1273 k = synthesize_name_acquired(a, b, m);
1276 log_error("Failed to synthesize message: %s", strerror(-r));
1282 k = sd_bus_send(b, m, NULL);
1284 if (k == -ECONNRESET)
1288 log_error("Failed to send message: %s", strerror(-r));
1299 r = sd_bus_process(b, &m);
1301 /* treat 'connection reset by peer' as clean exit condition */
1302 if (r == -ECONNRESET)
1305 log_error("Failed to process bus b: %s", strerror(-r));
1311 /* We officially got EOF, let's quit */
1312 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1317 k = process_hello(a, b, m, &got_hello);
1320 log_error("Failed to process HELLO: %s", strerror(-r));
1327 k = process_policy(a, b, m);
1330 log_error("Failed to process policy: %s", strerror(-r));
1334 k = process_driver(a, b, m);
1337 log_error("Failed to process driver calls: %s", strerror(-r));
1344 k = sd_bus_send(a, m, NULL);
1346 if (r == -ECONNRESET)
1350 log_error("Failed to send message: %s", strerror(-r));
1362 fd = sd_bus_get_fd(a);
1364 log_error("Failed to get fd: %s", strerror(-r));
1368 events_a = sd_bus_get_events(a);
1370 log_error("Failed to get events mask: %s", strerror(-r));
1374 r = sd_bus_get_timeout(a, &timeout_a);
1376 log_error("Failed to get timeout: %s", strerror(-r));
1380 events_b = sd_bus_get_events(b);
1382 log_error("Failed to get events mask: %s", strerror(-r));
1386 r = sd_bus_get_timeout(b, &timeout_b);
1388 log_error("Failed to get timeout: %s", strerror(-r));
1393 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
1396 if (t == (uint64_t) -1)
1401 nw = now(CLOCK_MONOTONIC);
1407 ts = timespec_store(&_ts, t);
1410 pollfd = (struct pollfd[3]) {
1411 {.fd = fd, .events = events_a, },
1412 {.fd = in_fd, .events = events_b & POLLIN, },
1413 {.fd = out_fd, .events = events_b & POLLOUT, }
1416 r = ppoll(pollfd, 3, ts, NULL);
1418 log_error("ppoll() failed: %m");
1427 policy_free(&policy);
1429 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;