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