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);
188 static int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
189 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
190 const char *name, *old_owner, *new_owner;
197 /* If we get NameOwnerChanged for our own name, we need to
198 * synthesize NameLost/NameAcquired, since socket clients need
199 * that, even though it is obsoleted on kdbus */
204 if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
205 !streq_ptr(m->path, "/org/freedesktop/DBus") ||
206 !streq_ptr(m->sender, "org.freedesktop.DBus"))
209 r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
213 r = sd_bus_message_rewind(m, true);
217 if (streq(old_owner, a->unique_name)) {
219 r = sd_bus_message_new_signal(
221 "/org/freedesktop/DBus",
222 "org.freedesktop.DBus",
226 } else if (streq(new_owner, a->unique_name)) {
228 r = sd_bus_message_new_signal(
230 "/org/freedesktop/DBus",
231 "org.freedesktop.DBus",
240 r = sd_bus_message_append(n, "s", name);
244 r = bus_message_append_sender(n, "org.freedesktop.DBus");
248 r = bus_seal_synthetic_message(b, n);
252 return sd_bus_send(b, n, NULL);
255 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
256 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
265 /* As reaction to hello we need to respond with two messages:
266 * the callback reply and the NameAcquired for the unique
267 * name, since hello is otherwise obsolete on kdbus. */
270 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
271 streq_ptr(m->destination, "org.freedesktop.DBus");
278 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
283 log_error("Got duplicate hello, aborting.");
292 r = sd_bus_message_new_method_return(m, &n);
294 log_error("Failed to generate HELLO reply: %s", strerror(-r));
298 r = sd_bus_message_append(n, "s", a->unique_name);
300 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
304 r = bus_message_append_sender(n, "org.freedesktop.DBus");
306 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
310 r = bus_seal_synthetic_message(b, n);
312 log_error("Failed to seal HELLO reply: %s", strerror(-r));
316 r = sd_bus_send(b, n, NULL);
318 log_error("Failed to send HELLO reply: %s", strerror(-r));
322 n = sd_bus_message_unref(n);
323 r = sd_bus_message_new_signal(
325 "/org/freedesktop/DBus",
326 "org.freedesktop.DBus",
330 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
334 r = sd_bus_message_append(n, "s", a->unique_name);
336 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
340 r = bus_message_append_sender(n, "org.freedesktop.DBus");
342 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
346 r = bus_seal_synthetic_message(b, n);
348 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
352 r = sd_bus_send(b, n, NULL);
354 log_error("Failed to send NameAcquired message: %s", strerror(-r));
361 static int getpeersec(int fd, char **ret) {
373 r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
384 r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
395 int main(int argc, char *argv[]) {
397 _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
398 sd_id128_t server_id;
399 int r, in_fd, out_fd;
400 bool got_hello = false;
402 struct ucred ucred = {};
403 _cleanup_free_ char *peersec = NULL;
405 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
406 log_parse_environment();
409 r = parse_argv(argc, argv);
413 r = sd_listen_fds(0);
415 in_fd = STDIN_FILENO;
416 out_fd = STDOUT_FILENO;
418 in_fd = SD_LISTEN_FDS_START;
419 out_fd = SD_LISTEN_FDS_START;
421 log_error("Illegal number of file descriptors passed\n");
426 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
427 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
430 socklen_t l = sizeof(ucred);
432 r = getsockopt(in_fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l);
438 assert(l == sizeof(ucred));
440 getpeersec(in_fd, &peersec);
445 log_error("Failed to allocate bus: %s", strerror(-r));
449 r = sd_bus_set_address(a, arg_address);
451 log_error("Failed to set address to connect to: %s", strerror(-r));
455 r = sd_bus_negotiate_fds(a, is_unix);
457 log_error("Failed to set FD negotiation: %s", strerror(-r));
462 a->fake_creds.pid = ucred.pid;
463 a->fake_creds.uid = ucred.uid;
464 a->fake_creds.gid = ucred.gid;
465 a->fake_creds_valid = true;
469 a->fake_label = peersec;
475 log_error("Failed to start bus client: %s", strerror(-r));
479 r = sd_bus_get_server_id(a, &server_id);
481 log_error("Failed to get server ID: %s", strerror(-r));
487 log_error("Failed to allocate bus: %s", strerror(-r));
491 r = sd_bus_set_fd(b, in_fd, out_fd);
493 log_error("Failed to set fds: %s", strerror(-r));
497 r = sd_bus_set_server(b, 1, server_id);
499 log_error("Failed to set server mode: %s", strerror(-r));
503 r = sd_bus_negotiate_fds(b, is_unix);
505 log_error("Failed to set FD negotiation: %s", strerror(-r));
509 r = sd_bus_set_anonymous(b, true);
511 log_error("Failed to set anonymous authentication: %s", strerror(-r));
517 log_error("Failed to start bus client: %s", strerror(-r));
521 r = rename_service(b);
523 log_debug("Failed to rename process: %s", strerror(-r));
526 _cleanup_free_ char *match = NULL;
529 r = sd_bus_get_unique_name(a, &unique);
531 log_error("Failed to get unique name: %s", strerror(-r));
535 match = strjoin("type='signal',"
536 "sender='org.freedesktop.DBus',"
537 "path='/org/freedesktop/DBus',"
538 "interface='org.freedesktop.DBus',"
539 "member='NameOwnerChanged',"
549 r = sd_bus_add_match(a, match, NULL, NULL);
551 log_error("Failed to add match for NameLost: %s", strerror(-r));
556 match = strjoin("type='signal',"
557 "sender='org.freedesktop.DBus',"
558 "path='/org/freedesktop/DBus',"
559 "interface='org.freedesktop.DBus',"
560 "member='NameOwnerChanged',"
570 r = sd_bus_add_match(a, match, NULL, NULL);
572 log_error("Failed to add match for NameAcquired: %s", strerror(-r));
578 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
579 int events_a, events_b, fd;
580 uint64_t timeout_a, timeout_b, t;
581 struct timespec _ts, *ts;
582 struct pollfd *pollfd;
586 r = sd_bus_process(a, &m);
588 /* treat 'connection reset by peer' as clean exit condition */
589 if (r == -ECONNRESET)
592 log_error("Failed to process bus a: %s", strerror(-r));
598 /* We officially got EOF, let's quit */
599 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
604 k = synthesize_name_acquired(a, b, m);
607 log_error("Failed to synthesize message: %s", strerror(-r));
611 k = sd_bus_send(b, m, NULL);
614 log_error("Failed to send message: %s", strerror(-r));
623 r = sd_bus_process(b, &m);
625 /* treat 'connection reset by peer' as clean exit condition */
626 if (r == -ECONNRESET)
629 log_error("Failed to process bus b: %s", strerror(-r));
635 /* We officially got EOF, let's quit */
636 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
641 k = process_hello(a, b, m, &got_hello);
650 k = sd_bus_send(a, m, NULL);
653 log_error("Failed to send message: %s", strerror(-r));
662 fd = sd_bus_get_fd(a);
664 log_error("Failed to get fd: %s", strerror(-r));
668 events_a = sd_bus_get_events(a);
670 log_error("Failed to get events mask: %s", strerror(-r));
674 r = sd_bus_get_timeout(a, &timeout_a);
676 log_error("Failed to get timeout: %s", strerror(-r));
680 events_b = sd_bus_get_events(b);
682 log_error("Failed to get events mask: %s", strerror(-r));
686 r = sd_bus_get_timeout(b, &timeout_b);
688 log_error("Failed to get timeout: %s", strerror(-r));
693 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
696 if (t == (uint64_t) -1)
701 nw = now(CLOCK_MONOTONIC);
707 ts = timespec_store(&_ts, t);
710 pollfd = (struct pollfd[3]) {
711 {.fd = fd, .events = events_a, },
712 {.fd = in_fd, .events = events_b & POLLIN, },
713 {.fd = out_fd, .events = events_b & POLLOUT, }
716 r = ppoll(pollfd, 3, ts, NULL);
718 log_error("ppoll() failed: %m");
729 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;