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