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