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