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