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