chiark / gitweb /
bd2b0a82cb010ddecdddbab9628928a81047b5a7
[elogind.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 }