chiark / gitweb /
libsystemd-bus: sync kdbus.h
[elogind.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 }