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