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