]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/bus-proxyd/bus-proxyd.c
Unify parse_argv style
[thirdparty/systemd.git] / src / bus-proxyd / bus-proxyd.c
CommitLineData
a8f11321
LP
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
dc780ecf
KS
7 Copyright 2013 Daniel Mack
8 Copyright 2014 Kay Sievers
a8f11321
LP
9
10 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
a8f11321
LP
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
5430f7f2 18 Lesser General Public License for more details.
a8f11321 19
5430f7f2 20 You should have received a copy of the GNU Lesser General Public License
a8f11321
LP
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>
d51539b1 31#include <sys/poll.h>
a8f11321 32#include <stddef.h>
71008e18 33#include <getopt.h>
a8f11321
LP
34
35#include "log.h"
36#include "util.h"
37#include "socket-util.h"
d51539b1
LP
38#include "sd-daemon.h"
39#include "sd-bus.h"
40#include "bus-internal.h"
41#include "bus-message.h"
40ca29a1 42#include "bus-util.h"
19befb2d 43#include "bus-internal.h"
71008e18 44#include "build.h"
0721804f 45#include "strv.h"
ab9001a1 46#include "def.h"
6a010ac9 47#include "capability.h"
bcf3295d 48#include "bus-policy.h"
71008e18 49
7f0d207d 50static char *arg_address = NULL;
0721804f 51static char *arg_command_line_buffer = NULL;
6a010ac9 52static bool arg_drop_privileges = false;
2e2b3608 53static char **arg_configuration = NULL;
0721804f 54
71008e18
DM
55static int help(void) {
56
57 printf("%s [OPTIONS...]\n\n"
ba768916 58 "Connect STDIO or a socket to a given bus address.\n\n"
2e2b3608
LP
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"
7f0d207d 63 " --machine=MACHINE Connect to specified machine\n"
2e2b3608 64 " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
7f0d207d 65 " (default: " DEFAULT_SYSTEM_BUS_PATH ")\n",
ba768916 66 program_invocation_short_name);
71008e18
DM
67
68 return 0;
69}
70
71static int parse_argv(int argc, char *argv[]) {
72
73 enum {
74 ARG_VERSION = 0x100,
ba768916 75 ARG_ADDRESS,
6a010ac9 76 ARG_DROP_PRIVILEGES,
2e2b3608 77 ARG_CONFIGURATION,
7f0d207d 78 ARG_MACHINE,
71008e18
DM
79 };
80
81 static const struct option options[] = {
6a010ac9
LP
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 },
2e2b3608 86 { "configuration", required_argument, NULL, ARG_CONFIGURATION },
7f0d207d
LP
87 { "machine", required_argument, NULL, ARG_MACHINE },
88 {},
71008e18
DM
89 };
90
2e2b3608 91 int c, r;
71008e18
DM
92
93 assert(argc >= 0);
94 assert(argv);
95
601185b4 96 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
71008e18
DM
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
7f0d207d
LP
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;
ba768916 118 break;
7f0d207d 119 }
ba768916 120
6a010ac9
LP
121 case ARG_DROP_PRIVILEGES:
122 arg_drop_privileges = true;
123 break;
124
2e2b3608
LP
125 case ARG_CONFIGURATION:
126 r = strv_extend(&arg_configuration, optarg);
127 if (r < 0)
128 return log_oom();
129 break;
130
7f0d207d
LP
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
71008e18
DM
153 case '?':
154 return -EINVAL;
155
71008e18 156 default:
ba768916 157 assert_not_reached("Unhandled option");
71008e18 158 }
71008e18 159
0721804f
LP
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];
7f0d207d 164 if (argc > optind + 1 || (arg_command_line_buffer && !in_charset(arg_command_line_buffer, "x"))) {
0721804f
LP
165 log_error("Too many arguments");
166 return -EINVAL;
167 }
168
7f0d207d
LP
169 if (!arg_address) {
170 arg_address = strdup(DEFAULT_SYSTEM_BUS_PATH);
171 if (!arg_address)
172 return log_oom();
173 }
174
71008e18
DM
175 return 1;
176}
a8f11321 177
758bf0c7 178static int rename_service(sd_bus *a, sd_bus *b) {
a7639e37
LP
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
758bf0c7 187 assert(a);
a7639e37
LP
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,
ccd06097
ZJS
220 "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
221 pid, p,
222 uid, name);
a7639e37
LP
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,
ccd06097
ZJS
230 "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
231 pid, comm,
232 uid, name);
a7639e37
LP
233
234 if (m > w)
29804cc1 235 memzero(arg_command_line_buffer + w, m - w);
a7639e37
LP
236 }
237
ccd06097
ZJS
238 log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
239 pid, p,
240 uid, name,
758bf0c7
LP
241 a->unique_name);
242 ;
a7639e37
LP
243 return 0;
244}
245
246static 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,
151b9b96 279 &n,
a7639e37
LP
280 "/org/freedesktop/DBus",
281 "org.freedesktop.DBus",
151b9b96 282 "NameLost");
a7639e37
LP
283
284 } else if (streq(new_owner, a->unique_name)) {
285
286 r = sd_bus_message_new_signal(
287 b,
151b9b96 288 &n,
a7639e37
LP
289 "/org/freedesktop/DBus",
290 "org.freedesktop.DBus",
151b9b96 291 "NameAcquired");
a7639e37
LP
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
c2595875
LP
313static 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
62bb05f6
LP
321 if (!a->is_kernel)
322 return 0;
323
c2595875
LP
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
2f1a3d08
LP
355static 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
372static 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
386static 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
401static int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
2f1a3d08
LP
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
dc780ecf
KS
425static 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
440static 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
465static 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
480static 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
2a0abe5b
LP
503static 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
62bb05f6
LP
510 if (!a->is_kernel)
511 return 0;
512
2a0abe5b
LP
513 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
514 return 0;
515
dc780ecf
KS
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")) {
2a0abe5b
LP
611 const char *match;
612
613 r = sd_bus_message_read(m, "s", &match);
614 if (r < 0)
2f1a3d08 615 return synthetic_reply_method_errno(m, r, NULL);
2a0abe5b 616
19befb2d 617 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
2a0abe5b 618 if (r < 0)
2f1a3d08 619 return synthetic_reply_method_errno(m, r, NULL);
2a0abe5b 620
2f1a3d08 621 return synthetic_reply_method_return(m, NULL);
2a0abe5b
LP
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)
2f1a3d08 628 return synthetic_reply_method_errno(m, r, NULL);
2a0abe5b 629
19befb2d
LP
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"));
2a0abe5b 633 if (r < 0)
2f1a3d08 634 return synthetic_reply_method_errno(m, r, NULL);
2a0abe5b 635
2f1a3d08 636 return synthetic_reply_method_return(m, NULL);
2a0abe5b 637
dc780ecf
KS
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
eb17e178 770 if (err < 0)
dc780ecf
KS
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)
19befb2d 807 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
dc780ecf 808 if (r == -EADDRINUSE)
19befb2d
LP
809 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
810
dc780ecf
KS
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 }
2a0abe5b
LP
953}
954
a7639e37
LP
955static 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,
151b9b96 1025 &n,
a7639e37
LP
1026 "/org/freedesktop/DBus",
1027 "org.freedesktop.DBus",
151b9b96 1028 "NameAcquired");
a7639e37
LP
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
7b217f41
LP
1061static 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
a8f11321 1091int main(int argc, char *argv[]) {
0721804f 1092
d51539b1
LP
1093 _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
1094 sd_id128_t server_id;
71008e18 1095 int r, in_fd, out_fd;
a7639e37 1096 bool got_hello = false;
0721804f 1097 bool is_unix;
8a0e0ed9
LP
1098 struct ucred ucred = {};
1099 _cleanup_free_ char *peersec = NULL;
bcf3295d 1100 Policy policy = {};
a8f11321 1101
4cfa2c99 1102 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
a8f11321
LP
1103 log_parse_environment();
1104 log_open();
1105
71008e18
DM
1106 r = parse_argv(argc, argv);
1107 if (r <= 0)
1108 goto finish;
1109
2e2b3608 1110 r = policy_load(&policy, arg_configuration);
bcf3295d
LP
1111 if (r < 0) {
1112 log_error("Failed to load policy: %s", strerror(-r));
1113 goto finish;
1114 }
1115
1116 /* policy_dump(&policy); */
1117
71008e18
DM
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 {
9f6445e3 1126 log_error("Illegal number of file descriptors passed");
71008e18
DM
1127 goto finish;
1128 }
1129
d51539b1 1130 is_unix =
71008e18
DM
1131 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
1132 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
d51539b1 1133
8a0e0ed9 1134 if (is_unix) {
eff05270 1135 getpeercred(in_fd, &ucred);
8a0e0ed9
LP
1136 getpeersec(in_fd, &peersec);
1137 }
1138
6a010ac9
LP
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
d51539b1
LP
1155 r = sd_bus_new(&a);
1156 if (r < 0) {
1157 log_error("Failed to allocate bus: %s", strerror(-r));
a8f11321
LP
1158 goto finish;
1159 }
1160
44b0ed05
LP
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
ba768916 1167 r = sd_bus_set_address(a, arg_address);
d51539b1
LP
1168 if (r < 0) {
1169 log_error("Failed to set address to connect to: %s", strerror(-r));
1170 goto finish;
1171 }
a8f11321 1172
264ad849 1173 r = sd_bus_negotiate_fds(a, is_unix);
d51539b1
LP
1174 if (r < 0) {
1175 log_error("Failed to set FD negotiation: %s", strerror(-r));
a8f11321
LP
1176 goto finish;
1177 }
1178
8a0e0ed9
LP
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
373f1422
LP
1186 if (peersec) {
1187 a->fake_label = peersec;
1188 peersec = NULL;
1189 }
8a0e0ed9 1190
758bf0c7
LP
1191 a->manual_peer_interface = true;
1192
d51539b1
LP
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 }
a8f11321 1198
d51539b1
LP
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));
a8f11321
LP
1202 goto finish;
1203 }
1204
d51539b1
LP
1205 r = sd_bus_new(&b);
1206 if (r < 0) {
1207 log_error("Failed to allocate bus: %s", strerror(-r));
1208 goto finish;
1209 }
a8f11321 1210
71008e18 1211 r = sd_bus_set_fd(b, in_fd, out_fd);
d51539b1
LP
1212 if (r < 0) {
1213 log_error("Failed to set fds: %s", strerror(-r));
1214 goto finish;
1215 }
a8f11321 1216
d51539b1
LP
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 }
a8f11321 1222
264ad849 1223 r = sd_bus_negotiate_fds(b, is_unix);
d51539b1
LP
1224 if (r < 0) {
1225 log_error("Failed to set FD negotiation: %s", strerror(-r));
a8f11321
LP
1226 goto finish;
1227 }
1228
d51539b1
LP
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 }
a8f11321 1234
758bf0c7
LP
1235 b->manual_peer_interface = true;
1236
d51539b1
LP
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 }
a8f11321 1242
758bf0c7 1243 r = rename_service(a, b);
a7639e37
LP
1244 if (r < 0)
1245 log_debug("Failed to rename process: %s", strerror(-r));
0721804f 1246
a7639e37 1247 if (a->is_kernel) {
94a6ce5b 1248 _cleanup_free_ char *match = NULL;
a7639e37
LP
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));
0721804f
LP
1254 goto finish;
1255 }
1256
a7639e37
LP
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();
0721804f
LP
1268 goto finish;
1269 }
1270
19befb2d 1271 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
a7639e37
LP
1272 if (r < 0) {
1273 log_error("Failed to add match for NameLost: %s", strerror(-r));
1274 goto finish;
1275 }
0721804f 1276
a7639e37
LP
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 }
0721804f 1291
19befb2d 1292 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
a7639e37
LP
1293 if (r < 0) {
1294 log_error("Failed to add match for NameAcquired: %s", strerror(-r));
1295 goto finish;
0721804f
LP
1296 }
1297 }
1298
d51539b1
LP
1299 for (;;) {
1300 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
f72a3e5b
KS
1301 int events_a, events_b, fd;
1302 uint64_t timeout_a, timeout_b, t;
d51539b1 1303 struct timespec _ts, *ts;
b2bb3469 1304 struct pollfd *pollfd;
f72a3e5b
KS
1305 int k;
1306
a7639e37
LP
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));
a8f11321 1315
0358b3f9
LP
1316 goto finish;
1317 }
1318
a7639e37
LP
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
7b217f41
LP
1333 patch_sender(a, m);
1334
a7639e37
LP
1335 k = sd_bus_send(b, m, NULL);
1336 if (k < 0) {
441d56a1
LP
1337 if (k == -ECONNRESET)
1338 r = 0;
1339 else {
1340 r = k;
1341 log_error("Failed to send message: %s", strerror(-r));
1342 }
1343
a7639e37
LP
1344 goto finish;
1345 }
d51539b1 1346 }
a8f11321 1347
a7639e37
LP
1348 if (r > 0)
1349 continue;
1350 }
f72a3e5b
KS
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
d51539b1
LP
1360 goto finish;
1361 }
a8f11321 1362
f72a3e5b
KS
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;
9818fa6d
ZJS
1367 goto finish;
1368 }
a8f11321 1369
a7639e37 1370 k = process_hello(a, b, m, &got_hello);
f72a3e5b
KS
1371 if (k < 0) {
1372 r = k;
920e2957 1373 log_error("Failed to process HELLO: %s", strerror(-r));
9818fa6d
ZJS
1374 goto finish;
1375 }
a7639e37
LP
1376
1377 if (k > 0)
1378 r = k;
1379 else {
c2595875
LP
1380 k = process_policy(a, b, m);
1381 if (k < 0) {
1382 r = k;
920e2957 1383 log_error("Failed to process policy: %s", strerror(-r));
c2595875
LP
1384 goto finish;
1385 }
1386
2a0abe5b 1387 k = process_driver(a, b, m);
a7639e37 1388 if (k < 0) {
2a0abe5b
LP
1389 r = k;
1390 log_error("Failed to process driver calls: %s", strerror(-r));
a7639e37
LP
1391 goto finish;
1392 }
2a0abe5b
LP
1393
1394 if (k > 0)
1395 r = k;
1396 else {
1397 k = sd_bus_send(a, m, NULL);
1398 if (k < 0) {
e05aa2e0 1399 if (k == -ECONNRESET)
2a0abe5b
LP
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 }
a7639e37 1409 }
d51539b1 1410 }
a8f11321 1411
f72a3e5b
KS
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;
a8f11321 1448
d51539b1
LP
1449 if (t == (uint64_t) -1)
1450 ts = NULL;
1451 else {
1452 usec_t nw;
a8f11321 1453
d51539b1
LP
1454 nw = now(CLOCK_MONOTONIC);
1455 if (t > nw)
1456 t -= nw;
1457 else
1458 t = 0;
a8f11321 1459
d51539b1 1460 ts = timespec_store(&_ts, t);
a8f11321
LP
1461 }
1462
b2bb3469 1463 pollfd = (struct pollfd[3]) {
f72a3e5b
KS
1464 {.fd = fd, .events = events_a, },
1465 {.fd = in_fd, .events = events_b & POLLIN, },
1466 {.fd = out_fd, .events = events_b & POLLOUT, }
b2bb3469 1467 };
d51539b1 1468
b2bb3469 1469 r = ppoll(pollfd, 3, ts, NULL);
d51539b1
LP
1470 if (r < 0) {
1471 log_error("ppoll() failed: %m");
1472 goto finish;
1473 }
1474 }
a8f11321 1475
a8f11321 1476finish:
0358b3f9
LP
1477 sd_bus_flush(a);
1478 sd_bus_flush(b);
7f0d207d
LP
1479 sd_bus_close(a);
1480 sd_bus_close(b);
0358b3f9 1481
bcf3295d 1482 policy_free(&policy);
2e2b3608 1483 strv_free(arg_configuration);
7f0d207d 1484 free(arg_address);
bcf3295d 1485
d51539b1 1486 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
a8f11321 1487}