]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus.c
tree-wide: take benefit of the fact that hashmap_free() returns NULL
[thirdparty/systemd.git] / src / core / dbus.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
ea430986 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
a7334b09
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
ea430986 22#include <sys/epoll.h>
ea430986
LP
23#include <errno.h>
24#include <unistd.h>
25
718db961 26#include "sd-bus.h"
ea430986
LP
27#include "log.h"
28#include "strv.h"
49e942b2 29#include "mkdir.h"
4db17f29 30#include "missing.h"
4139c1b2
LP
31#include "dbus-unit.h"
32#include "dbus-job.h"
33#include "dbus-manager.h"
718db961
LP
34#include "dbus-execute.h"
35#include "dbus-kill.h"
36#include "dbus-cgroup.h"
8f6df3fa 37#include "special.h"
718db961
LP
38#include "dbus.h"
39#include "bus-util.h"
40#include "bus-error.h"
96aad8d1 41#include "bus-common-errors.h"
718db961 42#include "strxcpyx.h"
969987ea
LP
43#include "bus-internal.h"
44#include "selinux-access.h"
4288f619 45
cbecf9bf 46#define CONNECTIONS_MAX 4096
5e8d1c9a 47
718db961
LP
48static void destroy_bus(Manager *m, sd_bus **bus);
49
50int bus_send_queued_message(Manager *m) {
51 int r;
8e274523 52
8e274523 53 assert(m);
2e317f52 54
718db961
LP
55 if (!m->queued_message)
56 return 0;
8e274523 57
718db961
LP
58 /* If we cannot get rid of this message we won't dispatch any
59 * D-Bus messages, so that we won't end up wanting to queue
60 * another message. */
ea430986 61
8f88ecf6 62 r = sd_bus_send(NULL, m->queued_message, NULL);
718db961 63 if (r < 0)
da927ba9 64 log_warning_errno(r, "Failed to send queued message: %m");
ea430986 65
718db961 66 m->queued_message = sd_bus_message_unref(m->queued_message);
ea430986 67
718db961 68 return 0;
ea430986
LP
69}
70
19070062 71static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus_error *error) {
0a069ce6
DH
72 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
73 const char *cgroup, *me;
718db961 74 Manager *m = userdata;
0a069ce6
DH
75 uid_t sender_uid;
76 sd_bus *bus;
718db961 77 int r;
ea430986 78
718db961 79 assert(message);
ea430986
LP
80 assert(m);
81
0a069ce6
DH
82 /* ignore recursive events sent by us on the system/user bus */
83 bus = sd_bus_message_get_bus(message);
84 if (!sd_bus_is_server(bus)) {
85 r = sd_bus_get_unique_name(bus, &me);
86 if (r < 0)
87 return r;
88
89 if (streq_ptr(sd_bus_message_get_sender(message), me))
90 return 0;
91 }
92
93 /* only accept org.freedesktop.systemd1.Agent from UID=0 */
94 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
95 if (r < 0)
96 return r;
97
98 r = sd_bus_creds_get_euid(creds, &sender_uid);
99 if (r < 0 || sender_uid != 0)
100 return 0;
101
102 /* parse 'cgroup-empty' notification */
718db961
LP
103 r = sd_bus_message_read(message, "s", &cgroup);
104 if (r < 0) {
105 bus_log_parse_error(r);
106 return 0;
107 }
ea430986 108
718db961 109 manager_notify_cgroup_empty(m, cgroup);
ea430986 110
a0c8526a
DH
111 /* if running as system-instance, forward under our name */
112 if (m->running_as == MANAGER_SYSTEM && m->system_bus) {
113 r = sd_bus_message_rewind(message, 1);
114 if (r >= 0)
115 r = sd_bus_send(m->system_bus, message, NULL);
116 if (r < 0)
117 log_warning_errno(r, "Failed to forward Released message: %m");
118 }
39881ed2 119
718db961
LP
120 return 0;
121}
ea430986 122
19070062 123static int signal_disconnected(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961 124 Manager *m = userdata;
19070062 125 sd_bus *bus;
ea430986 126
718db961
LP
127 assert(message);
128 assert(m);
19070062 129 assert_se(bus = sd_bus_message_get_bus(message));
ea430986 130
718db961
LP
131 if (bus == m->api_bus)
132 destroy_bus(m, &m->api_bus);
133 if (bus == m->system_bus)
134 destroy_bus(m, &m->system_bus);
135 if (set_remove(m->private_buses, bus)) {
136 log_debug("Got disconnect on private connection.");
137 destroy_bus(m, &bus);
ea430986
LP
138 }
139
718db961 140 return 0;
ea430986
LP
141}
142
19070062 143static int signal_activation_request(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
718db961
LP
144 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
145 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
146 Manager *m = userdata;
147 const char *name;
148 Unit *u;
149 int r;
ea430986 150
718db961 151 assert(message);
ea430986
LP
152 assert(m);
153
718db961
LP
154 r = sd_bus_message_read(message, "s", &name);
155 if (r < 0) {
156 bus_log_parse_error(r);
157 return 0;
158 }
ea430986 159
718db961
LP
160 if (manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SERVICE) ||
161 manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SOCKET)) {
162 r = sd_bus_error_setf(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down.");
163 goto failed;
164 }
ea430986 165
718db961
LP
166 r = manager_load_unit(m, name, NULL, &error, &u);
167 if (r < 0)
168 goto failed;
ea430986 169
718db961 170 if (u->refuse_manual_start) {
d14ab08b 171 r = sd_bus_error_setf(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, %s may be requested by dependency only.", u->id);
718db961 172 goto failed;
ea430986
LP
173 }
174
718db961
LP
175 r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL);
176 if (r < 0)
177 goto failed;
ea430986 178
718db961 179 /* Successfully queued, that's it for us */
ea430986 180 return 0;
ea430986 181
718db961
LP
182failed:
183 if (!sd_bus_error_is_set(&error))
184 sd_bus_error_set_errno(&error, r);
ea430986 185
718db961 186 log_debug("D-Bus activation failed for %s: %s", name, bus_error_message(&error, r));
ea430986 187
966c66e3 188 r = sd_bus_message_new_signal(sd_bus_message_get_bus(message), &reply, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure");
718db961
LP
189 if (r < 0) {
190 bus_log_create_error(r);
191 return 0;
192 }
193
fa0fed49 194 r = sd_bus_message_append(reply, "sss", name, error.name, error.message);
718db961
LP
195 if (r < 0) {
196 bus_log_create_error(r);
197 return 0;
198 }
199
966c66e3 200 r = sd_bus_send_to(NULL, reply, "org.freedesktop.DBus", NULL);
23bbb0de
MS
201 if (r < 0)
202 return log_error_errno(r, "Failed to respond with to bus activation request: %m");
ea430986 203
718db961 204 return 0;
ea430986
LP
205}
206
ad5b215d 207#ifdef HAVE_SELINUX
19070062 208static int mac_selinux_filter(sd_bus_message *message, void *userdata, sd_bus_error *error) {
969987ea
LP
209 Manager *m = userdata;
210 const char *verb, *path;
211 Unit *u = NULL;
212 Job *j;
213 int r;
214
969987ea
LP
215 assert(message);
216
217 /* Our own method calls are all protected individually with
218 * selinux checks, but the built-in interfaces need to be
219 * protected too. */
220
221 if (sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set"))
222 verb = "reload";
223 else if (sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", NULL) ||
224 sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Properties", NULL) ||
225 sd_bus_message_is_method_call(message, "org.freedesktop.DBus.ObjectManager", NULL) ||
226 sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Peer", NULL))
227 verb = "status";
228 else
229 return 0;
230
231 path = sd_bus_message_get_path(message);
232
233 if (object_path_startswith("/org/freedesktop/systemd1", path)) {
234
8a188de9 235 r = mac_selinux_access_check(message, verb, error);
969987ea
LP
236 if (r < 0)
237 return r;
238
239 return 0;
240 }
241
242 if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
5b12334d 243 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
969987ea
LP
244 pid_t pid;
245
5b12334d
LP
246 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
247 if (r < 0)
248 return 0;
249
250 r = sd_bus_creds_get_pid(creds, &pid);
969987ea
LP
251 if (r < 0)
252 return 0;
253
254 u = manager_get_unit_by_pid(m, pid);
255 } else {
256 r = manager_get_job_from_dbus_path(m, path, &j);
257 if (r >= 0)
258 u = j->unit;
259 else
260 manager_load_unit_from_dbus_path(m, path, NULL, &u);
261 }
262
263 if (!u)
264 return 0;
265
8a188de9 266 r = mac_selinux_unit_access_check(u, message, verb, error);
969987ea
LP
267 if (r < 0)
268 return r;
269
270 return 0;
271}
ad5b215d 272#endif
969987ea 273
f00c3121 274static int bus_job_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
275 Manager *m = userdata;
276 Job *j;
277 int r;
ea430986 278
718db961
LP
279 assert(bus);
280 assert(path);
281 assert(interface);
282 assert(found);
ea430986
LP
283 assert(m);
284
718db961
LP
285 r = manager_get_job_from_dbus_path(m, path, &j);
286 if (r < 0)
287 return 0;
ea430986 288
718db961
LP
289 *found = j;
290 return 1;
291}
ea430986 292
f00c3121 293static int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_bus_error *error) {
718db961
LP
294 Unit *u;
295 int r;
ea430986 296
718db961
LP
297 assert(m);
298 assert(bus);
299 assert(path);
ea430986 300
718db961 301 if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
5b12334d 302 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
718db961
LP
303 sd_bus_message *message;
304 pid_t pid;
ea430986 305
19befb2d 306 message = sd_bus_get_current_message(bus);
718db961 307 if (!message)
f00c3121 308 return 0;
ea430986 309
5b12334d 310 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
718db961 311 if (r < 0)
5b12334d
LP
312 return r;
313
314 r = sd_bus_creds_get_pid(creds, &pid);
315 if (r < 0)
316 return r;
ea430986 317
718db961
LP
318 u = manager_get_unit_by_pid(m, pid);
319 } else {
f00c3121 320 r = manager_load_unit_from_dbus_path(m, path, error, &u);
718db961 321 if (r < 0)
f00c3121 322 return 0;
718db961 323 }
ea430986 324
f00c3121
LP
325 if (!u)
326 return 0;
327
328 *unit = u;
329 return 1;
ea430986
LP
330}
331
f00c3121 332static int bus_unit_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961 333 Manager *m = userdata;
ea430986 334
718db961
LP
335 assert(bus);
336 assert(path);
337 assert(interface);
338 assert(found);
ea430986
LP
339 assert(m);
340
f00c3121 341 return find_unit(m, bus, path, (Unit**) found, error);
ea430986
LP
342}
343
f00c3121 344static int bus_unit_interface_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
345 Manager *m = userdata;
346 Unit *u;
f00c3121 347 int r;
ea430986 348
718db961
LP
349 assert(bus);
350 assert(path);
351 assert(interface);
352 assert(found);
ea430986
LP
353 assert(m);
354
f00c3121
LP
355 r = find_unit(m, bus, path, &u, error);
356 if (r <= 0)
357 return r;
3df5bf61 358
21b735e7 359 if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type)))
718db961 360 return 0;
ea430986 361
718db961
LP
362 *found = u;
363 return 1;
ea430986
LP
364}
365
f00c3121 366static int bus_unit_cgroup_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
367 Manager *m = userdata;
368 Unit *u;
f00c3121 369 int r;
c1e1601e 370
718db961
LP
371 assert(bus);
372 assert(path);
373 assert(interface);
374 assert(found);
c1e1601e
LP
375 assert(m);
376
f00c3121
LP
377 r = find_unit(m, bus, path, &u, error);
378 if (r <= 0)
379 return r;
05e343b7 380
21b735e7 381 if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type)))
718db961 382 return 0;
05e343b7 383
35b7ff80 384 if (!UNIT_HAS_CGROUP_CONTEXT(u))
718db961 385 return 0;
0034c15c 386
718db961
LP
387 *found = u;
388 return 1;
389}
0034c15c 390
f00c3121 391static int bus_cgroup_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
392 Manager *m = userdata;
393 CGroupContext *c;
394 Unit *u;
f00c3121 395 int r;
af25ec12 396
718db961
LP
397 assert(bus);
398 assert(path);
399 assert(interface);
400 assert(found);
401 assert(m);
0034c15c 402
f00c3121
LP
403 r = find_unit(m, bus, path, &u, error);
404 if (r <= 0)
405 return r;
0034c15c 406
21b735e7 407 if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type)))
718db961 408 return 0;
0034c15c 409
718db961
LP
410 c = unit_get_cgroup_context(u);
411 if (!c)
412 return 0;
c1e1601e 413
718db961
LP
414 *found = c;
415 return 1;
416}
0034c15c 417
f00c3121 418static int bus_exec_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
419 Manager *m = userdata;
420 ExecContext *c;
421 Unit *u;
f00c3121 422 int r;
0034c15c 423
718db961
LP
424 assert(bus);
425 assert(path);
426 assert(interface);
427 assert(found);
428 assert(m);
0034c15c 429
f00c3121
LP
430 r = find_unit(m, bus, path, &u, error);
431 if (r <= 0)
432 return r;
0034c15c 433
21b735e7 434 if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type)))
718db961 435 return 0;
0034c15c 436
718db961
LP
437 c = unit_get_exec_context(u);
438 if (!c)
439 return 0;
0034c15c 440
718db961
LP
441 *found = c;
442 return 1;
c1e1601e
LP
443}
444
f00c3121 445static int bus_kill_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
446 Manager *m = userdata;
447 KillContext *c;
448 Unit *u;
f00c3121 449 int r;
8e274523 450
718db961
LP
451 assert(bus);
452 assert(path);
453 assert(interface);
454 assert(found);
8e274523
LP
455 assert(m);
456
f00c3121
LP
457 r = find_unit(m, bus, path, &u, error);
458 if (r <= 0)
459 return r;
8e274523 460
21b735e7 461 if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type)))
718db961 462 return 0;
8e274523 463
718db961
LP
464 c = unit_get_kill_context(u);
465 if (!c)
466 return 0;
53c6a358 467
718db961
LP
468 *found = c;
469 return 1;
470}
8e274523 471
f00c3121 472static int bus_job_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
718db961
LP
473 _cleanup_free_ char **l = NULL;
474 Manager *m = userdata;
475 unsigned k = 0;
476 Iterator i;
477 Job *j;
8e274523 478
718db961
LP
479 l = new0(char*, hashmap_size(m->jobs)+1);
480 if (!l)
481 return -ENOMEM;
8e274523 482
718db961
LP
483 HASHMAP_FOREACH(j, m->jobs, i) {
484 l[k] = job_dbus_path(j);
485 if (!l[k])
486 return -ENOMEM;
5e8d1c9a 487
718db961
LP
488 k++;
489 }
5e8d1c9a 490
718db961 491 assert(hashmap_size(m->jobs) == k);
3c661fad 492
718db961
LP
493 *nodes = l;
494 l = NULL;
5e8d1c9a 495
718db961
LP
496 return k;
497}
53c6a358 498
f00c3121 499static int bus_unit_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
718db961
LP
500 _cleanup_free_ char **l = NULL;
501 Manager *m = userdata;
502 unsigned k = 0;
503 Iterator i;
504 Unit *u;
3c661fad 505
718db961
LP
506 l = new0(char*, hashmap_size(m->units)+1);
507 if (!l)
508 return -ENOMEM;
53c6a358 509
718db961
LP
510 HASHMAP_FOREACH(u, m->units, i) {
511 l[k] = unit_dbus_path(u);
512 if (!l[k])
513 return -ENOMEM;
53c6a358 514
718db961 515 k++;
3c661fad
LP
516 }
517
718db961
LP
518 *nodes = l;
519 l = NULL;
5e8d1c9a 520
718db961 521 return k;
5e8d1c9a
LP
522}
523
718db961
LP
524static int bus_setup_api_vtables(Manager *m, sd_bus *bus) {
525 UnitType t;
526 int r;
5e8d1c9a 527
ea430986 528 assert(m);
718db961 529 assert(bus);
ea430986 530
ad5b215d 531#ifdef HAVE_SELINUX
8a188de9 532 r = sd_bus_add_filter(bus, NULL, mac_selinux_filter, m);
23bbb0de
MS
533 if (r < 0)
534 return log_error_errno(r, "Failed to add SELinux access filter: %m");
ad5b215d 535#endif
969987ea 536
19befb2d 537 r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", bus_manager_vtable, m);
23bbb0de
MS
538 if (r < 0)
539 return log_error_errno(r, "Failed to register Manager vtable: %m");
a16e1123 540
19befb2d 541 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/job", "org.freedesktop.systemd1.Job", bus_job_vtable, bus_job_find, m);
23bbb0de
MS
542 if (r < 0)
543 return log_error_errno(r, "Failed to register Job vtable: %m");
c1e1601e 544
19befb2d 545 r = sd_bus_add_node_enumerator(bus, NULL, "/org/freedesktop/systemd1/job", bus_job_enumerate, m);
23bbb0de
MS
546 if (r < 0)
547 return log_error_errno(r, "Failed to add job enumerator: %m");
61902ea3 548
19befb2d 549 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", "org.freedesktop.systemd1.Unit", bus_unit_vtable, bus_unit_find, m);
23bbb0de
MS
550 if (r < 0)
551 return log_error_errno(r, "Failed to register Unit vtable: %m");
61902ea3 552
19befb2d 553 r = sd_bus_add_node_enumerator(bus, NULL, "/org/freedesktop/systemd1/unit", bus_unit_enumerate, m);
23bbb0de
MS
554 if (r < 0)
555 return log_error_errno(r, "Failed to add job enumerator: %m");
61902ea3 556
718db961 557 for (t = 0; t < _UNIT_TYPE_MAX; t++) {
21b735e7
LP
558 const char *interface;
559
560 assert_se(interface = unit_dbus_interface_from_type(t));
561
562 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, unit_vtable[t]->bus_vtable, bus_unit_interface_find, m);
23bbb0de 563 if (r < 0)
21b735e7 564 return log_error_errno(r, "Failed to register type specific vtable for %s: %m", interface);
61902ea3 565
718db961 566 if (unit_vtable[t]->cgroup_context_offset > 0) {
21b735e7 567 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_unit_cgroup_vtable, bus_unit_cgroup_find, m);
23bbb0de 568 if (r < 0)
21b735e7 569 return log_error_errno(r, "Failed to register control group unit vtable for %s: %m", interface);
61902ea3 570
21b735e7 571 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_cgroup_vtable, bus_cgroup_context_find, m);
23bbb0de 572 if (r < 0)
21b735e7 573 return log_error_errno(r, "Failed to register control group vtable for %s: %m", interface);
61902ea3
LP
574 }
575
718db961 576 if (unit_vtable[t]->exec_context_offset > 0) {
21b735e7 577 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_exec_vtable, bus_exec_context_find, m);
23bbb0de 578 if (r < 0)
21b735e7 579 return log_error_errno(r, "Failed to register execute vtable for %s: %m", interface);
718db961 580 }
61902ea3 581
718db961 582 if (unit_vtable[t]->kill_context_offset > 0) {
21b735e7 583 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_kill_vtable, bus_kill_context_find, m);
23bbb0de 584 if (r < 0)
21b735e7 585 return log_error_errno(r, "Failed to register kill vtable for %s: %m", interface);
718db961 586 }
61902ea3
LP
587 }
588
718db961 589 return 0;
61902ea3
LP
590}
591
718db961
LP
592static int bus_setup_disconnected_match(Manager *m, sd_bus *bus) {
593 int r;
61902ea3 594
718db961
LP
595 assert(m);
596 assert(bus);
61902ea3 597
718db961
LP
598 r = sd_bus_add_match(
599 bus,
19befb2d 600 NULL,
27fc65e1 601 "sender='org.freedesktop.DBus.Local',"
718db961
LP
602 "type='signal',"
603 "path='/org/freedesktop/DBus/Local',"
604 "interface='org.freedesktop.DBus.Local',"
605 "member='Disconnected'",
606 signal_disconnected, m);
05e343b7 607
23bbb0de
MS
608 if (r < 0)
609 return log_error_errno(r, "Failed to register match for Disconnected message: %m");
05e343b7 610
718db961 611 return 0;
ea430986
LP
612}
613
718db961
LP
614static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
615 _cleanup_bus_unref_ sd_bus *bus = NULL;
616 _cleanup_close_ int nfd = -1;
6dded4c7 617 Manager *m = userdata;
718db961
LP
618 sd_id128_t id;
619 int r;
6dded4c7 620
718db961 621 assert(s);
6dded4c7
LP
622 assert(m);
623
718db961
LP
624 nfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
625 if (nfd < 0) {
56f64d95 626 log_warning_errno(errno, "Failed to accept private connection, ignoring: %m");
718db961
LP
627 return 0;
628 }
6dded4c7 629
718db961
LP
630 if (set_size(m->private_buses) >= CONNECTIONS_MAX) {
631 log_warning("Too many concurrent connections, refusing");
632 return 0;
633 }
6dded4c7 634
d5099efc 635 r = set_ensure_allocated(&m->private_buses, NULL);
718db961
LP
636 if (r < 0) {
637 log_oom();
638 return 0;
639 }
6dded4c7 640
718db961
LP
641 r = sd_bus_new(&bus);
642 if (r < 0) {
da927ba9 643 log_warning_errno(r, "Failed to allocate new private connection bus: %m");
718db961
LP
644 return 0;
645 }
6dded4c7 646
718db961
LP
647 r = sd_bus_set_fd(bus, nfd, nfd);
648 if (r < 0) {
da927ba9 649 log_warning_errno(r, "Failed to set fd on new connection bus: %m");
718db961
LP
650 return 0;
651 }
6dded4c7 652
718db961 653 nfd = -1;
6dded4c7 654
718db961
LP
655 r = bus_check_peercred(bus);
656 if (r < 0) {
da927ba9 657 log_warning_errno(r, "Incoming private connection from unprivileged client, refusing: %m");
718db961
LP
658 return 0;
659 }
6dded4c7 660
718db961 661 assert_se(sd_id128_randomize(&id) >= 0);
6dded4c7 662
718db961
LP
663 r = sd_bus_set_server(bus, 1, id);
664 if (r < 0) {
da927ba9 665 log_warning_errno(r, "Failed to enable server support for new connection bus: %m");
718db961
LP
666 return 0;
667 }
6dded4c7 668
0674bbea
LP
669 r = sd_bus_negotiate_creds(bus, 1,
670 SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|
671 SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS|
672 SD_BUS_CREDS_SELINUX_CONTEXT);
673 if (r < 0) {
674 log_warning_errno(r, "Failed to enable credentials for new connection: %m");
675 return 0;
676 }
677
718db961
LP
678 r = sd_bus_start(bus);
679 if (r < 0) {
da927ba9 680 log_warning_errno(r, "Failed to start new connection bus: %m");
718db961 681 return 0;
6dded4c7
LP
682 }
683
718db961
LP
684 r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
685 if (r < 0) {
da927ba9 686 log_warning_errno(r, "Failed to attach new connection bus to event loop: %m");
718db961 687 return 0;
6dded4c7
LP
688 }
689
b2c23da8 690 if (m->running_as == MANAGER_SYSTEM) {
718db961
LP
691 /* When we run as system instance we get the Released
692 * signal via a direct connection */
693
694 r = sd_bus_add_match(
695 bus,
19befb2d 696 NULL,
718db961
LP
697 "type='signal',"
698 "interface='org.freedesktop.systemd1.Agent',"
699 "member='Released',"
700 "path='/org/freedesktop/systemd1/agent'",
701 signal_agent_released, m);
702
703 if (r < 0) {
da927ba9 704 log_warning_errno(r, "Failed to register Released match on new connection bus: %m");
718db961
LP
705 return 0;
706 }
707 }
6dded4c7 708
718db961
LP
709 r = bus_setup_disconnected_match(m, bus);
710 if (r < 0)
711 return 0;
6dded4c7 712
718db961
LP
713 r = bus_setup_api_vtables(m, bus);
714 if (r < 0) {
da927ba9 715 log_warning_errno(r, "Failed to set up API vtables on new connection bus: %m");
718db961
LP
716 return 0;
717 }
6dded4c7 718
718db961
LP
719 r = set_put(m->private_buses, bus);
720 if (r < 0) {
05a08cb6 721 log_warning_errno(r, "Failed to add new connection bus to set: %m");
718db961 722 return 0;
6dded4c7
LP
723 }
724
718db961 725 bus = NULL;
6dded4c7 726
718db961 727 log_debug("Accepted new private connection.");
6dded4c7 728
8e274523
LP
729 return 0;
730}
731
718db961 732static int bus_list_names(Manager *m, sd_bus *bus) {
0e7be129
LP
733 _cleanup_strv_free_ char **names = NULL;
734 char **i;
718db961 735 int r;
5e8d1c9a
LP
736
737 assert(m);
718db961 738 assert(bus);
5e8d1c9a 739
0e7be129 740 r = sd_bus_list_names(bus, &names, NULL);
23bbb0de
MS
741 if (r < 0)
742 return log_error_errno(r, "Failed to get initial list of names: %m");
5e8d1c9a 743
718db961
LP
744 /* This is a bit hacky, we say the owner of the name is the
745 * name itself, because we don't want the extra traffic to
746 * figure out the real owner. */
bbc29086
DM
747 STRV_FOREACH(i, names) {
748 Unit *u;
749
750 u = hashmap_get(m->watch_bus, *i);
751 if (u)
752 UNIT_VTABLE(u)->bus_name_owner_change(u, *i, NULL, *i);
753 }
5e8d1c9a 754
718db961 755 return 0;
5e8d1c9a
LP
756}
757
718db961 758static int bus_setup_api(Manager *m, sd_bus *bus) {
bbc29086
DM
759 Iterator i;
760 char *name;
761 Unit *u;
718db961 762 int r;
f278026d 763
718db961
LP
764 assert(m);
765 assert(bus);
c1e1601e 766
8fd00193
LP
767 /* Let's make sure we have enough credential bits so that we can make security and selinux decisions */
768 r = sd_bus_negotiate_creds(bus, 1,
769 SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|
770 SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS|
771 SD_BUS_CREDS_SELINUX_CONTEXT);
772 if (r < 0)
da927ba9 773 log_warning_errno(r, "Failed to enable credential passing, ignoring: %m");
8fd00193 774
718db961
LP
775 r = bus_setup_api_vtables(m, bus);
776 if (r < 0)
777 return r;
cbd37330 778
bbc29086
DM
779 HASHMAP_FOREACH_KEY(u, name, m->watch_bus, i) {
780 r = unit_install_bus_match(bus, u, name);
781 if (r < 0)
782 log_error_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m");
783 }
718db961
LP
784
785 r = sd_bus_add_match(
786 bus,
19befb2d 787 NULL,
718db961
LP
788 "type='signal',"
789 "sender='org.freedesktop.DBus',"
790 "path='/org/freedesktop/DBus',"
791 "interface='org.freedesktop.systemd1.Activator',"
792 "member='ActivationRequest'",
793 signal_activation_request, m);
794 if (r < 0)
da927ba9 795 log_warning_errno(r, "Failed to subscribe to activation signal: %m");
cbd37330 796
718db961
LP
797 /* Allow replacing of our name, to ease implementation of
798 * reexecution, where we keep the old connection open until
799 * after the new connection is set up and the name installed
800 * to allow clients to synchronously wait for reexecution to
801 * finish */
29a07cdb 802 r = sd_bus_request_name(bus,"org.freedesktop.systemd1", SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_ALLOW_REPLACEMENT);
23bbb0de
MS
803 if (r < 0)
804 return log_error_errno(r, "Failed to register name: %m");
53c6a358 805
718db961 806 bus_list_names(m, bus);
f278026d 807
718db961 808 log_debug("Successfully connected to API bus.");
f278026d
LP
809 return 0;
810}
811
718db961
LP
812static int bus_init_api(Manager *m) {
813 _cleanup_bus_unref_ sd_bus *bus = NULL;
f278026d
LP
814 int r;
815
718db961
LP
816 if (m->api_bus)
817 return 0;
cbd37330 818
718db961 819 /* The API and system bus is the same if we are running in system mode */
b2c23da8 820 if (m->running_as == MANAGER_SYSTEM && m->system_bus)
718db961
LP
821 bus = sd_bus_ref(m->system_bus);
822 else {
b2c23da8 823 if (m->running_as == MANAGER_SYSTEM)
718db961
LP
824 r = sd_bus_open_system(&bus);
825 else
826 r = sd_bus_open_user(&bus);
cbd37330 827
718db961
LP
828 if (r < 0) {
829 log_debug("Failed to connect to API bus, retrying later...");
830 return 0;
cbd37330
MS
831 }
832
718db961
LP
833 r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
834 if (r < 0) {
da927ba9 835 log_error_errno(r, "Failed to attach API bus to event loop: %m");
718db961 836 return 0;
cbd37330
MS
837 }
838
718db961
LP
839 r = bus_setup_disconnected_match(m, bus);
840 if (r < 0)
841 return 0;
cbd37330
MS
842 }
843
718db961 844 r = bus_setup_api(m, bus);
cbd37330 845 if (r < 0) {
da927ba9 846 log_error_errno(r, "Failed to set up API bus: %m");
718db961 847 return 0;
cbd37330 848 }
cbd37330 849
718db961
LP
850 m->api_bus = bus;
851 bus = NULL;
cbd37330
MS
852
853 return 0;
cbd37330
MS
854}
855
718db961
LP
856static int bus_setup_system(Manager *m, sd_bus *bus) {
857 int r;
cbd37330 858
718db961
LP
859 assert(m);
860 assert(bus);
cbd37330 861
f5b51ea7 862 /* On kdbus or if we are a user instance we get the Released message via the system bus */
b2c23da8 863 if (m->running_as == MANAGER_USER || m->kdbus_fd >= 0) {
f5b51ea7
DH
864 r = sd_bus_add_match(
865 bus,
866 NULL,
867 "type='signal',"
868 "interface='org.freedesktop.systemd1.Agent',"
869 "member='Released',"
870 "path='/org/freedesktop/systemd1/agent'",
871 signal_agent_released, m);
872 if (r < 0)
873 log_warning_errno(r, "Failed to register Released match on system bus: %m");
874 }
718db961
LP
875
876 log_debug("Successfully connected to system bus.");
877 return 0;
cbd37330
MS
878}
879
880static int bus_init_system(Manager *m) {
718db961 881 _cleanup_bus_unref_ sd_bus *bus = NULL;
cbd37330
MS
882 int r;
883
884 if (m->system_bus)
885 return 0;
886
718db961 887 /* The API and system bus is the same if we are running in system mode */
b2c23da8 888 if (m->running_as == MANAGER_SYSTEM && m->api_bus) {
718db961
LP
889 m->system_bus = sd_bus_ref(m->api_bus);
890 return 0;
9014a8bd 891 }
8e274523 892
718db961
LP
893 r = sd_bus_open_system(&bus);
894 if (r < 0) {
895 log_debug("Failed to connect to system bus, retrying later...");
896 return 0;
897 }
cbd37330 898
718db961 899 r = bus_setup_disconnected_match(m, bus);
cbd37330 900 if (r < 0)
cbd37330
MS
901 return 0;
902
718db961
LP
903 r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
904 if (r < 0) {
da927ba9 905 log_error_errno(r, "Failed to attach system bus to event loop: %m");
cbd37330
MS
906 return 0;
907 }
908
718db961
LP
909 r = bus_setup_system(m, bus);
910 if (r < 0) {
da927ba9 911 log_error_errno(r, "Failed to set up system bus: %m");
718db961 912 return 0;
cbd37330
MS
913 }
914
718db961
LP
915 m->system_bus = bus;
916 bus = NULL;
cbd37330
MS
917
918 return 0;
5e8d1c9a
LP
919}
920
921static int bus_init_private(Manager *m) {
718db961
LP
922 _cleanup_close_ int fd = -1;
923 union sockaddr_union sa = {
924 .un.sun_family = AF_UNIX
5e8d1c9a 925 };
718db961
LP
926 sd_event_source *s;
927 socklen_t salen;
928 int r;
5e8d1c9a
LP
929
930 assert(m);
931
718db961 932 if (m->private_listen_fd >= 0)
5e8d1c9a
LP
933 return 0;
934
a6aa8912
LP
935 /* We don't need the private socket if we have kdbus */
936 if (m->kdbus_fd >= 0)
937 return 0;
938
b2c23da8 939 if (m->running_as == MANAGER_SYSTEM) {
be81bfc4
LP
940
941 /* We want the private bus only when running as init */
942 if (getpid() != 1)
943 return 0;
944
718db961 945 strcpy(sa.un.sun_path, "/run/systemd/private");
f8294e41 946 salen = offsetof(union sockaddr_union, un.sun_path) + strlen("/run/systemd/private");
be81bfc4 947 } else {
718db961
LP
948 size_t left = sizeof(sa.un.sun_path);
949 char *p = sa.un.sun_path;
be81bfc4 950 const char *e;
be81bfc4 951
4db17f29 952 e = secure_getenv("XDG_RUNTIME_DIR");
718db961
LP
953 if (!e) {
954 log_error("Failed to determine XDG_RUNTIME_DIR");
955 return -EHOSTDOWN;
be81bfc4
LP
956 }
957
718db961
LP
958 left = strpcpy(&p, left, e);
959 left = strpcpy(&p, left, "/systemd/private");
92f30349 960
718db961 961 salen = sizeof(sa.un) - left;
be81bfc4 962 }
5e8d1c9a 963
f0e62e89
LP
964 (void) mkdir_parents_label(sa.un.sun_path, 0755);
965 (void) unlink(sa.un.sun_path);
718db961
LP
966
967 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
4a62c710
MS
968 if (fd < 0)
969 return log_error_errno(errno, "Failed to allocate private socket: %m");
5e8d1c9a 970
718db961 971 r = bind(fd, &sa.sa, salen);
4a62c710
MS
972 if (r < 0)
973 return log_error_errno(errno, "Failed to bind private socket: %m");
5e8d1c9a 974
718db961 975 r = listen(fd, SOMAXCONN);
4a62c710
MS
976 if (r < 0)
977 return log_error_errno(errno, "Failed to make private socket listening: %m");
5e8d1c9a 978
151b9b96 979 r = sd_event_add_io(m->event, &s, fd, EPOLLIN, bus_on_connection, m);
23bbb0de
MS
980 if (r < 0)
981 return log_error_errno(r, "Failed to allocate event source: %m");
5e8d1c9a 982
7dfbe2e3
TG
983 (void) sd_event_source_set_description(s, "bus-connection");
984
718db961
LP
985 m->private_listen_fd = fd;
986 m->private_listen_event_source = s;
987 fd = -1;
5e8d1c9a 988
718db961 989 log_debug("Successfully created private D-Bus server.");
5e8d1c9a 990
718db961 991 return 0;
5e8d1c9a
LP
992}
993
3996fbe2 994int bus_init(Manager *m, bool try_bus_connect) {
5e8d1c9a
LP
995 int r;
996
3996fbe2 997 if (try_bus_connect) {
718db961
LP
998 r = bus_init_system(m);
999 if (r < 0)
1000 return r;
1001
1002 r = bus_init_api(m);
1003 if (r < 0)
3996fbe2
LP
1004 return r;
1005 }
1006
6fa48533
LP
1007 r = bus_init_private(m);
1008 if (r < 0)
5e8d1c9a 1009 return r;
f278026d 1010
ea430986
LP
1011 return 0;
1012}
1013
718db961 1014static void destroy_bus(Manager *m, sd_bus **bus) {
a567261a 1015 Iterator i;
718db961 1016 Job *j;
a567261a 1017
718db961
LP
1018 assert(m);
1019 assert(bus);
5e8d1c9a 1020
718db961 1021 if (!*bus)
cbd37330 1022 return;
f278026d 1023
718db961 1024 /* Get rid of tracked clients on this bus */
8f8f05a9
LP
1025 if (m->subscribed && sd_bus_track_get_bus(m->subscribed) == *bus)
1026 m->subscribed = sd_bus_track_unref(m->subscribed);
1027
718db961 1028 HASHMAP_FOREACH(j, m->jobs, i)
b39a2770
SW
1029 if (j->clients && sd_bus_track_get_bus(j->clients) == *bus)
1030 j->clients = sd_bus_track_unref(j->clients);
c1e1601e 1031
718db961 1032 /* Get rid of queued message on this bus */
8f88ecf6
LP
1033 if (m->queued_message && sd_bus_message_get_bus(m->queued_message) == *bus)
1034 m->queued_message = sd_bus_message_unref(m->queued_message);
f278026d 1035
718db961
LP
1036 /* Possibly flush unwritten data, but only if we are
1037 * unprivileged, since we don't want to sync here */
b2c23da8 1038 if (m->running_as != MANAGER_SYSTEM)
718db961 1039 sd_bus_flush(*bus);
5e8d1c9a 1040
718db961
LP
1041 /* And destroy the object */
1042 sd_bus_close(*bus);
1043 *bus = sd_bus_unref(*bus);
5e8d1c9a
LP
1044}
1045
1046void bus_done(Manager *m) {
718db961 1047 sd_bus *b;
05e343b7
LP
1048
1049 assert(m);
05e343b7 1050
718db961
LP
1051 if (m->api_bus)
1052 destroy_bus(m, &m->api_bus);
1053 if (m->system_bus)
1054 destroy_bus(m, &m->system_bus);
1055 while ((b = set_steal_first(m->private_buses)))
1056 destroy_bus(m, &b);
05e343b7 1057
525d3cc7 1058 m->private_buses = set_free(m->private_buses);
8f8f05a9
LP
1059
1060 m->subscribed = sd_bus_track_unref(m->subscribed);
6796073e 1061 m->deserialized_subscribed = strv_free(m->deserialized_subscribed);
05e343b7 1062
718db961
LP
1063 if (m->private_listen_event_source)
1064 m->private_listen_event_source = sd_event_source_unref(m->private_listen_event_source);
05e343b7 1065
03e334a1 1066 m->private_listen_fd = safe_close(m->private_listen_fd);
283868e1
SW
1067
1068 bus_verify_polkit_async_registry_free(m->polkit_registry);
a567261a 1069}
b23de6af
LP
1070
1071int bus_fdset_add_all(Manager *m, FDSet *fds) {
1072 Iterator i;
718db961
LP
1073 sd_bus *b;
1074 int fd;
b23de6af
LP
1075
1076 assert(m);
1077 assert(fds);
1078
1079 /* When we are about to reexecute we add all D-Bus fds to the
1080 * set to pass over to the newly executed systemd. They won't
718db961 1081 * be used there however, except thatt they are closed at the
b23de6af 1082 * very end of deserialization, those making it possible for
44143309 1083 * clients to synchronously wait for systemd to reexec by
b23de6af
LP
1084 * simply waiting for disconnection */
1085
718db961
LP
1086 if (m->api_bus) {
1087 fd = sd_bus_get_fd(m->api_bus);
1088 if (fd >= 0) {
b23de6af 1089 fd = fdset_put_dup(fds, fd);
b23de6af
LP
1090 if (fd < 0)
1091 return fd;
1092 }
1093 }
1094
718db961
LP
1095 SET_FOREACH(b, m->private_buses, i) {
1096 fd = sd_bus_get_fd(b);
1097 if (fd >= 0) {
b23de6af 1098 fd = fdset_put_dup(fds, fd);
b23de6af
LP
1099 if (fd < 0)
1100 return fd;
1101 }
1102 }
1103
718db961
LP
1104 /* We don't offer any APIs on the system bus (well, unless it
1105 * is the same as the API bus) hence we don't bother with it
1106 * here */
6fa48533 1107
718db961 1108 return 0;
6fa48533
LP
1109}
1110
8f8f05a9
LP
1111int bus_foreach_bus(
1112 Manager *m,
1113 sd_bus_track *subscribed2,
1114 int (*send_message)(sd_bus *bus, void *userdata),
1115 void *userdata) {
1116
1117 Iterator i;
1118 sd_bus *b;
1119 int r, ret = 0;
1120
ff9b60f3 1121 /* Send to all direct buses, unconditionally */
8f8f05a9
LP
1122 SET_FOREACH(b, m->private_buses, i) {
1123 r = send_message(b, userdata);
1124 if (r < 0)
1125 ret = r;
1126 }
1127
1128 /* Send to API bus, but only if somebody is subscribed */
1129 if (sd_bus_track_count(m->subscribed) > 0 ||
1130 sd_bus_track_count(subscribed2) > 0) {
1131 r = send_message(m->api_bus, userdata);
1132 if (r < 0)
1133 ret = r;
1134 }
1135
1136 return ret;
1137}
1138
1139void bus_track_serialize(sd_bus_track *t, FILE *f) {
1140 const char *n;
1141
6fa48533
LP
1142 assert(f);
1143
8f8f05a9
LP
1144 for (n = sd_bus_track_first(t); n; n = sd_bus_track_next(t))
1145 fprintf(f, "subscribed=%s\n", n);
6fa48533
LP
1146}
1147
8f8f05a9
LP
1148int bus_track_deserialize_item(char ***l, const char *line) {
1149 const char *e;
230314d7 1150 int r;
8f8f05a9
LP
1151
1152 assert(l);
6fa48533
LP
1153 assert(line);
1154
8f8f05a9
LP
1155 e = startswith(line, "subscribed=");
1156 if (!e)
230314d7
LP
1157 return 0;
1158
1159 r = strv_extend(l, e);
1160 if (r < 0)
1161 return r;
8f8f05a9 1162
230314d7 1163 return 1;
8f8f05a9
LP
1164}
1165
1166int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l) {
1167 int r = 0;
1168
1169 assert(m);
1170 assert(t);
1171 assert(l);
1172
1173 if (!strv_isempty(*l) && m->api_bus) {
1174 char **i;
1175
1176 if (!*t) {
1177 r = sd_bus_track_new(m->api_bus, t, NULL, NULL);
1178 if (r < 0)
1179 return r;
1180 }
1181
1182 r = 0;
1183 STRV_FOREACH(i, *l) {
1184 int k;
1185
1186 k = sd_bus_track_add_name(*t, *i);
1187 if (k < 0)
1188 r = k;
1189 }
1190 }
1191
6796073e 1192 *l = strv_free(*l);
8f8f05a9
LP
1193
1194 return r;
6fa48533 1195}
283868e1 1196
1d22e906 1197int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
403ed0e5 1198 return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-units", NULL, false, UID_INVALID, &m->polkit_registry, error);
283868e1
SW
1199}
1200
283868e1 1201int bus_verify_manage_unit_files_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
403ed0e5 1202 return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-unit-files", NULL, false, UID_INVALID, &m->polkit_registry, error);
283868e1
SW
1203}
1204
1205int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
403ed0e5 1206 return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.reload-daemon", NULL, false, UID_INVALID, &m->polkit_registry, error);
283868e1 1207}
1d22e906
LP
1208
1209int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
403ed0e5 1210 return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.set-environment", NULL, false, UID_INVALID, &m->polkit_registry, error);
1d22e906 1211}