chiark / gitweb /
bc2c0c86f33b5c22d7a2d098aed826b4ea5018aa
[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_method_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_method_return_strv(m, names);
328
329         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
330                 struct kdbus_cmd_list cmd = {
331                         .flags = KDBUS_LIST_QUEUED,
332                         .size = sizeof(cmd),
333                 };
334                 struct kdbus_info *name_list, *name;
335                 _cleanup_strv_free_ char **owners = NULL;
336                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
337                 char *arg0;
338                 int err = 0;
339
340                 if (!sd_bus_message_has_signature(m, "s"))
341                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
342
343                 r = sd_bus_message_read(m, "s", &arg0);
344                 if (r < 0)
345                         return synthetic_reply_method_errno(m, r, NULL);
346
347                 r = sd_bus_get_name_creds(a, arg0, 0, NULL);
348                 if (r == -ESRCH || r == -ENXIO) {
349                         sd_bus_error_setf(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name.", arg0);
350                         return synthetic_reply_method_errno(m, r, &error);
351                 }
352                 if (r < 0)
353                         return synthetic_reply_method_errno(m, r, NULL);
354
355                 r = ioctl(a->input_fd, KDBUS_CMD_LIST, &cmd);
356                 if (r < 0)
357                         return synthetic_reply_method_errno(m, -errno, NULL);
358
359                 name_list = (struct kdbus_info *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
360
361                 KDBUS_FOREACH(name, name_list, cmd.list_size) {
362                         const char *entry_name = NULL;
363                         struct kdbus_item *item;
364                         char *n;
365
366                         KDBUS_ITEM_FOREACH(item, name, items)
367                                 if (item->type == KDBUS_ITEM_OWNED_NAME)
368                                         entry_name = item->name.name;
369
370                         if (!streq_ptr(entry_name, arg0))
371                                 continue;
372
373                         if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) {
374                                 err  = -ENOMEM;
375                                 break;
376                         }
377
378                         r = strv_consume(&owners, n);
379                         if (r < 0) {
380                                 err = r;
381                                 break;
382                         }
383                 }
384
385                 r = bus_kernel_cmd_free(a, cmd.offset);
386                 if (r < 0)
387                         return synthetic_reply_method_errno(m, r, NULL);
388
389                 if (err < 0)
390                         return synthetic_reply_method_errno(m, err, NULL);
391
392                 return synthetic_reply_method_return_strv(m, owners);
393
394         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
395                 const char *name;
396
397                 if (!sd_bus_message_has_signature(m, "s"))
398                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
399
400                 r = sd_bus_message_read(m, "s", &name);
401                 if (r < 0)
402                         return synthetic_reply_method_errno(m, r, NULL);
403
404                 if (streq(name, "org.freedesktop.DBus"))
405                         return synthetic_reply_method_return(m, "b", true);
406
407                 r = sd_bus_get_name_creds(a, name, 0, NULL);
408                 if (r < 0 && r != -ESRCH && r != -ENXIO)
409                         return synthetic_reply_method_errno(m, r, NULL);
410
411                 return synthetic_reply_method_return(m, "b", r >= 0);
412
413         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
414                 const char *name;
415
416                 if (!sd_bus_message_has_signature(m, "s"))
417                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
418
419                 r = sd_bus_message_read(m, "s", &name);
420                 if (r < 0)
421                         return synthetic_reply_method_errno(m, r, NULL);
422
423                 r = sd_bus_release_name(a, name);
424                 if (r < 0) {
425                         if (r == -ESRCH)
426                                 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
427                         if (r == -EADDRINUSE)
428                                 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
429
430                         return synthetic_reply_method_errno(m, r, NULL);
431                 }
432
433                 set_remove(owned_names, (char*) name);
434
435                 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
436
437         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
438                 if (!sd_bus_message_has_signature(m, ""))
439                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
440
441                 r = shared_policy_reload(sp);
442                 if (r < 0)
443                         return synthetic_reply_method_errno(m, r, NULL);
444
445                 return synthetic_reply_method_return(m, NULL);
446
447         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
448                 const char *name;
449                 uint32_t flags, param;
450                 bool in_queue;
451
452                 if (!sd_bus_message_has_signature(m, "su"))
453                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
454
455                 r = sd_bus_message_read(m, "su", &name, &flags);
456                 if (r < 0)
457                         return synthetic_reply_method_errno(m, r, NULL);
458
459                 if (sp) {
460                         Policy *policy;
461                         bool denied;
462
463                         policy = shared_policy_acquire(sp);
464                         denied = !policy_check_own(policy, ucred->uid, ucred->gid, name);
465                         shared_policy_release(sp, policy);
466                         if (denied)
467                                 return synthetic_reply_method_errno(m, -EPERM, NULL);
468                 }
469
470                 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
471                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
472
473                 param = 0;
474                 if (flags & BUS_NAME_ALLOW_REPLACEMENT)
475                         param |= SD_BUS_NAME_ALLOW_REPLACEMENT;
476                 if (flags & BUS_NAME_REPLACE_EXISTING)
477                         param |= SD_BUS_NAME_REPLACE_EXISTING;
478                 if (!(flags & BUS_NAME_DO_NOT_QUEUE))
479                         param |= SD_BUS_NAME_QUEUE;
480
481                 r = set_put_strdup(owned_names, name);
482                 if (r < 0)
483                         return synthetic_reply_method_errno(m, r, NULL);
484
485                 r = sd_bus_request_name(a, name, param);
486                 if (r < 0) {
487                         if (r == -EALREADY)
488                                 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
489
490                         set_remove(owned_names, (char*) name);
491
492                         if (r == -EEXIST)
493                                 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
494                         return synthetic_reply_method_errno(m, r, NULL);
495                 }
496
497                 in_queue = (r == 0);
498
499                 if (in_queue)
500                         return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
501
502                 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
503
504         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
505                 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
506                 const char *name;
507                 uint32_t flags;
508
509                 if (!sd_bus_message_has_signature(m, "su"))
510                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
511
512                 r = sd_bus_message_read(m, "su", &name, &flags);
513                 if (r < 0)
514                         return synthetic_reply_method_errno(m, r, NULL);
515
516                 if (flags != 0)
517                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
518
519                 r = sd_bus_get_name_creds(a, name, 0, NULL);
520                 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
521                         return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
522                 if (r != -ESRCH)
523                         return synthetic_reply_method_errno(m, r, NULL);
524
525                 r = sd_bus_message_new_method_call(
526                                 a,
527                                 &msg,
528                                 name,
529                                 "/",
530                                 "org.freedesktop.DBus.Peer",
531                                 "Ping");
532                 if (r < 0)
533                         return synthetic_reply_method_errno(m, r, NULL);
534
535                 r = sd_bus_send(a, msg, NULL);
536                 if (r < 0)
537                         return synthetic_reply_method_errno(m, r, NULL);
538
539                 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
540
541         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
542                 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
543                 _cleanup_strv_free_ char **args = NULL;
544
545                 if (!sd_bus_message_has_signature(m, "a{ss}"))
546                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
547
548                 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
549                 if (r < 0)
550                         return synthetic_reply_method_errno(m, r, NULL);
551
552                 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
553                         _cleanup_free_ char *s = NULL;
554                         const char *key;
555                         const char *value;
556
557                         r = sd_bus_message_read(m, "ss", &key, &value);
558                         if (r < 0)
559                                 return synthetic_reply_method_errno(m, r, NULL);
560
561                         s = strjoin(key, "=", value, NULL);
562                         if (!s)
563                                 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
564
565                         r  = strv_extend(&args, s);
566                         if (r < 0)
567                                 return synthetic_reply_method_errno(m, r, NULL);
568
569                         r = sd_bus_message_exit_container(m);
570                         if (r < 0)
571                                 return synthetic_reply_method_errno(m, r, NULL);
572                 }
573
574                 r = sd_bus_message_exit_container(m);
575                 if (r < 0)
576                         return synthetic_reply_method_errno(m, r, NULL);
577
578                 if (!args)
579                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
580
581                 r = sd_bus_message_new_method_call(
582                                 a,
583                                 &msg,
584                                 "org.freedesktop.systemd1",
585                                 "/org/freedesktop/systemd1",
586                                 "org.freedesktop.systemd1.Manager",
587                                 "SetEnvironment");
588                 if (r < 0)
589                         return synthetic_reply_method_errno(m, r, NULL);
590
591                 r = sd_bus_message_append_strv(msg, args);
592                 if (r < 0)
593                         return synthetic_reply_method_errno(m, r, NULL);
594
595                 r = sd_bus_call(a, msg, 0, NULL, NULL);
596                 if (r < 0)
597                         return synthetic_reply_method_errno(m, r, NULL);
598
599                 return synthetic_reply_method_return(m, NULL);
600
601         } else {
602                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
603
604                 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
605
606                 return synthetic_reply_method_errno(m, r, &error);
607         }
608 }