]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/bus-util.c
polkit: don't spawn local client if we access a remote system
[thirdparty/systemd.git] / src / libsystemd-bus / bus-util.c
CommitLineData
40ca29a1
LP
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
0c842e0a
TG
22#include <sys/socket.h>
23
40ca29a1 24#include "util.h"
ffc06c35 25#include "strv.h"
40ca29a1
LP
26#include "macro.h"
27#include "def.h"
28
ffc06c35
KS
29#include "sd-event.h"
30#include "sd-bus.h"
31#include "bus-error.h"
32#include "bus-message.h"
33
40ca29a1
LP
34#include "bus-util.h"
35
36static 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
47int 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
73int 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
abc5fe72 89 r = sd_event_run(e, exiting ? (uint64_t) -1 : timeout);
40ca29a1
LP
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
105int 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
124int 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;
102d8f81 154 int authorized = false, challenge = false;
40ca29a1
LP
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
313333b4
LP
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);
40ca29a1
LP
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
200typedef 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
207static 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
232static 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
247int 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) {
102d8f81 273 int authorized, challenge;
40ca29a1
LP
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
374void 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}
0c842e0a
TG
384
385static int bus_check_peercred(sd_bus *c) {
0c842e0a
TG
386 struct ucred ucred;
387 socklen_t l;
0f8bd8de 388 int fd;
0c842e0a
TG
389
390 assert(c);
391
392 fd = sd_bus_get_fd(c);
0f8bd8de
LP
393 if (fd < 0)
394 return fd;
0c842e0a
TG
395
396 l = sizeof(struct ucred);
0f8bd8de 397 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
0c842e0a 398 return -errno;
0c842e0a 399
0f8bd8de 400 if (l != sizeof(struct ucred))
0c842e0a 401 return -E2BIG;
0c842e0a
TG
402
403 if (ucred.uid != 0 && ucred.uid != geteuid())
404 return -EPERM;
405
406 return 1;
407}
408
0f8bd8de
LP
409int bus_open_system_systemd(sd_bus **_bus) {
410 _cleanup_bus_unref_ sd_bus *bus = NULL;
0c842e0a 411 int r;
0c842e0a
TG
412
413 assert(_bus);
414
0f8bd8de
LP
415 if (geteuid() != 0)
416 return sd_bus_open_system(_bus);
a1da8583 417
0f8bd8de
LP
418 /* If we are root, then let's talk directly to the system
419 * instance, instead of going via the bus */
a1da8583 420
0f8bd8de
LP
421 r = sd_bus_new(&bus);
422 if (r < 0)
423 return r;
a1da8583 424
0f8bd8de
LP
425 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
426 if (r < 0)
427 return r;
a1da8583 428
0f8bd8de
LP
429 r = sd_bus_start(bus);
430 if (r < 0)
431 return r;
a1da8583 432
0f8bd8de 433 r = bus_check_peercred(bus);
a1da8583
TG
434 if (r < 0)
435 return r;
436
437 *_bus = bus;
0f8bd8de
LP
438 bus = NULL;
439
a1da8583
TG
440 return 0;
441}
442
9f6eb1cd 443int bus_print_property(const char *name, sd_bus_message *property, bool all) {
a1da8583
TG
444 char type;
445 const char *contents;
9f6eb1cd 446 int r;
a1da8583
TG
447
448 assert(name);
449 assert(property);
450
9f6eb1cd
KS
451 r = sd_bus_message_peek_type(property, &type, &contents);
452 if (r < 0)
453 return r;
a1da8583
TG
454
455 switch (type) {
456
457 case SD_BUS_TYPE_STRING: {
458 const char *s;
9f6eb1cd
KS
459
460 r = sd_bus_message_read_basic(property, type, &s);
461 if (r < 0)
462 return r;
a1da8583
TG
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
9f6eb1cd
KS
473 r = sd_bus_message_read_basic(property, type, &b);
474 if (r < 0)
475 return r;
476
a1da8583
TG
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
9f6eb1cd
KS
485 r = sd_bus_message_read_basic(property, type, &u);
486 if (r < 0)
487 return r;
a1da8583
TG
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
9f6eb1cd
KS
512 r = sd_bus_message_read_basic(property, type, &u);
513 if (r < 0)
514 return r;
a1da8583
TG
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
9f6eb1cd
KS
527 r = sd_bus_message_read_basic(property, type, &i);
528 if (r < 0)
529 return r;
a1da8583
TG
530
531 printf("%s=%i\n", name, (int) i);
532 return 1;
533 }
534
535 case SD_BUS_TYPE_DOUBLE: {
536 double d;
537
9f6eb1cd
KS
538 r = sd_bus_message_read_basic(property, type, &d);
539 if (r < 0)
540 return r;
a1da8583
TG
541
542 printf("%s=%g\n", name, d);
543 return 1;
544 }
545
546 case SD_BUS_TYPE_ARRAY:
a1da8583 547 if (streq(contents, "s")) {
261afec5
MAP
548 bool first = true;
549 const char *str;
a1da8583 550
9f6eb1cd
KS
551 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
552 if (r < 0)
553 return r;
554
261afec5
MAP
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 }
9f6eb1cd
KS
563 if (r < 0)
564 return r;
a1da8583 565
261afec5 566 if (first && all)
a1da8583 567 printf("%s=", name);
261afec5 568 if (!first || all)
a1da8583 569 puts("");
a1da8583 570
9f6eb1cd
KS
571 r = sd_bus_message_exit_container(property);
572 if (r < 0)
573 return r;
a1da8583
TG
574
575 return 1;
576
577 } else if (streq(contents, "y")) {
578 const uint8_t *u;
579 size_t n;
580
9f6eb1cd
KS
581 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
582 if (r < 0)
583 return r;
584
a1da8583
TG
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
9f6eb1cd
KS
602 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
603 if (r < 0)
604 return r;
605
a1da8583
TG
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}
d21ed1ea 625
27e72d6b 626int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
9f6eb1cd 627 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
ffc06c35
KS
628 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
629 int r;
630
9f6eb1cd
KS
631 assert(bus);
632 assert(path);
633
634 r = sd_bus_call_method(bus,
27e72d6b 635 dest,
ffc06c35
KS
636 path,
637 "org.freedesktop.DBus.Properties",
638 "GetAll",
639 &error,
9f6eb1cd 640 &reply,
ffc06c35 641 "s", "");
9f6eb1cd 642 if (r < 0)
ffc06c35 643 return r;
ffc06c35 644
9f6eb1cd 645 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
ffc06c35
KS
646 if (r < 0)
647 return r;
648
9f6eb1cd 649 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
ffc06c35 650 const char *name;
ffc06c35 651 const char *contents;
ffc06c35 652
9f6eb1cd 653 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
ffc06c35
KS
654 if (r < 0)
655 return r;
656
9f6eb1cd
KS
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;
ffc06c35 665
9f6eb1cd
KS
666 r = bus_print_property(name, reply, all);
667 if (r < 0)
668 return r;
27e72d6b
SP
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 }
9f6eb1cd
KS
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);
ffc06c35
KS
688 if (r < 0)
689 return r;
9f6eb1cd
KS
690 }
691 if (r < 0)
692 return r;
ffc06c35 693
9f6eb1cd
KS
694 r = sd_bus_message_exit_container(reply);
695 if (r < 0)
696 return r;
ffc06c35 697
9f6eb1cd
KS
698 return 0;
699}
ffc06c35 700
9f6eb1cd
KS
701int 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;
ffc06c35 706
9f6eb1cd
KS
707 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
708 if (r < 0)
709 return r;
ffc06c35 710
9f6eb1cd
KS
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;
ffc06c35 717
9f6eb1cd
KS
718 return 0;
719}
ffc06c35 720
9f6eb1cd
KS
721static 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;
ffc06c35 724
9f6eb1cd
KS
725 r = sd_bus_message_peek_type(m, &type, NULL);
726 if (r < 0)
727 return r;
ffc06c35 728
9f6eb1cd
KS
729 switch (type) {
730 case SD_BUS_TYPE_STRING: {
731 const char *s;
732 char *str;
733 char **p = userdata;
ffc06c35 734
9f6eb1cd
KS
735 r = sd_bus_message_read_basic(m, type, &s);
736 if (r < 0)
737 break;
ffc06c35 738
9f6eb1cd
KS
739 if (isempty(s))
740 break;
ffc06c35 741
9f6eb1cd
KS
742 str = strdup(s);
743 if (!str) {
744 r = -ENOMEM;
ffc06c35
KS
745 break;
746 }
9f6eb1cd
KS
747 free(*p);
748 *p = str;
ffc06c35 749
9f6eb1cd
KS
750 break;
751 }
ffc06c35 752
9f6eb1cd
KS
753 case SD_BUS_TYPE_ARRAY: {
754 _cleanup_strv_free_ char **l = NULL;
755 char ***p = userdata;
ffc06c35 756
9f6eb1cd
KS
757 r = bus_message_read_strv_extend(m, &l);
758 if (r < 0)
759 break;
ffc06c35 760
9f6eb1cd
KS
761 strv_free(*p);
762 *p = l;
763 l = NULL;
ffc06c35 764
9f6eb1cd
KS
765 break;
766 }
ffc06c35 767
9f6eb1cd
KS
768 case SD_BUS_TYPE_BOOLEAN: {
769 unsigned b;
770 bool *p = userdata;
ffc06c35 771
9f6eb1cd
KS
772 r = sd_bus_message_read_basic(m, type, &b);
773 if (r < 0)
774 break;
ffc06c35 775
9f6eb1cd 776 *p = b;
ffc06c35 777
9f6eb1cd
KS
778 break;
779 }
ffc06c35 780
9f6eb1cd
KS
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)
ffc06c35 787 break;
ffc06c35 788
9f6eb1cd
KS
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)
ffc06c35 800 break;
ffc06c35 801
9f6eb1cd
KS
802 *p = t;
803
804 break;
805 }
806
807 default:
808 break;
809 }
810
811 return r;
812}
813
814int 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);
ffc06c35
KS
851 if (r < 0)
852 return r;
853
9f6eb1cd
KS
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;
27e72d6b 870 if (map[i].set)
9f6eb1cd
KS
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
ffc06c35
KS
884 r = sd_bus_message_exit_container(m);
885 if (r < 0)
886 return r;
887 }
888
ffc06c35
KS
889 return r;
890}
891
d21ed1ea
LP
892int 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}
e6504030
LP
926
927int 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
941int 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}