]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/bus-proxyd/bus-proxyd.c
bus-proxy: automatically detect scope of bus and derive which XML snippets to load...
[thirdparty/systemd.git] / src / bus-proxyd / bus-proxyd.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7 Copyright 2013 Daniel Mack
8 Copyright 2014 Kay Sievers
9
10 systemd is free software; you can redistribute it and/or modify it
11 under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14
15 systemd is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public License
21 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 ***/
23
24 #include <sys/socket.h>
25 #include <sys/un.h>
26 #include <sys/types.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <sys/poll.h>
32 #include <stddef.h>
33 #include <getopt.h>
34
35 #include "log.h"
36 #include "util.h"
37 #include "socket-util.h"
38 #include "sd-daemon.h"
39 #include "sd-bus.h"
40 #include "bus-internal.h"
41 #include "bus-message.h"
42 #include "bus-util.h"
43 #include "build.h"
44 #include "strv.h"
45 #include "def.h"
46 #include "capability.h"
47 #include "bus-policy.h"
48
49 static char *arg_address = NULL;
50 static char *arg_command_line_buffer = NULL;
51 static bool arg_drop_privileges = false;
52 static char **arg_configuration = NULL;
53
54 static int help(void) {
55
56 printf("%s [OPTIONS...]\n\n"
57 "Connect STDIO or a socket to a given bus address.\n\n"
58 " -h --help Show this help\n"
59 " --version Show package version\n"
60 " --drop-privileges Drop privileges\n"
61 " --configuration=PATH Configuration file or directory\n"
62 " --machine=MACHINE Connect to specified machine\n"
63 " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
64 " (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n",
65 program_invocation_short_name);
66
67 return 0;
68 }
69
70 static int parse_argv(int argc, char *argv[]) {
71
72 enum {
73 ARG_VERSION = 0x100,
74 ARG_ADDRESS,
75 ARG_DROP_PRIVILEGES,
76 ARG_CONFIGURATION,
77 ARG_MACHINE,
78 };
79
80 static const struct option options[] = {
81 { "help", no_argument, NULL, 'h' },
82 { "version", no_argument, NULL, ARG_VERSION },
83 { "address", required_argument, NULL, ARG_ADDRESS },
84 { "drop-privileges", no_argument, NULL, ARG_DROP_PRIVILEGES },
85 { "configuration", required_argument, NULL, ARG_CONFIGURATION },
86 { "machine", required_argument, NULL, ARG_MACHINE },
87 {},
88 };
89
90 int c, r;
91
92 assert(argc >= 0);
93 assert(argv);
94
95 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
96
97 switch (c) {
98
99 case 'h':
100 help();
101 return 0;
102
103 case ARG_VERSION:
104 puts(PACKAGE_STRING);
105 puts(SYSTEMD_FEATURES);
106 return 0;
107
108 case ARG_ADDRESS: {
109 char *a;
110
111 a = strdup(optarg);
112 if (!a)
113 return log_oom();
114
115 free(arg_address);
116 arg_address = a;
117 break;
118 }
119
120 case ARG_DROP_PRIVILEGES:
121 arg_drop_privileges = true;
122 break;
123
124 case ARG_CONFIGURATION:
125 r = strv_extend(&arg_configuration, optarg);
126 if (r < 0)
127 return log_oom();
128 break;
129
130 case ARG_MACHINE: {
131 _cleanup_free_ char *e = NULL;
132 char *a;
133
134 e = bus_address_escape(optarg);
135 if (!e)
136 return log_oom();
137
138 #ifdef ENABLE_KDBUS
139 a = strjoin("x-container-kernel:machine=", e, ";x-container-unix:machine=", e, NULL);
140 #else
141 a = strjoin("x-container-unix:machine=", e, NULL);
142 #endif
143 if (!a)
144 return log_oom();
145
146 free(arg_address);
147 arg_address = a;
148
149 break;
150 }
151
152 case '?':
153 return -EINVAL;
154
155 default:
156 assert_not_reached("Unhandled option");
157 }
158
159 /* If the first command line argument is only "x" characters
160 * we'll write who we are talking to into it, so that "ps" is
161 * explanatory */
162 arg_command_line_buffer = argv[optind];
163 if (argc > optind + 1 || (arg_command_line_buffer && !in_charset(arg_command_line_buffer, "x"))) {
164 log_error("Too many arguments");
165 return -EINVAL;
166 }
167
168 if (!arg_address) {
169 arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS);
170 if (!arg_address)
171 return log_oom();
172 }
173
174 return 1;
175 }
176
177 static int rename_service(sd_bus *a, sd_bus *b) {
178 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
179 _cleanup_free_ char *p = NULL, *name = NULL;
180 const char *comm;
181 char **cmdline;
182 uid_t uid;
183 pid_t pid;
184 int r;
185
186 assert(a);
187 assert(b);
188
189 r = sd_bus_get_owner_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM, &creds);
190 if (r < 0)
191 return r;
192
193 r = sd_bus_creds_get_uid(creds, &uid);
194 if (r < 0)
195 return r;
196
197 r = sd_bus_creds_get_pid(creds, &pid);
198 if (r < 0)
199 return r;
200
201 r = sd_bus_creds_get_cmdline(creds, &cmdline);
202 if (r < 0)
203 return r;
204
205 r = sd_bus_creds_get_comm(creds, &comm);
206 if (r < 0)
207 return r;
208
209 name = uid_to_name(uid);
210 if (!name)
211 return -ENOMEM;
212
213 p = strv_join(cmdline, " ");
214 if (!p)
215 return -ENOMEM;
216
217 /* The status string gets the full command line ... */
218 sd_notifyf(false,
219 "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
220 pid, p,
221 uid, name);
222
223 /* ... and the argv line only the short comm */
224 if (arg_command_line_buffer) {
225 size_t m, w;
226
227 m = strlen(arg_command_line_buffer);
228 w = snprintf(arg_command_line_buffer, m,
229 "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
230 pid, comm,
231 uid, name);
232
233 if (m > w)
234 memzero(arg_command_line_buffer + w, m - w);
235 }
236
237 log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
238 pid, p,
239 uid, name,
240 a->unique_name);
241
242 return 0;
243 }
244
245 static int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
246 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
247 const char *name, *old_owner, *new_owner;
248 int r;
249
250 assert(a);
251 assert(b);
252 assert(m);
253
254 /* If we get NameOwnerChanged for our own name, we need to
255 * synthesize NameLost/NameAcquired, since socket clients need
256 * that, even though it is obsoleted on kdbus */
257
258 if (!a->is_kernel)
259 return 0;
260
261 if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
262 !streq_ptr(m->path, "/org/freedesktop/DBus") ||
263 !streq_ptr(m->sender, "org.freedesktop.DBus"))
264 return 0;
265
266 r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
267 if (r < 0)
268 return r;
269
270 r = sd_bus_message_rewind(m, true);
271 if (r < 0)
272 return r;
273
274 if (streq(old_owner, a->unique_name)) {
275
276 r = sd_bus_message_new_signal(
277 b,
278 &n,
279 "/org/freedesktop/DBus",
280 "org.freedesktop.DBus",
281 "NameLost");
282
283 } else if (streq(new_owner, a->unique_name)) {
284
285 r = sd_bus_message_new_signal(
286 b,
287 &n,
288 "/org/freedesktop/DBus",
289 "org.freedesktop.DBus",
290 "NameAcquired");
291 } else
292 return 0;
293
294 if (r < 0)
295 return r;
296
297 r = sd_bus_message_append(n, "s", name);
298 if (r < 0)
299 return r;
300
301 r = bus_message_append_sender(n, "org.freedesktop.DBus");
302 if (r < 0)
303 return r;
304
305 r = bus_seal_synthetic_message(b, n);
306 if (r < 0)
307 return r;
308
309 return sd_bus_send(b, n, NULL);
310 }
311
312 static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
313 int r;
314
315 assert(b);
316 assert(m);
317
318 r = bus_message_append_sender(m, "org.freedesktop.DBus");
319 if (r < 0)
320 return r;
321
322 r = bus_seal_synthetic_message(b, m);
323 if (r < 0)
324 return r;
325
326 return sd_bus_send(b, m, NULL);
327 }
328
329 static int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
330 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
331 int r;
332
333 assert(call);
334
335 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
336 return 0;
337
338 r = sd_bus_message_new_method_error(call, &m, e);
339 if (r < 0)
340 return r;
341
342 return synthetic_driver_send(call->bus, m);
343 }
344
345 static int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
346
347 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
348
349 assert(call);
350
351 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
352 return 0;
353
354 if (sd_bus_error_is_set(p))
355 return synthetic_reply_method_error(call, p);
356
357 sd_bus_error_set_errno(&berror, error);
358
359 return synthetic_reply_method_error(call, &berror);
360 }
361
362 static int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
363 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
364 int r;
365
366 assert(call);
367
368 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
369 return 0;
370
371 r = sd_bus_message_new_method_return(call, &m);
372 if (r < 0)
373 return r;
374
375 if (!isempty(types)) {
376 va_list ap;
377
378 va_start(ap, types);
379 r = bus_message_append_ap(m, types, ap);
380 va_end(ap);
381 if (r < 0)
382 return r;
383 }
384
385 return synthetic_driver_send(call->bus, m);
386 }
387
388 static int synthetic_reply_return_strv(sd_bus_message *call, char **l) {
389 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
390 int r;
391
392 assert(call);
393
394 r = sd_bus_message_new_method_return(call, &m);
395 if (r < 0)
396 return synthetic_reply_method_errno(call, r, NULL);
397
398 r = sd_bus_message_append_strv(m, l);
399 if (r < 0)
400 return synthetic_reply_method_errno(call, r, NULL);
401
402 return synthetic_driver_send(call->bus, m);
403 }
404
405 static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
406 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
407 int r;
408
409 assert(bus);
410 assert(name);
411 assert(_creds);
412
413 r = sd_bus_get_name_creds(bus, name, mask, &c);
414 if (r == -ESRCH || r == -ENXIO)
415 return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
416 if (r < 0)
417 return r;
418
419 if ((c->mask & mask) != mask)
420 return -ENOTSUP;
421
422 *_creds = c;
423 c = NULL;
424
425 return 0;
426 }
427
428 static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
429 const char *name;
430 int r;
431
432 assert(bus);
433 assert(m);
434 assert(_creds);
435
436 r = sd_bus_message_read(m, "s", &name);
437 if (r < 0)
438 return r;
439
440 return get_creds_by_name(bus, name, mask, _creds, error);
441 }
442
443 static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, Policy *policy, const struct ucred *ucred, Set *owned_names) {
444 int r;
445
446 assert(a);
447 assert(b);
448 assert(m);
449
450 if (!a->is_kernel)
451 return 0;
452
453 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
454 return 0;
455
456 /* The "Hello()" call is is handled in process_hello() */
457
458 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
459
460 if (!sd_bus_message_has_signature(m, ""))
461 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
462
463 return synthetic_reply_method_return(m, "s",
464 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
465 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
466 "<node>\n"
467 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
468 " <method name=\"Introspect\">\n"
469 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
470 " </method>\n"
471 " </interface>\n"
472 " <interface name=\"org.freedesktop.DBus\">\n"
473 " <method name=\"AddMatch\">\n"
474 " <arg type=\"s\" direction=\"in\"/>\n"
475 " </method>\n"
476 " <method name=\"RemoveMatch\">\n"
477 " <arg type=\"s\" direction=\"in\"/>\n"
478 " </method>\n"
479 " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
480 " <arg type=\"s\" direction=\"in\"/>\n"
481 " <arg type=\"ay\" direction=\"out\"/>\n"
482 " </method>\n"
483 " <method name=\"GetConnectionUnixProcessID\">\n"
484 " <arg type=\"s\" direction=\"in\"/>\n"
485 " <arg type=\"u\" direction=\"out\"/>\n"
486 " </method>\n"
487 " <method name=\"GetConnectionUnixUser\">\n"
488 " <arg type=\"s\" direction=\"in\"/>\n"
489 " <arg type=\"u\" direction=\"out\"/>\n"
490 " </method>\n"
491 " <method name=\"GetId\">\n"
492 " <arg type=\"s\" direction=\"out\"/>\n"
493 " </method>\n"
494 " <method name=\"GetNameOwner\">\n"
495 " <arg type=\"s\" direction=\"in\"/>\n"
496 " <arg type=\"s\" direction=\"out\"/>\n"
497 " </method>\n"
498 " <method name=\"Hello\">\n"
499 " <arg type=\"s\" direction=\"out\"/>\n"
500 " </method>\n"
501 " <method name=\"ListActivatableNames\">\n"
502 " <arg type=\"as\" direction=\"out\"/>\n"
503 " </method>\n"
504 " <method name=\"ListNames\">\n"
505 " <arg type=\"as\" direction=\"out\"/>\n"
506 " </method>\n"
507 " <method name=\"ListQueuedOwners\">\n"
508 " <arg type=\"s\" direction=\"in\"/>\n"
509 " <arg type=\"as\" direction=\"out\"/>\n"
510 " </method>\n"
511 " <method name=\"NameHasOwner\">\n"
512 " <arg type=\"s\" direction=\"in\"/>\n"
513 " <arg type=\"b\" direction=\"out\"/>\n"
514 " </method>\n"
515 " <method name=\"ReleaseName\">\n"
516 " <arg type=\"s\" direction=\"in\"/>\n"
517 " <arg type=\"u\" direction=\"out\"/>\n"
518 " </method>\n"
519 " <method name=\"ReloadConfig\">\n"
520 " </method>\n"
521 " <method name=\"RequestName\">\n"
522 " <arg type=\"s\" direction=\"in\"/>\n"
523 " <arg type=\"u\" direction=\"in\"/>\n"
524 " <arg type=\"u\" direction=\"out\"/>\n"
525 " </method>\n"
526 " <method name=\"StartServiceByName\">\n"
527 " <arg type=\"s\" direction=\"in\"/>\n"
528 " <arg type=\"u\" direction=\"in\"/>\n"
529 " <arg type=\"u\" direction=\"out\"/>\n"
530 " </method>\n"
531 " <method name=\"UpdateActivationEnvironment\">\n"
532 " <arg type=\"a{ss}\" direction=\"in\"/>\n"
533 " </method>\n"
534 " <signal name=\"NameAcquired\">\n"
535 " <arg type=\"s\"/>\n"
536 " </signal>\n"
537 " <signal name=\"NameLost\">\n"
538 " <arg type=\"s\"/>\n"
539 " </signal>\n"
540 " <signal name=\"NameOwnerChanged\">\n"
541 " <arg type=\"s\"/>\n"
542 " <arg type=\"s\"/>\n"
543 " <arg type=\"s\"/>\n"
544 " </signal>\n"
545 " </interface>\n"
546 "</node>\n");
547
548 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
549 const char *match;
550
551 if (!sd_bus_message_has_signature(m, "s"))
552 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
553
554 r = sd_bus_message_read(m, "s", &match);
555 if (r < 0)
556 return synthetic_reply_method_errno(m, r, NULL);
557
558 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
559 if (r < 0)
560 return synthetic_reply_method_errno(m, r, NULL);
561
562 return synthetic_reply_method_return(m, NULL);
563
564 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
565 const char *match;
566
567 if (!sd_bus_message_has_signature(m, "s"))
568 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
569
570 r = sd_bus_message_read(m, "s", &match);
571 if (r < 0)
572 return synthetic_reply_method_errno(m, r, NULL);
573
574 r = bus_remove_match_by_string(a, match, NULL, NULL);
575 if (r == 0)
576 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
577 if (r < 0)
578 return synthetic_reply_method_errno(m, r, NULL);
579
580 return synthetic_reply_method_return(m, NULL);
581
582 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
583 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
584 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
585
586 if (!sd_bus_message_has_signature(m, "s"))
587 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
588
589 r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error);
590 if (r < 0)
591 return synthetic_reply_method_errno(m, r, &error);
592
593 return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
594
595 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
596 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
597 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
598
599 if (!sd_bus_message_has_signature(m, "s"))
600 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
601
602 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, &error);
603 if (r < 0)
604 return synthetic_reply_method_errno(m, r, &error);
605
606 return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
607
608 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
609 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
610 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
611
612 if (!sd_bus_message_has_signature(m, "s"))
613 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
614
615 r = get_creds_by_message(a, m, SD_BUS_CREDS_UID, &creds, &error);
616 if (r < 0)
617 return synthetic_reply_method_errno(m, r, &error);
618
619 return synthetic_reply_method_return(m, "u", (uint32_t) creds->uid);
620
621 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
622 sd_id128_t server_id;
623 char buf[SD_ID128_STRING_MAX];
624
625 if (!sd_bus_message_has_signature(m, ""))
626 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
627
628 r = sd_bus_get_owner_id(a, &server_id);
629 if (r < 0)
630 return synthetic_reply_method_errno(m, r, NULL);
631
632 return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
633
634 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
635 const char *name;
636 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
637 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
638
639 if (!sd_bus_message_has_signature(m, "s"))
640 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
641
642 r = sd_bus_message_read(m, "s", &name);
643 if (r < 0)
644 return synthetic_reply_method_errno(m, r, NULL);
645
646 if (streq(name, "org.freedesktop.DBus"))
647 return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
648
649 r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
650 if (r < 0)
651 return synthetic_reply_method_errno(m, r, &error);
652
653 return synthetic_reply_method_return(m, "s", creds->unique_name);
654
655 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
656 _cleanup_strv_free_ char **names = NULL;
657
658 if (!sd_bus_message_has_signature(m, ""))
659 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
660
661 r = sd_bus_list_names(a, NULL, &names);
662 if (r < 0)
663 return synthetic_reply_method_errno(m, r, NULL);
664
665 /* Let's sort the names list to make it stable */
666 strv_sort(names);
667
668 return synthetic_reply_return_strv(m, names);
669
670 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
671 _cleanup_strv_free_ char **names = NULL;
672
673 if (!sd_bus_message_has_signature(m, ""))
674 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
675
676 r = sd_bus_list_names(a, &names, NULL);
677 if (r < 0)
678 return synthetic_reply_method_errno(m, r, NULL);
679
680 r = strv_extend(&names, "org.freedesktop.DBus");
681 if (r < 0)
682 return synthetic_reply_method_errno(m, r, NULL);
683
684 /* Let's sort the names list to make it stable */
685 strv_sort(names);
686
687 return synthetic_reply_return_strv(m, names);
688
689 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
690 struct kdbus_cmd_name_list cmd = {};
691 struct kdbus_name_list *name_list;
692 struct kdbus_name_info *name;
693 _cleanup_strv_free_ char **owners = NULL;
694 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
695 char *arg0;
696 int err = 0;
697
698 if (!sd_bus_message_has_signature(m, "s"))
699 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
700
701 r = sd_bus_message_read(m, "s", &arg0);
702 if (r < 0)
703 return synthetic_reply_method_errno(m, r, NULL);
704
705 r = sd_bus_get_name_creds(a, arg0, 0, NULL);
706 if (r == -ESRCH || r == -ENXIO) {
707 sd_bus_error_setf(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name.", arg0);
708 return synthetic_reply_method_errno(m, r, &error);
709 }
710 if (r < 0)
711 return synthetic_reply_method_errno(m, r, NULL);
712
713 cmd.flags = KDBUS_NAME_LIST_QUEUED;
714 r = ioctl(a->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
715 if (r < 0)
716 return synthetic_reply_method_errno(m, -errno, NULL);
717
718 name_list = (struct kdbus_name_list *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
719
720 KDBUS_ITEM_FOREACH(name, name_list, names) {
721 const char *entry_name = NULL;
722 struct kdbus_item *item;
723 char *n;
724
725 KDBUS_ITEM_FOREACH(item, name, items)
726 if (item->type == KDBUS_ITEM_OWNED_NAME)
727 entry_name = item->name.name;
728
729 if (!streq_ptr(entry_name, arg0))
730 continue;
731
732 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
733 err = -ENOMEM;
734 break;
735 }
736
737 r = strv_consume(&owners, n);
738 if (r < 0) {
739 err = r;
740 break;
741 }
742 }
743
744 r = bus_kernel_cmd_free(a, cmd.offset);
745 if (r < 0)
746 return synthetic_reply_method_errno(m, r, NULL);
747
748 if (err < 0)
749 return synthetic_reply_method_errno(m, err, NULL);
750
751 return synthetic_reply_return_strv(m, owners);
752
753 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
754 const char *name;
755
756 if (!sd_bus_message_has_signature(m, "s"))
757 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
758
759 r = sd_bus_message_read(m, "s", &name);
760 if (r < 0)
761 return synthetic_reply_method_errno(m, r, NULL);
762
763 if (streq(name, "org.freedesktop.DBus"))
764 return synthetic_reply_method_return(m, "b", true);
765
766 r = sd_bus_get_name_creds(a, name, 0, NULL);
767 if (r < 0 && r != -ESRCH && r != -ENXIO)
768 return synthetic_reply_method_errno(m, r, NULL);
769
770 return synthetic_reply_method_return(m, "b", r >= 0);
771
772 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
773 const char *name;
774
775 if (!sd_bus_message_has_signature(m, "s"))
776 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
777
778 r = sd_bus_message_read(m, "s", &name);
779 if (r < 0)
780 return synthetic_reply_method_errno(m, r, NULL);
781
782 r = sd_bus_release_name(a, name);
783 if (r < 0) {
784 if (r == -ESRCH)
785 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
786 if (r == -EADDRINUSE)
787 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
788
789 return synthetic_reply_method_errno(m, r, NULL);
790 }
791
792 set_remove(owned_names, (char*) name);
793
794 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
795
796 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
797 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
798
799 if (!sd_bus_message_has_signature(m, ""))
800 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
801
802 r = sd_bus_error_setf(&error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
803
804 return synthetic_reply_method_errno(m, r, &error);
805
806 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
807 const char *name;
808 uint32_t flags, param;
809 bool in_queue;
810
811 if (!sd_bus_message_has_signature(m, "su"))
812 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
813
814 r = sd_bus_message_read(m, "su", &name, &flags);
815 if (r < 0)
816 return synthetic_reply_method_errno(m, r, NULL);
817
818 if (policy && !policy_check_own(policy, ucred->uid, ucred->gid, name))
819 return synthetic_reply_method_errno(m, -EPERM, NULL);
820
821 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
822 return synthetic_reply_method_errno(m, -EINVAL, NULL);
823
824 param = 0;
825 if (flags & BUS_NAME_ALLOW_REPLACEMENT)
826 param |= SD_BUS_NAME_ALLOW_REPLACEMENT;
827 if (flags & BUS_NAME_REPLACE_EXISTING)
828 param |= SD_BUS_NAME_REPLACE_EXISTING;
829 if (!(flags & BUS_NAME_DO_NOT_QUEUE))
830 param |= SD_BUS_NAME_QUEUE;
831
832 r = set_put_strdup(owned_names, name);
833 if (r < 0)
834 return synthetic_reply_method_errno(m, r, NULL);
835
836 r = sd_bus_request_name(a, name, param);
837 if (r < 0) {
838 if (r == -EALREADY)
839 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
840
841 set_remove(owned_names, (char*) name);
842
843 if (r == -EEXIST)
844 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
845 return synthetic_reply_method_errno(m, r, NULL);
846 }
847
848 in_queue = (r == 0);
849
850 if (in_queue)
851 return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
852
853 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
854
855 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
856 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
857 const char *name;
858 uint32_t flags;
859
860 if (!sd_bus_message_has_signature(m, "su"))
861 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
862
863 r = sd_bus_message_read(m, "su", &name, &flags);
864 if (r < 0)
865 return synthetic_reply_method_errno(m, r, NULL);
866
867 if (flags != 0)
868 return synthetic_reply_method_errno(m, -EINVAL, NULL);
869
870 r = sd_bus_get_name_creds(a, name, 0, NULL);
871 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
872 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
873 if (r != -ESRCH)
874 return synthetic_reply_method_errno(m, r, NULL);
875
876 r = sd_bus_message_new_method_call(
877 a,
878 &msg,
879 name,
880 "/",
881 "org.freedesktop.DBus.Peer",
882 "Ping");
883 if (r < 0)
884 return synthetic_reply_method_errno(m, r, NULL);
885
886 r = sd_bus_send(a, msg, NULL);
887 if (r < 0)
888 return synthetic_reply_method_errno(m, r, NULL);
889
890 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
891
892 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
893 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
894 _cleanup_strv_free_ char **args = NULL;
895
896 if (!sd_bus_message_has_signature(m, "a{ss}"))
897 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
898
899 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
900 if (r < 0)
901 return synthetic_reply_method_errno(m, r, NULL);
902
903 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
904 _cleanup_free_ char *s = NULL;
905 const char *key;
906 const char *value;
907
908 r = sd_bus_message_read(m, "ss", &key, &value);
909 if (r < 0)
910 return synthetic_reply_method_errno(m, r, NULL);
911
912 s = strjoin(key, "=", value, NULL);
913 if (!s)
914 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
915
916 r = strv_extend(&args, s);
917 if (r < 0)
918 return synthetic_reply_method_errno(m, r, NULL);
919
920 r = sd_bus_message_exit_container(m);
921 if (r < 0)
922 return synthetic_reply_method_errno(m, r, NULL);
923 }
924
925 r = sd_bus_message_exit_container(m);
926 if (r < 0)
927 return synthetic_reply_method_errno(m, r, NULL);
928
929 if (!args)
930 return synthetic_reply_method_errno(m, -EINVAL, NULL);
931
932 r = sd_bus_message_new_method_call(
933 a,
934 &msg,
935 "org.freedesktop.systemd1",
936 "/org/freedesktop/systemd1",
937 "org.freedesktop.systemd1.Manager",
938 "SetEnvironment");
939 if (r < 0)
940 return synthetic_reply_method_errno(m, r, NULL);
941
942 r = sd_bus_message_append_strv(msg, args);
943 if (r < 0)
944 return synthetic_reply_method_errno(m, r, NULL);
945
946 r = sd_bus_call(a, msg, 0, NULL, NULL);
947 if (r < 0)
948 return synthetic_reply_method_errno(m, r, NULL);
949
950 return synthetic_reply_method_return(m, NULL);
951
952 } else {
953 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
954
955 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
956
957 return synthetic_reply_method_errno(m, r, &error);
958 }
959 }
960
961 static int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, Policy *policy, const struct ucred *our_ucred, Set *owned_names) {
962 int r;
963
964 assert(from);
965 assert(to);
966 assert(m);
967
968 if (!policy)
969 return 0;
970
971 if (from->is_kernel) {
972 uid_t sender_uid = (uid_t) -1;
973 gid_t sender_gid = (gid_t) -1;
974 char **sender_names = NULL;
975 bool granted = false;
976
977 /* Driver messages are always OK */
978 if (streq_ptr(m->sender, "org.freedesktop.DBus"))
979 return 0;
980
981 /* The message came from the kernel, and is sent to our legacy client. */
982 r = sd_bus_creds_get_well_known_names(&m->creds, &sender_names);
983 if (r < 0)
984 return r;
985
986 (void) sd_bus_creds_get_uid(&m->creds, &sender_uid);
987 (void) sd_bus_creds_get_gid(&m->creds, &sender_gid);
988
989 /* First check whether the sender can send the message to our name */
990 if (set_isempty(owned_names)) {
991 if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, NULL, m->path, m->interface, m->member))
992 granted = true;
993 } else {
994 Iterator i;
995 char *n;
996
997 SET_FOREACH(n, owned_names, i)
998 if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, n, m->path, m->interface, m->member)) {
999 granted = true;
1000 break;
1001 }
1002 }
1003
1004 if (granted) {
1005 /* Then check whether us, the recipient can recieve from the sender's name */
1006 if (strv_isempty(sender_names)) {
1007 if (policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, m->path, m->interface, m->member))
1008 return 0;
1009 } else {
1010 char **n;
1011
1012 STRV_FOREACH(n, sender_names) {
1013 if (policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, *n, m->path, m->interface, m->member))
1014 return 0;
1015 }
1016 }
1017 }
1018
1019 /* Return an error back to the caller */
1020 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1021 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML receiver policy.");
1022
1023 /* Return 1, indicating that the message shall not be processed any further */
1024 return 1;
1025 }
1026
1027 if (to->is_kernel) {
1028 _cleanup_bus_creds_unref_ sd_bus_creds *destination_creds = NULL;
1029 uid_t destination_uid = (uid_t) -1;
1030 gid_t destination_gid = (gid_t) -1;
1031 const char *destination_unique = NULL;
1032 char **destination_names = NULL;
1033 bool granted = false;
1034
1035 /* Driver messages are always OK */
1036 if (streq_ptr(m->destination, "org.freedesktop.DBus"))
1037 return 0;
1038
1039 /* The message came from the legacy client, and is sent to kdbus. */
1040 if (m->destination) {
1041 r = sd_bus_get_name_creds(to, m->destination,
1042 SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME|
1043 SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID, &destination_creds);
1044 if (r < 0)
1045 return r;
1046
1047 r = sd_bus_creds_get_well_known_names(destination_creds, &destination_names);
1048 if (r < 0)
1049 return r;
1050
1051 r = sd_bus_creds_get_unique_name(destination_creds, &destination_unique);
1052 if (r < 0)
1053 return r;
1054
1055 (void) sd_bus_creds_get_uid(destination_creds, &destination_uid);
1056 (void) sd_bus_creds_get_gid(destination_creds, &destination_gid);
1057 }
1058
1059 /* First check if we, the sender can send to this name */
1060 if (strv_isempty(destination_names)) {
1061 if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, m->path, m->interface, m->member))
1062 granted = true;
1063 } else {
1064 char **n;
1065
1066 STRV_FOREACH(n, destination_names) {
1067 if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, *n, m->path, m->interface, m->member)) {
1068
1069 /* If we made a receiver decision,
1070 then remember which name's policy
1071 we used, and to which unique ID it
1072 mapped when we made the
1073 decision. Then, let's pass this to
1074 the kernel when sending the
1075 message, so that it refuses the
1076 operation should the name and
1077 unique ID not map to each other
1078 anymore. */
1079
1080 r = free_and_strdup(&m->destination_ptr, *n);
1081 if (r < 0)
1082 return r;
1083
1084 r = bus_kernel_parse_unique_name(destination_unique, &m->verify_destination_id);
1085 if (r < 0)
1086 break;
1087
1088 granted = true;
1089 break;
1090 }
1091 }
1092 }
1093
1094 /* Then check if the recipient can receive from our name */
1095 if (granted) {
1096 if (set_isempty(owned_names)) {
1097 if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, NULL, m->path, m->interface, m->member))
1098 return 0;
1099 } else {
1100 Iterator i;
1101 char *n;
1102
1103 SET_FOREACH(n, owned_names, i)
1104 if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, n, m->path, m->interface, m->member))
1105 return 0;
1106 }
1107 }
1108
1109 /* Return an error back to the caller */
1110 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1111 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML sender policy.");
1112
1113 /* Return 1, indicating that the message shall not be processed any further */
1114 return 1;
1115 }
1116
1117 return 0;
1118 }
1119
1120 static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
1121 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
1122 bool is_hello;
1123 int r;
1124
1125 assert(a);
1126 assert(b);
1127 assert(m);
1128 assert(got_hello);
1129
1130 /* As reaction to hello we need to respond with two messages:
1131 * the callback reply and the NameAcquired for the unique
1132 * name, since hello is otherwise obsolete on kdbus. */
1133
1134 is_hello =
1135 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
1136 streq_ptr(m->destination, "org.freedesktop.DBus");
1137
1138 if (!is_hello) {
1139
1140 if (*got_hello)
1141 return 0;
1142
1143 log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
1144 return -EIO;
1145 }
1146
1147 if (*got_hello) {
1148 log_error("Got duplicate hello, aborting.");
1149 return -EIO;
1150 }
1151
1152 *got_hello = true;
1153
1154 if (!a->is_kernel)
1155 return 0;
1156
1157 r = sd_bus_message_new_method_return(m, &n);
1158 if (r < 0) {
1159 log_error_errno(r, "Failed to generate HELLO reply: %m");
1160 return r;
1161 }
1162
1163 r = sd_bus_message_append(n, "s", a->unique_name);
1164 if (r < 0) {
1165 log_error_errno(r, "Failed to append unique name to HELLO reply: %m");
1166 return r;
1167 }
1168
1169 r = bus_message_append_sender(n, "org.freedesktop.DBus");
1170 if (r < 0) {
1171 log_error_errno(r, "Failed to append sender to HELLO reply: %m");
1172 return r;
1173 }
1174
1175 r = bus_seal_synthetic_message(b, n);
1176 if (r < 0) {
1177 log_error_errno(r, "Failed to seal HELLO reply: %m");
1178 return r;
1179 }
1180
1181 r = sd_bus_send(b, n, NULL);
1182 if (r < 0) {
1183 log_error_errno(r, "Failed to send HELLO reply: %m");
1184 return r;
1185 }
1186
1187 n = sd_bus_message_unref(n);
1188 r = sd_bus_message_new_signal(
1189 b,
1190 &n,
1191 "/org/freedesktop/DBus",
1192 "org.freedesktop.DBus",
1193 "NameAcquired");
1194 if (r < 0) {
1195 log_error_errno(r, "Failed to allocate initial NameAcquired message: %m");
1196 return r;
1197 }
1198
1199 r = sd_bus_message_append(n, "s", a->unique_name);
1200 if (r < 0) {
1201 log_error_errno(r, "Failed to append unique name to NameAcquired message: %m");
1202 return r;
1203 }
1204
1205 r = bus_message_append_sender(n, "org.freedesktop.DBus");
1206 if (r < 0) {
1207 log_error_errno(r, "Failed to append sender to NameAcquired message: %m");
1208 return r;
1209 }
1210
1211 r = bus_seal_synthetic_message(b, n);
1212 if (r < 0) {
1213 log_error_errno(r, "Failed to seal NameAcquired message: %m");
1214 return r;
1215 }
1216
1217 r = sd_bus_send(b, n, NULL);
1218 if (r < 0) {
1219 log_error_errno(r, "Failed to send NameAcquired message: %m");
1220 return r;
1221 }
1222
1223 return 1;
1224 }
1225
1226 static int patch_sender(sd_bus *a, sd_bus_message *m) {
1227 char **well_known = NULL;
1228 sd_bus_creds *c;
1229 int r;
1230
1231 assert(a);
1232 assert(m);
1233
1234 if (!a->is_kernel)
1235 return 0;
1236
1237 /* We will change the sender of messages from the bus driver
1238 * so that they originate from the bus driver. This is a
1239 * speciality originating from dbus1, where the bus driver did
1240 * not have a unique id, but only the well-known name. */
1241
1242 c = sd_bus_message_get_creds(m);
1243 if (!c)
1244 return 0;
1245
1246 r = sd_bus_creds_get_well_known_names(c, &well_known);
1247 if (r < 0)
1248 return r;
1249
1250 if (strv_contains(well_known, "org.freedesktop.DBus"))
1251 m->sender = "org.freedesktop.DBus";
1252
1253 return 0;
1254 }
1255
1256 int main(int argc, char *argv[]) {
1257
1258 _cleanup_bus_close_unref_ sd_bus *a = NULL, *b = NULL;
1259 sd_id128_t server_id;
1260 int r, in_fd, out_fd;
1261 bool got_hello = false;
1262 bool is_unix;
1263 struct ucred ucred = {};
1264 _cleanup_free_ char *peersec = NULL;
1265 Policy policy_buffer = {}, *policy = NULL;
1266 _cleanup_set_free_free_ Set *owned_names = NULL;
1267
1268 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
1269 log_parse_environment();
1270 log_open();
1271
1272 r = parse_argv(argc, argv);
1273 if (r <= 0)
1274 goto finish;
1275
1276 r = sd_listen_fds(0);
1277 if (r == 0) {
1278 in_fd = STDIN_FILENO;
1279 out_fd = STDOUT_FILENO;
1280 } else if (r == 1) {
1281 in_fd = SD_LISTEN_FDS_START;
1282 out_fd = SD_LISTEN_FDS_START;
1283 } else {
1284 log_error("Illegal number of file descriptors passed");
1285 goto finish;
1286 }
1287
1288 is_unix =
1289 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
1290 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
1291
1292 if (is_unix) {
1293 (void) getpeercred(in_fd, &ucred);
1294 (void) getpeersec(in_fd, &peersec);
1295 }
1296
1297 if (arg_drop_privileges) {
1298 const char *user = "systemd-bus-proxy";
1299 uid_t uid;
1300 gid_t gid;
1301
1302 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
1303 if (r < 0) {
1304 log_error_errno(r, "Cannot resolve user name %s: %m", user);
1305 goto finish;
1306 }
1307
1308 r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
1309 if (r < 0)
1310 goto finish;
1311 }
1312
1313 owned_names = set_new(&string_hash_ops);
1314 if (!owned_names) {
1315 log_oom();
1316 goto finish;
1317 }
1318
1319 r = sd_bus_new(&a);
1320 if (r < 0) {
1321 log_error_errno(r, "Failed to allocate bus: %m");
1322 goto finish;
1323 }
1324
1325 r = sd_bus_set_description(a, "sd-proxy");
1326 if (r < 0) {
1327 log_error_errno(r, "Failed to set bus name: %m");
1328 goto finish;
1329 }
1330
1331 r = sd_bus_set_address(a, arg_address);
1332 if (r < 0) {
1333 log_error_errno(r, "Failed to set address to connect to: %m");
1334 goto finish;
1335 }
1336
1337 r = sd_bus_negotiate_fds(a, is_unix);
1338 if (r < 0) {
1339 log_error_errno(r, "Failed to set FD negotiation: %m");
1340 goto finish;
1341 }
1342
1343 r = sd_bus_negotiate_creds(a, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_GID|SD_BUS_CREDS_SELINUX_CONTEXT);
1344 if (r < 0) {
1345 log_error_errno(r, "Failed to set credential negotiation: %m");
1346 goto finish;
1347 }
1348
1349 if (ucred.pid > 0) {
1350 a->fake_pids.pid = ucred.pid;
1351 a->fake_pids_valid = true;
1352
1353 a->fake_creds.uid = ucred.uid;
1354 a->fake_creds.euid = (uid_t) -1;
1355 a->fake_creds.suid = (uid_t) -1;
1356 a->fake_creds.fsuid = (uid_t) -1;
1357 a->fake_creds.gid = ucred.gid;
1358 a->fake_creds.egid = (gid_t) -1;
1359 a->fake_creds.sgid = (gid_t) -1;
1360 a->fake_creds.fsgid = (gid_t) -1;
1361 a->fake_creds_valid = true;
1362 }
1363
1364 if (peersec) {
1365 a->fake_label = peersec;
1366 peersec = NULL;
1367 }
1368
1369 a->manual_peer_interface = true;
1370
1371 r = sd_bus_start(a);
1372 if (r < 0) {
1373 log_error_errno(r, "Failed to start bus client: %m");
1374 goto finish;
1375 }
1376
1377 r = sd_bus_get_owner_id(a, &server_id);
1378 if (r < 0) {
1379 log_error_errno(r, "Failed to get server ID: %m");
1380 goto finish;
1381 }
1382
1383 if (a->is_kernel) {
1384 if (!arg_configuration) {
1385 const char *scope;
1386
1387 r = sd_bus_get_scope(a, &scope);
1388 if (r < 0) {
1389 log_error_errno(r, "Couldn't determine bus scope: %m");
1390 goto finish;
1391 }
1392
1393 if (streq(scope, "system"))
1394 arg_configuration = strv_new(
1395 "/etc/dbus-1/system.conf",
1396 "/etc/dbus-1/system.d/",
1397 "/etc/dbus-1/system-local.conf",
1398 NULL);
1399 else if (streq(scope, "user"))
1400 arg_configuration = strv_new(
1401 "/etc/dbus-1/session.conf",
1402 "/etc/dbus-1/session.d/",
1403 "/etc/dbus-1/session-local.conf",
1404 NULL);
1405 else {
1406 log_error("Unknown scope %s, don't know which policy to load. Refusing.", scope);
1407 goto finish;
1408 }
1409
1410 if (!arg_configuration) {
1411 r = log_oom();
1412 goto finish;
1413 }
1414 }
1415
1416 r = policy_load(&policy_buffer, arg_configuration);
1417 if (r < 0) {
1418 log_error_errno(r, "Failed to load policy: %m");
1419 goto finish;
1420 }
1421
1422 policy = &policy_buffer;
1423 policy_dump(policy);
1424
1425 if (!policy_check_hello(policy, ucred.uid, ucred.gid)) {
1426 r = log_error_errno(EPERM, "Policy denied connection.");
1427 goto finish;
1428 }
1429 }
1430
1431 r = sd_bus_new(&b);
1432 if (r < 0) {
1433 log_error_errno(r, "Failed to allocate bus: %m");
1434 goto finish;
1435 }
1436
1437 r = sd_bus_set_fd(b, in_fd, out_fd);
1438 if (r < 0) {
1439 log_error_errno(r, "Failed to set fds: %m");
1440 goto finish;
1441 }
1442
1443 r = sd_bus_set_server(b, 1, server_id);
1444 if (r < 0) {
1445 log_error_errno(r, "Failed to set server mode: %m");
1446 goto finish;
1447 }
1448
1449 r = sd_bus_negotiate_fds(b, is_unix);
1450 if (r < 0) {
1451 log_error_errno(r, "Failed to set FD negotiation: %m");
1452 goto finish;
1453 }
1454
1455 r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_GID|SD_BUS_CREDS_SELINUX_CONTEXT);
1456 if (r < 0) {
1457 log_error_errno(r, "Failed to set credential negotiation: %m");
1458 goto finish;
1459 }
1460
1461 r = sd_bus_set_anonymous(b, true);
1462 if (r < 0) {
1463 log_error_errno(r, "Failed to set anonymous authentication: %m");
1464 goto finish;
1465 }
1466
1467 b->manual_peer_interface = true;
1468
1469 r = sd_bus_start(b);
1470 if (r < 0) {
1471 log_error_errno(r, "Failed to start bus client: %m");
1472 goto finish;
1473 }
1474
1475 r = rename_service(a, b);
1476 if (r < 0)
1477 log_debug_errno(r, "Failed to rename process: %m");
1478
1479 if (a->is_kernel) {
1480 _cleanup_free_ char *match = NULL;
1481 const char *unique;
1482
1483 r = sd_bus_get_unique_name(a, &unique);
1484 if (r < 0) {
1485 log_error_errno(r, "Failed to get unique name: %m");
1486 goto finish;
1487 }
1488
1489 match = strjoin("type='signal',"
1490 "sender='org.freedesktop.DBus',"
1491 "path='/org/freedesktop/DBus',"
1492 "interface='org.freedesktop.DBus',"
1493 "member='NameOwnerChanged',"
1494 "arg1='",
1495 unique,
1496 "'",
1497 NULL);
1498 if (!match) {
1499 log_oom();
1500 goto finish;
1501 }
1502
1503 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1504 if (r < 0) {
1505 log_error_errno(r, "Failed to add match for NameLost: %m");
1506 goto finish;
1507 }
1508
1509 free(match);
1510 match = strjoin("type='signal',"
1511 "sender='org.freedesktop.DBus',"
1512 "path='/org/freedesktop/DBus',"
1513 "interface='org.freedesktop.DBus',"
1514 "member='NameOwnerChanged',"
1515 "arg2='",
1516 unique,
1517 "'",
1518 NULL);
1519 if (!match) {
1520 log_oom();
1521 goto finish;
1522 }
1523
1524 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
1525 if (r < 0) {
1526 log_error_errno(r, "Failed to add match for NameAcquired: %m");
1527 goto finish;
1528 }
1529 }
1530
1531 for (;;) {
1532 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1533 int events_a, events_b, fd;
1534 uint64_t timeout_a, timeout_b, t;
1535 struct timespec _ts, *ts;
1536 struct pollfd *pollfd;
1537 int k;
1538
1539 if (got_hello) {
1540 /* Read messages from bus, to pass them on to our client */
1541
1542 r = sd_bus_process(a, &m);
1543 if (r < 0) {
1544 /* treat 'connection reset by peer' as clean exit condition */
1545 if (r == -ECONNRESET)
1546 r = 0;
1547 else
1548 log_error_errno(r, "Failed to process bus a: %m");
1549
1550 goto finish;
1551 }
1552
1553 if (m) {
1554 bool processed = false;
1555
1556 /* We officially got EOF, let's quit */
1557 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1558 r = 0;
1559 goto finish;
1560 }
1561
1562 k = synthesize_name_acquired(a, b, m);
1563 if (k < 0) {
1564 r = k;
1565 log_error_errno(r, "Failed to synthesize message: %m");
1566 goto finish;
1567 }
1568
1569 patch_sender(a, m);
1570
1571 if (policy) {
1572 k = process_policy(a, b, m, policy, &ucred, owned_names);
1573 if (k < 0) {
1574 r = k;
1575 log_error_errno(r, "Failed to process policy: %m");
1576 goto finish;
1577 } else if (k > 0) {
1578 r = 1;
1579 processed = true;
1580 }
1581 }
1582
1583 if (!processed) {
1584 k = sd_bus_send(b, m, NULL);
1585 if (k < 0) {
1586 if (k == -ECONNRESET)
1587 r = 0;
1588 else {
1589 r = k;
1590 log_error_errno(r, "Failed to send message to client: %m");
1591 }
1592
1593 goto finish;
1594 } else
1595 r = 1;
1596 }
1597 }
1598
1599 if (r > 0)
1600 continue;
1601 }
1602
1603 /* Read messages from our client, to pass them on to the bus */
1604 r = sd_bus_process(b, &m);
1605 if (r < 0) {
1606 /* treat 'connection reset by peer' as clean exit condition */
1607 if (r == -ECONNRESET)
1608 r = 0;
1609 else
1610 log_error_errno(r, "Failed to process bus b: %m");
1611
1612 goto finish;
1613 }
1614
1615 if (m) {
1616 bool processed = false;
1617
1618 /* We officially got EOF, let's quit */
1619 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
1620 r = 0;
1621 goto finish;
1622 }
1623
1624 k = process_hello(a, b, m, &got_hello);
1625 if (k < 0) {
1626 r = k;
1627 log_error_errno(r, "Failed to process HELLO: %m");
1628 goto finish;
1629 } else if (k > 0) {
1630 processed = true;
1631 r = 1;
1632 }
1633
1634 if (!processed) {
1635 k = process_driver(a, b, m, policy, &ucred, owned_names);
1636 if (k < 0) {
1637 r = k;
1638 log_error_errno(r, "Failed to process driver calls: %m");
1639 goto finish;
1640 } else if (k > 0) {
1641 processed = true;
1642 r = 1;
1643 }
1644
1645 if (!processed) {
1646
1647 for (;;) {
1648 if (policy) {
1649 k = process_policy(b, a, m, policy, &ucred, owned_names);
1650 if (k < 0) {
1651 r = k;
1652 log_error_errno(r, "Failed to process policy: %m");
1653 goto finish;
1654 } else if (k > 0) {
1655 processed = true;
1656 r = 1;
1657 break;
1658 }
1659 }
1660
1661 k = sd_bus_send(a, m, NULL);
1662 if (k < 0) {
1663 if (k == -EREMCHG)
1664 /* The name database changed since the policy check, hence let's check again */
1665 continue;
1666 else if (k == -ECONNRESET)
1667 r = 0;
1668 else {
1669 r = k;
1670 log_error_errno(r, "Failed to send message to bus: %m");
1671 }
1672
1673 goto finish;
1674 } else
1675 r = 1;
1676
1677 break;
1678 }
1679 }
1680 }
1681 }
1682
1683 if (r > 0)
1684 continue;
1685
1686 fd = sd_bus_get_fd(a);
1687 if (fd < 0) {
1688 log_error_errno(r, "Failed to get fd: %m");
1689 goto finish;
1690 }
1691
1692 events_a = sd_bus_get_events(a);
1693 if (events_a < 0) {
1694 log_error_errno(r, "Failed to get events mask: %m");
1695 goto finish;
1696 }
1697
1698 r = sd_bus_get_timeout(a, &timeout_a);
1699 if (r < 0) {
1700 log_error_errno(r, "Failed to get timeout: %m");
1701 goto finish;
1702 }
1703
1704 events_b = sd_bus_get_events(b);
1705 if (events_b < 0) {
1706 log_error_errno(r, "Failed to get events mask: %m");
1707 goto finish;
1708 }
1709
1710 r = sd_bus_get_timeout(b, &timeout_b);
1711 if (r < 0) {
1712 log_error_errno(r, "Failed to get timeout: %m");
1713 goto finish;
1714 }
1715
1716 t = timeout_a;
1717 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
1718 t = timeout_b;
1719
1720 if (t == (uint64_t) -1)
1721 ts = NULL;
1722 else {
1723 usec_t nw;
1724
1725 nw = now(CLOCK_MONOTONIC);
1726 if (t > nw)
1727 t -= nw;
1728 else
1729 t = 0;
1730
1731 ts = timespec_store(&_ts, t);
1732 }
1733
1734 pollfd = (struct pollfd[3]) {
1735 {.fd = fd, .events = events_a, },
1736 {.fd = in_fd, .events = events_b & POLLIN, },
1737 {.fd = out_fd, .events = events_b & POLLOUT, }
1738 };
1739
1740 r = ppoll(pollfd, 3, ts, NULL);
1741 if (r < 0) {
1742 log_error("ppoll() failed: %m");
1743 goto finish;
1744 }
1745 }
1746
1747 finish:
1748 sd_notify(false,
1749 "STOPPING=1\n"
1750 "STATUS=Shutting down.");
1751
1752 policy_free(&policy_buffer);
1753 strv_free(arg_configuration);
1754 free(arg_address);
1755
1756 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1757 }