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