chiark / gitweb /
sd-bus: sync kdbus.h (API+ABI break)
[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                         const char *entry_name = NULL;
747                         struct kdbus_item *item;
748                         char *n;
749
750                         KDBUS_ITEM_FOREACH(item, name, items)
751                                 if (item->type == KDBUS_ITEM_NAME)
752                                         entry_name = item->str;
753
754                         if (!streq_ptr(entry_name, arg0))
755                                 continue;
756
757                         if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
758                                 err  = -ENOMEM;
759                                 break;
760                         }
761
762                         r = strv_consume(&owners, n);
763                         if (r < 0) {
764                                 err = r;
765                                 break;
766                         }
767                 }
768
769                 r = ioctl(a->input_fd, KDBUS_CMD_FREE, &cmd.offset);
770                 if (r < 0)
771                         return synthetic_reply_method_errno(m, r, NULL);
772
773                 if (err < 0)
774                         return synthetic_reply_method_errno(m, err, NULL);
775
776                 return synthetic_reply_return_strv(m, owners);
777
778         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
779                 const char *name;
780
781                 r = sd_bus_message_read(m, "s", &name);
782                 if (r < 0)
783                         return synthetic_reply_method_errno(m, r, NULL);
784
785                 if (!service_name_is_valid(name))
786                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
787
788                 if (streq(name, "org.freedesktop.DBus"))
789                         return synthetic_reply_method_return(m, "b", true);
790
791                 r = sd_bus_get_owner(a, name, 0, NULL);
792                 if (r < 0 && r != -ESRCH && r != -ENXIO)
793                         return synthetic_reply_method_errno(m, r, NULL);
794
795                 return synthetic_reply_method_return(m, "b", r >= 0);
796
797         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
798                 const char *name;
799
800                 r = sd_bus_message_read(m, "s", &name);
801                 if (r < 0)
802                         return synthetic_reply_method_errno(m, r, NULL);
803
804                 if (!service_name_is_valid(name))
805                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
806
807                 r = sd_bus_release_name(a, name);
808                 if (r < 0) {
809                         if (r == -ESRCH)
810                                 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
811                         if (r == -EADDRINUSE)
812                                 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
813
814                         return synthetic_reply_method_errno(m, r, NULL);
815                 }
816
817                 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
818
819         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
820                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
821
822                 r = sd_bus_error_setf(&error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
823
824                 return synthetic_reply_method_errno(m, r, &error);
825
826         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
827                 const char *name;
828                 uint32_t flags;
829
830                 r = sd_bus_message_read(m, "su", &name, &flags);
831                 if (r < 0)
832                         return synthetic_reply_method_errno(m, r, NULL);
833
834                 if (!service_name_is_valid(name))
835                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
836                 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
837                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
838
839                 r = sd_bus_request_name(a, name, flags);
840                 if (r < 0) {
841                         if (r == -EEXIST)
842                                 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
843                         if (r == -EALREADY)
844                                 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
845                         return synthetic_reply_method_errno(m, r, NULL);
846                 }
847
848                 if (r == 0)
849                         return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
850
851                 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
852
853         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
854                 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
855                 const char *name;
856                 uint32_t flags;
857
858                 r = sd_bus_message_read(m, "su", &name, &flags);
859                 if (r < 0)
860                         return synthetic_reply_method_errno(m, r, NULL);
861
862                 if (!service_name_is_valid(name))
863                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
864                 if (flags != 0)
865                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
866
867                 r = sd_bus_get_owner(a, name, 0, NULL);
868                 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
869                         return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
870                 if (r != -ESRCH)
871                         return synthetic_reply_method_errno(m, r, NULL);
872
873                 r = sd_bus_message_new_method_call(
874                                 a,
875                                 &msg,
876                                 name,
877                                 "/",
878                                 "org.freedesktop.DBus.Peer",
879                                 "Ping");
880                 if (r < 0)
881                         return synthetic_reply_method_errno(m, r, NULL);
882
883                 r = sd_bus_send(a, msg, NULL);
884                 if (r < 0)
885                         return synthetic_reply_method_errno(m, r, NULL);
886
887                 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
888
889         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
890                 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
891                 _cleanup_strv_free_ char **args = NULL;
892
893                 if (!peer_is_privileged(a, m))
894                         return synthetic_reply_method_errno(m, -EPERM, NULL);
895
896                 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
897                 if (r < 0)
898                         return synthetic_reply_method_errno(m, r, NULL);
899
900                 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
901                         _cleanup_free_ char *s = NULL;
902                         const char *key;
903                         const char *value;
904
905                         r = sd_bus_message_read(m, "ss", &key, &value);
906                         if (r < 0)
907                                 return synthetic_reply_method_errno(m, r, NULL);
908
909                         s = strjoin(key, "=", value, NULL);
910                         if (!s)
911                                 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
912
913                         r  = strv_extend(&args, s);
914                         if (r < 0)
915                                 return synthetic_reply_method_errno(m, r, NULL);
916
917                         r = sd_bus_message_exit_container(m);
918                         if (r < 0)
919                                 return synthetic_reply_method_errno(m, r, NULL);
920                 }
921
922                 r = sd_bus_message_exit_container(m);
923                 if (r < 0)
924                         return synthetic_reply_method_errno(m, r, NULL);
925
926                 if (!args)
927                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
928
929                 r = sd_bus_message_new_method_call(
930                                 a,
931                                 &msg,
932                                 "org.freedesktop.systemd1",
933                                 "/org/freedesktop/systemd1",
934                                 "org.freedesktop.systemd1.Manager",
935                                 "SetEnvironment");
936                 if (r < 0)
937                         return synthetic_reply_method_errno(m, r, NULL);
938
939                 r = sd_bus_message_append_strv(msg, args);
940                 if (r < 0)
941                         return synthetic_reply_method_errno(m, r, NULL);
942
943                 r = sd_bus_call(a, msg, 0, NULL, NULL);
944                 if (r < 0)
945                         return synthetic_reply_method_errno(m, r, NULL);
946
947                return synthetic_reply_method_return(m, NULL);
948
949         } else {
950                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
951
952                 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
953
954                 return synthetic_reply_method_errno(m, r, &error);
955         }
956 }
957
958 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
959         _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
960         bool is_hello;
961         int r;
962
963         assert(a);
964         assert(b);
965         assert(m);
966         assert(got_hello);
967
968         /* As reaction to hello we need to respond with two messages:
969          * the callback reply and the NameAcquired for the unique
970          * name, since hello is otherwise obsolete on kdbus. */
971
972         is_hello =
973                 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
974                 streq_ptr(m->destination, "org.freedesktop.DBus");
975
976         if (!is_hello) {
977
978                 if (*got_hello)
979                         return 0;
980
981                 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
982                 return -EIO;
983         }
984
985         if (*got_hello) {
986                 log_error("Got duplicate hello, aborting.");
987                 return -EIO;
988         }
989
990         *got_hello = true;
991
992         if (!a->is_kernel)
993                 return 0;
994
995         r = sd_bus_message_new_method_return(m, &n);
996         if (r < 0) {
997                 log_error("Failed to generate HELLO reply: %s", strerror(-r));
998                 return r;
999         }
1000
1001         r = sd_bus_message_append(n, "s", a->unique_name);
1002         if (r < 0) {
1003                 log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
1004                 return r;
1005         }
1006
1007         r = bus_message_append_sender(n, "org.freedesktop.DBus");
1008         if (r < 0) {
1009                 log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
1010                 return r;
1011         }
1012
1013         r = bus_seal_synthetic_message(b, n);
1014         if (r < 0) {
1015                 log_error("Failed to seal HELLO reply: %s", strerror(-r));
1016                 return r;
1017         }
1018
1019         r = sd_bus_send(b, n, NULL);
1020         if (r < 0) {
1021                 log_error("Failed to send HELLO reply: %s", strerror(-r));
1022                 return r;
1023         }
1024
1025         n = sd_bus_message_unref(n);
1026         r = sd_bus_message_new_signal(
1027                         b,
1028                         &n,
1029                         "/org/freedesktop/DBus",
1030                         "org.freedesktop.DBus",
1031                         "NameAcquired");
1032         if (r < 0) {
1033                 log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
1034                 return r;
1035         }
1036
1037         r = sd_bus_message_append(n, "s", a->unique_name);
1038         if (r < 0) {
1039                 log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
1040                 return r;
1041         }
1042
1043         r = bus_message_append_sender(n, "org.freedesktop.DBus");
1044         if (r < 0) {
1045                 log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
1046                 return r;
1047         }
1048
1049         r = bus_seal_synthetic_message(b, n);
1050         if (r < 0) {
1051                 log_error("Failed to seal NameAcquired message: %s", strerror(-r));
1052                 return r;
1053         }
1054
1055         r = sd_bus_send(b, n, NULL);
1056         if (r < 0) {
1057                 log_error("Failed to send NameAcquired message: %s", strerror(-r));
1058                 return r;
1059         }
1060
1061         return 1;
1062 }
1063
1064 static int patch_sender(sd_bus *a, sd_bus_message *m) {
1065         char **well_known = NULL;
1066         sd_bus_creds *c;
1067         int r;
1068
1069         assert(a);
1070         assert(m);
1071
1072         if (!a->is_kernel)
1073                 return 0;
1074
1075         /* We will change the sender of messages from the bus driver
1076          * so that they originate from the bus driver. This is a
1077          * speciality originating from dbus1, where the bus driver did
1078          * not have a unique id, but only the well-known name. */
1079
1080         c = sd_bus_message_get_creds(m);
1081         if (!c)
1082                 return 0;
1083
1084         r = sd_bus_creds_get_well_known_names(c, &well_known);
1085         if (r < 0)
1086                 return r;
1087
1088         if (strv_contains(well_known, "org.freedesktop.DBus"))
1089                 m->sender = "org.freedesktop.DBus";
1090
1091         return 0;
1092 }
1093
1094 int main(int argc, char *argv[]) {
1095
1096         _cleanup_bus_close_unref_ sd_bus *a = NULL, *b = NULL;
1097         sd_id128_t server_id;
1098         int r, in_fd, out_fd;
1099         bool got_hello = false;
1100         bool is_unix;
1101         struct ucred ucred = {};
1102         _cleanup_free_ char *peersec = NULL;
1103         Policy policy = {};
1104
1105         log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
1106         log_parse_environment();
1107         log_open();
1108
1109         r = parse_argv(argc, argv);
1110         if (r <= 0)
1111                 goto finish;
1112
1113         r = policy_load(&policy, arg_configuration);
1114         if (r < 0) {
1115                 log_error("Failed to load policy: %s", strerror(-r));
1116                 goto finish;
1117         }
1118
1119         /* policy_dump(&policy); */
1120
1121         r = sd_listen_fds(0);
1122         if (r == 0) {
1123                 in_fd = STDIN_FILENO;
1124                 out_fd = STDOUT_FILENO;
1125         } else if (r == 1) {
1126                 in_fd = SD_LISTEN_FDS_START;
1127                 out_fd = SD_LISTEN_FDS_START;
1128         } else {
1129                 log_error("Illegal number of file descriptors passed");
1130                 goto finish;
1131         }
1132
1133         is_unix =
1134                 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
1135                 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
1136
1137         if (is_unix) {
1138                 getpeercred(in_fd, &ucred);
1139                 getpeersec(in_fd, &peersec);
1140         }
1141
1142         if (arg_drop_privileges) {
1143                 const char *user = "systemd-bus-proxy";
1144                 uid_t uid;
1145                 gid_t gid;
1146
1147                 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
1148                 if (r < 0) {
1149                         log_error("Cannot resolve user name %s: %s", user, strerror(-r));
1150                         goto finish;
1151                 }
1152
1153                 r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
1154                 if (r < 0)
1155                         goto finish;
1156         }
1157
1158         r = sd_bus_new(&a);
1159         if (r < 0) {
1160                 log_error("Failed to allocate bus: %s", strerror(-r));
1161                 goto finish;
1162         }
1163
1164         r = sd_bus_set_name(a, "sd-proxy");
1165         if (r < 0) {
1166                 log_error("Failed to set bus name: %s", strerror(-r));
1167                 goto finish;
1168         }
1169
1170         r = sd_bus_set_address(a, arg_address);
1171         if (r < 0) {
1172                 log_error("Failed to set address to connect to: %s", strerror(-r));
1173                 goto finish;
1174         }
1175
1176         r = sd_bus_negotiate_fds(a, is_unix);
1177         if (r < 0) {
1178                 log_error("Failed to set FD negotiation: %s", strerror(-r));
1179                 goto finish;
1180         }
1181
1182         if (ucred.pid > 0) {
1183                 a->fake_creds.pid = ucred.pid;
1184                 a->fake_creds.uid = ucred.uid;
1185                 a->fake_creds.gid = ucred.gid;
1186                 a->fake_creds_valid = true;
1187         }
1188
1189         if (peersec) {
1190                 a->fake_label = peersec;
1191                 peersec = NULL;
1192         }
1193
1194         a->manual_peer_interface = true;
1195
1196         r = sd_bus_start(a);
1197         if (r < 0) {
1198                 log_error("Failed to start bus client: %s", strerror(-r));
1199                 goto finish;
1200         }
1201
1202         r = sd_bus_get_server_id(a, &server_id);
1203         if (r < 0) {
1204                 log_error("Failed to get server ID: %s", strerror(-r));
1205                 goto finish;
1206         }
1207
1208         r = sd_bus_new(&b);
1209         if (r < 0) {
1210                 log_error("Failed to allocate bus: %s", strerror(-r));
1211                 goto finish;
1212         }
1213
1214         r = sd_bus_set_fd(b, in_fd, out_fd);
1215         if (r < 0) {
1216                 log_error("Failed to set fds: %s", strerror(-r));
1217                 goto finish;
1218         }
1219
1220         r = sd_bus_set_server(b, 1, server_id);
1221         if (r < 0) {
1222                 log_error("Failed to set server mode: %s", strerror(-r));
1223                 goto finish;
1224         }
1225
1226         r = sd_bus_negotiate_fds(b, is_unix);
1227         if (r < 0) {
1228                 log_error("Failed to set FD negotiation: %s", strerror(-r));
1229                 goto finish;
1230         }
1231
1232         r = sd_bus_set_anonymous(b, true);
1233         if (r < 0) {
1234                 log_error("Failed to set anonymous authentication: %s", strerror(-r));
1235                 goto finish;
1236         }
1237
1238         b->manual_peer_interface = true;
1239
1240         r = sd_bus_start(b);
1241         if (r < 0) {
1242                 log_error("Failed to start bus client: %s", strerror(-r));
1243                 goto finish;
1244         }
1245
1246         r = rename_service(a, b);
1247         if (r < 0)
1248                 log_debug("Failed to rename process: %s", strerror(-r));
1249
1250         if (a->is_kernel) {
1251                 _cleanup_free_ char *match = NULL;
1252                 const char *unique;
1253
1254                 r = sd_bus_get_unique_name(a, &unique);
1255                 if (r < 0) {
1256                         log_error("Failed to get unique name: %s", strerror(-r));
1257                         goto finish;
1258                 }
1259
1260                 match = strjoin("type='signal',"
1261                                 "sender='org.freedesktop.DBus',"
1262                                 "path='/org/freedesktop/DBus',"
1263                                 "interface='org.freedesktop.DBus',"
1264                                 "member='NameOwnerChanged',"
1265                                 "arg1='",
1266                                 unique,
1267                                 "'",
1268                                 NULL);
1269                 if (!match) {
1270                         log_oom();
1271                         goto finish;
1272                 }
1273
1274                 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1275                 if (r < 0) {
1276                         log_error("Failed to add match for NameLost: %s", strerror(-r));
1277                         goto finish;
1278                 }
1279
1280                 free(match);
1281                 match = strjoin("type='signal',"
1282                                 "sender='org.freedesktop.DBus',"
1283                                 "path='/org/freedesktop/DBus',"
1284                                 "interface='org.freedesktop.DBus',"
1285                                 "member='NameOwnerChanged',"
1286                                 "arg2='",
1287                                 unique,
1288                                 "'",
1289                                 NULL);
1290                 if (!match) {
1291                         log_oom();
1292                         goto finish;
1293                 }
1294
1295                 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1296                 if (r < 0) {
1297                         log_error("Failed to add match for NameAcquired: %s", strerror(-r));
1298                         goto finish;
1299                 }
1300         }
1301
1302         for (;;) {
1303                 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1304                 int events_a, events_b, fd;
1305                 uint64_t timeout_a, timeout_b, t;
1306                 struct timespec _ts, *ts;
1307                 struct pollfd *pollfd;
1308                 int k;
1309
1310                 if (got_hello) {
1311                         r = sd_bus_process(a, &m);
1312                         if (r < 0) {
1313                                 /* treat 'connection reset by peer' as clean exit condition */
1314                                 if (r == -ECONNRESET)
1315                                         r = 0;
1316                                 else
1317                                         log_error("Failed to process bus a: %s", strerror(-r));
1318
1319                                 goto finish;
1320                         }
1321
1322                         if (m) {
1323                                 /* We officially got EOF, let's quit */
1324                                 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1325                                         r = 0;
1326                                         goto finish;
1327                                 }
1328
1329                                 k = synthesize_name_acquired(a, b, m);
1330                                 if (k < 0) {
1331                                         r = k;
1332                                         log_error("Failed to synthesize message: %s", strerror(-r));
1333                                         goto finish;
1334                                 }
1335
1336                                 patch_sender(a, m);
1337
1338                                 k = sd_bus_send(b, m, NULL);
1339                                 if (k < 0) {
1340                                         if (k == -ECONNRESET)
1341                                                 r = 0;
1342                                         else {
1343                                                 r = k;
1344                                                 log_error("Failed to send message: %s", strerror(-r));
1345                                         }
1346
1347                                         goto finish;
1348                                 }
1349                         }
1350
1351                         if (r > 0)
1352                                 continue;
1353                 }
1354
1355                 r = sd_bus_process(b, &m);
1356                 if (r < 0) {
1357                         /* treat 'connection reset by peer' as clean exit condition */
1358                         if (r == -ECONNRESET)
1359                                 r = 0;
1360                         else
1361                                 log_error("Failed to process bus b: %s", strerror(-r));
1362
1363                         goto finish;
1364                 }
1365
1366                 if (m) {
1367                         /* We officially got EOF, let's quit */
1368                         if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1369                                 r = 0;
1370                                 goto finish;
1371                         }
1372
1373                         k = process_hello(a, b, m, &got_hello);
1374                         if (k < 0) {
1375                                 r = k;
1376                                 log_error("Failed to process HELLO: %s", strerror(-r));
1377                                 goto finish;
1378                         }
1379
1380                         if (k > 0)
1381                                 r = k;
1382                         else {
1383                                 k = process_policy(a, b, m);
1384                                 if (k < 0) {
1385                                         r = k;
1386                                         log_error("Failed to process policy: %s", strerror(-r));
1387                                         goto finish;
1388                                 }
1389
1390                                 k = process_driver(a, b, m);
1391                                 if (k < 0) {
1392                                         r = k;
1393                                         log_error("Failed to process driver calls: %s", strerror(-r));
1394                                         goto finish;
1395                                 }
1396
1397                                 if (k > 0)
1398                                         r = k;
1399                                 else {
1400                                         k = sd_bus_send(a, m, NULL);
1401                                         if (k < 0) {
1402                                                 if (k == -ECONNRESET)
1403                                                         r = 0;
1404                                                 else {
1405                                                         r = k;
1406                                                         log_error("Failed to send message: %s", strerror(-r));
1407                                                 }
1408
1409                                                 goto finish;
1410                                         }
1411                                 }
1412                         }
1413                 }
1414
1415                 if (r > 0)
1416                         continue;
1417
1418                 fd = sd_bus_get_fd(a);
1419                 if (fd < 0) {
1420                         log_error("Failed to get fd: %s", strerror(-r));
1421                         goto finish;
1422                 }
1423
1424                 events_a = sd_bus_get_events(a);
1425                 if (events_a < 0) {
1426                         log_error("Failed to get events mask: %s", strerror(-r));
1427                         goto finish;
1428                 }
1429
1430                 r = sd_bus_get_timeout(a, &timeout_a);
1431                 if (r < 0) {
1432                         log_error("Failed to get timeout: %s", strerror(-r));
1433                         goto finish;
1434                 }
1435
1436                 events_b = sd_bus_get_events(b);
1437                 if (events_b < 0) {
1438                         log_error("Failed to get events mask: %s", strerror(-r));
1439                         goto finish;
1440                 }
1441
1442                 r = sd_bus_get_timeout(b, &timeout_b);
1443                 if (r < 0) {
1444                         log_error("Failed to get timeout: %s", strerror(-r));
1445                         goto finish;
1446                 }
1447
1448                 t = timeout_a;
1449                 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
1450                         t = timeout_b;
1451
1452                 if (t == (uint64_t) -1)
1453                         ts = NULL;
1454                 else {
1455                         usec_t nw;
1456
1457                         nw = now(CLOCK_MONOTONIC);
1458                         if (t > nw)
1459                                 t -= nw;
1460                         else
1461                                 t = 0;
1462
1463                         ts = timespec_store(&_ts, t);
1464                 }
1465
1466                 pollfd = (struct pollfd[3]) {
1467                         {.fd = fd,     .events = events_a,           },
1468                         {.fd = in_fd,  .events = events_b & POLLIN,  },
1469                         {.fd = out_fd, .events = events_b & POLLOUT, }
1470                 };
1471
1472                 r = ppoll(pollfd, 3, ts, NULL);
1473                 if (r < 0) {
1474                         log_error("ppoll() failed: %m");
1475                         goto finish;
1476                 }
1477         }
1478
1479 finish:
1480         sd_notify(false,
1481                   "STOPPING=1\n"
1482                   "STATUS=Shutting down.");
1483
1484         policy_free(&policy);
1485         strv_free(arg_configuration);
1486         free(arg_address);
1487
1488         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1489 }