Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <errno.h>
4 : #include <fcntl.h>
5 : #include <inttypes.h>
6 : #include <stdio.h>
7 : #include <stdlib.h>
8 : #include <string.h>
9 : #include <sys/ioctl.h>
10 : #include <sys/resource.h>
11 : #include <sys/socket.h>
12 : #include <unistd.h>
13 :
14 : #include "sd-bus-protocol.h"
15 : #include "sd-bus.h"
16 : #include "sd-daemon.h"
17 : #include "sd-event.h"
18 : #include "sd-id128.h"
19 :
20 : #include "alloc-util.h"
21 : #include "bus-internal.h"
22 : #include "bus-label.h"
23 : #include "bus-message.h"
24 : #include "bus-util.h"
25 : #include "cap-list.h"
26 : #include "cgroup-util.h"
27 : #include "def.h"
28 : #include "escape.h"
29 : #include "fd-util.h"
30 : #include "missing.h"
31 : #include "mountpoint-util.h"
32 : #include "nsflags.h"
33 : #include "parse-util.h"
34 : #include "path-util.h"
35 : #include "proc-cmdline.h"
36 : #include "rlimit-util.h"
37 : #include "stdio-util.h"
38 : #include "strv.h"
39 : #include "user-util.h"
40 :
41 0 : static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
42 0 : sd_event *e = userdata;
43 :
44 0 : assert(m);
45 0 : assert(e);
46 :
47 0 : sd_bus_close(sd_bus_message_get_bus(m));
48 0 : sd_event_exit(e, 0);
49 :
50 0 : return 1;
51 : }
52 :
53 0 : int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
54 : const char *match;
55 : const char *unique;
56 : int r;
57 :
58 0 : assert(e);
59 0 : assert(bus);
60 0 : assert(name);
61 :
62 : /* We unregister the name here and then wait for the
63 : * NameOwnerChanged signal for this event to arrive before we
64 : * quit. We do this in order to make sure that any queued
65 : * requests are still processed before we really exit. */
66 :
67 0 : r = sd_bus_get_unique_name(bus, &unique);
68 0 : if (r < 0)
69 0 : return r;
70 :
71 0 : match = strjoina(
72 : "sender='org.freedesktop.DBus',"
73 : "type='signal',"
74 : "interface='org.freedesktop.DBus',"
75 : "member='NameOwnerChanged',"
76 : "path='/org/freedesktop/DBus',"
77 : "arg0='", name, "',",
78 : "arg1='", unique, "',",
79 : "arg2=''");
80 :
81 0 : r = sd_bus_add_match_async(bus, NULL, match, name_owner_change_callback, NULL, e);
82 0 : if (r < 0)
83 0 : return r;
84 :
85 0 : r = sd_bus_release_name_async(bus, NULL, name, NULL, NULL);
86 0 : if (r < 0)
87 0 : return r;
88 :
89 0 : return 0;
90 : }
91 :
92 0 : int bus_event_loop_with_idle(
93 : sd_event *e,
94 : sd_bus *bus,
95 : const char *name,
96 : usec_t timeout,
97 : check_idle_t check_idle,
98 : void *userdata) {
99 0 : bool exiting = false;
100 : int r, code;
101 :
102 0 : assert(e);
103 0 : assert(bus);
104 0 : assert(name);
105 :
106 0 : for (;;) {
107 : bool idle;
108 :
109 0 : r = sd_event_get_state(e);
110 0 : if (r < 0)
111 0 : return r;
112 0 : if (r == SD_EVENT_FINISHED)
113 0 : break;
114 :
115 0 : if (check_idle)
116 0 : idle = check_idle(userdata);
117 : else
118 0 : idle = true;
119 :
120 0 : r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
121 0 : if (r < 0)
122 0 : return r;
123 :
124 0 : if (r == 0 && !exiting && idle) {
125 :
126 0 : r = sd_bus_try_close(bus);
127 0 : if (r == -EBUSY)
128 0 : continue;
129 :
130 : /* Fallback for dbus1 connections: we
131 : * unregister the name and wait for the
132 : * response to come through for it */
133 0 : if (r == -EOPNOTSUPP) {
134 :
135 : /* Inform the service manager that we
136 : * are going down, so that it will
137 : * queue all further start requests,
138 : * instead of assuming we are already
139 : * running. */
140 0 : sd_notify(false, "STOPPING=1");
141 :
142 0 : r = bus_async_unregister_and_exit(e, bus, name);
143 0 : if (r < 0)
144 0 : return r;
145 :
146 0 : exiting = true;
147 0 : continue;
148 : }
149 :
150 0 : if (r < 0)
151 0 : return r;
152 :
153 0 : sd_event_exit(e, 0);
154 0 : break;
155 : }
156 : }
157 :
158 0 : r = sd_event_get_exit_code(e, &code);
159 0 : if (r < 0)
160 0 : return r;
161 :
162 0 : return code;
163 : }
164 :
165 0 : int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
166 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *rep = NULL;
167 0 : int r, has_owner = 0;
168 :
169 0 : assert(c);
170 0 : assert(name);
171 :
172 0 : r = sd_bus_call_method(c,
173 : "org.freedesktop.DBus",
174 : "/org/freedesktop/dbus",
175 : "org.freedesktop.DBus",
176 : "NameHasOwner",
177 : error,
178 : &rep,
179 : "s",
180 : name);
181 0 : if (r < 0)
182 0 : return r;
183 :
184 0 : r = sd_bus_message_read_basic(rep, 'b', &has_owner);
185 0 : if (r < 0)
186 0 : return sd_bus_error_set_errno(error, r);
187 :
188 0 : return has_owner;
189 : }
190 :
191 0 : static int check_good_user(sd_bus_message *m, uid_t good_user) {
192 0 : _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
193 : uid_t sender_uid;
194 : int r;
195 :
196 0 : assert(m);
197 :
198 0 : if (good_user == UID_INVALID)
199 0 : return 0;
200 :
201 0 : r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds);
202 0 : if (r < 0)
203 0 : return r;
204 :
205 : /* Don't trust augmented credentials for authorization */
206 0 : assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EUID) == 0, -EPERM);
207 :
208 0 : r = sd_bus_creds_get_euid(creds, &sender_uid);
209 0 : if (r < 0)
210 0 : return r;
211 :
212 0 : return sender_uid == good_user;
213 : }
214 :
215 0 : int bus_test_polkit(
216 : sd_bus_message *call,
217 : int capability,
218 : const char *action,
219 : const char **details,
220 : uid_t good_user,
221 : bool *_challenge,
222 : sd_bus_error *e) {
223 :
224 : int r;
225 :
226 0 : assert(call);
227 0 : assert(action);
228 :
229 : /* Tests non-interactively! */
230 :
231 0 : r = check_good_user(call, good_user);
232 0 : if (r != 0)
233 0 : return r;
234 :
235 0 : r = sd_bus_query_sender_privilege(call, capability);
236 0 : if (r < 0)
237 0 : return r;
238 0 : else if (r > 0)
239 0 : return 1;
240 : #if ENABLE_POLKIT
241 : else {
242 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *request = NULL;
243 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
244 0 : int authorized = false, challenge = false;
245 : const char *sender, **k, **v;
246 :
247 0 : sender = sd_bus_message_get_sender(call);
248 0 : if (!sender)
249 0 : return -EBADMSG;
250 :
251 0 : r = sd_bus_message_new_method_call(
252 : call->bus,
253 : &request,
254 : "org.freedesktop.PolicyKit1",
255 : "/org/freedesktop/PolicyKit1/Authority",
256 : "org.freedesktop.PolicyKit1.Authority",
257 : "CheckAuthorization");
258 0 : if (r < 0)
259 0 : return r;
260 :
261 0 : r = sd_bus_message_append(
262 : request,
263 : "(sa{sv})s",
264 : "system-bus-name", 1, "name", "s", sender,
265 : action);
266 0 : if (r < 0)
267 0 : return r;
268 :
269 0 : r = sd_bus_message_open_container(request, 'a', "{ss}");
270 0 : if (r < 0)
271 0 : return r;
272 :
273 0 : STRV_FOREACH_PAIR(k, v, details) {
274 0 : r = sd_bus_message_append(request, "{ss}", *k, *v);
275 0 : if (r < 0)
276 0 : return r;
277 : }
278 :
279 0 : r = sd_bus_message_close_container(request);
280 0 : if (r < 0)
281 0 : return r;
282 :
283 0 : r = sd_bus_message_append(request, "us", 0, NULL);
284 0 : if (r < 0)
285 0 : return r;
286 :
287 0 : r = sd_bus_call(call->bus, request, 0, e, &reply);
288 0 : if (r < 0) {
289 : /* Treat no PK available as access denied */
290 0 : if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
291 0 : sd_bus_error_free(e);
292 0 : return -EACCES;
293 : }
294 :
295 0 : return r;
296 : }
297 :
298 0 : r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
299 0 : if (r < 0)
300 0 : return r;
301 :
302 0 : r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
303 0 : if (r < 0)
304 0 : return r;
305 :
306 0 : if (authorized)
307 0 : return 1;
308 :
309 0 : if (_challenge) {
310 0 : *_challenge = challenge;
311 0 : return 0;
312 : }
313 : }
314 : #endif
315 :
316 0 : return -EACCES;
317 : }
318 :
319 : #if ENABLE_POLKIT
320 :
321 : typedef struct AsyncPolkitQuery {
322 : sd_bus_message *request, *reply;
323 : sd_bus_message_handler_t callback;
324 : void *userdata;
325 : sd_bus_slot *slot;
326 : Hashmap *registry;
327 : } AsyncPolkitQuery;
328 :
329 0 : static void async_polkit_query_free(AsyncPolkitQuery *q) {
330 :
331 0 : if (!q)
332 0 : return;
333 :
334 0 : sd_bus_slot_unref(q->slot);
335 :
336 0 : if (q->registry && q->request)
337 0 : hashmap_remove(q->registry, q->request);
338 :
339 0 : sd_bus_message_unref(q->request);
340 0 : sd_bus_message_unref(q->reply);
341 :
342 0 : free(q);
343 : }
344 :
345 0 : static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
346 0 : _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
347 0 : AsyncPolkitQuery *q = userdata;
348 : int r;
349 :
350 0 : assert(reply);
351 0 : assert(q);
352 :
353 0 : q->slot = sd_bus_slot_unref(q->slot);
354 0 : q->reply = sd_bus_message_ref(reply);
355 :
356 0 : r = sd_bus_message_rewind(q->request, true);
357 0 : if (r < 0) {
358 0 : r = sd_bus_reply_method_errno(q->request, r, NULL);
359 0 : goto finish;
360 : }
361 :
362 0 : r = q->callback(q->request, q->userdata, &error_buffer);
363 0 : r = bus_maybe_reply_error(q->request, r, &error_buffer);
364 :
365 0 : finish:
366 0 : async_polkit_query_free(q);
367 :
368 0 : return r;
369 : }
370 :
371 : #endif
372 :
373 0 : int bus_verify_polkit_async(
374 : sd_bus_message *call,
375 : int capability,
376 : const char *action,
377 : const char **details,
378 : bool interactive,
379 : uid_t good_user,
380 : Hashmap **registry,
381 : sd_bus_error *error) {
382 :
383 : #if ENABLE_POLKIT
384 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL;
385 : AsyncPolkitQuery *q;
386 : const char *sender, **k, **v;
387 : sd_bus_message_handler_t callback;
388 : void *userdata;
389 : int c;
390 : #endif
391 : int r;
392 :
393 0 : assert(call);
394 0 : assert(action);
395 0 : assert(registry);
396 :
397 0 : r = check_good_user(call, good_user);
398 0 : if (r != 0)
399 0 : return r;
400 :
401 : #if ENABLE_POLKIT
402 0 : q = hashmap_get(*registry, call);
403 0 : if (q) {
404 : int authorized, challenge;
405 :
406 : /* This is the second invocation of this function, and
407 : * there's already a response from polkit, let's
408 : * process it */
409 0 : assert(q->reply);
410 :
411 0 : if (sd_bus_message_is_method_error(q->reply, NULL)) {
412 : const sd_bus_error *e;
413 :
414 0 : e = sd_bus_message_get_error(q->reply);
415 :
416 : /* Treat no PK available as access denied */
417 0 : if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
418 0 : return -EACCES;
419 :
420 : /* Copy error from polkit reply */
421 0 : sd_bus_error_copy(error, e);
422 0 : return -sd_bus_error_get_errno(e);
423 : }
424 :
425 0 : r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
426 0 : if (r >= 0)
427 0 : r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
428 :
429 0 : if (r < 0)
430 0 : return r;
431 :
432 0 : if (authorized)
433 0 : return 1;
434 :
435 0 : if (challenge)
436 0 : return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
437 :
438 0 : return -EACCES;
439 : }
440 : #endif
441 :
442 0 : r = sd_bus_query_sender_privilege(call, capability);
443 0 : if (r < 0)
444 0 : return r;
445 0 : else if (r > 0)
446 0 : return 1;
447 :
448 : #if ENABLE_POLKIT
449 0 : if (sd_bus_get_current_message(call->bus) != call)
450 0 : return -EINVAL;
451 :
452 0 : callback = sd_bus_get_current_handler(call->bus);
453 0 : if (!callback)
454 0 : return -EINVAL;
455 :
456 0 : userdata = sd_bus_get_current_userdata(call->bus);
457 :
458 0 : sender = sd_bus_message_get_sender(call);
459 0 : if (!sender)
460 0 : return -EBADMSG;
461 :
462 0 : c = sd_bus_message_get_allow_interactive_authorization(call);
463 0 : if (c < 0)
464 0 : return c;
465 0 : if (c > 0)
466 0 : interactive = true;
467 :
468 0 : r = hashmap_ensure_allocated(registry, NULL);
469 0 : if (r < 0)
470 0 : return r;
471 :
472 0 : r = sd_bus_message_new_method_call(
473 : call->bus,
474 : &pk,
475 : "org.freedesktop.PolicyKit1",
476 : "/org/freedesktop/PolicyKit1/Authority",
477 : "org.freedesktop.PolicyKit1.Authority",
478 : "CheckAuthorization");
479 0 : if (r < 0)
480 0 : return r;
481 :
482 0 : r = sd_bus_message_append(
483 : pk,
484 : "(sa{sv})s",
485 : "system-bus-name", 1, "name", "s", sender,
486 : action);
487 0 : if (r < 0)
488 0 : return r;
489 :
490 0 : r = sd_bus_message_open_container(pk, 'a', "{ss}");
491 0 : if (r < 0)
492 0 : return r;
493 :
494 0 : STRV_FOREACH_PAIR(k, v, details) {
495 0 : r = sd_bus_message_append(pk, "{ss}", *k, *v);
496 0 : if (r < 0)
497 0 : return r;
498 : }
499 :
500 0 : r = sd_bus_message_close_container(pk);
501 0 : if (r < 0)
502 0 : return r;
503 :
504 0 : r = sd_bus_message_append(pk, "us", interactive, NULL);
505 0 : if (r < 0)
506 0 : return r;
507 :
508 0 : q = new0(AsyncPolkitQuery, 1);
509 0 : if (!q)
510 0 : return -ENOMEM;
511 :
512 0 : q->request = sd_bus_message_ref(call);
513 0 : q->callback = callback;
514 0 : q->userdata = userdata;
515 :
516 0 : r = hashmap_put(*registry, call, q);
517 0 : if (r < 0) {
518 0 : async_polkit_query_free(q);
519 0 : return r;
520 : }
521 :
522 0 : q->registry = *registry;
523 :
524 0 : r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0);
525 0 : if (r < 0) {
526 0 : async_polkit_query_free(q);
527 0 : return r;
528 : }
529 :
530 0 : return 0;
531 : #endif
532 :
533 : return -EACCES;
534 : }
535 :
536 17 : void bus_verify_polkit_async_registry_free(Hashmap *registry) {
537 : #if ENABLE_POLKIT
538 17 : hashmap_free_with_destructor(registry, async_polkit_query_free);
539 : #endif
540 17 : }
541 :
542 0 : int bus_check_peercred(sd_bus *c) {
543 : struct ucred ucred;
544 : int fd, r;
545 :
546 0 : assert(c);
547 :
548 0 : fd = sd_bus_get_fd(c);
549 0 : if (fd < 0)
550 0 : return fd;
551 :
552 0 : r = getpeercred(fd, &ucred);
553 0 : if (r < 0)
554 0 : return r;
555 :
556 0 : if (ucred.uid != 0 && ucred.uid != geteuid())
557 0 : return -EPERM;
558 :
559 0 : return 1;
560 : }
561 :
562 0 : int bus_connect_system_systemd(sd_bus **_bus) {
563 0 : _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
564 : int r;
565 :
566 0 : assert(_bus);
567 :
568 0 : if (geteuid() != 0)
569 0 : return sd_bus_default_system(_bus);
570 :
571 : /* If we are root then let's talk directly to the system
572 : * instance, instead of going via the bus */
573 :
574 0 : r = sd_bus_new(&bus);
575 0 : if (r < 0)
576 0 : return r;
577 :
578 0 : r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
579 0 : if (r < 0)
580 0 : return r;
581 :
582 0 : r = sd_bus_start(bus);
583 0 : if (r < 0)
584 0 : return sd_bus_default_system(_bus);
585 :
586 0 : r = bus_check_peercred(bus);
587 0 : if (r < 0)
588 0 : return r;
589 :
590 0 : *_bus = TAKE_PTR(bus);
591 :
592 0 : return 0;
593 : }
594 :
595 0 : int bus_connect_user_systemd(sd_bus **_bus) {
596 0 : _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
597 0 : _cleanup_free_ char *ee = NULL;
598 : const char *e;
599 : int r;
600 :
601 0 : assert(_bus);
602 :
603 0 : e = secure_getenv("XDG_RUNTIME_DIR");
604 0 : if (!e)
605 0 : return sd_bus_default_user(_bus);
606 :
607 0 : ee = bus_address_escape(e);
608 0 : if (!ee)
609 0 : return -ENOMEM;
610 :
611 0 : r = sd_bus_new(&bus);
612 0 : if (r < 0)
613 0 : return r;
614 :
615 0 : bus->address = strjoin("unix:path=", ee, "/systemd/private");
616 0 : if (!bus->address)
617 0 : return -ENOMEM;
618 :
619 0 : r = sd_bus_start(bus);
620 0 : if (r < 0)
621 0 : return sd_bus_default_user(_bus);
622 :
623 0 : r = bus_check_peercred(bus);
624 0 : if (r < 0)
625 0 : return r;
626 :
627 0 : *_bus = TAKE_PTR(bus);
628 :
629 0 : return 0;
630 : }
631 :
632 0 : int bus_print_property_value(const char *name, const char *expected_value, bool only_value, const char *value) {
633 0 : assert(name);
634 :
635 0 : if (expected_value && !streq_ptr(expected_value, value))
636 0 : return 0;
637 :
638 0 : if (only_value)
639 0 : puts(value);
640 : else
641 0 : printf("%s=%s\n", name, value);
642 :
643 0 : return 0;
644 : }
645 :
646 0 : int bus_print_property_valuef(const char *name, const char *expected_value, bool only_value, const char *fmt, ...) {
647 : va_list ap;
648 : int r;
649 :
650 0 : assert(name);
651 0 : assert(fmt);
652 :
653 0 : if (expected_value) {
654 0 : _cleanup_free_ char *s = NULL;
655 :
656 0 : va_start(ap, fmt);
657 0 : r = vasprintf(&s, fmt, ap);
658 0 : va_end(ap);
659 0 : if (r < 0)
660 0 : return -ENOMEM;
661 :
662 0 : if (streq_ptr(expected_value, s)) {
663 0 : if (only_value)
664 0 : puts(s);
665 : else
666 0 : printf("%s=%s\n", name, s);
667 : }
668 :
669 0 : return 0;
670 : }
671 :
672 0 : if (!only_value)
673 0 : printf("%s=", name);
674 0 : va_start(ap, fmt);
675 0 : vprintf(fmt, ap);
676 0 : va_end(ap);
677 0 : puts("");
678 :
679 0 : return 0;
680 : }
681 :
682 0 : static int bus_print_property(const char *name, const char *expected_value, sd_bus_message *m, bool value, bool all) {
683 : char type;
684 : const char *contents;
685 : int r;
686 :
687 0 : assert(name);
688 0 : assert(m);
689 :
690 0 : r = sd_bus_message_peek_type(m, &type, &contents);
691 0 : if (r < 0)
692 0 : return r;
693 :
694 0 : switch (type) {
695 :
696 0 : case SD_BUS_TYPE_STRING: {
697 : const char *s;
698 :
699 0 : r = sd_bus_message_read_basic(m, type, &s);
700 0 : if (r < 0)
701 0 : return r;
702 :
703 0 : if (all || !isempty(s)) {
704 : bool good;
705 :
706 : /* This property has a single value, so we need to take
707 : * care not to print a new line, everything else is OK. */
708 0 : good = !strchr(s, '\n');
709 0 : bus_print_property_value(name, expected_value, value, good ? s : "[unprintable]");
710 : }
711 :
712 0 : return 1;
713 : }
714 :
715 0 : case SD_BUS_TYPE_BOOLEAN: {
716 : int b;
717 :
718 0 : r = sd_bus_message_read_basic(m, type, &b);
719 0 : if (r < 0)
720 0 : return r;
721 :
722 0 : if (expected_value && parse_boolean(expected_value) != b)
723 0 : return 1;
724 :
725 0 : bus_print_property_value(name, NULL, value, yes_no(b));
726 0 : return 1;
727 : }
728 :
729 0 : case SD_BUS_TYPE_UINT64: {
730 : uint64_t u;
731 :
732 0 : r = sd_bus_message_read_basic(m, type, &u);
733 0 : if (r < 0)
734 0 : return r;
735 :
736 : /* Yes, heuristics! But we can change this check
737 : * should it turn out to not be sufficient */
738 :
739 0 : if (endswith(name, "Timestamp") ||
740 0 : STR_IN_SET(name, "NextElapseUSecRealtime", "LastTriggerUSec", "TimeUSec", "RTCTimeUSec")) {
741 : char timestamp[FORMAT_TIMESTAMP_MAX];
742 : const char *t;
743 :
744 0 : t = format_timestamp(timestamp, sizeof(timestamp), u);
745 0 : if (t || all)
746 0 : bus_print_property_value(name, expected_value, value, strempty(t));
747 :
748 0 : } else if (strstr(name, "USec")) {
749 : char timespan[FORMAT_TIMESPAN_MAX];
750 :
751 0 : (void) format_timespan(timespan, sizeof(timespan), u, 0);
752 0 : bus_print_property_value(name, expected_value, value, timespan);
753 :
754 0 : } else if (streq(name, "RestrictNamespaces")) {
755 0 : _cleanup_free_ char *s = NULL;
756 : const char *result;
757 :
758 0 : if ((u & NAMESPACE_FLAGS_ALL) == 0)
759 0 : result = "yes";
760 0 : else if (FLAGS_SET(u, NAMESPACE_FLAGS_ALL))
761 0 : result = "no";
762 : else {
763 0 : r = namespace_flags_to_string(u, &s);
764 0 : if (r < 0)
765 0 : return r;
766 :
767 0 : result = s;
768 : }
769 :
770 0 : bus_print_property_value(name, expected_value, value, result);
771 :
772 0 : } else if (streq(name, "MountFlags")) {
773 : const char *result;
774 :
775 0 : result = mount_propagation_flags_to_string(u);
776 0 : if (!result)
777 0 : return -EINVAL;
778 :
779 0 : bus_print_property_value(name, expected_value, value, result);
780 :
781 0 : } else if (STR_IN_SET(name, "CapabilityBoundingSet", "AmbientCapabilities")) {
782 0 : _cleanup_free_ char *s = NULL;
783 :
784 0 : r = capability_set_to_string_alloc(u, &s);
785 0 : if (r < 0)
786 0 : return r;
787 :
788 0 : bus_print_property_value(name, expected_value, value, s);
789 :
790 0 : } else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) ||
791 0 : (STR_IN_SET(name, "CPUShares", "StartupCPUShares") && u == CGROUP_CPU_SHARES_INVALID) ||
792 0 : (STR_IN_SET(name, "BlockIOWeight", "StartupBlockIOWeight") && u == CGROUP_BLKIO_WEIGHT_INVALID) ||
793 0 : (STR_IN_SET(name, "MemoryCurrent", "TasksCurrent") && u == (uint64_t) -1) ||
794 0 : (endswith(name, "NSec") && u == (uint64_t) -1))
795 :
796 0 : bus_print_property_value(name, expected_value, value, "[not set]");
797 :
798 0 : else if ((STR_IN_SET(name, "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit") && u == CGROUP_LIMIT_MAX) ||
799 0 : (STR_IN_SET(name, "TasksMax", "DefaultTasksMax") && u == (uint64_t) -1) ||
800 0 : (startswith(name, "Limit") && u == (uint64_t) -1) ||
801 0 : (startswith(name, "DefaultLimit") && u == (uint64_t) -1))
802 :
803 0 : bus_print_property_value(name, expected_value, value, "infinity");
804 0 : else if (STR_IN_SET(name, "IPIngressBytes", "IPIngressPackets", "IPEgressBytes", "IPEgressPackets") && u == (uint64_t) -1)
805 0 : bus_print_property_value(name, expected_value, value, "[no data]");
806 : else
807 0 : bus_print_property_valuef(name, expected_value, value, "%"PRIu64, u);
808 :
809 0 : return 1;
810 : }
811 :
812 0 : case SD_BUS_TYPE_INT64: {
813 : int64_t i;
814 :
815 0 : r = sd_bus_message_read_basic(m, type, &i);
816 0 : if (r < 0)
817 0 : return r;
818 :
819 0 : bus_print_property_valuef(name, expected_value, value, "%"PRIi64, i);
820 0 : return 1;
821 : }
822 :
823 0 : case SD_BUS_TYPE_UINT32: {
824 : uint32_t u;
825 :
826 0 : r = sd_bus_message_read_basic(m, type, &u);
827 0 : if (r < 0)
828 0 : return r;
829 :
830 0 : if (strstr(name, "UMask") || strstr(name, "Mode"))
831 0 : bus_print_property_valuef(name, expected_value, value, "%04o", u);
832 :
833 0 : else if (streq(name, "UID")) {
834 0 : if (u == UID_INVALID)
835 0 : bus_print_property_value(name, expected_value, value, "[not set]");
836 : else
837 0 : bus_print_property_valuef(name, expected_value, value, "%"PRIu32, u);
838 0 : } else if (streq(name, "GID")) {
839 0 : if (u == GID_INVALID)
840 0 : bus_print_property_value(name, expected_value, value, "[not set]");
841 : else
842 0 : bus_print_property_valuef(name, expected_value, value, "%"PRIu32, u);
843 : } else
844 0 : bus_print_property_valuef(name, expected_value, value, "%"PRIu32, u);
845 :
846 0 : return 1;
847 : }
848 :
849 0 : case SD_BUS_TYPE_INT32: {
850 : int32_t i;
851 :
852 0 : r = sd_bus_message_read_basic(m, type, &i);
853 0 : if (r < 0)
854 0 : return r;
855 :
856 0 : bus_print_property_valuef(name, expected_value, value, "%"PRIi32, i);
857 0 : return 1;
858 : }
859 :
860 0 : case SD_BUS_TYPE_DOUBLE: {
861 : double d;
862 :
863 0 : r = sd_bus_message_read_basic(m, type, &d);
864 0 : if (r < 0)
865 0 : return r;
866 :
867 0 : bus_print_property_valuef(name, expected_value, value, "%g", d);
868 0 : return 1;
869 : }
870 :
871 0 : case SD_BUS_TYPE_ARRAY:
872 0 : if (streq(contents, "s")) {
873 0 : bool first = true;
874 : const char *str;
875 :
876 0 : r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, contents);
877 0 : if (r < 0)
878 0 : return r;
879 :
880 0 : while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &str)) > 0) {
881 : bool good;
882 :
883 0 : if (first && !value)
884 0 : printf("%s=", name);
885 :
886 : /* This property has multiple space-separated values, so
887 : * neither spaces nor newlines can be allowed in a value. */
888 0 : good = str[strcspn(str, " \n")] == '\0';
889 :
890 0 : printf("%s%s", first ? "" : " ", good ? str : "[unprintable]");
891 :
892 0 : first = false;
893 : }
894 0 : if (r < 0)
895 0 : return r;
896 :
897 0 : if (first && all && !value)
898 0 : printf("%s=", name);
899 0 : if (!first || all)
900 0 : puts("");
901 :
902 0 : r = sd_bus_message_exit_container(m);
903 0 : if (r < 0)
904 0 : return r;
905 :
906 0 : return 1;
907 :
908 0 : } else if (streq(contents, "y")) {
909 : const uint8_t *u;
910 : size_t n;
911 :
912 0 : r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
913 0 : if (r < 0)
914 0 : return r;
915 :
916 0 : if (all || n > 0) {
917 : unsigned i;
918 :
919 0 : if (!value)
920 0 : printf("%s=", name);
921 :
922 0 : for (i = 0; i < n; i++)
923 0 : printf("%02x", u[i]);
924 :
925 0 : puts("");
926 : }
927 :
928 0 : return 1;
929 :
930 0 : } else if (streq(contents, "u")) {
931 : uint32_t *u;
932 : size_t n;
933 :
934 0 : r = sd_bus_message_read_array(m, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
935 0 : if (r < 0)
936 0 : return r;
937 :
938 0 : if (all || n > 0) {
939 : unsigned i;
940 :
941 0 : if (!value)
942 0 : printf("%s=", name);
943 :
944 0 : for (i = 0; i < n; i++)
945 0 : printf("%08x", u[i]);
946 :
947 0 : puts("");
948 : }
949 :
950 0 : return 1;
951 : }
952 :
953 0 : break;
954 : }
955 :
956 0 : return 0;
957 : }
958 :
959 0 : int bus_message_print_all_properties(
960 : sd_bus_message *m,
961 : bus_message_print_t func,
962 : char **filter,
963 : bool value,
964 : bool all,
965 : Set **found_properties) {
966 :
967 : int r;
968 :
969 0 : assert(m);
970 :
971 0 : r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
972 0 : if (r < 0)
973 0 : return r;
974 :
975 0 : while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
976 0 : _cleanup_free_ char *name_with_equal = NULL;
977 0 : const char *name, *contents, *expected_value = NULL;
978 :
979 0 : r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &name);
980 0 : if (r < 0)
981 0 : return r;
982 :
983 0 : if (found_properties) {
984 0 : r = set_ensure_allocated(found_properties, &string_hash_ops);
985 0 : if (r < 0)
986 0 : return log_oom();
987 :
988 0 : r = set_put(*found_properties, name);
989 0 : if (r < 0 && r != -EEXIST)
990 0 : return log_oom();
991 : }
992 :
993 0 : name_with_equal = strjoin(name, "=");
994 0 : if (!name_with_equal)
995 0 : return log_oom();
996 :
997 0 : if (!filter || strv_find(filter, name) ||
998 0 : (expected_value = strv_find_startswith(filter, name_with_equal))) {
999 0 : r = sd_bus_message_peek_type(m, NULL, &contents);
1000 0 : if (r < 0)
1001 0 : return r;
1002 :
1003 0 : r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1004 0 : if (r < 0)
1005 0 : return r;
1006 :
1007 0 : if (func)
1008 0 : r = func(name, expected_value, m, value, all);
1009 0 : if (!func || r == 0)
1010 0 : r = bus_print_property(name, expected_value, m, value, all);
1011 0 : if (r < 0)
1012 0 : return r;
1013 0 : if (r == 0) {
1014 0 : if (all && !expected_value)
1015 0 : printf("%s=[unprintable]\n", name);
1016 : /* skip what we didn't read */
1017 0 : r = sd_bus_message_skip(m, contents);
1018 0 : if (r < 0)
1019 0 : return r;
1020 : }
1021 :
1022 0 : r = sd_bus_message_exit_container(m);
1023 0 : if (r < 0)
1024 0 : return r;
1025 : } else {
1026 0 : r = sd_bus_message_skip(m, "v");
1027 0 : if (r < 0)
1028 0 : return r;
1029 : }
1030 :
1031 0 : r = sd_bus_message_exit_container(m);
1032 0 : if (r < 0)
1033 0 : return r;
1034 : }
1035 0 : if (r < 0)
1036 0 : return r;
1037 :
1038 0 : r = sd_bus_message_exit_container(m);
1039 0 : if (r < 0)
1040 0 : return r;
1041 :
1042 0 : return 0;
1043 : }
1044 :
1045 0 : int bus_print_all_properties(
1046 : sd_bus *bus,
1047 : const char *dest,
1048 : const char *path,
1049 : bus_message_print_t func,
1050 : char **filter,
1051 : bool value,
1052 : bool all,
1053 : Set **found_properties) {
1054 :
1055 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1056 0 : _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1057 : int r;
1058 :
1059 0 : assert(bus);
1060 0 : assert(path);
1061 :
1062 0 : r = sd_bus_call_method(bus,
1063 : dest,
1064 : path,
1065 : "org.freedesktop.DBus.Properties",
1066 : "GetAll",
1067 : &error,
1068 : &reply,
1069 : "s", "");
1070 0 : if (r < 0)
1071 0 : return r;
1072 :
1073 0 : return bus_message_print_all_properties(reply, func, filter, value, all, found_properties);
1074 : }
1075 :
1076 0 : int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1077 0 : sd_id128_t *p = userdata;
1078 : const void *v;
1079 : size_t n;
1080 : int r;
1081 :
1082 0 : r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
1083 0 : if (r < 0)
1084 0 : return r;
1085 :
1086 0 : if (n == 0)
1087 0 : *p = SD_ID128_NULL;
1088 0 : else if (n == 16)
1089 0 : memcpy((*p).bytes, v, n);
1090 : else
1091 0 : return -EINVAL;
1092 :
1093 0 : return 0;
1094 : }
1095 :
1096 0 : static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, unsigned flags, sd_bus_error *error, void *userdata) {
1097 : char type;
1098 : int r;
1099 :
1100 0 : r = sd_bus_message_peek_type(m, &type, NULL);
1101 0 : if (r < 0)
1102 0 : return r;
1103 :
1104 0 : switch (type) {
1105 :
1106 0 : case SD_BUS_TYPE_STRING: {
1107 0 : const char **p = userdata;
1108 : const char *s;
1109 :
1110 0 : r = sd_bus_message_read_basic(m, type, &s);
1111 0 : if (r < 0)
1112 0 : return r;
1113 :
1114 0 : if (isempty(s))
1115 0 : s = NULL;
1116 :
1117 0 : if (flags & BUS_MAP_STRDUP)
1118 0 : return free_and_strdup((char **) userdata, s);
1119 :
1120 0 : *p = s;
1121 0 : return 0;
1122 : }
1123 :
1124 0 : case SD_BUS_TYPE_ARRAY: {
1125 0 : _cleanup_strv_free_ char **l = NULL;
1126 0 : char ***p = userdata;
1127 :
1128 0 : r = bus_message_read_strv_extend(m, &l);
1129 0 : if (r < 0)
1130 0 : return r;
1131 :
1132 0 : return strv_free_and_replace(*p, l);
1133 : }
1134 :
1135 0 : case SD_BUS_TYPE_BOOLEAN: {
1136 : int b;
1137 :
1138 0 : r = sd_bus_message_read_basic(m, type, &b);
1139 0 : if (r < 0)
1140 0 : return r;
1141 :
1142 0 : if (flags & BUS_MAP_BOOLEAN_AS_BOOL)
1143 0 : *(bool*) userdata = b;
1144 : else
1145 0 : *(int*) userdata = b;
1146 :
1147 0 : return 0;
1148 : }
1149 :
1150 0 : case SD_BUS_TYPE_INT32:
1151 : case SD_BUS_TYPE_UINT32: {
1152 0 : uint32_t u, *p = userdata;
1153 :
1154 0 : r = sd_bus_message_read_basic(m, type, &u);
1155 0 : if (r < 0)
1156 0 : return r;
1157 :
1158 0 : *p = u;
1159 0 : return 0;
1160 : }
1161 :
1162 0 : case SD_BUS_TYPE_INT64:
1163 : case SD_BUS_TYPE_UINT64: {
1164 0 : uint64_t t, *p = userdata;
1165 :
1166 0 : r = sd_bus_message_read_basic(m, type, &t);
1167 0 : if (r < 0)
1168 0 : return r;
1169 :
1170 0 : *p = t;
1171 0 : return 0;
1172 : }
1173 :
1174 0 : case SD_BUS_TYPE_DOUBLE: {
1175 0 : double d, *p = userdata;
1176 :
1177 0 : r = sd_bus_message_read_basic(m, type, &d);
1178 0 : if (r < 0)
1179 0 : return r;
1180 :
1181 0 : *p = d;
1182 0 : return 0;
1183 : }}
1184 :
1185 0 : return -EOPNOTSUPP;
1186 : }
1187 :
1188 0 : int bus_message_map_all_properties(
1189 : sd_bus_message *m,
1190 : const struct bus_properties_map *map,
1191 : unsigned flags,
1192 : sd_bus_error *error,
1193 : void *userdata) {
1194 :
1195 : int r;
1196 :
1197 0 : assert(m);
1198 0 : assert(map);
1199 :
1200 0 : r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
1201 0 : if (r < 0)
1202 0 : return r;
1203 :
1204 0 : while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
1205 : const struct bus_properties_map *prop;
1206 : const char *member;
1207 : const char *contents;
1208 : void *v;
1209 : unsigned i;
1210 :
1211 0 : r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
1212 0 : if (r < 0)
1213 0 : return r;
1214 :
1215 0 : for (i = 0, prop = NULL; map[i].member; i++)
1216 0 : if (streq(map[i].member, member)) {
1217 0 : prop = &map[i];
1218 0 : break;
1219 : }
1220 :
1221 0 : if (prop) {
1222 0 : r = sd_bus_message_peek_type(m, NULL, &contents);
1223 0 : if (r < 0)
1224 0 : return r;
1225 :
1226 0 : r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1227 0 : if (r < 0)
1228 0 : return r;
1229 :
1230 0 : v = (uint8_t *)userdata + prop->offset;
1231 0 : if (map[i].set)
1232 0 : r = prop->set(sd_bus_message_get_bus(m), member, m, error, v);
1233 : else
1234 0 : r = map_basic(sd_bus_message_get_bus(m), member, m, flags, error, v);
1235 0 : if (r < 0)
1236 0 : return r;
1237 :
1238 0 : r = sd_bus_message_exit_container(m);
1239 0 : if (r < 0)
1240 0 : return r;
1241 : } else {
1242 0 : r = sd_bus_message_skip(m, "v");
1243 0 : if (r < 0)
1244 0 : return r;
1245 : }
1246 :
1247 0 : r = sd_bus_message_exit_container(m);
1248 0 : if (r < 0)
1249 0 : return r;
1250 : }
1251 0 : if (r < 0)
1252 0 : return r;
1253 :
1254 0 : return sd_bus_message_exit_container(m);
1255 : }
1256 :
1257 0 : int bus_map_all_properties(
1258 : sd_bus *bus,
1259 : const char *destination,
1260 : const char *path,
1261 : const struct bus_properties_map *map,
1262 : unsigned flags,
1263 : sd_bus_error *error,
1264 : sd_bus_message **reply,
1265 : void *userdata) {
1266 :
1267 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1268 : int r;
1269 :
1270 0 : assert(bus);
1271 0 : assert(destination);
1272 0 : assert(path);
1273 0 : assert(map);
1274 0 : assert(reply || (flags & BUS_MAP_STRDUP));
1275 :
1276 0 : r = sd_bus_call_method(
1277 : bus,
1278 : destination,
1279 : path,
1280 : "org.freedesktop.DBus.Properties",
1281 : "GetAll",
1282 : error,
1283 : &m,
1284 : "s", "");
1285 0 : if (r < 0)
1286 0 : return r;
1287 :
1288 0 : r = bus_message_map_all_properties(m, map, flags, error, userdata);
1289 0 : if (r < 0)
1290 0 : return r;
1291 :
1292 0 : if (reply)
1293 0 : *reply = sd_bus_message_ref(m);
1294 :
1295 0 : return r;
1296 : }
1297 :
1298 0 : int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **ret) {
1299 0 : _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
1300 : int r;
1301 :
1302 0 : assert(transport >= 0);
1303 0 : assert(transport < _BUS_TRANSPORT_MAX);
1304 0 : assert(ret);
1305 :
1306 0 : assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1307 0 : assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
1308 :
1309 0 : switch (transport) {
1310 :
1311 0 : case BUS_TRANSPORT_LOCAL:
1312 0 : if (user)
1313 0 : r = sd_bus_default_user(&bus);
1314 : else {
1315 0 : if (sd_booted() <= 0) {
1316 : /* Print a friendly message when the local system is actually not running systemd as PID 1. */
1317 0 : log_error("System has not been booted with systemd as init system (PID 1). Can't operate.");
1318 :
1319 0 : return -EHOSTDOWN;
1320 : }
1321 0 : r = sd_bus_default_system(&bus);
1322 : }
1323 0 : break;
1324 :
1325 0 : case BUS_TRANSPORT_REMOTE:
1326 0 : r = sd_bus_open_system_remote(&bus, host);
1327 0 : break;
1328 :
1329 0 : case BUS_TRANSPORT_MACHINE:
1330 0 : r = sd_bus_open_system_machine(&bus, host);
1331 0 : break;
1332 :
1333 0 : default:
1334 0 : assert_not_reached("Hmm, unknown transport type.");
1335 : }
1336 0 : if (r < 0)
1337 0 : return r;
1338 :
1339 0 : r = sd_bus_set_exit_on_disconnect(bus, true);
1340 0 : if (r < 0)
1341 0 : return r;
1342 :
1343 0 : *ret = TAKE_PTR(bus);
1344 :
1345 0 : return 0;
1346 : }
1347 :
1348 0 : int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1349 : int r;
1350 :
1351 0 : assert(transport >= 0);
1352 0 : assert(transport < _BUS_TRANSPORT_MAX);
1353 0 : assert(bus);
1354 :
1355 0 : assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1356 0 : assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
1357 :
1358 0 : switch (transport) {
1359 :
1360 0 : case BUS_TRANSPORT_LOCAL:
1361 0 : if (user)
1362 0 : r = bus_connect_user_systemd(bus);
1363 : else {
1364 0 : if (sd_booted() <= 0)
1365 : /* Print a friendly message when the local system is actually not running systemd as PID 1. */
1366 0 : return log_error_errno(SYNTHETIC_ERRNO(EHOSTDOWN),
1367 : "System has not been booted with systemd as init system (PID 1). Can't operate.");
1368 0 : r = bus_connect_system_systemd(bus);
1369 : }
1370 0 : break;
1371 :
1372 0 : case BUS_TRANSPORT_REMOTE:
1373 0 : r = sd_bus_open_system_remote(bus, host);
1374 0 : break;
1375 :
1376 0 : case BUS_TRANSPORT_MACHINE:
1377 0 : r = sd_bus_open_system_machine(bus, host);
1378 0 : break;
1379 :
1380 0 : default:
1381 0 : assert_not_reached("Hmm, unknown transport type.");
1382 : }
1383 :
1384 0 : return r;
1385 : }
1386 :
1387 0 : int bus_property_get_bool(
1388 : sd_bus *bus,
1389 : const char *path,
1390 : const char *interface,
1391 : const char *property,
1392 : sd_bus_message *reply,
1393 : void *userdata,
1394 : sd_bus_error *error) {
1395 :
1396 0 : int b = *(bool*) userdata;
1397 :
1398 0 : return sd_bus_message_append_basic(reply, 'b', &b);
1399 : }
1400 :
1401 0 : int bus_property_set_bool(
1402 : sd_bus *bus,
1403 : const char *path,
1404 : const char *interface,
1405 : const char *property,
1406 : sd_bus_message *value,
1407 : void *userdata,
1408 : sd_bus_error *error) {
1409 :
1410 : int b, r;
1411 :
1412 0 : r = sd_bus_message_read(value, "b", &b);
1413 0 : if (r < 0)
1414 0 : return r;
1415 :
1416 0 : *(bool*) userdata = b;
1417 0 : return 0;
1418 : }
1419 :
1420 0 : int bus_property_get_id128(
1421 : sd_bus *bus,
1422 : const char *path,
1423 : const char *interface,
1424 : const char *property,
1425 : sd_bus_message *reply,
1426 : void *userdata,
1427 : sd_bus_error *error) {
1428 :
1429 0 : sd_id128_t *id = userdata;
1430 :
1431 0 : if (sd_id128_is_null(*id)) /* Add an empty array if the ID is zero */
1432 0 : return sd_bus_message_append(reply, "ay", 0);
1433 : else
1434 0 : return sd_bus_message_append_array(reply, 'y', id->bytes, 16);
1435 : }
1436 :
1437 : #if __SIZEOF_SIZE_T__ != 8
1438 : int bus_property_get_size(
1439 : sd_bus *bus,
1440 : const char *path,
1441 : const char *interface,
1442 : const char *property,
1443 : sd_bus_message *reply,
1444 : void *userdata,
1445 : sd_bus_error *error) {
1446 :
1447 : uint64_t sz = *(size_t*) userdata;
1448 :
1449 : return sd_bus_message_append_basic(reply, 't', &sz);
1450 : }
1451 : #endif
1452 :
1453 : #if __SIZEOF_LONG__ != 8
1454 : int bus_property_get_long(
1455 : sd_bus *bus,
1456 : const char *path,
1457 : const char *interface,
1458 : const char *property,
1459 : sd_bus_message *reply,
1460 : void *userdata,
1461 : sd_bus_error *error) {
1462 :
1463 : int64_t l = *(long*) userdata;
1464 :
1465 : return sd_bus_message_append_basic(reply, 'x', &l);
1466 : }
1467 :
1468 : int bus_property_get_ulong(
1469 : sd_bus *bus,
1470 : const char *path,
1471 : const char *interface,
1472 : const char *property,
1473 : sd_bus_message *reply,
1474 : void *userdata,
1475 : sd_bus_error *error) {
1476 :
1477 : uint64_t ul = *(unsigned long*) userdata;
1478 :
1479 : return sd_bus_message_append_basic(reply, 't', &ul);
1480 : }
1481 : #endif
1482 :
1483 : /**
1484 : * bus_path_encode_unique() - encode unique object path
1485 : * @b: bus connection or NULL
1486 : * @prefix: object path prefix
1487 : * @sender_id: unique-name of client, or NULL
1488 : * @external_id: external ID to be chosen by client, or NULL
1489 : * @ret_path: storage for encoded object path pointer
1490 : *
1491 : * Whenever we provide a bus API that allows clients to create and manage
1492 : * server-side objects, we need to provide a unique name for these objects. If
1493 : * we let the server choose the name, we suffer from a race condition: If a
1494 : * client creates an object asynchronously, it cannot destroy that object until
1495 : * it received the method reply. It cannot know the name of the new object,
1496 : * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
1497 : *
1498 : * Therefore, many APIs allow the client to choose the unique name for newly
1499 : * created objects. There're two problems to solve, though:
1500 : * 1) Object names are usually defined via dbus object paths, which are
1501 : * usually globally namespaced. Therefore, multiple clients must be able
1502 : * to choose unique object names without interference.
1503 : * 2) If multiple libraries share the same bus connection, they must be
1504 : * able to choose unique object names without interference.
1505 : * The first problem is solved easily by prefixing a name with the
1506 : * unique-bus-name of a connection. The server side must enforce this and
1507 : * reject any other name. The second problem is solved by providing unique
1508 : * suffixes from within sd-bus.
1509 : *
1510 : * This helper allows clients to create unique object-paths. It uses the
1511 : * template '/prefix/sender_id/external_id' and returns the new path in
1512 : * @ret_path (must be freed by the caller).
1513 : * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
1514 : * NULL, this function allocates a unique suffix via @b (by requesting a new
1515 : * cookie). If both @sender_id and @external_id are given, @b can be passed as
1516 : * NULL.
1517 : *
1518 : * Returns: 0 on success, negative error code on failure.
1519 : */
1520 1 : int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
1521 1 : _cleanup_free_ char *sender_label = NULL, *external_label = NULL;
1522 : char external_buf[DECIMAL_STR_MAX(uint64_t)], *p;
1523 : int r;
1524 :
1525 1 : assert_return(b || (sender_id && external_id), -EINVAL);
1526 1 : assert_return(object_path_is_valid(prefix), -EINVAL);
1527 1 : assert_return(ret_path, -EINVAL);
1528 :
1529 1 : if (!sender_id) {
1530 0 : r = sd_bus_get_unique_name(b, &sender_id);
1531 0 : if (r < 0)
1532 0 : return r;
1533 : }
1534 :
1535 1 : if (!external_id) {
1536 0 : xsprintf(external_buf, "%"PRIu64, ++b->cookie);
1537 0 : external_id = external_buf;
1538 : }
1539 :
1540 1 : sender_label = bus_label_escape(sender_id);
1541 1 : if (!sender_label)
1542 0 : return -ENOMEM;
1543 :
1544 1 : external_label = bus_label_escape(external_id);
1545 1 : if (!external_label)
1546 0 : return -ENOMEM;
1547 :
1548 1 : p = path_join(prefix, sender_label, external_label);
1549 1 : if (!p)
1550 0 : return -ENOMEM;
1551 :
1552 1 : *ret_path = p;
1553 1 : return 0;
1554 : }
1555 :
1556 : /**
1557 : * bus_path_decode_unique() - decode unique object path
1558 : * @path: object path to decode
1559 : * @prefix: object path prefix
1560 : * @ret_sender: output parameter for sender-id label
1561 : * @ret_external: output parameter for external-id label
1562 : *
1563 : * This does the reverse of bus_path_encode_unique() (see its description for
1564 : * details). Both trailing labels, sender-id and external-id, are unescaped and
1565 : * returned in the given output parameters (the caller must free them).
1566 : *
1567 : * Note that this function returns 0 if the path does not match the template
1568 : * (see bus_path_encode_unique()), 1 if it matched.
1569 : *
1570 : * Returns: Negative error code on failure, 0 if the given object path does not
1571 : * match the template (return parameters are set to NULL), 1 if it was
1572 : * parsed successfully (return parameters contain allocated labels).
1573 : */
1574 4 : int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external) {
1575 : const char *p, *q;
1576 : char *sender, *external;
1577 :
1578 4 : assert(object_path_is_valid(path));
1579 4 : assert(object_path_is_valid(prefix));
1580 4 : assert(ret_sender);
1581 4 : assert(ret_external);
1582 :
1583 4 : p = object_path_startswith(path, prefix);
1584 4 : if (!p) {
1585 1 : *ret_sender = NULL;
1586 1 : *ret_external = NULL;
1587 1 : return 0;
1588 : }
1589 :
1590 3 : q = strchr(p, '/');
1591 3 : if (!q) {
1592 1 : *ret_sender = NULL;
1593 1 : *ret_external = NULL;
1594 1 : return 0;
1595 : }
1596 :
1597 2 : sender = bus_label_unescape_n(p, q - p);
1598 2 : external = bus_label_unescape(q + 1);
1599 2 : if (!sender || !external) {
1600 0 : free(sender);
1601 0 : free(external);
1602 0 : return -ENOMEM;
1603 : }
1604 :
1605 2 : *ret_sender = sender;
1606 2 : *ret_external = external;
1607 2 : return 1;
1608 : }
1609 :
1610 0 : int bus_property_get_rlimit(
1611 : sd_bus *bus,
1612 : const char *path,
1613 : const char *interface,
1614 : const char *property,
1615 : sd_bus_message *reply,
1616 : void *userdata,
1617 : sd_bus_error *error) {
1618 :
1619 : const char *is_soft;
1620 : struct rlimit *rl;
1621 : uint64_t u;
1622 : rlim_t x;
1623 :
1624 0 : assert(bus);
1625 0 : assert(reply);
1626 0 : assert(userdata);
1627 :
1628 0 : is_soft = endswith(property, "Soft");
1629 :
1630 0 : rl = *(struct rlimit**) userdata;
1631 0 : if (rl)
1632 0 : x = is_soft ? rl->rlim_cur : rl->rlim_max;
1633 : else {
1634 0 : struct rlimit buf = {};
1635 : const char *s, *p;
1636 : int z;
1637 :
1638 : /* Chop off "Soft" suffix */
1639 0 : s = is_soft ? strndupa(property, is_soft - property) : property;
1640 :
1641 : /* Skip over any prefix, such as "Default" */
1642 0 : assert_se(p = strstr(s, "Limit"));
1643 :
1644 0 : z = rlimit_from_string(p + 5);
1645 0 : assert(z >= 0);
1646 :
1647 0 : (void) getrlimit(z, &buf);
1648 0 : x = is_soft ? buf.rlim_cur : buf.rlim_max;
1649 : }
1650 :
1651 : /* rlim_t might have different sizes, let's map RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on all
1652 : * archs */
1653 0 : u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
1654 :
1655 0 : return sd_bus_message_append(reply, "t", u);
1656 : }
1657 :
1658 0 : int bus_track_add_name_many(sd_bus_track *t, char **l) {
1659 0 : int r = 0;
1660 : char **i;
1661 :
1662 0 : assert(t);
1663 :
1664 : /* Continues adding after failure, and returns the first failure. */
1665 :
1666 0 : STRV_FOREACH(i, l) {
1667 : int k;
1668 :
1669 0 : k = sd_bus_track_add_name(t, *i);
1670 0 : if (k < 0 && r >= 0)
1671 0 : r = k;
1672 : }
1673 :
1674 0 : return r;
1675 : }
1676 :
1677 1 : int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *description) {
1678 1 : _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
1679 : const char *e;
1680 : int r;
1681 :
1682 1 : assert(ret);
1683 :
1684 : /* Match like sd_bus_open_system(), but with the "watch_bind" feature and the Connected() signal turned on. */
1685 :
1686 1 : r = sd_bus_new(&bus);
1687 1 : if (r < 0)
1688 0 : return r;
1689 :
1690 1 : if (description) {
1691 1 : r = sd_bus_set_description(bus, description);
1692 1 : if (r < 0)
1693 0 : return r;
1694 : }
1695 :
1696 1 : e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
1697 1 : if (!e)
1698 1 : e = DEFAULT_SYSTEM_BUS_ADDRESS;
1699 :
1700 1 : r = sd_bus_set_address(bus, e);
1701 1 : if (r < 0)
1702 0 : return r;
1703 :
1704 1 : r = sd_bus_set_bus_client(bus, true);
1705 1 : if (r < 0)
1706 0 : return r;
1707 :
1708 1 : r = sd_bus_set_trusted(bus, true);
1709 1 : if (r < 0)
1710 0 : return r;
1711 :
1712 1 : r = sd_bus_negotiate_creds(bus, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS);
1713 1 : if (r < 0)
1714 0 : return r;
1715 :
1716 1 : r = sd_bus_set_watch_bind(bus, true);
1717 1 : if (r < 0)
1718 0 : return r;
1719 :
1720 1 : r = sd_bus_set_connected_signal(bus, true);
1721 1 : if (r < 0)
1722 0 : return r;
1723 :
1724 1 : r = sd_bus_start(bus);
1725 1 : if (r < 0)
1726 0 : return r;
1727 :
1728 1 : *ret = TAKE_PTR(bus);
1729 :
1730 1 : return 0;
1731 : }
1732 :
1733 0 : int bus_reply_pair_array(sd_bus_message *m, char **l) {
1734 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1735 : char **k, **v;
1736 : int r;
1737 :
1738 0 : assert(m);
1739 :
1740 : /* Reply to the specified message with a message containing a dictionary put together from the specified
1741 : * strv */
1742 :
1743 0 : r = sd_bus_message_new_method_return(m, &reply);
1744 0 : if (r < 0)
1745 0 : return r;
1746 :
1747 0 : r = sd_bus_message_open_container(reply, 'a', "{ss}");
1748 0 : if (r < 0)
1749 0 : return r;
1750 :
1751 0 : STRV_FOREACH_PAIR(k, v, l) {
1752 0 : r = sd_bus_message_append(reply, "{ss}", *k, *v);
1753 0 : if (r < 0)
1754 0 : return r;
1755 : }
1756 :
1757 0 : r = sd_bus_message_close_container(reply);
1758 0 : if (r < 0)
1759 0 : return r;
1760 :
1761 0 : return sd_bus_send(NULL, reply, NULL);
1762 : }
1763 :
1764 0 : static void bus_message_unref_wrapper(void *m) {
1765 0 : sd_bus_message_unref(m);
1766 0 : }
1767 :
1768 : const struct hash_ops bus_message_hash_ops = {
1769 : .hash = trivial_hash_func,
1770 : .compare = trivial_compare_func,
1771 : .free_value = bus_message_unref_wrapper,
1772 : };
|