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