]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-control.c
network: fix typo in log message
[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 = y;
435 y = NULL;
436 }
437
438 if (acquired) {
439 *acquired = x;
440 x = NULL;
441 }
442
443 return 0;
444 }
445
446 _public_ int sd_bus_get_name_creds(
447 sd_bus *bus,
448 const char *name,
449 uint64_t mask,
450 sd_bus_creds **creds) {
451
452 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_unique = NULL, *reply = NULL;
453 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
454 const char *unique = NULL;
455 pid_t pid = 0;
456 int r;
457
458 assert_return(bus, -EINVAL);
459 assert_return(bus = bus_resolve(bus), -ENOPKG);
460 assert_return(name, -EINVAL);
461 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
462 assert_return(mask == 0 || creds, -EINVAL);
463 assert_return(!bus_pid_changed(bus), -ECHILD);
464 assert_return(service_name_is_valid(name), -EINVAL);
465
466 if (!bus->bus_client)
467 return -EINVAL;
468
469 /* Turn off augmenting if this isn't a local connection. If the connection is not local, then /proc is not
470 * going to match. */
471 if (!bus->is_local)
472 mask &= ~SD_BUS_CREDS_AUGMENT;
473
474 if (streq(name, "org.freedesktop.DBus.Local"))
475 return -EINVAL;
476
477 if (streq(name, "org.freedesktop.DBus"))
478 return sd_bus_get_owner_creds(bus, mask, creds);
479
480 if (!BUS_IS_OPEN(bus->state))
481 return -ENOTCONN;
482
483 /* Only query the owner if the caller wants to know it or if
484 * the caller just wants to check whether a name exists */
485 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
486 r = sd_bus_call_method(
487 bus,
488 "org.freedesktop.DBus",
489 "/org/freedesktop/DBus",
490 "org.freedesktop.DBus",
491 "GetNameOwner",
492 NULL,
493 &reply_unique,
494 "s",
495 name);
496 if (r < 0)
497 return r;
498
499 r = sd_bus_message_read(reply_unique, "s", &unique);
500 if (r < 0)
501 return r;
502 }
503
504 if (mask != 0) {
505 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
506 bool need_pid, need_uid, need_selinux, need_separate_calls;
507 c = bus_creds_new();
508 if (!c)
509 return -ENOMEM;
510
511 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
512 c->unique_name = strdup(unique);
513 if (!c->unique_name)
514 return -ENOMEM;
515
516 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
517 }
518
519 need_pid = (mask & SD_BUS_CREDS_PID) ||
520 ((mask & SD_BUS_CREDS_AUGMENT) &&
521 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
522 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
523 SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
524 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
525 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|
526 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
527 SD_BUS_CREDS_SELINUX_CONTEXT|
528 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)));
529 need_uid = mask & SD_BUS_CREDS_EUID;
530 need_selinux = mask & SD_BUS_CREDS_SELINUX_CONTEXT;
531
532 if (need_pid + need_uid + need_selinux > 1) {
533
534 /* If we need more than one of the credentials, then use GetConnectionCredentials() */
535
536 r = sd_bus_call_method(
537 bus,
538 "org.freedesktop.DBus",
539 "/org/freedesktop/DBus",
540 "org.freedesktop.DBus",
541 "GetConnectionCredentials",
542 &error,
543 &reply,
544 "s",
545 unique ?: name);
546
547 if (r < 0) {
548
549 if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
550 return r;
551
552 /* If we got an unknown method error, fall back to the invidual calls... */
553 need_separate_calls = true;
554 sd_bus_error_free(&error);
555
556 } else {
557 need_separate_calls = false;
558
559 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
560 if (r < 0)
561 return r;
562
563 for (;;) {
564 const char *m;
565
566 r = sd_bus_message_enter_container(reply, 'e', "sv");
567 if (r < 0)
568 return r;
569 if (r == 0)
570 break;
571
572 r = sd_bus_message_read(reply, "s", &m);
573 if (r < 0)
574 return r;
575
576 if (need_uid && streq(m, "UnixUserID")) {
577 uint32_t u;
578
579 r = sd_bus_message_read(reply, "v", "u", &u);
580 if (r < 0)
581 return r;
582
583 c->euid = u;
584 c->mask |= SD_BUS_CREDS_EUID;
585
586 } else if (need_pid && streq(m, "ProcessID")) {
587 uint32_t p;
588
589 r = sd_bus_message_read(reply, "v", "u", &p);
590 if (r < 0)
591 return r;
592
593 pid = p;
594 if (mask & SD_BUS_CREDS_PID) {
595 c->pid = p;
596 c->mask |= SD_BUS_CREDS_PID;
597 }
598
599 } else if (need_selinux && streq(m, "LinuxSecurityLabel")) {
600 const void *p = NULL;
601 size_t sz = 0;
602
603 r = sd_bus_message_enter_container(reply, 'v', "ay");
604 if (r < 0)
605 return r;
606
607 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
608 if (r < 0)
609 return r;
610
611 free(c->label);
612 c->label = strndup(p, sz);
613 if (!c->label)
614 return -ENOMEM;
615
616 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
617
618 r = sd_bus_message_exit_container(reply);
619 if (r < 0)
620 return r;
621 } else {
622 r = sd_bus_message_skip(reply, "v");
623 if (r < 0)
624 return r;
625 }
626
627 r = sd_bus_message_exit_container(reply);
628 if (r < 0)
629 return r;
630 }
631
632 r = sd_bus_message_exit_container(reply);
633 if (r < 0)
634 return r;
635
636 if (need_pid && pid == 0)
637 return -EPROTO;
638 }
639
640 } else /* When we only need a single field, then let's use separate calls */
641 need_separate_calls = true;
642
643 if (need_separate_calls) {
644 if (need_pid) {
645 uint32_t u;
646
647 r = sd_bus_call_method(
648 bus,
649 "org.freedesktop.DBus",
650 "/org/freedesktop/DBus",
651 "org.freedesktop.DBus",
652 "GetConnectionUnixProcessID",
653 NULL,
654 &reply,
655 "s",
656 unique ?: name);
657 if (r < 0)
658 return r;
659
660 r = sd_bus_message_read(reply, "u", &u);
661 if (r < 0)
662 return r;
663
664 pid = u;
665 if (mask & SD_BUS_CREDS_PID) {
666 c->pid = u;
667 c->mask |= SD_BUS_CREDS_PID;
668 }
669
670 reply = sd_bus_message_unref(reply);
671 }
672
673 if (need_uid) {
674 uint32_t u;
675
676 r = sd_bus_call_method(
677 bus,
678 "org.freedesktop.DBus",
679 "/org/freedesktop/DBus",
680 "org.freedesktop.DBus",
681 "GetConnectionUnixUser",
682 NULL,
683 &reply,
684 "s",
685 unique ? unique : name);
686 if (r < 0)
687 return r;
688
689 r = sd_bus_message_read(reply, "u", &u);
690 if (r < 0)
691 return r;
692
693 c->euid = u;
694 c->mask |= SD_BUS_CREDS_EUID;
695
696 reply = sd_bus_message_unref(reply);
697 }
698
699 if (need_selinux) {
700 const void *p = NULL;
701 size_t sz = 0;
702
703 r = sd_bus_call_method(
704 bus,
705 "org.freedesktop.DBus",
706 "/org/freedesktop/DBus",
707 "org.freedesktop.DBus",
708 "GetConnectionSELinuxSecurityContext",
709 &error,
710 &reply,
711 "s",
712 unique ? unique : name);
713 if (r < 0) {
714 if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
715 return r;
716
717 /* no data is fine */
718 } else {
719 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
720 if (r < 0)
721 return r;
722
723 c->label = strndup(p, sz);
724 if (!c->label)
725 return -ENOMEM;
726
727 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
728 }
729 }
730 }
731
732 r = bus_creds_add_more(c, mask, pid, 0);
733 if (r < 0)
734 return r;
735 }
736
737 if (creds) {
738 *creds = c;
739 c = NULL;
740 }
741
742 return 0;
743 }
744
745 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
746 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
747 bool do_label, do_groups;
748 pid_t pid = 0;
749 int r;
750
751 assert_return(bus, -EINVAL);
752 assert_return(bus = bus_resolve(bus), -ENOPKG);
753 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
754 assert_return(ret, -EINVAL);
755 assert_return(!bus_pid_changed(bus), -ECHILD);
756
757 if (!BUS_IS_OPEN(bus->state))
758 return -ENOTCONN;
759
760 if (!bus->is_local)
761 mask &= ~SD_BUS_CREDS_AUGMENT;
762
763 do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
764 do_groups = bus->n_groups != (size_t) -1 && (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS);
765
766 /* Avoid allocating anything if we have no chance of returning useful data */
767 if (!bus->ucred_valid && !do_label && !do_groups)
768 return -ENODATA;
769
770 c = bus_creds_new();
771 if (!c)
772 return -ENOMEM;
773
774 if (bus->ucred_valid) {
775 if (pid_is_valid(bus->ucred.pid)) {
776 pid = c->pid = bus->ucred.pid;
777 c->mask |= SD_BUS_CREDS_PID & mask;
778 }
779
780 if (uid_is_valid(bus->ucred.uid)) {
781 c->euid = bus->ucred.uid;
782 c->mask |= SD_BUS_CREDS_EUID & mask;
783 }
784
785 if (gid_is_valid(bus->ucred.gid)) {
786 c->egid = bus->ucred.gid;
787 c->mask |= SD_BUS_CREDS_EGID & mask;
788 }
789 }
790
791 if (do_label) {
792 c->label = strdup(bus->label);
793 if (!c->label)
794 return -ENOMEM;
795
796 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
797 }
798
799 if (do_groups) {
800 c->supplementary_gids = newdup(gid_t, bus->groups, bus->n_groups);
801 if (!c->supplementary_gids)
802 return -ENOMEM;
803
804 c->n_supplementary_gids = bus->n_groups;
805
806 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
807 }
808
809 r = bus_creds_add_more(c, mask, pid, 0);
810 if (r < 0)
811 return r;
812
813 *ret = c;
814 c = NULL;
815 return 0;
816 }
817
818 #define append_eavesdrop(bus, m) \
819 ((bus)->is_monitor \
820 ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
821 : (m))
822
823 int bus_add_match_internal(
824 sd_bus *bus,
825 const char *match) {
826
827 const char *e;
828
829 assert(bus);
830
831 if (!bus->bus_client)
832 return -EINVAL;
833
834 e = append_eavesdrop(bus, match);
835
836 return sd_bus_call_method(
837 bus,
838 "org.freedesktop.DBus",
839 "/org/freedesktop/DBus",
840 "org.freedesktop.DBus",
841 "AddMatch",
842 NULL,
843 NULL,
844 "s",
845 e);
846 }
847 int bus_add_match_internal_async(
848 sd_bus *bus,
849 sd_bus_slot **ret_slot,
850 const char *match,
851 sd_bus_message_handler_t callback,
852 void *userdata) {
853
854 const char *e;
855
856 assert(bus);
857
858 if (!bus->bus_client)
859 return -EINVAL;
860
861 e = append_eavesdrop(bus, match);
862
863 return sd_bus_call_method_async(
864 bus,
865 ret_slot,
866 "org.freedesktop.DBus",
867 "/org/freedesktop/DBus",
868 "org.freedesktop.DBus",
869 "AddMatch",
870 callback,
871 userdata,
872 "s",
873 e);
874 }
875
876 int bus_remove_match_internal(
877 sd_bus *bus,
878 const char *match) {
879
880 const char *e;
881
882 assert(bus);
883 assert(match);
884
885 if (!bus->bus_client)
886 return -EINVAL;
887
888 e = append_eavesdrop(bus, match);
889
890 /* Fire and forget */
891
892 return sd_bus_call_method_async(
893 bus,
894 NULL,
895 "org.freedesktop.DBus",
896 "/org/freedesktop/DBus",
897 "org.freedesktop.DBus",
898 "RemoveMatch",
899 NULL,
900 NULL,
901 "s",
902 e);
903 }
904
905 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
906 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
907 const char *mid;
908 int r;
909
910 assert_return(bus, -EINVAL);
911 assert_return(bus = bus_resolve(bus), -ENOPKG);
912 assert_return(name, -EINVAL);
913 assert_return(machine, -EINVAL);
914 assert_return(!bus_pid_changed(bus), -ECHILD);
915 assert_return(service_name_is_valid(name), -EINVAL);
916
917 if (!bus->bus_client)
918 return -EINVAL;
919
920 if (!BUS_IS_OPEN(bus->state))
921 return -ENOTCONN;
922
923 if (streq_ptr(name, bus->unique_name))
924 return sd_id128_get_machine(machine);
925
926 r = sd_bus_message_new_method_call(
927 bus,
928 &m,
929 name,
930 "/",
931 "org.freedesktop.DBus.Peer",
932 "GetMachineId");
933 if (r < 0)
934 return r;
935
936 r = sd_bus_message_set_auto_start(m, false);
937 if (r < 0)
938 return r;
939
940 r = sd_bus_call(bus, m, 0, NULL, &reply);
941 if (r < 0)
942 return r;
943
944 r = sd_bus_message_read(reply, "s", &mid);
945 if (r < 0)
946 return r;
947
948 return sd_id128_from_string(mid, machine);
949 }