1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/socket.h>
24 #include <sys/types.h>
35 #include "socket-util.h"
36 #include "sd-daemon.h"
38 #include "bus-internal.h"
39 #include "bus-message.h"
45 static const char *arg_address = DEFAULT_SYSTEM_BUS_PATH;
46 static char *arg_command_line_buffer = NULL;
48 static int help(void) {
50 printf("%s [OPTIONS...]\n\n"
51 "Connect STDIO or a socket to a given bus address.\n\n"
52 " -h --help Show this help\n"
53 " --version Show package version\n"
54 " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
55 " (default: " DEFAULT_SYSTEM_BUS_PATH ")\n",
56 program_invocation_short_name);
61 static int parse_argv(int argc, char *argv[]) {
68 static const struct option options[] = {
69 { "help", no_argument, NULL, 'h' },
70 { "version", no_argument, NULL, ARG_VERSION },
71 { "address", required_argument, NULL, ARG_ADDRESS },
80 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
90 puts(SYSTEMD_FEATURES);
101 assert_not_reached("Unhandled option");
105 /* If the first command line argument is only "x" characters
106 * we'll write who we are talking to into it, so that "ps" is
108 arg_command_line_buffer = argv[optind];
109 if (argc > optind + 1 ||
110 (arg_command_line_buffer && arg_command_line_buffer[strspn(arg_command_line_buffer, "x")] != 0)) {
111 log_error("Too many arguments");
118 static int rename_service(sd_bus *a, sd_bus *b) {
119 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
120 _cleanup_free_ char *p = NULL, *name = NULL;
130 r = sd_bus_get_peer_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM, &creds);
134 r = sd_bus_creds_get_uid(creds, &uid);
138 r = sd_bus_creds_get_pid(creds, &pid);
142 r = sd_bus_creds_get_cmdline(creds, &cmdline);
146 r = sd_bus_creds_get_comm(creds, &comm);
150 name = uid_to_name(uid);
154 p = strv_join(cmdline, " ");
158 /* The status string gets the full command line ... */
160 "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
164 /* ... and the argv line only the short comm */
165 if (arg_command_line_buffer) {
168 m = strlen(arg_command_line_buffer);
169 w = snprintf(arg_command_line_buffer, m,
170 "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
175 memzero(arg_command_line_buffer + w, m - w);
178 log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
186 static int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
187 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
188 const char *name, *old_owner, *new_owner;
195 /* If we get NameOwnerChanged for our own name, we need to
196 * synthesize NameLost/NameAcquired, since socket clients need
197 * that, even though it is obsoleted on kdbus */
202 if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
203 !streq_ptr(m->path, "/org/freedesktop/DBus") ||
204 !streq_ptr(m->sender, "org.freedesktop.DBus"))
207 r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
211 r = sd_bus_message_rewind(m, true);
215 if (streq(old_owner, a->unique_name)) {
217 r = sd_bus_message_new_signal(
220 "/org/freedesktop/DBus",
221 "org.freedesktop.DBus",
224 } else if (streq(new_owner, a->unique_name)) {
226 r = sd_bus_message_new_signal(
229 "/org/freedesktop/DBus",
230 "org.freedesktop.DBus",
238 r = sd_bus_message_append(n, "s", name);
242 r = bus_message_append_sender(n, "org.freedesktop.DBus");
246 r = bus_seal_synthetic_message(b, n);
250 return sd_bus_send(b, n, NULL);
253 static int process_policy(sd_bus *a, sd_bus *b, sd_bus_message *m) {
254 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
261 if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll"))
264 if (!streq_ptr(m->path, "/org/gnome/DisplayManager/Slave"))
267 r = sd_bus_message_new_method_errorf(m, &n, SD_BUS_ERROR_ACCESS_DENIED, "gdm, you are stupid");
271 r = bus_message_append_sender(n, "org.freedesktop.DBus");
273 log_error("Failed to append sender to gdm reply: %s", strerror(-r));
277 r = bus_seal_synthetic_message(b, n);
279 log_error("Failed to seal gdm reply: %s", strerror(-r));
283 r = sd_bus_send(b, n, NULL);
285 log_error("Failed to send gdm reply: %s", strerror(-r));
292 static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
298 r = bus_message_append_sender(m, "org.freedesktop.DBus");
302 r = bus_seal_synthetic_message(b, m);
306 return sd_bus_send(b, m, NULL);
309 static int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
310 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
313 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
316 r = sd_bus_message_new_method_error(call, &m, e);
320 return synthetic_driver_send(call->bus, m);
323 static int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
325 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
327 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
330 if (sd_bus_error_is_set(p))
331 return synthetic_reply_method_error(call, p);
333 sd_bus_error_set_errno(&berror, error);
335 return synthetic_reply_method_error(call, &berror);
338 static int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
340 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
343 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
346 r = sd_bus_message_new_method_return(call, &m);
350 if (!isempty(types)) {
354 r = bus_message_append_ap(m, types, ap);
360 return synthetic_driver_send(call->bus, m);
363 static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
370 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
373 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
374 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
377 r = sd_bus_message_read(m, "s", &match);
379 return synthetic_reply_method_errno(m, r, NULL);
381 r = sd_bus_add_match(a, match, NULL, NULL);
383 return synthetic_reply_method_errno(m, r, NULL);
385 return synthetic_reply_method_return(m, NULL);
387 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
390 r = sd_bus_message_read(m, "s", &match);
392 return synthetic_reply_method_errno(m, r, NULL);
394 r = sd_bus_remove_match(a, match, NULL, NULL);
396 return synthetic_reply_method_errno(m, r, NULL);
398 return synthetic_reply_method_return(m, NULL);
404 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
405 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
414 /* As reaction to hello we need to respond with two messages:
415 * the callback reply and the NameAcquired for the unique
416 * name, since hello is otherwise obsolete on kdbus. */
419 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
420 streq_ptr(m->destination, "org.freedesktop.DBus");
427 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
432 log_error("Got duplicate hello, aborting.");
441 r = sd_bus_message_new_method_return(m, &n);
443 log_error("Failed to generate HELLO reply: %s", strerror(-r));
447 r = sd_bus_message_append(n, "s", a->unique_name);
449 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
453 r = bus_message_append_sender(n, "org.freedesktop.DBus");
455 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
459 r = bus_seal_synthetic_message(b, n);
461 log_error("Failed to seal HELLO reply: %s", strerror(-r));
465 r = sd_bus_send(b, n, NULL);
467 log_error("Failed to send HELLO reply: %s", strerror(-r));
471 n = sd_bus_message_unref(n);
472 r = sd_bus_message_new_signal(
475 "/org/freedesktop/DBus",
476 "org.freedesktop.DBus",
479 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
483 r = sd_bus_message_append(n, "s", a->unique_name);
485 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
489 r = bus_message_append_sender(n, "org.freedesktop.DBus");
491 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
495 r = bus_seal_synthetic_message(b, n);
497 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
501 r = sd_bus_send(b, n, NULL);
503 log_error("Failed to send NameAcquired message: %s", strerror(-r));
510 static int patch_sender(sd_bus *a, sd_bus_message *m) {
511 char **well_known = NULL;
521 /* We will change the sender of messages from the bus driver
522 * so that they originate from the bus driver. This is a
523 * speciality originating from dbus1, where the bus driver did
524 * not have a unique id, but only the well-known name. */
526 c = sd_bus_message_get_creds(m);
530 r = sd_bus_creds_get_well_known_names(c, &well_known);
534 if (strv_contains(well_known, "org.freedesktop.DBus"))
535 m->sender = "org.freedesktop.DBus";
540 int main(int argc, char *argv[]) {
542 _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
543 sd_id128_t server_id;
544 int r, in_fd, out_fd;
545 bool got_hello = false;
547 struct ucred ucred = {};
548 _cleanup_free_ char *peersec = NULL;
550 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
551 log_parse_environment();
554 r = parse_argv(argc, argv);
558 r = sd_listen_fds(0);
560 in_fd = STDIN_FILENO;
561 out_fd = STDOUT_FILENO;
563 in_fd = SD_LISTEN_FDS_START;
564 out_fd = SD_LISTEN_FDS_START;
566 log_error("Illegal number of file descriptors passed");
571 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
572 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
575 getpeercred(in_fd, &ucred);
576 getpeersec(in_fd, &peersec);
581 log_error("Failed to allocate bus: %s", strerror(-r));
585 r = sd_bus_set_name(a, "sd-proxy");
587 log_error("Failed to set bus name: %s", strerror(-r));
591 r = sd_bus_set_address(a, arg_address);
593 log_error("Failed to set address to connect to: %s", strerror(-r));
597 r = sd_bus_negotiate_fds(a, is_unix);
599 log_error("Failed to set FD negotiation: %s", strerror(-r));
604 a->fake_creds.pid = ucred.pid;
605 a->fake_creds.uid = ucred.uid;
606 a->fake_creds.gid = ucred.gid;
607 a->fake_creds_valid = true;
611 a->fake_label = peersec;
615 a->manual_peer_interface = true;
619 log_error("Failed to start bus client: %s", strerror(-r));
623 r = sd_bus_get_server_id(a, &server_id);
625 log_error("Failed to get server ID: %s", strerror(-r));
631 log_error("Failed to allocate bus: %s", strerror(-r));
635 r = sd_bus_set_fd(b, in_fd, out_fd);
637 log_error("Failed to set fds: %s", strerror(-r));
641 r = sd_bus_set_server(b, 1, server_id);
643 log_error("Failed to set server mode: %s", strerror(-r));
647 r = sd_bus_negotiate_fds(b, is_unix);
649 log_error("Failed to set FD negotiation: %s", strerror(-r));
653 r = sd_bus_set_anonymous(b, true);
655 log_error("Failed to set anonymous authentication: %s", strerror(-r));
659 b->manual_peer_interface = true;
663 log_error("Failed to start bus client: %s", strerror(-r));
667 r = rename_service(a, b);
669 log_debug("Failed to rename process: %s", strerror(-r));
672 _cleanup_free_ char *match = NULL;
675 r = sd_bus_get_unique_name(a, &unique);
677 log_error("Failed to get unique name: %s", strerror(-r));
681 match = strjoin("type='signal',"
682 "sender='org.freedesktop.DBus',"
683 "path='/org/freedesktop/DBus',"
684 "interface='org.freedesktop.DBus',"
685 "member='NameOwnerChanged',"
695 r = sd_bus_add_match(a, match, NULL, NULL);
697 log_error("Failed to add match for NameLost: %s", strerror(-r));
702 match = strjoin("type='signal',"
703 "sender='org.freedesktop.DBus',"
704 "path='/org/freedesktop/DBus',"
705 "interface='org.freedesktop.DBus',"
706 "member='NameOwnerChanged',"
716 r = sd_bus_add_match(a, match, NULL, NULL);
718 log_error("Failed to add match for NameAcquired: %s", strerror(-r));
724 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
725 int events_a, events_b, fd;
726 uint64_t timeout_a, timeout_b, t;
727 struct timespec _ts, *ts;
728 struct pollfd *pollfd;
732 r = sd_bus_process(a, &m);
734 /* treat 'connection reset by peer' as clean exit condition */
735 if (r == -ECONNRESET)
738 log_error("Failed to process bus a: %s", strerror(-r));
744 /* We officially got EOF, let's quit */
745 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
750 k = synthesize_name_acquired(a, b, m);
753 log_error("Failed to synthesize message: %s", strerror(-r));
759 k = sd_bus_send(b, m, NULL);
761 if (k == -ECONNRESET)
765 log_error("Failed to send message: %s", strerror(-r));
776 r = sd_bus_process(b, &m);
778 /* treat 'connection reset by peer' as clean exit condition */
779 if (r == -ECONNRESET)
782 log_error("Failed to process bus b: %s", strerror(-r));
788 /* We officially got EOF, let's quit */
789 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
794 k = process_hello(a, b, m, &got_hello);
797 log_error("Failed to process HELLO: %s", strerror(-r));
804 k = process_policy(a, b, m);
807 log_error("Failed to process policy: %s", strerror(-r));
811 k = process_driver(a, b, m);
814 log_error("Failed to process driver calls: %s", strerror(-r));
821 k = sd_bus_send(a, m, NULL);
823 if (r == -ECONNRESET)
827 log_error("Failed to send message: %s", strerror(-r));
839 fd = sd_bus_get_fd(a);
841 log_error("Failed to get fd: %s", strerror(-r));
845 events_a = sd_bus_get_events(a);
847 log_error("Failed to get events mask: %s", strerror(-r));
851 r = sd_bus_get_timeout(a, &timeout_a);
853 log_error("Failed to get timeout: %s", strerror(-r));
857 events_b = sd_bus_get_events(b);
859 log_error("Failed to get events mask: %s", strerror(-r));
863 r = sd_bus_get_timeout(b, &timeout_b);
865 log_error("Failed to get timeout: %s", strerror(-r));
870 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
873 if (t == (uint64_t) -1)
878 nw = now(CLOCK_MONOTONIC);
884 ts = timespec_store(&_ts, t);
887 pollfd = (struct pollfd[3]) {
888 {.fd = fd, .events = events_a, },
889 {.fd = in_fd, .events = events_b & POLLIN, },
890 {.fd = out_fd, .events = events_b & POLLOUT, }
893 r = ppoll(pollfd, 3, ts, NULL);
895 log_error("ppoll() failed: %m");
904 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;