]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/shared/bus-util.c
man: Fix typo in name of sd_id128_to_uuid_string
[thirdparty/systemd.git] / src / shared / bus-util.c
... / ...
CommitLineData
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include <fcntl.h>
4#include <malloc.h>
5#include <stdlib.h>
6#include <sys/socket.h>
7#include <sys/stat.h>
8#include <unistd.h>
9
10#include "sd-bus.h"
11#include "sd-daemon.h"
12#include "sd-event.h"
13#include "sd-id128.h"
14
15#include "alloc-util.h"
16#include "bus-common-errors.h"
17#include "bus-internal.h"
18#include "bus-label.h"
19#include "bus-util.h"
20#include "capsule-util.h"
21#include "chase.h"
22#include "daemon-util.h"
23#include "env-util.h"
24#include "errno-util.h"
25#include "fd-util.h"
26#include "format-util.h"
27#include "log.h"
28#include "memfd-util.h"
29#include "memstream-util.h"
30#include "path-util.h"
31#include "pidref.h"
32#include "socket-util.h"
33#include "stdio-util.h"
34#include "string-table.h"
35#include "string-util.h"
36#include "strv.h"
37#include "time-util.h"
38#include "uid-classification.h"
39
40static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *reterr_error) {
41 sd_event *e = ASSERT_PTR(userdata);
42
43 assert(m);
44
45 sd_bus_close(sd_bus_message_get_bus(m));
46 sd_event_exit(e, 0);
47
48 return 1;
49}
50
51int bus_log_address_error(int r, BusTransport transport) {
52 bool hint = transport == BUS_TRANSPORT_LOCAL && r == -ENOMEDIUM;
53
54 return log_error_errno(r,
55 hint ? "Failed to set bus address: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined (consider using --machine=<user>@.host --user to connect to bus of other user)" :
56 "Failed to set bus address: %m");
57}
58
59int bus_log_connect_full(int log_level, int r, BusTransport transport, RuntimeScope scope) {
60 bool hint_vars = transport == BUS_TRANSPORT_LOCAL && r == -ENOMEDIUM,
61 hint_addr = transport == BUS_TRANSPORT_LOCAL && ERRNO_IS_PRIVILEGE(r);
62
63 return log_full_errno(log_level, r,
64 hint_vars ? "Failed to connect to %s scope bus via %s transport: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined (consider using --machine=<user>@.host --user to connect to bus of other user)" :
65 hint_addr ? "Failed to connect to %s scope bus via %s transport: Operation not permitted (consider using --machine=<user>@.host --user to connect to bus of other user)" :
66 "Failed to connect to %s scope bus via %s transport: %m", runtime_scope_to_string(scope), bus_transport_to_string(transport));
67}
68
69int bus_log_connect_error(int r, BusTransport transport, RuntimeScope scope) {
70 return bus_log_connect_full(LOG_ERR, r, transport, scope);
71}
72
73int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
74 const char *match;
75 const char *unique;
76 int r;
77
78 assert(e);
79 assert(bus);
80 assert(name);
81
82 /* We unregister the name here and then wait for the
83 * NameOwnerChanged signal for this event to arrive before we
84 * quit. We do this in order to make sure that any queued
85 * requests are still processed before we really exit. */
86
87 r = sd_bus_get_unique_name(bus, &unique);
88 if (r < 0)
89 return r;
90
91 match = strjoina(
92 "sender='org.freedesktop.DBus',"
93 "type='signal',"
94 "interface='org.freedesktop.DBus',"
95 "member='NameOwnerChanged',"
96 "path='/org/freedesktop/DBus',"
97 "arg0='", name, "',",
98 "arg1='", unique, "',",
99 "arg2=''");
100
101 r = sd_bus_add_match_async(bus, NULL, match, name_owner_change_callback, NULL, e);
102 if (r < 0)
103 return r;
104
105 r = sd_bus_release_name_async(bus, NULL, name, NULL, NULL);
106 if (r < 0)
107 return r;
108
109 return 0;
110}
111
112static bool idle_allowed(void) {
113 static int allowed = -1;
114
115 if (allowed >= 0)
116 return allowed;
117
118 allowed = secure_getenv_bool("SYSTEMD_EXIT_ON_IDLE");
119 if (allowed < 0 && allowed != -ENXIO)
120 log_debug_errno(allowed, "Failed to parse $SYSTEMD_EXIT_ON_IDLE, ignoring: %m");
121
122 return allowed != 0;
123}
124
125int bus_event_loop_with_idle(
126 sd_event *e,
127 sd_bus *bus,
128 const char *name,
129 usec_t timeout,
130 check_idle_t check_idle,
131 void *userdata) {
132
133 bool exiting = false;
134 int r, code;
135
136 assert(e);
137 assert(bus);
138 assert(name);
139
140 for (;;) {
141 bool idle;
142
143 r = sd_event_get_state(e);
144 if (r < 0)
145 return r;
146 if (r == SD_EVENT_FINISHED)
147 break;
148
149 if (!idle_allowed() || sd_bus_pending_method_calls(bus) > 0)
150 idle = false;
151 else if (check_idle)
152 idle = check_idle(userdata);
153 else
154 idle = true;
155
156 r = sd_event_run(e, exiting || !idle ? UINT64_MAX : timeout);
157 if (r < 0)
158 return r;
159
160 if (r == 0 && !exiting && idle) {
161 log_debug("Idle for %s, exiting.", FORMAT_TIMESPAN(timeout, 1));
162
163 /* Inform the service manager that we are going down, so that it will queue all
164 * further start requests, instead of assuming we are still running. */
165 (void) sd_notify(false, NOTIFY_STOPPING_MESSAGE);
166
167 r = bus_async_unregister_and_exit(e, bus, name);
168 if (r < 0)
169 return r;
170
171 exiting = true;
172 }
173 }
174
175 r = sd_event_get_exit_code(e, &code);
176 if (r < 0)
177 return r;
178
179 return code;
180}
181
182int bus_name_has_owner(sd_bus *bus, const char *name, sd_bus_error *reterr_error) {
183 _cleanup_(sd_bus_message_unrefp) sd_bus_message *rep = NULL;
184 int r, has_owner = 0;
185
186 assert(bus);
187 assert(name);
188
189 r = sd_bus_call_method(bus,
190 "org.freedesktop.DBus",
191 "/org/freedesktop/dbus",
192 "org.freedesktop.DBus",
193 "NameHasOwner",
194 reterr_error,
195 &rep,
196 "s",
197 name);
198 if (r < 0)
199 return r;
200
201 r = sd_bus_message_read_basic(rep, 'b', &has_owner);
202 if (r < 0)
203 return sd_bus_error_set_errno(reterr_error, r);
204
205 return has_owner;
206}
207
208bool bus_error_is_unknown_service(const sd_bus_error *error) {
209 return sd_bus_error_has_names(error,
210 SD_BUS_ERROR_SERVICE_UNKNOWN,
211 SD_BUS_ERROR_NAME_HAS_NO_OWNER,
212 BUS_ERROR_NO_SUCH_UNIT);
213}
214
215bool bus_error_is_connection(const sd_bus_error *error) {
216 return sd_bus_error_has_names(error,
217 SD_BUS_ERROR_NO_REPLY,
218 SD_BUS_ERROR_DISCONNECTED,
219 SD_BUS_ERROR_TIMED_OUT);
220}
221
222int bus_check_peercred(sd_bus *bus) {
223 struct ucred ucred;
224 int fd, r;
225
226 assert(bus);
227
228 fd = sd_bus_get_fd(bus);
229 if (fd < 0)
230 return fd;
231
232 r = getpeercred(fd, &ucred);
233 if (r < 0)
234 return r;
235
236 if (ucred.uid != 0 && ucred.uid != geteuid())
237 return -EPERM;
238
239 return 1;
240}
241
242int bus_connect_system_systemd(sd_bus **ret) {
243 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
244 int r;
245
246 assert(ret);
247
248 r = sd_bus_new(&bus);
249 if (r < 0)
250 return r;
251
252 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
253 if (r < 0)
254 return r;
255
256 r = sd_bus_start(bus);
257 if (r < 0)
258 return r;
259
260 r = bus_check_peercred(bus);
261 if (r < 0)
262 return r;
263
264 *ret = TAKE_PTR(bus);
265 return 0;
266}
267
268int bus_connect_user_systemd(sd_bus **ret) {
269 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
270 _cleanup_free_ char *ee = NULL;
271 const char *e;
272 int r;
273
274 assert(ret);
275
276 e = secure_getenv("XDG_RUNTIME_DIR");
277 if (!e)
278 return -ENOMEDIUM;
279
280 ee = bus_address_escape(e);
281 if (!ee)
282 return -ENOMEM;
283
284 r = sd_bus_new(&bus);
285 if (r < 0)
286 return r;
287
288 bus->address = strjoin("unix:path=", ee, "/systemd/private");
289 if (!bus->address)
290 return -ENOMEM;
291
292 r = sd_bus_start(bus);
293 if (r < 0)
294 return r;
295
296 r = bus_check_peercred(bus);
297 if (r < 0)
298 return r;
299
300 *ret = TAKE_PTR(bus);
301 return 0;
302}
303
304static int pin_capsule_socket(const char *capsule, const char *suffix, uid_t *ret_uid, gid_t *ret_gid) {
305 _cleanup_close_ int inode_fd = -EBADF;
306 _cleanup_free_ char *p = NULL;
307 struct stat st;
308 int r;
309
310 assert(capsule);
311 assert(suffix);
312 assert(ret_uid);
313 assert(ret_gid);
314
315 p = path_join("/run/capsules", capsule, suffix);
316 if (!p)
317 return -ENOMEM;
318
319 /* We enter territory owned by the user, hence let's be paranoid about symlinks and ownership */
320 r = chase(p, /* root= */ NULL, CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS, /* ret_path= */ NULL, &inode_fd);
321 if (r < 0)
322 return r;
323
324 if (fstat(inode_fd, &st) < 0)
325 return negative_errno();
326
327 /* Paranoid safety check */
328 if (uid_is_system(st.st_uid) || gid_is_system(st.st_gid))
329 return -EPERM;
330
331 *ret_uid = st.st_uid;
332 *ret_gid = st.st_gid;
333
334 return TAKE_FD(inode_fd);
335}
336
337static int bus_set_address_capsule(sd_bus *bus, const char *capsule, const char *suffix, int *ret_pin_fd) {
338 _cleanup_close_ int inode_fd = -EBADF;
339 _cleanup_free_ char *pp = NULL;
340 uid_t uid;
341 gid_t gid;
342 int r;
343
344 assert(bus);
345 assert(capsule);
346 assert(suffix);
347 assert(ret_pin_fd);
348
349 /* Connects to a capsule's user bus. We need to do so under the capsule's UID/GID, otherwise
350 * the service manager might refuse our connection. Hence fake it. */
351
352 r = capsule_name_is_valid(capsule);
353 if (r < 0)
354 return r;
355 if (r == 0)
356 return -EINVAL;
357
358 inode_fd = pin_capsule_socket(capsule, suffix, &uid, &gid);
359 if (inode_fd < 0)
360 return inode_fd;
361
362 pp = bus_address_escape(FORMAT_PROC_FD_PATH(inode_fd));
363 if (!pp)
364 return -ENOMEM;
365
366 if (asprintf(&bus->address, "unix:path=%s,uid=" UID_FMT ",gid=" GID_FMT, pp, uid, gid) < 0)
367 return -ENOMEM;
368
369 *ret_pin_fd = TAKE_FD(inode_fd); /* This fd must be kept pinned until the connection has been established */
370 return 0;
371}
372
373int bus_set_address_capsule_bus(sd_bus *bus, const char *capsule, int *ret_pin_fd) {
374 return bus_set_address_capsule(bus, capsule, "bus", ret_pin_fd);
375}
376
377int bus_connect_capsule_systemd(const char *capsule, sd_bus **ret) {
378 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
379 _cleanup_close_ int inode_fd = -EBADF;
380 int r;
381
382 assert(capsule);
383 assert(ret);
384
385 r = sd_bus_new(&bus);
386 if (r < 0)
387 return r;
388
389 r = bus_set_address_capsule(bus, capsule, "systemd/private", &inode_fd);
390 if (r < 0)
391 return r;
392
393 r = sd_bus_start(bus);
394 if (r < 0)
395 return r;
396
397 *ret = TAKE_PTR(bus);
398 return 0;
399}
400
401int bus_connect_capsule_bus(const char *capsule, sd_bus **ret) {
402 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
403 _cleanup_close_ int inode_fd = -EBADF;
404 int r;
405
406 assert(capsule);
407 assert(ret);
408
409 r = sd_bus_new(&bus);
410 if (r < 0)
411 return r;
412
413 r = bus_set_address_capsule_bus(bus, capsule, &inode_fd);
414 if (r < 0)
415 return r;
416
417 r = sd_bus_set_bus_client(bus, true);
418 if (r < 0)
419 return r;
420
421 r = sd_bus_start(bus);
422 if (r < 0)
423 return r;
424
425 *ret = TAKE_PTR(bus);
426 return 0;
427}
428
429int bus_connect_transport(
430 BusTransport transport,
431 const char *host,
432 RuntimeScope runtime_scope,
433 sd_bus **ret) {
434
435 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
436 int r;
437
438 assert(transport >= 0);
439 assert(transport < _BUS_TRANSPORT_MAX);
440 assert(ret);
441
442 switch (transport) {
443
444 case BUS_TRANSPORT_LOCAL:
445 assert_return(!host, -EINVAL);
446
447 switch (runtime_scope) {
448
449 case RUNTIME_SCOPE_USER:
450 r = sd_bus_default_user(&bus);
451 break;
452
453 case RUNTIME_SCOPE_SYSTEM:
454 if (sd_booted() <= 0)
455 /* Print a friendly message when the local system is actually not running systemd as PID 1. */
456 return log_error_errno(SYNTHETIC_ERRNO(EHOSTDOWN),
457 "System has not been booted with systemd as init system (PID 1). Can't operate.");
458
459 r = sd_bus_default_system(&bus);
460 break;
461
462 default:
463 assert_not_reached();
464 }
465 break;
466
467 case BUS_TRANSPORT_REMOTE:
468 assert_return(runtime_scope == RUNTIME_SCOPE_SYSTEM, -EOPNOTSUPP);
469
470 r = sd_bus_open_system_remote(&bus, host);
471 break;
472
473 case BUS_TRANSPORT_MACHINE:
474 switch (runtime_scope) {
475
476 case RUNTIME_SCOPE_USER:
477 r = sd_bus_open_user_machine(&bus, host);
478 break;
479
480 case RUNTIME_SCOPE_SYSTEM:
481 r = sd_bus_open_system_machine(&bus, host);
482 break;
483
484 default:
485 assert_not_reached();
486 }
487
488 break;
489
490 case BUS_TRANSPORT_CAPSULE:
491 assert_return(runtime_scope == RUNTIME_SCOPE_USER, -EINVAL);
492
493 r = bus_connect_capsule_bus(host, &bus);
494 break;
495
496 default:
497 assert_not_reached();
498 }
499 if (r < 0)
500 return r;
501
502 r = sd_bus_set_exit_on_disconnect(bus, true);
503 if (r < 0)
504 return r;
505
506 *ret = TAKE_PTR(bus);
507 return 0;
508}
509
510int bus_connect_transport_systemd(
511 BusTransport transport,
512 const char *host,
513 RuntimeScope runtime_scope,
514 sd_bus **ret) {
515
516 int r;
517
518 assert(transport >= 0);
519 assert(transport < _BUS_TRANSPORT_MAX);
520 assert(ret);
521
522 switch (transport) {
523
524 case BUS_TRANSPORT_LOCAL:
525 assert_return(!host, -EINVAL);
526
527 switch (runtime_scope) {
528
529 case RUNTIME_SCOPE_USER:
530 r = bus_connect_user_systemd(ret);
531 /* We used to always fall back to the user session bus if we couldn't connect to the
532 * private manager bus. To keep compat with existing code that was setting
533 * DBUS_SESSION_BUS_ADDRESS without setting XDG_RUNTIME_DIR, connect to the user
534 * session bus if DBUS_SESSION_BUS_ADDRESS is set and XDG_RUNTIME_DIR isn't. */
535 if (r == -ENOMEDIUM && secure_getenv("DBUS_SESSION_BUS_ADDRESS")) {
536 log_debug_errno(r, "$XDG_RUNTIME_DIR not set, unable to connect to private bus. Falling back to session bus.");
537 r = sd_bus_default_user(ret);
538 }
539
540 return r;
541
542 case RUNTIME_SCOPE_SYSTEM:
543 if (sd_booted() <= 0)
544 /* Print a friendly message when the local system is actually not running systemd as PID 1. */
545 return log_error_errno(SYNTHETIC_ERRNO(EHOSTDOWN),
546 "System has not been booted with systemd as init system (PID 1). Can't operate.");
547
548 /* If we are root then let's talk directly to the system instance, instead of
549 * going via the bus. */
550 if (geteuid() == 0)
551 return bus_connect_system_systemd(ret);
552
553 return sd_bus_default_system(ret);
554
555 default:
556 assert_not_reached();
557 }
558
559 break;
560
561 case BUS_TRANSPORT_REMOTE:
562 assert_return(runtime_scope == RUNTIME_SCOPE_SYSTEM, -EOPNOTSUPP);
563 return sd_bus_open_system_remote(ret, host);
564
565 case BUS_TRANSPORT_MACHINE:
566 assert_return(runtime_scope == RUNTIME_SCOPE_SYSTEM, -EOPNOTSUPP);
567 return sd_bus_open_system_machine(ret, host);
568
569 case BUS_TRANSPORT_CAPSULE:
570 assert_return(runtime_scope == RUNTIME_SCOPE_USER, -EINVAL);
571 return bus_connect_capsule_systemd(host, ret);
572
573 default:
574 assert_not_reached();
575 }
576}
577
578/**
579 * bus_path_encode_unique() - encode unique object path
580 * @b: bus connection or NULL
581 * @prefix: object path prefix
582 * @sender_id: unique-name of client, or NULL
583 * @external_id: external ID to be chosen by client, or NULL
584 * @ret_path: storage for encoded object path pointer
585 *
586 * Whenever we provide a bus API that allows clients to create and manage
587 * server-side objects, we need to provide a unique name for these objects. If
588 * we let the server choose the name, we suffer from a race condition: If a
589 * client creates an object asynchronously, it cannot destroy that object until
590 * it received the method reply. It cannot know the name of the new object,
591 * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
592 *
593 * Therefore, many APIs allow the client to choose the unique name for newly
594 * created objects. There're two problems to solve, though:
595 * 1) Object names are usually defined via dbus object paths, which are
596 * usually globally namespaced. Therefore, multiple clients must be able
597 * to choose unique object names without interference.
598 * 2) If multiple libraries share the same bus connection, they must be
599 * able to choose unique object names without interference.
600 * The first problem is solved easily by prefixing a name with the
601 * unique-bus-name of a connection. The server side must enforce this and
602 * reject any other name. The second problem is solved by providing unique
603 * suffixes from within sd-bus.
604 *
605 * This helper allows clients to create unique object-paths. It uses the
606 * template '/prefix/sender_id/external_id' and returns the new path in
607 * @ret_path (must be freed by the caller).
608 * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
609 * NULL, this function allocates a unique suffix via @b (by requesting a new
610 * cookie). If both @sender_id and @external_id are given, @b can be passed as
611 * NULL.
612 *
613 * Returns: 0 on success, negative error code on failure.
614 */
615int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
616 _cleanup_free_ char *sender_label = NULL, *external_label = NULL;
617 char external_buf[DECIMAL_STR_MAX(uint64_t)], *p;
618 int r;
619
620 assert_return(b || (sender_id && external_id), -EINVAL);
621 assert_return(sd_bus_object_path_is_valid(prefix), -EINVAL);
622 assert_return(ret_path, -EINVAL);
623
624 if (!sender_id) {
625 r = sd_bus_get_unique_name(b, &sender_id);
626 if (r < 0)
627 return r;
628 }
629
630 if (!external_id) {
631 xsprintf(external_buf, "%"PRIu64, ++b->cookie);
632 external_id = external_buf;
633 }
634
635 sender_label = bus_label_escape(sender_id);
636 if (!sender_label)
637 return -ENOMEM;
638
639 external_label = bus_label_escape(external_id);
640 if (!external_label)
641 return -ENOMEM;
642
643 p = path_join(prefix, sender_label, external_label);
644 if (!p)
645 return -ENOMEM;
646
647 *ret_path = p;
648 return 0;
649}
650
651/**
652 * bus_path_decode_unique() - decode unique object path
653 * @path: object path to decode
654 * @prefix: object path prefix
655 * @ret_sender: output parameter for sender-id label
656 * @ret_external: output parameter for external-id label
657 *
658 * This does the reverse of bus_path_encode_unique() (see its description for
659 * details). Both trailing labels, sender-id and external-id, are unescaped and
660 * returned in the given output parameters (the caller must free them).
661 *
662 * Note that this function returns 0 if the path does not match the template
663 * (see bus_path_encode_unique()), 1 if it matched.
664 *
665 * Returns: Negative error code on failure, 0 if the given object path does not
666 * match the template (return parameters are set to NULL), 1 if it was
667 * parsed successfully (return parameters contain allocated labels).
668 */
669int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external) {
670 const char *p, *q;
671 char *sender, *external;
672
673 assert(sd_bus_object_path_is_valid(path));
674 assert(sd_bus_object_path_is_valid(prefix));
675 assert(ret_sender);
676 assert(ret_external);
677
678 p = object_path_startswith(path, prefix);
679 if (!p) {
680 *ret_sender = NULL;
681 *ret_external = NULL;
682 return 0;
683 }
684
685 q = strchr(p, '/');
686 if (!q) {
687 *ret_sender = NULL;
688 *ret_external = NULL;
689 return 0;
690 }
691
692 sender = bus_label_unescape_n(p, q - p);
693 external = bus_label_unescape(q + 1);
694 if (!sender || !external) {
695 free(sender);
696 free(external);
697 return -ENOMEM;
698 }
699
700 *ret_sender = sender;
701 *ret_external = external;
702 return 1;
703}
704
705int bus_track_add_name_many(sd_bus_track *t, char * const *l) {
706 int r = 0;
707
708 assert(t);
709
710 /* Continues adding after failure, and returns the first failure. */
711
712 STRV_FOREACH(i, l)
713 RET_GATHER(r, sd_bus_track_add_name(t, *i));
714 return r;
715}
716
717int bus_track_to_strv(sd_bus_track *t, char ***ret) {
718 _cleanup_strv_free_ char **subscribed = NULL;
719 int r;
720
721 assert(ret);
722
723 for (const char *n = sd_bus_track_first(t); n; n = sd_bus_track_next(t)) {
724 int c = sd_bus_track_count_name(t, n);
725 assert(c >= 0);
726
727 for (int j = 0; j < c; j++) {
728 r = strv_extend(&subscribed, n);
729 if (r < 0)
730 return r;
731 }
732 }
733
734 *ret = TAKE_PTR(subscribed);
735 return 0;
736}
737
738int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *description) {
739 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
740 const char *e;
741 int r;
742
743 assert(ret);
744
745 /* Match like sd_bus_open_system(), but with the "watch_bind" feature and the Connected() signal
746 * turned on. */
747
748 r = sd_bus_new(&bus);
749 if (r < 0)
750 return r;
751
752 if (description) {
753 r = sd_bus_set_description(bus, description);
754 if (r < 0)
755 return r;
756 }
757
758 e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
759 if (!e)
760 e = DEFAULT_SYSTEM_BUS_ADDRESS;
761
762 r = sd_bus_set_address(bus, e);
763 if (r < 0)
764 return r;
765
766 r = sd_bus_set_bus_client(bus, true);
767 if (r < 0)
768 return r;
769
770 r = sd_bus_negotiate_creds(bus, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS);
771 if (r < 0)
772 return r;
773
774 r = sd_bus_set_watch_bind(bus, true);
775 if (r < 0)
776 return r;
777
778 r = sd_bus_set_connected_signal(bus, true);
779 if (r < 0)
780 return r;
781
782 r = sd_bus_start(bus);
783 if (r < 0)
784 return r;
785
786 *ret = TAKE_PTR(bus);
787
788 return 0;
789}
790
791int bus_reply_pair_array(sd_bus_message *m, char * const *l) {
792 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
793 int r;
794
795 assert(m);
796
797 /* Reply to the specified message with a message containing a dictionary put together from the
798 * specified strv */
799
800 r = sd_bus_message_new_method_return(m, &reply);
801 if (r < 0)
802 return r;
803
804 r = sd_bus_message_open_container(reply, 'a', "{ss}");
805 if (r < 0)
806 return r;
807
808 STRV_FOREACH_PAIR(k, v, l) {
809 r = sd_bus_message_append(reply, "{ss}", *k, *v);
810 if (r < 0)
811 return r;
812 }
813
814 r = sd_bus_message_close_container(reply);
815 if (r < 0)
816 return r;
817
818 return sd_bus_message_send(reply);
819}
820
821static int method_dump_memory_state_by_fd(sd_bus_message *message, void *userdata, sd_bus_error *reterr_error) {
822 _cleanup_(memstream_done) MemStream m = {};
823 _cleanup_free_ char *dump = NULL;
824 _cleanup_close_ int fd = -EBADF;
825 size_t dump_size;
826 FILE *f;
827 int r;
828
829 assert(message);
830
831 f = memstream_init(&m);
832 if (!f)
833 return -ENOMEM;
834
835 r = RET_NERRNO(malloc_info(/* options= */ 0, f));
836 if (r < 0)
837 return r;
838
839 r = memstream_finalize(&m, &dump, &dump_size);
840 if (r < 0)
841 return r;
842
843 fd = memfd_new_and_seal("malloc-info", dump, dump_size);
844 if (fd < 0)
845 return fd;
846
847 r = sd_bus_reply_method_return(message, "h", fd);
848 if (r < 0)
849 return r;
850
851 return 1; /* Stop further processing */
852}
853
854/* The default install callback will fail and disconnect the bus if it cannot register the match, but this
855 * is only a debug method, we definitely don't want to fail in case there's some permission issue. */
856static int dummy_install_callback(sd_bus_message *message, void *userdata, sd_bus_error *reterr_error) {
857 return 1;
858}
859
860int bus_register_malloc_status(sd_bus *bus, const char *destination) {
861 const char *match;
862 int r;
863
864 assert(bus);
865 assert(!isempty(destination));
866
867 match = strjoina("type='method_call',"
868 "interface='org.freedesktop.MemoryAllocation1',"
869 "path='/org/freedesktop/MemoryAllocation1',"
870 "destination='", destination, "',",
871 "member='GetMallocInfo'");
872
873 r = sd_bus_add_match_async(bus, NULL, match, method_dump_memory_state_by_fd, dummy_install_callback, NULL);
874 if (r < 0)
875 return log_debug_errno(r, "Failed to subscribe to GetMallocInfo() calls on MemoryAllocation1 interface: %m");
876
877 return 0;
878}
879
880int bus_creds_get_pidref(
881 sd_bus_creds *c,
882 PidRef *ret) {
883
884 int pidfd = -EBADF;
885 pid_t pid;
886 int r;
887
888 assert(c);
889 assert(ret);
890
891 r = sd_bus_creds_get_pid(c, &pid);
892 if (r < 0)
893 return r;
894
895 r = sd_bus_creds_get_pidfd_dup(c, &pidfd);
896 if (r < 0 && r != -ENODATA)
897 return r;
898
899 *ret = (PidRef) {
900 .pid = pid,
901 .fd = pidfd,
902 };
903
904 return 0;
905}
906
907int bus_query_sender_pidref(
908 sd_bus_message *m,
909 PidRef *ret) {
910
911 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
912 int r;
913
914 assert(m);
915 assert(ret);
916
917 r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_PID|SD_BUS_CREDS_PIDFD, &creds);
918 if (r < 0)
919 return r;
920
921 return bus_creds_get_pidref(creds, ret);
922}
923
924int bus_get_instance_id(sd_bus *bus, sd_id128_t *ret) {
925 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
926 int r;
927
928 assert(bus);
929 assert(ret);
930
931 r = sd_bus_call_method(bus,
932 "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "GetId",
933 /* reterr_error = */ NULL, &reply, NULL);
934 if (r < 0)
935 return r;
936
937 const char *id;
938
939 r = sd_bus_message_read_basic(reply, 's', &id);
940 if (r < 0)
941 return r;
942
943 return sd_id128_from_string(id, ret);
944}
945
946static const char* const bus_transport_table[] = {
947 [BUS_TRANSPORT_LOCAL] = "local",
948 [BUS_TRANSPORT_REMOTE] = "remote",
949 [BUS_TRANSPORT_MACHINE] = "machine",
950 [BUS_TRANSPORT_CAPSULE] = "capsule",
951};
952
953DEFINE_STRING_TABLE_LOOKUP_TO_STRING(bus_transport, BusTransport);