]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/bus-proxyd/proxy.c
btrfs: always remove the per-subvol qgroup when removing a subvol
[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
e3c57a86
DH
656 r = sd_bus_message_set_destination(n, p->destination_bus->unique_name);
657 if (r < 0)
658 return log_error_errno(r, "Failed to set destination for NameAcquired message: %m");
659
c0395aeb
DH
660 r = bus_seal_synthetic_message(p->local_bus, n);
661 if (r < 0)
662 return log_error_errno(r, "Failed to seal NameAcquired message: %m");
663
664 r = sd_bus_send(p->local_bus, n, NULL);
665 if (r < 0)
666 return log_error_errno(r, "Failed to send NameAcquired message: %m");
667
668 return 1;
669}
670
671static int patch_sender(sd_bus *a, sd_bus_message *m) {
672 char **well_known = NULL;
673 sd_bus_creds *c;
674 int r;
675
676 assert(a);
677 assert(m);
678
679 if (!a->is_kernel)
680 return 0;
681
682 /* We will change the sender of messages from the bus driver
683 * so that they originate from the bus driver. This is a
684 * speciality originating from dbus1, where the bus driver did
685 * not have a unique id, but only the well-known name. */
686
687 c = sd_bus_message_get_creds(m);
688 if (!c)
689 return 0;
690
691 r = sd_bus_creds_get_well_known_names(c, &well_known);
692 if (r < 0)
693 return r;
694
695 if (strv_contains(well_known, "org.freedesktop.DBus"))
696 m->sender = "org.freedesktop.DBus";
697
698 return 0;
699}
700
d27efd93 701static int proxy_process_destination_to_local(Proxy *p) {
c0395aeb 702 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
e23bc0e7 703 bool matched, matched_synthetic;
c0395aeb
DH
704 int r;
705
706 assert(p);
707
e23bc0e7
DH
708 /*
709 * Usually, we would just take any message that the bus passes to us
710 * and forward it to the local connection. However, there are actually
711 * applications that fail if they receive broadcasts that they didn't
712 * subscribe to. Therefore, we actually emulate a real broadcast
713 * matching here, and discard any broadcasts that weren't matched. Our
714 * match-handlers remembers whether a message was matched by any rule,
715 * by marking it in @p->message_matched.
716 */
717
d27efd93 718 r = sd_bus_process(p->destination_bus, &m);
e23bc0e7
DH
719
720 matched = p->message_matched;
721 matched_synthetic = p->synthetic_matched;
722 p->message_matched = false;
723 p->synthetic_matched = false;
724
557b5d4a 725 if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
418e4cb0 726 return r;
c0395aeb 727 if (r < 0) {
418e4cb0 728 log_error_errno(r, "Failed to process destination bus: %m");
c0395aeb
DH
729 return r;
730 }
c0395aeb
DH
731 if (r == 0)
732 return 0;
733 if (!m)
734 return 1;
735
736 /* We officially got EOF, let's quit */
737 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
738 return -ECONNRESET;
739
e23bc0e7 740 r = synthesize_name_acquired(p, p->destination_bus, p->local_bus, m);
c74f883c
LP
741 if (r == -ECONNRESET || r == -ENOTCONN)
742 return r;
c0395aeb
DH
743 if (r < 0)
744 return log_error_errno(r, "Failed to synthesize message: %m");
745
e23bc0e7
DH
746 /* discard broadcasts that were not matched by any MATCH rule */
747 if (!matched && !sd_bus_message_get_destination(m)) {
748 if (!matched_synthetic)
ad8373e9
DM
749 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",
750 p->local_creds.uid, p->local_creds.gid, p->local_creds.pid, bus_message_type_to_string(m->header->type),
751 strna(m->path), strna(m->interface), strna(m->member), strna(m->sender), strna(m->destination));
e23bc0e7
DH
752 return 1;
753 }
754
d27efd93 755 patch_sender(p->destination_bus, m);
c0395aeb
DH
756
757 if (p->policy) {
d27efd93 758 r = process_policy(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
c74f883c
LP
759 if (r == -ECONNRESET || r == -ENOTCONN)
760 return r;
c0395aeb
DH
761 if (r < 0)
762 return log_error_errno(r, "Failed to process policy: %m");
418e4cb0 763 if (r > 0)
c0395aeb
DH
764 return 1;
765 }
766
767 r = sd_bus_send(p->local_bus, m, NULL);
768 if (r < 0) {
557b5d4a 769 if (r == -ECONNRESET || r == -ENOTCONN)
c0395aeb 770 return r;
5f6cb091
LP
771
772 /* If the peer tries to send a reply and it is
2c960818 773 * rejected with EBADSLT by the kernel, we ignore the
5f6cb091
LP
774 * error. This catches cases where the original
775 * method-call didn't had EXPECT_REPLY set, but the
776 * proxy-peer still sends a reply. This is allowed in
777 * dbus1, but not in kdbus. We don't want to track
778 * reply-windows in the proxy, so we simply ignore
2c960818 779 * EBADSLT for all replies. The only downside is, that
5f6cb091
LP
780 * callers are no longer notified if their replies are
781 * dropped. However, this is equivalent to the
782 * caller's timeout to expire, so this should be
783 * acceptable. Nobody sane sends replies without a
784 * matching method-call, so nobody should care. */
855fc974
KS
785
786 /* FIXME: remove -EPERM when kdbus is updated */
2c960818 787 if ((r == -EPERM || r == -EBADSLT) && m->reply_cookie > 0)
5f6cb091
LP
788 return 1;
789
790 /* Return the error to the client, if we can */
791 synthetic_reply_method_errnof(m, r, "Failed to forward message we got from destination: %m");
ec2c7b56
DH
792 if (r == -ENOBUFS) {
793 /* if local dbus1 peer does not dispatch its queue, warn only once */
794 if (!p->queue_overflow)
795 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);
796 p->queue_overflow = true;
797 } else
798 log_error_errno(r,
799 "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",
800 p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
801 strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
802
5f6cb091 803 return 1;
c0395aeb
DH
804 }
805
ec2c7b56 806 p->queue_overflow = false;
c0395aeb
DH
807 return 1;
808}
809
d27efd93 810static int proxy_process_local_to_destination(Proxy *p) {
c0395aeb
DH
811 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
812 int r;
813
814 assert(p);
815
816 r = sd_bus_process(p->local_bus, &m);
557b5d4a 817 if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
418e4cb0 818 return r;
c0395aeb 819 if (r < 0) {
418e4cb0 820 log_error_errno(r, "Failed to process local bus: %m");
c0395aeb
DH
821 return r;
822 }
c0395aeb
DH
823 if (r == 0)
824 return 0;
825 if (!m)
826 return 1;
827
828 /* We officially got EOF, let's quit */
829 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
830 return -ECONNRESET;
831
832 r = process_hello(p, m);
c74f883c
LP
833 if (r == -ECONNRESET || r == -ENOTCONN)
834 return r;
c0395aeb
DH
835 if (r < 0)
836 return log_error_errno(r, "Failed to process HELLO: %m");
418e4cb0 837 if (r > 0)
c0395aeb
DH
838 return 1;
839
e23bc0e7 840 r = bus_proxy_process_driver(p, p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
c74f883c
LP
841 if (r == -ECONNRESET || r == -ENOTCONN)
842 return r;
c0395aeb
DH
843 if (r < 0)
844 return log_error_errno(r, "Failed to process driver calls: %m");
418e4cb0 845 if (r > 0)
c0395aeb
DH
846 return 1;
847
848 for (;;) {
849 if (p->policy) {
d27efd93 850 r = process_policy(p->local_bus, p->destination_bus, m, p->policy, &p->local_creds, p->owned_names);
c74f883c
LP
851 if (r == -ECONNRESET || r == -ENOTCONN)
852 return r;
c0395aeb
DH
853 if (r < 0)
854 return log_error_errno(r, "Failed to process policy: %m");
c74f883c 855 if (r > 0)
c0395aeb
DH
856 return 1;
857 }
858
d27efd93 859 r = sd_bus_send(p->destination_bus, m, NULL);
c0395aeb 860 if (r < 0) {
557b5d4a 861 if (r == -ECONNRESET || r == -ENOTCONN)
5f6cb091
LP
862 return r;
863
864 /* The name database changed since the policy check, hence let's check again */
865 if (r == -EREMCHG)
c0395aeb 866 continue;
5f6cb091 867
2c960818
DH
868 /* see above why EBADSLT is ignored for replies */
869 if ((r == -EPERM || r == -EBADSLT) && m->reply_cookie > 0)
c0395aeb 870 return 1;
5f6cb091
LP
871
872 synthetic_reply_method_errnof(m, r, "Failed to forward message we got from local: %m");
e2856931
DH
873 log_error_errno(r,
874 "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",
875 p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
876 strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
5f6cb091 877 return 1;
c0395aeb
DH
878 }
879
880 break;
881 }
882
883 return 1;
884}
885
e23bc0e7
DH
886int proxy_match(sd_bus_message *m, void *userdata, sd_bus_error *error) {
887 Proxy *p = userdata;
888
889 p->message_matched = true;
890 return 0; /* make sure to continue processing it in further handlers */
891}
892
c0395aeb
DH
893int proxy_run(Proxy *p) {
894 int r;
895
896 assert(p);
897
898 for (;;) {
899 bool busy = false;
900
901 if (p->got_hello) {
902 /* Read messages from bus, to pass them on to our client */
d27efd93 903 r = proxy_process_destination_to_local(p);
557b5d4a 904 if (r == -ECONNRESET || r == -ENOTCONN)
c0395aeb 905 return 0;
418e4cb0 906 if (r < 0)
c0395aeb 907 return r;
418e4cb0 908 if (r > 0)
c0395aeb
DH
909 busy = true;
910 }
911
912 /* Read messages from our client, to pass them on to the bus */
d27efd93 913 r = proxy_process_local_to_destination(p);
557b5d4a 914 if (r == -ECONNRESET || r == -ENOTCONN)
c0395aeb 915 return 0;
418e4cb0 916 if (r < 0)
c0395aeb 917 return r;
418e4cb0 918 if (r > 0)
c0395aeb
DH
919 busy = true;
920
921 if (!busy) {
922 r = proxy_wait(p);
c74f883c
LP
923 if (r == -ECONNRESET || r == -ENOTCONN)
924 return 0;
c0395aeb
DH
925 if (r < 0)
926 return r;
927 }
928 }
929
930 return 0;
931}