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