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