]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-util.c
bus-util: simplify bus_verify_polkit_async() a bit
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/socket.h>
23 #include <sys/capability.h>
24
25 #include "util.h"
26 #include "strv.h"
27 #include "macro.h"
28 #include "def.h"
29 #include "path-util.h"
30 #include "missing.h"
31
32 #include "sd-event.h"
33 #include "sd-bus.h"
34 #include "bus-error.h"
35 #include "bus-message.h"
36 #include "bus-util.h"
37 #include "bus-internal.h"
38
39 static int name_owner_change_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
40 sd_event *e = userdata;
41
42 assert(bus);
43 assert(m);
44 assert(e);
45
46 sd_bus_close(bus);
47 sd_event_exit(e, 0);
48
49 return 1;
50 }
51
52 int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
53 _cleanup_free_ char *match = NULL;
54 const char *unique;
55 int r;
56
57 assert(e);
58 assert(bus);
59 assert(name);
60
61 /* We unregister the name here and then wait for the
62 * NameOwnerChanged signal for this event to arrive before we
63 * quit. We do this in order to make sure that any queued
64 * requests are still processed before we really exit. */
65
66 r = sd_bus_get_unique_name(bus, &unique);
67 if (r < 0)
68 return r;
69
70 r = asprintf(&match,
71 "sender='org.freedesktop.DBus',"
72 "type='signal',"
73 "interface='org.freedesktop.DBus',"
74 "member='NameOwnerChanged',"
75 "path='/org/freedesktop/DBus',"
76 "arg0='%s',"
77 "arg1='%s',"
78 "arg2=''", name, unique);
79 if (r < 0)
80 return -ENOMEM;
81
82 r = sd_bus_add_match(bus, NULL, match, name_owner_change_callback, e);
83 if (r < 0)
84 return r;
85
86 r = sd_bus_release_name(bus, name);
87 if (r < 0)
88 return r;
89
90 return 0;
91 }
92
93 int bus_event_loop_with_idle(
94 sd_event *e,
95 sd_bus *bus,
96 const char *name,
97 usec_t timeout,
98 check_idle_t check_idle,
99 void *userdata) {
100 bool exiting = false;
101 int r, code;
102
103 assert(e);
104 assert(bus);
105 assert(name);
106
107 for (;;) {
108 bool idle;
109
110 r = sd_event_get_state(e);
111 if (r < 0)
112 return r;
113 if (r == SD_EVENT_FINISHED)
114 break;
115
116 if (check_idle)
117 idle = check_idle(userdata);
118 else
119 idle = true;
120
121 r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
122 if (r < 0)
123 return r;
124
125 if (r == 0 && !exiting) {
126
127 r = sd_bus_try_close(bus);
128 if (r == -EBUSY)
129 continue;
130
131 if (r == -ENOTSUP) {
132 /* Fallback for dbus1 connections: we
133 * unregister the name and wait for
134 * the response to come through for
135 * it */
136
137 r = bus_async_unregister_and_exit(e, bus, name);
138 if (r < 0)
139 return r;
140
141 exiting = true;
142 continue;
143 }
144
145 if (r < 0)
146 return r;
147
148 sd_event_exit(e, 0);
149 break;
150 }
151 }
152
153 r = sd_event_get_exit_code(e, &code);
154 if (r < 0)
155 return r;
156
157 return code;
158 }
159
160 int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
161 _cleanup_bus_message_unref_ sd_bus_message *rep = NULL;
162 int r, has_owner = 0;
163
164 assert(c);
165 assert(name);
166
167 r = sd_bus_call_method(c,
168 "org.freedesktop.DBus",
169 "/org/freedesktop/dbus",
170 "org.freedesktop.DBus",
171 "NameHasOwner",
172 error,
173 &rep,
174 "s",
175 name);
176 if (r < 0)
177 return r;
178
179 r = sd_bus_message_read_basic(rep, 'b', &has_owner);
180 if (r < 0)
181 return sd_bus_error_set_errno(error, r);
182
183 return has_owner;
184 }
185
186 int bus_verify_polkit(
187 sd_bus_message *call,
188 int capability,
189 const char *action,
190 bool interactive,
191 bool *_challenge,
192 sd_bus_error *e) {
193
194 int r;
195
196 assert(call);
197 assert(action);
198
199 r = sd_bus_query_sender_privilege(call, capability);
200 if (r < 0)
201 return r;
202 else if (r > 0)
203 return 1;
204 #ifdef ENABLE_POLKIT
205 else {
206 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
207 int authorized = false, challenge = false;
208 const char *sender;
209
210 sender = sd_bus_message_get_sender(call);
211 if (!sender)
212 return -EBADMSG;
213
214 r = sd_bus_call_method(
215 call->bus,
216 "org.freedesktop.PolicyKit1",
217 "/org/freedesktop/PolicyKit1/Authority",
218 "org.freedesktop.PolicyKit1.Authority",
219 "CheckAuthorization",
220 e,
221 &reply,
222 "(sa{sv})sa{ss}us",
223 "system-bus-name", 1, "name", "s", sender,
224 action,
225 0,
226 interactive ? 1 : 0,
227 "");
228
229 if (r < 0) {
230 /* Treat no PK available as access denied */
231 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
232 sd_bus_error_free(e);
233 return -EACCES;
234 }
235
236 return r;
237 }
238
239 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
240 if (r < 0)
241 return r;
242
243 r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
244 if (r < 0)
245 return r;
246
247 if (authorized)
248 return 1;
249
250 if (_challenge) {
251 *_challenge = challenge;
252 return 0;
253 }
254 }
255 #endif
256
257 return -EACCES;
258 }
259
260 #ifdef ENABLE_POLKIT
261
262 typedef struct AsyncPolkitQuery {
263 sd_bus_message *request, *reply;
264 sd_bus_message_handler_t callback;
265 void *userdata;
266 sd_bus_slot *slot;
267 Hashmap *registry;
268 } AsyncPolkitQuery;
269
270 static void async_polkit_query_free(AsyncPolkitQuery *q) {
271
272 if (!q)
273 return;
274
275 sd_bus_slot_unref(q->slot);
276
277 if (q->registry && q->request)
278 hashmap_remove(q->registry, q->request);
279
280 sd_bus_message_unref(q->request);
281 sd_bus_message_unref(q->reply);
282
283 free(q);
284 }
285
286 static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
287 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
288 AsyncPolkitQuery *q = userdata;
289 int r;
290
291 assert(bus);
292 assert(reply);
293 assert(q);
294
295 q->slot = sd_bus_slot_unref(q->slot);
296 q->reply = sd_bus_message_ref(reply);
297
298 r = sd_bus_message_rewind(q->request, true);
299 if (r < 0) {
300 r = sd_bus_reply_method_errno(q->request, r, NULL);
301 goto finish;
302 }
303
304 r = q->callback(bus, q->request, q->userdata, &error_buffer);
305 r = bus_maybe_reply_error(q->request, r, &error_buffer);
306
307 finish:
308 async_polkit_query_free(q);
309
310 return r;
311 }
312
313 #endif
314
315 int bus_verify_polkit_async(
316 sd_bus_message *call,
317 int capability,
318 const char *action,
319 bool interactive,
320 Hashmap **registry,
321 sd_bus_error *error) {
322
323 #ifdef ENABLE_POLKIT
324 _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
325 _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
326 AsyncPolkitQuery *q;
327 const char *sender;
328 sd_bus_message_handler_t callback;
329 void *userdata;
330 #endif
331 int r;
332
333 assert(call);
334 assert(action);
335 assert(registry);
336
337 #ifdef ENABLE_POLKIT
338 q = hashmap_get(*registry, call);
339 if (q) {
340 int authorized, challenge;
341
342 /* This is the second invocation of this function, and
343 * there's already a response from polkit, let's
344 * process it */
345 assert(q->reply);
346
347 if (sd_bus_message_is_method_error(q->reply, NULL)) {
348 const sd_bus_error *e;
349
350 /* Copy error from polkit reply */
351 e = sd_bus_message_get_error(q->reply);
352 sd_bus_error_copy(error, e);
353
354 /* Treat no PK available as access denied */
355 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
356 return -EACCES;
357
358 return -sd_bus_error_get_errno(e);
359 }
360
361 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
362 if (r >= 0)
363 r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
364
365 if (r < 0)
366 return r;
367
368 if (authorized)
369 return 1;
370
371 return -EACCES;
372 }
373 #endif
374
375 r = sd_bus_query_sender_privilege(call, capability);
376 if (r < 0)
377 return r;
378 else if (r > 0)
379 return 1;
380
381 #ifdef ENABLE_POLKIT
382 if (sd_bus_get_current_message(call->bus) != call)
383 return -EINVAL;
384
385 callback = sd_bus_get_current_handler(call->bus);
386 if (!callback)
387 return -EINVAL;
388
389 userdata = sd_bus_get_current_userdata(call->bus);
390
391 sender = sd_bus_message_get_sender(call);
392 if (!sender)
393 return -EBADMSG;
394
395 r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func);
396 if (r < 0)
397 return r;
398
399 r = sd_bus_message_new_method_call(
400 call->bus,
401 &pk,
402 "org.freedesktop.PolicyKit1",
403 "/org/freedesktop/PolicyKit1/Authority",
404 "org.freedesktop.PolicyKit1.Authority",
405 "CheckAuthorization");
406 if (r < 0)
407 return r;
408
409 r = sd_bus_message_append(
410 pk,
411 "(sa{sv})sa{ss}us",
412 "system-bus-name", 1, "name", "s", sender,
413 action,
414 0,
415 interactive ? 1 : 0,
416 NULL);
417 if (r < 0)
418 return r;
419
420 q = new0(AsyncPolkitQuery, 1);
421 if (!q)
422 return -ENOMEM;
423
424 q->request = sd_bus_message_ref(call);
425 q->callback = callback;
426 q->userdata = userdata;
427
428 r = hashmap_put(*registry, call, q);
429 if (r < 0) {
430 async_polkit_query_free(q);
431 return r;
432 }
433
434 q->registry = *registry;
435
436 r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0);
437 if (r < 0) {
438 async_polkit_query_free(q);
439 return r;
440 }
441
442 return 0;
443 #endif
444
445 return -EACCES;
446 }
447
448 void bus_verify_polkit_async_registry_free(Hashmap *registry) {
449 #ifdef ENABLE_POLKIT
450 AsyncPolkitQuery *q;
451
452 while ((q = hashmap_steal_first(registry)))
453 async_polkit_query_free(q);
454
455 hashmap_free(registry);
456 #endif
457 }
458
459 int bus_check_peercred(sd_bus *c) {
460 struct ucred ucred;
461 socklen_t l;
462 int fd;
463
464 assert(c);
465
466 fd = sd_bus_get_fd(c);
467 if (fd < 0)
468 return fd;
469
470 l = sizeof(struct ucred);
471 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
472 return -errno;
473
474 if (l != sizeof(struct ucred))
475 return -E2BIG;
476
477 if (ucred.uid != 0 && ucred.uid != geteuid())
478 return -EPERM;
479
480 return 1;
481 }
482
483 int bus_open_system_systemd(sd_bus **_bus) {
484 _cleanup_bus_unref_ sd_bus *bus = NULL;
485 int r;
486
487 assert(_bus);
488
489 if (geteuid() != 0)
490 return sd_bus_open_system(_bus);
491
492 /* If we are root and kdbus is not available, then let's talk
493 * directly to the system instance, instead of going via the
494 * bus */
495
496 #ifdef ENABLE_KDBUS
497 r = sd_bus_new(&bus);
498 if (r < 0)
499 return r;
500
501 r = sd_bus_set_address(bus, KERNEL_SYSTEM_BUS_PATH);
502 if (r < 0)
503 return r;
504
505 bus->bus_client = true;
506
507 r = sd_bus_start(bus);
508 if (r >= 0) {
509 *_bus = bus;
510 bus = NULL;
511 return 0;
512 }
513
514 bus = sd_bus_unref(bus);
515 #endif
516
517 r = sd_bus_new(&bus);
518 if (r < 0)
519 return r;
520
521 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
522 if (r < 0)
523 return r;
524
525 r = sd_bus_start(bus);
526 if (r < 0)
527 return sd_bus_open_system(_bus);
528
529 r = bus_check_peercred(bus);
530 if (r < 0)
531 return r;
532
533 *_bus = bus;
534 bus = NULL;
535
536 return 0;
537 }
538
539 int bus_open_user_systemd(sd_bus **_bus) {
540 _cleanup_bus_unref_ sd_bus *bus = NULL;
541 _cleanup_free_ char *ee = NULL;
542 const char *e;
543 int r;
544
545 /* Try via kdbus first, and then directly */
546
547 assert(_bus);
548
549 #ifdef ENABLE_KDBUS
550 r = sd_bus_new(&bus);
551 if (r < 0)
552 return r;
553
554 if (asprintf(&bus->address, KERNEL_USER_BUS_FMT, getuid()) < 0)
555 return -ENOMEM;
556
557 bus->bus_client = true;
558
559 r = sd_bus_start(bus);
560 if (r >= 0) {
561 *_bus = bus;
562 bus = NULL;
563 return 0;
564 }
565
566 bus = sd_bus_unref(bus);
567 #endif
568
569 e = secure_getenv("XDG_RUNTIME_DIR");
570 if (!e)
571 return sd_bus_open_user(_bus);
572
573 ee = bus_address_escape(e);
574 if (!ee)
575 return -ENOMEM;
576
577 r = sd_bus_new(&bus);
578 if (r < 0)
579 return r;
580
581 bus->address = strjoin("unix:path=", ee, "/systemd/private", NULL);
582 if (!bus->address)
583 return -ENOMEM;
584
585 r = sd_bus_start(bus);
586 if (r < 0)
587 return sd_bus_open_user(_bus);
588
589 r = bus_check_peercred(bus);
590 if (r < 0)
591 return r;
592
593 *_bus = bus;
594 bus = NULL;
595
596 return 0;
597 }
598
599 int bus_print_property(const char *name, sd_bus_message *property, bool all) {
600 char type;
601 const char *contents;
602 int r;
603
604 assert(name);
605 assert(property);
606
607 r = sd_bus_message_peek_type(property, &type, &contents);
608 if (r < 0)
609 return r;
610
611 switch (type) {
612
613 case SD_BUS_TYPE_STRING: {
614 const char *s;
615
616 r = sd_bus_message_read_basic(property, type, &s);
617 if (r < 0)
618 return r;
619
620 if (all || !isempty(s))
621 printf("%s=%s\n", name, s);
622
623 return 1;
624 }
625
626 case SD_BUS_TYPE_BOOLEAN: {
627 bool b;
628
629 r = sd_bus_message_read_basic(property, type, &b);
630 if (r < 0)
631 return r;
632
633 printf("%s=%s\n", name, yes_no(b));
634
635 return 1;
636 }
637
638 case SD_BUS_TYPE_UINT64: {
639 uint64_t u;
640
641 r = sd_bus_message_read_basic(property, type, &u);
642 if (r < 0)
643 return r;
644
645 /* Yes, heuristics! But we can change this check
646 * should it turn out to not be sufficient */
647
648 if (endswith(name, "Timestamp")) {
649 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
650
651 t = format_timestamp(timestamp, sizeof(timestamp), u);
652 if (t || all)
653 printf("%s=%s\n", name, strempty(t));
654
655 } else if (strstr(name, "USec")) {
656 char timespan[FORMAT_TIMESPAN_MAX];
657
658 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
659 } else
660 printf("%s=%llu\n", name, (unsigned long long) u);
661
662 return 1;
663 }
664
665 case SD_BUS_TYPE_UINT32: {
666 uint32_t u;
667
668 r = sd_bus_message_read_basic(property, type, &u);
669 if (r < 0)
670 return r;
671
672 if (strstr(name, "UMask") || strstr(name, "Mode"))
673 printf("%s=%04o\n", name, u);
674 else
675 printf("%s=%u\n", name, (unsigned) u);
676
677 return 1;
678 }
679
680 case SD_BUS_TYPE_INT32: {
681 int32_t i;
682
683 r = sd_bus_message_read_basic(property, type, &i);
684 if (r < 0)
685 return r;
686
687 printf("%s=%i\n", name, (int) i);
688 return 1;
689 }
690
691 case SD_BUS_TYPE_DOUBLE: {
692 double d;
693
694 r = sd_bus_message_read_basic(property, type, &d);
695 if (r < 0)
696 return r;
697
698 printf("%s=%g\n", name, d);
699 return 1;
700 }
701
702 case SD_BUS_TYPE_ARRAY:
703 if (streq(contents, "s")) {
704 bool first = true;
705 const char *str;
706
707 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
708 if (r < 0)
709 return r;
710
711 while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
712 if (first)
713 printf("%s=", name);
714
715 printf("%s%s", first ? "" : " ", str);
716
717 first = false;
718 }
719 if (r < 0)
720 return r;
721
722 if (first && all)
723 printf("%s=", name);
724 if (!first || all)
725 puts("");
726
727 r = sd_bus_message_exit_container(property);
728 if (r < 0)
729 return r;
730
731 return 1;
732
733 } else if (streq(contents, "y")) {
734 const uint8_t *u;
735 size_t n;
736
737 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
738 if (r < 0)
739 return r;
740
741 if (all || n > 0) {
742 unsigned int i;
743
744 printf("%s=", name);
745
746 for (i = 0; i < n; i++)
747 printf("%02x", u[i]);
748
749 puts("");
750 }
751
752 return 1;
753
754 } else if (streq(contents, "u")) {
755 uint32_t *u;
756 size_t n;
757
758 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
759 if (r < 0)
760 return r;
761
762 if (all || n > 0) {
763 unsigned int i;
764
765 printf("%s=", name);
766
767 for (i = 0; i < n; i++)
768 printf("%08x", u[i]);
769
770 puts("");
771 }
772
773 return 1;
774 }
775
776 break;
777 }
778
779 return 0;
780 }
781
782 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
783 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
784 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
785 int r;
786
787 assert(bus);
788 assert(path);
789
790 r = sd_bus_call_method(bus,
791 dest,
792 path,
793 "org.freedesktop.DBus.Properties",
794 "GetAll",
795 &error,
796 &reply,
797 "s", "");
798 if (r < 0)
799 return r;
800
801 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
802 if (r < 0)
803 return r;
804
805 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
806 const char *name;
807 const char *contents;
808
809 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
810 if (r < 0)
811 return r;
812
813 if (!filter || strv_find(filter, name)) {
814 r = sd_bus_message_peek_type(reply, NULL, &contents);
815 if (r < 0)
816 return r;
817
818 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
819 if (r < 0)
820 return r;
821
822 r = bus_print_property(name, reply, all);
823 if (r < 0)
824 return r;
825 if (r == 0) {
826 if (all)
827 printf("%s=[unprintable]\n", name);
828 /* skip what we didn't read */
829 r = sd_bus_message_skip(reply, contents);
830 if (r < 0)
831 return r;
832 }
833
834 r = sd_bus_message_exit_container(reply);
835 if (r < 0)
836 return r;
837 } else {
838 r = sd_bus_message_skip(reply, "v");
839 if (r < 0)
840 return r;
841 }
842
843 r = sd_bus_message_exit_container(reply);
844 if (r < 0)
845 return r;
846 }
847 if (r < 0)
848 return r;
849
850 r = sd_bus_message_exit_container(reply);
851 if (r < 0)
852 return r;
853
854 return 0;
855 }
856
857 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
858 sd_id128_t *p = userdata;
859 const void *v;
860 size_t n;
861 int r;
862
863 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
864 if (r < 0)
865 return r;
866
867 if (n == 0)
868 *p = SD_ID128_NULL;
869 else if (n == 16)
870 memcpy((*p).bytes, v, n);
871 else
872 return -EINVAL;
873
874 return 0;
875 }
876
877 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
878 char type;
879 int r;
880
881 r = sd_bus_message_peek_type(m, &type, NULL);
882 if (r < 0)
883 return r;
884
885 switch (type) {
886 case SD_BUS_TYPE_STRING: {
887 const char *s;
888 char *str;
889 char **p = userdata;
890
891 r = sd_bus_message_read_basic(m, type, &s);
892 if (r < 0)
893 break;
894
895 if (isempty(s))
896 break;
897
898 str = strdup(s);
899 if (!str) {
900 r = -ENOMEM;
901 break;
902 }
903 free(*p);
904 *p = str;
905
906 break;
907 }
908
909 case SD_BUS_TYPE_ARRAY: {
910 _cleanup_strv_free_ char **l = NULL;
911 char ***p = userdata;
912
913 r = bus_message_read_strv_extend(m, &l);
914 if (r < 0)
915 break;
916
917 strv_free(*p);
918 *p = l;
919 l = NULL;
920
921 break;
922 }
923
924 case SD_BUS_TYPE_BOOLEAN: {
925 unsigned b;
926 bool *p = userdata;
927
928 r = sd_bus_message_read_basic(m, type, &b);
929 if (r < 0)
930 break;
931
932 *p = b;
933
934 break;
935 }
936
937 case SD_BUS_TYPE_UINT32: {
938 uint64_t u;
939 uint32_t *p = userdata;
940
941 r = sd_bus_message_read_basic(m, type, &u);
942 if (r < 0)
943 break;
944
945 *p = u;
946
947 break;
948 }
949
950 case SD_BUS_TYPE_UINT64: {
951 uint64_t t;
952 uint64_t *p = userdata;
953
954 r = sd_bus_message_read_basic(m, type, &t);
955 if (r < 0)
956 break;
957
958 *p = t;
959
960 break;
961 }
962
963 default:
964 break;
965 }
966
967 return r;
968 }
969
970 int bus_map_all_properties(sd_bus *bus,
971 const char *destination,
972 const char *path,
973 const struct bus_properties_map *map,
974 void *userdata) {
975 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
976 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
977 int r;
978
979 assert(bus);
980 assert(destination);
981 assert(path);
982 assert(map);
983
984 r = sd_bus_call_method(
985 bus,
986 destination,
987 path,
988 "org.freedesktop.DBus.Properties",
989 "GetAll",
990 &error,
991 &m,
992 "s", "");
993 if (r < 0)
994 return r;
995
996 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
997 if (r < 0)
998 return r;
999
1000 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
1001 const struct bus_properties_map *prop;
1002 const char *member;
1003 const char *contents;
1004 void *v;
1005 unsigned i;
1006
1007 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
1008 if (r < 0)
1009 return r;
1010
1011 for (i = 0, prop = NULL; map[i].member; i++)
1012 if (streq(map[i].member, member)) {
1013 prop = &map[i];
1014 break;
1015 }
1016
1017 if (prop) {
1018 r = sd_bus_message_peek_type(m, NULL, &contents);
1019 if (r < 0)
1020 return r;
1021
1022 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1023 if (r < 0)
1024 return r;
1025
1026 v = (uint8_t *)userdata + prop->offset;
1027 if (map[i].set)
1028 r = prop->set(bus, member, m, &error, v);
1029 else
1030 r = map_basic(bus, member, m, &error, v);
1031 if (r < 0)
1032 return r;
1033
1034 r = sd_bus_message_exit_container(m);
1035 if (r < 0)
1036 return r;
1037 } else {
1038 r = sd_bus_message_skip(m, "v");
1039 if (r < 0)
1040 return r;
1041 }
1042
1043 r = sd_bus_message_exit_container(m);
1044 if (r < 0)
1045 return r;
1046 }
1047
1048 return r;
1049 }
1050
1051 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1052 int r;
1053
1054 assert(transport >= 0);
1055 assert(transport < _BUS_TRANSPORT_MAX);
1056 assert(bus);
1057
1058 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1059 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1060
1061 switch (transport) {
1062
1063 case BUS_TRANSPORT_LOCAL:
1064 if (user)
1065 r = sd_bus_default_user(bus);
1066 else
1067 r = sd_bus_default_system(bus);
1068
1069 break;
1070
1071 case BUS_TRANSPORT_REMOTE:
1072 r = sd_bus_open_system_remote(bus, host);
1073 break;
1074
1075 case BUS_TRANSPORT_CONTAINER:
1076 r = sd_bus_open_system_container(bus, host);
1077 break;
1078
1079 default:
1080 assert_not_reached("Hmm, unknown transport type.");
1081 }
1082
1083 return r;
1084 }
1085
1086 int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1087 int r;
1088
1089 assert(transport >= 0);
1090 assert(transport < _BUS_TRANSPORT_MAX);
1091 assert(bus);
1092
1093 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1094 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1095
1096 switch (transport) {
1097
1098 case BUS_TRANSPORT_LOCAL:
1099 if (user)
1100 r = bus_open_user_systemd(bus);
1101 else
1102 r = bus_open_system_systemd(bus);
1103
1104 break;
1105
1106 case BUS_TRANSPORT_REMOTE:
1107 r = sd_bus_open_system_remote(bus, host);
1108 break;
1109
1110 case BUS_TRANSPORT_CONTAINER:
1111 r = sd_bus_open_system_container(bus, host);
1112 break;
1113
1114 default:
1115 assert_not_reached("Hmm, unknown transport type.");
1116 }
1117
1118 return r;
1119 }
1120
1121 int bus_property_get_bool(
1122 sd_bus *bus,
1123 const char *path,
1124 const char *interface,
1125 const char *property,
1126 sd_bus_message *reply,
1127 void *userdata,
1128 sd_bus_error *error) {
1129
1130 int b = *(bool*) userdata;
1131
1132 return sd_bus_message_append_basic(reply, 'b', &b);
1133 }
1134
1135 #if __SIZEOF_SIZE_T__ != 8
1136 int bus_property_get_size(
1137 sd_bus *bus,
1138 const char *path,
1139 const char *interface,
1140 const char *property,
1141 sd_bus_message *reply,
1142 void *userdata,
1143 sd_bus_error *error) {
1144
1145 uint64_t sz = *(size_t*) userdata;
1146
1147 return sd_bus_message_append_basic(reply, 't', &sz);
1148 }
1149 #endif
1150
1151 #if __SIZEOF_LONG__ != 8
1152 int bus_property_get_long(
1153 sd_bus *bus,
1154 const char *path,
1155 const char *interface,
1156 const char *property,
1157 sd_bus_message *reply,
1158 void *userdata,
1159 sd_bus_error *error) {
1160
1161 int64_t l = *(long*) userdata;
1162
1163 return sd_bus_message_append_basic(reply, 'x', &l);
1164 }
1165
1166 int bus_property_get_ulong(
1167 sd_bus *bus,
1168 const char *path,
1169 const char *interface,
1170 const char *property,
1171 sd_bus_message *reply,
1172 void *userdata,
1173 sd_bus_error *error) {
1174
1175 uint64_t ul = *(unsigned long*) userdata;
1176
1177 return sd_bus_message_append_basic(reply, 't', &ul);
1178 }
1179 #endif
1180
1181 int bus_log_parse_error(int r) {
1182 log_error("Failed to parse bus message: %s", strerror(-r));
1183 return r;
1184 }
1185
1186 int bus_log_create_error(int r) {
1187 log_error("Failed to create bus message: %s", strerror(-r));
1188 return r;
1189 }
1190
1191 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1192 assert(message);
1193 assert(u);
1194
1195 u->machine = NULL;
1196
1197 return sd_bus_message_read(
1198 message,
1199 "(ssssssouso)",
1200 &u->id,
1201 &u->description,
1202 &u->load_state,
1203 &u->active_state,
1204 &u->sub_state,
1205 &u->following,
1206 &u->unit_path,
1207 &u->job_id,
1208 &u->job_type,
1209 &u->job_path);
1210 }
1211
1212 int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
1213 assert(m);
1214
1215 if (r < 0) {
1216 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1217 sd_bus_reply_method_errno(m, r, error);
1218
1219 } else if (sd_bus_error_is_set(error)) {
1220 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1221 sd_bus_reply_method_error(m, error);
1222 } else
1223 return r;
1224
1225 log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
1226 bus_message_type_to_string(m->header->type),
1227 strna(m->sender),
1228 strna(m->path),
1229 strna(m->interface),
1230 strna(m->member),
1231 strna(m->root_container.signature),
1232 bus_error_message(error, r));
1233
1234 return 1;
1235 }
1236
1237 int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
1238 const char *eq, *field;
1239 int r;
1240
1241 assert(m);
1242 assert(assignment);
1243
1244 eq = strchr(assignment, '=');
1245 if (!eq) {
1246 log_error("Not an assignment: %s", assignment);
1247 return -EINVAL;
1248 }
1249
1250 field = strndupa(assignment, eq - assignment);
1251 eq ++;
1252
1253 if (streq(field, "CPUQuota")) {
1254
1255 if (isempty(eq)) {
1256
1257 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1258 if (r < 0)
1259 return bus_log_create_error(r);
1260
1261 r = sd_bus_message_append(m, "v", "t", USEC_INFINITY);
1262
1263 } else if (endswith(eq, "%")) {
1264 double percent;
1265
1266 if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) {
1267 log_error("CPU quota '%s' invalid.", eq);
1268 return -EINVAL;
1269 }
1270
1271 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1272 if (r < 0)
1273 return bus_log_create_error(r);
1274
1275 r = sd_bus_message_append(m, "v", "t", (usec_t) percent * USEC_PER_SEC / 100);
1276 } else {
1277 log_error("CPU quota needs to be in percent.");
1278 return -EINVAL;
1279 }
1280
1281 if (r < 0)
1282 return bus_log_create_error(r);
1283
1284 return 0;
1285 }
1286
1287 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1288 if (r < 0)
1289 return bus_log_create_error(r);
1290
1291 if (STR_IN_SET(field,
1292 "CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
1293 "SendSIGHUP", "SendSIGKILL")) {
1294
1295 r = parse_boolean(eq);
1296 if (r < 0) {
1297 log_error("Failed to parse boolean assignment %s.", assignment);
1298 return -EINVAL;
1299 }
1300
1301 r = sd_bus_message_append(m, "v", "b", r);
1302
1303 } else if (streq(field, "MemoryLimit")) {
1304 off_t bytes;
1305
1306 r = parse_size(eq, 1024, &bytes);
1307 if (r < 0) {
1308 log_error("Failed to parse bytes specification %s", assignment);
1309 return -EINVAL;
1310 }
1311
1312 r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
1313
1314 } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) {
1315 uint64_t u;
1316
1317 r = safe_atou64(eq, &u);
1318 if (r < 0) {
1319 log_error("Failed to parse %s value %s.", field, eq);
1320 return -EINVAL;
1321 }
1322
1323 r = sd_bus_message_append(m, "v", "t", u);
1324
1325 } else if (STR_IN_SET(field, "User", "Group", "DevicePolicy", "KillMode"))
1326 r = sd_bus_message_append(m, "v", "s", eq);
1327
1328 else if (streq(field, "DeviceAllow")) {
1329
1330 if (isempty(eq))
1331 r = sd_bus_message_append(m, "v", "a(ss)", 0);
1332 else {
1333 const char *path, *rwm, *e;
1334
1335 e = strchr(eq, ' ');
1336 if (e) {
1337 path = strndupa(eq, e - eq);
1338 rwm = e+1;
1339 } else {
1340 path = eq;
1341 rwm = "";
1342 }
1343
1344 if (!path_startswith(path, "/dev")) {
1345 log_error("%s is not a device file in /dev.", path);
1346 return -EINVAL;
1347 }
1348
1349 r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
1350 }
1351
1352 } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1353
1354 if (isempty(eq))
1355 r = sd_bus_message_append(m, "v", "a(st)", 0);
1356 else {
1357 const char *path, *bandwidth, *e;
1358 off_t bytes;
1359
1360 e = strchr(eq, ' ');
1361 if (e) {
1362 path = strndupa(eq, e - eq);
1363 bandwidth = e+1;
1364 } else {
1365 log_error("Failed to parse %s value %s.", field, eq);
1366 return -EINVAL;
1367 }
1368
1369 if (!path_startswith(path, "/dev")) {
1370 log_error("%s is not a device file in /dev.", path);
1371 return -EINVAL;
1372 }
1373
1374 r = parse_size(bandwidth, 1000, &bytes);
1375 if (r < 0) {
1376 log_error("Failed to parse byte value %s.", bandwidth);
1377 return -EINVAL;
1378 }
1379
1380 r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes);
1381 }
1382
1383 } else if (streq(field, "BlockIODeviceWeight")) {
1384
1385 if (isempty(eq))
1386 r = sd_bus_message_append(m, "v", "a(st)", 0);
1387 else {
1388 const char *path, *weight, *e;
1389 uint64_t u;
1390
1391 e = strchr(eq, ' ');
1392 if (e) {
1393 path = strndupa(eq, e - eq);
1394 weight = e+1;
1395 } else {
1396 log_error("Failed to parse %s value %s.", field, eq);
1397 return -EINVAL;
1398 }
1399
1400 if (!path_startswith(path, "/dev")) {
1401 log_error("%s is not a device file in /dev.", path);
1402 return -EINVAL;
1403 }
1404
1405 r = safe_atou64(weight, &u);
1406 if (r < 0) {
1407 log_error("Failed to parse %s value %s.", field, weight);
1408 return -EINVAL;
1409 }
1410 r = sd_bus_message_append(m, "v", "a(st)", path, u);
1411 }
1412
1413 } else if (rlimit_from_string(field) >= 0) {
1414 uint64_t rl;
1415
1416 if (streq(eq, "infinity"))
1417 rl = (uint64_t) -1;
1418 else {
1419 r = safe_atou64(eq, &rl);
1420 if (r < 0) {
1421 log_error("Invalid resource limit: %s", eq);
1422 return -EINVAL;
1423 }
1424 }
1425
1426 r = sd_bus_message_append(m, "v", "t", rl);
1427
1428 } else if (streq(field, "Nice")) {
1429 int32_t i;
1430
1431 r = safe_atoi32(eq, &i);
1432 if (r < 0) {
1433 log_error("Failed to parse %s value %s.", field, eq);
1434 return -EINVAL;
1435 }
1436
1437 r = sd_bus_message_append(m, "v", "i", i);
1438
1439 } else if (streq(field, "Environment")) {
1440
1441 r = sd_bus_message_append(m, "v", "as", 1, eq);
1442
1443 } else if (streq(field, "KillSignal")) {
1444 int sig;
1445
1446 sig = signal_from_string_try_harder(eq);
1447 if (sig < 0) {
1448 log_error("Failed to parse %s value %s.", field, eq);
1449 return -EINVAL;
1450 }
1451
1452 r = sd_bus_message_append(m, "v", "i", sig);
1453
1454 } else {
1455 log_error("Unknown assignment %s.", assignment);
1456 return -EINVAL;
1457 }
1458
1459 if (r < 0)
1460 return bus_log_create_error(r);
1461
1462 return 0;
1463 }