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 process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
299 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
302 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
305 r = sd_bus_message_read(m, "s", &match);
309 r = sd_bus_add_match(a, match, NULL, NULL);
313 return sd_bus_reply_method_return(m, NULL);
315 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
318 r = sd_bus_message_read(m, "s", &match);
322 r = sd_bus_remove_match(a, match, NULL, NULL);
326 return sd_bus_reply_method_return(m, NULL);
333 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
334 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
343 /* As reaction to hello we need to respond with two messages:
344 * the callback reply and the NameAcquired for the unique
345 * name, since hello is otherwise obsolete on kdbus. */
348 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
349 streq_ptr(m->destination, "org.freedesktop.DBus");
356 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
361 log_error("Got duplicate hello, aborting.");
370 r = sd_bus_message_new_method_return(m, &n);
372 log_error("Failed to generate HELLO reply: %s", strerror(-r));
376 r = sd_bus_message_append(n, "s", a->unique_name);
378 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
382 r = bus_message_append_sender(n, "org.freedesktop.DBus");
384 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
388 r = bus_seal_synthetic_message(b, n);
390 log_error("Failed to seal HELLO reply: %s", strerror(-r));
394 r = sd_bus_send(b, n, NULL);
396 log_error("Failed to send HELLO reply: %s", strerror(-r));
400 n = sd_bus_message_unref(n);
401 r = sd_bus_message_new_signal(
404 "/org/freedesktop/DBus",
405 "org.freedesktop.DBus",
408 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
412 r = sd_bus_message_append(n, "s", a->unique_name);
414 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
418 r = bus_message_append_sender(n, "org.freedesktop.DBus");
420 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
424 r = bus_seal_synthetic_message(b, n);
426 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
430 r = sd_bus_send(b, n, NULL);
432 log_error("Failed to send NameAcquired message: %s", strerror(-r));
439 static int patch_sender(sd_bus *a, sd_bus_message *m) {
440 char **well_known = NULL;
450 /* We will change the sender of messages from the bus driver
451 * so that they originate from the bus driver. This is a
452 * speciality originating from dbus1, where the bus driver did
453 * not have a unique id, but only the well-known name. */
455 c = sd_bus_message_get_creds(m);
459 r = sd_bus_creds_get_well_known_names(c, &well_known);
463 if (strv_contains(well_known, "org.freedesktop.DBus"))
464 m->sender = "org.freedesktop.DBus";
469 int main(int argc, char *argv[]) {
471 _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
472 sd_id128_t server_id;
473 int r, in_fd, out_fd;
474 bool got_hello = false;
476 struct ucred ucred = {};
477 _cleanup_free_ char *peersec = NULL;
479 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
480 log_parse_environment();
483 r = parse_argv(argc, argv);
487 r = sd_listen_fds(0);
489 in_fd = STDIN_FILENO;
490 out_fd = STDOUT_FILENO;
492 in_fd = SD_LISTEN_FDS_START;
493 out_fd = SD_LISTEN_FDS_START;
495 log_error("Illegal number of file descriptors passed");
500 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
501 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
504 getpeercred(in_fd, &ucred);
505 getpeersec(in_fd, &peersec);
510 log_error("Failed to allocate bus: %s", strerror(-r));
514 r = sd_bus_set_name(a, "sd-proxy");
516 log_error("Failed to set bus name: %s", strerror(-r));
520 r = sd_bus_set_address(a, arg_address);
522 log_error("Failed to set address to connect to: %s", strerror(-r));
526 r = sd_bus_negotiate_fds(a, is_unix);
528 log_error("Failed to set FD negotiation: %s", strerror(-r));
533 a->fake_creds.pid = ucred.pid;
534 a->fake_creds.uid = ucred.uid;
535 a->fake_creds.gid = ucred.gid;
536 a->fake_creds_valid = true;
540 a->fake_label = peersec;
544 a->manual_peer_interface = true;
548 log_error("Failed to start bus client: %s", strerror(-r));
552 r = sd_bus_get_server_id(a, &server_id);
554 log_error("Failed to get server ID: %s", strerror(-r));
560 log_error("Failed to allocate bus: %s", strerror(-r));
564 r = sd_bus_set_fd(b, in_fd, out_fd);
566 log_error("Failed to set fds: %s", strerror(-r));
570 r = sd_bus_set_server(b, 1, server_id);
572 log_error("Failed to set server mode: %s", strerror(-r));
576 r = sd_bus_negotiate_fds(b, is_unix);
578 log_error("Failed to set FD negotiation: %s", strerror(-r));
582 r = sd_bus_set_anonymous(b, true);
584 log_error("Failed to set anonymous authentication: %s", strerror(-r));
588 b->manual_peer_interface = true;
592 log_error("Failed to start bus client: %s", strerror(-r));
596 r = rename_service(a, b);
598 log_debug("Failed to rename process: %s", strerror(-r));
601 _cleanup_free_ char *match = NULL;
604 r = sd_bus_get_unique_name(a, &unique);
606 log_error("Failed to get unique name: %s", strerror(-r));
610 match = strjoin("type='signal',"
611 "sender='org.freedesktop.DBus',"
612 "path='/org/freedesktop/DBus',"
613 "interface='org.freedesktop.DBus',"
614 "member='NameOwnerChanged',"
624 r = sd_bus_add_match(a, match, NULL, NULL);
626 log_error("Failed to add match for NameLost: %s", strerror(-r));
631 match = strjoin("type='signal',"
632 "sender='org.freedesktop.DBus',"
633 "path='/org/freedesktop/DBus',"
634 "interface='org.freedesktop.DBus',"
635 "member='NameOwnerChanged',"
645 r = sd_bus_add_match(a, match, NULL, NULL);
647 log_error("Failed to add match for NameAcquired: %s", strerror(-r));
653 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
654 int events_a, events_b, fd;
655 uint64_t timeout_a, timeout_b, t;
656 struct timespec _ts, *ts;
657 struct pollfd *pollfd;
661 r = sd_bus_process(a, &m);
663 /* treat 'connection reset by peer' as clean exit condition */
664 if (r == -ECONNRESET)
667 log_error("Failed to process bus a: %s", strerror(-r));
673 /* We officially got EOF, let's quit */
674 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
679 k = synthesize_name_acquired(a, b, m);
682 log_error("Failed to synthesize message: %s", strerror(-r));
688 k = sd_bus_send(b, m, NULL);
690 if (k == -ECONNRESET)
694 log_error("Failed to send message: %s", strerror(-r));
705 r = sd_bus_process(b, &m);
707 /* treat 'connection reset by peer' as clean exit condition */
708 if (r == -ECONNRESET)
711 log_error("Failed to process bus b: %s", strerror(-r));
717 /* We officially got EOF, let's quit */
718 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
723 k = process_hello(a, b, m, &got_hello);
726 log_error("Failed to process HELLO: %s", strerror(-r));
733 k = process_policy(a, b, m);
736 log_error("Failed to process policy: %s", strerror(-r));
740 k = process_driver(a, b, m);
743 log_error("Failed to process driver calls: %s", strerror(-r));
750 k = sd_bus_send(a, m, NULL);
752 if (r == -ECONNRESET)
756 log_error("Failed to send message: %s", strerror(-r));
768 fd = sd_bus_get_fd(a);
770 log_error("Failed to get fd: %s", strerror(-r));
774 events_a = sd_bus_get_events(a);
776 log_error("Failed to get events mask: %s", strerror(-r));
780 r = sd_bus_get_timeout(a, &timeout_a);
782 log_error("Failed to get timeout: %s", strerror(-r));
786 events_b = sd_bus_get_events(b);
788 log_error("Failed to get events mask: %s", strerror(-r));
792 r = sd_bus_get_timeout(b, &timeout_b);
794 log_error("Failed to get timeout: %s", strerror(-r));
799 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
802 if (t == (uint64_t) -1)
807 nw = now(CLOCK_MONOTONIC);
813 ts = timespec_store(&_ts, t);
816 pollfd = (struct pollfd[3]) {
817 {.fd = fd, .events = events_a, },
818 {.fd = in_fd, .events = events_b & POLLIN, },
819 {.fd = out_fd, .events = events_b & POLLOUT, }
822 r = ppoll(pollfd, 3, ts, NULL);
824 log_error("ppoll() failed: %m");
833 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;