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