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 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 " --configuration=PATH Configuration file or directory\n"
62 " --machine=MACHINE Connect to specified machine\n"
63 " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
64 " (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n",
65 program_invocation_short_name);
70 static int parse_argv(int argc, char *argv[]) {
80 static const struct option options[] = {
81 { "help", no_argument, NULL, 'h' },
82 { "version", no_argument, NULL, ARG_VERSION },
83 { "address", required_argument, NULL, ARG_ADDRESS },
84 { "drop-privileges", no_argument, NULL, ARG_DROP_PRIVILEGES },
85 { "configuration", required_argument, NULL, ARG_CONFIGURATION },
86 { "machine", required_argument, NULL, ARG_MACHINE },
95 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
104 puts(PACKAGE_STRING);
105 puts(SYSTEMD_FEATURES);
120 case ARG_DROP_PRIVILEGES:
121 arg_drop_privileges = true;
124 case ARG_CONFIGURATION:
125 r = strv_extend(&arg_configuration, optarg);
131 _cleanup_free_ char *e = NULL;
134 e = bus_address_escape(optarg);
139 a = strjoin("x-container-kernel:machine=", e, ";x-container-unix:machine=", e, NULL);
141 a = strjoin("x-container-unix:machine=", e, NULL);
156 assert_not_reached("Unhandled option");
159 /* If the first command line argument is only "x" characters
160 * we'll write who we are talking to into it, so that "ps" is
162 arg_command_line_buffer = argv[optind];
163 if (argc > optind + 1 || (arg_command_line_buffer && !in_charset(arg_command_line_buffer, "x"))) {
164 log_error("Too many arguments");
169 arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS);
177 static int rename_service(sd_bus *a, sd_bus *b) {
178 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
179 _cleanup_free_ char *p = NULL, *name = NULL;
189 r = sd_bus_get_owner_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM, &creds);
193 r = sd_bus_creds_get_uid(creds, &uid);
197 r = sd_bus_creds_get_pid(creds, &pid);
201 r = sd_bus_creds_get_cmdline(creds, &cmdline);
205 r = sd_bus_creds_get_comm(creds, &comm);
209 name = uid_to_name(uid);
213 p = strv_join(cmdline, " ");
217 /* The status string gets the full command line ... */
219 "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
223 /* ... and the argv line only the short comm */
224 if (arg_command_line_buffer) {
227 m = strlen(arg_command_line_buffer);
228 w = snprintf(arg_command_line_buffer, m,
229 "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
234 memzero(arg_command_line_buffer + w, m - w);
237 log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
245 static int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
246 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
247 const char *name, *old_owner, *new_owner;
254 /* If we get NameOwnerChanged for our own name, we need to
255 * synthesize NameLost/NameAcquired, since socket clients need
256 * that, even though it is obsoleted on kdbus */
261 if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
262 !streq_ptr(m->path, "/org/freedesktop/DBus") ||
263 !streq_ptr(m->sender, "org.freedesktop.DBus"))
266 r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
270 r = sd_bus_message_rewind(m, true);
274 if (streq(old_owner, a->unique_name)) {
276 r = sd_bus_message_new_signal(
279 "/org/freedesktop/DBus",
280 "org.freedesktop.DBus",
283 } else if (streq(new_owner, a->unique_name)) {
285 r = sd_bus_message_new_signal(
288 "/org/freedesktop/DBus",
289 "org.freedesktop.DBus",
297 r = sd_bus_message_append(n, "s", name);
301 r = bus_message_append_sender(n, "org.freedesktop.DBus");
305 r = bus_seal_synthetic_message(b, n);
309 return sd_bus_send(b, n, NULL);
312 static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
318 r = bus_message_append_sender(m, "org.freedesktop.DBus");
322 r = bus_seal_synthetic_message(b, m);
326 return sd_bus_send(b, m, NULL);
329 static int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
330 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
335 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
338 r = sd_bus_message_new_method_error(call, &m, e);
342 return synthetic_driver_send(call->bus, m);
345 static int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
347 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
351 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
354 if (sd_bus_error_is_set(p))
355 return synthetic_reply_method_error(call, p);
357 sd_bus_error_set_errno(&berror, error);
359 return synthetic_reply_method_error(call, &berror);
362 static int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
363 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
368 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
371 r = sd_bus_message_new_method_return(call, &m);
375 if (!isempty(types)) {
379 r = bus_message_append_ap(m, types, ap);
385 return synthetic_driver_send(call->bus, m);
388 static int synthetic_reply_return_strv(sd_bus_message *call, char **l) {
389 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
394 r = sd_bus_message_new_method_return(call, &m);
396 return synthetic_reply_method_errno(call, r, NULL);
398 r = sd_bus_message_append_strv(m, l);
400 return synthetic_reply_method_errno(call, r, NULL);
402 return synthetic_driver_send(call->bus, m);
405 static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
406 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
413 r = sd_bus_get_name_creds(bus, name, mask, &c);
414 if (r == -ESRCH || r == -ENXIO)
415 return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
419 if ((c->mask & mask) != mask)
428 static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
436 r = sd_bus_message_read(m, "s", &name);
440 return get_creds_by_name(bus, name, mask, _creds, error);
443 static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, Policy *policy, const struct ucred *ucred, Set *owned_names) {
453 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
456 /* The "Hello()" call is is handled in process_hello() */
458 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
460 if (!sd_bus_message_has_signature(m, ""))
461 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
463 return synthetic_reply_method_return(m, "s",
464 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
465 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
467 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
468 " <method name=\"Introspect\">\n"
469 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
472 " <interface name=\"org.freedesktop.DBus\">\n"
473 " <method name=\"AddMatch\">\n"
474 " <arg type=\"s\" direction=\"in\"/>\n"
476 " <method name=\"RemoveMatch\">\n"
477 " <arg type=\"s\" direction=\"in\"/>\n"
479 " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
480 " <arg type=\"s\" direction=\"in\"/>\n"
481 " <arg type=\"ay\" direction=\"out\"/>\n"
483 " <method name=\"GetConnectionUnixProcessID\">\n"
484 " <arg type=\"s\" direction=\"in\"/>\n"
485 " <arg type=\"u\" direction=\"out\"/>\n"
487 " <method name=\"GetConnectionUnixUser\">\n"
488 " <arg type=\"s\" direction=\"in\"/>\n"
489 " <arg type=\"u\" direction=\"out\"/>\n"
491 " <method name=\"GetId\">\n"
492 " <arg type=\"s\" direction=\"out\"/>\n"
494 " <method name=\"GetNameOwner\">\n"
495 " <arg type=\"s\" direction=\"in\"/>\n"
496 " <arg type=\"s\" direction=\"out\"/>\n"
498 " <method name=\"Hello\">\n"
499 " <arg type=\"s\" direction=\"out\"/>\n"
501 " <method name=\"ListActivatableNames\">\n"
502 " <arg type=\"as\" direction=\"out\"/>\n"
504 " <method name=\"ListNames\">\n"
505 " <arg type=\"as\" direction=\"out\"/>\n"
507 " <method name=\"ListQueuedOwners\">\n"
508 " <arg type=\"s\" direction=\"in\"/>\n"
509 " <arg type=\"as\" direction=\"out\"/>\n"
511 " <method name=\"NameHasOwner\">\n"
512 " <arg type=\"s\" direction=\"in\"/>\n"
513 " <arg type=\"b\" direction=\"out\"/>\n"
515 " <method name=\"ReleaseName\">\n"
516 " <arg type=\"s\" direction=\"in\"/>\n"
517 " <arg type=\"u\" direction=\"out\"/>\n"
519 " <method name=\"ReloadConfig\">\n"
521 " <method name=\"RequestName\">\n"
522 " <arg type=\"s\" direction=\"in\"/>\n"
523 " <arg type=\"u\" direction=\"in\"/>\n"
524 " <arg type=\"u\" direction=\"out\"/>\n"
526 " <method name=\"StartServiceByName\">\n"
527 " <arg type=\"s\" direction=\"in\"/>\n"
528 " <arg type=\"u\" direction=\"in\"/>\n"
529 " <arg type=\"u\" direction=\"out\"/>\n"
531 " <method name=\"UpdateActivationEnvironment\">\n"
532 " <arg type=\"a{ss}\" direction=\"in\"/>\n"
534 " <signal name=\"NameAcquired\">\n"
535 " <arg type=\"s\"/>\n"
537 " <signal name=\"NameLost\">\n"
538 " <arg type=\"s\"/>\n"
540 " <signal name=\"NameOwnerChanged\">\n"
541 " <arg type=\"s\"/>\n"
542 " <arg type=\"s\"/>\n"
543 " <arg type=\"s\"/>\n"
548 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
551 if (!sd_bus_message_has_signature(m, "s"))
552 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
554 r = sd_bus_message_read(m, "s", &match);
556 return synthetic_reply_method_errno(m, r, NULL);
558 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
560 return synthetic_reply_method_errno(m, r, NULL);
562 return synthetic_reply_method_return(m, NULL);
564 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
567 if (!sd_bus_message_has_signature(m, "s"))
568 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
570 r = sd_bus_message_read(m, "s", &match);
572 return synthetic_reply_method_errno(m, r, NULL);
574 r = bus_remove_match_by_string(a, match, NULL, NULL);
576 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
578 return synthetic_reply_method_errno(m, r, NULL);
580 return synthetic_reply_method_return(m, NULL);
582 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
583 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
584 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
586 if (!sd_bus_message_has_signature(m, "s"))
587 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
589 r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error);
591 return synthetic_reply_method_errno(m, r, &error);
593 return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
595 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
596 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
597 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
599 if (!sd_bus_message_has_signature(m, "s"))
600 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
602 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, &error);
604 return synthetic_reply_method_errno(m, r, &error);
606 return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
608 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
609 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
610 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
612 if (!sd_bus_message_has_signature(m, "s"))
613 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
615 r = get_creds_by_message(a, m, SD_BUS_CREDS_UID, &creds, &error);
617 return synthetic_reply_method_errno(m, r, &error);
619 return synthetic_reply_method_return(m, "u", (uint32_t) creds->uid);
621 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
622 sd_id128_t server_id;
623 char buf[SD_ID128_STRING_MAX];
625 if (!sd_bus_message_has_signature(m, ""))
626 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
628 r = sd_bus_get_bus_id(a, &server_id);
630 return synthetic_reply_method_errno(m, r, NULL);
632 return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
634 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
636 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
637 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
639 if (!sd_bus_message_has_signature(m, "s"))
640 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
642 r = sd_bus_message_read(m, "s", &name);
644 return synthetic_reply_method_errno(m, r, NULL);
646 if (streq(name, "org.freedesktop.DBus"))
647 return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
649 r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
651 return synthetic_reply_method_errno(m, r, &error);
653 return synthetic_reply_method_return(m, "s", creds->unique_name);
655 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
656 _cleanup_strv_free_ char **names = NULL;
658 if (!sd_bus_message_has_signature(m, ""))
659 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
661 r = sd_bus_list_names(a, NULL, &names);
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", "ListNames")) {
671 _cleanup_strv_free_ char **names = NULL;
673 if (!sd_bus_message_has_signature(m, ""))
674 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
676 r = sd_bus_list_names(a, &names, NULL);
678 return synthetic_reply_method_errno(m, r, NULL);
680 r = strv_extend(&names, "org.freedesktop.DBus");
682 return synthetic_reply_method_errno(m, r, NULL);
684 /* Let's sort the names list to make it stable */
687 return synthetic_reply_return_strv(m, names);
689 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
690 struct kdbus_cmd_name_list cmd = {};
691 struct kdbus_name_list *name_list;
692 struct kdbus_name_info *name;
693 _cleanup_strv_free_ char **owners = NULL;
694 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
698 if (!sd_bus_message_has_signature(m, "s"))
699 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
701 r = sd_bus_message_read(m, "s", &arg0);
703 return synthetic_reply_method_errno(m, r, NULL);
705 r = sd_bus_get_name_creds(a, arg0, 0, NULL);
706 if (r == -ESRCH || r == -ENXIO) {
707 sd_bus_error_setf(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name.", arg0);
708 return synthetic_reply_method_errno(m, r, &error);
711 return synthetic_reply_method_errno(m, r, NULL);
713 cmd.flags = KDBUS_NAME_LIST_QUEUED;
714 r = ioctl(a->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
716 return synthetic_reply_method_errno(m, -errno, NULL);
718 name_list = (struct kdbus_name_list *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
720 KDBUS_ITEM_FOREACH(name, name_list, names) {
721 const char *entry_name = NULL;
722 struct kdbus_item *item;
725 KDBUS_ITEM_FOREACH(item, name, items)
726 if (item->type == KDBUS_ITEM_OWNED_NAME)
727 entry_name = item->name.name;
729 if (!streq_ptr(entry_name, arg0))
732 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
737 r = strv_consume(&owners, n);
744 r = bus_kernel_cmd_free(a, cmd.offset);
746 return synthetic_reply_method_errno(m, r, NULL);
749 return synthetic_reply_method_errno(m, err, NULL);
751 return synthetic_reply_return_strv(m, owners);
753 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
756 if (!sd_bus_message_has_signature(m, "s"))
757 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
759 r = sd_bus_message_read(m, "s", &name);
761 return synthetic_reply_method_errno(m, r, NULL);
763 if (streq(name, "org.freedesktop.DBus"))
764 return synthetic_reply_method_return(m, "b", true);
766 r = sd_bus_get_name_creds(a, name, 0, NULL);
767 if (r < 0 && r != -ESRCH && r != -ENXIO)
768 return synthetic_reply_method_errno(m, r, NULL);
770 return synthetic_reply_method_return(m, "b", r >= 0);
772 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
775 if (!sd_bus_message_has_signature(m, "s"))
776 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
778 r = sd_bus_message_read(m, "s", &name);
780 return synthetic_reply_method_errno(m, r, NULL);
782 r = sd_bus_release_name(a, name);
785 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
786 if (r == -EADDRINUSE)
787 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
789 return synthetic_reply_method_errno(m, r, NULL);
792 set_remove(owned_names, (char*) name);
794 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
796 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
797 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
799 if (!sd_bus_message_has_signature(m, ""))
800 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
802 r = sd_bus_error_setf(&error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
804 return synthetic_reply_method_errno(m, r, &error);
806 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
808 uint32_t flags, param;
811 if (!sd_bus_message_has_signature(m, "su"))
812 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
814 r = sd_bus_message_read(m, "su", &name, &flags);
816 return synthetic_reply_method_errno(m, r, NULL);
818 if (policy && !policy_check_own(policy, ucred->uid, ucred->gid, name))
819 return synthetic_reply_method_errno(m, -EPERM, NULL);
821 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
822 return synthetic_reply_method_errno(m, -EINVAL, NULL);
825 if (flags & BUS_NAME_ALLOW_REPLACEMENT)
826 param |= SD_BUS_NAME_ALLOW_REPLACEMENT;
827 if (flags & BUS_NAME_REPLACE_EXISTING)
828 param |= SD_BUS_NAME_REPLACE_EXISTING;
829 if (!(flags & BUS_NAME_DO_NOT_QUEUE))
830 param |= SD_BUS_NAME_QUEUE;
832 r = set_put_strdup(owned_names, name);
834 return synthetic_reply_method_errno(m, r, NULL);
836 r = sd_bus_request_name(a, name, param);
839 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
841 set_remove(owned_names, (char*) name);
844 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
845 return synthetic_reply_method_errno(m, r, NULL);
851 return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
853 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
855 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
856 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
860 if (!sd_bus_message_has_signature(m, "su"))
861 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
863 r = sd_bus_message_read(m, "su", &name, &flags);
865 return synthetic_reply_method_errno(m, r, NULL);
868 return synthetic_reply_method_errno(m, -EINVAL, NULL);
870 r = sd_bus_get_name_creds(a, name, 0, NULL);
871 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
872 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
874 return synthetic_reply_method_errno(m, r, NULL);
876 r = sd_bus_message_new_method_call(
881 "org.freedesktop.DBus.Peer",
884 return synthetic_reply_method_errno(m, r, NULL);
886 r = sd_bus_send(a, msg, NULL);
888 return synthetic_reply_method_errno(m, r, NULL);
890 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
892 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
893 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
894 _cleanup_strv_free_ char **args = NULL;
896 if (!sd_bus_message_has_signature(m, "a{ss}"))
897 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
899 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
901 return synthetic_reply_method_errno(m, r, NULL);
903 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
904 _cleanup_free_ char *s = NULL;
908 r = sd_bus_message_read(m, "ss", &key, &value);
910 return synthetic_reply_method_errno(m, r, NULL);
912 s = strjoin(key, "=", value, NULL);
914 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
916 r = strv_extend(&args, s);
918 return synthetic_reply_method_errno(m, r, NULL);
920 r = sd_bus_message_exit_container(m);
922 return synthetic_reply_method_errno(m, r, NULL);
925 r = sd_bus_message_exit_container(m);
927 return synthetic_reply_method_errno(m, r, NULL);
930 return synthetic_reply_method_errno(m, -EINVAL, NULL);
932 r = sd_bus_message_new_method_call(
935 "org.freedesktop.systemd1",
936 "/org/freedesktop/systemd1",
937 "org.freedesktop.systemd1.Manager",
940 return synthetic_reply_method_errno(m, r, NULL);
942 r = sd_bus_message_append_strv(msg, args);
944 return synthetic_reply_method_errno(m, r, NULL);
946 r = sd_bus_call(a, msg, 0, NULL, NULL);
948 return synthetic_reply_method_errno(m, r, NULL);
950 return synthetic_reply_method_return(m, NULL);
953 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
955 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
957 return synthetic_reply_method_errno(m, r, &error);
961 static int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, Policy *policy, const struct ucred *our_ucred, Set *owned_names) {
971 if (from->is_kernel) {
972 uid_t sender_uid = (uid_t) -1;
973 gid_t sender_gid = (gid_t) -1;
974 char **sender_names = NULL;
975 bool granted = false;
977 /* Driver messages are always OK */
978 if (streq_ptr(m->sender, "org.freedesktop.DBus"))
981 /* The message came from the kernel, and is sent to our legacy client. */
982 r = sd_bus_creds_get_well_known_names(&m->creds, &sender_names);
986 (void) sd_bus_creds_get_uid(&m->creds, &sender_uid);
987 (void) sd_bus_creds_get_gid(&m->creds, &sender_gid);
989 /* First check whether the sender can send the message to our name */
990 if (set_isempty(owned_names)) {
991 if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, NULL, m->path, m->interface, m->member))
997 SET_FOREACH(n, owned_names, i)
998 if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, n, m->path, m->interface, m->member)) {
1005 /* Then check whether us, the recipient can recieve from the sender's name */
1006 if (strv_isempty(sender_names)) {
1007 if (policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, m->path, m->interface, m->member))
1012 STRV_FOREACH(n, sender_names) {
1013 if (policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, *n, m->path, m->interface, m->member))
1019 /* Return an error back to the caller */
1020 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1021 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML receiver policy.");
1023 /* Return 1, indicating that the message shall not be processed any further */
1027 if (to->is_kernel) {
1028 _cleanup_bus_creds_unref_ sd_bus_creds *destination_creds = NULL;
1029 uid_t destination_uid = (uid_t) -1;
1030 gid_t destination_gid = (gid_t) -1;
1031 const char *destination_unique = NULL;
1032 char **destination_names = NULL;
1033 bool granted = false;
1035 /* Driver messages are always OK */
1036 if (streq_ptr(m->destination, "org.freedesktop.DBus"))
1039 /* The message came from the legacy client, and is sent to kdbus. */
1040 if (m->destination) {
1041 r = sd_bus_get_name_creds(to, m->destination,
1042 SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME|
1043 SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID, &destination_creds);
1047 r = sd_bus_creds_get_well_known_names(destination_creds, &destination_names);
1051 r = sd_bus_creds_get_unique_name(destination_creds, &destination_unique);
1055 (void) sd_bus_creds_get_uid(destination_creds, &destination_uid);
1056 (void) sd_bus_creds_get_gid(destination_creds, &destination_gid);
1059 /* First check if we, the sender can send to this name */
1060 if (strv_isempty(destination_names)) {
1061 if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, m->path, m->interface, m->member))
1066 STRV_FOREACH(n, destination_names) {
1067 if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, *n, m->path, m->interface, m->member)) {
1069 /* If we made a receiver decision,
1070 then remember which name's policy
1071 we used, and to which unique ID it
1072 mapped when we made the
1073 decision. Then, let's pass this to
1074 the kernel when sending the
1075 message, so that it refuses the
1076 operation should the name and
1077 unique ID not map to each other
1080 r = free_and_strdup(&m->destination_ptr, *n);
1084 r = bus_kernel_parse_unique_name(destination_unique, &m->verify_destination_id);
1094 /* Then check if the recipient can receive from our name */
1096 if (set_isempty(owned_names)) {
1097 if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, NULL, m->path, m->interface, m->member))
1103 SET_FOREACH(n, owned_names, i)
1104 if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, n, m->path, m->interface, m->member))
1109 /* Return an error back to the caller */
1110 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1111 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML sender policy.");
1113 /* Return 1, indicating that the message shall not be processed any further */
1120 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
1121 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
1130 /* As reaction to hello we need to respond with two messages:
1131 * the callback reply and the NameAcquired for the unique
1132 * name, since hello is otherwise obsolete on kdbus. */
1135 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
1136 streq_ptr(m->destination, "org.freedesktop.DBus");
1143 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
1148 log_error("Got duplicate hello, aborting.");
1157 r = sd_bus_message_new_method_return(m, &n);
1159 return log_error_errno(r, "Failed to generate HELLO reply: %m");
1161 r = sd_bus_message_append(n, "s", a->unique_name);
1163 return log_error_errno(r, "Failed to append unique name to HELLO reply: %m");
1165 r = bus_message_append_sender(n, "org.freedesktop.DBus");
1167 return log_error_errno(r, "Failed to append sender to HELLO reply: %m");
1169 r = bus_seal_synthetic_message(b, n);
1171 return log_error_errno(r, "Failed to seal HELLO reply: %m");
1173 r = sd_bus_send(b, n, NULL);
1175 return log_error_errno(r, "Failed to send HELLO reply: %m");
1177 n = sd_bus_message_unref(n);
1178 r = sd_bus_message_new_signal(
1181 "/org/freedesktop/DBus",
1182 "org.freedesktop.DBus",
1185 return log_error_errno(r, "Failed to allocate initial NameAcquired message: %m");
1187 r = sd_bus_message_append(n, "s", a->unique_name);
1189 return log_error_errno(r, "Failed to append unique name to NameAcquired message: %m");
1191 r = bus_message_append_sender(n, "org.freedesktop.DBus");
1193 return log_error_errno(r, "Failed to append sender to NameAcquired message: %m");
1195 r = bus_seal_synthetic_message(b, n);
1197 return log_error_errno(r, "Failed to seal NameAcquired message: %m");
1199 r = sd_bus_send(b, n, NULL);
1201 return log_error_errno(r, "Failed to send NameAcquired message: %m");
1206 static int patch_sender(sd_bus *a, sd_bus_message *m) {
1207 char **well_known = NULL;
1217 /* We will change the sender of messages from the bus driver
1218 * so that they originate from the bus driver. This is a
1219 * speciality originating from dbus1, where the bus driver did
1220 * not have a unique id, but only the well-known name. */
1222 c = sd_bus_message_get_creds(m);
1226 r = sd_bus_creds_get_well_known_names(c, &well_known);
1230 if (strv_contains(well_known, "org.freedesktop.DBus"))
1231 m->sender = "org.freedesktop.DBus";
1236 int main(int argc, char *argv[]) {
1238 _cleanup_bus_close_unref_ sd_bus *a = NULL, *b = NULL;
1239 sd_id128_t server_id;
1240 int r, in_fd, out_fd;
1241 bool got_hello = false;
1243 struct ucred ucred = {};
1244 _cleanup_free_ char *peersec = NULL;
1245 Policy policy_buffer = {}, *policy = NULL;
1246 _cleanup_set_free_free_ Set *owned_names = NULL;
1248 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
1249 log_parse_environment();
1252 r = parse_argv(argc, argv);
1256 r = sd_listen_fds(0);
1258 in_fd = STDIN_FILENO;
1259 out_fd = STDOUT_FILENO;
1260 } else if (r == 1) {
1261 in_fd = SD_LISTEN_FDS_START;
1262 out_fd = SD_LISTEN_FDS_START;
1264 log_error("Illegal number of file descriptors passed");
1269 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
1270 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
1273 (void) getpeercred(in_fd, &ucred);
1274 (void) getpeersec(in_fd, &peersec);
1277 if (arg_drop_privileges) {
1278 const char *user = "systemd-bus-proxy";
1282 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
1284 log_error_errno(r, "Cannot resolve user name %s: %m", user);
1288 r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
1293 owned_names = set_new(&string_hash_ops);
1301 log_error_errno(r, "Failed to allocate bus: %m");
1305 r = sd_bus_set_description(a, "sd-proxy");
1307 log_error_errno(r, "Failed to set bus name: %m");
1311 r = sd_bus_set_address(a, arg_address);
1313 log_error_errno(r, "Failed to set address to connect to: %m");
1317 r = sd_bus_negotiate_fds(a, is_unix);
1319 log_error_errno(r, "Failed to set FD negotiation: %m");
1323 r = sd_bus_negotiate_creds(a, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_GID|SD_BUS_CREDS_SELINUX_CONTEXT);
1325 log_error_errno(r, "Failed to set credential negotiation: %m");
1329 if (ucred.pid > 0) {
1330 a->fake_pids.pid = ucred.pid;
1331 a->fake_pids_valid = true;
1333 a->fake_creds.uid = ucred.uid;
1334 a->fake_creds.euid = (uid_t) -1;
1335 a->fake_creds.suid = (uid_t) -1;
1336 a->fake_creds.fsuid = (uid_t) -1;
1337 a->fake_creds.gid = ucred.gid;
1338 a->fake_creds.egid = (gid_t) -1;
1339 a->fake_creds.sgid = (gid_t) -1;
1340 a->fake_creds.fsgid = (gid_t) -1;
1341 a->fake_creds_valid = true;
1345 a->fake_label = peersec;
1349 a->manual_peer_interface = true;
1351 r = sd_bus_start(a);
1353 log_error_errno(r, "Failed to start bus client: %m");
1357 r = sd_bus_get_bus_id(a, &server_id);
1359 log_error_errno(r, "Failed to get server ID: %m");
1364 if (!arg_configuration) {
1367 r = sd_bus_get_scope(a, &scope);
1369 log_error_errno(r, "Couldn't determine bus scope: %m");
1373 if (streq(scope, "system"))
1374 arg_configuration = strv_new(
1375 "/etc/dbus-1/system.conf",
1376 "/etc/dbus-1/system.d/",
1377 "/etc/dbus-1/system-local.conf",
1379 else if (streq(scope, "user"))
1380 arg_configuration = strv_new(
1381 "/etc/dbus-1/session.conf",
1382 "/etc/dbus-1/session.d/",
1383 "/etc/dbus-1/session-local.conf",
1386 log_error("Unknown scope %s, don't know which policy to load. Refusing.", scope);
1390 if (!arg_configuration) {
1396 r = policy_load(&policy_buffer, arg_configuration);
1398 log_error_errno(r, "Failed to load policy: %m");
1402 policy = &policy_buffer;
1403 policy_dump(policy);
1405 if (!policy_check_hello(policy, ucred.uid, ucred.gid)) {
1406 r = log_error_errno(EPERM, "Policy denied connection.");
1413 log_error_errno(r, "Failed to allocate bus: %m");
1417 r = sd_bus_set_fd(b, in_fd, out_fd);
1419 log_error_errno(r, "Failed to set fds: %m");
1423 r = sd_bus_set_server(b, 1, server_id);
1425 log_error_errno(r, "Failed to set server mode: %m");
1429 r = sd_bus_negotiate_fds(b, is_unix);
1431 log_error_errno(r, "Failed to set FD negotiation: %m");
1435 r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_GID|SD_BUS_CREDS_SELINUX_CONTEXT);
1437 log_error_errno(r, "Failed to set credential negotiation: %m");
1441 r = sd_bus_set_anonymous(b, true);
1443 log_error_errno(r, "Failed to set anonymous authentication: %m");
1447 b->manual_peer_interface = true;
1449 r = sd_bus_start(b);
1451 log_error_errno(r, "Failed to start bus client: %m");
1455 r = rename_service(a, b);
1457 log_debug_errno(r, "Failed to rename process: %m");
1460 _cleanup_free_ char *match = NULL;
1463 r = sd_bus_get_unique_name(a, &unique);
1465 log_error_errno(r, "Failed to get unique name: %m");
1469 match = strjoin("type='signal',"
1470 "sender='org.freedesktop.DBus',"
1471 "path='/org/freedesktop/DBus',"
1472 "interface='org.freedesktop.DBus',"
1473 "member='NameOwnerChanged',"
1483 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1485 log_error_errno(r, "Failed to add match for NameLost: %m");
1490 match = strjoin("type='signal',"
1491 "sender='org.freedesktop.DBus',"
1492 "path='/org/freedesktop/DBus',"
1493 "interface='org.freedesktop.DBus',"
1494 "member='NameOwnerChanged',"
1504 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1506 log_error_errno(r, "Failed to add match for NameAcquired: %m");
1512 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1513 int events_a, events_b, fd;
1514 uint64_t timeout_a, timeout_b, t;
1515 struct timespec _ts, *ts;
1516 struct pollfd *pollfd;
1520 /* Read messages from bus, to pass them on to our client */
1522 r = sd_bus_process(a, &m);
1524 /* treat 'connection reset by peer' as clean exit condition */
1525 if (r == -ECONNRESET)
1528 log_error_errno(r, "Failed to process bus a: %m");
1534 bool processed = false;
1536 /* We officially got EOF, let's quit */
1537 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1542 k = synthesize_name_acquired(a, b, m);
1545 log_error_errno(r, "Failed to synthesize message: %m");
1552 k = process_policy(a, b, m, policy, &ucred, owned_names);
1555 log_error_errno(r, "Failed to process policy: %m");
1564 k = sd_bus_send(b, m, NULL);
1566 if (k == -ECONNRESET)
1570 log_error_errno(r, "Failed to send message to client: %m");
1583 /* Read messages from our client, to pass them on to the bus */
1584 r = sd_bus_process(b, &m);
1586 /* treat 'connection reset by peer' as clean exit condition */
1587 if (r == -ECONNRESET)
1590 log_error_errno(r, "Failed to process bus b: %m");
1596 bool processed = false;
1598 /* We officially got EOF, let's quit */
1599 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1604 k = process_hello(a, b, m, &got_hello);
1607 log_error_errno(r, "Failed to process HELLO: %m");
1615 k = process_driver(a, b, m, policy, &ucred, owned_names);
1618 log_error_errno(r, "Failed to process driver calls: %m");
1629 k = process_policy(b, a, m, policy, &ucred, owned_names);
1632 log_error_errno(r, "Failed to process policy: %m");
1641 k = sd_bus_send(a, m, NULL);
1644 /* The name database changed since the policy check, hence let's check again */
1646 else if (k == -ECONNRESET)
1650 log_error_errno(r, "Failed to send message to bus: %m");
1666 fd = sd_bus_get_fd(a);
1668 log_error_errno(r, "Failed to get fd: %m");
1672 events_a = sd_bus_get_events(a);
1674 log_error_errno(r, "Failed to get events mask: %m");
1678 r = sd_bus_get_timeout(a, &timeout_a);
1680 log_error_errno(r, "Failed to get timeout: %m");
1684 events_b = sd_bus_get_events(b);
1686 log_error_errno(r, "Failed to get events mask: %m");
1690 r = sd_bus_get_timeout(b, &timeout_b);
1692 log_error_errno(r, "Failed to get timeout: %m");
1697 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
1700 if (t == (uint64_t) -1)
1705 nw = now(CLOCK_MONOTONIC);
1711 ts = timespec_store(&_ts, t);
1714 pollfd = (struct pollfd[3]) {
1715 {.fd = fd, .events = events_a, },
1716 {.fd = in_fd, .events = events_b & POLLIN, },
1717 {.fd = out_fd, .events = events_b & POLLOUT, }
1720 r = ppoll(pollfd, 3, ts, NULL);
1722 log_error_errno(errno, "ppoll() failed: %m");
1730 "STATUS=Shutting down.");
1732 policy_free(&policy_buffer);
1733 strv_free(arg_configuration);
1736 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;