chiark / gitweb /
sd-bus: use SO_PEERGROUPS when available to identify groups of peer
[elogind.git] / src / libelogind / sd-bus / bus-control.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3   This file is part of systemd.
4
5   Copyright 2013 Lennart Poettering
6
7   systemd is free software; you can redistribute it and/or modify it
8   under the terms of the GNU Lesser General Public License as published by
9   the Free Software Foundation; either version 2.1 of the License, or
10   (at your option) any later version.
11
12   systemd is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   Lesser General Public License for more details.
16
17   You should have received a copy of the GNU Lesser General Public License
18   along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #if HAVE_VALGRIND_MEMCHECK_H
22 #include <valgrind/memcheck.h>
23 #endif
24
25 #include <errno.h>
26 #include <stddef.h>
27
28 #include "sd-bus.h"
29
30 #include "alloc-util.h"
31 #include "bus-bloom.h"
32 #include "bus-control.h"
33 #include "bus-internal.h"
34 #include "bus-message.h"
35 #include "bus-util.h"
36 #include "capability-util.h"
37 #include "stdio-util.h"
38 #include "string-util.h"
39 #include "strv.h"
40 #include "user-util.h"
41
42 _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
43         int r;
44
45         assert_return(bus, -EINVAL);
46         assert_return(unique, -EINVAL);
47         assert_return(!bus_pid_changed(bus), -ECHILD);
48
49         if (!bus->bus_client)
50                 return -EINVAL;
51
52         r = bus_ensure_running(bus);
53         if (r < 0)
54                 return r;
55
56         *unique = bus->unique_name;
57         return 0;
58 }
59
60 static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) {
61         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
62         uint32_t ret, param = 0;
63         int r;
64
65         assert(bus);
66         assert(name);
67
68         if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
69                 param |= BUS_NAME_ALLOW_REPLACEMENT;
70         if (flags & SD_BUS_NAME_REPLACE_EXISTING)
71                 param |= BUS_NAME_REPLACE_EXISTING;
72         if (!(flags & SD_BUS_NAME_QUEUE))
73                 param |= BUS_NAME_DO_NOT_QUEUE;
74
75         r = sd_bus_call_method(
76                         bus,
77                         "org.freedesktop.DBus",
78                         "/org/freedesktop/DBus",
79                         "org.freedesktop.DBus",
80                         "RequestName",
81                         NULL,
82                         &reply,
83                         "su",
84                         name,
85                         param);
86         if (r < 0)
87                 return r;
88
89         r = sd_bus_message_read(reply, "u", &ret);
90         if (r < 0)
91                 return r;
92
93         if (ret == BUS_NAME_ALREADY_OWNER)
94                 return -EALREADY;
95         else if (ret == BUS_NAME_EXISTS)
96                 return -EEXIST;
97         else if (ret == BUS_NAME_IN_QUEUE)
98                 return 0;
99         else if (ret == BUS_NAME_PRIMARY_OWNER)
100                 return 1;
101
102         return -EIO;
103 }
104
105 _public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) {
106         assert_return(bus, -EINVAL);
107         assert_return(name, -EINVAL);
108         assert_return(!bus_pid_changed(bus), -ECHILD);
109         assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
110         assert_return(service_name_is_valid(name), -EINVAL);
111         assert_return(name[0] != ':', -EINVAL);
112
113         if (!bus->bus_client)
114                 return -EINVAL;
115
116         /* Don't allow requesting the special driver and local names */
117         if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
118                 return -EINVAL;
119
120         if (!BUS_IS_OPEN(bus->state))
121                 return -ENOTCONN;
122
123         return bus_request_name_dbus1(bus, name, flags);
124 }
125
126 static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
127         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
128         uint32_t ret;
129         int r;
130
131         assert(bus);
132         assert(name);
133
134         r = sd_bus_call_method(
135                         bus,
136                         "org.freedesktop.DBus",
137                         "/org/freedesktop/DBus",
138                         "org.freedesktop.DBus",
139                         "ReleaseName",
140                         NULL,
141                         &reply,
142                         "s",
143                         name);
144         if (r < 0)
145                 return r;
146
147         r = sd_bus_message_read(reply, "u", &ret);
148         if (r < 0)
149                 return r;
150         if (ret == BUS_NAME_NON_EXISTENT)
151                 return -ESRCH;
152         if (ret == BUS_NAME_NOT_OWNER)
153                 return -EADDRINUSE;
154         if (ret == BUS_NAME_RELEASED)
155                 return 0;
156
157         return -EINVAL;
158 }
159
160 _public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
161         assert_return(bus, -EINVAL);
162         assert_return(name, -EINVAL);
163         assert_return(!bus_pid_changed(bus), -ECHILD);
164         assert_return(service_name_is_valid(name), -EINVAL);
165         assert_return(name[0] != ':', -EINVAL);
166
167         if (!bus->bus_client)
168                 return -EINVAL;
169
170         /* Don't allow releasing the special driver and local names */
171         if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
172                 return -EINVAL;
173
174         if (!BUS_IS_OPEN(bus->state))
175                 return -ENOTCONN;
176
177         return bus_release_name_dbus1(bus, name);
178 }
179
180 static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
181         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
182         _cleanup_strv_free_ char **x = NULL, **y = NULL;
183         int r;
184
185         if (acquired) {
186                 r = sd_bus_call_method(
187                                 bus,
188                                 "org.freedesktop.DBus",
189                                 "/org/freedesktop/DBus",
190                                 "org.freedesktop.DBus",
191                                 "ListNames",
192                                 NULL,
193                                 &reply,
194                                 NULL);
195                 if (r < 0)
196                         return r;
197
198                 r = sd_bus_message_read_strv(reply, &x);
199                 if (r < 0)
200                         return r;
201
202                 reply = sd_bus_message_unref(reply);
203         }
204
205         if (activatable) {
206                 r = sd_bus_call_method(
207                                 bus,
208                                 "org.freedesktop.DBus",
209                                 "/org/freedesktop/DBus",
210                                 "org.freedesktop.DBus",
211                                 "ListActivatableNames",
212                                 NULL,
213                                 &reply,
214                                 NULL);
215                 if (r < 0)
216                         return r;
217
218                 r = sd_bus_message_read_strv(reply, &y);
219                 if (r < 0)
220                         return r;
221
222                 *activatable = y;
223                 y = NULL;
224         }
225
226         if (acquired) {
227                 *acquired = x;
228                 x = NULL;
229         }
230
231         return 0;
232 }
233
234 _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
235         assert_return(bus, -EINVAL);
236         assert_return(acquired || activatable, -EINVAL);
237         assert_return(!bus_pid_changed(bus), -ECHILD);
238
239         if (!bus->bus_client)
240                 return -EINVAL;
241
242         if (!BUS_IS_OPEN(bus->state))
243                 return -ENOTCONN;
244
245         return bus_list_names_dbus1(bus, acquired, activatable);
246 }
247
248 static int bus_get_name_creds_dbus1(
249                 sd_bus *bus,
250                 const char *name,
251                 uint64_t mask,
252                 sd_bus_creds **creds) {
253
254         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_unique = NULL, *reply = NULL;
255         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
256         const char *unique = NULL;
257         pid_t pid = 0;
258         int r;
259
260         /* Only query the owner if the caller wants to know it or if
261          * the caller just wants to check whether a name exists */
262         if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
263                 r = sd_bus_call_method(
264                                 bus,
265                                 "org.freedesktop.DBus",
266                                 "/org/freedesktop/DBus",
267                                 "org.freedesktop.DBus",
268                                 "GetNameOwner",
269                                 NULL,
270                                 &reply_unique,
271                                 "s",
272                                 name);
273                 if (r < 0)
274                         return r;
275
276                 r = sd_bus_message_read(reply_unique, "s", &unique);
277                 if (r < 0)
278                         return r;
279         }
280
281         if (mask != 0) {
282                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
283                 bool need_pid, need_uid, need_selinux, need_separate_calls;
284                 c = bus_creds_new();
285                 if (!c)
286                         return -ENOMEM;
287
288                 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
289                         c->unique_name = strdup(unique);
290                         if (!c->unique_name)
291                                 return -ENOMEM;
292
293                         c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
294                 }
295
296                 need_pid = (mask & SD_BUS_CREDS_PID) ||
297                         ((mask & SD_BUS_CREDS_AUGMENT) &&
298                          (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
299                                   SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
300                                   SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
301                                   SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
302                                   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|
303                                   SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
304                                   SD_BUS_CREDS_SELINUX_CONTEXT|
305                                   SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)));
306                 need_uid = mask & SD_BUS_CREDS_EUID;
307                 need_selinux = mask & SD_BUS_CREDS_SELINUX_CONTEXT;
308
309                 if (need_pid + need_uid + need_selinux > 1) {
310
311                         /* If we need more than one of the credentials, then use GetConnectionCredentials() */
312
313                         r = sd_bus_call_method(
314                                         bus,
315                                         "org.freedesktop.DBus",
316                                         "/org/freedesktop/DBus",
317                                         "org.freedesktop.DBus",
318                                         "GetConnectionCredentials",
319                                         &error,
320                                         &reply,
321                                         "s",
322                                         unique ?: name);
323
324                         if (r < 0) {
325
326                                 if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
327                                         return r;
328
329                                 /* If we got an unknown method error, fall back to the invidual calls... */
330                                 need_separate_calls = true;
331                                 sd_bus_error_free(&error);
332
333                         } else {
334                                 need_separate_calls = false;
335
336                                 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
337                                 if (r < 0)
338                                         return r;
339
340                                 for (;;) {
341                                         const char *m;
342
343                                         r = sd_bus_message_enter_container(reply, 'e', "sv");
344                                         if (r < 0)
345                                                 return r;
346                                         if (r == 0)
347                                                 break;
348
349                                         r = sd_bus_message_read(reply, "s", &m);
350                                         if (r < 0)
351                                                 return r;
352
353                                         if (need_uid && streq(m, "UnixUserID")) {
354                                                 uint32_t u;
355
356                                                 r = sd_bus_message_read(reply, "v", "u", &u);
357                                                 if (r < 0)
358                                                         return r;
359
360                                                 c->euid = u;
361                                                 c->mask |= SD_BUS_CREDS_EUID;
362
363                                         } else if (need_pid && streq(m, "ProcessID")) {
364                                                 uint32_t p;
365
366                                                 r = sd_bus_message_read(reply, "v", "u", &p);
367                                                 if (r < 0)
368                                                         return r;
369
370                                                 pid = p;
371                                                 if (mask & SD_BUS_CREDS_PID) {
372                                                         c->pid = p;
373                                                         c->mask |= SD_BUS_CREDS_PID;
374                                                 }
375
376                                         } else if (need_selinux && streq(m, "LinuxSecurityLabel")) {
377                                                 const void *p = NULL;
378                                                 size_t sz = 0;
379
380                                                 r = sd_bus_message_enter_container(reply, 'v', "ay");
381                                                 if (r < 0)
382                                                         return r;
383
384                                                 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
385                                                 if (r < 0)
386                                                         return r;
387
388                                                 free(c->label);
389                                                 c->label = strndup(p, sz);
390                                                 if (!c->label)
391                                                         return -ENOMEM;
392
393                                                 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
394
395                                                 r = sd_bus_message_exit_container(reply);
396                                                 if (r < 0)
397                                                         return r;
398                                         } else {
399                                                 r = sd_bus_message_skip(reply, "v");
400                                                 if (r < 0)
401                                                         return r;
402                                         }
403
404                                         r = sd_bus_message_exit_container(reply);
405                                         if (r < 0)
406                                                 return r;
407                                 }
408
409                                 r = sd_bus_message_exit_container(reply);
410                                 if (r < 0)
411                                         return r;
412
413                                 if (need_pid && pid == 0)
414                                         return -EPROTO;
415                         }
416
417                 } else /* When we only need a single field, then let's use separate calls */
418                         need_separate_calls = true;
419
420                 if (need_separate_calls) {
421                         if (need_pid) {
422                                 uint32_t u;
423
424                                 r = sd_bus_call_method(
425                                                 bus,
426                                                 "org.freedesktop.DBus",
427                                                 "/org/freedesktop/DBus",
428                                                 "org.freedesktop.DBus",
429                                                 "GetConnectionUnixProcessID",
430                                                 NULL,
431                                                 &reply,
432                                                 "s",
433                                                 unique ?: name);
434                                 if (r < 0)
435                                         return r;
436
437                                 r = sd_bus_message_read(reply, "u", &u);
438                                 if (r < 0)
439                                         return r;
440
441                                 pid = u;
442                                 if (mask & SD_BUS_CREDS_PID) {
443                                         c->pid = u;
444                                         c->mask |= SD_BUS_CREDS_PID;
445                                 }
446
447                                 reply = sd_bus_message_unref(reply);
448                         }
449
450                         if (need_uid) {
451                                 uint32_t u;
452
453                                 r = sd_bus_call_method(
454                                                 bus,
455                                                 "org.freedesktop.DBus",
456                                                 "/org/freedesktop/DBus",
457                                                 "org.freedesktop.DBus",
458                                                 "GetConnectionUnixUser",
459                                                 NULL,
460                                                 &reply,
461                                                 "s",
462                                                 unique ? unique : name);
463                                 if (r < 0)
464                                         return r;
465
466                                 r = sd_bus_message_read(reply, "u", &u);
467                                 if (r < 0)
468                                         return r;
469
470                                 c->euid = u;
471                                 c->mask |= SD_BUS_CREDS_EUID;
472
473                                 reply = sd_bus_message_unref(reply);
474                         }
475
476                         if (need_selinux) {
477                                 const void *p = NULL;
478                                 size_t sz = 0;
479
480                                 r = sd_bus_call_method(
481                                                 bus,
482                                                 "org.freedesktop.DBus",
483                                                 "/org/freedesktop/DBus",
484                                                 "org.freedesktop.DBus",
485                                                 "GetConnectionSELinuxSecurityContext",
486                                                 &error,
487                                                 &reply,
488                                                 "s",
489                                                 unique ? unique : name);
490                                 if (r < 0) {
491                                         if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
492                                                 return r;
493
494                                         /* no data is fine */
495                                 } else {
496                                         r = sd_bus_message_read_array(reply, 'y', &p, &sz);
497                                         if (r < 0)
498                                                 return r;
499
500                                         c->label = strndup(p, sz);
501                                         if (!c->label)
502                                                 return -ENOMEM;
503
504                                         c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
505                                 }
506                         }
507                 }
508
509                 r = bus_creds_add_more(c, mask, pid, 0);
510                 if (r < 0)
511                         return r;
512         }
513
514         if (creds) {
515                 *creds = c;
516                 c = NULL;
517         }
518
519         return 0;
520 }
521
522 _public_ int sd_bus_get_name_creds(
523                 sd_bus *bus,
524                 const char *name,
525                 uint64_t mask,
526                 sd_bus_creds **creds) {
527
528         assert_return(bus, -EINVAL);
529         assert_return(name, -EINVAL);
530         assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
531         assert_return(mask == 0 || creds, -EINVAL);
532         assert_return(!bus_pid_changed(bus), -ECHILD);
533         assert_return(service_name_is_valid(name), -EINVAL);
534
535         if (!bus->bus_client)
536                 return -EINVAL;
537
538         /* Turn off augmenting if this isn't a local connection. If the connection is not local, then /proc is not
539          * going to match. */
540         if (!bus->is_local)
541                 mask &= ~SD_BUS_CREDS_AUGMENT;
542
543         if (streq(name, "org.freedesktop.DBus.Local"))
544                 return -EINVAL;
545
546         if (streq(name, "org.freedesktop.DBus"))
547                 return sd_bus_get_owner_creds(bus, mask, creds);
548
549         if (!BUS_IS_OPEN(bus->state))
550                 return -ENOTCONN;
551
552         return bus_get_name_creds_dbus1(bus, name, mask, creds);
553 }
554
555 static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
556         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
557         pid_t pid = 0;
558         bool do_label, do_groups;
559         int r;
560
561         assert(bus);
562
563         do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
564         do_groups = bus->n_groups != (size_t) -1 && (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS);
565
566         /* Avoid allocating anything if we have no chance of returning useful data */
567         if (!bus->ucred_valid && !do_label && !do_groups)
568                 return -ENODATA;
569
570         c = bus_creds_new();
571         if (!c)
572                 return -ENOMEM;
573
574         if (bus->ucred_valid) {
575                 if (pid_is_valid(bus->ucred.pid)) {
576                         pid = c->pid = bus->ucred.pid;
577                         c->mask |= SD_BUS_CREDS_PID & mask;
578                 }
579
580                 if (uid_is_valid(bus->ucred.uid)) {
581                         c->euid = bus->ucred.uid;
582                         c->mask |= SD_BUS_CREDS_EUID & mask;
583                 }
584
585                 if (gid_is_valid(bus->ucred.gid)) {
586                         c->egid = bus->ucred.gid;
587                         c->mask |= SD_BUS_CREDS_EGID & mask;
588                 }
589         }
590
591         if (do_label) {
592                 c->label = strdup(bus->label);
593                 if (!c->label)
594                         return -ENOMEM;
595
596                 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
597         }
598
599         if (do_groups) {
600                 c->supplementary_gids = newdup(gid_t, bus->groups, bus->n_groups);
601                 if (!c->supplementary_gids)
602                         return -ENOMEM;
603
604                 c->n_supplementary_gids = bus->n_groups;
605
606                 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
607         }
608
609         r = bus_creds_add_more(c, mask, pid, 0);
610         if (r < 0)
611                 return r;
612
613         *ret = c;
614         c = NULL;
615         return 0;
616 }
617
618 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
619         assert_return(bus, -EINVAL);
620         assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
621         assert_return(ret, -EINVAL);
622         assert_return(!bus_pid_changed(bus), -ECHILD);
623
624         if (!BUS_IS_OPEN(bus->state))
625                 return -ENOTCONN;
626
627         if (!bus->is_local)
628                 mask &= ~SD_BUS_CREDS_AUGMENT;
629
630         return bus_get_owner_creds_dbus1(bus, mask, ret);
631 }
632
633 #define internal_match(bus, m)                                          \
634         ((bus)->hello_flags & KDBUS_HELLO_MONITOR                       \
635          ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
636          : (m))
637
638 static int bus_add_match_internal_dbus1(
639                 sd_bus *bus,
640                 const char *match) {
641
642         const char *e;
643
644         assert(bus);
645         assert(match);
646
647         e = internal_match(bus, match);
648
649         return sd_bus_call_method(
650                         bus,
651                         "org.freedesktop.DBus",
652                         "/org/freedesktop/DBus",
653                         "org.freedesktop.DBus",
654                         "AddMatch",
655                         NULL,
656                         NULL,
657                         "s",
658                         e);
659 }
660
661 int bus_add_match_internal(
662                 sd_bus *bus,
663                 const char *match,
664                 struct bus_match_component *components,
665                 unsigned n_components) {
666
667         assert(bus);
668
669         if (!bus->bus_client)
670                 return -EINVAL;
671
672         return bus_add_match_internal_dbus1(bus, match);
673 }
674
675 static int bus_remove_match_internal_dbus1(
676                 sd_bus *bus,
677                 const char *match) {
678
679         const char *e;
680
681         assert(bus);
682         assert(match);
683
684         e = internal_match(bus, match);
685
686         return sd_bus_call_method(
687                         bus,
688                         "org.freedesktop.DBus",
689                         "/org/freedesktop/DBus",
690                         "org.freedesktop.DBus",
691                         "RemoveMatch",
692                         NULL,
693                         NULL,
694                         "s",
695                         e);
696 }
697
698 int bus_remove_match_internal(
699                 sd_bus *bus,
700                 const char *match) {
701
702         assert(bus);
703
704         if (!bus->bus_client)
705                 return -EINVAL;
706
707         return bus_remove_match_internal_dbus1(bus, match);
708 }
709
710 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
711         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
712         const char *mid;
713         int r;
714
715         assert_return(bus, -EINVAL);
716         assert_return(name, -EINVAL);
717         assert_return(machine, -EINVAL);
718         assert_return(!bus_pid_changed(bus), -ECHILD);
719         assert_return(service_name_is_valid(name), -EINVAL);
720
721         if (!bus->bus_client)
722                 return -EINVAL;
723
724         if (!BUS_IS_OPEN(bus->state))
725                 return -ENOTCONN;
726
727         if (streq_ptr(name, bus->unique_name))
728                 return sd_id128_get_machine(machine);
729
730         r = sd_bus_message_new_method_call(
731                         bus,
732                         &m,
733                         name,
734                         "/",
735                         "org.freedesktop.DBus.Peer",
736                         "GetMachineId");
737         if (r < 0)
738                 return r;
739
740         r = sd_bus_message_set_auto_start(m, false);
741         if (r < 0)
742                 return r;
743
744         r = sd_bus_call(bus, m, 0, NULL, &reply);
745         if (r < 0)
746                 return r;
747
748         r = sd_bus_message_read(reply, "s", &mid);
749         if (r < 0)
750                 return r;
751
752         return sd_id128_from_string(mid, machine);
753 }