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