]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-control.c
Merge pull request #8575 from keszybz/non-absolute-paths
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-control.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2013 Lennart Poettering
6 ***/
7
8 #if HAVE_VALGRIND_MEMCHECK_H
9 #include <valgrind/memcheck.h>
10 #endif
11
12 #include <errno.h>
13 #include <stddef.h>
14
15 #include "sd-bus.h"
16
17 #include "alloc-util.h"
18 #include "bus-control.h"
19 #include "bus-internal.h"
20 #include "bus-message.h"
21 #include "bus-util.h"
22 #include "capability-util.h"
23 #include "process-util.h"
24 #include "stdio-util.h"
25 #include "string-util.h"
26 #include "strv.h"
27 #include "user-util.h"
28
29 _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
30 int r;
31
32 assert_return(bus, -EINVAL);
33 assert_return(bus = bus_resolve(bus), -ENOPKG);
34 assert_return(unique, -EINVAL);
35 assert_return(!bus_pid_changed(bus), -ECHILD);
36
37 if (!bus->bus_client)
38 return -EINVAL;
39
40 r = bus_ensure_running(bus);
41 if (r < 0)
42 return r;
43
44 *unique = bus->unique_name;
45 return 0;
46 }
47
48 static int validate_request_name_parameters(
49 sd_bus *bus,
50 const char *name,
51 uint64_t flags,
52 uint32_t *ret_param) {
53
54 uint32_t param = 0;
55
56 assert(bus);
57 assert(name);
58 assert(ret_param);
59
60 assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
61 assert_return(service_name_is_valid(name), -EINVAL);
62 assert_return(name[0] != ':', -EINVAL);
63
64 if (!bus->bus_client)
65 return -EINVAL;
66
67 /* Don't allow requesting the special driver and local names */
68 if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
69 return -EINVAL;
70
71 if (!BUS_IS_OPEN(bus->state))
72 return -ENOTCONN;
73
74 if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
75 param |= BUS_NAME_ALLOW_REPLACEMENT;
76 if (flags & SD_BUS_NAME_REPLACE_EXISTING)
77 param |= BUS_NAME_REPLACE_EXISTING;
78 if (!(flags & SD_BUS_NAME_QUEUE))
79 param |= BUS_NAME_DO_NOT_QUEUE;
80
81 *ret_param = param;
82
83 return 0;
84 }
85
86 _public_ int sd_bus_request_name(
87 sd_bus *bus,
88 const char *name,
89 uint64_t flags) {
90
91 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
92 uint32_t ret, param = 0;
93 int r;
94
95 assert_return(bus, -EINVAL);
96 assert_return(bus = bus_resolve(bus), -ENOPKG);
97 assert_return(name, -EINVAL);
98 assert_return(!bus_pid_changed(bus), -ECHILD);
99
100 r = validate_request_name_parameters(bus, name, flags, &param);
101 if (r < 0)
102 return r;
103
104 r = sd_bus_call_method(
105 bus,
106 "org.freedesktop.DBus",
107 "/org/freedesktop/DBus",
108 "org.freedesktop.DBus",
109 "RequestName",
110 NULL,
111 &reply,
112 "su",
113 name,
114 param);
115 if (r < 0)
116 return r;
117
118 r = sd_bus_message_read(reply, "u", &ret);
119 if (r < 0)
120 return r;
121
122 switch (ret) {
123
124 case BUS_NAME_ALREADY_OWNER:
125 return -EALREADY;
126
127 case BUS_NAME_EXISTS:
128 return -EEXIST;
129
130 case BUS_NAME_IN_QUEUE:
131 return 0;
132
133 case BUS_NAME_PRIMARY_OWNER:
134 return 1;
135 }
136
137 return -EIO;
138 }
139
140 static int default_request_name_handler(
141 sd_bus_message *m,
142 void *userdata,
143 sd_bus_error *ret_error) {
144
145 uint32_t ret;
146 int r;
147
148 assert(m);
149
150 if (sd_bus_message_is_method_error(m, NULL)) {
151 log_debug_errno(sd_bus_message_get_errno(m),
152 "Unable to request name, failing connection: %s",
153 sd_bus_message_get_error(m)->message);
154
155 bus_enter_closing(sd_bus_message_get_bus(m));
156 return 1;
157 }
158
159 r = sd_bus_message_read(m, "u", &ret);
160 if (r < 0)
161 return r;
162
163 switch (ret) {
164
165 case BUS_NAME_ALREADY_OWNER:
166 log_debug("Already owner of requested service name, ignoring.");
167 return 1;
168
169 case BUS_NAME_IN_QUEUE:
170 log_debug("In queue for requested service name.");
171 return 1;
172
173 case BUS_NAME_PRIMARY_OWNER:
174 log_debug("Successfully acquired requested service name.");
175 return 1;
176
177 case BUS_NAME_EXISTS:
178 log_debug("Requested service name already owned, failing connection.");
179 bus_enter_closing(sd_bus_message_get_bus(m));
180 return 1;
181 }
182
183 log_debug("Unexpected response from RequestName(), failing connection.");
184 bus_enter_closing(sd_bus_message_get_bus(m));
185 return 1;
186 }
187
188 _public_ int sd_bus_request_name_async(
189 sd_bus *bus,
190 sd_bus_slot **ret_slot,
191 const char *name,
192 uint64_t flags,
193 sd_bus_message_handler_t callback,
194 void *userdata) {
195
196 uint32_t param = 0;
197 int r;
198
199 assert_return(bus, -EINVAL);
200 assert_return(bus = bus_resolve(bus), -ENOPKG);
201 assert_return(name, -EINVAL);
202 assert_return(!bus_pid_changed(bus), -ECHILD);
203
204 r = validate_request_name_parameters(bus, name, flags, &param);
205 if (r < 0)
206 return r;
207
208 return sd_bus_call_method_async(
209 bus,
210 ret_slot,
211 "org.freedesktop.DBus",
212 "/org/freedesktop/DBus",
213 "org.freedesktop.DBus",
214 "RequestName",
215 callback ?: default_request_name_handler,
216 userdata,
217 "su",
218 name,
219 param);
220 }
221
222 static int validate_release_name_parameters(
223 sd_bus *bus,
224 const char *name) {
225
226 assert(bus);
227 assert(name);
228
229 assert_return(service_name_is_valid(name), -EINVAL);
230 assert_return(name[0] != ':', -EINVAL);
231
232 if (!bus->bus_client)
233 return -EINVAL;
234
235 /* Don't allow releasing the special driver and local names */
236 if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
237 return -EINVAL;
238
239 if (!BUS_IS_OPEN(bus->state))
240 return -ENOTCONN;
241
242 return 0;
243 }
244
245 _public_ int sd_bus_release_name(
246 sd_bus *bus,
247 const char *name) {
248
249 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
250 uint32_t ret;
251 int r;
252
253 assert_return(bus, -EINVAL);
254 assert_return(bus = bus_resolve(bus), -ENOPKG);
255 assert_return(name, -EINVAL);
256 assert_return(!bus_pid_changed(bus), -ECHILD);
257
258 r = validate_release_name_parameters(bus, name);
259 if (r < 0)
260 return r;
261
262 r = sd_bus_call_method(
263 bus,
264 "org.freedesktop.DBus",
265 "/org/freedesktop/DBus",
266 "org.freedesktop.DBus",
267 "ReleaseName",
268 NULL,
269 &reply,
270 "s",
271 name);
272 if (r < 0)
273 return r;
274
275 r = sd_bus_message_read(reply, "u", &ret);
276 if (r < 0)
277 return r;
278
279 switch (ret) {
280
281 case BUS_NAME_NON_EXISTENT:
282 return -ESRCH;
283
284 case BUS_NAME_NOT_OWNER:
285 return -EADDRINUSE;
286
287 case BUS_NAME_RELEASED:
288 return 0;
289 }
290
291 return -EIO;
292 }
293
294 static int default_release_name_handler(
295 sd_bus_message *m,
296 void *userdata,
297 sd_bus_error *ret_error) {
298
299 uint32_t ret;
300 int r;
301
302 assert(m);
303
304 if (sd_bus_message_is_method_error(m, NULL)) {
305 log_debug_errno(sd_bus_message_get_errno(m),
306 "Unable to release name, failing connection: %s",
307 sd_bus_message_get_error(m)->message);
308
309 bus_enter_closing(sd_bus_message_get_bus(m));
310 return 1;
311 }
312
313 r = sd_bus_message_read(m, "u", &ret);
314 if (r < 0)
315 return r;
316
317 switch (ret) {
318
319 case BUS_NAME_NON_EXISTENT:
320 log_debug("Name asked to release is not taken currently, ignoring.");
321 return 1;
322
323 case BUS_NAME_NOT_OWNER:
324 log_debug("Name asked to release is owned by somebody else, ignoring.");
325 return 1;
326
327 case BUS_NAME_RELEASED:
328 log_debug("Name successfully released.");
329 return 1;
330 }
331
332 log_debug("Unexpected response from ReleaseName(), failing connection.");
333 bus_enter_closing(sd_bus_message_get_bus(m));
334 return 1;
335 }
336
337 _public_ int sd_bus_release_name_async(
338 sd_bus *bus,
339 sd_bus_slot **ret_slot,
340 const char *name,
341 sd_bus_message_handler_t callback,
342 void *userdata) {
343
344 int r;
345
346 assert_return(bus, -EINVAL);
347 assert_return(bus = bus_resolve(bus), -ENOPKG);
348 assert_return(name, -EINVAL);
349 assert_return(!bus_pid_changed(bus), -ECHILD);
350
351 r = validate_release_name_parameters(bus, name);
352 if (r < 0)
353 return r;
354
355 return sd_bus_call_method_async(
356 bus,
357 ret_slot,
358 "org.freedesktop.DBus",
359 "/org/freedesktop/DBus",
360 "org.freedesktop.DBus",
361 "ReleaseName",
362 callback ?: default_release_name_handler,
363 userdata,
364 "s",
365 name);
366 }
367
368 _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
369 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
370 _cleanup_strv_free_ char **x = NULL, **y = NULL;
371 int r;
372
373 assert_return(bus, -EINVAL);
374 assert_return(bus = bus_resolve(bus), -ENOPKG);
375 assert_return(acquired || activatable, -EINVAL);
376 assert_return(!bus_pid_changed(bus), -ECHILD);
377
378 if (!bus->bus_client)
379 return -EINVAL;
380
381 if (!BUS_IS_OPEN(bus->state))
382 return -ENOTCONN;
383
384 if (acquired) {
385 r = sd_bus_call_method(
386 bus,
387 "org.freedesktop.DBus",
388 "/org/freedesktop/DBus",
389 "org.freedesktop.DBus",
390 "ListNames",
391 NULL,
392 &reply,
393 NULL);
394 if (r < 0)
395 return r;
396
397 r = sd_bus_message_read_strv(reply, &x);
398 if (r < 0)
399 return r;
400
401 reply = sd_bus_message_unref(reply);
402 }
403
404 if (activatable) {
405 r = sd_bus_call_method(
406 bus,
407 "org.freedesktop.DBus",
408 "/org/freedesktop/DBus",
409 "org.freedesktop.DBus",
410 "ListActivatableNames",
411 NULL,
412 &reply,
413 NULL);
414 if (r < 0)
415 return r;
416
417 r = sd_bus_message_read_strv(reply, &y);
418 if (r < 0)
419 return r;
420
421 *activatable = TAKE_PTR(y);
422 }
423
424 if (acquired)
425 *acquired = TAKE_PTR(x);
426
427 return 0;
428 }
429
430 _public_ int sd_bus_get_name_creds(
431 sd_bus *bus,
432 const char *name,
433 uint64_t mask,
434 sd_bus_creds **creds) {
435
436 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_unique = NULL, *reply = NULL;
437 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
438 const char *unique = NULL;
439 pid_t pid = 0;
440 int r;
441
442 assert_return(bus, -EINVAL);
443 assert_return(bus = bus_resolve(bus), -ENOPKG);
444 assert_return(name, -EINVAL);
445 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
446 assert_return(mask == 0 || creds, -EINVAL);
447 assert_return(!bus_pid_changed(bus), -ECHILD);
448 assert_return(service_name_is_valid(name), -EINVAL);
449
450 if (!bus->bus_client)
451 return -EINVAL;
452
453 /* Turn off augmenting if this isn't a local connection. If the connection is not local, then /proc is not
454 * going to match. */
455 if (!bus->is_local)
456 mask &= ~SD_BUS_CREDS_AUGMENT;
457
458 if (streq(name, "org.freedesktop.DBus.Local"))
459 return -EINVAL;
460
461 if (streq(name, "org.freedesktop.DBus"))
462 return sd_bus_get_owner_creds(bus, mask, creds);
463
464 if (!BUS_IS_OPEN(bus->state))
465 return -ENOTCONN;
466
467 /* Only query the owner if the caller wants to know it or if
468 * the caller just wants to check whether a name exists */
469 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
470 r = sd_bus_call_method(
471 bus,
472 "org.freedesktop.DBus",
473 "/org/freedesktop/DBus",
474 "org.freedesktop.DBus",
475 "GetNameOwner",
476 NULL,
477 &reply_unique,
478 "s",
479 name);
480 if (r < 0)
481 return r;
482
483 r = sd_bus_message_read(reply_unique, "s", &unique);
484 if (r < 0)
485 return r;
486 }
487
488 if (mask != 0) {
489 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
490 bool need_pid, need_uid, need_selinux, need_separate_calls;
491 c = bus_creds_new();
492 if (!c)
493 return -ENOMEM;
494
495 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
496 c->unique_name = strdup(unique);
497 if (!c->unique_name)
498 return -ENOMEM;
499
500 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
501 }
502
503 need_pid = (mask & SD_BUS_CREDS_PID) ||
504 ((mask & SD_BUS_CREDS_AUGMENT) &&
505 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
506 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
507 SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
508 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
509 SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
510 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
511 SD_BUS_CREDS_SELINUX_CONTEXT|
512 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)));
513 need_uid = mask & SD_BUS_CREDS_EUID;
514 need_selinux = mask & SD_BUS_CREDS_SELINUX_CONTEXT;
515
516 if (need_pid + need_uid + need_selinux > 1) {
517
518 /* If we need more than one of the credentials, then use GetConnectionCredentials() */
519
520 r = sd_bus_call_method(
521 bus,
522 "org.freedesktop.DBus",
523 "/org/freedesktop/DBus",
524 "org.freedesktop.DBus",
525 "GetConnectionCredentials",
526 &error,
527 &reply,
528 "s",
529 unique ?: name);
530
531 if (r < 0) {
532
533 if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
534 return r;
535
536 /* If we got an unknown method error, fall back to the invidual calls... */
537 need_separate_calls = true;
538 sd_bus_error_free(&error);
539
540 } else {
541 need_separate_calls = false;
542
543 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
544 if (r < 0)
545 return r;
546
547 for (;;) {
548 const char *m;
549
550 r = sd_bus_message_enter_container(reply, 'e', "sv");
551 if (r < 0)
552 return r;
553 if (r == 0)
554 break;
555
556 r = sd_bus_message_read(reply, "s", &m);
557 if (r < 0)
558 return r;
559
560 if (need_uid && streq(m, "UnixUserID")) {
561 uint32_t u;
562
563 r = sd_bus_message_read(reply, "v", "u", &u);
564 if (r < 0)
565 return r;
566
567 c->euid = u;
568 c->mask |= SD_BUS_CREDS_EUID;
569
570 } else if (need_pid && streq(m, "ProcessID")) {
571 uint32_t p;
572
573 r = sd_bus_message_read(reply, "v", "u", &p);
574 if (r < 0)
575 return r;
576
577 pid = p;
578 if (mask & SD_BUS_CREDS_PID) {
579 c->pid = p;
580 c->mask |= SD_BUS_CREDS_PID;
581 }
582
583 } else if (need_selinux && streq(m, "LinuxSecurityLabel")) {
584 const void *p = NULL;
585 size_t sz = 0;
586
587 r = sd_bus_message_enter_container(reply, 'v', "ay");
588 if (r < 0)
589 return r;
590
591 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
592 if (r < 0)
593 return r;
594
595 free(c->label);
596 c->label = strndup(p, sz);
597 if (!c->label)
598 return -ENOMEM;
599
600 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
601
602 r = sd_bus_message_exit_container(reply);
603 if (r < 0)
604 return r;
605 } else {
606 r = sd_bus_message_skip(reply, "v");
607 if (r < 0)
608 return r;
609 }
610
611 r = sd_bus_message_exit_container(reply);
612 if (r < 0)
613 return r;
614 }
615
616 r = sd_bus_message_exit_container(reply);
617 if (r < 0)
618 return r;
619
620 if (need_pid && pid == 0)
621 return -EPROTO;
622 }
623
624 } else /* When we only need a single field, then let's use separate calls */
625 need_separate_calls = true;
626
627 if (need_separate_calls) {
628 if (need_pid) {
629 uint32_t u;
630
631 r = sd_bus_call_method(
632 bus,
633 "org.freedesktop.DBus",
634 "/org/freedesktop/DBus",
635 "org.freedesktop.DBus",
636 "GetConnectionUnixProcessID",
637 NULL,
638 &reply,
639 "s",
640 unique ?: name);
641 if (r < 0)
642 return r;
643
644 r = sd_bus_message_read(reply, "u", &u);
645 if (r < 0)
646 return r;
647
648 pid = u;
649 if (mask & SD_BUS_CREDS_PID) {
650 c->pid = u;
651 c->mask |= SD_BUS_CREDS_PID;
652 }
653
654 reply = sd_bus_message_unref(reply);
655 }
656
657 if (need_uid) {
658 uint32_t u;
659
660 r = sd_bus_call_method(
661 bus,
662 "org.freedesktop.DBus",
663 "/org/freedesktop/DBus",
664 "org.freedesktop.DBus",
665 "GetConnectionUnixUser",
666 NULL,
667 &reply,
668 "s",
669 unique ? unique : name);
670 if (r < 0)
671 return r;
672
673 r = sd_bus_message_read(reply, "u", &u);
674 if (r < 0)
675 return r;
676
677 c->euid = u;
678 c->mask |= SD_BUS_CREDS_EUID;
679
680 reply = sd_bus_message_unref(reply);
681 }
682
683 if (need_selinux) {
684 const void *p = NULL;
685 size_t sz = 0;
686
687 r = sd_bus_call_method(
688 bus,
689 "org.freedesktop.DBus",
690 "/org/freedesktop/DBus",
691 "org.freedesktop.DBus",
692 "GetConnectionSELinuxSecurityContext",
693 &error,
694 &reply,
695 "s",
696 unique ? unique : name);
697 if (r < 0) {
698 if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
699 return r;
700
701 /* no data is fine */
702 } else {
703 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
704 if (r < 0)
705 return r;
706
707 c->label = strndup(p, sz);
708 if (!c->label)
709 return -ENOMEM;
710
711 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
712 }
713 }
714 }
715
716 r = bus_creds_add_more(c, mask, pid, 0);
717 if (r < 0)
718 return r;
719 }
720
721 if (creds)
722 *creds = TAKE_PTR(c);
723
724 return 0;
725 }
726
727 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
728 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
729 bool do_label, do_groups;
730 pid_t pid = 0;
731 int r;
732
733 assert_return(bus, -EINVAL);
734 assert_return(bus = bus_resolve(bus), -ENOPKG);
735 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
736 assert_return(ret, -EINVAL);
737 assert_return(!bus_pid_changed(bus), -ECHILD);
738
739 if (!BUS_IS_OPEN(bus->state))
740 return -ENOTCONN;
741
742 if (!bus->is_local)
743 mask &= ~SD_BUS_CREDS_AUGMENT;
744
745 do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
746 do_groups = bus->n_groups != (size_t) -1 && (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS);
747
748 /* Avoid allocating anything if we have no chance of returning useful data */
749 if (!bus->ucred_valid && !do_label && !do_groups)
750 return -ENODATA;
751
752 c = bus_creds_new();
753 if (!c)
754 return -ENOMEM;
755
756 if (bus->ucred_valid) {
757 if (pid_is_valid(bus->ucred.pid)) {
758 pid = c->pid = bus->ucred.pid;
759 c->mask |= SD_BUS_CREDS_PID & mask;
760 }
761
762 if (uid_is_valid(bus->ucred.uid)) {
763 c->euid = bus->ucred.uid;
764 c->mask |= SD_BUS_CREDS_EUID & mask;
765 }
766
767 if (gid_is_valid(bus->ucred.gid)) {
768 c->egid = bus->ucred.gid;
769 c->mask |= SD_BUS_CREDS_EGID & mask;
770 }
771 }
772
773 if (do_label) {
774 c->label = strdup(bus->label);
775 if (!c->label)
776 return -ENOMEM;
777
778 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
779 }
780
781 if (do_groups) {
782 c->supplementary_gids = newdup(gid_t, bus->groups, bus->n_groups);
783 if (!c->supplementary_gids)
784 return -ENOMEM;
785
786 c->n_supplementary_gids = bus->n_groups;
787
788 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
789 }
790
791 r = bus_creds_add_more(c, mask, pid, 0);
792 if (r < 0)
793 return r;
794
795 *ret = TAKE_PTR(c);
796
797 return 0;
798 }
799
800 #define append_eavesdrop(bus, m) \
801 ((bus)->is_monitor \
802 ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
803 : (m))
804
805 int bus_add_match_internal(
806 sd_bus *bus,
807 const char *match) {
808
809 const char *e;
810
811 assert(bus);
812
813 if (!bus->bus_client)
814 return -EINVAL;
815
816 e = append_eavesdrop(bus, match);
817
818 return sd_bus_call_method(
819 bus,
820 "org.freedesktop.DBus",
821 "/org/freedesktop/DBus",
822 "org.freedesktop.DBus",
823 "AddMatch",
824 NULL,
825 NULL,
826 "s",
827 e);
828 }
829 int bus_add_match_internal_async(
830 sd_bus *bus,
831 sd_bus_slot **ret_slot,
832 const char *match,
833 sd_bus_message_handler_t callback,
834 void *userdata) {
835
836 const char *e;
837
838 assert(bus);
839
840 if (!bus->bus_client)
841 return -EINVAL;
842
843 e = append_eavesdrop(bus, match);
844
845 return sd_bus_call_method_async(
846 bus,
847 ret_slot,
848 "org.freedesktop.DBus",
849 "/org/freedesktop/DBus",
850 "org.freedesktop.DBus",
851 "AddMatch",
852 callback,
853 userdata,
854 "s",
855 e);
856 }
857
858 int bus_remove_match_internal(
859 sd_bus *bus,
860 const char *match) {
861
862 const char *e;
863
864 assert(bus);
865 assert(match);
866
867 if (!bus->bus_client)
868 return -EINVAL;
869
870 e = append_eavesdrop(bus, match);
871
872 /* Fire and forget */
873
874 return sd_bus_call_method_async(
875 bus,
876 NULL,
877 "org.freedesktop.DBus",
878 "/org/freedesktop/DBus",
879 "org.freedesktop.DBus",
880 "RemoveMatch",
881 NULL,
882 NULL,
883 "s",
884 e);
885 }
886
887 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
888 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
889 const char *mid;
890 int r;
891
892 assert_return(bus, -EINVAL);
893 assert_return(bus = bus_resolve(bus), -ENOPKG);
894 assert_return(name, -EINVAL);
895 assert_return(machine, -EINVAL);
896 assert_return(!bus_pid_changed(bus), -ECHILD);
897 assert_return(service_name_is_valid(name), -EINVAL);
898
899 if (!bus->bus_client)
900 return -EINVAL;
901
902 if (!BUS_IS_OPEN(bus->state))
903 return -ENOTCONN;
904
905 if (streq_ptr(name, bus->unique_name))
906 return sd_id128_get_machine(machine);
907
908 r = sd_bus_message_new_method_call(
909 bus,
910 &m,
911 name,
912 "/",
913 "org.freedesktop.DBus.Peer",
914 "GetMachineId");
915 if (r < 0)
916 return r;
917
918 r = sd_bus_message_set_auto_start(m, false);
919 if (r < 0)
920 return r;
921
922 r = sd_bus_call(bus, m, 0, NULL, &reply);
923 if (r < 0)
924 return r;
925
926 r = sd_bus_message_read(reply, "s", &mid);
927 if (r < 0)
928 return r;
929
930 return sd_id128_from_string(mid, machine);
931 }