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