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