chiark / gitweb /
bus-proxy: remove unused variable
[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                 const char *match;
375
376                 r = sd_bus_message_read(m, "s", &match);
377                 if (r < 0)
378                         return synthetic_reply_method_errno(m, r, NULL);
379
380                 r = sd_bus_add_match(a, match, NULL, NULL);
381                 if (r < 0)
382                         return synthetic_reply_method_errno(m, r, NULL);
383
384                 return synthetic_reply_method_return(m, NULL);
385
386         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
387                 const char *match;
388
389                 r = sd_bus_message_read(m, "s", &match);
390                 if (r < 0)
391                         return synthetic_reply_method_errno(m, r, NULL);
392
393                 r = sd_bus_remove_match(a, match, NULL, NULL);
394                 if (r < 0)
395                         return synthetic_reply_method_errno(m, r, NULL);
396
397                 return synthetic_reply_method_return(m, NULL);
398         }
399
400         return 0;
401 }
402
403 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
404         _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
405         bool is_hello;
406         int r;
407
408         assert(a);
409         assert(b);
410         assert(m);
411         assert(got_hello);
412
413         /* As reaction to hello we need to respond with two messages:
414          * the callback reply and the NameAcquired for the unique
415          * name, since hello is otherwise obsolete on kdbus. */
416
417         is_hello =
418                 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
419                 streq_ptr(m->destination, "org.freedesktop.DBus");
420
421         if (!is_hello) {
422
423                 if (*got_hello)
424                         return 0;
425
426                 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
427                 return -EIO;
428         }
429
430         if (*got_hello) {
431                 log_error("Got duplicate hello, aborting.");
432                 return -EIO;
433         }
434
435         *got_hello = true;
436
437         if (!a->is_kernel)
438                 return 0;
439
440         r = sd_bus_message_new_method_return(m, &n);
441         if (r < 0) {
442                 log_error("Failed to generate HELLO reply: %s", strerror(-r));
443                 return r;
444         }
445
446         r = sd_bus_message_append(n, "s", a->unique_name);
447         if (r < 0) {
448                 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
449                 return r;
450         }
451
452         r = bus_message_append_sender(n, "org.freedesktop.DBus");
453         if (r < 0) {
454                 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
455                 return r;
456         }
457
458         r = bus_seal_synthetic_message(b, n);
459         if (r < 0) {
460                 log_error("Failed to seal HELLO reply: %s", strerror(-r));
461                 return r;
462         }
463
464         r = sd_bus_send(b, n, NULL);
465         if (r < 0) {
466                 log_error("Failed to send HELLO reply: %s", strerror(-r));
467                 return r;
468         }
469
470         n = sd_bus_message_unref(n);
471         r = sd_bus_message_new_signal(
472                         b,
473                         &n,
474                         "/org/freedesktop/DBus",
475                         "org.freedesktop.DBus",
476                         "NameAcquired");
477         if (r < 0) {
478                 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
479                 return r;
480         }
481
482         r = sd_bus_message_append(n, "s", a->unique_name);
483         if (r < 0) {
484                 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
485                 return r;
486         }
487
488         r = bus_message_append_sender(n, "org.freedesktop.DBus");
489         if (r < 0) {
490                 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
491                 return r;
492         }
493
494         r = bus_seal_synthetic_message(b, n);
495         if (r < 0) {
496                 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
497                 return r;
498         }
499
500         r = sd_bus_send(b, n, NULL);
501         if (r < 0) {
502                 log_error("Failed to send NameAcquired message: %s", strerror(-r));
503                 return r;
504         }
505
506         return 1;
507 }
508
509 static int patch_sender(sd_bus *a, sd_bus_message *m) {
510         char **well_known = NULL;
511         sd_bus_creds *c;
512         int r;
513
514         assert(a);
515         assert(m);
516
517         if (!a->is_kernel)
518                 return 0;
519
520         /* We will change the sender of messages from the bus driver
521          * so that they originate from the bus driver. This is a
522          * speciality originating from dbus1, where the bus driver did
523          * not have a unique id, but only the well-known name. */
524
525         c = sd_bus_message_get_creds(m);
526         if (!c)
527                 return 0;
528
529         r = sd_bus_creds_get_well_known_names(c, &well_known);
530         if (r < 0)
531                 return r;
532
533         if (strv_contains(well_known, "org.freedesktop.DBus"))
534                 m->sender = "org.freedesktop.DBus";
535
536         return 0;
537 }
538
539 int main(int argc, char *argv[]) {
540
541         _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
542         sd_id128_t server_id;
543         int r, in_fd, out_fd;
544         bool got_hello = false;
545         bool is_unix;
546         struct ucred ucred = {};
547         _cleanup_free_ char *peersec = NULL;
548
549         log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
550         log_parse_environment();
551         log_open();
552
553         r = parse_argv(argc, argv);
554         if (r <= 0)
555                 goto finish;
556
557         r = sd_listen_fds(0);
558         if (r == 0) {
559                 in_fd = STDIN_FILENO;
560                 out_fd = STDOUT_FILENO;
561         } else if (r == 1) {
562                 in_fd = SD_LISTEN_FDS_START;
563                 out_fd = SD_LISTEN_FDS_START;
564         } else {
565                 log_error("Illegal number of file descriptors passed");
566                 goto finish;
567         }
568
569         is_unix =
570                 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
571                 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
572
573         if (is_unix) {
574                 getpeercred(in_fd, &ucred);
575                 getpeersec(in_fd, &peersec);
576         }
577
578         r = sd_bus_new(&a);
579         if (r < 0) {
580                 log_error("Failed to allocate bus: %s", strerror(-r));
581                 goto finish;
582         }
583
584         r = sd_bus_set_name(a, "sd-proxy");
585         if (r < 0) {
586                 log_error("Failed to set bus name: %s", strerror(-r));
587                 goto finish;
588         }
589
590         r = sd_bus_set_address(a, arg_address);
591         if (r < 0) {
592                 log_error("Failed to set address to connect to: %s", strerror(-r));
593                 goto finish;
594         }
595
596         r = sd_bus_negotiate_fds(a, is_unix);
597         if (r < 0) {
598                 log_error("Failed to set FD negotiation: %s", strerror(-r));
599                 goto finish;
600         }
601
602         if (ucred.pid > 0) {
603                 a->fake_creds.pid = ucred.pid;
604                 a->fake_creds.uid = ucred.uid;
605                 a->fake_creds.gid = ucred.gid;
606                 a->fake_creds_valid = true;
607         }
608
609         if (peersec) {
610                 a->fake_label = peersec;
611                 peersec = NULL;
612         }
613
614         a->manual_peer_interface = true;
615
616         r = sd_bus_start(a);
617         if (r < 0) {
618                 log_error("Failed to start bus client: %s", strerror(-r));
619                 goto finish;
620         }
621
622         r = sd_bus_get_server_id(a, &server_id);
623         if (r < 0) {
624                 log_error("Failed to get server ID: %s", strerror(-r));
625                 goto finish;
626         }
627
628         r = sd_bus_new(&b);
629         if (r < 0) {
630                 log_error("Failed to allocate bus: %s", strerror(-r));
631                 goto finish;
632         }
633
634         r = sd_bus_set_fd(b, in_fd, out_fd);
635         if (r < 0) {
636                 log_error("Failed to set fds: %s", strerror(-r));
637                 goto finish;
638         }
639
640         r = sd_bus_set_server(b, 1, server_id);
641         if (r < 0) {
642                 log_error("Failed to set server mode: %s", strerror(-r));
643                 goto finish;
644         }
645
646         r = sd_bus_negotiate_fds(b, is_unix);
647         if (r < 0) {
648                 log_error("Failed to set FD negotiation: %s", strerror(-r));
649                 goto finish;
650         }
651
652         r = sd_bus_set_anonymous(b, true);
653         if (r < 0) {
654                 log_error("Failed to set anonymous authentication: %s", strerror(-r));
655                 goto finish;
656         }
657
658         b->manual_peer_interface = true;
659
660         r = sd_bus_start(b);
661         if (r < 0) {
662                 log_error("Failed to start bus client: %s", strerror(-r));
663                 goto finish;
664         }
665
666         r = rename_service(a, b);
667         if (r < 0)
668                 log_debug("Failed to rename process: %s", strerror(-r));
669
670         if (a->is_kernel) {
671                 _cleanup_free_ char *match = NULL;
672                 const char *unique;
673
674                 r = sd_bus_get_unique_name(a, &unique);
675                 if (r < 0) {
676                         log_error("Failed to get unique name: %s", strerror(-r));
677                         goto finish;
678                 }
679
680                 match = strjoin("type='signal',"
681                                 "sender='org.freedesktop.DBus',"
682                                 "path='/org/freedesktop/DBus',"
683                                 "interface='org.freedesktop.DBus',"
684                                 "member='NameOwnerChanged',"
685                                 "arg1='",
686                                 unique,
687                                 "'",
688                                 NULL);
689                 if (!match) {
690                         log_oom();
691                         goto finish;
692                 }
693
694                 r = sd_bus_add_match(a, match, NULL, NULL);
695                 if (r < 0) {
696                         log_error("Failed to add match for NameLost: %s", strerror(-r));
697                         goto finish;
698                 }
699
700                 free(match);
701                 match = strjoin("type='signal',"
702                                 "sender='org.freedesktop.DBus',"
703                                 "path='/org/freedesktop/DBus',"
704                                 "interface='org.freedesktop.DBus',"
705                                 "member='NameOwnerChanged',"
706                                 "arg2='",
707                                 unique,
708                                 "'",
709                                 NULL);
710                 if (!match) {
711                         log_oom();
712                         goto finish;
713                 }
714
715                 r = sd_bus_add_match(a, match, NULL, NULL);
716                 if (r < 0) {
717                         log_error("Failed to add match for NameAcquired: %s", strerror(-r));
718                         goto finish;
719                 }
720         }
721
722         for (;;) {
723                 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
724                 int events_a, events_b, fd;
725                 uint64_t timeout_a, timeout_b, t;
726                 struct timespec _ts, *ts;
727                 struct pollfd *pollfd;
728                 int k;
729
730                 if (got_hello) {
731                         r = sd_bus_process(a, &m);
732                         if (r < 0) {
733                                 /* treat 'connection reset by peer' as clean exit condition */
734                                 if (r == -ECONNRESET)
735                                         r = 0;
736                                 else
737                                         log_error("Failed to process bus a: %s", strerror(-r));
738
739                                 goto finish;
740                         }
741
742                         if (m) {
743                                 /* We officially got EOF, let's quit */
744                                 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
745                                         r = 0;
746                                         goto finish;
747                                 }
748
749                                 k = synthesize_name_acquired(a, b, m);
750                                 if (k < 0) {
751                                         r = k;
752                                         log_error("Failed to synthesize message: %s", strerror(-r));
753                                         goto finish;
754                                 }
755
756                                 patch_sender(a, m);
757
758                                 k = sd_bus_send(b, m, NULL);
759                                 if (k < 0) {
760                                         if (k == -ECONNRESET)
761                                                 r = 0;
762                                         else {
763                                                 r = k;
764                                                 log_error("Failed to send message: %s", strerror(-r));
765                                         }
766
767                                         goto finish;
768                                 }
769                         }
770
771                         if (r > 0)
772                                 continue;
773                 }
774
775                 r = sd_bus_process(b, &m);
776                 if (r < 0) {
777                         /* treat 'connection reset by peer' as clean exit condition */
778                         if (r == -ECONNRESET)
779                                 r = 0;
780                         else
781                                 log_error("Failed to process bus b: %s", strerror(-r));
782
783                         goto finish;
784                 }
785
786                 if (m) {
787                         /* We officially got EOF, let's quit */
788                         if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
789                                 r = 0;
790                                 goto finish;
791                         }
792
793                         k = process_hello(a, b, m, &got_hello);
794                         if (k < 0) {
795                                 r = k;
796                                 log_error("Failed to process HELLO: %s", strerror(-r));
797                                 goto finish;
798                         }
799
800                         if (k > 0)
801                                 r = k;
802                         else {
803                                 k = process_policy(a, b, m);
804                                 if (k < 0) {
805                                         r = k;
806                                         log_error("Failed to process policy: %s", strerror(-r));
807                                         goto finish;
808                                 }
809
810                                 k = process_driver(a, b, m);
811                                 if (k < 0) {
812                                         r = k;
813                                         log_error("Failed to process driver calls: %s", strerror(-r));
814                                         goto finish;
815                                 }
816
817                                 if (k > 0)
818                                         r = k;
819                                 else {
820                                         k = sd_bus_send(a, m, NULL);
821                                         if (k < 0) {
822                                                 if (r == -ECONNRESET)
823                                                         r = 0;
824                                                 else {
825                                                         r = k;
826                                                         log_error("Failed to send message: %s", strerror(-r));
827                                                 }
828
829                                                 goto finish;
830                                         }
831                                 }
832                         }
833                 }
834
835                 if (r > 0)
836                         continue;
837
838                 fd = sd_bus_get_fd(a);
839                 if (fd < 0) {
840                         log_error("Failed to get fd: %s", strerror(-r));
841                         goto finish;
842                 }
843
844                 events_a = sd_bus_get_events(a);
845                 if (events_a < 0) {
846                         log_error("Failed to get events mask: %s", strerror(-r));
847                         goto finish;
848                 }
849
850                 r = sd_bus_get_timeout(a, &timeout_a);
851                 if (r < 0) {
852                         log_error("Failed to get timeout: %s", strerror(-r));
853                         goto finish;
854                 }
855
856                 events_b = sd_bus_get_events(b);
857                 if (events_b < 0) {
858                         log_error("Failed to get events mask: %s", strerror(-r));
859                         goto finish;
860                 }
861
862                 r = sd_bus_get_timeout(b, &timeout_b);
863                 if (r < 0) {
864                         log_error("Failed to get timeout: %s", strerror(-r));
865                         goto finish;
866                 }
867
868                 t = timeout_a;
869                 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
870                         t = timeout_b;
871
872                 if (t == (uint64_t) -1)
873                         ts = NULL;
874                 else {
875                         usec_t nw;
876
877                         nw = now(CLOCK_MONOTONIC);
878                         if (t > nw)
879                                 t -= nw;
880                         else
881                                 t = 0;
882
883                         ts = timespec_store(&_ts, t);
884                 }
885
886                 pollfd = (struct pollfd[3]) {
887                         {.fd = fd,     .events = events_a,           },
888                         {.fd = in_fd,  .events = events_b & POLLIN,  },
889                         {.fd = out_fd, .events = events_b & POLLOUT, }
890                 };
891
892                 r = ppoll(pollfd, 3, ts, NULL);
893                 if (r < 0) {
894                         log_error("ppoll() failed: %m");
895                         goto finish;
896                 }
897         }
898
899 finish:
900         sd_bus_flush(a);
901         sd_bus_flush(b);
902
903         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
904 }