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