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