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