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