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