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