]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-bus/bus-util.c
bus: add new sd_bus_creds object to encapsulate process credentials
[thirdparty/systemd.git] / src / libsystemd-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 "missing.h"
30
31 #include "sd-event.h"
32 #include "sd-bus.h"
33 #include "bus-error.h"
34 #include "bus-message.h"
35 #include "bus-util.h"
36 #include "bus-internal.h"
37
38 static int quit_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
39 sd_event *e = userdata;
40
41 assert(bus);
42 assert(m);
43 assert(e);
44
45 sd_event_request_quit(e);
46 return 1;
47 }
48
49 int bus_async_unregister_and_quit(sd_event *e, sd_bus *bus, const char *name) {
50 _cleanup_free_ char *match = NULL;
51 int r;
52
53 assert(e);
54 assert(bus);
55 assert(name);
56
57 r = asprintf(&match, "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameLost',arg0='%s'", name);
58 if (r < 0)
59 return r;
60
61 r = sd_bus_add_match(bus, match, quit_callback, e);
62 if (r < 0)
63 return r;
64
65 r = sd_bus_release_name(bus, name);
66 if (r < 0)
67 return r;
68
69 if (r != SD_BUS_NAME_RELEASED)
70 return -EIO;
71
72 return 0;
73 }
74
75 int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t timeout) {
76 bool exiting = false;
77 int r;
78
79 assert(e);
80 assert(bus);
81 assert(name);
82
83 for (;;) {
84 r = sd_event_get_state(e);
85 if (r < 0)
86 return r;
87
88 if (r == SD_EVENT_FINISHED)
89 break;
90
91 r = sd_event_run(e, exiting ? (uint64_t) -1 : timeout);
92 if (r < 0)
93 return r;
94
95 if (r == 0 && !exiting) {
96 r = bus_async_unregister_and_quit(e, bus, name);
97 if (r < 0)
98 return r;
99
100 exiting = true;
101 }
102 }
103
104 return 0;
105 }
106
107 int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
108 _cleanup_bus_message_unref_ sd_bus_message *rep = NULL;
109 int r, has_owner = 0;
110
111 assert(c);
112 assert(name);
113
114 r = sd_bus_call_method(c,
115 "org.freedesktop.DBus",
116 "/org/freedesktop/dbus",
117 "org.freedesktop.DBus",
118 "NameHasOwner",
119 error,
120 &rep,
121 "s",
122 name);
123 if (r < 0)
124 return r;
125
126 r = sd_bus_message_read_basic(rep, 'b', &has_owner);
127 if (r < 0)
128 return sd_bus_error_set_errno(error, r);
129
130 return has_owner;
131 }
132
133 int bus_verify_polkit(
134 sd_bus *bus,
135 sd_bus_message *m,
136 const char *action,
137 bool interactive,
138 bool *_challenge,
139 sd_bus_error *e) {
140
141 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
142 uid_t uid;
143 int r;
144
145 assert(bus);
146 assert(m);
147 assert(action);
148
149 r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
150 if (r < 0)
151 return r;
152
153 r = sd_bus_creds_get_uid(creds, &uid);
154 if (r < 0)
155 return r;
156
157 if (uid == 0)
158 return 1;
159
160 #ifdef ENABLE_POLKIT
161 else {
162 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
163 int authorized = false, challenge = false;
164 const char *sender;
165
166 sender = sd_bus_message_get_sender(m);
167 if (!sender)
168 return -EBADMSG;
169
170 r = sd_bus_call_method(
171 bus,
172 "org.freedesktop.PolicyKit1",
173 "/org/freedesktop/PolicyKit1/Authority",
174 "org.freedesktop.PolicyKit1.Authority",
175 "CheckAuthorization",
176 e,
177 &reply,
178 "(sa{sv})sa{ss}us",
179 "system-bus-name", 1, "name", "s", sender,
180 action,
181 0,
182 interactive ? 1 : 0,
183 "");
184
185 if (r < 0) {
186 /* Treat no PK available as access denied */
187 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
188 sd_bus_error_free(e);
189 return -EACCES;
190 }
191
192 return r;
193 }
194
195 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
196 if (r >= 0)
197 r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
198
199 if (authorized)
200 return 1;
201
202 if (_challenge) {
203 *_challenge = challenge;
204 return 0;
205 }
206 }
207 #endif
208
209 return -EACCES;
210 }
211
212 #ifdef ENABLE_POLKIT
213
214 typedef struct AsyncPolkitQuery {
215 sd_bus_message *request, *reply;
216 sd_bus_message_handler_t callback;
217 void *userdata;
218 uint64_t serial;
219 Hashmap *registry;
220 } AsyncPolkitQuery;
221
222 static void async_polkit_query_free(sd_bus *b, AsyncPolkitQuery *q) {
223
224 if (!q)
225 return;
226
227 if (q->serial > 0 && b)
228 sd_bus_call_async_cancel(b, q->serial);
229
230 if (q->registry && q->request)
231 hashmap_remove(q->registry, q->request);
232
233 sd_bus_message_unref(q->request);
234 sd_bus_message_unref(q->reply);
235
236 free(q);
237 }
238
239 static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
240 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
241 AsyncPolkitQuery *q = userdata;
242 int r;
243
244 assert(bus);
245 assert(reply);
246 assert(q);
247
248 q->reply = sd_bus_message_ref(reply);
249 q->serial = 0;
250
251 r = sd_bus_message_rewind(q->request, true);
252 if (r < 0) {
253 r = sd_bus_reply_method_errno(q->request, r, NULL);
254 goto finish;
255 }
256
257 r = q->callback(bus, q->request, q->userdata, &error_buffer);
258 r = bus_maybe_reply_error(q->request, r, &error_buffer);
259
260 finish:
261 async_polkit_query_free(bus, q);
262 return r;
263 }
264
265 #endif
266
267 int bus_verify_polkit_async(
268 sd_bus *bus,
269 Hashmap **registry,
270 sd_bus_message *m,
271 const char *action,
272 bool interactive,
273 sd_bus_error *error,
274 sd_bus_message_handler_t callback,
275 void *userdata) {
276
277 #ifdef ENABLE_POLKIT
278 _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
279 AsyncPolkitQuery *q;
280 const char *sender;
281 #endif
282 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
283 uid_t uid;
284 int r;
285
286 assert(bus);
287 assert(registry);
288 assert(m);
289 assert(action);
290
291 #ifdef ENABLE_POLKIT
292 q = hashmap_get(*registry, m);
293 if (q) {
294 int authorized, challenge;
295
296 /* This is the second invocation of this function, and
297 * there's already a response from polkit, let's
298 * process it */
299 assert(q->reply);
300
301 if (sd_bus_message_is_method_error(q->reply, NULL)) {
302 const sd_bus_error *e;
303
304 /* Copy error from polkit reply */
305 e = sd_bus_message_get_error(q->reply);
306 sd_bus_error_copy(error, e);
307
308 /* Treat no PK available as access denied */
309 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
310 return -EACCES;
311
312 return sd_bus_error_get_errno(e);
313 }
314
315 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
316 if (r >= 0)
317 r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
318
319 if (r < 0)
320 return r;
321
322 if (authorized)
323 return 1;
324
325 return -EACCES;
326 }
327 #endif
328
329 r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
330 if (r < 0)
331 return r;
332
333 r = sd_bus_creds_get_uid(creds, &uid);
334 if (r < 0)
335 return r;
336
337 if (uid == 0)
338 return 1;
339
340 #ifdef ENABLE_POLKIT
341 sender = sd_bus_message_get_sender(m);
342 if (!sender)
343 return -EBADMSG;
344
345 r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func);
346 if (r < 0)
347 return r;
348
349 r = sd_bus_message_new_method_call(
350 bus,
351 "org.freedesktop.PolicyKit1",
352 "/org/freedesktop/PolicyKit1/Authority",
353 "org.freedesktop.PolicyKit1.Authority",
354 "CheckAuthorization",
355 &pk);
356 if (r < 0)
357 return r;
358
359 r = sd_bus_message_append(
360 pk,
361 "(sa{sv})sa{ss}us",
362 "system-bus-name", 1, "name", "s", sender,
363 action,
364 0,
365 interactive ? 1 : 0,
366 NULL);
367 if (r < 0)
368 return r;
369
370 q = new0(AsyncPolkitQuery, 1);
371 if (!q)
372 return -ENOMEM;
373
374 q->request = sd_bus_message_ref(m);
375 q->callback = callback;
376 q->userdata = userdata;
377
378 r = hashmap_put(*registry, m, q);
379 if (r < 0) {
380 async_polkit_query_free(bus, q);
381 return r;
382 }
383
384 q->registry = *registry;
385
386 r = sd_bus_call_async(bus, pk, async_polkit_callback, q, 0, &q->serial);
387 if (r < 0) {
388 async_polkit_query_free(bus, q);
389 return r;
390 }
391
392 return 0;
393 #endif
394
395 return -EACCES;
396 }
397
398 void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry) {
399 #ifdef ENABLE_POLKIT
400 AsyncPolkitQuery *q;
401
402 while ((q = hashmap_steal_first(registry)))
403 async_polkit_query_free(bus, q);
404
405 hashmap_free(registry);
406 #endif
407 }
408
409 int bus_check_peercred(sd_bus *c) {
410 struct ucred ucred;
411 socklen_t l;
412 int fd;
413
414 assert(c);
415
416 fd = sd_bus_get_fd(c);
417 if (fd < 0)
418 return fd;
419
420 l = sizeof(struct ucred);
421 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
422 return -errno;
423
424 if (l != sizeof(struct ucred))
425 return -E2BIG;
426
427 if (ucred.uid != 0 && ucred.uid != geteuid())
428 return -EPERM;
429
430 return 1;
431 }
432
433 int bus_open_system_systemd(sd_bus **_bus) {
434 _cleanup_bus_unref_ sd_bus *bus = NULL;
435 int r;
436
437 assert(_bus);
438
439 if (geteuid() != 0)
440 return sd_bus_open_system(_bus);
441
442 /* If we are root, then let's talk directly to the system
443 * instance, instead of going via the bus */
444
445 r = sd_bus_new(&bus);
446 if (r < 0)
447 return r;
448
449 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
450 if (r < 0)
451 return r;
452
453 r = sd_bus_start(bus);
454 if (r < 0)
455 return r;
456
457 r = bus_check_peercred(bus);
458 if (r < 0)
459 return r;
460
461 *_bus = bus;
462 bus = NULL;
463
464 return 0;
465 }
466
467 int bus_open_user_systemd(sd_bus **_bus) {
468 _cleanup_bus_unref_ sd_bus *bus = NULL;
469 _cleanup_free_ char *p = NULL;
470 const char *e;
471 int r;
472
473 /* If we are supposed to talk to the instance, try via
474 * XDG_RUNTIME_DIR first, then fallback to normal bus
475 * access */
476
477 assert(_bus);
478
479 e = secure_getenv("XDG_RUNTIME_DIR");
480 if (e) {
481 if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0)
482 return -ENOMEM;
483 }
484
485 r = sd_bus_new(&bus);
486 if (r < 0)
487 return r;
488
489 r = sd_bus_set_address(bus, p);
490 if (r < 0)
491 return r;
492
493 r = sd_bus_start(bus);
494 if (r < 0)
495 return r;
496
497 r = bus_check_peercred(bus);
498 if (r < 0)
499 return r;
500
501 *_bus = bus;
502 bus = NULL;
503
504 return 0;
505 }
506
507 int bus_print_property(const char *name, sd_bus_message *property, bool all) {
508 char type;
509 const char *contents;
510 int r;
511
512 assert(name);
513 assert(property);
514
515 r = sd_bus_message_peek_type(property, &type, &contents);
516 if (r < 0)
517 return r;
518
519 switch (type) {
520
521 case SD_BUS_TYPE_STRING: {
522 const char *s;
523
524 r = sd_bus_message_read_basic(property, type, &s);
525 if (r < 0)
526 return r;
527
528 if (all || !isempty(s))
529 printf("%s=%s\n", name, s);
530
531 return 1;
532 }
533
534 case SD_BUS_TYPE_BOOLEAN: {
535 bool b;
536
537 r = sd_bus_message_read_basic(property, type, &b);
538 if (r < 0)
539 return r;
540
541 printf("%s=%s\n", name, yes_no(b));
542
543 return 1;
544 }
545
546 case SD_BUS_TYPE_UINT64: {
547 uint64_t u;
548
549 r = sd_bus_message_read_basic(property, type, &u);
550 if (r < 0)
551 return r;
552
553 /* Yes, heuristics! But we can change this check
554 * should it turn out to not be sufficient */
555
556 if (endswith(name, "Timestamp")) {
557 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
558
559 t = format_timestamp(timestamp, sizeof(timestamp), u);
560 if (t || all)
561 printf("%s=%s\n", name, strempty(t));
562
563 } else if (strstr(name, "USec")) {
564 char timespan[FORMAT_TIMESPAN_MAX];
565
566 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
567 } else
568 printf("%s=%llu\n", name, (unsigned long long) u);
569
570 return 1;
571 }
572
573 case SD_BUS_TYPE_UINT32: {
574 uint32_t u;
575
576 r = sd_bus_message_read_basic(property, type, &u);
577 if (r < 0)
578 return r;
579
580 if (strstr(name, "UMask") || strstr(name, "Mode"))
581 printf("%s=%04o\n", name, u);
582 else
583 printf("%s=%u\n", name, (unsigned) u);
584
585 return 1;
586 }
587
588 case SD_BUS_TYPE_INT32: {
589 int32_t i;
590
591 r = sd_bus_message_read_basic(property, type, &i);
592 if (r < 0)
593 return r;
594
595 printf("%s=%i\n", name, (int) i);
596 return 1;
597 }
598
599 case SD_BUS_TYPE_DOUBLE: {
600 double d;
601
602 r = sd_bus_message_read_basic(property, type, &d);
603 if (r < 0)
604 return r;
605
606 printf("%s=%g\n", name, d);
607 return 1;
608 }
609
610 case SD_BUS_TYPE_ARRAY:
611 if (streq(contents, "s")) {
612 bool first = true;
613 const char *str;
614
615 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
616 if (r < 0)
617 return r;
618
619 while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
620 if (first)
621 printf("%s=", name);
622
623 printf("%s%s", first ? "" : " ", str);
624
625 first = false;
626 }
627 if (r < 0)
628 return r;
629
630 if (first && all)
631 printf("%s=", name);
632 if (!first || all)
633 puts("");
634
635 r = sd_bus_message_exit_container(property);
636 if (r < 0)
637 return r;
638
639 return 1;
640
641 } else if (streq(contents, "y")) {
642 const uint8_t *u;
643 size_t n;
644
645 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
646 if (r < 0)
647 return r;
648
649 if (all || n > 0) {
650 unsigned int i;
651
652 printf("%s=", name);
653
654 for (i = 0; i < n; i++)
655 printf("%02x", u[i]);
656
657 puts("");
658 }
659
660 return 1;
661
662 } else if (streq(contents, "u")) {
663 uint32_t *u;
664 size_t n;
665
666 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
667 if (r < 0)
668 return r;
669
670 if (all || n > 0) {
671 unsigned int i;
672
673 printf("%s=", name);
674
675 for (i = 0; i < n; i++)
676 printf("%08x", u[i]);
677
678 puts("");
679 }
680
681 return 1;
682 }
683
684 break;
685 }
686
687 return 0;
688 }
689
690 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
691 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
692 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
693 int r;
694
695 assert(bus);
696 assert(path);
697
698 r = sd_bus_call_method(bus,
699 dest,
700 path,
701 "org.freedesktop.DBus.Properties",
702 "GetAll",
703 &error,
704 &reply,
705 "s", "");
706 if (r < 0)
707 return r;
708
709 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
710 if (r < 0)
711 return r;
712
713 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
714 const char *name;
715 const char *contents;
716
717 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
718 if (r < 0)
719 return r;
720
721 if (!filter || strv_find(filter, name)) {
722 r = sd_bus_message_peek_type(reply, NULL, &contents);
723 if (r < 0)
724 return r;
725
726 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
727 if (r < 0)
728 return r;
729
730 r = bus_print_property(name, reply, all);
731 if (r < 0)
732 return r;
733 if (r == 0) {
734 if (all)
735 printf("%s=[unprintable]\n", name);
736 /* skip what we didn't read */
737 r = sd_bus_message_skip(reply, contents);
738 if (r < 0)
739 return r;
740 }
741
742 r = sd_bus_message_exit_container(reply);
743 if (r < 0)
744 return r;
745 } else {
746 r = sd_bus_message_skip(reply, "v");
747 if (r < 0)
748 return r;
749 }
750
751 r = sd_bus_message_exit_container(reply);
752 if (r < 0)
753 return r;
754 }
755 if (r < 0)
756 return r;
757
758 r = sd_bus_message_exit_container(reply);
759 if (r < 0)
760 return r;
761
762 return 0;
763 }
764
765 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
766 sd_id128_t *p = userdata;
767 const void *v;
768 size_t n;
769 int r;
770
771 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
772 if (r < 0)
773 return r;
774
775 if (n == 0)
776 *p = SD_ID128_NULL;
777 else if (n == 16)
778 memcpy((*p).bytes, v, n);
779 else
780 return -EINVAL;
781
782 return 0;
783 }
784
785 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
786 char type;
787 int r;
788
789 r = sd_bus_message_peek_type(m, &type, NULL);
790 if (r < 0)
791 return r;
792
793 switch (type) {
794 case SD_BUS_TYPE_STRING: {
795 const char *s;
796 char *str;
797 char **p = userdata;
798
799 r = sd_bus_message_read_basic(m, type, &s);
800 if (r < 0)
801 break;
802
803 if (isempty(s))
804 break;
805
806 str = strdup(s);
807 if (!str) {
808 r = -ENOMEM;
809 break;
810 }
811 free(*p);
812 *p = str;
813
814 break;
815 }
816
817 case SD_BUS_TYPE_ARRAY: {
818 _cleanup_strv_free_ char **l = NULL;
819 char ***p = userdata;
820
821 r = bus_message_read_strv_extend(m, &l);
822 if (r < 0)
823 break;
824
825 strv_free(*p);
826 *p = l;
827 l = NULL;
828
829 break;
830 }
831
832 case SD_BUS_TYPE_BOOLEAN: {
833 unsigned b;
834 bool *p = userdata;
835
836 r = sd_bus_message_read_basic(m, type, &b);
837 if (r < 0)
838 break;
839
840 *p = b;
841
842 break;
843 }
844
845 case SD_BUS_TYPE_UINT32: {
846 uint64_t u;
847 uint32_t *p = userdata;
848
849 r = sd_bus_message_read_basic(m, type, &u);
850 if (r < 0)
851 break;
852
853 *p = u;
854
855 break;
856 }
857
858 case SD_BUS_TYPE_UINT64: {
859 uint64_t t;
860 uint64_t *p = userdata;
861
862 r = sd_bus_message_read_basic(m, type, &t);
863 if (r < 0)
864 break;
865
866 *p = t;
867
868 break;
869 }
870
871 default:
872 break;
873 }
874
875 return r;
876 }
877
878 int bus_map_all_properties(sd_bus *bus,
879 const char *destination,
880 const char *path,
881 const struct bus_properties_map *map,
882 void *userdata) {
883 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
884 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
885 int r;
886
887 assert(bus);
888 assert(destination);
889 assert(path);
890 assert(map);
891
892 r = sd_bus_call_method( bus,
893 destination,
894 path,
895 "org.freedesktop.DBus.Properties",
896 "GetAll",
897 &error,
898 &m,
899 "s", "");
900 if (r < 0)
901 return r;
902
903 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
904 if (r < 0)
905 return r;
906
907 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
908 const struct bus_properties_map *prop;
909 const char *member;
910 const char *contents;
911 void *v;
912 unsigned i;
913
914 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
915 if (r < 0)
916 return r;
917
918 for (i = 0, prop = NULL; map[i].member; i++)
919 if (streq(map[i].member, member)) {
920 prop = &map[i];
921 break;
922 }
923
924 if (prop) {
925 r = sd_bus_message_peek_type(m, NULL, &contents);
926 if (r < 0)
927 return r;
928
929 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
930 if (r < 0)
931 return r;
932
933 v = (uint8_t *)userdata + prop->offset;
934 if (map[i].set)
935 r = prop->set(bus, member, m, &error, v);
936 else
937 r = map_basic(bus, member, m, &error, v);
938
939 r = sd_bus_message_exit_container(m);
940 if (r < 0)
941 return r;
942 } else {
943 r = sd_bus_message_skip(m, "v");
944 if (r < 0)
945 return r;
946 }
947
948 r = sd_bus_message_exit_container(m);
949 if (r < 0)
950 return r;
951 }
952
953 return r;
954 }
955
956 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
957 int r;
958
959 assert(transport >= 0);
960 assert(transport < _BUS_TRANSPORT_MAX);
961 assert(bus);
962
963 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
964 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
965
966 switch (transport) {
967
968 case BUS_TRANSPORT_LOCAL:
969 if (user)
970 r = sd_bus_default_user(bus);
971 else
972 r = sd_bus_default_system(bus);
973
974 break;
975
976 case BUS_TRANSPORT_REMOTE:
977 r = sd_bus_open_system_remote(host, bus);
978 break;
979
980 case BUS_TRANSPORT_CONTAINER:
981 r = sd_bus_open_system_container(host, bus);
982 break;
983
984 default:
985 assert_not_reached("Hmm, unknown transport type.");
986 }
987
988 return r;
989 }
990
991 int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
992 int r;
993
994 assert(transport >= 0);
995 assert(transport < _BUS_TRANSPORT_MAX);
996 assert(bus);
997
998 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
999 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1000
1001 switch (transport) {
1002
1003 case BUS_TRANSPORT_LOCAL:
1004 if (user)
1005 r = bus_open_user_systemd(bus);
1006 else
1007 r = bus_open_system_systemd(bus);
1008
1009 break;
1010
1011 case BUS_TRANSPORT_REMOTE:
1012 r = sd_bus_open_system_remote(host, bus);
1013 break;
1014
1015 case BUS_TRANSPORT_CONTAINER:
1016 r = sd_bus_open_system_container(host, bus);
1017 break;
1018
1019 default:
1020 assert_not_reached("Hmm, unknown transport type.");
1021 }
1022
1023 return r;
1024 }
1025
1026 int bus_property_get_tristate(
1027 sd_bus *bus,
1028 const char *path,
1029 const char *interface,
1030 const char *property,
1031 sd_bus_message *reply,
1032 void *userdata,
1033 sd_bus_error *error) {
1034
1035 int *tristate = userdata;
1036
1037 return sd_bus_message_append(reply, "b", *tristate > 0);
1038 }
1039
1040 int bus_property_get_bool(
1041 sd_bus *bus,
1042 const char *path,
1043 const char *interface,
1044 const char *property,
1045 sd_bus_message *reply,
1046 void *userdata,
1047 sd_bus_error *error) {
1048
1049 int b = *(bool*) userdata;
1050
1051 return sd_bus_message_append_basic(reply, 'b', &b);
1052 }
1053
1054 #if __SIZEOF_SIZE_T__ != 8
1055 int bus_property_get_size(
1056 sd_bus *bus,
1057 const char *path,
1058 const char *interface,
1059 const char *property,
1060 sd_bus_message *reply,
1061 void *userdata,
1062 sd_bus_error *error) {
1063
1064 uint64_t sz = *(size_t*) userdata;
1065
1066 return sd_bus_message_append_basic(reply, 't', &sz);
1067 }
1068 #endif
1069
1070 #if __SIZEOF_LONG__ != 8
1071 int bus_property_get_long(
1072 sd_bus *bus,
1073 const char *path,
1074 const char *interface,
1075 const char *property,
1076 sd_bus_message *reply,
1077 void *userdata,
1078 sd_bus_error *error) {
1079
1080 int64_t l = *(long*) userdata;
1081
1082 return sd_bus_message_append_basic(reply, 'x', &l);
1083 }
1084
1085 int bus_property_get_ulong(
1086 sd_bus *bus,
1087 const char *path,
1088 const char *interface,
1089 const char *property,
1090 sd_bus_message *reply,
1091 void *userdata,
1092 sd_bus_error *error) {
1093
1094 uint64_t ul = *(unsigned long*) userdata;
1095
1096 return sd_bus_message_append_basic(reply, 't', &ul);
1097 }
1098 #endif
1099
1100 int bus_log_parse_error(int r) {
1101 log_error("Failed to parse message: %s", strerror(-r));
1102 return r;
1103 }
1104
1105 int bus_log_create_error(int r) {
1106 log_error("Failed to create message: %s", strerror(-r));
1107 return r;
1108 }
1109
1110 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1111 assert(message);
1112 assert(u);
1113
1114 return sd_bus_message_read(
1115 message,
1116 "(ssssssouso)",
1117 &u->id,
1118 &u->description,
1119 &u->load_state,
1120 &u->active_state,
1121 &u->sub_state,
1122 &u->following,
1123 &u->unit_path,
1124 &u->job_id,
1125 &u->job_type,
1126 &u->job_path);
1127 }
1128
1129 int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
1130 assert(m);
1131
1132 if (r < 0) {
1133 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1134 sd_bus_reply_method_errno(m, r, error);
1135
1136 } else if (sd_bus_error_is_set(error)) {
1137 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1138 sd_bus_reply_method_error(m, error);
1139 } else
1140 return r;
1141
1142 log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
1143 bus_message_type_to_string(m->header->type),
1144 strna(m->sender),
1145 strna(m->path),
1146 strna(m->interface),
1147 strna(m->member),
1148 strna(m->root_container.signature),
1149 bus_error_message(error, r));
1150
1151 return 1;
1152 }