chiark / gitweb /
socket: optionally remove sockets/FIFOs in the file system after use
[elogind.git] / src / bus-proxyd / bus-proxyd.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7   Copyright 2013 Daniel Mack
8   Copyright 2014 Kay Sievers
9
10   systemd is free software; you can redistribute it and/or modify it
11   under the terms of the GNU Lesser General Public License as published by
12   the Free Software Foundation; either version 2.1 of the License, or
13   (at your option) any later version.
14
15   systemd is distributed in the hope that it will be useful, but
16   WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18   Lesser General Public License for more details.
19
20   You should have received a copy of the GNU Lesser General Public License
21   along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 ***/
23
24 #include <sys/socket.h>
25 #include <sys/un.h>
26 #include <sys/types.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <sys/poll.h>
32 #include <stddef.h>
33 #include <getopt.h>
34
35 #include "log.h"
36 #include "util.h"
37 #include "socket-util.h"
38 #include "sd-daemon.h"
39 #include "sd-bus.h"
40 #include "bus-internal.h"
41 #include "bus-message.h"
42 #include "bus-util.h"
43 #include "bus-internal.h"
44 #include "build.h"
45 #include "strv.h"
46 #include "def.h"
47 #include "capability.h"
48
49 static const char *arg_address = DEFAULT_SYSTEM_BUS_PATH;
50 static char *arg_command_line_buffer = NULL;
51 static bool arg_drop_privileges = false;
52
53 static int help(void) {
54
55         printf("%s [OPTIONS...]\n\n"
56                "Connect STDIO or a socket to a given bus address.\n\n"
57                "  -h --help              Show this help\n"
58                "     --version           Show package version\n"
59                "     --drop-privileges   Drop privileges\n"
60                "     --address=ADDRESS   Connect to the bus specified by ADDRESS\n"
61                "                         (default: " DEFAULT_SYSTEM_BUS_PATH ")\n",
62                program_invocation_short_name);
63
64         return 0;
65 }
66
67 static int parse_argv(int argc, char *argv[]) {
68
69         enum {
70                 ARG_VERSION = 0x100,
71                 ARG_ADDRESS,
72                 ARG_DROP_PRIVILEGES,
73         };
74
75         static const struct option options[] = {
76                 { "help",            no_argument,       NULL, 'h'                 },
77                 { "version",         no_argument,       NULL, ARG_VERSION         },
78                 { "address",         required_argument, NULL, ARG_ADDRESS         },
79                 { "drop-privileges", no_argument,       NULL, ARG_DROP_PRIVILEGES },
80                 { NULL,              0,                 NULL, 0                   },
81         };
82
83         int c;
84
85         assert(argc >= 0);
86         assert(argv);
87
88         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
89
90                 switch (c) {
91
92                 case 'h':
93                         help();
94                         return 0;
95
96                 case ARG_VERSION:
97                         puts(PACKAGE_STRING);
98                         puts(SYSTEMD_FEATURES);
99                         return 0;
100
101                 case ARG_ADDRESS:
102                         arg_address = optarg;
103                         break;
104
105                 case ARG_DROP_PRIVILEGES:
106                         arg_drop_privileges = true;
107                         break;
108
109                 case '?':
110                         return -EINVAL;
111
112                 default:
113                         assert_not_reached("Unhandled option");
114                 }
115         }
116
117         /* If the first command line argument is only "x" characters
118          * we'll write who we are talking to into it, so that "ps" is
119          * explanatory */
120         arg_command_line_buffer = argv[optind];
121         if (argc > optind + 1 ||
122             (arg_command_line_buffer && arg_command_line_buffer[strspn(arg_command_line_buffer, "x")] != 0)) {
123                 log_error("Too many arguments");
124                 return -EINVAL;
125         }
126
127         return 1;
128 }
129
130 static int rename_service(sd_bus *a, sd_bus *b) {
131         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
132         _cleanup_free_ char *p = NULL, *name = NULL;
133         const char *comm;
134         char **cmdline;
135         uid_t uid;
136         pid_t pid;
137         int r;
138
139         assert(a);
140         assert(b);
141
142         r = sd_bus_get_peer_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM, &creds);
143         if (r < 0)
144                 return r;
145
146         r = sd_bus_creds_get_uid(creds, &uid);
147         if (r < 0)
148                 return r;
149
150         r = sd_bus_creds_get_pid(creds, &pid);
151         if (r < 0)
152                 return r;
153
154         r = sd_bus_creds_get_cmdline(creds, &cmdline);
155         if (r < 0)
156                 return r;
157
158         r = sd_bus_creds_get_comm(creds, &comm);
159         if (r < 0)
160                 return r;
161
162         name = uid_to_name(uid);
163         if (!name)
164                 return -ENOMEM;
165
166         p = strv_join(cmdline, " ");
167         if (!p)
168                 return -ENOMEM;
169
170         /* The status string gets the full command line ... */
171         sd_notifyf(false,
172                    "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
173                    pid, p,
174                    uid, name);
175
176         /* ... and the argv line only the short comm */
177         if (arg_command_line_buffer) {
178                 size_t m, w;
179
180                 m = strlen(arg_command_line_buffer);
181                 w = snprintf(arg_command_line_buffer, m,
182                              "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
183                              pid, comm,
184                              uid, name);
185
186                 if (m > w)
187                         memzero(arg_command_line_buffer + w, m - w);
188         }
189
190         log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
191                   pid, p,
192                   uid, name,
193                   a->unique_name);
194                 ;
195         return 0;
196 }
197
198 static int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
199         _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
200         const char *name, *old_owner, *new_owner;
201         int r;
202
203         assert(a);
204         assert(b);
205         assert(m);
206
207         /* If we get NameOwnerChanged for our own name, we need to
208          * synthesize NameLost/NameAcquired, since socket clients need
209          * that, even though it is obsoleted on kdbus */
210
211         if (!a->is_kernel)
212                 return 0;
213
214         if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
215             !streq_ptr(m->path, "/org/freedesktop/DBus") ||
216             !streq_ptr(m->sender, "org.freedesktop.DBus"))
217                 return 0;
218
219         r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
220         if (r < 0)
221                 return r;
222
223         r = sd_bus_message_rewind(m, true);
224         if (r < 0)
225                 return r;
226
227         if (streq(old_owner, a->unique_name)) {
228
229                 r = sd_bus_message_new_signal(
230                                 b,
231                                 &n,
232                                 "/org/freedesktop/DBus",
233                                 "org.freedesktop.DBus",
234                                 "NameLost");
235
236         } else if (streq(new_owner, a->unique_name)) {
237
238                 r = sd_bus_message_new_signal(
239                                 b,
240                                 &n,
241                                 "/org/freedesktop/DBus",
242                                 "org.freedesktop.DBus",
243                                 "NameAcquired");
244         } else
245                 return 0;
246
247         if (r < 0)
248                 return r;
249
250         r = sd_bus_message_append(n, "s", name);
251         if (r < 0)
252                 return r;
253
254         r = bus_message_append_sender(n, "org.freedesktop.DBus");
255         if (r < 0)
256                 return r;
257
258         r = bus_seal_synthetic_message(b, n);
259         if (r < 0)
260                 return r;
261
262         return sd_bus_send(b, n, NULL);
263 }
264
265 static int process_policy(sd_bus *a, sd_bus *b, sd_bus_message *m) {
266         _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
267         int r;
268
269         assert(a);
270         assert(b);
271         assert(m);
272
273         if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll"))
274                 return 0;
275
276         if (!streq_ptr(m->path, "/org/gnome/DisplayManager/Slave"))
277                 return 0;
278
279         r = sd_bus_message_new_method_errorf(m, &n, SD_BUS_ERROR_ACCESS_DENIED, "gdm, you are stupid");
280         if (r < 0)
281                 return r;
282
283         r = bus_message_append_sender(n, "org.freedesktop.DBus");
284         if (r < 0) {
285                 log_error("Failed to append sender to gdm reply: %s", strerror(-r));
286                 return r;
287         }
288
289         r = bus_seal_synthetic_message(b, n);
290         if (r < 0) {
291                 log_error("Failed to seal gdm reply: %s", strerror(-r));
292                 return r;
293         }
294
295         r = sd_bus_send(b, n, NULL);
296         if (r < 0) {
297                 log_error("Failed to send gdm reply: %s", strerror(-r));
298                 return r;
299         }
300
301         return 1;
302 }
303
304 static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
305         int r;
306
307         assert(b);
308         assert(m);
309
310         r = bus_message_append_sender(m, "org.freedesktop.DBus");
311         if (r < 0)
312                 return r;
313
314         r = bus_seal_synthetic_message(b, m);
315         if (r < 0)
316                 return r;
317
318         return sd_bus_send(b, m, NULL);
319 }
320
321 static int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
322         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
323         int r;
324
325         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
326                 return 0;
327
328         r = sd_bus_message_new_method_error(call, &m, e);
329         if (r < 0)
330                 return r;
331
332         return synthetic_driver_send(call->bus, m);
333 }
334
335 static int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
336
337         _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
338
339         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
340                 return 0;
341
342         if (sd_bus_error_is_set(p))
343                 return synthetic_reply_method_error(call, p);
344
345         sd_bus_error_set_errno(&berror, error);
346
347         return synthetic_reply_method_error(call, &berror);
348 }
349
350 static int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
351         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
352         int r;
353
354         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
355                 return 0;
356
357         r = sd_bus_message_new_method_return(call, &m);
358         if (r < 0)
359                 return r;
360
361         if (!isempty(types)) {
362                 va_list ap;
363
364                 va_start(ap, types);
365                 r = bus_message_append_ap(m, types, ap);
366                 va_end(ap);
367                 if (r < 0)
368                         return r;
369         }
370
371         return synthetic_driver_send(call->bus, m);
372 }
373
374 static int synthetic_reply_return_strv(sd_bus_message *call, char **l) {
375         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
376         int r;
377
378         r = sd_bus_message_new_method_return(call, &m);
379         if (r < 0)
380                 return synthetic_reply_method_errno(call, r, NULL);
381
382         r = sd_bus_message_append_strv(m, l);
383         if (r < 0)
384                 return synthetic_reply_method_errno(call, r, NULL);
385
386         return synthetic_driver_send(call->bus, m);
387 }
388
389 static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
390         _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
391         int r;
392
393         assert(bus);
394         assert(name);
395         assert(_creds);
396
397         assert_return(service_name_is_valid(name), -EINVAL);
398
399         r = sd_bus_get_owner(bus, name, mask, &c);
400         if (r == -ESRCH || r == -ENXIO)
401                 return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
402         if (r < 0)
403                 return r;
404
405         if ((c->mask & mask) != mask)
406                 return -ENOTSUP;
407
408         *_creds = c;
409         c = NULL;
410
411         return 0;
412 }
413
414 static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
415         const char *name;
416         int r;
417
418         assert(bus);
419         assert(m);
420         assert(_creds);
421
422         r = sd_bus_message_read(m, "s", &name);
423         if (r < 0)
424                 return r;
425
426         return get_creds_by_name(bus, name, mask, _creds, error);
427 }
428
429 static int peer_is_privileged(sd_bus *bus, sd_bus_message *m) {
430         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
431         uid_t uid;
432         int r;
433
434         r = get_creds_by_message(bus, m, SD_BUS_CREDS_UID, &creds, NULL);
435         if (r < 0)
436                 return r;
437
438         r = sd_bus_creds_get_uid(creds, &uid);
439         if (r < 0)
440                 return r;
441
442         r = sd_bus_creds_has_effective_cap(creds, CAP_SYS_ADMIN);
443         if (r > 0)
444                 return true;
445
446         if (uid == getuid())
447                 return true;
448
449         return false;
450 }
451
452 static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
453         int r;
454
455         assert(a);
456         assert(b);
457         assert(m);
458
459         if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
460                 return 0;
461
462         if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
463                 if (0 && !isempty(sd_bus_message_get_signature(m, true))) {
464                         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
465
466                         r = sd_bus_error_setf(&error, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
467
468                         return synthetic_reply_method_errno(m, r, &error);
469                 }
470
471                 return synthetic_reply_method_return(m, "s",
472                         "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
473                           "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
474                         "<node>\n"
475                         " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
476                         "  <method name=\"Introspect\">\n"
477                         "   <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
478                         "  </method>\n"
479                         " </interface>\n"
480                         " <interface name=\"org.freedesktop.DBus\">\n"
481                         "  <method name=\"AddMatch\">\n"
482                         "   <arg type=\"s\" direction=\"in\"/>\n"
483                         "  </method>\n"
484                         "  <method name=\"RemoveMatch\">\n"
485                         "   <arg type=\"s\" direction=\"in\"/>\n"
486                         "  </method>\n"
487                         "  <method name=\"GetConnectionSELinuxSecurityContext\">\n"
488                         "   <arg type=\"s\" direction=\"in\"/>\n"
489                         "   <arg type=\"ay\" direction=\"out\"/>\n"
490                         "  </method>\n"
491                         "  <method name=\"GetConnectionUnixProcessID\">\n"
492                         "   <arg type=\"s\" direction=\"in\"/>\n"
493                         "   <arg type=\"u\" direction=\"out\"/>\n"
494                         "  </method>\n"
495                         "  <method name=\"GetConnectionUnixUser\">\n"
496                         "   <arg type=\"s\" direction=\"in\"/>\n"
497                         "   <arg type=\"u\" direction=\"out\"/>\n"
498                         "  </method>\n"
499                         "  <method name=\"GetId\">\n"
500                         "   <arg type=\"s\" direction=\"out\"/>\n"
501                         "  </method>\n"
502                         "  <method name=\"GetNameOwner\">\n"
503                         "   <arg type=\"s\" direction=\"in\"/>\n"
504                         "   <arg type=\"s\" direction=\"out\"/>\n"
505                         "  </method>\n"
506                         "  <method name=\"Hello\">\n"
507                         "   <arg type=\"s\" direction=\"out\"/>\n"
508                         "  </method>\n"
509                         "  <method name=\"ListActivatableNames\">\n"
510                         "   <arg type=\"as\" direction=\"out\"/>\n"
511                         "  </method>\n"
512                         "  <method name=\"ListNames\">\n"
513                         "   <arg type=\"as\" direction=\"out\"/>\n"
514                         "  </method>\n"
515                         "  <method name=\"ListQueuedOwners\">\n"
516                         "   <arg type=\"s\" direction=\"in\"/>\n"
517                         "   <arg type=\"as\" direction=\"out\"/>\n"
518                         "  </method>\n"
519                         "  <method name=\"NameHasOwner\">\n"
520                         "   <arg type=\"s\" direction=\"in\"/>\n"
521                         "   <arg type=\"b\" direction=\"out\"/>\n"
522                         "  </method>\n"
523                         "  <method name=\"ReleaseName\">\n"
524                         "   <arg type=\"s\" direction=\"in\"/>\n"
525                         "   <arg type=\"u\" direction=\"out\"/>\n"
526                         "  </method>\n"
527                         "  <method name=\"ReloadConfig\">\n"
528                         "  </method>\n"
529                         "  <method name=\"RequestName\">\n"
530                         "   <arg type=\"s\" direction=\"in\"/>\n"
531                         "   <arg type=\"u\" direction=\"in\"/>\n"
532                         "   <arg type=\"u\" direction=\"out\"/>\n"
533                         "  </method>\n"
534                         "  <method name=\"StartServiceByName\">\n"
535                         "   <arg type=\"s\" direction=\"in\"/>\n"
536                         "   <arg type=\"u\" direction=\"in\"/>\n"
537                         "   <arg type=\"u\" direction=\"out\"/>\n"
538                         "  </method>\n"
539                         "  <method name=\"UpdateActivationEnvironment\">\n"
540                         "   <arg type=\"a{ss}\" direction=\"in\"/>\n"
541                         "  </method>\n"
542                         "  <signal name=\"NameAcquired\">\n"
543                         "   <arg type=\"s\"/>\n"
544                         "  </signal>\n"
545                         "  <signal name=\"NameLost\">\n"
546                         "   <arg type=\"s\"/>\n"
547                         "  </signal>\n"
548                         "  <signal name=\"NameOwnerChanged\">\n"
549                         "   <arg type=\"s\"/>\n"
550                         "   <arg type=\"s\"/>\n"
551                         "   <arg type=\"s\"/>\n"
552                         "  </signal>\n"
553                         " </interface>\n"
554                         "</node>\n");
555
556         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
557                 const char *match;
558
559                 r = sd_bus_message_read(m, "s", &match);
560                 if (r < 0)
561                         return synthetic_reply_method_errno(m, r, NULL);
562
563                 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
564                 if (r < 0)
565                         return synthetic_reply_method_errno(m, r, NULL);
566
567                 return synthetic_reply_method_return(m, NULL);
568
569         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
570                 const char *match;
571
572                 r = sd_bus_message_read(m, "s", &match);
573                 if (r < 0)
574                         return synthetic_reply_method_errno(m, r, NULL);
575
576                 r = bus_remove_match_by_string(a, match, NULL, NULL);
577                 if (r == 0)
578                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
579                 if (r < 0)
580                         return synthetic_reply_method_errno(m, r, NULL);
581
582                 return synthetic_reply_method_return(m, NULL);
583
584         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
585                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
586
587                 r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, NULL);
588                 if (r < 0)
589                         return synthetic_reply_method_errno(m, r, NULL);
590
591                 return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
592
593         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
594                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
595
596                 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, NULL);
597                 if (r < 0)
598                         return synthetic_reply_method_errno(m, r, NULL);
599
600                 return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
601
602         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
603                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
604
605                 r = get_creds_by_message(a, m, SD_BUS_CREDS_UID, &creds, NULL);
606                 if (r < 0)
607                         return synthetic_reply_method_errno(m, r, NULL);
608
609                 return synthetic_reply_method_return(m, "u", (uint32_t) creds->uid);
610
611         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
612                 sd_id128_t server_id;
613                 char buf[SD_ID128_STRING_MAX];
614
615                 r = sd_bus_get_server_id(a, &server_id);
616                 if (r < 0)
617                         return synthetic_reply_method_errno(m, r, NULL);
618
619                 return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
620
621         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
622                 const char *name;
623                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
624                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
625
626                 r = sd_bus_message_read(m, "s", &name);
627                 if (r < 0)
628                         return synthetic_reply_method_errno(m, r, NULL);
629
630                 if (streq(name, "org.freedesktop.DBus"))
631                         return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
632
633                 r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
634                 if (r < 0)
635                         return synthetic_reply_method_errno(m, r, &error);
636
637                 return synthetic_reply_method_return(m, "s", creds->unique_name);
638
639         /* "Hello" is handled in process_hello() */
640
641         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
642                 _cleanup_strv_free_ char **names = NULL;
643
644                 r = sd_bus_list_names(a, NULL, &names);
645                 if (r < 0)
646                         return synthetic_reply_method_errno(m, r, NULL);
647
648                 /* Let's sort the names list to make it stable */
649                 strv_sort(names);
650
651                 return synthetic_reply_return_strv(m, names);
652
653         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
654                 _cleanup_strv_free_ char **names = NULL;
655
656                 r = sd_bus_list_names(a, &names, NULL);
657                 if (r < 0)
658                         return synthetic_reply_method_errno(m, r, NULL);
659
660                 r = strv_extend(&names, "org.freedesktop.DBus");
661                 if (r < 0)
662                         return synthetic_reply_method_errno(m, r, NULL);
663
664                 /* Let's sort the names list to make it stable */
665                 strv_sort(names);
666
667                 return synthetic_reply_return_strv(m, names);
668
669         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
670                 struct kdbus_cmd_name_list cmd = {};
671                 struct kdbus_name_list *name_list;
672                 struct kdbus_cmd_name *name;
673                 _cleanup_strv_free_ char **owners = NULL;
674                 char *arg0;
675                 int err = 0;
676
677                 r = sd_bus_message_read(m, "s", &arg0);
678                 if (r < 0)
679                         return synthetic_reply_method_errno(m, r, NULL);
680
681                 if (service_name_is_valid(arg0) < 0)
682                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
683
684                 cmd.flags = KDBUS_NAME_LIST_QUEUED;
685                 r = ioctl(a->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
686                 if (r < 0)
687                         return synthetic_reply_method_errno(m, -errno, NULL);
688
689                 name_list = (struct kdbus_name_list *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
690
691                 KDBUS_ITEM_FOREACH(name, name_list, names) {
692                         char *n;
693
694                         if (name->size <= sizeof(*name))
695                                 continue;
696
697                         if (!streq(name->name, arg0))
698                                 continue;
699
700                         if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
701                                 err  = -ENOMEM;
702                                 break;
703                         }
704
705                         r = strv_consume(&owners, n);
706                         if (r < 0) {
707                                 err = r;
708                                 break;
709                         }
710                 }
711
712                 r = ioctl(a->input_fd, KDBUS_CMD_FREE, &cmd.offset);
713                 if (r < 0)
714                         return synthetic_reply_method_errno(m, r, NULL);
715
716                 if (err > 0)
717                         return synthetic_reply_method_errno(m, err, NULL);
718
719                 return synthetic_reply_return_strv(m, owners);
720
721         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
722                 const char *name;
723
724                 r = sd_bus_message_read(m, "s", &name);
725                 if (r < 0)
726                         return synthetic_reply_method_errno(m, r, NULL);
727
728                 if (service_name_is_valid(name) < 0)
729                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
730
731                 if (streq(name, "org.freedesktop.DBus"))
732                         return synthetic_reply_method_return(m, "b", true);
733
734                 r = sd_bus_get_owner(a, name, 0, NULL);
735                 if (r < 0 && r != -ESRCH && r != -ENXIO)
736                         return synthetic_reply_method_errno(m, r, NULL);
737
738                 return synthetic_reply_method_return(m, "b", r >= 0);
739
740         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
741                 const char *name;
742
743                 r = sd_bus_message_read(m, "s", &name);
744                 if (r < 0)
745                         return synthetic_reply_method_errno(m, r, NULL);
746
747                 if (service_name_is_valid(name) < 0)
748                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
749
750                 r = sd_bus_release_name(a, name);
751                 if (r < 0) {
752                         if (r == -ESRCH)
753                                 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
754                         if (r == -EADDRINUSE)
755                                 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
756
757                         return synthetic_reply_method_errno(m, r, NULL);
758                 }
759
760                 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
761
762         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
763                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
764
765                 r = sd_bus_error_setf(&error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
766
767                 return synthetic_reply_method_errno(m, r, &error);
768
769         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
770                 const char *name;
771                 uint32_t flags;
772
773                 r = sd_bus_message_read(m, "su", &name, &flags);
774                 if (r < 0)
775                         return synthetic_reply_method_errno(m, r, NULL);
776
777                 if (service_name_is_valid(name) < 0)
778                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
779                 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
780                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
781
782                 r = sd_bus_request_name(a, name, flags);
783                 if (r < 0) {
784                         if (r == -EEXIST)
785                                 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
786                         if (r == -EALREADY)
787                                 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
788                         return synthetic_reply_method_errno(m, r, NULL);
789                 }
790
791                 if (r == 0)
792                         return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
793
794                 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
795
796         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
797                 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
798                 const char *name;
799                 uint32_t flags;
800
801                 r = sd_bus_message_read(m, "su", &name, &flags);
802                 if (r < 0)
803                         return synthetic_reply_method_errno(m, r, NULL);
804
805                 if (service_name_is_valid(name) < 0)
806                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
807                 if (flags != 0)
808                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
809
810                 r = sd_bus_get_owner(a, name, 0, NULL);
811                 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
812                         return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
813                 if (r != -ESRCH)
814                         return synthetic_reply_method_errno(m, r, NULL);
815
816                 r = sd_bus_message_new_method_call(
817                                 a,
818                                 &msg,
819                                 name,
820                                 "/",
821                                 "org.freedesktop.DBus.Peer",
822                                 "Ping");
823                 if (r < 0)
824                         return synthetic_reply_method_errno(m, r, NULL);
825
826                 r = sd_bus_send(a, msg, NULL);
827                 if (r < 0)
828                         return synthetic_reply_method_errno(m, r, NULL);
829
830                 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
831
832         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
833                 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
834                 _cleanup_strv_free_ char **args = NULL;
835
836                 if (!peer_is_privileged(a, m))
837                         return synthetic_reply_method_errno(m, -EPERM, NULL);
838
839                 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
840                 if (r < 0)
841                         return synthetic_reply_method_errno(m, r, NULL);
842
843                 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
844                         _cleanup_free_ char *s = NULL;
845                         const char *key;
846                         const char *value;
847
848                         r = sd_bus_message_read(m, "ss", &key, &value);
849                         if (r < 0)
850                                 return synthetic_reply_method_errno(m, r, NULL);
851
852                         s = strjoin(key, "=", value, NULL);
853                         if (!s)
854                                 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
855
856                         r  = strv_extend(&args, s);
857                         if (r < 0)
858                                 return synthetic_reply_method_errno(m, r, NULL);
859
860                         r = sd_bus_message_exit_container(m);
861                         if (r < 0)
862                                 return synthetic_reply_method_errno(m, r, NULL);
863                 }
864
865                 r = sd_bus_message_exit_container(m);
866                 if (r < 0)
867                         return synthetic_reply_method_errno(m, r, NULL);
868
869                 if (!args)
870                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
871
872                 r = sd_bus_message_new_method_call(
873                                 a,
874                                 &msg,
875                                 "org.freedesktop.systemd1",
876                                 "/org/freedesktop/systemd1",
877                                 "org.freedesktop.systemd1.Manager",
878                                 "SetEnvironment");
879                 if (r < 0)
880                         return synthetic_reply_method_errno(m, r, NULL);
881
882                 r = sd_bus_message_append_strv(msg, args);
883                 if (r < 0)
884                         return synthetic_reply_method_errno(m, r, NULL);
885
886                 r = sd_bus_call(a, msg, 0, NULL, NULL);
887                 if (r < 0)
888                         return synthetic_reply_method_errno(m, r, NULL);
889
890                return synthetic_reply_method_return(m, NULL);
891
892         } else {
893                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
894
895                 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
896
897                 return synthetic_reply_method_errno(m, r, &error);
898         }
899 }
900
901 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
902         _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
903         bool is_hello;
904         int r;
905
906         assert(a);
907         assert(b);
908         assert(m);
909         assert(got_hello);
910
911         /* As reaction to hello we need to respond with two messages:
912          * the callback reply and the NameAcquired for the unique
913          * name, since hello is otherwise obsolete on kdbus. */
914
915         is_hello =
916                 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
917                 streq_ptr(m->destination, "org.freedesktop.DBus");
918
919         if (!is_hello) {
920
921                 if (*got_hello)
922                         return 0;
923
924                 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
925                 return -EIO;
926         }
927
928         if (*got_hello) {
929                 log_error("Got duplicate hello, aborting.");
930                 return -EIO;
931         }
932
933         *got_hello = true;
934
935         if (!a->is_kernel)
936                 return 0;
937
938         r = sd_bus_message_new_method_return(m, &n);
939         if (r < 0) {
940                 log_error("Failed to generate HELLO reply: %s", strerror(-r));
941                 return r;
942         }
943
944         r = sd_bus_message_append(n, "s", a->unique_name);
945         if (r < 0) {
946                 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
947                 return r;
948         }
949
950         r = bus_message_append_sender(n, "org.freedesktop.DBus");
951         if (r < 0) {
952                 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
953                 return r;
954         }
955
956         r = bus_seal_synthetic_message(b, n);
957         if (r < 0) {
958                 log_error("Failed to seal HELLO reply: %s", strerror(-r));
959                 return r;
960         }
961
962         r = sd_bus_send(b, n, NULL);
963         if (r < 0) {
964                 log_error("Failed to send HELLO reply: %s", strerror(-r));
965                 return r;
966         }
967
968         n = sd_bus_message_unref(n);
969         r = sd_bus_message_new_signal(
970                         b,
971                         &n,
972                         "/org/freedesktop/DBus",
973                         "org.freedesktop.DBus",
974                         "NameAcquired");
975         if (r < 0) {
976                 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
977                 return r;
978         }
979
980         r = sd_bus_message_append(n, "s", a->unique_name);
981         if (r < 0) {
982                 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
983                 return r;
984         }
985
986         r = bus_message_append_sender(n, "org.freedesktop.DBus");
987         if (r < 0) {
988                 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
989                 return r;
990         }
991
992         r = bus_seal_synthetic_message(b, n);
993         if (r < 0) {
994                 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
995                 return r;
996         }
997
998         r = sd_bus_send(b, n, NULL);
999         if (r < 0) {
1000                 log_error("Failed to send NameAcquired message: %s", strerror(-r));
1001                 return r;
1002         }
1003
1004         return 1;
1005 }
1006
1007 static int patch_sender(sd_bus *a, sd_bus_message *m) {
1008         char **well_known = NULL;
1009         sd_bus_creds *c;
1010         int r;
1011
1012         assert(a);
1013         assert(m);
1014
1015         if (!a->is_kernel)
1016                 return 0;
1017
1018         /* We will change the sender of messages from the bus driver
1019          * so that they originate from the bus driver. This is a
1020          * speciality originating from dbus1, where the bus driver did
1021          * not have a unique id, but only the well-known name. */
1022
1023         c = sd_bus_message_get_creds(m);
1024         if (!c)
1025                 return 0;
1026
1027         r = sd_bus_creds_get_well_known_names(c, &well_known);
1028         if (r < 0)
1029                 return r;
1030
1031         if (strv_contains(well_known, "org.freedesktop.DBus"))
1032                 m->sender = "org.freedesktop.DBus";
1033
1034         return 0;
1035 }
1036
1037 int main(int argc, char *argv[]) {
1038
1039         _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
1040         sd_id128_t server_id;
1041         int r, in_fd, out_fd;
1042         bool got_hello = false;
1043         bool is_unix;
1044         struct ucred ucred = {};
1045         _cleanup_free_ char *peersec = NULL;
1046
1047         log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
1048         log_parse_environment();
1049         log_open();
1050
1051         r = parse_argv(argc, argv);
1052         if (r <= 0)
1053                 goto finish;
1054
1055         r = sd_listen_fds(0);
1056         if (r == 0) {
1057                 in_fd = STDIN_FILENO;
1058                 out_fd = STDOUT_FILENO;
1059         } else if (r == 1) {
1060                 in_fd = SD_LISTEN_FDS_START;
1061                 out_fd = SD_LISTEN_FDS_START;
1062         } else {
1063                 log_error("Illegal number of file descriptors passed");
1064                 goto finish;
1065         }
1066
1067         is_unix =
1068                 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
1069                 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
1070
1071         if (is_unix) {
1072                 getpeercred(in_fd, &ucred);
1073                 getpeersec(in_fd, &peersec);
1074         }
1075
1076         if (arg_drop_privileges) {
1077                 const char *user = "systemd-bus-proxy";
1078                 uid_t uid;
1079                 gid_t gid;
1080
1081                 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
1082                 if (r < 0) {
1083                         log_error("Cannot resolve user name %s: %s", user, strerror(-r));
1084                         goto finish;
1085                 }
1086
1087                 r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
1088                 if (r < 0)
1089                         goto finish;
1090         }
1091
1092         r = sd_bus_new(&a);
1093         if (r < 0) {
1094                 log_error("Failed to allocate bus: %s", strerror(-r));
1095                 goto finish;
1096         }
1097
1098         r = sd_bus_set_name(a, "sd-proxy");
1099         if (r < 0) {
1100                 log_error("Failed to set bus name: %s", strerror(-r));
1101                 goto finish;
1102         }
1103
1104         r = sd_bus_set_address(a, arg_address);
1105         if (r < 0) {
1106                 log_error("Failed to set address to connect to: %s", strerror(-r));
1107                 goto finish;
1108         }
1109
1110         r = sd_bus_negotiate_fds(a, is_unix);
1111         if (r < 0) {
1112                 log_error("Failed to set FD negotiation: %s", strerror(-r));
1113                 goto finish;
1114         }
1115
1116         if (ucred.pid > 0) {
1117                 a->fake_creds.pid = ucred.pid;
1118                 a->fake_creds.uid = ucred.uid;
1119                 a->fake_creds.gid = ucred.gid;
1120                 a->fake_creds_valid = true;
1121         }
1122
1123         if (peersec) {
1124                 a->fake_label = peersec;
1125                 peersec = NULL;
1126         }
1127
1128         a->manual_peer_interface = true;
1129
1130         r = sd_bus_start(a);
1131         if (r < 0) {
1132                 log_error("Failed to start bus client: %s", strerror(-r));
1133                 goto finish;
1134         }
1135
1136         r = sd_bus_get_server_id(a, &server_id);
1137         if (r < 0) {
1138                 log_error("Failed to get server ID: %s", strerror(-r));
1139                 goto finish;
1140         }
1141
1142         r = sd_bus_new(&b);
1143         if (r < 0) {
1144                 log_error("Failed to allocate bus: %s", strerror(-r));
1145                 goto finish;
1146         }
1147
1148         r = sd_bus_set_fd(b, in_fd, out_fd);
1149         if (r < 0) {
1150                 log_error("Failed to set fds: %s", strerror(-r));
1151                 goto finish;
1152         }
1153
1154         r = sd_bus_set_server(b, 1, server_id);
1155         if (r < 0) {
1156                 log_error("Failed to set server mode: %s", strerror(-r));
1157                 goto finish;
1158         }
1159
1160         r = sd_bus_negotiate_fds(b, is_unix);
1161         if (r < 0) {
1162                 log_error("Failed to set FD negotiation: %s", strerror(-r));
1163                 goto finish;
1164         }
1165
1166         r = sd_bus_set_anonymous(b, true);
1167         if (r < 0) {
1168                 log_error("Failed to set anonymous authentication: %s", strerror(-r));
1169                 goto finish;
1170         }
1171
1172         b->manual_peer_interface = true;
1173
1174         r = sd_bus_start(b);
1175         if (r < 0) {
1176                 log_error("Failed to start bus client: %s", strerror(-r));
1177                 goto finish;
1178         }
1179
1180         r = rename_service(a, b);
1181         if (r < 0)
1182                 log_debug("Failed to rename process: %s", strerror(-r));
1183
1184         if (a->is_kernel) {
1185                 _cleanup_free_ char *match = NULL;
1186                 const char *unique;
1187
1188                 r = sd_bus_get_unique_name(a, &unique);
1189                 if (r < 0) {
1190                         log_error("Failed to get unique name: %s", strerror(-r));
1191                         goto finish;
1192                 }
1193
1194                 match = strjoin("type='signal',"
1195                                 "sender='org.freedesktop.DBus',"
1196                                 "path='/org/freedesktop/DBus',"
1197                                 "interface='org.freedesktop.DBus',"
1198                                 "member='NameOwnerChanged',"
1199                                 "arg1='",
1200                                 unique,
1201                                 "'",
1202                                 NULL);
1203                 if (!match) {
1204                         log_oom();
1205                         goto finish;
1206                 }
1207
1208                 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1209                 if (r < 0) {
1210                         log_error("Failed to add match for NameLost: %s", strerror(-r));
1211                         goto finish;
1212                 }
1213
1214                 free(match);
1215                 match = strjoin("type='signal',"
1216                                 "sender='org.freedesktop.DBus',"
1217                                 "path='/org/freedesktop/DBus',"
1218                                 "interface='org.freedesktop.DBus',"
1219                                 "member='NameOwnerChanged',"
1220                                 "arg2='",
1221                                 unique,
1222                                 "'",
1223                                 NULL);
1224                 if (!match) {
1225                         log_oom();
1226                         goto finish;
1227                 }
1228
1229                 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1230                 if (r < 0) {
1231                         log_error("Failed to add match for NameAcquired: %s", strerror(-r));
1232                         goto finish;
1233                 }
1234         }
1235
1236         for (;;) {
1237                 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1238                 int events_a, events_b, fd;
1239                 uint64_t timeout_a, timeout_b, t;
1240                 struct timespec _ts, *ts;
1241                 struct pollfd *pollfd;
1242                 int k;
1243
1244                 if (got_hello) {
1245                         r = sd_bus_process(a, &m);
1246                         if (r < 0) {
1247                                 /* treat 'connection reset by peer' as clean exit condition */
1248                                 if (r == -ECONNRESET)
1249                                         r = 0;
1250                                 else
1251                                         log_error("Failed to process bus a: %s", strerror(-r));
1252
1253                                 goto finish;
1254                         }
1255
1256                         if (m) {
1257                                 /* We officially got EOF, let's quit */
1258                                 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1259                                         r = 0;
1260                                         goto finish;
1261                                 }
1262
1263                                 k = synthesize_name_acquired(a, b, m);
1264                                 if (k < 0) {
1265                                         r = k;
1266                                         log_error("Failed to synthesize message: %s", strerror(-r));
1267                                         goto finish;
1268                                 }
1269
1270                                 patch_sender(a, m);
1271
1272                                 k = sd_bus_send(b, m, NULL);
1273                                 if (k < 0) {
1274                                         if (k == -ECONNRESET)
1275                                                 r = 0;
1276                                         else {
1277                                                 r = k;
1278                                                 log_error("Failed to send message: %s", strerror(-r));
1279                                         }
1280
1281                                         goto finish;
1282                                 }
1283                         }
1284
1285                         if (r > 0)
1286                                 continue;
1287                 }
1288
1289                 r = sd_bus_process(b, &m);
1290                 if (r < 0) {
1291                         /* treat 'connection reset by peer' as clean exit condition */
1292                         if (r == -ECONNRESET)
1293                                 r = 0;
1294                         else
1295                                 log_error("Failed to process bus b: %s", strerror(-r));
1296
1297                         goto finish;
1298                 }
1299
1300                 if (m) {
1301                         /* We officially got EOF, let's quit */
1302                         if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1303                                 r = 0;
1304                                 goto finish;
1305                         }
1306
1307                         k = process_hello(a, b, m, &got_hello);
1308                         if (k < 0) {
1309                                 r = k;
1310                                 log_error("Failed to process HELLO: %s", strerror(-r));
1311                                 goto finish;
1312                         }
1313
1314                         if (k > 0)
1315                                 r = k;
1316                         else {
1317                                 k = process_policy(a, b, m);
1318                                 if (k < 0) {
1319                                         r = k;
1320                                         log_error("Failed to process policy: %s", strerror(-r));
1321                                         goto finish;
1322                                 }
1323
1324                                 k = process_driver(a, b, m);
1325                                 if (k < 0) {
1326                                         r = k;
1327                                         log_error("Failed to process driver calls: %s", strerror(-r));
1328                                         goto finish;
1329                                 }
1330
1331                                 if (k > 0)
1332                                         r = k;
1333                                 else {
1334                                         k = sd_bus_send(a, m, NULL);
1335                                         if (k < 0) {
1336                                                 if (r == -ECONNRESET)
1337                                                         r = 0;
1338                                                 else {
1339                                                         r = k;
1340                                                         log_error("Failed to send message: %s", strerror(-r));
1341                                                 }
1342
1343                                                 goto finish;
1344                                         }
1345                                 }
1346                         }
1347                 }
1348
1349                 if (r > 0)
1350                         continue;
1351
1352                 fd = sd_bus_get_fd(a);
1353                 if (fd < 0) {
1354                         log_error("Failed to get fd: %s", strerror(-r));
1355                         goto finish;
1356                 }
1357
1358                 events_a = sd_bus_get_events(a);
1359                 if (events_a < 0) {
1360                         log_error("Failed to get events mask: %s", strerror(-r));
1361                         goto finish;
1362                 }
1363
1364                 r = sd_bus_get_timeout(a, &timeout_a);
1365                 if (r < 0) {
1366                         log_error("Failed to get timeout: %s", strerror(-r));
1367                         goto finish;
1368                 }
1369
1370                 events_b = sd_bus_get_events(b);
1371                 if (events_b < 0) {
1372                         log_error("Failed to get events mask: %s", strerror(-r));
1373                         goto finish;
1374                 }
1375
1376                 r = sd_bus_get_timeout(b, &timeout_b);
1377                 if (r < 0) {
1378                         log_error("Failed to get timeout: %s", strerror(-r));
1379                         goto finish;
1380                 }
1381
1382                 t = timeout_a;
1383                 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
1384                         t = timeout_b;
1385
1386                 if (t == (uint64_t) -1)
1387                         ts = NULL;
1388                 else {
1389                         usec_t nw;
1390
1391                         nw = now(CLOCK_MONOTONIC);
1392                         if (t > nw)
1393                                 t -= nw;
1394                         else
1395                                 t = 0;
1396
1397                         ts = timespec_store(&_ts, t);
1398                 }
1399
1400                 pollfd = (struct pollfd[3]) {
1401                         {.fd = fd,     .events = events_a,           },
1402                         {.fd = in_fd,  .events = events_b & POLLIN,  },
1403                         {.fd = out_fd, .events = events_b & POLLOUT, }
1404                 };
1405
1406                 r = ppoll(pollfd, 3, ts, NULL);
1407                 if (r < 0) {
1408                         log_error("ppoll() failed: %m");
1409                         goto finish;
1410                 }
1411         }
1412
1413 finish:
1414         sd_bus_flush(a);
1415         sd_bus_flush(b);
1416
1417         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1418 }