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