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