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