chiark / gitweb /
bf8fb409059d95266f926fcc69e62a52038bf99b
[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 space = false;
549                         char tp;
550                         const char *cnt;
551
552                         r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
553                         if (r < 0)
554                                 return r;
555
556                         r = sd_bus_message_peek_type(property, &tp, &cnt);
557                         if (r < 0)
558                                 return r;
559
560                         if (all || cnt) {
561                                 const char *str;
562
563                                 printf("%s=", name);
564
565                                 while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) >= 0) {
566                                         printf("%s%s", space ? " " : "", str);
567
568                                         space = true;
569                                 }
570                                 if (r < 0)
571                                         return r;
572
573                                 puts("");
574                         }
575
576                         r = sd_bus_message_exit_container(property);
577                         if (r < 0)
578                                 return r;
579
580                         return 1;
581
582                 } else if (streq(contents, "y")) {
583                         const uint8_t *u;
584                         size_t n;
585
586                         r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
587                         if (r < 0)
588                                 return r;
589
590                         if (all || n > 0) {
591                                 unsigned int i;
592
593                                 printf("%s=", name);
594
595                                 for (i = 0; i < n; i++)
596                                         printf("%02x", u[i]);
597
598                                 puts("");
599                         }
600
601                         return 1;
602
603                 } else if (streq(contents, "u")) {
604                         uint32_t *u;
605                         size_t n;
606
607                         r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
608                         if (r < 0)
609                                 return r;
610
611                         if (all || n > 0) {
612                                 unsigned int i;
613
614                                 printf("%s=", name);
615
616                                 for (i = 0; i < n; i++)
617                                         printf("%08x", u[i]);
618
619                                 puts("");
620                         }
621
622                         return 1;
623                 }
624
625                 break;
626         }
627
628         return 0;
629 }
630
631 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
632         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
633         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
634         int r;
635
636         assert(bus);
637         assert(path);
638
639         r = sd_bus_call_method(bus,
640                         dest,
641                         path,
642                         "org.freedesktop.DBus.Properties",
643                         "GetAll",
644                         &error,
645                         &reply,
646                         "s", "");
647         if (r < 0)
648                 return r;
649
650         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
651         if (r < 0)
652                 return r;
653
654         while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
655                 const char *name;
656                 const char *contents;
657
658                 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
659                 if (r < 0)
660                         return r;
661
662                 if (!filter || strv_find(filter, name)) {
663                         r = sd_bus_message_peek_type(reply, NULL, &contents);
664                         if (r < 0)
665                                 return r;
666
667                         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
668                         if (r < 0)
669                                 return r;
670
671                         r = bus_print_property(name, reply, all);
672                         if (r < 0)
673                                 return r;
674                         if (r == 0) {
675                                 if (all)
676                                         printf("%s=[unprintable]\n", name);
677                                 /* skip what we didn't read */
678                                 r = sd_bus_message_skip(reply, contents);
679                                 if (r < 0)
680                                         return r;
681                         }
682
683                         r = sd_bus_message_exit_container(reply);
684                         if (r < 0)
685                                 return r;
686                 } else {
687                         r = sd_bus_message_skip(reply, "v");
688                         if (r < 0)
689                                 return r;
690                 }
691
692                 r = sd_bus_message_exit_container(reply);
693                 if (r < 0)
694                         return r;
695         }
696         if (r < 0)
697                 return r;
698
699         r = sd_bus_message_exit_container(reply);
700         if (r < 0)
701                 return r;
702
703         return 0;
704 }
705
706 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
707         sd_id128_t *p = userdata;
708         const void *v;
709         size_t n;
710         int r;
711
712         r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
713         if (r < 0)
714                 return r;
715
716         if (n == 0)
717                 *p = SD_ID128_NULL;
718         else if (n == 16)
719                 memcpy((*p).bytes, v, n);
720         else
721                 return -EINVAL;
722
723         return 0;
724 }
725
726 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
727         char type;
728         int r;
729
730         r = sd_bus_message_peek_type(m, &type, NULL);
731         if (r < 0)
732                 return r;
733
734         switch (type) {
735         case SD_BUS_TYPE_STRING: {
736                 const char *s;
737                 char *str;
738                 char **p = userdata;
739
740                 r = sd_bus_message_read_basic(m, type, &s);
741                 if (r < 0)
742                         break;
743
744                 if (isempty(s))
745                         break;
746
747                 str = strdup(s);
748                 if (!str) {
749                         r = -ENOMEM;
750                         break;
751                 }
752                 free(*p);
753                 *p = str;
754
755                 break;
756         }
757
758         case SD_BUS_TYPE_ARRAY: {
759                _cleanup_strv_free_ char **l = NULL;
760                char ***p = userdata;
761
762                 r = bus_message_read_strv_extend(m, &l);
763                 if (r < 0)
764                         break;
765
766                 strv_free(*p);
767                 *p = l;
768                 l = NULL;
769
770                 break;
771         }
772
773         case SD_BUS_TYPE_BOOLEAN: {
774                 unsigned b;
775                 bool *p = userdata;
776
777                 r = sd_bus_message_read_basic(m, type, &b);
778                 if (r < 0)
779                         break;
780
781                 *p = b;
782
783                 break;
784         }
785
786         case SD_BUS_TYPE_UINT32: {
787                 uint64_t u;
788                 uint32_t *p = userdata;
789
790                 r = sd_bus_message_read_basic(m, type, &u);
791                 if (r < 0)
792                         break;
793
794                 *p = u;
795
796                 break;
797         }
798
799         case SD_BUS_TYPE_UINT64: {
800                 uint64_t t;
801                 uint64_t *p = userdata;
802
803                 r = sd_bus_message_read_basic(m, type, &t);
804                 if (r < 0)
805                         break;
806
807                 *p = t;
808
809                 break;
810         }
811
812         default:
813                 break;
814         }
815
816         return r;
817 }
818
819 int bus_map_all_properties(sd_bus *bus,
820                            const char *destination,
821                            const char *path,
822                            const struct bus_properties_map *map,
823                            void *userdata) {
824         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
825         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
826         int r;
827
828         assert(bus);
829         assert(destination);
830         assert(path);
831         assert(map);
832
833         r = sd_bus_call_method( bus,
834                         destination,
835                         path,
836                         "org.freedesktop.DBus.Properties",
837                         "GetAll",
838                         &error,
839                         &m,
840                         "s", "");
841         if (r < 0)
842                 return r;
843
844         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
845         if (r < 0)
846                 return r;
847
848         while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
849                 const struct bus_properties_map *prop;
850                 const char *member;
851                 const char *contents;
852                 void *v;
853                 unsigned i;
854
855                 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
856                 if (r < 0)
857                         return r;
858
859                 for (i = 0, prop = NULL; map[i].member; i++)
860                         if (streq(map[i].member, member)) {
861                                 prop = &map[i];
862                                 break;
863                         }
864
865                 if (prop) {
866                         r = sd_bus_message_peek_type(m, NULL, &contents);
867                         if (r < 0)
868                                 return r;
869
870                         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
871                         if (r < 0)
872                                 return r;
873
874                         v = (uint8_t *)userdata + prop->offset;
875                         if (map[i].set)
876                                 r = prop->set(bus, member, m, &error, v);
877                         else
878                                 r = map_basic(bus, member, m, &error, v);
879
880                         r = sd_bus_message_exit_container(m);
881                         if (r < 0)
882                                 return r;
883                 } else {
884                         r = sd_bus_message_skip(m, "v");
885                         if (r < 0)
886                                 return -r;
887                 }
888
889                 r = sd_bus_message_exit_container(m);
890                 if (r < 0)
891                         return r;
892         }
893
894         return r;
895 }
896
897 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
898         int r;
899
900         assert(transport >= 0);
901         assert(transport < _BUS_TRANSPORT_MAX);
902         assert(bus);
903
904         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
905         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
906
907         switch (transport) {
908
909         case BUS_TRANSPORT_LOCAL:
910                 if (user)
911                         r = sd_bus_open_user(bus);
912                 else
913                         r = sd_bus_open_system(bus);
914
915                 break;
916
917         case BUS_TRANSPORT_REMOTE:
918                 r = sd_bus_open_system_remote(host, bus);
919                 break;
920
921         case BUS_TRANSPORT_CONTAINER:
922                 r = sd_bus_open_system_container(host, bus);
923                 break;
924
925         default:
926                 assert_not_reached("Hmm, unknown transport type.");
927         }
928
929         return r;
930 }
931
932 int bus_property_get_bool(
933                 sd_bus *bus,
934                 const char *path,
935                 const char *interface,
936                 const char *property,
937                 sd_bus_message *reply,
938                 sd_bus_error *error,
939                 void *userdata) {
940
941         int b = *(bool*) userdata;
942
943         return sd_bus_message_append_basic(reply, 'b', &b);
944 }
945
946 int bus_property_get_uid(
947                 sd_bus *bus,
948                 const char *path,
949                 const char *interface,
950                 const char *property,
951                 sd_bus_message *reply,
952                 sd_bus_error *error,
953                 void *userdata) {
954
955         assert_cc(sizeof(uint32_t) == sizeof(uid_t));
956         assert_cc(sizeof(uint32_t) == sizeof(gid_t));
957         assert_cc(sizeof(uint32_t) == sizeof(pid_t));
958
959         return sd_bus_message_append_basic(reply, 'u', userdata);
960 }