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