]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/bus-proxyd/proxy.c
bus-proxy: make StartServiceByName synchronous
[thirdparty/systemd.git] / src / bus-proxyd / proxy.c
CommitLineData
c0395aeb
DH
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>
c0395aeb 26#include <sys/types.h>
c0395aeb
DH
27#include <string.h>
28#include <errno.h>
0a6f50c0 29#include <poll.h>
c0395aeb
DH
30
31#include "log.h"
32#include "util.h"
c0395aeb
DH
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"
c0395aeb 38#include "strv.h"
c0395aeb 39#include "bus-control.h"
c0395aeb
DH
40#include "set.h"
41#include "bus-xml-policy.h"
42#include "driver.h"
43#include "proxy.h"
44#include "synthesize.h"
6482f626 45#include "formats-util.h"
c0395aeb 46
d27efd93 47static int proxy_create_destination(Proxy *p, const char *destination, const char *local_sec, bool negotiate_fds) {
03976f7b 48 _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
c0395aeb
DH
49 int r;
50
51 r = sd_bus_new(&b);
52 if (r < 0)
53 return log_error_errno(r, "Failed to allocate bus: %m");
54
55 r = sd_bus_set_description(b, "sd-proxy");
56 if (r < 0)
57 return log_error_errno(r, "Failed to set bus name: %m");
58
d27efd93 59 r = sd_bus_set_address(b, destination);
c0395aeb
DH
60 if (r < 0)
61 return log_error_errno(r, "Failed to set address to connect to: %m");
62
63 r = sd_bus_negotiate_fds(b, negotiate_fds);
64 if (r < 0)
65 return log_error_errno(r, "Failed to set FD negotiation: %m");
66
05bae4a6 67 r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SELINUX_CONTEXT);
c0395aeb
DH
68 if (r < 0)
69 return log_error_errno(r, "Failed to set credential negotiation: %m");
70
71 if (p->local_creds.pid > 0) {
72 b->fake_pids.pid = p->local_creds.pid;
73 b->fake_pids_valid = true;
74
d90c154e 75 b->fake_creds.uid = UID_INVALID;
e23f4bb5 76 b->fake_creds.euid = p->local_creds.uid;
d90c154e
DH
77 b->fake_creds.suid = UID_INVALID;
78 b->fake_creds.fsuid = UID_INVALID;
79 b->fake_creds.gid = GID_INVALID;
e23f4bb5 80 b->fake_creds.egid = p->local_creds.gid;
d90c154e
DH
81 b->fake_creds.sgid = GID_INVALID;
82 b->fake_creds.fsgid = GID_INVALID;
c0395aeb
DH
83 b->fake_creds_valid = true;
84 }
85
86 if (local_sec) {
87 b->fake_label = strdup(local_sec);
88 if (!b->fake_label)
89 return log_oom();
90 }
91
92 b->manual_peer_interface = true;
93
94 r = sd_bus_start(b);
95 if (r < 0)
96 return log_error_errno(r, "Failed to start bus client: %m");
97
d27efd93 98 p->destination_bus = b;
c0395aeb
DH
99 b = NULL;
100 return 0;
101}
102
103static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fds) {
03976f7b 104 _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
c0395aeb
DH
105 sd_id128_t server_id;
106 int r;
107
108 r = sd_bus_new(&b);
109 if (r < 0)
110 return log_error_errno(r, "Failed to allocate bus: %m");
111
112 r = sd_bus_set_fd(b, in_fd, out_fd);
113 if (r < 0)
114 return log_error_errno(r, "Failed to set fds: %m");
115
d27efd93 116 r = sd_bus_get_bus_id(p->destination_bus, &server_id);
c0395aeb
DH
117 if (r < 0)
118 return log_error_errno(r, "Failed to get server ID: %m");
119
120 r = sd_bus_set_server(b, 1, server_id);
121 if (r < 0)
122 return log_error_errno(r, "Failed to set server mode: %m");
123
124 r = sd_bus_negotiate_fds(b, negotiate_fds);
125 if (r < 0)
126 return log_error_errno(r, "Failed to set FD negotiation: %m");
127
05bae4a6 128 r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SELINUX_CONTEXT);
c0395aeb
DH
129 if (r < 0)
130 return log_error_errno(r, "Failed to set credential negotiation: %m");
131
132 r = sd_bus_set_anonymous(b, true);
133 if (r < 0)
134 return log_error_errno(r, "Failed to set anonymous authentication: %m");
135
136 b->manual_peer_interface = true;
137
138 r = sd_bus_start(b);
139 if (r < 0)
140 return log_error_errno(r, "Failed to start bus client: %m");
141
142 p->local_bus = b;
143 b = NULL;
144 return 0;
145}
146
e23bc0e7
DH
147static int proxy_match_synthetic(sd_bus_message *m, void *userdata, sd_bus_error *error) {
148 Proxy *p = userdata;
149
150 p->synthetic_matched = true;
151 return 0; /* make sure to continue processing it in further handlers */
152}
153
619b80a1 154/*
e23bc0e7
DH
155 * We always need NameOwnerChanged so we can synthesize NameLost and
156 * NameAcquired. Furthermore, dbus-1 always passes unicast-signals through, so
157 * subscribe unconditionally.
619b80a1 158 */
c0395aeb
DH
159static int proxy_prepare_matches(Proxy *p) {
160 _cleanup_free_ char *match = NULL;
161 const char *unique;
162 int r;
163
d27efd93 164 if (!p->destination_bus->is_kernel)
c0395aeb
DH
165 return 0;
166
d27efd93 167 r = sd_bus_get_unique_name(p->destination_bus, &unique);
c0395aeb
DH
168 if (r < 0)
169 return log_error_errno(r, "Failed to get unique name: %m");
170
171 match = strjoin("type='signal',"
172 "sender='org.freedesktop.DBus',"
173 "path='/org/freedesktop/DBus',"
174 "interface='org.freedesktop.DBus',"
175 "member='NameOwnerChanged',"
176 "arg1='",
177 unique,
178 "'",
179 NULL);
180 if (!match)
181 return log_oom();
182
e23bc0e7 183 r = sd_bus_add_match(p->destination_bus, NULL, match, proxy_match_synthetic, p);
c0395aeb
DH
184 if (r < 0)
185 return log_error_errno(r, "Failed to add match for NameLost: %m");
186
187 free(match);
188 match = strjoin("type='signal',"
189 "sender='org.freedesktop.DBus',"
190 "path='/org/freedesktop/DBus',"
191 "interface='org.freedesktop.DBus',"
192 "member='NameOwnerChanged',"
193 "arg2='",
194 unique,
195 "'",
196 NULL);
197 if (!match)
198 return log_oom();
199
e23bc0e7 200 r = sd_bus_add_match(p->destination_bus, NULL, match, proxy_match_synthetic, p);
c0395aeb
DH
201 if (r < 0)
202 return log_error_errno(r, "Failed to add match for NameAcquired: %m");
203
de865432
KS
204 free(match);
205 match = strjoin("type='signal',"
206 "destination='",
207 unique,
208 "'",
209 NULL);
210 if (!match)
211 return log_oom();
212
e23bc0e7 213 r = sd_bus_add_match(p->destination_bus, NULL, match, proxy_match_synthetic, p);
de865432 214 if (r < 0)
619b80a1
KS
215 log_error_errno(r, "Failed to add match for directed signals: %m");
216 /* FIXME: temporarily ignore error to support older kdbus versions */
de865432 217
c0395aeb
DH
218 return 0;
219}
220
d27efd93 221int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) {
c0395aeb
DH
222 _cleanup_(proxy_freep) Proxy *p = NULL;
223 _cleanup_free_ char *local_sec = NULL;
224 bool is_unix;
225 int r;
226
227 p = new0(Proxy, 1);
228 if (!p)
229 return log_oom();
230
231 p->local_in = in_fd;
232 p->local_out = out_fd;
233
234 p->owned_names = set_new(&string_hash_ops);
235 if (!p->owned_names)
236 return log_oom();
237
238 is_unix = sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
239 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
240
241 if (is_unix) {
242 (void) getpeercred(in_fd, &p->local_creds);
243 (void) getpeersec(in_fd, &local_sec);
244 }
245
d27efd93 246 r = proxy_create_destination(p, destination, local_sec, is_unix);
c0395aeb
DH
247 if (r < 0)
248 return r;
249
250 r = proxy_create_local(p, in_fd, out_fd, is_unix);
251 if (r < 0)
252 return r;
253
254 r = proxy_prepare_matches(p);
255 if (r < 0)
256 return r;
257
258 *out = p;
259 p = NULL;
260 return 0;
261}
262
263Proxy *proxy_free(Proxy *p) {
11f254be
DH
264 ProxyActivation *activation;
265
c0395aeb
DH
266 if (!p)
267 return NULL;
268
11f254be
DH
269 while ((activation = p->activations)) {
270 LIST_REMOVE(activations_by_proxy, p->activations, activation);
271 sd_bus_message_unref(activation->request);
272 sd_bus_slot_unref(activation->slot);
273 free(activation);
274 }
275
03976f7b
LP
276 sd_bus_flush_close_unref(p->local_bus);
277 sd_bus_flush_close_unref(p->destination_bus);
c0395aeb
DH
278 set_free_free(p->owned_names);
279 free(p);
280
281 return NULL;
282}
283
c4bc1a84 284int proxy_set_policy(Proxy *p, SharedPolicy *sp, char **configuration) {
c0395aeb 285 _cleanup_strv_free_ char **strv = NULL;
c4bc1a84 286 Policy *policy;
c0395aeb
DH
287 int r;
288
289 assert(p);
c4bc1a84 290 assert(sp);
c0395aeb
DH
291
292 /* no need to load legacy policy if destination is not kdbus */
d27efd93 293 if (!p->destination_bus->is_kernel)
c0395aeb
DH
294 return 0;
295
c4bc1a84
DH
296 p->policy = sp;
297
298 policy = shared_policy_acquire(sp);
299 if (policy) {
300 /* policy already pre-loaded */
301 shared_policy_release(sp, policy);
302 return 0;
303 }
304
c0395aeb
DH
305 if (!configuration) {
306 const char *scope;
307
d27efd93 308 r = sd_bus_get_scope(p->destination_bus, &scope);
c0395aeb
DH
309 if (r < 0)
310 return log_error_errno(r, "Couldn't determine bus scope: %m");
311
312 if (streq(scope, "system"))
97af81cf
LP
313 strv = strv_new("/usr/share/dbus-1/system.conf",
314 "/etc/dbus-1/system.conf",
315 "/usr/share/dbus-1/system.d/",
c0395aeb
DH
316 "/etc/dbus-1/system.d/",
317 "/etc/dbus-1/system-local.conf",
318 NULL);
319 else if (streq(scope, "user"))
97af81cf
LP
320 strv = strv_new("/usr/share/dbus-1/session.conf",
321 "/etc/dbus-1/session.conf",
322 "/usr/share/dbus-1/session.d/",
c0395aeb
DH
323 "/etc/dbus-1/session.d/",
324 "/etc/dbus-1/session-local.conf",
325 NULL);
326 else
327 return log_error("Unknown scope %s, don't know which policy to load. Refusing.", scope);
328
329 if (!strv)
330 return log_oom();
331
332 configuration = strv;
333 }
334
c4bc1a84 335 return shared_policy_preload(sp, configuration);
c0395aeb
DH
336}
337
338int proxy_hello_policy(Proxy *p, uid_t original_uid) {
c4bc1a84
DH
339 Policy *policy;
340 int r = 0;
341
c0395aeb
DH
342 assert(p);
343
344 if (!p->policy)
345 return 0;
346
c4bc1a84
DH
347 policy = shared_policy_acquire(p->policy);
348
c0395aeb
DH
349 if (p->local_creds.uid == original_uid)
350 log_debug("Permitting access, since bus owner matches bus client.");
c4bc1a84 351 else if (policy_check_hello(policy, p->local_creds.uid, p->local_creds.gid))
c0395aeb
DH
352 log_debug("Permitting access due to XML policy.");
353 else
c4bc1a84 354 r = log_error_errno(EPERM, "Policy denied connection.");
c0395aeb 355
c4bc1a84
DH
356 shared_policy_release(p->policy, policy);
357
358 return r;
c0395aeb
DH
359}
360
361static int proxy_wait(Proxy *p) {
d27efd93
LP
362 uint64_t timeout_destination, timeout_local, t;
363 int events_destination, events_local, fd;
c0395aeb
DH
364 struct timespec _ts, *ts;
365 struct pollfd *pollfd;
366 int r;
367
368 assert(p);
369
d27efd93 370 fd = sd_bus_get_fd(p->destination_bus);
c0395aeb
DH
371 if (fd < 0)
372 return log_error_errno(fd, "Failed to get fd: %m");
373
d27efd93
LP
374 events_destination = sd_bus_get_events(p->destination_bus);
375 if (events_destination < 0)
376 return log_error_errno(events_destination, "Failed to get events mask: %m");
c0395aeb 377
d27efd93 378 r = sd_bus_get_timeout(p->destination_bus, &timeout_destination);
c0395aeb
DH
379 if (r < 0)
380 return log_error_errno(r, "Failed to get timeout: %m");
381
382 events_local = sd_bus_get_events(p->local_bus);
383 if (events_local < 0)
384 return log_error_errno(events_local, "Failed to get events mask: %m");
385
386 r = sd_bus_get_timeout(p->local_bus, &timeout_local);
387 if (r < 0)
388 return log_error_errno(r, "Failed to get timeout: %m");
389
d27efd93
LP
390 t = timeout_destination;
391 if (t == (uint64_t) -1 || (timeout_local != (uint64_t) -1 && timeout_local < timeout_destination))
c0395aeb
DH
392 t = timeout_local;
393
394 if (t == (uint64_t) -1)
395 ts = NULL;
396 else {
397 usec_t nw;
398
399 nw = now(CLOCK_MONOTONIC);
400 if (t > nw)
401 t -= nw;
402 else
403 t = 0;
404
405 ts = timespec_store(&_ts, t);
406 }
407
408 pollfd = (struct pollfd[3]) {
c74f883c 409 { .fd = fd, .events = events_destination, },
c0395aeb
DH
410 { .fd = p->local_in, .events = events_local & POLLIN, },
411 { .fd = p->local_out, .events = events_local & POLLOUT, },
412 };
413
414 r = ppoll(pollfd, 3, ts, NULL);
415 if (r < 0)
416 return log_error_errno(errno, "ppoll() failed: %m");
417
418 return 0;
419}
420
421static int handle_policy_error(sd_bus_message *m, int r) {
422 if (r == -ESRCH || r == -ENXIO)
423 return synthetic_reply_method_errorf(m, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", m->destination);
424
425 return r;
426}
427
c4bc1a84 428static int process_policy_unlocked(sd_bus *from, sd_bus *to, sd_bus_message *m, Policy *policy, const struct ucred *our_ucred, Set *owned_names) {
c0395aeb
DH
429 int r;
430
431 assert(from);
432 assert(to);
433 assert(m);
434
435 if (!policy)
436 return 0;
437
438 /*
439 * dbus-1 distinguishes expected and non-expected replies by tracking
440 * method-calls and timeouts. By default, DENY rules are *NEVER* applied
441 * on expected replies, unless explicitly specified. But we dont track
442 * method-calls, thus, we cannot know whether a reply is expected.
443 * Fortunately, the kdbus forbids non-expected replies, so we can safely
444 * ignore any policy on those and let the kernel deal with it.
445 *
446 * TODO: To be correct, we should only ignore policy-tags that are
447 * applied on non-expected replies. However, so far we don't parse those
448 * tags so we let everything pass. I haven't seen a DENY policy tag on
449 * expected-replies, ever, so don't bother..
450 */
451 if (m->reply_cookie > 0)
452 return 0;
453
454 if (from->is_kernel) {
455 uid_t sender_uid = UID_INVALID;
456 gid_t sender_gid = GID_INVALID;
457 char **sender_names = NULL;
c0395aeb
DH
458
459 /* Driver messages are always OK */
460 if (streq_ptr(m->sender, "org.freedesktop.DBus"))
461 return 0;
462
463 /* The message came from the kernel, and is sent to our legacy client. */
1140e154 464 (void) sd_bus_creds_get_well_known_names(&m->creds, &sender_names);
c0395aeb 465
05bae4a6
DH
466 (void) sd_bus_creds_get_euid(&m->creds, &sender_uid);
467 (void) sd_bus_creds_get_egid(&m->creds, &sender_gid);
c0395aeb
DH
468
469 if (sender_uid == UID_INVALID || sender_gid == GID_INVALID) {
470 _cleanup_bus_creds_unref_ sd_bus_creds *sender_creds = NULL;
471
472 /* If the message came from another legacy
473 * client, then the message creds will be
474 * missing, simply because on legacy clients
475 * per-message creds were unknown. In this
476 * case, query the creds of the peer
477 * instead. */
478
05bae4a6 479 r = bus_get_name_creds_kdbus(from, m->sender, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID, true, &sender_creds);
c0395aeb
DH
480 if (r < 0)
481 return handle_policy_error(m, r);
482
05bae4a6
DH
483 (void) sd_bus_creds_get_euid(sender_creds, &sender_uid);
484 (void) sd_bus_creds_get_egid(sender_creds, &sender_gid);
c0395aeb
DH
485 }
486
487 /* First check whether the sender can send the message to our name */
7447362c
DH
488 if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, false, NULL) &&
489 policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, sender_names, m->path, m->interface, m->member, false))
490 return 0;
c0395aeb
DH
491
492 /* Return an error back to the caller */
493 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
494 return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML receiver policy.");
495
496 /* Return 1, indicating that the message shall not be processed any further */
497 return 1;
498 }
499
500 if (to->is_kernel) {
501 _cleanup_bus_creds_unref_ sd_bus_creds *destination_creds = NULL;
502 uid_t destination_uid = UID_INVALID;
503 gid_t destination_gid = GID_INVALID;
504 const char *destination_unique = NULL;
505 char **destination_names = NULL;
7447362c 506 char *n;
c0395aeb
DH
507
508 /* Driver messages are always OK */
509 if (streq_ptr(m->destination, "org.freedesktop.DBus"))
510 return 0;
511
512 /* The message came from the legacy client, and is sent to kdbus. */
513 if (m->destination) {
514 r = bus_get_name_creds_kdbus(to, m->destination,
515 SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME|
05bae4a6 516 SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID,
c0395aeb
DH
517 true, &destination_creds);
518 if (r < 0)
519 return handle_policy_error(m, r);
520
521 r = sd_bus_creds_get_unique_name(destination_creds, &destination_unique);
522 if (r < 0)
523 return handle_policy_error(m, r);
524
1140e154 525 (void) sd_bus_creds_get_well_known_names(destination_creds, &destination_names);
c0395aeb 526
05bae4a6
DH
527 (void) sd_bus_creds_get_euid(destination_creds, &destination_uid);
528 (void) sd_bus_creds_get_egid(destination_creds, &destination_gid);
c0395aeb
DH
529 }
530
531 /* First check if we (the sender) can send to this name */
3723263f
DH
532 if (sd_bus_message_is_signal(m, NULL, NULL)) {
533 /* If we forward a signal from dbus-1 to kdbus, we have
534 * no idea who the recipient is. Therefore, we cannot
535 * apply any dbus-1 policies that match on receiver
536 * credentials. We know sd-bus always sets
537 * KDBUS_MSG_SIGNAL, so the kernel applies policies to
538 * the message. Therefore, skip policy checks in this
539 * case. */
540 return 0;
541 } else 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)) {
7447362c
DH
542 if (n) {
543 /* If we made a receiver decision, then remember which
544 * name's policy we used, and to which unique ID it
545 * mapped when we made the decision. Then, let's pass
546 * this to the kernel when sending the message, so that
547 * it refuses the operation should the name and unique
548 * ID not map to each other anymore. */
549
550 r = free_and_strdup(&m->destination_ptr, n);
551 if (r < 0)
552 return r;
553
554 r = bus_kernel_parse_unique_name(destination_unique, &m->verify_destination_id);
555 if (r < 0)
556 return r;
c0395aeb 557 }
c0395aeb 558
3723263f 559 if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, true))
7447362c 560 return 0;
c0395aeb
DH
561 }
562
563 /* Return an error back to the caller */
564 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
565 return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML sender policy.");
566
567 /* Return 1, indicating that the message shall not be processed any further */
568 return 1;
569 }
570
571 return 0;
572}
573
c4bc1a84
DH
574static int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, SharedPolicy *sp, const struct ucred *our_ucred, Set *owned_names) {
575 Policy *policy;
576 int r;
577
578 assert(sp);
579
580 policy = shared_policy_acquire(sp);
581 r = process_policy_unlocked(from, to, m, policy, our_ucred, owned_names);
582 shared_policy_release(sp, policy);
583
584 return r;
585}
586
c0395aeb
DH
587static 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
61adca52 607 return log_error_errno(EIO, "First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
c0395aeb
DH
608 }
609
610 if (p->got_hello)
61adca52 611 return log_error_errno(EIO, "Got duplicate hello, aborting.");
c0395aeb
DH
612
613 p->got_hello = true;
614
d27efd93 615 if (!p->destination_bus->is_kernel)
c0395aeb
DH
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
d27efd93 622 r = sd_bus_message_append(n, "s", p->destination_bus->unique_name);
c0395aeb
DH
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
d27efd93 648 r = sd_bus_message_append(n, "s", p->destination_bus->unique_name);
c0395aeb
DH
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
667static 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
d27efd93 697static int proxy_process_destination_to_local(Proxy *p) {
c0395aeb 698 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
e23bc0e7 699 bool matched, matched_synthetic;
c0395aeb
DH
700 int r;
701
702 assert(p);
703
e23bc0e7
DH
704 /*
705 * Usually, we would just take any message that the bus passes to us
706 * and forward it to the local connection. However, there are actually
707 * applications that fail if they receive broadcasts that they didn't
708 * subscribe to. Therefore, we actually emulate a real broadcast
709 * matching here, and discard any broadcasts that weren't matched. Our
710 * match-handlers remembers whether a message was matched by any rule,
711 * by marking it in @p->message_matched.
712 */
713
d27efd93 714 r = sd_bus_process(p->destination_bus, &m);
e23bc0e7
DH
715
716 matched = p->message_matched;
717 matched_synthetic = p->synthetic_matched;
718 p->message_matched = false;
719 p->synthetic_matched = false;
720
557b5d4a 721 if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
418e4cb0 722 return r;
c0395aeb 723 if (r < 0) {
418e4cb0 724 log_error_errno(r, "Failed to process destination bus: %m");
c0395aeb
DH
725 return r;
726 }
c0395aeb
DH
727 if (r == 0)
728 return 0;
729 if (!m)
730 return 1;
731
732 /* We officially got EOF, let's quit */
733 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
734 return -ECONNRESET;
735
e23bc0e7 736 r = synthesize_name_acquired(p, p->destination_bus, p->local_bus, m);
c74f883c
LP
737 if (r == -ECONNRESET || r == -ENOTCONN)
738 return r;
c0395aeb
DH
739 if (r < 0)
740 return log_error_errno(r, "Failed to synthesize message: %m");
741
e23bc0e7
DH
742 /* discard broadcasts that were not matched by any MATCH rule */
743 if (!matched && !sd_bus_message_get_destination(m)) {
744 if (!matched_synthetic)
ad8373e9
DM
745 log_debug("Dropped unmatched broadcast: uid=" UID_FMT " gid=" GID_FMT " pid=" PID_FMT " message=%s path=%s interface=%s member=%s sender=%s destination=%s",
746 p->local_creds.uid, p->local_creds.gid, p->local_creds.pid, bus_message_type_to_string(m->header->type),
747 strna(m->path), strna(m->interface), strna(m->member), strna(m->sender), strna(m->destination));
e23bc0e7
DH
748 return 1;
749 }
750
d27efd93 751 patch_sender(p->destination_bus, m);
c0395aeb
DH
752
753 if (p->policy) {
d27efd93 754 r = process_policy(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
c74f883c
LP
755 if (r == -ECONNRESET || r == -ENOTCONN)
756 return r;
c0395aeb
DH
757 if (r < 0)
758 return log_error_errno(r, "Failed to process policy: %m");
418e4cb0 759 if (r > 0)
c0395aeb
DH
760 return 1;
761 }
762
763 r = sd_bus_send(p->local_bus, m, NULL);
764 if (r < 0) {
557b5d4a 765 if (r == -ECONNRESET || r == -ENOTCONN)
c0395aeb 766 return r;
5f6cb091
LP
767
768 /* If the peer tries to send a reply and it is
769 * rejected with EPERM by the kernel, we ignore the
770 * error. This catches cases where the original
771 * method-call didn't had EXPECT_REPLY set, but the
772 * proxy-peer still sends a reply. This is allowed in
773 * dbus1, but not in kdbus. We don't want to track
774 * reply-windows in the proxy, so we simply ignore
775 * EPERM for all replies. The only downside is, that
776 * callers are no longer notified if their replies are
777 * dropped. However, this is equivalent to the
778 * caller's timeout to expire, so this should be
779 * acceptable. Nobody sane sends replies without a
780 * matching method-call, so nobody should care. */
781 if (r == -EPERM && m->reply_cookie > 0)
782 return 1;
783
784 /* Return the error to the client, if we can */
785 synthetic_reply_method_errnof(m, r, "Failed to forward message we got from destination: %m");
ec2c7b56
DH
786 if (r == -ENOBUFS) {
787 /* if local dbus1 peer does not dispatch its queue, warn only once */
788 if (!p->queue_overflow)
789 log_error("Dropped messages due to queue overflow of local peer (pid: "PID_FMT" uid: "UID_FMT")", p->local_creds.pid, p->local_creds.uid);
790 p->queue_overflow = true;
791 } else
792 log_error_errno(r,
793 "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",
794 p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
795 strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
796
5f6cb091 797 return 1;
c0395aeb
DH
798 }
799
ec2c7b56 800 p->queue_overflow = false;
c0395aeb
DH
801 return 1;
802}
803
d27efd93 804static int proxy_process_local_to_destination(Proxy *p) {
c0395aeb
DH
805 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
806 int r;
807
808 assert(p);
809
810 r = sd_bus_process(p->local_bus, &m);
557b5d4a 811 if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
418e4cb0 812 return r;
c0395aeb 813 if (r < 0) {
418e4cb0 814 log_error_errno(r, "Failed to process local bus: %m");
c0395aeb
DH
815 return r;
816 }
c0395aeb
DH
817 if (r == 0)
818 return 0;
819 if (!m)
820 return 1;
821
822 /* We officially got EOF, let's quit */
823 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
824 return -ECONNRESET;
825
826 r = process_hello(p, m);
c74f883c
LP
827 if (r == -ECONNRESET || r == -ENOTCONN)
828 return r;
c0395aeb
DH
829 if (r < 0)
830 return log_error_errno(r, "Failed to process HELLO: %m");
418e4cb0 831 if (r > 0)
c0395aeb
DH
832 return 1;
833
e23bc0e7 834 r = bus_proxy_process_driver(p, p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
c74f883c
LP
835 if (r == -ECONNRESET || r == -ENOTCONN)
836 return r;
c0395aeb
DH
837 if (r < 0)
838 return log_error_errno(r, "Failed to process driver calls: %m");
418e4cb0 839 if (r > 0)
c0395aeb
DH
840 return 1;
841
842 for (;;) {
843 if (p->policy) {
d27efd93 844 r = process_policy(p->local_bus, p->destination_bus, m, p->policy, &p->local_creds, p->owned_names);
c74f883c
LP
845 if (r == -ECONNRESET || r == -ENOTCONN)
846 return r;
c0395aeb
DH
847 if (r < 0)
848 return log_error_errno(r, "Failed to process policy: %m");
c74f883c 849 if (r > 0)
c0395aeb
DH
850 return 1;
851 }
852
d27efd93 853 r = sd_bus_send(p->destination_bus, m, NULL);
c0395aeb 854 if (r < 0) {
557b5d4a 855 if (r == -ECONNRESET || r == -ENOTCONN)
5f6cb091
LP
856 return r;
857
858 /* The name database changed since the policy check, hence let's check again */
859 if (r == -EREMCHG)
c0395aeb 860 continue;
5f6cb091
LP
861
862 /* see above why EPERM is ignored for replies */
863 if (r == -EPERM && m->reply_cookie > 0)
c0395aeb 864 return 1;
5f6cb091
LP
865
866 synthetic_reply_method_errnof(m, r, "Failed to forward message we got from local: %m");
e2856931
DH
867 log_error_errno(r,
868 "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",
869 p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
870 strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
5f6cb091 871 return 1;
c0395aeb
DH
872 }
873
874 break;
875 }
876
877 return 1;
878}
879
e23bc0e7
DH
880int proxy_match(sd_bus_message *m, void *userdata, sd_bus_error *error) {
881 Proxy *p = userdata;
882
883 p->message_matched = true;
884 return 0; /* make sure to continue processing it in further handlers */
885}
886
c0395aeb
DH
887int proxy_run(Proxy *p) {
888 int r;
889
890 assert(p);
891
892 for (;;) {
893 bool busy = false;
894
895 if (p->got_hello) {
896 /* Read messages from bus, to pass them on to our client */
d27efd93 897 r = proxy_process_destination_to_local(p);
557b5d4a 898 if (r == -ECONNRESET || r == -ENOTCONN)
c0395aeb 899 return 0;
418e4cb0 900 if (r < 0)
c0395aeb 901 return r;
418e4cb0 902 if (r > 0)
c0395aeb
DH
903 busy = true;
904 }
905
906 /* Read messages from our client, to pass them on to the bus */
d27efd93 907 r = proxy_process_local_to_destination(p);
557b5d4a 908 if (r == -ECONNRESET || r == -ENOTCONN)
c0395aeb 909 return 0;
418e4cb0 910 if (r < 0)
c0395aeb 911 return r;
418e4cb0 912 if (r > 0)
c0395aeb
DH
913 busy = true;
914
915 if (!busy) {
916 r = proxy_wait(p);
c74f883c
LP
917 if (r == -ECONNRESET || r == -ENOTCONN)
918 return 0;
c0395aeb
DH
919 if (r < 0)
920 return r;
921 }
922 }
923
924 return 0;
925}