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