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