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