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