chiark / gitweb /
bus-proxy: factor out code for driver handling and message synthesis
[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-control.h"
48 #include "smack-util.h"
49 #include "set.h"
50 #include "bus-xml-policy.h"
51 #include "driver.h"
52 #include "synthesize.h"
53
54 static char *arg_address = NULL;
55 static char *arg_command_line_buffer = NULL;
56 static bool arg_drop_privileges = false;
57 static char **arg_configuration = NULL;
58
59 static int help(void) {
60
61         printf("%s [OPTIONS...]\n\n"
62                "Connect STDIO or a socket to a given bus address.\n\n"
63                "  -h --help               Show this help\n"
64                "     --version            Show package version\n"
65                "     --drop-privileges    Drop privileges\n"
66                "     --configuration=PATH Configuration file or directory\n"
67                "     --machine=MACHINE    Connect to specified machine\n"
68                "     --address=ADDRESS    Connect to the bus specified by ADDRESS\n"
69                "                          (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n",
70                program_invocation_short_name);
71
72         return 0;
73 }
74
75 static int parse_argv(int argc, char *argv[]) {
76
77         enum {
78                 ARG_VERSION = 0x100,
79                 ARG_ADDRESS,
80                 ARG_DROP_PRIVILEGES,
81                 ARG_CONFIGURATION,
82                 ARG_MACHINE,
83         };
84
85         static const struct option options[] = {
86                 { "help",            no_argument,       NULL, 'h'                 },
87                 { "version",         no_argument,       NULL, ARG_VERSION         },
88                 { "address",         required_argument, NULL, ARG_ADDRESS         },
89                 { "drop-privileges", no_argument,       NULL, ARG_DROP_PRIVILEGES },
90                 { "configuration",   required_argument, NULL, ARG_CONFIGURATION   },
91                 { "machine",         required_argument, NULL, ARG_MACHINE         },
92                 {},
93         };
94
95         int c, r;
96
97         assert(argc >= 0);
98         assert(argv);
99
100         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
101
102                 switch (c) {
103
104                 case 'h':
105                         help();
106                         return 0;
107
108                 case ARG_VERSION:
109                         puts(PACKAGE_STRING);
110                         puts(SYSTEMD_FEATURES);
111                         return 0;
112
113                 case ARG_ADDRESS: {
114                         char *a;
115
116                         a = strdup(optarg);
117                         if (!a)
118                                 return log_oom();
119
120                         free(arg_address);
121                         arg_address = a;
122                         break;
123                 }
124
125                 case ARG_DROP_PRIVILEGES:
126                         arg_drop_privileges = true;
127                         break;
128
129                 case ARG_CONFIGURATION:
130                         r = strv_extend(&arg_configuration, optarg);
131                         if (r < 0)
132                                 return log_oom();
133                         break;
134
135                 case ARG_MACHINE: {
136                         _cleanup_free_ char *e = NULL;
137                         char *a;
138
139                         e = bus_address_escape(optarg);
140                         if (!e)
141                                 return log_oom();
142
143 #ifdef ENABLE_KDBUS
144                         a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL);
145 #else
146                         a = strjoin("x-machine-unix:machine=", e, NULL);
147 #endif
148                         if (!a)
149                                 return log_oom();
150
151                         free(arg_address);
152                         arg_address = a;
153
154                         break;
155                 }
156
157                 case '?':
158                         return -EINVAL;
159
160                 default:
161                         assert_not_reached("Unhandled option");
162                 }
163
164         /* If the first command line argument is only "x" characters
165          * we'll write who we are talking to into it, so that "ps" is
166          * explanatory */
167         arg_command_line_buffer = argv[optind];
168         if (argc > optind + 1 || (arg_command_line_buffer && !in_charset(arg_command_line_buffer, "x"))) {
169                 log_error("Too many arguments");
170                 return -EINVAL;
171         }
172
173         if (!arg_address) {
174                 arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS);
175                 if (!arg_address)
176                         return log_oom();
177         }
178
179         return 1;
180 }
181
182 static int rename_service(sd_bus *a, sd_bus *b) {
183         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
184         _cleanup_free_ char *p = NULL, *name = NULL;
185         const char *comm;
186         char **cmdline;
187         uid_t uid;
188         pid_t pid;
189         int r;
190
191         assert(a);
192         assert(b);
193
194         r = sd_bus_get_owner_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_AUGMENT, &creds);
195         if (r < 0)
196                 return r;
197
198         r = sd_bus_creds_get_uid(creds, &uid);
199         if (r < 0)
200                 return r;
201
202         r = sd_bus_creds_get_pid(creds, &pid);
203         if (r < 0)
204                 return r;
205
206         r = sd_bus_creds_get_cmdline(creds, &cmdline);
207         if (r < 0)
208                 return r;
209
210         r = sd_bus_creds_get_comm(creds, &comm);
211         if (r < 0)
212                 return r;
213
214         name = uid_to_name(uid);
215         if (!name)
216                 return -ENOMEM;
217
218         p = strv_join(cmdline, " ");
219         if (!p)
220                 return -ENOMEM;
221
222         /* The status string gets the full command line ... */
223         sd_notifyf(false,
224                    "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
225                    pid, p,
226                    uid, name);
227
228         /* ... and the argv line only the short comm */
229         if (arg_command_line_buffer) {
230                 size_t m, w;
231
232                 m = strlen(arg_command_line_buffer);
233                 w = snprintf(arg_command_line_buffer, m,
234                              "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
235                              pid, comm,
236                              uid, name);
237
238                 if (m > w)
239                         memzero(arg_command_line_buffer + w, m - w);
240         }
241
242         log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
243                   pid, p,
244                   uid, name,
245                   a->unique_name);
246
247         return 0;
248 }
249
250 static int handle_policy_error(sd_bus_message *m, int r) {
251         if (r == -ESRCH || r == -ENXIO)
252                 return synthetic_reply_method_errorf(m, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", m->destination);
253
254         return r;
255 }
256
257 static int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, Policy *policy, const struct ucred *our_ucred, Set *owned_names) {
258         int r;
259
260         assert(from);
261         assert(to);
262         assert(m);
263
264         if (!policy)
265                 return 0;
266
267         /*
268          * dbus-1 distinguishes expected and non-expected replies by tracking
269          * method-calls and timeouts. By default, DENY rules are *NEVER* applied
270          * on expected replies, unless explicitly specified. But we dont track
271          * method-calls, thus, we cannot know whether a reply is expected.
272          * Fortunately, the kdbus forbids non-expected replies, so we can safely
273          * ignore any policy on those and let the kernel deal with it.
274          *
275          * TODO: To be correct, we should only ignore policy-tags that are
276          * applied on non-expected replies. However, so far we don't parse those
277          * tags so we let everything pass. I haven't seen a DENY policy tag on
278          * expected-replies, ever, so don't bother..
279          */
280         if (m->reply_cookie > 0)
281                 return 0;
282
283         if (from->is_kernel) {
284                 uid_t sender_uid = UID_INVALID;
285                 gid_t sender_gid = GID_INVALID;
286                 char **sender_names = NULL;
287                 bool granted = false;
288
289                 /* Driver messages are always OK */
290                 if (streq_ptr(m->sender, "org.freedesktop.DBus"))
291                         return 0;
292
293                 /* The message came from the kernel, and is sent to our legacy client. */
294                 sd_bus_creds_get_well_known_names(&m->creds, &sender_names);
295
296                 (void) sd_bus_creds_get_uid(&m->creds, &sender_uid);
297                 (void) sd_bus_creds_get_gid(&m->creds, &sender_gid);
298
299                 if (sender_uid == UID_INVALID || sender_gid == GID_INVALID) {
300                         _cleanup_bus_creds_unref_ sd_bus_creds *sender_creds = NULL;
301
302                         /* If the message came from another legacy
303                          * client, then the message creds will be
304                          * missing, simply because on legacy clients
305                          * per-message creds were unknown. In this
306                          * case, query the creds of the peer
307                          * instead. */
308
309                         r = bus_get_name_creds_kdbus(from, m->sender, SD_BUS_CREDS_UID|SD_BUS_CREDS_GID, true, &sender_creds);
310                         if (r < 0)
311                                 return handle_policy_error(m, r);
312
313                         (void) sd_bus_creds_get_uid(sender_creds, &sender_uid);
314                         (void) sd_bus_creds_get_gid(sender_creds, &sender_gid);
315                 }
316
317                 /* First check whether the sender can send the message to our name */
318                 if (set_isempty(owned_names)) {
319                         if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, NULL, m->path, m->interface, m->member, false))
320                                 granted = true;
321                 } else {
322                         Iterator i;
323                         char *n;
324
325                         SET_FOREACH(n, owned_names, i)
326                                 if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, n, m->path, m->interface, m->member, false)) {
327                                         granted = true;
328                                         break;
329                                 }
330                 }
331
332                 if (granted) {
333                         /* Then check whether us (the recipient) can receive from the sender's name */
334                         if (strv_isempty(sender_names)) {
335                                 if (policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, m->path, m->interface, m->member, false))
336                                         return 0;
337                         } else {
338                                 char **n;
339
340                                 STRV_FOREACH(n, sender_names) {
341                                         if (policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, *n, m->path, m->interface, m->member, false))
342                                                 return 0;
343                                 }
344                         }
345                 }
346
347                 /* Return an error back to the caller */
348                 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
349                         return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML receiver policy.");
350
351                 /* Return 1, indicating that the message shall not be processed any further */
352                 return 1;
353         }
354
355         if (to->is_kernel) {
356                 _cleanup_bus_creds_unref_ sd_bus_creds *destination_creds = NULL;
357                 uid_t destination_uid = UID_INVALID;
358                 gid_t destination_gid = GID_INVALID;
359                 const char *destination_unique = NULL;
360                 char **destination_names = NULL;
361                 bool granted = false;
362
363                 /* Driver messages are always OK */
364                 if (streq_ptr(m->destination, "org.freedesktop.DBus"))
365                         return 0;
366
367                 /* The message came from the legacy client, and is sent to kdbus. */
368                 if (m->destination) {
369                         r = bus_get_name_creds_kdbus(to, m->destination,
370                                                      SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME|
371                                                      SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID,
372                                                      true, &destination_creds);
373                         if (r < 0)
374                                 return handle_policy_error(m, r);
375
376                         r = sd_bus_creds_get_unique_name(destination_creds, &destination_unique);
377                         if (r < 0)
378                                 return handle_policy_error(m, r);
379
380                         sd_bus_creds_get_well_known_names(destination_creds, &destination_names);
381
382                         (void) sd_bus_creds_get_uid(destination_creds, &destination_uid);
383                         (void) sd_bus_creds_get_gid(destination_creds, &destination_gid);
384                 }
385
386                 /* First check if we (the sender) can send to this name */
387                 if (strv_isempty(destination_names)) {
388                         if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, m->path, m->interface, m->member, true))
389                                 granted = true;
390                 } else {
391                         char **n;
392
393                         STRV_FOREACH(n, destination_names) {
394                                 if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, *n, m->path, m->interface, m->member, true)) {
395
396                                         /* If we made a receiver decision,
397                                            then remember which name's policy
398                                            we used, and to which unique ID it
399                                            mapped when we made the
400                                            decision. Then, let's pass this to
401                                            the kernel when sending the
402                                            message, so that it refuses the
403                                            operation should the name and
404                                            unique ID not map to each other
405                                            anymore. */
406
407                                         r = free_and_strdup(&m->destination_ptr, *n);
408                                         if (r < 0)
409                                                 return r;
410
411                                         r = bus_kernel_parse_unique_name(destination_unique, &m->verify_destination_id);
412                                         if (r < 0)
413                                                 break;
414
415                                         granted = true;
416                                         break;
417                                 }
418                         }
419                 }
420
421                 /* Then check if the recipient can receive from our name */
422                 if (granted) {
423                         if (sd_bus_message_is_signal(m, NULL, NULL)) {
424                                 /* If we forward a signal from dbus-1 to kdbus,
425                                  * we have no idea who the recipient is.
426                                  * Therefore, we cannot apply any dbus-1
427                                  * receiver policies that match on receiver
428                                  * credentials. We know sd-bus always sets
429                                  * KDBUS_MSG_SIGNAL, so the kernel applies
430                                  * receiver policies to the message. Therefore,
431                                  * skip policy checks in this case. */
432                                 return 0;
433                         } else if (set_isempty(owned_names)) {
434                                 if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, NULL, m->path, m->interface, m->member, true))
435                                         return 0;
436                         } else {
437                                 Iterator i;
438                                 char *n;
439
440                                 SET_FOREACH(n, owned_names, i)
441                                         if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, n, m->path, m->interface, m->member, true))
442                                                 return 0;
443                         }
444                 }
445
446                 /* Return an error back to the caller */
447                 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
448                         return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML sender policy.");
449
450                 /* Return 1, indicating that the message shall not be processed any further */
451                 return 1;
452         }
453
454         return 0;
455 }
456
457 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
458         _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
459         bool is_hello;
460         int r;
461
462         assert(a);
463         assert(b);
464         assert(m);
465         assert(got_hello);
466
467         /* As reaction to hello we need to respond with two messages:
468          * the callback reply and the NameAcquired for the unique
469          * name, since hello is otherwise obsolete on kdbus. */
470
471         is_hello =
472                 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
473                 streq_ptr(m->destination, "org.freedesktop.DBus");
474
475         if (!is_hello) {
476
477                 if (*got_hello)
478                         return 0;
479
480                 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
481                 return -EIO;
482         }
483
484         if (*got_hello) {
485                 log_error("Got duplicate hello, aborting.");
486                 return -EIO;
487         }
488
489         *got_hello = true;
490
491         if (!a->is_kernel)
492                 return 0;
493
494         r = sd_bus_message_new_method_return(m, &n);
495         if (r < 0)
496                 return log_error_errno(r, "Failed to generate HELLO reply: %m");
497
498         r = sd_bus_message_append(n, "s", a->unique_name);
499         if (r < 0)
500                 return log_error_errno(r, "Failed to append unique name to HELLO reply: %m");
501
502         r = bus_message_append_sender(n, "org.freedesktop.DBus");
503         if (r < 0)
504                 return log_error_errno(r, "Failed to append sender to HELLO reply: %m");
505
506         r = bus_seal_synthetic_message(b, n);
507         if (r < 0)
508                 return log_error_errno(r, "Failed to seal HELLO reply: %m");
509
510         r = sd_bus_send(b, n, NULL);
511         if (r < 0)
512                 return log_error_errno(r, "Failed to send HELLO reply: %m");
513
514         n = sd_bus_message_unref(n);
515         r = sd_bus_message_new_signal(
516                         b,
517                         &n,
518                         "/org/freedesktop/DBus",
519                         "org.freedesktop.DBus",
520                         "NameAcquired");
521         if (r < 0)
522                 return log_error_errno(r, "Failed to allocate initial NameAcquired message: %m");
523
524         r = sd_bus_message_append(n, "s", a->unique_name);
525         if (r < 0)
526                 return log_error_errno(r, "Failed to append unique name to NameAcquired message: %m");
527
528         r = bus_message_append_sender(n, "org.freedesktop.DBus");
529         if (r < 0)
530                 return log_error_errno(r, "Failed to append sender to NameAcquired message: %m");
531
532         r = bus_seal_synthetic_message(b, n);
533         if (r < 0)
534                 return log_error_errno(r, "Failed to seal NameAcquired message: %m");
535
536         r = sd_bus_send(b, n, NULL);
537         if (r < 0)
538                 return log_error_errno(r, "Failed to send NameAcquired message: %m");
539
540         return 1;
541 }
542
543 static int patch_sender(sd_bus *a, sd_bus_message *m) {
544         char **well_known = NULL;
545         sd_bus_creds *c;
546         int r;
547
548         assert(a);
549         assert(m);
550
551         if (!a->is_kernel)
552                 return 0;
553
554         /* We will change the sender of messages from the bus driver
555          * so that they originate from the bus driver. This is a
556          * speciality originating from dbus1, where the bus driver did
557          * not have a unique id, but only the well-known name. */
558
559         c = sd_bus_message_get_creds(m);
560         if (!c)
561                 return 0;
562
563         r = sd_bus_creds_get_well_known_names(c, &well_known);
564         if (r < 0)
565                 return r;
566
567         if (strv_contains(well_known, "org.freedesktop.DBus"))
568                 m->sender = "org.freedesktop.DBus";
569
570         return 0;
571 }
572
573 static int mac_smack_apply_label_and_drop_cap_mac_admin(pid_t its_pid, const char *new_label) {
574 #ifdef HAVE_SMACK
575         int r = 0, k;
576
577         if (!mac_smack_use())
578                 return 0;
579
580         if (new_label && its_pid > 0)
581                 r = mac_smack_apply_pid(its_pid, new_label);
582
583         k = drop_capability(CAP_MAC_ADMIN);
584         return r < 0 ? r : k;
585 #else
586         return 0;
587 #endif
588 }
589
590 static int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
591         _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
592         const char *name, *old_owner, *new_owner;
593         int r;
594
595         assert(a);
596         assert(b);
597         assert(m);
598
599         /* If we get NameOwnerChanged for our own name, we need to
600          * synthesize NameLost/NameAcquired, since socket clients need
601          * that, even though it is obsoleted on kdbus */
602
603         if (!a->is_kernel)
604                 return 0;
605
606         if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
607             !streq_ptr(m->path, "/org/freedesktop/DBus") ||
608             !streq_ptr(m->sender, "org.freedesktop.DBus"))
609                 return 0;
610
611         r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
612         if (r < 0)
613                 return r;
614
615         r = sd_bus_message_rewind(m, true);
616         if (r < 0)
617                 return r;
618
619         if (streq(old_owner, a->unique_name)) {
620
621                 r = sd_bus_message_new_signal(
622                                 b,
623                                 &n,
624                                 "/org/freedesktop/DBus",
625                                 "org.freedesktop.DBus",
626                                 "NameLost");
627
628         } else if (streq(new_owner, a->unique_name)) {
629
630                 r = sd_bus_message_new_signal(
631                                 b,
632                                 &n,
633                                 "/org/freedesktop/DBus",
634                                 "org.freedesktop.DBus",
635                                 "NameAcquired");
636         } else
637                 return 0;
638
639         if (r < 0)
640                 return r;
641
642         r = sd_bus_message_append(n, "s", name);
643         if (r < 0)
644                 return r;
645
646         r = bus_message_append_sender(n, "org.freedesktop.DBus");
647         if (r < 0)
648                 return r;
649
650         r = bus_seal_synthetic_message(b, n);
651         if (r < 0)
652                 return r;
653
654         return sd_bus_send(b, n, NULL);
655 }
656
657 int main(int argc, char *argv[]) {
658
659         _cleanup_bus_close_unref_ sd_bus *a = NULL, *b = NULL;
660         sd_id128_t server_id;
661         int r, in_fd, out_fd;
662         bool got_hello = false;
663         bool is_unix;
664         struct ucred ucred = {};
665         _cleanup_free_ char *peersec = NULL;
666         Policy policy_buffer = {}, *policy = NULL;
667         _cleanup_set_free_free_ Set *owned_names = NULL;
668         uid_t original_uid;
669
670         log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
671         log_parse_environment();
672         log_open();
673
674         r = parse_argv(argc, argv);
675         if (r <= 0)
676                 goto finish;
677
678         r = sd_listen_fds(0);
679         if (r == 0) {
680                 in_fd = STDIN_FILENO;
681                 out_fd = STDOUT_FILENO;
682         } else if (r == 1) {
683                 in_fd = SD_LISTEN_FDS_START;
684                 out_fd = SD_LISTEN_FDS_START;
685         } else {
686                 log_error("Illegal number of file descriptors passed");
687                 goto finish;
688         }
689
690         original_uid = getuid();
691
692         is_unix =
693                 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
694                 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
695
696         if (is_unix) {
697                 (void) getpeercred(in_fd, &ucred);
698                 (void) getpeersec(in_fd, &peersec);
699
700                 r = mac_smack_apply_label_and_drop_cap_mac_admin(getpid(), peersec);
701                 if (r < 0)
702                         log_warning_errno(r, "Failed to set SMACK label (%s) and drop CAP_MAC_ADMIN: %m", peersec);
703         }
704
705         if (arg_drop_privileges) {
706                 const char *user = "systemd-bus-proxy";
707                 uid_t uid;
708                 gid_t gid;
709
710                 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
711                 if (r < 0) {
712                         log_error_errno(r, "Cannot resolve user name %s: %m", user);
713                         goto finish;
714                 }
715
716                 r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
717                 if (r < 0)
718                         goto finish;
719         }
720
721         owned_names = set_new(&string_hash_ops);
722         if (!owned_names) {
723                 log_oom();
724                 goto finish;
725         }
726
727         r = sd_bus_new(&a);
728         if (r < 0) {
729                 log_error_errno(r, "Failed to allocate bus: %m");
730                 goto finish;
731         }
732
733         r = sd_bus_set_description(a, "sd-proxy");
734         if (r < 0) {
735                 log_error_errno(r, "Failed to set bus name: %m");
736                 goto finish;
737         }
738
739         r = sd_bus_set_address(a, arg_address);
740         if (r < 0) {
741                 log_error_errno(r, "Failed to set address to connect to: %m");
742                 goto finish;
743         }
744
745         r = sd_bus_negotiate_fds(a, is_unix);
746         if (r < 0) {
747                 log_error_errno(r, "Failed to set FD negotiation: %m");
748                 goto finish;
749         }
750
751         r = sd_bus_negotiate_creds(a, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_GID|SD_BUS_CREDS_SELINUX_CONTEXT);
752         if (r < 0) {
753                 log_error_errno(r, "Failed to set credential negotiation: %m");
754                 goto finish;
755         }
756
757         if (ucred.pid > 0) {
758                 a->fake_pids.pid = ucred.pid;
759                 a->fake_pids_valid = true;
760
761                 a->fake_creds.uid = ucred.uid;
762                 a->fake_creds.euid = UID_INVALID;
763                 a->fake_creds.suid = UID_INVALID;
764                 a->fake_creds.fsuid = UID_INVALID;
765                 a->fake_creds.gid = ucred.gid;
766                 a->fake_creds.egid = GID_INVALID;
767                 a->fake_creds.sgid = GID_INVALID;
768                 a->fake_creds.fsgid = GID_INVALID;
769                 a->fake_creds_valid = true;
770         }
771
772         if (peersec) {
773                 a->fake_label = peersec;
774                 peersec = NULL;
775         }
776
777         a->manual_peer_interface = true;
778
779         r = sd_bus_start(a);
780         if (r < 0) {
781                 log_error_errno(r, "Failed to start bus client: %m");
782                 goto finish;
783         }
784
785         r = sd_bus_get_bus_id(a, &server_id);
786         if (r < 0) {
787                 log_error_errno(r, "Failed to get server ID: %m");
788                 goto finish;
789         }
790
791         if (a->is_kernel) {
792                 if (!arg_configuration) {
793                         const char *scope;
794
795                         r = sd_bus_get_scope(a, &scope);
796                         if (r < 0) {
797                                 log_error_errno(r, "Couldn't determine bus scope: %m");
798                                 goto finish;
799                         }
800
801                         if (streq(scope, "system"))
802                                 arg_configuration = strv_new(
803                                                 "/etc/dbus-1/system.conf",
804                                                 "/etc/dbus-1/system.d/",
805                                                 "/etc/dbus-1/system-local.conf",
806                                                 NULL);
807                         else if (streq(scope, "user"))
808                                 arg_configuration = strv_new(
809                                                 "/etc/dbus-1/session.conf",
810                                                 "/etc/dbus-1/session.d/",
811                                                 "/etc/dbus-1/session-local.conf",
812                                                 NULL);
813                         else {
814                                 log_error("Unknown scope %s, don't know which policy to load. Refusing.", scope);
815                                 goto finish;
816                         }
817
818                         if (!arg_configuration) {
819                                 r = log_oom();
820                                 goto finish;
821                         }
822                 }
823
824                 r = policy_load(&policy_buffer, arg_configuration);
825                 if (r < 0) {
826                         log_error_errno(r, "Failed to load policy: %m");
827                         goto finish;
828                 }
829
830                 policy = &policy_buffer;
831                 /* policy_dump(policy); */
832
833                 if (ucred.uid == original_uid)
834                         log_debug("Permitting access, since bus owner matches bus client.");
835                 else if (policy_check_hello(policy, ucred.uid, ucred.gid))
836                         log_debug("Permitting access due to XML policy.");
837                 else {
838                         r = log_error_errno(EPERM, "Policy denied connection.");
839                         goto finish;
840                 }
841         }
842
843         r = sd_bus_new(&b);
844         if (r < 0) {
845                 log_error_errno(r, "Failed to allocate bus: %m");
846                 goto finish;
847         }
848
849         r = sd_bus_set_fd(b, in_fd, out_fd);
850         if (r < 0) {
851                 log_error_errno(r, "Failed to set fds: %m");
852                 goto finish;
853         }
854
855         r = sd_bus_set_server(b, 1, server_id);
856         if (r < 0) {
857                 log_error_errno(r, "Failed to set server mode: %m");
858                 goto finish;
859         }
860
861         r = sd_bus_negotiate_fds(b, is_unix);
862         if (r < 0) {
863                 log_error_errno(r, "Failed to set FD negotiation: %m");
864                 goto finish;
865         }
866
867         r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_GID|SD_BUS_CREDS_SELINUX_CONTEXT);
868         if (r < 0) {
869                 log_error_errno(r, "Failed to set credential negotiation: %m");
870                 goto finish;
871         }
872
873         r = sd_bus_set_anonymous(b, true);
874         if (r < 0) {
875                 log_error_errno(r, "Failed to set anonymous authentication: %m");
876                 goto finish;
877         }
878
879         b->manual_peer_interface = true;
880
881         r = sd_bus_start(b);
882         if (r < 0) {
883                 log_error_errno(r, "Failed to start bus client: %m");
884                 goto finish;
885         }
886
887         r = rename_service(a, b);
888         if (r < 0)
889                 log_debug_errno(r, "Failed to rename process: %m");
890
891         if (a->is_kernel) {
892                 _cleanup_free_ char *match = NULL;
893                 const char *unique;
894
895                 r = sd_bus_get_unique_name(a, &unique);
896                 if (r < 0) {
897                         log_error_errno(r, "Failed to get unique name: %m");
898                         goto finish;
899                 }
900
901                 match = strjoin("type='signal',"
902                                 "sender='org.freedesktop.DBus',"
903                                 "path='/org/freedesktop/DBus',"
904                                 "interface='org.freedesktop.DBus',"
905                                 "member='NameOwnerChanged',"
906                                 "arg1='",
907                                 unique,
908                                 "'",
909                                 NULL);
910                 if (!match) {
911                         log_oom();
912                         goto finish;
913                 }
914
915                 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
916                 if (r < 0) {
917                         log_error_errno(r, "Failed to add match for NameLost: %m");
918                         goto finish;
919                 }
920
921                 free(match);
922                 match = strjoin("type='signal',"
923                                 "sender='org.freedesktop.DBus',"
924                                 "path='/org/freedesktop/DBus',"
925                                 "interface='org.freedesktop.DBus',"
926                                 "member='NameOwnerChanged',"
927                                 "arg2='",
928                                 unique,
929                                 "'",
930                                 NULL);
931                 if (!match) {
932                         log_oom();
933                         goto finish;
934                 }
935
936                 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
937                 if (r < 0) {
938                         log_error_errno(r, "Failed to add match for NameAcquired: %m");
939                         goto finish;
940                 }
941         }
942
943         for (;;) {
944                 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
945                 int events_a, events_b, fd;
946                 uint64_t timeout_a, timeout_b, t;
947                 struct timespec _ts, *ts;
948                 struct pollfd *pollfd;
949                 int k;
950
951                 if (got_hello) {
952                         /* Read messages from bus, to pass them on to our client */
953
954                         r = sd_bus_process(a, &m);
955                         if (r < 0) {
956                                 /* treat 'connection reset by peer' as clean exit condition */
957                                 if (r == -ECONNRESET)
958                                         r = 0;
959                                 else
960                                         log_error_errno(r, "Failed to process bus a: %m");
961
962                                 goto finish;
963                         }
964
965                         if (m) {
966                                 bool processed = false;
967
968                                 /* We officially got EOF, let's quit */
969                                 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
970                                         r = 0;
971                                         goto finish;
972                                 }
973
974                                 k = synthesize_name_acquired(a, b, m);
975                                 if (k < 0) {
976                                         r = k;
977                                         log_error_errno(r, "Failed to synthesize message: %m");
978                                         goto finish;
979                                 }
980
981                                 patch_sender(a, m);
982
983                                 if (policy) {
984                                         k = process_policy(a, b, m, policy, &ucred, owned_names);
985                                         if (k < 0) {
986                                                 r = k;
987                                                 log_error_errno(r, "Failed to process policy: %m");
988                                                 goto finish;
989                                         } else if (k > 0) {
990                                                 r = 1;
991                                                 processed = true;
992                                         }
993                                 }
994
995                                 if (!processed) {
996                                         k = sd_bus_send(b, m, NULL);
997                                         if (k < 0) {
998                                                 if (k == -ECONNRESET) {
999                                                         r = 0;
1000                                                         goto finish;
1001                                                 } else if (k == -EPERM && m->reply_cookie > 0) {
1002                                                         /* If the peer tries to send a reply and it is rejected with EPERM
1003                                                          * by the kernel, we ignore the error. This catches cases where the
1004                                                          * original method-call didn't had EXPECT_REPLY set, but the proxy-peer
1005                                                          * still sends a reply. This is allowed in dbus1, but not in kdbus. We
1006                                                          * don't want to track reply-windows in the proxy, so we simply ignore
1007                                                          * EPERM for all replies. The only downside is, that callers are no
1008                                                          * longer notified if their replies are dropped. However, this is
1009                                                          * equivalent to the caller's timeout to expire, so this should be
1010                                                          * acceptable. Nobody sane sends replies without a matching method-call,
1011                                                          * so nobody should care. */
1012                                                         r = 1;
1013                                                 } else {
1014                                                         r = k;
1015                                                         log_error_errno(r, "Failed to send message to client: %m");
1016                                                         goto finish;
1017                                                 }
1018                                         } else
1019                                                 r = 1;
1020                                 }
1021                         }
1022
1023                         if (r > 0)
1024                                 continue;
1025                 }
1026
1027                 /* Read messages from our client, to pass them on to the bus */
1028                 r = sd_bus_process(b, &m);
1029                 if (r < 0) {
1030                         /* treat 'connection reset by peer' as clean exit condition */
1031                         if (r == -ECONNRESET)
1032                                 r = 0;
1033                         else
1034                                 log_error_errno(r, "Failed to process bus b: %m");
1035
1036                         goto finish;
1037                 }
1038
1039                 if (m) {
1040                         bool processed = false;
1041
1042                         /* We officially got EOF, let's quit */
1043                         if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1044                                 r = 0;
1045                                 goto finish;
1046                         }
1047
1048                         k = process_hello(a, b, m, &got_hello);
1049                         if (k < 0) {
1050                                 r = k;
1051                                 log_error_errno(r, "Failed to process HELLO: %m");
1052                                 goto finish;
1053                         } else if (k > 0) {
1054                                 processed = true;
1055                                 r = 1;
1056                         }
1057
1058                         if (!processed) {
1059                                 k = bus_proxy_process_driver(a, b, m, policy, &ucred, owned_names);
1060                                 if (k < 0) {
1061                                         r = k;
1062                                         log_error_errno(r, "Failed to process driver calls: %m");
1063                                         goto finish;
1064                                 } else if (k > 0) {
1065                                         processed = true;
1066                                         r = 1;
1067                                 }
1068
1069                                 if (!processed) {
1070
1071                                         for (;;) {
1072                                                 if (policy) {
1073                                                         k = process_policy(b, a, m, policy, &ucred, owned_names);
1074                                                         if (k < 0) {
1075                                                                 r = k;
1076                                                                 log_error_errno(r, "Failed to process policy: %m");
1077                                                                 goto finish;
1078                                                         } else if (k > 0) {
1079                                                                 processed = true;
1080                                                                 r = 1;
1081                                                                 break;
1082                                                         }
1083                                                 }
1084
1085                                                 k = sd_bus_send(a, m, NULL);
1086                                                 if (k < 0) {
1087                                                         if (k == -EREMCHG) {
1088                                                                 /* The name database changed since the policy check, hence let's check again */
1089                                                                 continue;
1090                                                         } else if (k == -ECONNRESET) {
1091                                                                 r = 0;
1092                                                                 goto finish;
1093                                                         } else if (k == -EPERM && m->reply_cookie > 0) {
1094                                                                 /* see above why EPERM is ignored for replies */
1095                                                                 r = 1;
1096                                                         } else {
1097                                                                 r = k;
1098                                                                 log_error_errno(r, "Failed to send message to bus: %m");
1099                                                                 goto finish;
1100                                                         }
1101                                                 } else
1102                                                         r = 1;
1103
1104                                                 break;
1105                                         }
1106                                 }
1107                         }
1108                 }
1109
1110                 if (r > 0)
1111                         continue;
1112
1113                 fd = sd_bus_get_fd(a);
1114                 if (fd < 0) {
1115                         log_error_errno(r, "Failed to get fd: %m");
1116                         goto finish;
1117                 }
1118
1119                 events_a = sd_bus_get_events(a);
1120                 if (events_a < 0) {
1121                         log_error_errno(r, "Failed to get events mask: %m");
1122                         goto finish;
1123                 }
1124
1125                 r = sd_bus_get_timeout(a, &timeout_a);
1126                 if (r < 0) {
1127                         log_error_errno(r, "Failed to get timeout: %m");
1128                         goto finish;
1129                 }
1130
1131                 events_b = sd_bus_get_events(b);
1132                 if (events_b < 0) {
1133                         log_error_errno(r, "Failed to get events mask: %m");
1134                         goto finish;
1135                 }
1136
1137                 r = sd_bus_get_timeout(b, &timeout_b);
1138                 if (r < 0) {
1139                         log_error_errno(r, "Failed to get timeout: %m");
1140                         goto finish;
1141                 }
1142
1143                 t = timeout_a;
1144                 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
1145                         t = timeout_b;
1146
1147                 if (t == (uint64_t) -1)
1148                         ts = NULL;
1149                 else {
1150                         usec_t nw;
1151
1152                         nw = now(CLOCK_MONOTONIC);
1153                         if (t > nw)
1154                                 t -= nw;
1155                         else
1156                                 t = 0;
1157
1158                         ts = timespec_store(&_ts, t);
1159                 }
1160
1161                 pollfd = (struct pollfd[3]) {
1162                         {.fd = fd,     .events = events_a,           },
1163                         {.fd = in_fd,  .events = events_b & POLLIN,  },
1164                         {.fd = out_fd, .events = events_b & POLLOUT, }
1165                 };
1166
1167                 r = ppoll(pollfd, 3, ts, NULL);
1168                 if (r < 0) {
1169                         log_error_errno(errno, "ppoll() failed: %m");
1170                         goto finish;
1171                 }
1172         }
1173
1174 finish:
1175         sd_notify(false,
1176                   "STOPPING=1\n"
1177                   "STATUS=Shutting down.");
1178
1179         policy_free(&policy_buffer);
1180         strv_free(arg_configuration);
1181         free(arg_address);
1182
1183         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1184 }