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