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