chiark / gitweb /
build: move stdio-bridge into $PATH
[elogind.git] / src / bus-proxyd / proxy.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   Copyright 2014 David Herrmann
10
11   systemd is free software; you can redistribute it and/or modify it
12   under the terms of the GNU Lesser General Public License as published by
13   the Free Software Foundation; either version 2.1 of the License, or
14   (at your option) any later version.
15
16   systemd is distributed in the hope that it will be useful, but
17   WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19   Lesser General Public License for more details.
20
21   You should have received a copy of the GNU Lesser General Public License
22   along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 ***/
24
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <sys/types.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <sys/poll.h>
33 #include <stddef.h>
34 #include <getopt.h>
35
36 #include "log.h"
37 #include "util.h"
38 #include "socket-util.h"
39 #include "sd-daemon.h"
40 #include "sd-bus.h"
41 #include "bus-internal.h"
42 #include "bus-message.h"
43 #include "bus-util.h"
44 #include "build.h"
45 #include "strv.h"
46 #include "def.h"
47 #include "capability.h"
48 #include "bus-control.h"
49 #include "smack-util.h"
50 #include "set.h"
51 #include "bus-xml-policy.h"
52 #include "driver.h"
53 #include "proxy.h"
54 #include "synthesize.h"
55
56 static int proxy_create_dest(Proxy *p, const char *dest, const char *local_sec, bool negotiate_fds) {
57         _cleanup_bus_close_unref_ sd_bus *b = NULL;
58         int r;
59
60         r = sd_bus_new(&b);
61         if (r < 0)
62                 return log_error_errno(r, "Failed to allocate bus: %m");
63
64         r = sd_bus_set_description(b, "sd-proxy");
65         if (r < 0)
66                 return log_error_errno(r, "Failed to set bus name: %m");
67
68         r = sd_bus_set_address(b, dest);
69         if (r < 0)
70                 return log_error_errno(r, "Failed to set address to connect to: %m");
71
72         r = sd_bus_negotiate_fds(b, negotiate_fds);
73         if (r < 0)
74                 return log_error_errno(r, "Failed to set FD negotiation: %m");
75
76         r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_GID|SD_BUS_CREDS_SELINUX_CONTEXT);
77         if (r < 0)
78                 return log_error_errno(r, "Failed to set credential negotiation: %m");
79
80         if (p->local_creds.pid > 0) {
81                 b->fake_pids.pid = p->local_creds.pid;
82                 b->fake_pids_valid = true;
83
84                 b->fake_creds.uid = p->local_creds.uid;
85                 b->fake_creds.euid = UID_INVALID;
86                 b->fake_creds.suid = UID_INVALID;
87                 b->fake_creds.fsuid = UID_INVALID;
88                 b->fake_creds.gid = p->local_creds.gid;
89                 b->fake_creds.egid = GID_INVALID;
90                 b->fake_creds.sgid = GID_INVALID;
91                 b->fake_creds.fsgid = GID_INVALID;
92                 b->fake_creds_valid = true;
93         }
94
95         if (local_sec) {
96                 b->fake_label = strdup(local_sec);
97                 if (!b->fake_label)
98                         return log_oom();
99         }
100
101         b->manual_peer_interface = true;
102
103         r = sd_bus_start(b);
104         if (r < 0)
105                 return log_error_errno(r, "Failed to start bus client: %m");
106
107         p->dest_bus = b;
108         b = NULL;
109         return 0;
110 }
111
112 static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fds) {
113         _cleanup_bus_close_unref_ sd_bus *b = NULL;
114         sd_id128_t server_id;
115         int r;
116
117         r = sd_bus_new(&b);
118         if (r < 0)
119                 return log_error_errno(r, "Failed to allocate bus: %m");
120
121         r = sd_bus_set_fd(b, in_fd, out_fd);
122         if (r < 0)
123                 return log_error_errno(r, "Failed to set fds: %m");
124
125         r = sd_bus_get_bus_id(p->dest_bus, &server_id);
126         if (r < 0)
127                 return log_error_errno(r, "Failed to get server ID: %m");
128
129         r = sd_bus_set_server(b, 1, server_id);
130         if (r < 0)
131                 return log_error_errno(r, "Failed to set server mode: %m");
132
133         r = sd_bus_negotiate_fds(b, negotiate_fds);
134         if (r < 0)
135                 return log_error_errno(r, "Failed to set FD negotiation: %m");
136
137         r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_GID|SD_BUS_CREDS_SELINUX_CONTEXT);
138         if (r < 0)
139                 return log_error_errno(r, "Failed to set credential negotiation: %m");
140
141         r = sd_bus_set_anonymous(b, true);
142         if (r < 0)
143                 return log_error_errno(r, "Failed to set anonymous authentication: %m");
144
145         b->manual_peer_interface = true;
146
147         r = sd_bus_start(b);
148         if (r < 0)
149                 return log_error_errno(r, "Failed to start bus client: %m");
150
151         p->local_bus = b;
152         b = NULL;
153         return 0;
154 }
155
156 static int proxy_prepare_matches(Proxy *p) {
157         _cleanup_free_ char *match = NULL;
158         const char *unique;
159         int r;
160
161         if (!p->dest_bus->is_kernel)
162                 return 0;
163
164         r = sd_bus_get_unique_name(p->dest_bus, &unique);
165         if (r < 0)
166                 return log_error_errno(r, "Failed to get unique name: %m");
167
168         match = strjoin("type='signal',"
169                         "sender='org.freedesktop.DBus',"
170                         "path='/org/freedesktop/DBus',"
171                         "interface='org.freedesktop.DBus',"
172                         "member='NameOwnerChanged',"
173                         "arg1='",
174                         unique,
175                         "'",
176                         NULL);
177         if (!match)
178                 return log_oom();
179
180         r = sd_bus_add_match(p->dest_bus, NULL, match, NULL, NULL);
181         if (r < 0)
182                 return log_error_errno(r, "Failed to add match for NameLost: %m");
183
184         free(match);
185         match = strjoin("type='signal',"
186                         "sender='org.freedesktop.DBus',"
187                         "path='/org/freedesktop/DBus',"
188                         "interface='org.freedesktop.DBus',"
189                         "member='NameOwnerChanged',"
190                         "arg2='",
191                         unique,
192                         "'",
193                         NULL);
194         if (!match)
195                 return log_oom();
196
197         r = sd_bus_add_match(p->dest_bus, NULL, match, NULL, NULL);
198         if (r < 0)
199                 return log_error_errno(r, "Failed to add match for NameAcquired: %m");
200
201         return 0;
202 }
203
204 int proxy_new(Proxy **out, int in_fd, int out_fd, const char *dest) {
205         _cleanup_(proxy_freep) Proxy *p = NULL;
206         _cleanup_free_ char *local_sec = NULL;
207         bool is_unix;
208         int r;
209
210         p = new0(Proxy, 1);
211         if (!p)
212                 return log_oom();
213
214         p->local_in = in_fd;
215         p->local_out = out_fd;
216
217         p->owned_names = set_new(&string_hash_ops);
218         if (!p->owned_names)
219                 return log_oom();
220
221         is_unix = sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
222                   sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
223
224         if (is_unix) {
225                 (void) getpeercred(in_fd, &p->local_creds);
226                 (void) getpeersec(in_fd, &local_sec);
227         }
228
229         r = proxy_create_dest(p, dest, local_sec, is_unix);
230         if (r < 0)
231                 return r;
232
233         r = proxy_create_local(p, in_fd, out_fd, is_unix);
234         if (r < 0)
235                 return r;
236
237         r = proxy_prepare_matches(p);
238         if (r < 0)
239                 return r;
240
241         *out = p;
242         p = NULL;
243         return 0;
244 }
245
246 Proxy *proxy_free(Proxy *p) {
247         if (!p)
248                 return NULL;
249
250         sd_bus_close_unrefp(&p->local_bus);
251         sd_bus_close_unrefp(&p->dest_bus);
252         set_free_free(p->owned_names);
253         free(p);
254
255         return NULL;
256 }
257
258 int proxy_load_policy(Proxy *p, char **configuration) {
259         _cleanup_strv_free_ char **strv = NULL;
260         int r;
261
262         assert(p);
263
264         /* no need to load legacy policy if destination is not kdbus */
265         if (!p->dest_bus->is_kernel)
266                 return 0;
267
268         if (!configuration) {
269                 const char *scope;
270
271                 r = sd_bus_get_scope(p->dest_bus, &scope);
272                 if (r < 0)
273                         return log_error_errno(r, "Couldn't determine bus scope: %m");
274
275                 if (streq(scope, "system"))
276                         strv = strv_new("/etc/dbus-1/system.conf",
277                                         "/etc/dbus-1/system.d/",
278                                         "/etc/dbus-1/system-local.conf",
279                                         NULL);
280                 else if (streq(scope, "user"))
281                         strv = strv_new("/etc/dbus-1/session.conf",
282                                         "/etc/dbus-1/session.d/",
283                                         "/etc/dbus-1/session-local.conf",
284                                         NULL);
285                 else
286                         return log_error("Unknown scope %s, don't know which policy to load. Refusing.", scope);
287
288                 if (!strv)
289                         return log_oom();
290
291                 configuration = strv;
292         }
293
294         r = policy_load(&p->policy_buffer, configuration);
295         if (r < 0)
296                 return log_error_errno(r, "Failed to load policy: %m");
297
298         p->policy = &p->policy_buffer;
299         /* policy_dump(p->policy); */
300
301         return 0;
302 }
303
304 int proxy_hello_policy(Proxy *p, uid_t original_uid) {
305         assert(p);
306
307         if (!p->policy)
308                 return 0;
309
310         if (p->local_creds.uid == original_uid)
311                 log_debug("Permitting access, since bus owner matches bus client.");
312         else if (policy_check_hello(p->policy, p->local_creds.uid, p->local_creds.gid))
313                 log_debug("Permitting access due to XML policy.");
314         else
315                 return log_error_errno(EPERM, "Policy denied connection.");
316
317         return 0;
318 }
319
320 static int proxy_wait(Proxy *p) {
321         uint64_t timeout_dest, timeout_local, t;
322         int events_dest, events_local, fd;
323         struct timespec _ts, *ts;
324         struct pollfd *pollfd;
325         int r;
326
327         assert(p);
328
329         fd = sd_bus_get_fd(p->dest_bus);
330         if (fd < 0)
331                 return log_error_errno(fd, "Failed to get fd: %m");
332
333         events_dest = sd_bus_get_events(p->dest_bus);
334         if (events_dest < 0)
335                 return log_error_errno(events_dest, "Failed to get events mask: %m");
336
337         r = sd_bus_get_timeout(p->dest_bus, &timeout_dest);
338         if (r < 0)
339                 return log_error_errno(r, "Failed to get timeout: %m");
340
341         events_local = sd_bus_get_events(p->local_bus);
342         if (events_local < 0)
343                 return log_error_errno(events_local, "Failed to get events mask: %m");
344
345         r = sd_bus_get_timeout(p->local_bus, &timeout_local);
346         if (r < 0)
347                 return log_error_errno(r, "Failed to get timeout: %m");
348
349         t = timeout_dest;
350         if (t == (uint64_t) -1 || (timeout_local != (uint64_t) -1 && timeout_local < timeout_dest))
351                 t = timeout_local;
352
353         if (t == (uint64_t) -1)
354                 ts = NULL;
355         else {
356                 usec_t nw;
357
358                 nw = now(CLOCK_MONOTONIC);
359                 if (t > nw)
360                         t -= nw;
361                 else
362                         t = 0;
363
364                 ts = timespec_store(&_ts, t);
365         }
366
367         pollfd = (struct pollfd[3]) {
368                 { .fd = fd,           .events = events_dest,            },
369                 { .fd = p->local_in,  .events = events_local & POLLIN,  },
370                 { .fd = p->local_out, .events = events_local & POLLOUT, },
371         };
372
373         r = ppoll(pollfd, 3, ts, NULL);
374         if (r < 0)
375                 return log_error_errno(errno, "ppoll() failed: %m");
376
377         return 0;
378 }
379
380 static int handle_policy_error(sd_bus_message *m, int r) {
381         if (r == -ESRCH || r == -ENXIO)
382                 return synthetic_reply_method_errorf(m, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", m->destination);
383
384         return r;
385 }
386
387 static int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, Policy *policy, const struct ucred *our_ucred, Set *owned_names) {
388         int r;
389
390         assert(from);
391         assert(to);
392         assert(m);
393
394         if (!policy)
395                 return 0;
396
397         /*
398          * dbus-1 distinguishes expected and non-expected replies by tracking
399          * method-calls and timeouts. By default, DENY rules are *NEVER* applied
400          * on expected replies, unless explicitly specified. But we dont track
401          * method-calls, thus, we cannot know whether a reply is expected.
402          * Fortunately, the kdbus forbids non-expected replies, so we can safely
403          * ignore any policy on those and let the kernel deal with it.
404          *
405          * TODO: To be correct, we should only ignore policy-tags that are
406          * applied on non-expected replies. However, so far we don't parse those
407          * tags so we let everything pass. I haven't seen a DENY policy tag on
408          * expected-replies, ever, so don't bother..
409          */
410         if (m->reply_cookie > 0)
411                 return 0;
412
413         if (from->is_kernel) {
414                 uid_t sender_uid = UID_INVALID;
415                 gid_t sender_gid = GID_INVALID;
416                 char **sender_names = NULL;
417                 bool granted = false;
418
419                 /* Driver messages are always OK */
420                 if (streq_ptr(m->sender, "org.freedesktop.DBus"))
421                         return 0;
422
423                 /* The message came from the kernel, and is sent to our legacy client. */
424                 sd_bus_creds_get_well_known_names(&m->creds, &sender_names);
425
426                 (void) sd_bus_creds_get_uid(&m->creds, &sender_uid);
427                 (void) sd_bus_creds_get_gid(&m->creds, &sender_gid);
428
429                 if (sender_uid == UID_INVALID || sender_gid == GID_INVALID) {
430                         _cleanup_bus_creds_unref_ sd_bus_creds *sender_creds = NULL;
431
432                         /* If the message came from another legacy
433                          * client, then the message creds will be
434                          * missing, simply because on legacy clients
435                          * per-message creds were unknown. In this
436                          * case, query the creds of the peer
437                          * instead. */
438
439                         r = bus_get_name_creds_kdbus(from, m->sender, SD_BUS_CREDS_UID|SD_BUS_CREDS_GID, true, &sender_creds);
440                         if (r < 0)
441                                 return handle_policy_error(m, r);
442
443                         (void) sd_bus_creds_get_uid(sender_creds, &sender_uid);
444                         (void) sd_bus_creds_get_gid(sender_creds, &sender_gid);
445                 }
446
447                 /* First check whether the sender can send the message to our name */
448                 if (set_isempty(owned_names)) {
449                         if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, NULL, m->path, m->interface, m->member, false))
450                                 granted = true;
451                 } else {
452                         Iterator i;
453                         char *n;
454
455                         SET_FOREACH(n, owned_names, i)
456                                 if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, n, m->path, m->interface, m->member, false)) {
457                                         granted = true;
458                                         break;
459                                 }
460                 }
461
462                 if (granted) {
463                         /* Then check whether us (the recipient) can receive from the sender's name */
464                         if (strv_isempty(sender_names)) {
465                                 if (policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, m->path, m->interface, m->member, false))
466                                         return 0;
467                         } else {
468                                 char **n;
469
470                                 STRV_FOREACH(n, sender_names) {
471                                         if (policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, *n, m->path, m->interface, m->member, false))
472                                                 return 0;
473                                 }
474                         }
475                 }
476
477                 /* Return an error back to the caller */
478                 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
479                         return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML receiver policy.");
480
481                 /* Return 1, indicating that the message shall not be processed any further */
482                 return 1;
483         }
484
485         if (to->is_kernel) {
486                 _cleanup_bus_creds_unref_ sd_bus_creds *destination_creds = NULL;
487                 uid_t destination_uid = UID_INVALID;
488                 gid_t destination_gid = GID_INVALID;
489                 const char *destination_unique = NULL;
490                 char **destination_names = NULL;
491                 bool granted = false;
492
493                 /* Driver messages are always OK */
494                 if (streq_ptr(m->destination, "org.freedesktop.DBus"))
495                         return 0;
496
497                 /* The message came from the legacy client, and is sent to kdbus. */
498                 if (m->destination) {
499                         r = bus_get_name_creds_kdbus(to, m->destination,
500                                                      SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME|
501                                                      SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID,
502                                                      true, &destination_creds);
503                         if (r < 0)
504                                 return handle_policy_error(m, r);
505
506                         r = sd_bus_creds_get_unique_name(destination_creds, &destination_unique);
507                         if (r < 0)
508                                 return handle_policy_error(m, r);
509
510                         sd_bus_creds_get_well_known_names(destination_creds, &destination_names);
511
512                         (void) sd_bus_creds_get_uid(destination_creds, &destination_uid);
513                         (void) sd_bus_creds_get_gid(destination_creds, &destination_gid);
514                 }
515
516                 /* First check if we (the sender) can send to this name */
517                 if (strv_isempty(destination_names)) {
518                         if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, m->path, m->interface, m->member, true))
519                                 granted = true;
520                 } else {
521                         char **n;
522
523                         STRV_FOREACH(n, destination_names) {
524                                 if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, *n, m->path, m->interface, m->member, true)) {
525
526                                         /* If we made a receiver decision,
527                                            then remember which name's policy
528                                            we used, and to which unique ID it
529                                            mapped when we made the
530                                            decision. Then, let's pass this to
531                                            the kernel when sending the
532                                            message, so that it refuses the
533                                            operation should the name and
534                                            unique ID not map to each other
535                                            anymore. */
536
537                                         r = free_and_strdup(&m->destination_ptr, *n);
538                                         if (r < 0)
539                                                 return r;
540
541                                         r = bus_kernel_parse_unique_name(destination_unique, &m->verify_destination_id);
542                                         if (r < 0)
543                                                 break;
544
545                                         granted = true;
546                                         break;
547                                 }
548                         }
549                 }
550
551                 /* Then check if the recipient can receive from our name */
552                 if (granted) {
553                         if (sd_bus_message_is_signal(m, NULL, NULL)) {
554                                 /* If we forward a signal from dbus-1 to kdbus,
555                                  * we have no idea who the recipient is.
556                                  * Therefore, we cannot apply any dbus-1
557                                  * receiver policies that match on receiver
558                                  * credentials. We know sd-bus always sets
559                                  * KDBUS_MSG_SIGNAL, so the kernel applies
560                                  * receiver policies to the message. Therefore,
561                                  * skip policy checks in this case. */
562                                 return 0;
563                         } else if (set_isempty(owned_names)) {
564                                 if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, NULL, m->path, m->interface, m->member, true))
565                                         return 0;
566                         } else {
567                                 Iterator i;
568                                 char *n;
569
570                                 SET_FOREACH(n, owned_names, i)
571                                         if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, n, m->path, m->interface, m->member, true))
572                                                 return 0;
573                         }
574                 }
575
576                 /* Return an error back to the caller */
577                 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
578                         return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML sender policy.");
579
580                 /* Return 1, indicating that the message shall not be processed any further */
581                 return 1;
582         }
583
584         return 0;
585 }
586
587 static int process_hello(Proxy *p, sd_bus_message *m) {
588         _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
589         bool is_hello;
590         int r;
591
592         assert(p);
593         assert(m);
594
595         /* As reaction to hello we need to respond with two messages:
596          * the callback reply and the NameAcquired for the unique
597          * name, since hello is otherwise obsolete on kdbus. */
598
599         is_hello =
600                 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
601                 streq_ptr(m->destination, "org.freedesktop.DBus");
602
603         if (!is_hello) {
604                 if (p->got_hello)
605                         return 0;
606
607                 return log_error_errno(-EIO, "First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
608         }
609
610         if (p->got_hello)
611                 return log_error_errno(-EIO, "Got duplicate hello, aborting.");
612
613         p->got_hello = true;
614
615         if (!p->dest_bus->is_kernel)
616                 return 0;
617
618         r = sd_bus_message_new_method_return(m, &n);
619         if (r < 0)
620                 return log_error_errno(r, "Failed to generate HELLO reply: %m");
621
622         r = sd_bus_message_append(n, "s", p->dest_bus->unique_name);
623         if (r < 0)
624                 return log_error_errno(r, "Failed to append unique name to HELLO reply: %m");
625
626         r = bus_message_append_sender(n, "org.freedesktop.DBus");
627         if (r < 0)
628                 return log_error_errno(r, "Failed to append sender to HELLO reply: %m");
629
630         r = bus_seal_synthetic_message(p->local_bus, n);
631         if (r < 0)
632                 return log_error_errno(r, "Failed to seal HELLO reply: %m");
633
634         r = sd_bus_send(p->local_bus, n, NULL);
635         if (r < 0)
636                 return log_error_errno(r, "Failed to send HELLO reply: %m");
637
638         n = sd_bus_message_unref(n);
639         r = sd_bus_message_new_signal(
640                         p->local_bus,
641                         &n,
642                         "/org/freedesktop/DBus",
643                         "org.freedesktop.DBus",
644                         "NameAcquired");
645         if (r < 0)
646                 return log_error_errno(r, "Failed to allocate initial NameAcquired message: %m");
647
648         r = sd_bus_message_append(n, "s", p->dest_bus->unique_name);
649         if (r < 0)
650                 return log_error_errno(r, "Failed to append unique name to NameAcquired message: %m");
651
652         r = bus_message_append_sender(n, "org.freedesktop.DBus");
653         if (r < 0)
654                 return log_error_errno(r, "Failed to append sender to NameAcquired message: %m");
655
656         r = bus_seal_synthetic_message(p->local_bus, n);
657         if (r < 0)
658                 return log_error_errno(r, "Failed to seal NameAcquired message: %m");
659
660         r = sd_bus_send(p->local_bus, n, NULL);
661         if (r < 0)
662                 return log_error_errno(r, "Failed to send NameAcquired message: %m");
663
664         return 1;
665 }
666
667 static int patch_sender(sd_bus *a, sd_bus_message *m) {
668         char **well_known = NULL;
669         sd_bus_creds *c;
670         int r;
671
672         assert(a);
673         assert(m);
674
675         if (!a->is_kernel)
676                 return 0;
677
678         /* We will change the sender of messages from the bus driver
679          * so that they originate from the bus driver. This is a
680          * speciality originating from dbus1, where the bus driver did
681          * not have a unique id, but only the well-known name. */
682
683         c = sd_bus_message_get_creds(m);
684         if (!c)
685                 return 0;
686
687         r = sd_bus_creds_get_well_known_names(c, &well_known);
688         if (r < 0)
689                 return r;
690
691         if (strv_contains(well_known, "org.freedesktop.DBus"))
692                 m->sender = "org.freedesktop.DBus";
693
694         return 0;
695 }
696
697 static int proxy_process_dest_to_local(Proxy *p) {
698         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
699         int r;
700
701         assert(p);
702
703         r = sd_bus_process(p->dest_bus, &m);
704         if (r < 0) {
705                 /* treat 'connection reset by peer' as clean exit condition */
706                 if (r != -ECONNRESET)
707                         log_error_errno(r, "Failed to process destination bus: %m");
708                 return r;
709         }
710
711         if (r == 0)
712                 return 0;
713         if (!m)
714                 return 1;
715
716         /* We officially got EOF, let's quit */
717         if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
718                 return -ECONNRESET;
719
720         r = synthesize_name_acquired(p->dest_bus, p->local_bus, m);
721         if (r < 0)
722                 return log_error_errno(r, "Failed to synthesize message: %m");
723
724         patch_sender(p->dest_bus, m);
725
726         if (p->policy) {
727                 r = process_policy(p->dest_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
728                 if (r < 0)
729                         return log_error_errno(r, "Failed to process policy: %m");
730                 else if (r > 0)
731                         return 1;
732         }
733
734         r = sd_bus_send(p->local_bus, m, NULL);
735         if (r < 0) {
736                 if (r == -EPERM && m->reply_cookie > 0) {
737                         /* If the peer tries to send a reply and it is rejected with EPERM
738                          * by the kernel, we ignore the error. This catches cases where the
739                          * original method-call didn't had EXPECT_REPLY set, but the proxy-peer
740                          * still sends a reply. This is allowed in dbus1, but not in kdbus. We
741                          * don't want to track reply-windows in the proxy, so we simply ignore
742                          * EPERM for all replies. The only downside is, that callers are no
743                          * longer notified if their replies are dropped. However, this is
744                          * equivalent to the caller's timeout to expire, so this should be
745                          * acceptable. Nobody sane sends replies without a matching method-call,
746                          * so nobody should care. */
747                         return 1;
748                 } else {
749                         if (r != -ECONNRESET)
750                                 log_error_errno(r, "Failed to send message to client: %m");
751                         return r;
752                 }
753         }
754
755         return 1;
756 }
757
758 static int proxy_process_local_to_dest(Proxy *p) {
759         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
760         int r;
761
762         assert(p);
763
764         r = sd_bus_process(p->local_bus, &m);
765         if (r < 0) {
766                 /* treat 'connection reset by peer' as clean exit condition */
767                 if (r != -ECONNRESET)
768                         log_error_errno(r, "Failed to process local bus: %m");
769                 return r;
770         }
771
772         if (r == 0)
773                 return 0;
774         if (!m)
775                 return 1;
776
777         /* We officially got EOF, let's quit */
778         if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
779                 return -ECONNRESET;
780
781         r = process_hello(p, m);
782         if (r < 0)
783                 return log_error_errno(r, "Failed to process HELLO: %m");
784         else if (r > 0)
785                 return 1;
786
787         r = bus_proxy_process_driver(p->dest_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
788         if (r < 0)
789                 return log_error_errno(r, "Failed to process driver calls: %m");
790         else if (r > 0)
791                 return 1;
792
793         for (;;) {
794                 if (p->policy) {
795                         r = process_policy(p->local_bus, p->dest_bus, m, p->policy, &p->local_creds, p->owned_names);
796                         if (r < 0)
797                                 return log_error_errno(r, "Failed to process policy: %m");
798                         else if (r > 0)
799                                 return 1;
800                 }
801
802                 r = sd_bus_send(p->dest_bus, m, NULL);
803                 if (r < 0) {
804                         if (r == -EREMCHG) {
805                                 /* The name database changed since the policy check, hence let's check again */
806                                 continue;
807                         } else if (r == -EPERM && m->reply_cookie > 0) {
808                                 /* see above why EPERM is ignored for replies */
809                                 return 1;
810                         } else {
811                                 if (r != -ECONNRESET)
812                                         log_error_errno(r, "Failed to send message to bus: %m");
813                                 return r;
814                         }
815                 }
816
817                 break;
818         }
819
820         return 1;
821 }
822
823 int proxy_run(Proxy *p) {
824         int r;
825
826         assert(p);
827
828         for (;;) {
829                 bool busy = false;
830
831                 if (p->got_hello) {
832                         /* Read messages from bus, to pass them on to our client */
833                         r = proxy_process_dest_to_local(p);
834                         if (r == -ECONNRESET)
835                                 return 0;
836                         else if (r < 0)
837                                 return r;
838                         else if (r > 0)
839                                 busy = true;
840                 }
841
842                 /* Read messages from our client, to pass them on to the bus */
843                 r = proxy_process_local_to_dest(p);
844                 if (r == -ECONNRESET)
845                         return 0;
846                 else if (r < 0)
847                         return r;
848                 else if (r > 0)
849                         busy = true;
850
851                 if (!busy) {
852                         r = proxy_wait(p);
853                         if (r < 0)
854                                 return r;
855                 }
856         }
857
858         return 0;
859 }