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"
44 #define UNIX_BUS_PATH "unix:path=/run/dbus/system_bus_socket"
45 #define KERNEL_BUS_PATH "kernel:path=/dev/kdbus/0-system/bus"
48 # define DEFAULT_BUS_PATH KERNEL_BUS_PATH ";" UNIX_BUS_PATH
50 # define DEFAULT_BUS_PATH UNIX_BUS_PATH
53 static const char *arg_address = DEFAULT_BUS_PATH;
54 static char *arg_command_line_buffer = NULL;
56 static int help(void) {
58 printf("%s [OPTIONS...]\n\n"
59 "Connect STDIO or a socket to a given bus address.\n\n"
60 " -h --help Show this help\n"
61 " --version Show package version\n"
62 " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
63 " (default: " DEFAULT_BUS_PATH ")\n",
64 program_invocation_short_name);
69 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 },
88 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
98 puts(SYSTEMD_FEATURES);
102 arg_address = optarg;
109 assert_not_reached("Unhandled option");
113 /* If the first command line argument is only "x" characters
114 * we'll write who we are talking to into it, so that "ps" is
116 arg_command_line_buffer = argv[optind];
117 if (argc > optind + 1 ||
118 (arg_command_line_buffer && arg_command_line_buffer[strspn(arg_command_line_buffer, "x")] != 0)) {
119 log_error("Too many arguments");
126 static int rename_service(sd_bus *b) {
127 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
128 _cleanup_free_ char *p = NULL, *name = NULL;
137 r = sd_bus_get_peer_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM, &creds);
141 r = sd_bus_creds_get_uid(creds, &uid);
145 r = sd_bus_creds_get_pid(creds, &pid);
149 r = sd_bus_creds_get_cmdline(creds, &cmdline);
153 r = sd_bus_creds_get_comm(creds, &comm);
157 name = uid_to_name(uid);
161 p = strv_join(cmdline, " ");
165 /* The status string gets the full command line ... */
167 "STATUS=Processing requests from client PID %lu (%s); UID %lu (%s)",
168 (unsigned long) pid, p,
169 (unsigned long) uid, name);
171 /* ... and the argv line only the short comm */
172 if (arg_command_line_buffer) {
175 m = strlen(arg_command_line_buffer);
176 w = snprintf(arg_command_line_buffer, m,
177 "[PID %lu/%s; UID %lu/%s]",
178 (unsigned long) pid, comm,
179 (unsigned long) uid, name);
182 memset(arg_command_line_buffer + w, 0, m - w);
185 log_debug("Running on behalf of PID %lu (%s), UID %lu (%s).",
186 (unsigned long) pid, p,
187 (unsigned long) uid, name);
191 static int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
192 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
193 const char *name, *old_owner, *new_owner;
200 /* If we get NameOwnerChanged for our own name, we need to
201 * synthesize NameLost/NameAcquired, since socket clients need
202 * that, even though it is obsoleted on kdbus */
207 if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
208 !streq_ptr(m->path, "/org/freedesktop/DBus") ||
209 !streq_ptr(m->sender, "org.freedesktop.DBus"))
212 r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
216 r = sd_bus_message_rewind(m, true);
220 if (streq(old_owner, a->unique_name)) {
222 r = sd_bus_message_new_signal(
224 "/org/freedesktop/DBus",
225 "org.freedesktop.DBus",
229 } else if (streq(new_owner, a->unique_name)) {
231 r = sd_bus_message_new_signal(
233 "/org/freedesktop/DBus",
234 "org.freedesktop.DBus",
243 r = sd_bus_message_append(n, "s", name);
247 r = bus_message_append_sender(n, "org.freedesktop.DBus");
251 r = bus_seal_synthetic_message(b, n);
255 return sd_bus_send(b, n, NULL);
258 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
259 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
268 /* As reaction to hello we need to respond with two messages:
269 * the callback reply and the NameAcquired for the unique
270 * name, since hello is otherwise obsolete on kdbus. */
273 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
274 streq_ptr(m->destination, "org.freedesktop.DBus");
281 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
286 log_error("Got duplicate hello, aborting.");
295 r = sd_bus_message_new_method_return(m, &n);
297 log_error("Failed to generate HELLO reply: %s", strerror(-r));
301 r = sd_bus_message_append(n, "s", a->unique_name);
303 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
307 r = bus_message_append_sender(n, "org.freedesktop.DBus");
309 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
313 r = bus_seal_synthetic_message(b, n);
315 log_error("Failed to seal HELLO reply: %s", strerror(-r));
319 r = sd_bus_send(b, n, NULL);
321 log_error("Failed to send HELLO reply: %s", strerror(-r));
325 n = sd_bus_message_unref(n);
326 r = sd_bus_message_new_signal(
328 "/org/freedesktop/DBus",
329 "org.freedesktop.DBus",
333 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
337 r = sd_bus_message_append(n, "s", a->unique_name);
339 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
343 r = bus_message_append_sender(n, "org.freedesktop.DBus");
345 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
349 r = bus_seal_synthetic_message(b, n);
351 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
355 r = sd_bus_send(b, n, NULL);
357 log_error("Failed to send NameAcquired message: %s", strerror(-r));
364 int main(int argc, char *argv[]) {
366 _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
367 sd_id128_t server_id;
368 int r, in_fd, out_fd;
369 bool got_hello = false;
371 struct ucred ucred = {};
372 _cleanup_free_ char *peersec = NULL;
374 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
375 log_parse_environment();
378 r = parse_argv(argc, argv);
382 r = sd_listen_fds(0);
384 in_fd = STDIN_FILENO;
385 out_fd = STDOUT_FILENO;
387 in_fd = SD_LISTEN_FDS_START;
388 out_fd = SD_LISTEN_FDS_START;
390 log_error("Illegal number of file descriptors passed");
395 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
396 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
399 getpeercred(in_fd, &ucred);
400 getpeersec(in_fd, &peersec);
405 log_error("Failed to allocate bus: %s", strerror(-r));
409 r = sd_bus_set_address(a, arg_address);
411 log_error("Failed to set address to connect to: %s", strerror(-r));
415 r = sd_bus_negotiate_fds(a, is_unix);
417 log_error("Failed to set FD negotiation: %s", strerror(-r));
422 a->fake_creds.pid = ucred.pid;
423 a->fake_creds.uid = ucred.uid;
424 a->fake_creds.gid = ucred.gid;
425 a->fake_creds_valid = true;
429 a->fake_label = peersec;
435 log_error("Failed to start bus client: %s", strerror(-r));
439 r = sd_bus_get_server_id(a, &server_id);
441 log_error("Failed to get server ID: %s", strerror(-r));
447 log_error("Failed to allocate bus: %s", strerror(-r));
451 r = sd_bus_set_fd(b, in_fd, out_fd);
453 log_error("Failed to set fds: %s", strerror(-r));
457 r = sd_bus_set_server(b, 1, server_id);
459 log_error("Failed to set server mode: %s", strerror(-r));
463 r = sd_bus_negotiate_fds(b, is_unix);
465 log_error("Failed to set FD negotiation: %s", strerror(-r));
469 r = sd_bus_set_anonymous(b, true);
471 log_error("Failed to set anonymous authentication: %s", strerror(-r));
477 log_error("Failed to start bus client: %s", strerror(-r));
481 r = rename_service(b);
483 log_debug("Failed to rename process: %s", strerror(-r));
486 _cleanup_free_ char *match = NULL;
489 r = sd_bus_get_unique_name(a, &unique);
491 log_error("Failed to get unique name: %s", strerror(-r));
495 match = strjoin("type='signal',"
496 "sender='org.freedesktop.DBus',"
497 "path='/org/freedesktop/DBus',"
498 "interface='org.freedesktop.DBus',"
499 "member='NameOwnerChanged',"
509 r = sd_bus_add_match(a, match, NULL, NULL);
511 log_error("Failed to add match for NameLost: %s", strerror(-r));
516 match = strjoin("type='signal',"
517 "sender='org.freedesktop.DBus',"
518 "path='/org/freedesktop/DBus',"
519 "interface='org.freedesktop.DBus',"
520 "member='NameOwnerChanged',"
530 r = sd_bus_add_match(a, match, NULL, NULL);
532 log_error("Failed to add match for NameAcquired: %s", strerror(-r));
538 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
539 int events_a, events_b, fd;
540 uint64_t timeout_a, timeout_b, t;
541 struct timespec _ts, *ts;
542 struct pollfd *pollfd;
546 r = sd_bus_process(a, &m);
548 /* treat 'connection reset by peer' as clean exit condition */
549 if (r == -ECONNRESET)
552 log_error("Failed to process bus a: %s", strerror(-r));
558 /* We officially got EOF, let's quit */
559 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
564 k = synthesize_name_acquired(a, b, m);
567 log_error("Failed to synthesize message: %s", strerror(-r));
571 k = sd_bus_send(b, m, NULL);
574 log_error("Failed to send message: %s", strerror(-r));
583 r = sd_bus_process(b, &m);
585 /* treat 'connection reset by peer' as clean exit condition */
586 if (r == -ECONNRESET)
589 log_error("Failed to process bus b: %s", strerror(-r));
595 /* We officially got EOF, let's quit */
596 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
601 k = process_hello(a, b, m, &got_hello);
610 k = sd_bus_send(a, m, NULL);
613 log_error("Failed to send message: %s", strerror(-r));
622 fd = sd_bus_get_fd(a);
624 log_error("Failed to get fd: %s", strerror(-r));
628 events_a = sd_bus_get_events(a);
630 log_error("Failed to get events mask: %s", strerror(-r));
634 r = sd_bus_get_timeout(a, &timeout_a);
636 log_error("Failed to get timeout: %s", strerror(-r));
640 events_b = sd_bus_get_events(b);
642 log_error("Failed to get events mask: %s", strerror(-r));
646 r = sd_bus_get_timeout(b, &timeout_b);
648 log_error("Failed to get timeout: %s", strerror(-r));
653 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
656 if (t == (uint64_t) -1)
661 nw = now(CLOCK_MONOTONIC);
667 ts = timespec_store(&_ts, t);
670 pollfd = (struct pollfd[3]) {
671 {.fd = fd, .events = events_a, },
672 {.fd = in_fd, .events = events_b & POLLIN, },
673 {.fd = out_fd, .events = events_b & POLLOUT, }
676 r = ppoll(pollfd, 3, ts, NULL);
678 log_error("ppoll() failed: %m");
689 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;