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