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