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