chiark / gitweb /
6a72d181fe833398848a4f156bdd14b2f175cedd
[elogind.git] / src / bus-proxyd / driver.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/types.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <stddef.h>
29
30 #include "log.h"
31 #include "util.h"
32 #include "sd-bus.h"
33 #include "bus-internal.h"
34 #include "bus-message.h"
35 #include "bus-util.h"
36 #include "build.h"
37 #include "strv.h"
38 #include "def.h"
39 #include "capability.h"
40 #include "bus-control.h"
41 #include "set.h"
42 #include "driver.h"
43 #include "synthesize.h"
44
45 static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
46         _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
47         int r;
48
49         assert(bus);
50         assert(name);
51         assert(_creds);
52
53         r = sd_bus_get_name_creds(bus, name, mask, &c);
54         if (r == -ESRCH || r == -ENXIO)
55                 return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
56         if (r < 0)
57                 return r;
58
59         if ((c->mask & mask) != mask)
60                 return -ENOTSUP;
61
62         *_creds = c;
63         c = NULL;
64
65         return 0;
66 }
67
68 static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
69         const char *name;
70         int r;
71
72         assert(bus);
73         assert(m);
74         assert(_creds);
75
76         r = sd_bus_message_read(m, "s", &name);
77         if (r < 0)
78                 return r;
79
80         return get_creds_by_name(bus, name, mask, _creds, error);
81 }
82
83 int bus_proxy_process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names) {
84         int r;
85
86         assert(a);
87         assert(b);
88         assert(m);
89
90         if (!a->is_kernel)
91                 return 0;
92
93         if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
94                 return 0;
95
96         /* The "Hello()" call is is handled in process_hello() */
97
98         if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
99
100                 if (!sd_bus_message_has_signature(m, ""))
101                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
102
103                 return synthetic_reply_method_return(m, "s",
104                         "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
105                           "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
106                         "<node>\n"
107                         " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
108                         "  <method name=\"Introspect\">\n"
109                         "   <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
110                         "  </method>\n"
111                         " </interface>\n"
112                         " <interface name=\"org.freedesktop.DBus\">\n"
113                         "  <method name=\"AddMatch\">\n"
114                         "   <arg type=\"s\" direction=\"in\"/>\n"
115                         "  </method>\n"
116                         "  <method name=\"RemoveMatch\">\n"
117                         "   <arg type=\"s\" direction=\"in\"/>\n"
118                         "  </method>\n"
119                         "  <method name=\"GetConnectionSELinuxSecurityContext\">\n"
120                         "   <arg type=\"s\" direction=\"in\"/>\n"
121                         "   <arg type=\"ay\" direction=\"out\"/>\n"
122                         "  </method>\n"
123                         "  <method name=\"GetConnectionUnixProcessID\">\n"
124                         "   <arg type=\"s\" direction=\"in\"/>\n"
125                         "   <arg type=\"u\" direction=\"out\"/>\n"
126                         "  </method>\n"
127                         "  <method name=\"GetConnectionUnixUser\">\n"
128                         "   <arg type=\"s\" direction=\"in\"/>\n"
129                         "   <arg type=\"u\" direction=\"out\"/>\n"
130                         "  </method>\n"
131                         "  <method name=\"GetId\">\n"
132                         "   <arg type=\"s\" direction=\"out\"/>\n"
133                         "  </method>\n"
134                         "  <method name=\"GetNameOwner\">\n"
135                         "   <arg type=\"s\" direction=\"in\"/>\n"
136                         "   <arg type=\"s\" direction=\"out\"/>\n"
137                         "  </method>\n"
138                         "  <method name=\"Hello\">\n"
139                         "   <arg type=\"s\" direction=\"out\"/>\n"
140                         "  </method>\n"
141                         "  <method name=\"ListActivatableNames\">\n"
142                         "   <arg type=\"as\" direction=\"out\"/>\n"
143                         "  </method>\n"
144                         "  <method name=\"ListNames\">\n"
145                         "   <arg type=\"as\" direction=\"out\"/>\n"
146                         "  </method>\n"
147                         "  <method name=\"ListQueuedOwners\">\n"
148                         "   <arg type=\"s\" direction=\"in\"/>\n"
149                         "   <arg type=\"as\" direction=\"out\"/>\n"
150                         "  </method>\n"
151                         "  <method name=\"NameHasOwner\">\n"
152                         "   <arg type=\"s\" direction=\"in\"/>\n"
153                         "   <arg type=\"b\" direction=\"out\"/>\n"
154                         "  </method>\n"
155                         "  <method name=\"ReleaseName\">\n"
156                         "   <arg type=\"s\" direction=\"in\"/>\n"
157                         "   <arg type=\"u\" direction=\"out\"/>\n"
158                         "  </method>\n"
159                         "  <method name=\"ReloadConfig\">\n"
160                         "  </method>\n"
161                         "  <method name=\"RequestName\">\n"
162                         "   <arg type=\"s\" direction=\"in\"/>\n"
163                         "   <arg type=\"u\" direction=\"in\"/>\n"
164                         "   <arg type=\"u\" direction=\"out\"/>\n"
165                         "  </method>\n"
166                         "  <method name=\"StartServiceByName\">\n"
167                         "   <arg type=\"s\" direction=\"in\"/>\n"
168                         "   <arg type=\"u\" direction=\"in\"/>\n"
169                         "   <arg type=\"u\" direction=\"out\"/>\n"
170                         "  </method>\n"
171                         "  <method name=\"UpdateActivationEnvironment\">\n"
172                         "   <arg type=\"a{ss}\" direction=\"in\"/>\n"
173                         "  </method>\n"
174                         "  <signal name=\"NameAcquired\">\n"
175                         "   <arg type=\"s\"/>\n"
176                         "  </signal>\n"
177                         "  <signal name=\"NameLost\">\n"
178                         "   <arg type=\"s\"/>\n"
179                         "  </signal>\n"
180                         "  <signal name=\"NameOwnerChanged\">\n"
181                         "   <arg type=\"s\"/>\n"
182                         "   <arg type=\"s\"/>\n"
183                         "   <arg type=\"s\"/>\n"
184                         "  </signal>\n"
185                         " </interface>\n"
186                         "</node>\n");
187
188         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
189                 const char *match;
190
191                 if (!sd_bus_message_has_signature(m, "s"))
192                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
193
194                 r = sd_bus_message_read(m, "s", &match);
195                 if (r < 0)
196                         return synthetic_reply_method_errno(m, r, NULL);
197
198                 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
199                 if (r < 0)
200                         return synthetic_reply_method_errno(m, r, NULL);
201
202                 return synthetic_reply_method_return(m, NULL);
203
204         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
205                 const char *match;
206
207                 if (!sd_bus_message_has_signature(m, "s"))
208                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
209
210                 r = sd_bus_message_read(m, "s", &match);
211                 if (r < 0)
212                         return synthetic_reply_method_errno(m, r, NULL);
213
214                 r = bus_remove_match_by_string(a, match, NULL, NULL);
215                 if (r == 0)
216                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
217                 if (r < 0)
218                         return synthetic_reply_method_errno(m, r, NULL);
219
220                 return synthetic_reply_method_return(m, NULL);
221
222         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
223                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
224                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
225
226                 if (!sd_bus_message_has_signature(m, "s"))
227                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
228
229                 r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error);
230                 if (r < 0)
231                         return synthetic_reply_method_errno(m, r, &error);
232
233                 return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
234
235         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
236                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
237                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
238
239                 if (!sd_bus_message_has_signature(m, "s"))
240                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
241
242                 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, &error);
243                 if (r < 0)
244                         return synthetic_reply_method_errno(m, r, &error);
245
246                 return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
247
248         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
249                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
250                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
251
252                 if (!sd_bus_message_has_signature(m, "s"))
253                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
254
255                 r = get_creds_by_message(a, m, SD_BUS_CREDS_EUID, &creds, &error);
256                 if (r < 0)
257                         return synthetic_reply_method_errno(m, r, &error);
258
259                 return synthetic_reply_method_return(m, "u", (uint32_t) creds->euid);
260
261         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
262                 sd_id128_t server_id;
263                 char buf[SD_ID128_STRING_MAX];
264
265                 if (!sd_bus_message_has_signature(m, ""))
266                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
267
268                 r = sd_bus_get_bus_id(a, &server_id);
269                 if (r < 0)
270                         return synthetic_reply_method_errno(m, r, NULL);
271
272                 return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
273
274         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
275                 const char *name;
276                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
277                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
278
279                 if (!sd_bus_message_has_signature(m, "s"))
280                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
281
282                 r = sd_bus_message_read(m, "s", &name);
283                 if (r < 0)
284                         return synthetic_reply_method_errno(m, r, NULL);
285
286                 if (streq(name, "org.freedesktop.DBus"))
287                         return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
288
289                 r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
290                 if (r < 0)
291                         return synthetic_reply_method_errno(m, r, &error);
292
293                 return synthetic_reply_method_return(m, "s", creds->unique_name);
294
295         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
296                 _cleanup_strv_free_ char **names = NULL;
297
298                 if (!sd_bus_message_has_signature(m, ""))
299                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
300
301                 r = sd_bus_list_names(a, NULL, &names);
302                 if (r < 0)
303                         return synthetic_reply_method_errno(m, r, NULL);
304
305                 /* Let's sort the names list to make it stable */
306                 strv_sort(names);
307
308                 return synthetic_reply_return_strv(m, names);
309
310         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
311                 _cleanup_strv_free_ char **names = NULL;
312
313                 if (!sd_bus_message_has_signature(m, ""))
314                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
315
316                 r = sd_bus_list_names(a, &names, NULL);
317                 if (r < 0)
318                         return synthetic_reply_method_errno(m, r, NULL);
319
320                 r = strv_extend(&names, "org.freedesktop.DBus");
321                 if (r < 0)
322                         return synthetic_reply_method_errno(m, r, NULL);
323
324                 /* Let's sort the names list to make it stable */
325                 strv_sort(names);
326
327                 return synthetic_reply_return_strv(m, names);
328
329         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
330                 struct kdbus_cmd_name_list cmd = {};
331                 struct kdbus_name_list *name_list;
332                 struct kdbus_name_info *name;
333                 _cleanup_strv_free_ char **owners = NULL;
334                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
335                 char *arg0;
336                 int err = 0;
337
338                 if (!sd_bus_message_has_signature(m, "s"))
339                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
340
341                 r = sd_bus_message_read(m, "s", &arg0);
342                 if (r < 0)
343                         return synthetic_reply_method_errno(m, r, NULL);
344
345                 r = sd_bus_get_name_creds(a, arg0, 0, NULL);
346                 if (r == -ESRCH || r == -ENXIO) {
347                         sd_bus_error_setf(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name.", arg0);
348                         return synthetic_reply_method_errno(m, r, &error);
349                 }
350                 if (r < 0)
351                         return synthetic_reply_method_errno(m, r, NULL);
352
353                 cmd.flags = KDBUS_NAME_LIST_QUEUED;
354                 r = ioctl(a->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
355                 if (r < 0)
356                         return synthetic_reply_method_errno(m, -errno, NULL);
357
358                 name_list = (struct kdbus_name_list *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
359
360                 KDBUS_ITEM_FOREACH(name, name_list, names) {
361                         const char *entry_name = NULL;
362                         struct kdbus_item *item;
363                         char *n;
364
365                         KDBUS_ITEM_FOREACH(item, name, items)
366                                 if (item->type == KDBUS_ITEM_OWNED_NAME)
367                                         entry_name = item->name.name;
368
369                         if (!streq_ptr(entry_name, arg0))
370                                 continue;
371
372                         if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
373                                 err  = -ENOMEM;
374                                 break;
375                         }
376
377                         r = strv_consume(&owners, n);
378                         if (r < 0) {
379                                 err = r;
380                                 break;
381                         }
382                 }
383
384                 r = bus_kernel_cmd_free(a, cmd.offset);
385                 if (r < 0)
386                         return synthetic_reply_method_errno(m, r, NULL);
387
388                 if (err < 0)
389                         return synthetic_reply_method_errno(m, err, NULL);
390
391                 return synthetic_reply_return_strv(m, owners);
392
393         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
394                 const char *name;
395
396                 if (!sd_bus_message_has_signature(m, "s"))
397                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
398
399                 r = sd_bus_message_read(m, "s", &name);
400                 if (r < 0)
401                         return synthetic_reply_method_errno(m, r, NULL);
402
403                 if (streq(name, "org.freedesktop.DBus"))
404                         return synthetic_reply_method_return(m, "b", true);
405
406                 r = sd_bus_get_name_creds(a, name, 0, NULL);
407                 if (r < 0 && r != -ESRCH && r != -ENXIO)
408                         return synthetic_reply_method_errno(m, r, NULL);
409
410                 return synthetic_reply_method_return(m, "b", r >= 0);
411
412         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
413                 const char *name;
414
415                 if (!sd_bus_message_has_signature(m, "s"))
416                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
417
418                 r = sd_bus_message_read(m, "s", &name);
419                 if (r < 0)
420                         return synthetic_reply_method_errno(m, r, NULL);
421
422                 r = sd_bus_release_name(a, name);
423                 if (r < 0) {
424                         if (r == -ESRCH)
425                                 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
426                         if (r == -EADDRINUSE)
427                                 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
428
429                         return synthetic_reply_method_errno(m, r, NULL);
430                 }
431
432                 set_remove(owned_names, (char*) name);
433
434                 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
435
436         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
437                 if (!sd_bus_message_has_signature(m, ""))
438                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
439
440                 r = shared_policy_reload(sp);
441                 if (r < 0)
442                         return synthetic_reply_method_errno(m, r, NULL);
443
444                 return synthetic_reply_method_return(m, NULL);
445
446         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
447                 const char *name;
448                 uint32_t flags, param;
449                 bool in_queue;
450
451                 if (!sd_bus_message_has_signature(m, "su"))
452                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
453
454                 r = sd_bus_message_read(m, "su", &name, &flags);
455                 if (r < 0)
456                         return synthetic_reply_method_errno(m, r, NULL);
457
458                 if (sp) {
459                         Policy *policy;
460                         bool denied;
461
462                         policy = shared_policy_acquire(sp);
463                         denied = !policy_check_own(policy, ucred->uid, ucred->gid, name);
464                         shared_policy_release(sp, policy);
465                         if (denied)
466                                 return synthetic_reply_method_errno(m, -EPERM, NULL);
467                 }
468
469                 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
470                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
471
472                 param = 0;
473                 if (flags & BUS_NAME_ALLOW_REPLACEMENT)
474                         param |= SD_BUS_NAME_ALLOW_REPLACEMENT;
475                 if (flags & BUS_NAME_REPLACE_EXISTING)
476                         param |= SD_BUS_NAME_REPLACE_EXISTING;
477                 if (!(flags & BUS_NAME_DO_NOT_QUEUE))
478                         param |= SD_BUS_NAME_QUEUE;
479
480                 r = set_put_strdup(owned_names, name);
481                 if (r < 0)
482                         return synthetic_reply_method_errno(m, r, NULL);
483
484                 r = sd_bus_request_name(a, name, param);
485                 if (r < 0) {
486                         if (r == -EALREADY)
487                                 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
488
489                         set_remove(owned_names, (char*) name);
490
491                         if (r == -EEXIST)
492                                 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
493                         return synthetic_reply_method_errno(m, r, NULL);
494                 }
495
496                 in_queue = (r == 0);
497
498                 if (in_queue)
499                         return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
500
501                 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
502
503         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
504                 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
505                 const char *name;
506                 uint32_t flags;
507
508                 if (!sd_bus_message_has_signature(m, "su"))
509                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
510
511                 r = sd_bus_message_read(m, "su", &name, &flags);
512                 if (r < 0)
513                         return synthetic_reply_method_errno(m, r, NULL);
514
515                 if (flags != 0)
516                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
517
518                 r = sd_bus_get_name_creds(a, name, 0, NULL);
519                 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
520                         return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
521                 if (r != -ESRCH)
522                         return synthetic_reply_method_errno(m, r, NULL);
523
524                 r = sd_bus_message_new_method_call(
525                                 a,
526                                 &msg,
527                                 name,
528                                 "/",
529                                 "org.freedesktop.DBus.Peer",
530                                 "Ping");
531                 if (r < 0)
532                         return synthetic_reply_method_errno(m, r, NULL);
533
534                 r = sd_bus_send(a, msg, NULL);
535                 if (r < 0)
536                         return synthetic_reply_method_errno(m, r, NULL);
537
538                 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
539
540         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
541                 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
542                 _cleanup_strv_free_ char **args = NULL;
543
544                 if (!sd_bus_message_has_signature(m, "a{ss}"))
545                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
546
547                 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
548                 if (r < 0)
549                         return synthetic_reply_method_errno(m, r, NULL);
550
551                 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
552                         _cleanup_free_ char *s = NULL;
553                         const char *key;
554                         const char *value;
555
556                         r = sd_bus_message_read(m, "ss", &key, &value);
557                         if (r < 0)
558                                 return synthetic_reply_method_errno(m, r, NULL);
559
560                         s = strjoin(key, "=", value, NULL);
561                         if (!s)
562                                 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
563
564                         r  = strv_extend(&args, s);
565                         if (r < 0)
566                                 return synthetic_reply_method_errno(m, r, NULL);
567
568                         r = sd_bus_message_exit_container(m);
569                         if (r < 0)
570                                 return synthetic_reply_method_errno(m, r, NULL);
571                 }
572
573                 r = sd_bus_message_exit_container(m);
574                 if (r < 0)
575                         return synthetic_reply_method_errno(m, r, NULL);
576
577                 if (!args)
578                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
579
580                 r = sd_bus_message_new_method_call(
581                                 a,
582                                 &msg,
583                                 "org.freedesktop.systemd1",
584                                 "/org/freedesktop/systemd1",
585                                 "org.freedesktop.systemd1.Manager",
586                                 "SetEnvironment");
587                 if (r < 0)
588                         return synthetic_reply_method_errno(m, r, NULL);
589
590                 r = sd_bus_message_append_strv(msg, args);
591                 if (r < 0)
592                         return synthetic_reply_method_errno(m, r, NULL);
593
594                 r = sd_bus_call(a, msg, 0, NULL, NULL);
595                 if (r < 0)
596                         return synthetic_reply_method_errno(m, r, NULL);
597
598                 return synthetic_reply_method_return(m, NULL);
599
600         } else {
601                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
602
603                 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
604
605                 return synthetic_reply_method_errno(m, r, &error);
606         }
607 }