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