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