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