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