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