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