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