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 *a, sd_bus *b) {
127 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
128 _cleanup_free_ char *p = NULL, *name = NULL;
138 r = sd_bus_get_peer_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM, &creds);
142 r = sd_bus_creds_get_uid(creds, &uid);
146 r = sd_bus_creds_get_pid(creds, &pid);
150 r = sd_bus_creds_get_cmdline(creds, &cmdline);
154 r = sd_bus_creds_get_comm(creds, &comm);
158 name = uid_to_name(uid);
162 p = strv_join(cmdline, " ");
166 /* The status string gets the full command line ... */
168 "STATUS=Processing requests from client PID %lu (%s); UID %lu (%s)",
169 (unsigned long) pid, p,
170 (unsigned long) uid, name);
172 /* ... and the argv line only the short comm */
173 if (arg_command_line_buffer) {
176 m = strlen(arg_command_line_buffer);
177 w = snprintf(arg_command_line_buffer, m,
178 "[PID %lu/%s; UID %lu/%s]",
179 (unsigned long) pid, comm,
180 (unsigned long) uid, name);
183 memset(arg_command_line_buffer + w, 0, m - w);
186 log_debug("Running on behalf of PID %lu (%s), UID %lu (%s), %s",
187 (unsigned long) pid, p,
188 (unsigned long) uid, name,
194 static int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
195 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
196 const char *name, *old_owner, *new_owner;
203 /* If we get NameOwnerChanged for our own name, we need to
204 * synthesize NameLost/NameAcquired, since socket clients need
205 * that, even though it is obsoleted on kdbus */
210 if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
211 !streq_ptr(m->path, "/org/freedesktop/DBus") ||
212 !streq_ptr(m->sender, "org.freedesktop.DBus"))
215 r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
219 r = sd_bus_message_rewind(m, true);
223 if (streq(old_owner, a->unique_name)) {
225 r = sd_bus_message_new_signal(
227 "/org/freedesktop/DBus",
228 "org.freedesktop.DBus",
232 } else if (streq(new_owner, a->unique_name)) {
234 r = sd_bus_message_new_signal(
236 "/org/freedesktop/DBus",
237 "org.freedesktop.DBus",
246 r = sd_bus_message_append(n, "s", name);
250 r = bus_message_append_sender(n, "org.freedesktop.DBus");
254 r = bus_seal_synthetic_message(b, n);
258 return sd_bus_send(b, n, NULL);
261 static int process_policy(sd_bus *a, sd_bus *b, sd_bus_message *m) {
262 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
269 if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll"))
272 if (!streq_ptr(m->path, "/org/gnome/DisplayManager/Slave"))
275 r = sd_bus_message_new_method_errorf(m, &n, SD_BUS_ERROR_ACCESS_DENIED, "gdm, you are stupid");
279 r = bus_message_append_sender(n, "org.freedesktop.DBus");
281 log_error("Failed to append sender to gdm reply: %s", strerror(-r));
285 r = bus_seal_synthetic_message(b, n);
287 log_error("Failed to seal gdm reply: %s", strerror(-r));
291 r = sd_bus_send(b, n, NULL);
293 log_error("Failed to send gdm reply: %s", strerror(-r));
300 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
301 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
310 /* As reaction to hello we need to respond with two messages:
311 * the callback reply and the NameAcquired for the unique
312 * name, since hello is otherwise obsolete on kdbus. */
315 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
316 streq_ptr(m->destination, "org.freedesktop.DBus");
323 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
328 log_error("Got duplicate hello, aborting.");
337 r = sd_bus_message_new_method_return(m, &n);
339 log_error("Failed to generate HELLO reply: %s", strerror(-r));
343 r = sd_bus_message_append(n, "s", a->unique_name);
345 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
349 r = bus_message_append_sender(n, "org.freedesktop.DBus");
351 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
355 r = bus_seal_synthetic_message(b, n);
357 log_error("Failed to seal HELLO reply: %s", strerror(-r));
361 r = sd_bus_send(b, n, NULL);
363 log_error("Failed to send HELLO reply: %s", strerror(-r));
367 n = sd_bus_message_unref(n);
368 r = sd_bus_message_new_signal(
370 "/org/freedesktop/DBus",
371 "org.freedesktop.DBus",
375 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
379 r = sd_bus_message_append(n, "s", a->unique_name);
381 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
385 r = bus_message_append_sender(n, "org.freedesktop.DBus");
387 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
391 r = bus_seal_synthetic_message(b, n);
393 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
397 r = sd_bus_send(b, n, NULL);
399 log_error("Failed to send NameAcquired message: %s", strerror(-r));
406 int main(int argc, char *argv[]) {
408 _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
409 sd_id128_t server_id;
410 int r, in_fd, out_fd;
411 bool got_hello = false;
413 struct ucred ucred = {};
414 _cleanup_free_ char *peersec = NULL;
416 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
417 log_parse_environment();
420 r = parse_argv(argc, argv);
424 r = sd_listen_fds(0);
426 in_fd = STDIN_FILENO;
427 out_fd = STDOUT_FILENO;
429 in_fd = SD_LISTEN_FDS_START;
430 out_fd = SD_LISTEN_FDS_START;
432 log_error("Illegal number of file descriptors passed");
437 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
438 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
441 getpeercred(in_fd, &ucred);
442 getpeersec(in_fd, &peersec);
447 log_error("Failed to allocate bus: %s", strerror(-r));
451 r = sd_bus_set_address(a, arg_address);
453 log_error("Failed to set address to connect to: %s", strerror(-r));
457 r = sd_bus_negotiate_fds(a, is_unix);
459 log_error("Failed to set FD negotiation: %s", strerror(-r));
464 a->fake_creds.pid = ucred.pid;
465 a->fake_creds.uid = ucred.uid;
466 a->fake_creds.gid = ucred.gid;
467 a->fake_creds_valid = true;
471 a->fake_label = peersec;
475 a->manual_peer_interface = true;
479 log_error("Failed to start bus client: %s", strerror(-r));
483 r = sd_bus_get_server_id(a, &server_id);
485 log_error("Failed to get server ID: %s", strerror(-r));
491 log_error("Failed to allocate bus: %s", strerror(-r));
495 r = sd_bus_set_fd(b, in_fd, out_fd);
497 log_error("Failed to set fds: %s", strerror(-r));
501 r = sd_bus_set_server(b, 1, server_id);
503 log_error("Failed to set server mode: %s", strerror(-r));
507 r = sd_bus_negotiate_fds(b, is_unix);
509 log_error("Failed to set FD negotiation: %s", strerror(-r));
513 r = sd_bus_set_anonymous(b, true);
515 log_error("Failed to set anonymous authentication: %s", strerror(-r));
519 b->manual_peer_interface = true;
523 log_error("Failed to start bus client: %s", strerror(-r));
527 r = rename_service(a, b);
529 log_debug("Failed to rename process: %s", strerror(-r));
532 _cleanup_free_ char *match = NULL;
535 r = sd_bus_get_unique_name(a, &unique);
537 log_error("Failed to get unique name: %s", strerror(-r));
541 match = strjoin("type='signal',"
542 "sender='org.freedesktop.DBus',"
543 "path='/org/freedesktop/DBus',"
544 "interface='org.freedesktop.DBus',"
545 "member='NameOwnerChanged',"
555 r = sd_bus_add_match(a, match, NULL, NULL);
557 log_error("Failed to add match for NameLost: %s", strerror(-r));
562 match = strjoin("type='signal',"
563 "sender='org.freedesktop.DBus',"
564 "path='/org/freedesktop/DBus',"
565 "interface='org.freedesktop.DBus',"
566 "member='NameOwnerChanged',"
576 r = sd_bus_add_match(a, match, NULL, NULL);
578 log_error("Failed to add match for NameAcquired: %s", strerror(-r));
584 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
585 int events_a, events_b, fd;
586 uint64_t timeout_a, timeout_b, t;
587 struct timespec _ts, *ts;
588 struct pollfd *pollfd;
592 r = sd_bus_process(a, &m);
594 /* treat 'connection reset by peer' as clean exit condition */
595 if (r == -ECONNRESET)
598 log_error("Failed to process bus a: %s", strerror(-r));
604 /* We officially got EOF, let's quit */
605 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
610 k = synthesize_name_acquired(a, b, m);
613 log_error("Failed to synthesize message: %s", strerror(-r));
617 k = sd_bus_send(b, m, NULL);
620 log_error("Failed to send message: %s", strerror(-r));
629 r = sd_bus_process(b, &m);
631 /* treat 'connection reset by peer' as clean exit condition */
632 if (r == -ECONNRESET)
635 log_error("Failed to process bus b: %s", strerror(-r));
641 /* We officially got EOF, let's quit */
642 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
647 k = process_hello(a, b, m, &got_hello);
656 k = process_policy(a, b, m);
662 k = sd_bus_send(a, m, NULL);
665 log_error("Failed to send message: %s", strerror(-r));
674 fd = sd_bus_get_fd(a);
676 log_error("Failed to get fd: %s", strerror(-r));
680 events_a = sd_bus_get_events(a);
682 log_error("Failed to get events mask: %s", strerror(-r));
686 r = sd_bus_get_timeout(a, &timeout_a);
688 log_error("Failed to get timeout: %s", strerror(-r));
692 events_b = sd_bus_get_events(b);
694 log_error("Failed to get events mask: %s", strerror(-r));
698 r = sd_bus_get_timeout(b, &timeout_b);
700 log_error("Failed to get timeout: %s", strerror(-r));
705 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
708 if (t == (uint64_t) -1)
713 nw = now(CLOCK_MONOTONIC);
719 ts = timespec_store(&_ts, t);
722 pollfd = (struct pollfd[3]) {
723 {.fd = fd, .events = events_a, },
724 {.fd = in_fd, .events = events_b & POLLIN, },
725 {.fd = out_fd, .events = events_b & POLLOUT, }
728 r = ppoll(pollfd, 3, ts, NULL);
730 log_error("ppoll() failed: %m");
741 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;