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 memset(arg_command_line_buffer + w, 0, 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(
219 "/org/freedesktop/DBus",
220 "org.freedesktop.DBus",
224 } else if (streq(new_owner, a->unique_name)) {
226 r = sd_bus_message_new_signal(
228 "/org/freedesktop/DBus",
229 "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_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
293 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
302 /* As reaction to hello we need to respond with two messages:
303 * the callback reply and the NameAcquired for the unique
304 * name, since hello is otherwise obsolete on kdbus. */
307 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
308 streq_ptr(m->destination, "org.freedesktop.DBus");
315 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
320 log_error("Got duplicate hello, aborting.");
329 r = sd_bus_message_new_method_return(m, &n);
331 log_error("Failed to generate HELLO reply: %s", strerror(-r));
335 r = sd_bus_message_append(n, "s", a->unique_name);
337 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
341 r = bus_message_append_sender(n, "org.freedesktop.DBus");
343 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
347 r = bus_seal_synthetic_message(b, n);
349 log_error("Failed to seal HELLO reply: %s", strerror(-r));
353 r = sd_bus_send(b, n, NULL);
355 log_error("Failed to send HELLO reply: %s", strerror(-r));
359 n = sd_bus_message_unref(n);
360 r = sd_bus_message_new_signal(
362 "/org/freedesktop/DBus",
363 "org.freedesktop.DBus",
367 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
371 r = sd_bus_message_append(n, "s", a->unique_name);
373 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
377 r = bus_message_append_sender(n, "org.freedesktop.DBus");
379 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
383 r = bus_seal_synthetic_message(b, n);
385 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
389 r = sd_bus_send(b, n, NULL);
391 log_error("Failed to send NameAcquired message: %s", strerror(-r));
398 int main(int argc, char *argv[]) {
400 _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
401 sd_id128_t server_id;
402 int r, in_fd, out_fd;
403 bool got_hello = false;
405 struct ucred ucred = {};
406 _cleanup_free_ char *peersec = NULL;
408 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
409 log_parse_environment();
412 r = parse_argv(argc, argv);
416 r = sd_listen_fds(0);
418 in_fd = STDIN_FILENO;
419 out_fd = STDOUT_FILENO;
421 in_fd = SD_LISTEN_FDS_START;
422 out_fd = SD_LISTEN_FDS_START;
424 log_error("Illegal number of file descriptors passed");
429 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
430 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
433 getpeercred(in_fd, &ucred);
434 getpeersec(in_fd, &peersec);
439 log_error("Failed to allocate bus: %s", strerror(-r));
443 r = sd_bus_set_name(a, "sd-proxy");
445 log_error("Failed to set bus name: %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;
468 /* FIXME: faking security labels is broken in kdbus right now */
470 /* a->fake_label = peersec; */
471 /* peersec = NULL; */
474 a->manual_peer_interface = true;
478 log_error("Failed to start bus client: %s", strerror(-r));
482 r = sd_bus_get_server_id(a, &server_id);
484 log_error("Failed to get server ID: %s", strerror(-r));
490 log_error("Failed to allocate bus: %s", strerror(-r));
494 r = sd_bus_set_fd(b, in_fd, out_fd);
496 log_error("Failed to set fds: %s", strerror(-r));
500 r = sd_bus_set_server(b, 1, server_id);
502 log_error("Failed to set server mode: %s", strerror(-r));
506 r = sd_bus_negotiate_fds(b, is_unix);
508 log_error("Failed to set FD negotiation: %s", strerror(-r));
512 r = sd_bus_set_anonymous(b, true);
514 log_error("Failed to set anonymous authentication: %s", strerror(-r));
518 b->manual_peer_interface = true;
522 log_error("Failed to start bus client: %s", strerror(-r));
526 r = rename_service(a, b);
528 log_debug("Failed to rename process: %s", strerror(-r));
531 _cleanup_free_ char *match = NULL;
534 r = sd_bus_get_unique_name(a, &unique);
536 log_error("Failed to get unique name: %s", strerror(-r));
540 match = strjoin("type='signal',"
541 "sender='org.freedesktop.DBus',"
542 "path='/org/freedesktop/DBus',"
543 "interface='org.freedesktop.DBus',"
544 "member='NameOwnerChanged',"
554 r = sd_bus_add_match(a, match, NULL, NULL);
556 log_error("Failed to add match for NameLost: %s", strerror(-r));
561 match = strjoin("type='signal',"
562 "sender='org.freedesktop.DBus',"
563 "path='/org/freedesktop/DBus',"
564 "interface='org.freedesktop.DBus',"
565 "member='NameOwnerChanged',"
575 r = sd_bus_add_match(a, match, NULL, NULL);
577 log_error("Failed to add match for NameAcquired: %s", strerror(-r));
583 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
584 int events_a, events_b, fd;
585 uint64_t timeout_a, timeout_b, t;
586 struct timespec _ts, *ts;
587 struct pollfd *pollfd;
591 r = sd_bus_process(a, &m);
593 /* treat 'connection reset by peer' as clean exit condition */
594 if (r == -ECONNRESET)
597 log_error("Failed to process bus a: %s", strerror(-r));
603 /* We officially got EOF, let's quit */
604 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
609 k = synthesize_name_acquired(a, b, m);
612 log_error("Failed to synthesize message: %s", strerror(-r));
616 k = sd_bus_send(b, m, NULL);
618 if (k == -ECONNRESET)
622 log_error("Failed to send message: %s", strerror(-r));
633 r = sd_bus_process(b, &m);
635 /* treat 'connection reset by peer' as clean exit condition */
636 if (r == -ECONNRESET)
639 log_error("Failed to process bus b: %s", strerror(-r));
645 /* We officially got EOF, let's quit */
646 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
651 k = process_hello(a, b, m, &got_hello);
654 log_error("Failed to process HELLO: %s", strerror(-r));
661 k = process_policy(a, b, m);
664 log_error("Failed to process policy: %s", strerror(-r));
668 k = sd_bus_send(a, m, NULL);
670 if (r == -ECONNRESET)
674 log_error("Failed to send message: %s", strerror(-r));
685 fd = sd_bus_get_fd(a);
687 log_error("Failed to get fd: %s", strerror(-r));
691 events_a = sd_bus_get_events(a);
693 log_error("Failed to get events mask: %s", strerror(-r));
697 r = sd_bus_get_timeout(a, &timeout_a);
699 log_error("Failed to get timeout: %s", strerror(-r));
703 events_b = sd_bus_get_events(b);
705 log_error("Failed to get events mask: %s", strerror(-r));
709 r = sd_bus_get_timeout(b, &timeout_b);
711 log_error("Failed to get timeout: %s", strerror(-r));
716 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
719 if (t == (uint64_t) -1)
724 nw = now(CLOCK_MONOTONIC);
730 ts = timespec_store(&_ts, t);
733 pollfd = (struct pollfd[3]) {
734 {.fd = fd, .events = events_a, },
735 {.fd = in_fd, .events = events_b & POLLIN, },
736 {.fd = out_fd, .events = events_b & POLLOUT, }
739 r = ppoll(pollfd, 3, ts, NULL);
741 log_error("ppoll() failed: %m");
752 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;