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