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