chiark / gitweb /
bus-proxy: be more verbose if messages cannot be forwarded
[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 <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_destination(Proxy *p, const char *destination, 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, destination);
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_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|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 = UID_INVALID;
85                 b->fake_creds.euid = p->local_creds.uid;
86                 b->fake_creds.suid = UID_INVALID;
87                 b->fake_creds.fsuid = UID_INVALID;
88                 b->fake_creds.gid = GID_INVALID;
89                 b->fake_creds.egid = p->local_creds.gid;
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->destination_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->destination_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_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|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->destination_bus->is_kernel)
162                 return 0;
163
164         r = sd_bus_get_unique_name(p->destination_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->destination_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->destination_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 *destination) {
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_destination(p, destination, 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->destination_bus);
252         set_free_free(p->owned_names);
253         free(p);
254
255         return NULL;
256 }
257
258 int proxy_set_policy(Proxy *p, SharedPolicy *sp, char **configuration) {
259         _cleanup_strv_free_ char **strv = NULL;
260         Policy *policy;
261         int r;
262
263         assert(p);
264         assert(sp);
265
266         /* no need to load legacy policy if destination is not kdbus */
267         if (!p->destination_bus->is_kernel)
268                 return 0;
269
270         p->policy = sp;
271
272         policy = shared_policy_acquire(sp);
273         if (policy) {
274                 /* policy already pre-loaded */
275                 shared_policy_release(sp, policy);
276                 return 0;
277         }
278
279         if (!configuration) {
280                 const char *scope;
281
282                 r = sd_bus_get_scope(p->destination_bus, &scope);
283                 if (r < 0)
284                         return log_error_errno(r, "Couldn't determine bus scope: %m");
285
286                 if (streq(scope, "system"))
287                         strv = strv_new("/etc/dbus-1/system.conf",
288                                         "/etc/dbus-1/system.d/",
289                                         "/etc/dbus-1/system-local.conf",
290                                         NULL);
291                 else if (streq(scope, "user"))
292                         strv = strv_new("/etc/dbus-1/session.conf",
293                                         "/etc/dbus-1/session.d/",
294                                         "/etc/dbus-1/session-local.conf",
295                                         NULL);
296                 else
297                         return log_error("Unknown scope %s, don't know which policy to load. Refusing.", scope);
298
299                 if (!strv)
300                         return log_oom();
301
302                 configuration = strv;
303         }
304
305         return shared_policy_preload(sp, configuration);
306 }
307
308 int proxy_hello_policy(Proxy *p, uid_t original_uid) {
309         Policy *policy;
310         int r = 0;
311
312         assert(p);
313
314         if (!p->policy)
315                 return 0;
316
317         policy = shared_policy_acquire(p->policy);
318
319         if (p->local_creds.uid == original_uid)
320                 log_debug("Permitting access, since bus owner matches bus client.");
321         else if (policy_check_hello(policy, p->local_creds.uid, p->local_creds.gid))
322                 log_debug("Permitting access due to XML policy.");
323         else
324                 r = log_error_errno(EPERM, "Policy denied connection.");
325
326         shared_policy_release(p->policy, policy);
327
328         return r;
329 }
330
331 static int proxy_wait(Proxy *p) {
332         uint64_t timeout_destination, timeout_local, t;
333         int events_destination, events_local, fd;
334         struct timespec _ts, *ts;
335         struct pollfd *pollfd;
336         int r;
337
338         assert(p);
339
340         fd = sd_bus_get_fd(p->destination_bus);
341         if (fd < 0)
342                 return log_error_errno(fd, "Failed to get fd: %m");
343
344         events_destination = sd_bus_get_events(p->destination_bus);
345         if (events_destination < 0)
346                 return log_error_errno(events_destination, "Failed to get events mask: %m");
347
348         r = sd_bus_get_timeout(p->destination_bus, &timeout_destination);
349         if (r < 0)
350                 return log_error_errno(r, "Failed to get timeout: %m");
351
352         events_local = sd_bus_get_events(p->local_bus);
353         if (events_local < 0)
354                 return log_error_errno(events_local, "Failed to get events mask: %m");
355
356         r = sd_bus_get_timeout(p->local_bus, &timeout_local);
357         if (r < 0)
358                 return log_error_errno(r, "Failed to get timeout: %m");
359
360         t = timeout_destination;
361         if (t == (uint64_t) -1 || (timeout_local != (uint64_t) -1 && timeout_local < timeout_destination))
362                 t = timeout_local;
363
364         if (t == (uint64_t) -1)
365                 ts = NULL;
366         else {
367                 usec_t nw;
368
369                 nw = now(CLOCK_MONOTONIC);
370                 if (t > nw)
371                         t -= nw;
372                 else
373                         t = 0;
374
375                 ts = timespec_store(&_ts, t);
376         }
377
378         pollfd = (struct pollfd[3]) {
379                 { .fd = fd,           .events = events_destination,     },
380                 { .fd = p->local_in,  .events = events_local & POLLIN,  },
381                 { .fd = p->local_out, .events = events_local & POLLOUT, },
382         };
383
384         r = ppoll(pollfd, 3, ts, NULL);
385         if (r < 0)
386                 return log_error_errno(errno, "ppoll() failed: %m");
387
388         return 0;
389 }
390
391 static int handle_policy_error(sd_bus_message *m, int r) {
392         if (r == -ESRCH || r == -ENXIO)
393                 return synthetic_reply_method_errorf(m, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", m->destination);
394
395         return r;
396 }
397
398 static int process_policy_unlocked(sd_bus *from, sd_bus *to, sd_bus_message *m, Policy *policy, const struct ucred *our_ucred, Set *owned_names) {
399         int r;
400
401         assert(from);
402         assert(to);
403         assert(m);
404
405         if (!policy)
406                 return 0;
407
408         /*
409          * dbus-1 distinguishes expected and non-expected replies by tracking
410          * method-calls and timeouts. By default, DENY rules are *NEVER* applied
411          * on expected replies, unless explicitly specified. But we dont track
412          * method-calls, thus, we cannot know whether a reply is expected.
413          * Fortunately, the kdbus forbids non-expected replies, so we can safely
414          * ignore any policy on those and let the kernel deal with it.
415          *
416          * TODO: To be correct, we should only ignore policy-tags that are
417          * applied on non-expected replies. However, so far we don't parse those
418          * tags so we let everything pass. I haven't seen a DENY policy tag on
419          * expected-replies, ever, so don't bother..
420          */
421         if (m->reply_cookie > 0)
422                 return 0;
423
424         if (from->is_kernel) {
425                 uid_t sender_uid = UID_INVALID;
426                 gid_t sender_gid = GID_INVALID;
427                 char **sender_names = NULL;
428
429                 /* Driver messages are always OK */
430                 if (streq_ptr(m->sender, "org.freedesktop.DBus"))
431                         return 0;
432
433                 /* The message came from the kernel, and is sent to our legacy client. */
434                 (void) sd_bus_creds_get_well_known_names(&m->creds, &sender_names);
435
436                 (void) sd_bus_creds_get_euid(&m->creds, &sender_uid);
437                 (void) sd_bus_creds_get_egid(&m->creds, &sender_gid);
438
439                 if (sender_uid == UID_INVALID || sender_gid == GID_INVALID) {
440                         _cleanup_bus_creds_unref_ sd_bus_creds *sender_creds = NULL;
441
442                         /* If the message came from another legacy
443                          * client, then the message creds will be
444                          * missing, simply because on legacy clients
445                          * per-message creds were unknown. In this
446                          * case, query the creds of the peer
447                          * instead. */
448
449                         r = bus_get_name_creds_kdbus(from, m->sender, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID, true, &sender_creds);
450                         if (r < 0)
451                                 return handle_policy_error(m, r);
452
453                         (void) sd_bus_creds_get_euid(sender_creds, &sender_uid);
454                         (void) sd_bus_creds_get_egid(sender_creds, &sender_gid);
455                 }
456
457                 /* First check whether the sender can send the message to our name */
458                 if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, false, NULL) &&
459                     policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, sender_names, m->path, m->interface, m->member, false))
460                         return 0;
461
462                 /* Return an error back to the caller */
463                 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
464                         return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML receiver policy.");
465
466                 /* Return 1, indicating that the message shall not be processed any further */
467                 return 1;
468         }
469
470         if (to->is_kernel) {
471                 _cleanup_bus_creds_unref_ sd_bus_creds *destination_creds = NULL;
472                 uid_t destination_uid = UID_INVALID;
473                 gid_t destination_gid = GID_INVALID;
474                 const char *destination_unique = NULL;
475                 char **destination_names = NULL;
476                 char *n;
477
478                 /* Driver messages are always OK */
479                 if (streq_ptr(m->destination, "org.freedesktop.DBus"))
480                         return 0;
481
482                 /* The message came from the legacy client, and is sent to kdbus. */
483                 if (m->destination) {
484                         r = bus_get_name_creds_kdbus(to, m->destination,
485                                                      SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME|
486                                                      SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID,
487                                                      true, &destination_creds);
488                         if (r < 0)
489                                 return handle_policy_error(m, r);
490
491                         r = sd_bus_creds_get_unique_name(destination_creds, &destination_unique);
492                         if (r < 0)
493                                 return handle_policy_error(m, r);
494
495                         (void) sd_bus_creds_get_well_known_names(destination_creds, &destination_names);
496
497                         (void) sd_bus_creds_get_euid(destination_creds, &destination_uid);
498                         (void) sd_bus_creds_get_egid(destination_creds, &destination_gid);
499                 }
500
501                 /* First check if we (the sender) can send to this name */
502                 if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, destination_names, m->path, m->interface, m->member, true, &n)) {
503                         if (n) {
504                                 /* If we made a receiver decision, then remember which
505                                  * name's policy we used, and to which unique ID it
506                                  * mapped when we made the decision. Then, let's pass
507                                  * this to the kernel when sending the message, so that
508                                  * it refuses the operation should the name and unique
509                                  * ID not map to each other anymore. */
510
511                                 r = free_and_strdup(&m->destination_ptr, n);
512                                 if (r < 0)
513                                         return r;
514
515                                 r = bus_kernel_parse_unique_name(destination_unique, &m->verify_destination_id);
516                                 if (r < 0)
517                                         return r;
518                         }
519
520                         if (sd_bus_message_is_signal(m, NULL, NULL)) {
521                                 /* If we forward a signal from dbus-1 to kdbus,
522                                  * we have no idea who the recipient is.
523                                  * Therefore, we cannot apply any dbus-1
524                                  * receiver policies that match on receiver
525                                  * credentials. We know sd-bus always sets
526                                  * KDBUS_MSG_SIGNAL, so the kernel applies
527                                  * receiver policies to the message. Therefore,
528                                  * skip policy checks in this case. */
529                                 return 0;
530                         } else if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, true)) {
531                                 return 0;
532                         }
533                 }
534
535                 /* Return an error back to the caller */
536                 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
537                         return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML sender policy.");
538
539                 /* Return 1, indicating that the message shall not be processed any further */
540                 return 1;
541         }
542
543         return 0;
544 }
545
546 static int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, SharedPolicy *sp, const struct ucred *our_ucred, Set *owned_names) {
547         Policy *policy;
548         int r;
549
550         assert(sp);
551
552         policy = shared_policy_acquire(sp);
553         r = process_policy_unlocked(from, to, m, policy, our_ucred, owned_names);
554         shared_policy_release(sp, policy);
555
556         return r;
557 }
558
559 static int process_hello(Proxy *p, sd_bus_message *m) {
560         _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
561         bool is_hello;
562         int r;
563
564         assert(p);
565         assert(m);
566
567         /* As reaction to hello we need to respond with two messages:
568          * the callback reply and the NameAcquired for the unique
569          * name, since hello is otherwise obsolete on kdbus. */
570
571         is_hello =
572                 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
573                 streq_ptr(m->destination, "org.freedesktop.DBus");
574
575         if (!is_hello) {
576                 if (p->got_hello)
577                         return 0;
578
579                 return log_error_errno(EIO, "First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
580         }
581
582         if (p->got_hello)
583                 return log_error_errno(EIO, "Got duplicate hello, aborting.");
584
585         p->got_hello = true;
586
587         if (!p->destination_bus->is_kernel)
588                 return 0;
589
590         r = sd_bus_message_new_method_return(m, &n);
591         if (r < 0)
592                 return log_error_errno(r, "Failed to generate HELLO reply: %m");
593
594         r = sd_bus_message_append(n, "s", p->destination_bus->unique_name);
595         if (r < 0)
596                 return log_error_errno(r, "Failed to append unique name to HELLO reply: %m");
597
598         r = bus_message_append_sender(n, "org.freedesktop.DBus");
599         if (r < 0)
600                 return log_error_errno(r, "Failed to append sender to HELLO reply: %m");
601
602         r = bus_seal_synthetic_message(p->local_bus, n);
603         if (r < 0)
604                 return log_error_errno(r, "Failed to seal HELLO reply: %m");
605
606         r = sd_bus_send(p->local_bus, n, NULL);
607         if (r < 0)
608                 return log_error_errno(r, "Failed to send HELLO reply: %m");
609
610         n = sd_bus_message_unref(n);
611         r = sd_bus_message_new_signal(
612                         p->local_bus,
613                         &n,
614                         "/org/freedesktop/DBus",
615                         "org.freedesktop.DBus",
616                         "NameAcquired");
617         if (r < 0)
618                 return log_error_errno(r, "Failed to allocate initial NameAcquired message: %m");
619
620         r = sd_bus_message_append(n, "s", p->destination_bus->unique_name);
621         if (r < 0)
622                 return log_error_errno(r, "Failed to append unique name to NameAcquired message: %m");
623
624         r = bus_message_append_sender(n, "org.freedesktop.DBus");
625         if (r < 0)
626                 return log_error_errno(r, "Failed to append sender to NameAcquired message: %m");
627
628         r = bus_seal_synthetic_message(p->local_bus, n);
629         if (r < 0)
630                 return log_error_errno(r, "Failed to seal NameAcquired message: %m");
631
632         r = sd_bus_send(p->local_bus, n, NULL);
633         if (r < 0)
634                 return log_error_errno(r, "Failed to send NameAcquired message: %m");
635
636         return 1;
637 }
638
639 static int patch_sender(sd_bus *a, sd_bus_message *m) {
640         char **well_known = NULL;
641         sd_bus_creds *c;
642         int r;
643
644         assert(a);
645         assert(m);
646
647         if (!a->is_kernel)
648                 return 0;
649
650         /* We will change the sender of messages from the bus driver
651          * so that they originate from the bus driver. This is a
652          * speciality originating from dbus1, where the bus driver did
653          * not have a unique id, but only the well-known name. */
654
655         c = sd_bus_message_get_creds(m);
656         if (!c)
657                 return 0;
658
659         r = sd_bus_creds_get_well_known_names(c, &well_known);
660         if (r < 0)
661                 return r;
662
663         if (strv_contains(well_known, "org.freedesktop.DBus"))
664                 m->sender = "org.freedesktop.DBus";
665
666         return 0;
667 }
668
669 static int proxy_process_destination_to_local(Proxy *p) {
670         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
671         int r;
672
673         assert(p);
674
675         r = sd_bus_process(p->destination_bus, &m);
676         if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
677                 return r;
678         if (r < 0) {
679                 log_error_errno(r, "Failed to process destination bus: %m");
680                 return r;
681         }
682         if (r == 0)
683                 return 0;
684         if (!m)
685                 return 1;
686
687         /* We officially got EOF, let's quit */
688         if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
689                 return -ECONNRESET;
690
691         r = synthesize_name_acquired(p->destination_bus, p->local_bus, m);
692         if (r == -ECONNRESET || r == -ENOTCONN)
693                 return r;
694         if (r < 0)
695                 return log_error_errno(r, "Failed to synthesize message: %m");
696
697         patch_sender(p->destination_bus, m);
698
699         if (p->policy) {
700                 r = process_policy(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
701                 if (r == -ECONNRESET || r == -ENOTCONN)
702                         return r;
703                 if (r < 0)
704                         return log_error_errno(r, "Failed to process policy: %m");
705                 if (r > 0)
706                         return 1;
707         }
708
709         r = sd_bus_send(p->local_bus, m, NULL);
710         if (r < 0) {
711                 if (r == -ECONNRESET || r == -ENOTCONN)
712                         return r;
713
714                 /* If the peer tries to send a reply and it is
715                  * rejected with EPERM by the kernel, we ignore the
716                  * error. This catches cases where the original
717                  * method-call didn't had EXPECT_REPLY set, but the
718                  * proxy-peer still sends a reply. This is allowed in
719                  * dbus1, but not in kdbus. We don't want to track
720                  * reply-windows in the proxy, so we simply ignore
721                  * EPERM for all replies. The only downside is, that
722                  * callers are no longer notified if their replies are
723                  * dropped. However, this is equivalent to the
724                  * caller's timeout to expire, so this should be
725                  * acceptable. Nobody sane sends replies without a
726                  * matching method-call, so nobody should care. */
727                 if (r == -EPERM && m->reply_cookie > 0)
728                         return 1;
729
730                 /* Return the error to the client, if we can */
731                 synthetic_reply_method_errnof(m, r, "Failed to forward message we got from destination: %m");
732                 log_error_errno(r,
733                          "Failed to forward message we got from destination: uid=" UID_FMT " gid=" GID_FMT" message=%s destination=%s path=%s interface=%s member=%s: %m",
734                          p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
735                          strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
736                 return 1;
737         }
738
739         return 1;
740 }
741
742 static int proxy_process_local_to_destination(Proxy *p) {
743         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
744         int r;
745
746         assert(p);
747
748         r = sd_bus_process(p->local_bus, &m);
749         if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
750                 return r;
751         if (r < 0) {
752                 log_error_errno(r, "Failed to process local bus: %m");
753                 return r;
754         }
755         if (r == 0)
756                 return 0;
757         if (!m)
758                 return 1;
759
760         /* We officially got EOF, let's quit */
761         if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
762                 return -ECONNRESET;
763
764         r = process_hello(p, m);
765         if (r == -ECONNRESET || r == -ENOTCONN)
766                 return r;
767         if (r < 0)
768                 return log_error_errno(r, "Failed to process HELLO: %m");
769         if (r > 0)
770                 return 1;
771
772         r = bus_proxy_process_driver(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
773         if (r == -ECONNRESET || r == -ENOTCONN)
774                 return r;
775         if (r < 0)
776                 return log_error_errno(r, "Failed to process driver calls: %m");
777         if (r > 0)
778                 return 1;
779
780         for (;;) {
781                 if (p->policy) {
782                         r = process_policy(p->local_bus, p->destination_bus, m, p->policy, &p->local_creds, p->owned_names);
783                         if (r == -ECONNRESET || r == -ENOTCONN)
784                                 return r;
785                         if (r < 0)
786                                 return log_error_errno(r, "Failed to process policy: %m");
787                         if (r > 0)
788                                 return 1;
789                 }
790
791                 r = sd_bus_send(p->destination_bus, m, NULL);
792                 if (r < 0) {
793                         if (r == -ECONNRESET || r == -ENOTCONN)
794                                 return r;
795
796                         /* The name database changed since the policy check, hence let's check again */
797                         if (r == -EREMCHG)
798                                 continue;
799
800                         /* see above why EPERM is ignored for replies */
801                         if (r == -EPERM && m->reply_cookie > 0)
802                                 return 1;
803
804                         synthetic_reply_method_errnof(m, r, "Failed to forward message we got from local: %m");
805                         log_error_errno(r,
806                                  "Failed to forward message we got from local: uid=" UID_FMT " gid=" GID_FMT" message=%s destination=%s path=%s interface=%s member=%s: %m",
807                                  p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
808                                  strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
809                         return 1;
810                 }
811
812                 break;
813         }
814
815         return 1;
816 }
817
818 int proxy_run(Proxy *p) {
819         int r;
820
821         assert(p);
822
823         for (;;) {
824                 bool busy = false;
825
826                 if (p->got_hello) {
827                         /* Read messages from bus, to pass them on to our client */
828                         r = proxy_process_destination_to_local(p);
829                         if (r == -ECONNRESET || r == -ENOTCONN)
830                                 return 0;
831                         if (r < 0)
832                                 return r;
833                         if (r > 0)
834                                 busy = true;
835                 }
836
837                 /* Read messages from our client, to pass them on to the bus */
838                 r = proxy_process_local_to_destination(p);
839                 if (r == -ECONNRESET || r == -ENOTCONN)
840                         return 0;
841                 if (r < 0)
842                         return r;
843                 if (r > 0)
844                         busy = true;
845
846                 if (!busy) {
847                         r = proxy_wait(p);
848                         if (r == -ECONNRESET || r == -ENOTCONN)
849                                 return 0;
850                         if (r < 0)
851                                 return r;
852                 }
853         }
854
855         return 0;
856 }