chiark / gitweb /
46df223c517982a42c054c5d5a65a98ed278ec1e
[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
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.
12
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.
17
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/>.
20 ***/
21
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <sys/types.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <sys/poll.h>
30 #include <stddef.h>
31 #include <getopt.h>
32
33 #include "log.h"
34 #include "util.h"
35 #include "socket-util.h"
36 #include "sd-daemon.h"
37 #include "sd-bus.h"
38 #include "bus-internal.h"
39 #include "bus-message.h"
40 #include "bus-util.h"
41 #include "build.h"
42 #include "strv.h"
43 #include "def.h"
44
45 static const char *arg_address = DEFAULT_SYSTEM_BUS_PATH;
46 static char *arg_command_line_buffer = NULL;
47
48 static int help(void) {
49
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);
57
58         return 0;
59 }
60
61 static int parse_argv(int argc, char *argv[]) {
62
63         enum {
64                 ARG_VERSION = 0x100,
65                 ARG_ADDRESS,
66         };
67
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    },
72                 { NULL,         0,                 NULL, 0              }
73         };
74
75         int c;
76
77         assert(argc >= 0);
78         assert(argv);
79
80         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
81
82                 switch (c) {
83
84                 case 'h':
85                         help();
86                         return 0;
87
88                 case ARG_VERSION:
89                         puts(PACKAGE_STRING);
90                         puts(SYSTEMD_FEATURES);
91                         return 0;
92
93                 case ARG_ADDRESS:
94                         arg_address = optarg;
95                         break;
96
97                 case '?':
98                         return -EINVAL;
99
100                 default:
101                         assert_not_reached("Unhandled option");
102                 }
103         }
104
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
107          * explanatory */
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");
112                 return -EINVAL;
113         }
114
115         return 1;
116 }
117
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;
121         const char *comm;
122         char **cmdline;
123         uid_t uid;
124         pid_t pid;
125         int r;
126
127         assert(a);
128         assert(b);
129
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);
131         if (r < 0)
132                 return r;
133
134         r = sd_bus_creds_get_uid(creds, &uid);
135         if (r < 0)
136                 return r;
137
138         r = sd_bus_creds_get_pid(creds, &pid);
139         if (r < 0)
140                 return r;
141
142         r = sd_bus_creds_get_cmdline(creds, &cmdline);
143         if (r < 0)
144                 return r;
145
146         r = sd_bus_creds_get_comm(creds, &comm);
147         if (r < 0)
148                 return r;
149
150         name = uid_to_name(uid);
151         if (!name)
152                 return -ENOMEM;
153
154         p = strv_join(cmdline, " ");
155         if (!p)
156                 return -ENOMEM;
157
158         /* The status string gets the full command line ... */
159         sd_notifyf(false,
160                    "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
161                    pid, p,
162                    uid, name);
163
164         /* ... and the argv line only the short comm */
165         if (arg_command_line_buffer) {
166                 size_t m, w;
167
168                 m = strlen(arg_command_line_buffer);
169                 w = snprintf(arg_command_line_buffer, m,
170                              "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
171                              pid, comm,
172                              uid, name);
173
174                 if (m > w)
175                         memzero(arg_command_line_buffer + w, m - w);
176         }
177
178         log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
179                   pid, p,
180                   uid, name,
181                   a->unique_name);
182                 ;
183         return 0;
184 }
185
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;
189         int r;
190
191         assert(a);
192         assert(b);
193         assert(m);
194
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 */
198
199         if (!a->is_kernel)
200                 return 0;
201
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"))
205                 return 0;
206
207         r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
208         if (r < 0)
209                 return r;
210
211         r = sd_bus_message_rewind(m, true);
212         if (r < 0)
213                 return r;
214
215         if (streq(old_owner, a->unique_name)) {
216
217                 r = sd_bus_message_new_signal(
218                                 b,
219                                 &n,
220                                 "/org/freedesktop/DBus",
221                                 "org.freedesktop.DBus",
222                                 "NameLost");
223
224         } else if (streq(new_owner, a->unique_name)) {
225
226                 r = sd_bus_message_new_signal(
227                                 b,
228                                 &n,
229                                 "/org/freedesktop/DBus",
230                                 "org.freedesktop.DBus",
231                                 "NameAcquired");
232         } else
233                 return 0;
234
235         if (r < 0)
236                 return r;
237
238         r = sd_bus_message_append(n, "s", name);
239         if (r < 0)
240                 return r;
241
242         r = bus_message_append_sender(n, "org.freedesktop.DBus");
243         if (r < 0)
244                 return r;
245
246         r = bus_seal_synthetic_message(b, n);
247         if (r < 0)
248                 return r;
249
250         return sd_bus_send(b, n, NULL);
251 }
252
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;
255         int r;
256
257         assert(a);
258         assert(b);
259         assert(m);
260
261         if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll"))
262                 return 0;
263
264         if (!streq_ptr(m->path, "/org/gnome/DisplayManager/Slave"))
265                 return 0;
266
267         r = sd_bus_message_new_method_errorf(m, &n, SD_BUS_ERROR_ACCESS_DENIED, "gdm, you are stupid");
268         if (r < 0)
269                 return r;
270
271         r = bus_message_append_sender(n, "org.freedesktop.DBus");
272         if (r < 0) {
273                 log_error("Failed to append sender to gdm reply: %s", strerror(-r));
274                 return r;
275         }
276
277         r = bus_seal_synthetic_message(b, n);
278         if (r < 0) {
279                 log_error("Failed to seal gdm reply: %s", strerror(-r));
280                 return r;
281         }
282
283         r = sd_bus_send(b, n, NULL);
284         if (r < 0) {
285                 log_error("Failed to send gdm reply: %s", strerror(-r));
286                 return r;
287         }
288
289         return 1;
290 }
291
292 static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
293         int r;
294
295         assert(b);
296         assert(m);
297
298         r = bus_message_append_sender(m, "org.freedesktop.DBus");
299         if (r < 0)
300                 return r;
301
302         r = bus_seal_synthetic_message(b, m);
303         if (r < 0)
304                 return r;
305
306         return sd_bus_send(b, m, NULL);
307 }
308
309 static int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
310         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
311         int r;
312
313         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
314                 return 0;
315
316         r = sd_bus_message_new_method_error(call, &m, e);
317         if (r < 0)
318                 return r;
319
320         return synthetic_driver_send(call->bus, m);
321 }
322
323 static int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
324
325         _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
326
327         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
328                 return 0;
329
330         if (sd_bus_error_is_set(p))
331                 return synthetic_reply_method_error(call, p);
332
333         sd_bus_error_set_errno(&berror, error);
334
335         return synthetic_reply_method_error(call, &berror);
336 }
337
338 static int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
339
340         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
341         int r;
342
343         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
344                 return 0;
345
346         r = sd_bus_message_new_method_return(call, &m);
347         if (r < 0)
348                 return r;
349
350         if (!isempty(types)) {
351                 va_list ap;
352
353                 va_start(ap, types);
354                 r = bus_message_append_ap(m, types, ap);
355                 va_end(ap);
356                 if (r < 0)
357                         return r;
358         }
359
360         return synthetic_driver_send(call->bus, m);
361 }
362
363 static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
364         int r;
365
366         assert(a);
367         assert(b);
368         assert(m);
369
370         if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
371                 return 0;
372
373         if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
374                 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
375                 const char *match;
376
377                 r = sd_bus_message_read(m, "s", &match);
378                 if (r < 0)
379                         return synthetic_reply_method_errno(m, r, NULL);
380
381                 r = sd_bus_add_match(a, match, NULL, NULL);
382                 if (r < 0)
383                         return synthetic_reply_method_errno(m, r, NULL);
384
385                 return synthetic_reply_method_return(m, NULL);
386
387         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
388                 const char *match;
389
390                 r = sd_bus_message_read(m, "s", &match);
391                 if (r < 0)
392                         return synthetic_reply_method_errno(m, r, NULL);
393
394                 r = sd_bus_remove_match(a, match, NULL, NULL);
395                 if (r < 0)
396                         return synthetic_reply_method_errno(m, r, NULL);
397
398                 return synthetic_reply_method_return(m, NULL);
399         }
400
401         return 0;
402 }
403
404 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
405         _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
406         bool is_hello;
407         int r;
408
409         assert(a);
410         assert(b);
411         assert(m);
412         assert(got_hello);
413
414         /* As reaction to hello we need to respond with two messages:
415          * the callback reply and the NameAcquired for the unique
416          * name, since hello is otherwise obsolete on kdbus. */
417
418         is_hello =
419                 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
420                 streq_ptr(m->destination, "org.freedesktop.DBus");
421
422         if (!is_hello) {
423
424                 if (*got_hello)
425                         return 0;
426
427                 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
428                 return -EIO;
429         }
430
431         if (*got_hello) {
432                 log_error("Got duplicate hello, aborting.");
433                 return -EIO;
434         }
435
436         *got_hello = true;
437
438         if (!a->is_kernel)
439                 return 0;
440
441         r = sd_bus_message_new_method_return(m, &n);
442         if (r < 0) {
443                 log_error("Failed to generate HELLO reply: %s", strerror(-r));
444                 return r;
445         }
446
447         r = sd_bus_message_append(n, "s", a->unique_name);
448         if (r < 0) {
449                 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
450                 return r;
451         }
452
453         r = bus_message_append_sender(n, "org.freedesktop.DBus");
454         if (r < 0) {
455                 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
456                 return r;
457         }
458
459         r = bus_seal_synthetic_message(b, n);
460         if (r < 0) {
461                 log_error("Failed to seal HELLO reply: %s", strerror(-r));
462                 return r;
463         }
464
465         r = sd_bus_send(b, n, NULL);
466         if (r < 0) {
467                 log_error("Failed to send HELLO reply: %s", strerror(-r));
468                 return r;
469         }
470
471         n = sd_bus_message_unref(n);
472         r = sd_bus_message_new_signal(
473                         b,
474                         &n,
475                         "/org/freedesktop/DBus",
476                         "org.freedesktop.DBus",
477                         "NameAcquired");
478         if (r < 0) {
479                 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
480                 return r;
481         }
482
483         r = sd_bus_message_append(n, "s", a->unique_name);
484         if (r < 0) {
485                 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
486                 return r;
487         }
488
489         r = bus_message_append_sender(n, "org.freedesktop.DBus");
490         if (r < 0) {
491                 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
492                 return r;
493         }
494
495         r = bus_seal_synthetic_message(b, n);
496         if (r < 0) {
497                 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
498                 return r;
499         }
500
501         r = sd_bus_send(b, n, NULL);
502         if (r < 0) {
503                 log_error("Failed to send NameAcquired message: %s", strerror(-r));
504                 return r;
505         }
506
507         return 1;
508 }
509
510 static int patch_sender(sd_bus *a, sd_bus_message *m) {
511         char **well_known = NULL;
512         sd_bus_creds *c;
513         int r;
514
515         assert(a);
516         assert(m);
517
518         if (!a->is_kernel)
519                 return 0;
520
521         /* We will change the sender of messages from the bus driver
522          * so that they originate from the bus driver. This is a
523          * speciality originating from dbus1, where the bus driver did
524          * not have a unique id, but only the well-known name. */
525
526         c = sd_bus_message_get_creds(m);
527         if (!c)
528                 return 0;
529
530         r = sd_bus_creds_get_well_known_names(c, &well_known);
531         if (r < 0)
532                 return r;
533
534         if (strv_contains(well_known, "org.freedesktop.DBus"))
535                 m->sender = "org.freedesktop.DBus";
536
537         return 0;
538 }
539
540 int main(int argc, char *argv[]) {
541
542         _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
543         sd_id128_t server_id;
544         int r, in_fd, out_fd;
545         bool got_hello = false;
546         bool is_unix;
547         struct ucred ucred = {};
548         _cleanup_free_ char *peersec = NULL;
549
550         log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
551         log_parse_environment();
552         log_open();
553
554         r = parse_argv(argc, argv);
555         if (r <= 0)
556                 goto finish;
557
558         r = sd_listen_fds(0);
559         if (r == 0) {
560                 in_fd = STDIN_FILENO;
561                 out_fd = STDOUT_FILENO;
562         } else if (r == 1) {
563                 in_fd = SD_LISTEN_FDS_START;
564                 out_fd = SD_LISTEN_FDS_START;
565         } else {
566                 log_error("Illegal number of file descriptors passed");
567                 goto finish;
568         }
569
570         is_unix =
571                 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
572                 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
573
574         if (is_unix) {
575                 getpeercred(in_fd, &ucred);
576                 getpeersec(in_fd, &peersec);
577         }
578
579         r = sd_bus_new(&a);
580         if (r < 0) {
581                 log_error("Failed to allocate bus: %s", strerror(-r));
582                 goto finish;
583         }
584
585         r = sd_bus_set_name(a, "sd-proxy");
586         if (r < 0) {
587                 log_error("Failed to set bus name: %s", strerror(-r));
588                 goto finish;
589         }
590
591         r = sd_bus_set_address(a, arg_address);
592         if (r < 0) {
593                 log_error("Failed to set address to connect to: %s", strerror(-r));
594                 goto finish;
595         }
596
597         r = sd_bus_negotiate_fds(a, is_unix);
598         if (r < 0) {
599                 log_error("Failed to set FD negotiation: %s", strerror(-r));
600                 goto finish;
601         }
602
603         if (ucred.pid > 0) {
604                 a->fake_creds.pid = ucred.pid;
605                 a->fake_creds.uid = ucred.uid;
606                 a->fake_creds.gid = ucred.gid;
607                 a->fake_creds_valid = true;
608         }
609
610         if (peersec) {
611                 a->fake_label = peersec;
612                 peersec = NULL;
613         }
614
615         a->manual_peer_interface = true;
616
617         r = sd_bus_start(a);
618         if (r < 0) {
619                 log_error("Failed to start bus client: %s", strerror(-r));
620                 goto finish;
621         }
622
623         r = sd_bus_get_server_id(a, &server_id);
624         if (r < 0) {
625                 log_error("Failed to get server ID: %s", strerror(-r));
626                 goto finish;
627         }
628
629         r = sd_bus_new(&b);
630         if (r < 0) {
631                 log_error("Failed to allocate bus: %s", strerror(-r));
632                 goto finish;
633         }
634
635         r = sd_bus_set_fd(b, in_fd, out_fd);
636         if (r < 0) {
637                 log_error("Failed to set fds: %s", strerror(-r));
638                 goto finish;
639         }
640
641         r = sd_bus_set_server(b, 1, server_id);
642         if (r < 0) {
643                 log_error("Failed to set server mode: %s", strerror(-r));
644                 goto finish;
645         }
646
647         r = sd_bus_negotiate_fds(b, is_unix);
648         if (r < 0) {
649                 log_error("Failed to set FD negotiation: %s", strerror(-r));
650                 goto finish;
651         }
652
653         r = sd_bus_set_anonymous(b, true);
654         if (r < 0) {
655                 log_error("Failed to set anonymous authentication: %s", strerror(-r));
656                 goto finish;
657         }
658
659         b->manual_peer_interface = true;
660
661         r = sd_bus_start(b);
662         if (r < 0) {
663                 log_error("Failed to start bus client: %s", strerror(-r));
664                 goto finish;
665         }
666
667         r = rename_service(a, b);
668         if (r < 0)
669                 log_debug("Failed to rename process: %s", strerror(-r));
670
671         if (a->is_kernel) {
672                 _cleanup_free_ char *match = NULL;
673                 const char *unique;
674
675                 r = sd_bus_get_unique_name(a, &unique);
676                 if (r < 0) {
677                         log_error("Failed to get unique name: %s", strerror(-r));
678                         goto finish;
679                 }
680
681                 match = strjoin("type='signal',"
682                                 "sender='org.freedesktop.DBus',"
683                                 "path='/org/freedesktop/DBus',"
684                                 "interface='org.freedesktop.DBus',"
685                                 "member='NameOwnerChanged',"
686                                 "arg1='",
687                                 unique,
688                                 "'",
689                                 NULL);
690                 if (!match) {
691                         log_oom();
692                         goto finish;
693                 }
694
695                 r = sd_bus_add_match(a, match, NULL, NULL);
696                 if (r < 0) {
697                         log_error("Failed to add match for NameLost: %s", strerror(-r));
698                         goto finish;
699                 }
700
701                 free(match);
702                 match = strjoin("type='signal',"
703                                 "sender='org.freedesktop.DBus',"
704                                 "path='/org/freedesktop/DBus',"
705                                 "interface='org.freedesktop.DBus',"
706                                 "member='NameOwnerChanged',"
707                                 "arg2='",
708                                 unique,
709                                 "'",
710                                 NULL);
711                 if (!match) {
712                         log_oom();
713                         goto finish;
714                 }
715
716                 r = sd_bus_add_match(a, match, NULL, NULL);
717                 if (r < 0) {
718                         log_error("Failed to add match for NameAcquired: %s", strerror(-r));
719                         goto finish;
720                 }
721         }
722
723         for (;;) {
724                 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
725                 int events_a, events_b, fd;
726                 uint64_t timeout_a, timeout_b, t;
727                 struct timespec _ts, *ts;
728                 struct pollfd *pollfd;
729                 int k;
730
731                 if (got_hello) {
732                         r = sd_bus_process(a, &m);
733                         if (r < 0) {
734                                 /* treat 'connection reset by peer' as clean exit condition */
735                                 if (r == -ECONNRESET)
736                                         r = 0;
737                                 else
738                                         log_error("Failed to process bus a: %s", strerror(-r));
739
740                                 goto finish;
741                         }
742
743                         if (m) {
744                                 /* We officially got EOF, let's quit */
745                                 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
746                                         r = 0;
747                                         goto finish;
748                                 }
749
750                                 k = synthesize_name_acquired(a, b, m);
751                                 if (k < 0) {
752                                         r = k;
753                                         log_error("Failed to synthesize message: %s", strerror(-r));
754                                         goto finish;
755                                 }
756
757                                 patch_sender(a, m);
758
759                                 k = sd_bus_send(b, m, NULL);
760                                 if (k < 0) {
761                                         if (k == -ECONNRESET)
762                                                 r = 0;
763                                         else {
764                                                 r = k;
765                                                 log_error("Failed to send message: %s", strerror(-r));
766                                         }
767
768                                         goto finish;
769                                 }
770                         }
771
772                         if (r > 0)
773                                 continue;
774                 }
775
776                 r = sd_bus_process(b, &m);
777                 if (r < 0) {
778                         /* treat 'connection reset by peer' as clean exit condition */
779                         if (r == -ECONNRESET)
780                                 r = 0;
781                         else
782                                 log_error("Failed to process bus b: %s", strerror(-r));
783
784                         goto finish;
785                 }
786
787                 if (m) {
788                         /* We officially got EOF, let's quit */
789                         if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
790                                 r = 0;
791                                 goto finish;
792                         }
793
794                         k = process_hello(a, b, m, &got_hello);
795                         if (k < 0) {
796                                 r = k;
797                                 log_error("Failed to process HELLO: %s", strerror(-r));
798                                 goto finish;
799                         }
800
801                         if (k > 0)
802                                 r = k;
803                         else {
804                                 k = process_policy(a, b, m);
805                                 if (k < 0) {
806                                         r = k;
807                                         log_error("Failed to process policy: %s", strerror(-r));
808                                         goto finish;
809                                 }
810
811                                 k = process_driver(a, b, m);
812                                 if (k < 0) {
813                                         r = k;
814                                         log_error("Failed to process driver calls: %s", strerror(-r));
815                                         goto finish;
816                                 }
817
818                                 if (k > 0)
819                                         r = k;
820                                 else {
821                                         k = sd_bus_send(a, m, NULL);
822                                         if (k < 0) {
823                                                 if (r == -ECONNRESET)
824                                                         r = 0;
825                                                 else {
826                                                         r = k;
827                                                         log_error("Failed to send message: %s", strerror(-r));
828                                                 }
829
830                                                 goto finish;
831                                         }
832                                 }
833                         }
834                 }
835
836                 if (r > 0)
837                         continue;
838
839                 fd = sd_bus_get_fd(a);
840                 if (fd < 0) {
841                         log_error("Failed to get fd: %s", strerror(-r));
842                         goto finish;
843                 }
844
845                 events_a = sd_bus_get_events(a);
846                 if (events_a < 0) {
847                         log_error("Failed to get events mask: %s", strerror(-r));
848                         goto finish;
849                 }
850
851                 r = sd_bus_get_timeout(a, &timeout_a);
852                 if (r < 0) {
853                         log_error("Failed to get timeout: %s", strerror(-r));
854                         goto finish;
855                 }
856
857                 events_b = sd_bus_get_events(b);
858                 if (events_b < 0) {
859                         log_error("Failed to get events mask: %s", strerror(-r));
860                         goto finish;
861                 }
862
863                 r = sd_bus_get_timeout(b, &timeout_b);
864                 if (r < 0) {
865                         log_error("Failed to get timeout: %s", strerror(-r));
866                         goto finish;
867                 }
868
869                 t = timeout_a;
870                 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
871                         t = timeout_b;
872
873                 if (t == (uint64_t) -1)
874                         ts = NULL;
875                 else {
876                         usec_t nw;
877
878                         nw = now(CLOCK_MONOTONIC);
879                         if (t > nw)
880                                 t -= nw;
881                         else
882                                 t = 0;
883
884                         ts = timespec_store(&_ts, t);
885                 }
886
887                 pollfd = (struct pollfd[3]) {
888                         {.fd = fd,     .events = events_a,           },
889                         {.fd = in_fd,  .events = events_b & POLLIN,  },
890                         {.fd = out_fd, .events = events_b & POLLOUT, }
891                 };
892
893                 r = ppoll(pollfd, 3, ts, NULL);
894                 if (r < 0) {
895                         log_error("ppoll() failed: %m");
896                         goto finish;
897                 }
898         }
899
900 finish:
901         sd_bus_flush(a);
902         sd_bus_flush(b);
903
904         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
905 }