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