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