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