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