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