chiark / gitweb /
sd-bus: reuse the KDBUS_CMD_FREE wrapper wherever appropriate
[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                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
438
439                 if (!sd_bus_message_has_signature(m, ""))
440                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
441
442                 r = shared_policy_reload(sp);
443                 if (r < 0)
444                         return synthetic_reply_method_errno(m, r, NULL);
445
446                 return synthetic_reply_method_return(m, NULL);
447
448         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
449                 const char *name;
450                 uint32_t flags, param;
451                 bool in_queue;
452
453                 if (!sd_bus_message_has_signature(m, "su"))
454                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
455
456                 r = sd_bus_message_read(m, "su", &name, &flags);
457                 if (r < 0)
458                         return synthetic_reply_method_errno(m, r, NULL);
459
460                 if (sp) {
461                         Policy *policy;
462                         bool denied;
463
464                         policy = shared_policy_acquire(sp);
465                         denied = !policy_check_own(policy, ucred->uid, ucred->gid, name);
466                         shared_policy_release(sp, policy);
467                         if (denied)
468                                 return synthetic_reply_method_errno(m, -EPERM, NULL);
469                 }
470
471                 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
472                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
473
474                 param = 0;
475                 if (flags & BUS_NAME_ALLOW_REPLACEMENT)
476                         param |= SD_BUS_NAME_ALLOW_REPLACEMENT;
477                 if (flags & BUS_NAME_REPLACE_EXISTING)
478                         param |= SD_BUS_NAME_REPLACE_EXISTING;
479                 if (!(flags & BUS_NAME_DO_NOT_QUEUE))
480                         param |= SD_BUS_NAME_QUEUE;
481
482                 r = set_put_strdup(owned_names, name);
483                 if (r < 0)
484                         return synthetic_reply_method_errno(m, r, NULL);
485
486                 r = sd_bus_request_name(a, name, param);
487                 if (r < 0) {
488                         if (r == -EALREADY)
489                                 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
490
491                         set_remove(owned_names, (char*) name);
492
493                         if (r == -EEXIST)
494                                 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
495                         return synthetic_reply_method_errno(m, r, NULL);
496                 }
497
498                 in_queue = (r == 0);
499
500                 if (in_queue)
501                         return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
502
503                 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
504
505         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
506                 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
507                 const char *name;
508                 uint32_t flags;
509
510                 if (!sd_bus_message_has_signature(m, "su"))
511                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
512
513                 r = sd_bus_message_read(m, "su", &name, &flags);
514                 if (r < 0)
515                         return synthetic_reply_method_errno(m, r, NULL);
516
517                 if (flags != 0)
518                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
519
520                 r = sd_bus_get_name_creds(a, name, 0, NULL);
521                 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
522                         return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
523                 if (r != -ESRCH)
524                         return synthetic_reply_method_errno(m, r, NULL);
525
526                 r = sd_bus_message_new_method_call(
527                                 a,
528                                 &msg,
529                                 name,
530                                 "/",
531                                 "org.freedesktop.DBus.Peer",
532                                 "Ping");
533                 if (r < 0)
534                         return synthetic_reply_method_errno(m, r, NULL);
535
536                 r = sd_bus_send(a, msg, NULL);
537                 if (r < 0)
538                         return synthetic_reply_method_errno(m, r, NULL);
539
540                 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
541
542         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
543                 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
544                 _cleanup_strv_free_ char **args = NULL;
545
546                 if (!sd_bus_message_has_signature(m, "a{ss}"))
547                         return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
548
549                 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
550                 if (r < 0)
551                         return synthetic_reply_method_errno(m, r, NULL);
552
553                 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
554                         _cleanup_free_ char *s = NULL;
555                         const char *key;
556                         const char *value;
557
558                         r = sd_bus_message_read(m, "ss", &key, &value);
559                         if (r < 0)
560                                 return synthetic_reply_method_errno(m, r, NULL);
561
562                         s = strjoin(key, "=", value, NULL);
563                         if (!s)
564                                 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
565
566                         r  = strv_extend(&args, s);
567                         if (r < 0)
568                                 return synthetic_reply_method_errno(m, r, NULL);
569
570                         r = sd_bus_message_exit_container(m);
571                         if (r < 0)
572                                 return synthetic_reply_method_errno(m, r, NULL);
573                 }
574
575                 r = sd_bus_message_exit_container(m);
576                 if (r < 0)
577                         return synthetic_reply_method_errno(m, r, NULL);
578
579                 if (!args)
580                         return synthetic_reply_method_errno(m, -EINVAL, NULL);
581
582                 r = sd_bus_message_new_method_call(
583                                 a,
584                                 &msg,
585                                 "org.freedesktop.systemd1",
586                                 "/org/freedesktop/systemd1",
587                                 "org.freedesktop.systemd1.Manager",
588                                 "SetEnvironment");
589                 if (r < 0)
590                         return synthetic_reply_method_errno(m, r, NULL);
591
592                 r = sd_bus_message_append_strv(msg, args);
593                 if (r < 0)
594                         return synthetic_reply_method_errno(m, r, NULL);
595
596                 r = sd_bus_call(a, msg, 0, NULL, NULL);
597                 if (r < 0)
598                         return synthetic_reply_method_errno(m, r, NULL);
599
600                 return synthetic_reply_method_return(m, NULL);
601
602         } else {
603                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
604
605                 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
606
607                 return synthetic_reply_method_errno(m, r, &error);
608         }
609 }