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