chiark / gitweb /
sd-bus: add APIs to request/release names asynchronously
[elogind.git] / src / libelogind / sd-bus / bus-control.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
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
21 #if HAVE_VALGRIND_MEMCHECK_H
22 #include <valgrind/memcheck.h>
23 #endif
24
25 #include <errno.h>
26 #include <stddef.h>
27
28 #include "sd-bus.h"
29
30 #include "alloc-util.h"
31 #include "bus-bloom.h"
32 #include "bus-control.h"
33 #include "bus-internal.h"
34 #include "bus-message.h"
35 #include "bus-util.h"
36 #include "capability-util.h"
37 #include "stdio-util.h"
38 #include "string-util.h"
39 #include "strv.h"
40 #include "user-util.h"
41
42 _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
43         int r;
44
45         assert_return(bus, -EINVAL);
46         assert_return(unique, -EINVAL);
47         assert_return(!bus_pid_changed(bus), -ECHILD);
48
49         if (!bus->bus_client)
50                 return -EINVAL;
51
52         r = bus_ensure_running(bus);
53         if (r < 0)
54                 return r;
55
56         *unique = bus->unique_name;
57         return 0;
58 }
59
60 static 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);
71
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;
85
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
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
115         r = sd_bus_call_method(
116                         bus,
117                         "org.freedesktop.DBus",
118                         "/org/freedesktop/DBus",
119                         "org.freedesktop.DBus",
120                         "RequestName",
121                         NULL,
122                         &reply,
123                         "su",
124                         name,
125                         param);
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
133         switch (ret) {
134
135         case BUS_NAME_ALREADY_OWNER:
136                 return -EALREADY;
137
138         case BUS_NAME_EXISTS:
139                 return -EEXIST;
140
141         case BUS_NAME_IN_QUEUE:
142                 return 0;
143
144         case BUS_NAME_PRIMARY_OWNER:
145                 return 1;
146         }
147
148         return -EIO;
149 }
150
151 static int default_request_name_handler(
152                 sd_bus_message *m,
153                 void *userdata,
154                 sd_bus_error *ret_error) {
155
156         uint32_t ret;
157         int r;
158
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
210         assert_return(bus, -EINVAL);
211         assert_return(name, -EINVAL);
212         assert_return(!bus_pid_changed(bus), -ECHILD);
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
232 static int validate_release_name_parameters(
233                 sd_bus *bus,
234                 const char *name) {
235
236         assert(bus);
237         assert(name);
238
239         assert_return(service_name_is_valid(name), -EINVAL);
240         assert_return(name[0] != ':', -EINVAL);
241
242         if (!bus->bus_client)
243                 return -EINVAL;
244
245         /* Don't allow releasing the special driver and local names */
246         if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
247                 return -EINVAL;
248
249         if (!BUS_IS_OPEN(bus->state))
250                 return -ENOTCONN;
251
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
271         r = sd_bus_call_method(
272                         bus,
273                         "org.freedesktop.DBus",
274                         "/org/freedesktop/DBus",
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;
287
288         switch (ret) {
289
290         case BUS_NAME_NON_EXISTENT:
291                 return -ESRCH;
292
293         case BUS_NAME_NOT_OWNER:
294                 return -EADDRINUSE;
295
296         case BUS_NAME_RELEASED:
297                 return 0;
298         }
299
300         return -EIO;
301 }
302
303 static 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);
317
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);
374 }
375
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
381         assert_return(bus, -EINVAL);
382         assert_return(acquired || activatable, -EINVAL);
383         assert_return(!bus_pid_changed(bus), -ECHILD);
384
385         if (!bus->bus_client)
386                 return -EINVAL;
387
388         if (!BUS_IS_OPEN(bus->state))
389                 return -ENOTCONN;
390
391         if (acquired) {
392                 r = sd_bus_call_method(
393                                 bus,
394                                 "org.freedesktop.DBus",
395                                 "/org/freedesktop/DBus",
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",
415                                 "/org/freedesktop/DBus",
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;
435         }
436
437         return 0;
438 }
439
440 _public_ int sd_bus_get_name_creds(
441                 sd_bus *bus,
442                 const char *name,
443                 uint64_t mask,
444                 sd_bus_creds **creds) {
445
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;
448         const char *unique = NULL;
449         pid_t pid = 0;
450         int r;
451
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
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",
482                                 "/org/freedesktop/DBus",
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) {
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;
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                 }
511
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;
524
525                 if (need_pid + need_uid + need_selinux > 1) {
526
527                         /* If we need more than one of the credentials, then use GetConnectionCredentials() */
528
529                         r = sd_bus_call_method(
530                                         bus,
531                                         "org.freedesktop.DBus",
532                                         "/org/freedesktop/DBus",
533                                         "org.freedesktop.DBus",
534                                         "GetConnectionCredentials",
535                                         &error,
536                                         &reply,
537                                         "s",
538                                         unique ?: name);
539
540                         if (r < 0) {
541
542                                 if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
543                                         return r;
544
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);
548
549                         } else {
550                                 need_separate_calls = false;
551
552                                 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
553                                 if (r < 0)
554                                         return r;
555
556                                 for (;;) {
557                                         const char *m;
558
559                                         r = sd_bus_message_enter_container(reply, 'e', "sv");
560                                         if (r < 0)
561                                                 return r;
562                                         if (r == 0)
563                                                 break;
564
565                                         r = sd_bus_message_read(reply, "s", &m);
566                                         if (r < 0)
567                                                 return r;
568
569                                         if (need_uid && streq(m, "UnixUserID")) {
570                                                 uint32_t u;
571
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)
627                                         return r;
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);
650                                 if (r < 0)
651                                         return r;
652
653                                 r = sd_bus_message_read(reply, "u", &u);
654                                 if (r < 0)
655                                         return r;
656
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                                 }
722                         }
723                 }
724
725                 r = bus_creds_add_more(c, mask, pid, 0);
726                 if (r < 0)
727                         return r;
728         }
729
730         if (creds) {
731                 *creds = c;
732                 c = NULL;
733         }
734
735         return 0;
736 }
737
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;
743
744         assert_return(bus, -EINVAL);
745         assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
746         assert_return(ret, -EINVAL);
747         assert_return(!bus_pid_changed(bus), -ECHILD);
748
749         if (!BUS_IS_OPEN(bus->state))
750                 return -ENOTCONN;
751
752         if (!bus->is_local)
753                 mask &= ~SD_BUS_CREDS_AUGMENT;
754
755         do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
756         do_groups = bus->n_groups != (size_t) -1 && (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS);
757
758         /* Avoid allocating anything if we have no chance of returning useful data */
759         if (!bus->ucred_valid && !do_label && !do_groups)
760                 return -ENODATA;
761
762         c = bus_creds_new();
763         if (!c)
764                 return -ENOMEM;
765
766         if (bus->ucred_valid) {
767                 if (pid_is_valid(bus->ucred.pid)) {
768                         pid = c->pid = bus->ucred.pid;
769                         c->mask |= SD_BUS_CREDS_PID & mask;
770                 }
771
772                 if (uid_is_valid(bus->ucred.uid)) {
773                         c->euid = bus->ucred.uid;
774                         c->mask |= SD_BUS_CREDS_EUID & mask;
775                 }
776
777                 if (gid_is_valid(bus->ucred.gid)) {
778                         c->egid = bus->ucred.gid;
779                         c->mask |= SD_BUS_CREDS_EGID & mask;
780                 }
781         }
782
783         if (do_label) {
784                 c->label = strdup(bus->label);
785                 if (!c->label)
786                         return -ENOMEM;
787
788                 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
789         }
790
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
801         r = bus_creds_add_more(c, mask, pid, 0);
802         if (r < 0)
803                 return r;
804
805         *ret = c;
806         c = NULL;
807         return 0;
808 }
809
810 #define append_eavesdrop(bus, m)                                        \
811         ((bus)->is_monitor                                              \
812          ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
813          : (m))
814
815 int bus_add_match_internal(
816                 sd_bus *bus,
817                 const char *match,
818                 struct bus_match_component *components,
819                 unsigned n_components) {
820
821         const char *e;
822
823         assert(bus);
824
825         if (!bus->bus_client)
826                 return -EINVAL;
827
828         e = append_eavesdrop(bus, match);
829
830         return sd_bus_call_method(
831                         bus,
832                         "org.freedesktop.DBus",
833                         "/org/freedesktop/DBus",
834                         "org.freedesktop.DBus",
835                         "AddMatch",
836                         NULL,
837                         NULL,
838                         "s",
839                         e);
840 }
841
842 int bus_remove_match_internal(
843                 sd_bus *bus,
844                 const char *match) {
845
846         const char *e;
847
848         assert(bus);
849         assert(match);
850
851         if (!bus->bus_client)
852                 return -EINVAL;
853
854         e = append_eavesdrop(bus, match);
855
856         return sd_bus_call_method(
857                         bus,
858                         "org.freedesktop.DBus",
859                         "/org/freedesktop/DBus",
860                         "org.freedesktop.DBus",
861                         "RemoveMatch",
862                         NULL,
863                         NULL,
864                         "s",
865                         e);
866 }
867
868 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
869         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
870         const char *mid;
871         int r;
872
873         assert_return(bus, -EINVAL);
874         assert_return(name, -EINVAL);
875         assert_return(machine, -EINVAL);
876         assert_return(!bus_pid_changed(bus), -ECHILD);
877         assert_return(service_name_is_valid(name), -EINVAL);
878
879         if (!bus->bus_client)
880                 return -EINVAL;
881
882         if (!BUS_IS_OPEN(bus->state))
883                 return -ENOTCONN;
884
885         if (streq_ptr(name, bus->unique_name))
886                 return sd_id128_get_machine(machine);
887
888         r = sd_bus_message_new_method_call(
889                         bus,
890                         &m,
891                         name,
892                         "/",
893                         "org.freedesktop.DBus.Peer",
894                         "GetMachineId");
895         if (r < 0)
896                 return r;
897
898         r = sd_bus_message_set_auto_start(m, false);
899         if (r < 0)
900                 return r;
901
902         r = sd_bus_call(bus, m, 0, NULL, &reply);
903         if (r < 0)
904                 return r;
905
906         r = sd_bus_message_read(reply, "s", &mid);
907         if (r < 0)
908                 return r;
909
910         return sd_id128_from_string(mid, machine);
911 }