]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-control.c
tree-wide: use TAKE_PTR() and TAKE_FD() macros
[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"
dccca82b 36#include "process-util.h"
15a5e950 37#include "stdio-util.h"
07630cea
LP
38#include "string-util.h"
39#include "strv.h"
ee104e11 40#include "user-util.h"
de1c301e 41
d9f644e2 42_public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
20902f3e
LP
43 int r;
44
9bb058a1 45 assert_return(bus, -EINVAL);
45b1f410 46 assert_return(bus = bus_resolve(bus), -ENOPKG);
9bb058a1
LS
47 assert_return(unique, -EINVAL);
48 assert_return(!bus_pid_changed(bus), -ECHILD);
20902f3e 49
33c62dcb
LP
50 if (!bus->bus_client)
51 return -EINVAL;
52
20902f3e
LP
53 r = bus_ensure_running(bus);
54 if (r < 0)
55 return r;
de1c301e 56
20902f3e
LP
57 *unique = bus->unique_name;
58 return 0;
de1c301e
LP
59}
60
98c5bbc8
LP
61static 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);
de1c301e 72
e8bd7b09
LP
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;
e7176abb 86
29a07cdb
LP
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
98c5bbc8
LP
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);
45b1f410 109 assert_return(bus = bus_resolve(bus), -ENOPKG);
98c5bbc8
LP
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
e7176abb
LP
117 r = sd_bus_call_method(
118 bus,
119 "org.freedesktop.DBus",
cd789fdf 120 "/org/freedesktop/DBus",
e7176abb
LP
121 "org.freedesktop.DBus",
122 "RequestName",
123 NULL,
124 &reply,
125 "su",
126 name,
29a07cdb 127 param);
e7176abb
LP
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
98c5bbc8
LP
135 switch (ret) {
136
137 case BUS_NAME_ALREADY_OWNER:
e7176abb 138 return -EALREADY;
98c5bbc8
LP
139
140 case BUS_NAME_EXISTS:
e7176abb 141 return -EEXIST;
98c5bbc8
LP
142
143 case BUS_NAME_IN_QUEUE:
e7176abb 144 return 0;
98c5bbc8
LP
145
146 case BUS_NAME_PRIMARY_OWNER:
c0a09132 147 return 1;
98c5bbc8 148 }
e7176abb 149
c0a09132 150 return -EIO;
e7176abb
LP
151}
152
98c5bbc8
LP
153static int default_request_name_handler(
154 sd_bus_message *m,
155 void *userdata,
156 sd_bus_error *ret_error) {
157
e8bd7b09
LP
158 uint32_t ret;
159 int r;
160
98c5bbc8
LP
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
9bb058a1 212 assert_return(bus, -EINVAL);
45b1f410 213 assert_return(bus = bus_resolve(bus), -ENOPKG);
9bb058a1 214 assert_return(name, -EINVAL);
9bb058a1 215 assert_return(!bus_pid_changed(bus), -ECHILD);
98c5bbc8
LP
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
235static int validate_release_name_parameters(
236 sd_bus *bus,
237 const char *name) {
238
239 assert(bus);
240 assert(name);
241
45fd5e4d
LP
242 assert_return(service_name_is_valid(name), -EINVAL);
243 assert_return(name[0] != ':', -EINVAL);
de1c301e 244
33c62dcb
LP
245 if (!bus->bus_client)
246 return -EINVAL;
247
e8bd7b09 248 /* Don't allow releasing the special driver and local names */
210a6882
LP
249 if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
250 return -EINVAL;
251
a3d59cd1
LP
252 if (!BUS_IS_OPEN(bus->state))
253 return -ENOTCONN;
254
98c5bbc8
LP
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);
45b1f410 267 assert_return(bus = bus_resolve(bus), -ENOPKG);
98c5bbc8
LP
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
e7176abb
LP
275 r = sd_bus_call_method(
276 bus,
277 "org.freedesktop.DBus",
cd789fdf 278 "/org/freedesktop/DBus",
e7176abb
LP
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;
98c5bbc8
LP
291
292 switch (ret) {
293
294 case BUS_NAME_NON_EXISTENT:
043ccd83 295 return -ESRCH;
98c5bbc8
LP
296
297 case BUS_NAME_NOT_OWNER:
043ccd83 298 return -EADDRINUSE;
98c5bbc8
LP
299
300 case BUS_NAME_RELEASED:
e7176abb 301 return 0;
98c5bbc8
LP
302 }
303
304 return -EIO;
305}
306
307static 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);
e7176abb 321
98c5bbc8
LP
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);
45b1f410 360 assert_return(bus = bus_resolve(bus), -ENOPKG);
98c5bbc8
LP
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);
e7176abb
LP
379}
380
e8bd7b09
LP
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
9bb058a1 386 assert_return(bus, -EINVAL);
45b1f410 387 assert_return(bus = bus_resolve(bus), -ENOPKG);
e8bd7b09 388 assert_return(acquired || activatable, -EINVAL);
9bb058a1 389 assert_return(!bus_pid_changed(bus), -ECHILD);
de1c301e 390
33c62dcb
LP
391 if (!bus->bus_client)
392 return -EINVAL;
393
a3d59cd1
LP
394 if (!BUS_IS_OPEN(bus->state))
395 return -ENOTCONN;
396
71f2ab46
LP
397 if (acquired) {
398 r = sd_bus_call_method(
399 bus,
400 "org.freedesktop.DBus",
cd789fdf 401 "/org/freedesktop/DBus",
71f2ab46
LP
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",
cd789fdf 421 "/org/freedesktop/DBus",
71f2ab46
LP
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
1cc6c93a 434 *activatable = TAKE_PTR(y);
71f2ab46
LP
435 }
436
1cc6c93a
YW
437 if (acquired)
438 *acquired = TAKE_PTR(x);
de1c301e 439
49b832c5
LP
440 return 0;
441}
442
e8bd7b09 443_public_ int sd_bus_get_name_creds(
e7176abb
LP
444 sd_bus *bus,
445 const char *name,
446 uint64_t mask,
447 sd_bus_creds **creds) {
448
4afd3348
LP
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;
e7176abb
LP
451 const char *unique = NULL;
452 pid_t pid = 0;
453 int r;
454
e8bd7b09 455 assert_return(bus, -EINVAL);
45b1f410 456 assert_return(bus = bus_resolve(bus), -ENOPKG);
e8bd7b09
LP
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
e7176abb
LP
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",
cd789fdf 486 "/org/freedesktop/DBus",
e7176abb
LP
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) {
40f35505
LP
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;
e7176abb
LP
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 }
49b832c5 515
40f35505
LP
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;
705a415f 528
40f35505
LP
529 if (need_pid + need_uid + need_selinux > 1) {
530
531 /* If we need more than one of the credentials, then use GetConnectionCredentials() */
49b832c5 532
e7176abb
LP
533 r = sd_bus_call_method(
534 bus,
535 "org.freedesktop.DBus",
cd789fdf 536 "/org/freedesktop/DBus",
e7176abb 537 "org.freedesktop.DBus",
40f35505
LP
538 "GetConnectionCredentials",
539 &error,
e7176abb
LP
540 &reply,
541 "s",
40f35505 542 unique ?: name);
49b832c5 543
40f35505 544 if (r < 0) {
e7176abb 545
40f35505
LP
546 if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
547 return r;
49b832c5 548
40f35505
LP
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);
49b832c5 552
40f35505
LP
553 } else {
554 need_separate_calls = false;
49b832c5 555
40f35505
LP
556 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
557 if (r < 0)
558 return r;
49b832c5 559
40f35505
LP
560 for (;;) {
561 const char *m;
49b832c5 562
40f35505
LP
563 r = sd_bus_message_enter_container(reply, 'e', "sv");
564 if (r < 0)
565 return r;
566 if (r == 0)
567 break;
49b832c5 568
40f35505
LP
569 r = sd_bus_message_read(reply, "s", &m);
570 if (r < 0)
571 return r;
49b832c5 572
40f35505
LP
573 if (need_uid && streq(m, "UnixUserID")) {
574 uint32_t u;
49b832c5 575
40f35505
LP
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)
359c09b1 631 return r;
40f35505
LP
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);
359c09b1
LP
654 if (r < 0)
655 return r;
e7176abb 656
40f35505
LP
657 r = sd_bus_message_read(reply, "u", &u);
658 if (r < 0)
659 return r;
e7176abb 660
40f35505
LP
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 }
359c09b1 726 }
49b832c5 727 }
e7176abb
LP
728
729 r = bus_creds_add_more(c, mask, pid, 0);
730 if (r < 0)
731 return r;
49b832c5
LP
732 }
733
1cc6c93a
YW
734 if (creds)
735 *creds = TAKE_PTR(c);
49b832c5 736
e7176abb 737 return 0;
49b832c5
LP
738}
739
e8bd7b09
LP
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;
49b832c5
LP
745
746 assert_return(bus, -EINVAL);
45b1f410 747 assert_return(bus = bus_resolve(bus), -ENOPKG);
15411c0c 748 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
e8bd7b09 749 assert_return(ret, -EINVAL);
49b832c5 750 assert_return(!bus_pid_changed(bus), -ECHILD);
51c7d5aa 751
a3d59cd1
LP
752 if (!BUS_IS_OPEN(bus->state))
753 return -ENOTCONN;
754
e8bd7b09
LP
755 if (!bus->is_local)
756 mask &= ~SD_BUS_CREDS_AUGMENT;
7fc04b12
LP
757
758 do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
18ac4643 759 do_groups = bus->n_groups != (size_t) -1 && (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS);
8f44e3ea 760
c4e6556c 761 /* Avoid allocating anything if we have no chance of returning useful data */
18ac4643 762 if (!bus->ucred_valid && !do_label && !do_groups)
8f44e3ea
DM
763 return -ENODATA;
764
765 c = bus_creds_new();
766 if (!c)
767 return -ENOMEM;
768
769 if (bus->ucred_valid) {
bbcc701e 770 if (pid_is_valid(bus->ucred.pid)) {
52cfc037
LP
771 pid = c->pid = bus->ucred.pid;
772 c->mask |= SD_BUS_CREDS_PID & mask;
773 }
8f44e3ea 774
bbcc701e 775 if (uid_is_valid(bus->ucred.uid)) {
05bae4a6
DH
776 c->euid = bus->ucred.uid;
777 c->mask |= SD_BUS_CREDS_EUID & mask;
52cfc037
LP
778 }
779
bbcc701e 780 if (gid_is_valid(bus->ucred.gid)) {
05bae4a6
DH
781 c->egid = bus->ucred.gid;
782 c->mask |= SD_BUS_CREDS_EGID & mask;
52cfc037 783 }
8f44e3ea
DM
784 }
785
c4e6556c 786 if (do_label) {
8f44e3ea 787 c->label = strdup(bus->label);
505e77ca 788 if (!c->label)
8f44e3ea 789 return -ENOMEM;
8f44e3ea
DM
790
791 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
792 }
793
18ac4643
LP
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
705a415f
LP
804 r = bus_creds_add_more(c, mask, pid, 0);
805 if (r < 0)
806 return r;
807
1cc6c93a
YW
808 *ret = TAKE_PTR(c);
809
8f44e3ea
DM
810 return 0;
811}
812
e8bd7b09 813#define append_eavesdrop(bus, m) \
c7db1984 814 ((bus)->is_monitor \
63c372cb 815 ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
09365592
LP
816 : (m))
817
e8bd7b09 818int bus_add_match_internal(
e7176abb 819 sd_bus *bus,
0259b87f 820 const char *match) {
777d7a61 821
09365592
LP
822 const char *e;
823
e7176abb 824 assert(bus);
777d7a61 825
e8bd7b09
LP
826 if (!bus->bus_client)
827 return -EINVAL;
828
829 e = append_eavesdrop(bus, match);
09365592 830
e7176abb
LP
831 return sd_bus_call_method(
832 bus,
833 "org.freedesktop.DBus",
cd789fdf 834 "/org/freedesktop/DBus",
e7176abb
LP
835 "org.freedesktop.DBus",
836 "AddMatch",
837 NULL,
838 NULL,
839 "s",
09365592 840 e);
7593c7a4
LP
841}
842int 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);
de1c301e
LP
869}
870
e8bd7b09 871int bus_remove_match_internal(
e7176abb
LP
872 sd_bus *bus,
873 const char *match) {
777d7a61 874
09365592
LP
875 const char *e;
876
e7176abb
LP
877 assert(bus);
878 assert(match);
879
e8bd7b09
LP
880 if (!bus->bus_client)
881 return -EINVAL;
882
883 e = append_eavesdrop(bus, match);
09365592 884
acd34015
LP
885 /* Fire and forget */
886
887 return sd_bus_call_method_async(
e7176abb 888 bus,
acd34015 889 NULL,
e7176abb 890 "org.freedesktop.DBus",
cd789fdf 891 "/org/freedesktop/DBus",
e7176abb
LP
892 "org.freedesktop.DBus",
893 "RemoveMatch",
894 NULL,
895 NULL,
896 "s",
09365592 897 e);
e7176abb
LP
898}
899
056f95d0 900_public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
4afd3348 901 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
70666185
LP
902 const char *mid;
903 int r;
904
8d162091 905 assert_return(bus, -EINVAL);
45b1f410 906 assert_return(bus = bus_resolve(bus), -ENOPKG);
8d162091
LP
907 assert_return(name, -EINVAL);
908 assert_return(machine, -EINVAL);
8d162091 909 assert_return(!bus_pid_changed(bus), -ECHILD);
45fd5e4d 910 assert_return(service_name_is_valid(name), -EINVAL);
70666185 911
33c62dcb
LP
912 if (!bus->bus_client)
913 return -EINVAL;
914
a3d59cd1
LP
915 if (!BUS_IS_OPEN(bus->state))
916 return -ENOTCONN;
917
70666185
LP
918 if (streq_ptr(name, bus->unique_name))
919 return sd_id128_get_machine(machine);
920
8d162091
LP
921 r = sd_bus_message_new_method_call(
922 bus,
151b9b96 923 &m,
8d162091
LP
924 name,
925 "/",
926 "org.freedesktop.DBus.Peer",
151b9b96 927 "GetMachineId");
8d162091
LP
928 if (r < 0)
929 return r;
930
eee9ec0e 931 r = sd_bus_message_set_auto_start(m, false);
8d162091
LP
932 if (r < 0)
933 return r;
70666185 934
8d162091 935 r = sd_bus_call(bus, m, 0, NULL, &reply);
70666185
LP
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}