1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
7 Copyright 2013 Daniel Mack
8 Copyright 2014 Kay Sievers
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.
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.
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/>.
30 #include "bus-internal.h"
31 #include "bus-message.h"
36 #include "synthesize.h"
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;
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);
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) {
66 r = sd_bus_message_read(m, "s", &name);
70 return get_creds_by_name(bus, name, mask, _creds, error);
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) {
83 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
86 /* The "Hello()" call is is handled in process_hello() */
88 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
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"));
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"
97 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
98 " <method name=\"Introspect\">\n"
99 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
102 " <interface name=\"org.freedesktop.DBus\">\n"
103 " <method name=\"AddMatch\">\n"
104 " <arg type=\"s\" direction=\"in\"/>\n"
106 " <method name=\"RemoveMatch\">\n"
107 " <arg type=\"s\" direction=\"in\"/>\n"
109 " <method name=\"GetConnectionCredentials\">\n"
110 " <arg type=\"s\" direction=\"in\"/>\n"
111 " <arg type=\"a{sv}\" direction=\"out\"/>\n"
113 " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
114 " <arg type=\"s\" direction=\"in\"/>\n"
115 " <arg type=\"ay\" direction=\"out\"/>\n"
117 " <method name=\"GetConnectionUnixProcessID\">\n"
118 " <arg type=\"s\" direction=\"in\"/>\n"
119 " <arg type=\"u\" direction=\"out\"/>\n"
121 " <method name=\"GetConnectionUnixUser\">\n"
122 " <arg type=\"s\" direction=\"in\"/>\n"
123 " <arg type=\"u\" direction=\"out\"/>\n"
125 " <method name=\"GetId\">\n"
126 " <arg type=\"s\" direction=\"out\"/>\n"
128 " <method name=\"GetNameOwner\">\n"
129 " <arg type=\"s\" direction=\"in\"/>\n"
130 " <arg type=\"s\" direction=\"out\"/>\n"
132 " <method name=\"Hello\">\n"
133 " <arg type=\"s\" direction=\"out\"/>\n"
135 " <method name=\"ListActivatableNames\">\n"
136 " <arg type=\"as\" direction=\"out\"/>\n"
138 " <method name=\"ListNames\">\n"
139 " <arg type=\"as\" direction=\"out\"/>\n"
141 " <method name=\"ListQueuedOwners\">\n"
142 " <arg type=\"s\" direction=\"in\"/>\n"
143 " <arg type=\"as\" direction=\"out\"/>\n"
145 " <method name=\"NameHasOwner\">\n"
146 " <arg type=\"s\" direction=\"in\"/>\n"
147 " <arg type=\"b\" direction=\"out\"/>\n"
149 " <method name=\"ReleaseName\">\n"
150 " <arg type=\"s\" direction=\"in\"/>\n"
151 " <arg type=\"u\" direction=\"out\"/>\n"
153 " <method name=\"ReloadConfig\">\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"
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"
165 " <method name=\"UpdateActivationEnvironment\">\n"
166 " <arg type=\"a{ss}\" direction=\"in\"/>\n"
168 " <signal name=\"NameAcquired\">\n"
169 " <arg type=\"s\"/>\n"
171 " <signal name=\"NameLost\">\n"
172 " <arg type=\"s\"/>\n"
174 " <signal name=\"NameOwnerChanged\">\n"
175 " <arg type=\"s\"/>\n"
176 " <arg type=\"s\"/>\n"
177 " <arg type=\"s\"/>\n"
182 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
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"));
188 r = sd_bus_message_read(m, "s", &match);
190 return synthetic_reply_method_errno(m, r, NULL);
192 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
194 return synthetic_reply_method_errno(m, r, NULL);
196 return synthetic_reply_method_return(m, NULL);
198 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
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"));
204 r = sd_bus_message_read(m, "s", &match);
206 return synthetic_reply_method_errno(m, r, NULL);
208 r = bus_remove_match_by_string(a, match, NULL, NULL);
210 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
212 return synthetic_reply_method_errno(m, r, NULL);
214 return synthetic_reply_method_return(m, NULL);
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;
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"));
224 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error);
226 return synthetic_reply_method_errno(m, r, &error);
228 r = sd_bus_message_new_method_return(m, &reply);
230 return synthetic_reply_method_errno(m, r, NULL);
232 r = sd_bus_message_open_container(reply, 'a', "{sv}");
234 return synthetic_reply_method_errno(m, r, NULL);
236 /* Due to i.e. namespace translations some data might be missing */
238 if (creds->mask & SD_BUS_CREDS_PID) {
239 r = sd_bus_message_append(reply, "{sv}", "ProcessID", "u", (uint32_t) creds->pid);
241 return synthetic_reply_method_errno(m, r, NULL);
244 if (creds->mask & SD_BUS_CREDS_EUID) {
245 r = sd_bus_message_append(reply, "{sv}", "UnixUserID", "u", (uint32_t) creds->euid);
247 return synthetic_reply_method_errno(m, r, NULL);
250 if (creds->mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
251 r = sd_bus_message_open_container(reply, 'e', "sv");
253 return synthetic_reply_method_errno(m, r, NULL);
255 r = sd_bus_message_append(reply, "s", "LinuxSecurityLabel");
257 return synthetic_reply_method_errno(m, r, NULL);
259 r = sd_bus_message_open_container(reply, 'v', "ay");
261 return synthetic_reply_method_errno(m, r, NULL);
263 r = sd_bus_message_append_array(reply, 'y', creds->label, strlen(creds->label));
265 return synthetic_reply_method_errno(m, r, NULL);
267 r = sd_bus_message_close_container(reply);
269 return synthetic_reply_method_errno(m, r, NULL);
271 r = sd_bus_message_close_container(reply);
273 return synthetic_reply_method_errno(m, r, NULL);
276 r = sd_bus_message_close_container(reply);
278 return synthetic_reply_method_errno(m, r, NULL);
280 return synthetic_driver_send(m->bus, reply);
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;
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"));
289 r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error);
291 return synthetic_reply_method_errno(m, r, &error);
293 if (!(creds->mask & SD_BUS_CREDS_SELINUX_CONTEXT))
294 return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL);
296 return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
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;
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"));
305 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, &error);
307 return synthetic_reply_method_errno(m, r, &error);
309 if (!(creds->mask & SD_BUS_CREDS_PID))
310 return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL);
312 return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
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;
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"));
321 r = get_creds_by_message(a, m, SD_BUS_CREDS_EUID, &creds, &error);
323 return synthetic_reply_method_errno(m, r, &error);
325 if (!(creds->mask & SD_BUS_CREDS_EUID))
326 return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL);
328 return synthetic_reply_method_return(m, "u", (uint32_t) creds->euid);
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];
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"));
337 r = sd_bus_get_bus_id(a, &server_id);
339 return synthetic_reply_method_errno(m, r, NULL);
341 return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
343 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
345 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
346 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
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"));
351 r = sd_bus_message_read(m, "s", &name);
353 return synthetic_reply_method_errno(m, r, NULL);
355 if (streq(name, "org.freedesktop.DBus"))
356 return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
358 r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
360 return synthetic_reply_method_errno(m, r, &error);
362 if (!(creds->mask & SD_BUS_CREDS_UNIQUE_NAME))
363 return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL);
365 return synthetic_reply_method_return(m, "s", creds->unique_name);
367 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
368 _cleanup_strv_free_ char **names = NULL;
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"));
373 r = sd_bus_list_names(a, NULL, &names);
375 return synthetic_reply_method_errno(m, r, NULL);
377 /* Let's sort the names list to make it stable */
380 return synthetic_reply_method_return_strv(m, names);
382 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
383 _cleanup_strv_free_ char **names = NULL;
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"));
388 r = sd_bus_list_names(a, &names, NULL);
390 return synthetic_reply_method_errno(m, r, NULL);
392 r = strv_extend(&names, "org.freedesktop.DBus");
394 return synthetic_reply_method_errno(m, r, NULL);
396 /* Let's sort the names list to make it stable */
399 return synthetic_reply_method_return_strv(m, names);
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,
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;
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"));
415 r = sd_bus_message_read(m, "s", &arg0);
417 return synthetic_reply_method_errno(m, r, NULL);
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);
425 return synthetic_reply_method_errno(m, r, NULL);
427 r = ioctl(a->input_fd, KDBUS_CMD_LIST, &cmd);
429 return synthetic_reply_method_errno(m, -errno, NULL);
431 name_list = (struct kdbus_info *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
433 KDBUS_FOREACH(name, name_list, cmd.list_size) {
434 const char *entry_name = NULL;
435 struct kdbus_item *item;
438 KDBUS_ITEM_FOREACH(item, name, items)
439 if (item->type == KDBUS_ITEM_OWNED_NAME)
440 entry_name = item->name.name;
442 if (!streq_ptr(entry_name, arg0))
445 if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) {
450 r = strv_consume(&owners, n);
457 r = bus_kernel_cmd_free(a, cmd.offset);
459 return synthetic_reply_method_errno(m, r, NULL);
462 return synthetic_reply_method_errno(m, err, NULL);
464 return synthetic_reply_method_return_strv(m, owners);
466 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
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"));
472 r = sd_bus_message_read(m, "s", &name);
474 return synthetic_reply_method_errno(m, r, NULL);
476 if (streq(name, "org.freedesktop.DBus"))
477 return synthetic_reply_method_return(m, "b", true);
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);
483 return synthetic_reply_method_return(m, "b", r >= 0);
485 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
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"));
491 r = sd_bus_message_read(m, "s", &name);
493 return synthetic_reply_method_errno(m, r, NULL);
495 r = sd_bus_release_name(a, name);
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);
502 return synthetic_reply_method_errno(m, r, NULL);
505 set_remove(owned_names, (char*) name);
507 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
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"));
513 r = shared_policy_reload(sp);
515 return synthetic_reply_method_errno(m, r, NULL);
517 return synthetic_reply_method_return(m, NULL);
519 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
521 uint32_t flags, param;
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"));
527 r = sd_bus_message_read(m, "su", &name, &flags);
529 return synthetic_reply_method_errno(m, r, NULL);
535 policy = shared_policy_acquire(sp);
536 denied = !policy_check_own(policy, ucred->uid, ucred->gid, name);
537 shared_policy_release(sp, policy);
539 return synthetic_reply_method_errno(m, -EPERM, NULL);
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);
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;
553 r = set_put_strdup(owned_names, name);
555 return synthetic_reply_method_errno(m, r, NULL);
557 r = sd_bus_request_name(a, name, param);
560 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
562 set_remove(owned_names, (char*) name);
565 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
566 return synthetic_reply_method_errno(m, r, NULL);
572 return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
574 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
576 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
577 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
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"));
584 r = sd_bus_message_read(m, "su", &name, &flags);
586 return synthetic_reply_method_errno(m, r, NULL);
589 return synthetic_reply_method_errno(m, -EINVAL, NULL);
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);
595 return synthetic_reply_method_errno(m, r, NULL);
597 r = sd_bus_message_new_method_call(
602 "org.freedesktop.DBus.Peer",
605 return synthetic_reply_method_errno(m, r, NULL);
607 r = sd_bus_send(a, msg, NULL);
609 return synthetic_reply_method_errno(m, r, NULL);
611 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
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;
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"));
620 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
622 return synthetic_reply_method_errno(m, r, NULL);
624 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
625 _cleanup_free_ char *s = NULL;
629 r = sd_bus_message_read(m, "ss", &key, &value);
631 return synthetic_reply_method_errno(m, r, NULL);
633 s = strjoin(key, "=", value, NULL);
635 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
637 r = strv_extend(&args, s);
639 return synthetic_reply_method_errno(m, r, NULL);
641 r = sd_bus_message_exit_container(m);
643 return synthetic_reply_method_errno(m, r, NULL);
646 r = sd_bus_message_exit_container(m);
648 return synthetic_reply_method_errno(m, r, NULL);
651 return synthetic_reply_method_errno(m, -EINVAL, NULL);
653 r = sd_bus_message_new_method_call(
656 "org.freedesktop.systemd1",
657 "/org/freedesktop/systemd1",
658 "org.freedesktop.systemd1.Manager",
661 return synthetic_reply_method_errno(m, r, NULL);
663 r = sd_bus_message_append_strv(msg, args);
665 return synthetic_reply_method_errno(m, r, NULL);
667 r = sd_bus_call(a, msg, 0, NULL, NULL);
669 return synthetic_reply_method_errno(m, r, NULL);
671 return synthetic_reply_method_return(m, NULL);
674 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
676 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
678 return synthetic_reply_method_errno(m, r, &error);