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