]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/bus-util.c
85b5bedbc09d69e20aca9a1c383f5de5fa4af602
[thirdparty/systemd.git] / src / shared / bus-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <inttypes.h>
6 #include <stdlib.h>
7 #include <sys/ioctl.h>
8 #include <sys/resource.h>
9 #include <sys/socket.h>
10 #include <unistd.h>
11
12 #include "sd-bus.h"
13 #include "sd-daemon.h"
14 #include "sd-event.h"
15 #include "sd-id128.h"
16
17 #include "alloc-util.h"
18 #include "bus-internal.h"
19 #include "bus-label.h"
20 #include "bus-util.h"
21 #include "path-util.h"
22 #include "rlimit-util.h"
23 #include "socket-util.h"
24 #include "stdio-util.h"
25 #include "string-util.h"
26
27 static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
28 sd_event *e = userdata;
29
30 assert(m);
31 assert(e);
32
33 sd_bus_close(sd_bus_message_get_bus(m));
34 sd_event_exit(e, 0);
35
36 return 1;
37 }
38
39 int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
40 const char *match;
41 const char *unique;
42 int r;
43
44 assert(e);
45 assert(bus);
46 assert(name);
47
48 /* We unregister the name here and then wait for the
49 * NameOwnerChanged signal for this event to arrive before we
50 * quit. We do this in order to make sure that any queued
51 * requests are still processed before we really exit. */
52
53 r = sd_bus_get_unique_name(bus, &unique);
54 if (r < 0)
55 return r;
56
57 match = strjoina(
58 "sender='org.freedesktop.DBus',"
59 "type='signal',"
60 "interface='org.freedesktop.DBus',"
61 "member='NameOwnerChanged',"
62 "path='/org/freedesktop/DBus',"
63 "arg0='", name, "',",
64 "arg1='", unique, "',",
65 "arg2=''");
66
67 r = sd_bus_add_match_async(bus, NULL, match, name_owner_change_callback, NULL, e);
68 if (r < 0)
69 return r;
70
71 r = sd_bus_release_name_async(bus, NULL, name, NULL, NULL);
72 if (r < 0)
73 return r;
74
75 return 0;
76 }
77
78 int bus_event_loop_with_idle(
79 sd_event *e,
80 sd_bus *bus,
81 const char *name,
82 usec_t timeout,
83 check_idle_t check_idle,
84 void *userdata) {
85 bool exiting = false;
86 int r, code;
87
88 assert(e);
89 assert(bus);
90 assert(name);
91
92 for (;;) {
93 bool idle;
94
95 r = sd_event_get_state(e);
96 if (r < 0)
97 return r;
98 if (r == SD_EVENT_FINISHED)
99 break;
100
101 if (check_idle)
102 idle = check_idle(userdata);
103 else
104 idle = true;
105
106 r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
107 if (r < 0)
108 return r;
109
110 if (r == 0 && !exiting && idle) {
111 /* Inform the service manager that we are going down, so that it will queue all
112 * further start requests, instead of assuming we are already running. */
113 sd_notify(false, "STOPPING=1");
114
115 r = bus_async_unregister_and_exit(e, bus, name);
116 if (r < 0)
117 return r;
118
119 exiting = true;
120 continue;
121 }
122 }
123
124 r = sd_event_get_exit_code(e, &code);
125 if (r < 0)
126 return r;
127
128 return code;
129 }
130
131 int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
132 _cleanup_(sd_bus_message_unrefp) sd_bus_message *rep = NULL;
133 int r, has_owner = 0;
134
135 assert(c);
136 assert(name);
137
138 r = sd_bus_call_method(c,
139 "org.freedesktop.DBus",
140 "/org/freedesktop/dbus",
141 "org.freedesktop.DBus",
142 "NameHasOwner",
143 error,
144 &rep,
145 "s",
146 name);
147 if (r < 0)
148 return r;
149
150 r = sd_bus_message_read_basic(rep, 'b', &has_owner);
151 if (r < 0)
152 return sd_bus_error_set_errno(error, r);
153
154 return has_owner;
155 }
156
157 int bus_check_peercred(sd_bus *c) {
158 struct ucred ucred;
159 int fd, r;
160
161 assert(c);
162
163 fd = sd_bus_get_fd(c);
164 if (fd < 0)
165 return fd;
166
167 r = getpeercred(fd, &ucred);
168 if (r < 0)
169 return r;
170
171 if (ucred.uid != 0 && ucred.uid != geteuid())
172 return -EPERM;
173
174 return 1;
175 }
176
177 int bus_connect_system_systemd(sd_bus **_bus) {
178 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
179 int r;
180
181 assert(_bus);
182
183 if (geteuid() != 0)
184 return sd_bus_default_system(_bus);
185
186 /* If we are root then let's talk directly to the system
187 * instance, instead of going via the bus */
188
189 r = sd_bus_new(&bus);
190 if (r < 0)
191 return r;
192
193 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
194 if (r < 0)
195 return r;
196
197 r = sd_bus_start(bus);
198 if (r < 0)
199 return sd_bus_default_system(_bus);
200
201 r = bus_check_peercred(bus);
202 if (r < 0)
203 return r;
204
205 *_bus = TAKE_PTR(bus);
206
207 return 0;
208 }
209
210 int bus_connect_user_systemd(sd_bus **_bus) {
211 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
212 _cleanup_free_ char *ee = NULL;
213 const char *e;
214 int r;
215
216 assert(_bus);
217
218 e = secure_getenv("XDG_RUNTIME_DIR");
219 if (!e)
220 return sd_bus_default_user(_bus);
221
222 ee = bus_address_escape(e);
223 if (!ee)
224 return -ENOMEM;
225
226 r = sd_bus_new(&bus);
227 if (r < 0)
228 return r;
229
230 bus->address = strjoin("unix:path=", ee, "/systemd/private");
231 if (!bus->address)
232 return -ENOMEM;
233
234 r = sd_bus_start(bus);
235 if (r < 0)
236 return sd_bus_default_user(_bus);
237
238 r = bus_check_peercred(bus);
239 if (r < 0)
240 return r;
241
242 *_bus = TAKE_PTR(bus);
243
244 return 0;
245 }
246
247 int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **ret) {
248 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
249 int r;
250
251 assert(transport >= 0);
252 assert(transport < _BUS_TRANSPORT_MAX);
253 assert(ret);
254
255 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
256 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
257
258 switch (transport) {
259
260 case BUS_TRANSPORT_LOCAL:
261 if (user)
262 r = sd_bus_default_user(&bus);
263 else {
264 if (sd_booted() <= 0) {
265 /* Print a friendly message when the local system is actually not running systemd as PID 1. */
266 log_error("System has not been booted with systemd as init system (PID 1). Can't operate.");
267
268 return -EHOSTDOWN;
269 }
270 r = sd_bus_default_system(&bus);
271 }
272 break;
273
274 case BUS_TRANSPORT_REMOTE:
275 r = sd_bus_open_system_remote(&bus, host);
276 break;
277
278 case BUS_TRANSPORT_MACHINE:
279 r = sd_bus_open_system_machine(&bus, host);
280 break;
281
282 default:
283 assert_not_reached("Hmm, unknown transport type.");
284 }
285 if (r < 0)
286 return r;
287
288 r = sd_bus_set_exit_on_disconnect(bus, true);
289 if (r < 0)
290 return r;
291
292 *ret = TAKE_PTR(bus);
293
294 return 0;
295 }
296
297 int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
298 int r;
299
300 assert(transport >= 0);
301 assert(transport < _BUS_TRANSPORT_MAX);
302 assert(bus);
303
304 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
305 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
306
307 switch (transport) {
308
309 case BUS_TRANSPORT_LOCAL:
310 if (user)
311 r = bus_connect_user_systemd(bus);
312 else {
313 if (sd_booted() <= 0)
314 /* Print a friendly message when the local system is actually not running systemd as PID 1. */
315 return log_error_errno(SYNTHETIC_ERRNO(EHOSTDOWN),
316 "System has not been booted with systemd as init system (PID 1). Can't operate.");
317 r = bus_connect_system_systemd(bus);
318 }
319 break;
320
321 case BUS_TRANSPORT_REMOTE:
322 r = sd_bus_open_system_remote(bus, host);
323 break;
324
325 case BUS_TRANSPORT_MACHINE:
326 r = sd_bus_open_system_machine(bus, host);
327 break;
328
329 default:
330 assert_not_reached("Hmm, unknown transport type.");
331 }
332
333 return r;
334 }
335
336 int bus_property_get_bool(
337 sd_bus *bus,
338 const char *path,
339 const char *interface,
340 const char *property,
341 sd_bus_message *reply,
342 void *userdata,
343 sd_bus_error *error) {
344
345 int b = *(bool*) userdata;
346
347 return sd_bus_message_append_basic(reply, 'b', &b);
348 }
349
350 int bus_property_set_bool(
351 sd_bus *bus,
352 const char *path,
353 const char *interface,
354 const char *property,
355 sd_bus_message *value,
356 void *userdata,
357 sd_bus_error *error) {
358
359 int b, r;
360
361 r = sd_bus_message_read(value, "b", &b);
362 if (r < 0)
363 return r;
364
365 *(bool*) userdata = b;
366 return 0;
367 }
368
369 int bus_property_get_id128(
370 sd_bus *bus,
371 const char *path,
372 const char *interface,
373 const char *property,
374 sd_bus_message *reply,
375 void *userdata,
376 sd_bus_error *error) {
377
378 sd_id128_t *id = userdata;
379
380 if (sd_id128_is_null(*id)) /* Add an empty array if the ID is zero */
381 return sd_bus_message_append(reply, "ay", 0);
382 else
383 return sd_bus_message_append_array(reply, 'y', id->bytes, 16);
384 }
385
386 #if __SIZEOF_SIZE_T__ != 8
387 int bus_property_get_size(
388 sd_bus *bus,
389 const char *path,
390 const char *interface,
391 const char *property,
392 sd_bus_message *reply,
393 void *userdata,
394 sd_bus_error *error) {
395
396 uint64_t sz = *(size_t*) userdata;
397
398 return sd_bus_message_append_basic(reply, 't', &sz);
399 }
400 #endif
401
402 #if __SIZEOF_LONG__ != 8
403 int bus_property_get_long(
404 sd_bus *bus,
405 const char *path,
406 const char *interface,
407 const char *property,
408 sd_bus_message *reply,
409 void *userdata,
410 sd_bus_error *error) {
411
412 int64_t l = *(long*) userdata;
413
414 return sd_bus_message_append_basic(reply, 'x', &l);
415 }
416
417 int bus_property_get_ulong(
418 sd_bus *bus,
419 const char *path,
420 const char *interface,
421 const char *property,
422 sd_bus_message *reply,
423 void *userdata,
424 sd_bus_error *error) {
425
426 uint64_t ul = *(unsigned long*) userdata;
427
428 return sd_bus_message_append_basic(reply, 't', &ul);
429 }
430 #endif
431
432 /**
433 * bus_path_encode_unique() - encode unique object path
434 * @b: bus connection or NULL
435 * @prefix: object path prefix
436 * @sender_id: unique-name of client, or NULL
437 * @external_id: external ID to be chosen by client, or NULL
438 * @ret_path: storage for encoded object path pointer
439 *
440 * Whenever we provide a bus API that allows clients to create and manage
441 * server-side objects, we need to provide a unique name for these objects. If
442 * we let the server choose the name, we suffer from a race condition: If a
443 * client creates an object asynchronously, it cannot destroy that object until
444 * it received the method reply. It cannot know the name of the new object,
445 * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
446 *
447 * Therefore, many APIs allow the client to choose the unique name for newly
448 * created objects. There're two problems to solve, though:
449 * 1) Object names are usually defined via dbus object paths, which are
450 * usually globally namespaced. Therefore, multiple clients must be able
451 * to choose unique object names without interference.
452 * 2) If multiple libraries share the same bus connection, they must be
453 * able to choose unique object names without interference.
454 * The first problem is solved easily by prefixing a name with the
455 * unique-bus-name of a connection. The server side must enforce this and
456 * reject any other name. The second problem is solved by providing unique
457 * suffixes from within sd-bus.
458 *
459 * This helper allows clients to create unique object-paths. It uses the
460 * template '/prefix/sender_id/external_id' and returns the new path in
461 * @ret_path (must be freed by the caller).
462 * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
463 * NULL, this function allocates a unique suffix via @b (by requesting a new
464 * cookie). If both @sender_id and @external_id are given, @b can be passed as
465 * NULL.
466 *
467 * Returns: 0 on success, negative error code on failure.
468 */
469 int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
470 _cleanup_free_ char *sender_label = NULL, *external_label = NULL;
471 char external_buf[DECIMAL_STR_MAX(uint64_t)], *p;
472 int r;
473
474 assert_return(b || (sender_id && external_id), -EINVAL);
475 assert_return(sd_bus_object_path_is_valid(prefix), -EINVAL);
476 assert_return(ret_path, -EINVAL);
477
478 if (!sender_id) {
479 r = sd_bus_get_unique_name(b, &sender_id);
480 if (r < 0)
481 return r;
482 }
483
484 if (!external_id) {
485 xsprintf(external_buf, "%"PRIu64, ++b->cookie);
486 external_id = external_buf;
487 }
488
489 sender_label = bus_label_escape(sender_id);
490 if (!sender_label)
491 return -ENOMEM;
492
493 external_label = bus_label_escape(external_id);
494 if (!external_label)
495 return -ENOMEM;
496
497 p = path_join(prefix, sender_label, external_label);
498 if (!p)
499 return -ENOMEM;
500
501 *ret_path = p;
502 return 0;
503 }
504
505 /**
506 * bus_path_decode_unique() - decode unique object path
507 * @path: object path to decode
508 * @prefix: object path prefix
509 * @ret_sender: output parameter for sender-id label
510 * @ret_external: output parameter for external-id label
511 *
512 * This does the reverse of bus_path_encode_unique() (see its description for
513 * details). Both trailing labels, sender-id and external-id, are unescaped and
514 * returned in the given output parameters (the caller must free them).
515 *
516 * Note that this function returns 0 if the path does not match the template
517 * (see bus_path_encode_unique()), 1 if it matched.
518 *
519 * Returns: Negative error code on failure, 0 if the given object path does not
520 * match the template (return parameters are set to NULL), 1 if it was
521 * parsed successfully (return parameters contain allocated labels).
522 */
523 int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external) {
524 const char *p, *q;
525 char *sender, *external;
526
527 assert(sd_bus_object_path_is_valid(path));
528 assert(sd_bus_object_path_is_valid(prefix));
529 assert(ret_sender);
530 assert(ret_external);
531
532 p = object_path_startswith(path, prefix);
533 if (!p) {
534 *ret_sender = NULL;
535 *ret_external = NULL;
536 return 0;
537 }
538
539 q = strchr(p, '/');
540 if (!q) {
541 *ret_sender = NULL;
542 *ret_external = NULL;
543 return 0;
544 }
545
546 sender = bus_label_unescape_n(p, q - p);
547 external = bus_label_unescape(q + 1);
548 if (!sender || !external) {
549 free(sender);
550 free(external);
551 return -ENOMEM;
552 }
553
554 *ret_sender = sender;
555 *ret_external = external;
556 return 1;
557 }
558
559 int bus_property_get_rlimit(
560 sd_bus *bus,
561 const char *path,
562 const char *interface,
563 const char *property,
564 sd_bus_message *reply,
565 void *userdata,
566 sd_bus_error *error) {
567
568 const char *is_soft;
569 struct rlimit *rl;
570 uint64_t u;
571 rlim_t x;
572
573 assert(bus);
574 assert(reply);
575 assert(userdata);
576
577 is_soft = endswith(property, "Soft");
578
579 rl = *(struct rlimit**) userdata;
580 if (rl)
581 x = is_soft ? rl->rlim_cur : rl->rlim_max;
582 else {
583 struct rlimit buf = {};
584 const char *s, *p;
585 int z;
586
587 /* Chop off "Soft" suffix */
588 s = is_soft ? strndupa(property, is_soft - property) : property;
589
590 /* Skip over any prefix, such as "Default" */
591 assert_se(p = strstr(s, "Limit"));
592
593 z = rlimit_from_string(p + 5);
594 assert(z >= 0);
595
596 (void) getrlimit(z, &buf);
597 x = is_soft ? buf.rlim_cur : buf.rlim_max;
598 }
599
600 /* rlim_t might have different sizes, let's map RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on all
601 * archs */
602 u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
603
604 return sd_bus_message_append(reply, "t", u);
605 }
606
607 int bus_track_add_name_many(sd_bus_track *t, char **l) {
608 int r = 0;
609 char **i;
610
611 assert(t);
612
613 /* Continues adding after failure, and returns the first failure. */
614
615 STRV_FOREACH(i, l) {
616 int k;
617
618 k = sd_bus_track_add_name(t, *i);
619 if (k < 0 && r >= 0)
620 r = k;
621 }
622
623 return r;
624 }
625
626 int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *description) {
627 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
628 const char *e;
629 int r;
630
631 assert(ret);
632
633 /* Match like sd_bus_open_system(), but with the "watch_bind" feature and the Connected() signal
634 * turned on. */
635
636 r = sd_bus_new(&bus);
637 if (r < 0)
638 return r;
639
640 if (description) {
641 r = sd_bus_set_description(bus, description);
642 if (r < 0)
643 return r;
644 }
645
646 e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
647 if (!e)
648 e = DEFAULT_SYSTEM_BUS_ADDRESS;
649
650 r = sd_bus_set_address(bus, e);
651 if (r < 0)
652 return r;
653
654 r = sd_bus_set_bus_client(bus, true);
655 if (r < 0)
656 return r;
657
658 r = sd_bus_negotiate_creds(bus, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS);
659 if (r < 0)
660 return r;
661
662 r = sd_bus_set_watch_bind(bus, true);
663 if (r < 0)
664 return r;
665
666 r = sd_bus_set_connected_signal(bus, true);
667 if (r < 0)
668 return r;
669
670 r = sd_bus_start(bus);
671 if (r < 0)
672 return r;
673
674 *ret = TAKE_PTR(bus);
675
676 return 0;
677 }
678
679 int bus_reply_pair_array(sd_bus_message *m, char **l) {
680 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
681 char **k, **v;
682 int r;
683
684 assert(m);
685
686 /* Reply to the specified message with a message containing a dictionary put together from the
687 * specified strv */
688
689 r = sd_bus_message_new_method_return(m, &reply);
690 if (r < 0)
691 return r;
692
693 r = sd_bus_message_open_container(reply, 'a', "{ss}");
694 if (r < 0)
695 return r;
696
697 STRV_FOREACH_PAIR(k, v, l) {
698 r = sd_bus_message_append(reply, "{ss}", *k, *v);
699 if (r < 0)
700 return r;
701 }
702
703 r = sd_bus_message_close_container(reply);
704 if (r < 0)
705 return r;
706
707 return sd_bus_send(NULL, reply, NULL);
708 }
709
710 static void bus_message_unref_wrapper(void *m) {
711 sd_bus_message_unref(m);
712 }
713
714 const struct hash_ops bus_message_hash_ops = {
715 .hash = trivial_hash_func,
716 .compare = trivial_compare_func,
717 .free_value = bus_message_unref_wrapper,
718 };