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