chiark / gitweb /
aed3889b121819a255545e254fb6799f6904e5d3
[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, trivial_hash_func, trivial_compare_func);
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         /* skip interface, but allow callers to do that themselves */
1055         sd_bus_message_skip(m, "s");
1056
1057         r = bus_message_map_all_properties(bus, m, map, userdata);
1058         if (r < 0)
1059                 return r;
1060
1061         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
1062         if (r < 0)
1063                 return r;
1064
1065         invalidated = 0;
1066         while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member)) > 0)
1067                 for (i = 0; map[i].member; i++)
1068                         if (streq(map[i].member, member)) {
1069                                 ++invalidated;
1070                                 break;
1071                         }
1072
1073         r = sd_bus_message_exit_container(m);
1074         if (r < 0)
1075                 return r;
1076
1077         return invalidated;
1078 }
1079
1080 int bus_map_all_properties(sd_bus *bus,
1081                            const char *destination,
1082                            const char *path,
1083                            const struct bus_properties_map *map,
1084                            void *userdata) {
1085         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1086         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1087         int r;
1088
1089         assert(bus);
1090         assert(destination);
1091         assert(path);
1092         assert(map);
1093
1094         r = sd_bus_call_method(
1095                         bus,
1096                         destination,
1097                         path,
1098                         "org.freedesktop.DBus.Properties",
1099                         "GetAll",
1100                         &error,
1101                         &m,
1102                         "s", "");
1103         if (r < 0)
1104                 return r;
1105
1106         return bus_message_map_all_properties(bus, m, map, userdata);
1107 }
1108
1109 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1110         int r;
1111
1112         assert(transport >= 0);
1113         assert(transport < _BUS_TRANSPORT_MAX);
1114         assert(bus);
1115
1116         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1117         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1118
1119         switch (transport) {
1120
1121         case BUS_TRANSPORT_LOCAL:
1122                 if (user)
1123                         r = sd_bus_default_user(bus);
1124                 else
1125                         r = sd_bus_default_system(bus);
1126
1127                 break;
1128
1129         case BUS_TRANSPORT_REMOTE:
1130                 r = sd_bus_open_system_remote(bus, host);
1131                 break;
1132
1133         case BUS_TRANSPORT_CONTAINER:
1134                 r = sd_bus_open_system_container(bus, host);
1135                 break;
1136
1137         default:
1138                 assert_not_reached("Hmm, unknown transport type.");
1139         }
1140
1141         return r;
1142 }
1143
1144 int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1145         int r;
1146
1147         assert(transport >= 0);
1148         assert(transport < _BUS_TRANSPORT_MAX);
1149         assert(bus);
1150
1151         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1152         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1153
1154         switch (transport) {
1155
1156         case BUS_TRANSPORT_LOCAL:
1157                 if (user)
1158                         r = bus_open_user_systemd(bus);
1159                 else
1160                         r = bus_open_system_systemd(bus);
1161
1162                 break;
1163
1164         case BUS_TRANSPORT_REMOTE:
1165                 r = sd_bus_open_system_remote(bus, host);
1166                 break;
1167
1168         case BUS_TRANSPORT_CONTAINER:
1169                 r = sd_bus_open_system_container(bus, host);
1170                 break;
1171
1172         default:
1173                 assert_not_reached("Hmm, unknown transport type.");
1174         }
1175
1176         return r;
1177 }
1178
1179 int bus_property_get_bool(
1180                 sd_bus *bus,
1181                 const char *path,
1182                 const char *interface,
1183                 const char *property,
1184                 sd_bus_message *reply,
1185                 void *userdata,
1186                 sd_bus_error *error) {
1187
1188         int b = *(bool*) userdata;
1189
1190         return sd_bus_message_append_basic(reply, 'b', &b);
1191 }
1192
1193 #if __SIZEOF_SIZE_T__ != 8
1194 int bus_property_get_size(
1195                 sd_bus *bus,
1196                 const char *path,
1197                 const char *interface,
1198                 const char *property,
1199                 sd_bus_message *reply,
1200                 void *userdata,
1201                 sd_bus_error *error) {
1202
1203         uint64_t sz = *(size_t*) userdata;
1204
1205         return sd_bus_message_append_basic(reply, 't', &sz);
1206 }
1207 #endif
1208
1209 #if __SIZEOF_LONG__ != 8
1210 int bus_property_get_long(
1211                 sd_bus *bus,
1212                 const char *path,
1213                 const char *interface,
1214                 const char *property,
1215                 sd_bus_message *reply,
1216                 void *userdata,
1217                 sd_bus_error *error) {
1218
1219         int64_t l = *(long*) userdata;
1220
1221         return sd_bus_message_append_basic(reply, 'x', &l);
1222 }
1223
1224 int bus_property_get_ulong(
1225                 sd_bus *bus,
1226                 const char *path,
1227                 const char *interface,
1228                 const char *property,
1229                 sd_bus_message *reply,
1230                 void *userdata,
1231                 sd_bus_error *error) {
1232
1233         uint64_t ul = *(unsigned long*) userdata;
1234
1235         return sd_bus_message_append_basic(reply, 't', &ul);
1236 }
1237 #endif
1238
1239 int bus_log_parse_error(int r) {
1240         log_error("Failed to parse bus message: %s", strerror(-r));
1241         return r;
1242 }
1243
1244 int bus_log_create_error(int r) {
1245         log_error("Failed to create bus message: %s", strerror(-r));
1246         return r;
1247 }
1248
1249 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1250         assert(message);
1251         assert(u);
1252
1253         u->machine = NULL;
1254
1255         return sd_bus_message_read(
1256                         message,
1257                         "(ssssssouso)",
1258                         &u->id,
1259                         &u->description,
1260                         &u->load_state,
1261                         &u->active_state,
1262                         &u->sub_state,
1263                         &u->following,
1264                         &u->unit_path,
1265                         &u->job_id,
1266                         &u->job_type,
1267                         &u->job_path);
1268 }
1269
1270 int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
1271         assert(m);
1272
1273         if (r < 0) {
1274                 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1275                         sd_bus_reply_method_errno(m, r, error);
1276
1277         } else if (sd_bus_error_is_set(error)) {
1278                 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1279                         sd_bus_reply_method_error(m, error);
1280         } else
1281                 return r;
1282
1283         log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
1284                   bus_message_type_to_string(m->header->type),
1285                   strna(m->sender),
1286                   strna(m->path),
1287                   strna(m->interface),
1288                   strna(m->member),
1289                   strna(m->root_container.signature),
1290                   bus_error_message(error, r));
1291
1292         return 1;
1293 }
1294
1295 int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
1296         const char *eq, *field;
1297         int r;
1298
1299         assert(m);
1300         assert(assignment);
1301
1302         eq = strchr(assignment, '=');
1303         if (!eq) {
1304                 log_error("Not an assignment: %s", assignment);
1305                 return -EINVAL;
1306         }
1307
1308         field = strndupa(assignment, eq - assignment);
1309         eq ++;
1310
1311         if (streq(field, "CPUQuota")) {
1312
1313                 if (isempty(eq)) {
1314
1315                         r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1316                         if (r < 0)
1317                                 return bus_log_create_error(r);
1318
1319                         r = sd_bus_message_append(m, "v", "t", USEC_INFINITY);
1320
1321                 } else if (endswith(eq, "%")) {
1322                         double percent;
1323
1324                         if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) {
1325                                 log_error("CPU quota '%s' invalid.", eq);
1326                                 return -EINVAL;
1327                         }
1328
1329                         r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1330                         if (r < 0)
1331                                 return bus_log_create_error(r);
1332
1333                         r = sd_bus_message_append(m, "v", "t", (usec_t) percent * USEC_PER_SEC / 100);
1334                 } else {
1335                         log_error("CPU quota needs to be in percent.");
1336                         return -EINVAL;
1337                 }
1338
1339                 if (r < 0)
1340                         return bus_log_create_error(r);
1341
1342                 return 0;
1343         }
1344
1345         r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1346         if (r < 0)
1347                 return bus_log_create_error(r);
1348
1349         if (STR_IN_SET(field,
1350                        "CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
1351                        "SendSIGHUP", "SendSIGKILL")) {
1352
1353                 r = parse_boolean(eq);
1354                 if (r < 0) {
1355                         log_error("Failed to parse boolean assignment %s.", assignment);
1356                         return -EINVAL;
1357                 }
1358
1359                 r = sd_bus_message_append(m, "v", "b", r);
1360
1361         } else if (streq(field, "MemoryLimit")) {
1362                 off_t bytes;
1363
1364                 r = parse_size(eq, 1024, &bytes);
1365                 if (r < 0) {
1366                         log_error("Failed to parse bytes specification %s", assignment);
1367                         return -EINVAL;
1368                 }
1369
1370                 r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
1371
1372         } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) {
1373                 uint64_t u;
1374
1375                 r = safe_atou64(eq, &u);
1376                 if (r < 0) {
1377                         log_error("Failed to parse %s value %s.", field, eq);
1378                         return -EINVAL;
1379                 }
1380
1381                 r = sd_bus_message_append(m, "v", "t", u);
1382
1383         } else if (STR_IN_SET(field, "User", "Group", "DevicePolicy", "KillMode"))
1384                 r = sd_bus_message_append(m, "v", "s", eq);
1385
1386         else if (streq(field, "DeviceAllow")) {
1387
1388                 if (isempty(eq))
1389                         r = sd_bus_message_append(m, "v", "a(ss)", 0);
1390                 else {
1391                         const char *path, *rwm, *e;
1392
1393                         e = strchr(eq, ' ');
1394                         if (e) {
1395                                 path = strndupa(eq, e - eq);
1396                                 rwm = e+1;
1397                         } else {
1398                                 path = eq;
1399                                 rwm = "";
1400                         }
1401
1402                         if (!path_startswith(path, "/dev")) {
1403                                 log_error("%s is not a device file in /dev.", path);
1404                                 return -EINVAL;
1405                         }
1406
1407                         r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
1408                 }
1409
1410         } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1411
1412                 if (isempty(eq))
1413                         r = sd_bus_message_append(m, "v", "a(st)", 0);
1414                 else {
1415                         const char *path, *bandwidth, *e;
1416                         off_t bytes;
1417
1418                         e = strchr(eq, ' ');
1419                         if (e) {
1420                                 path = strndupa(eq, e - eq);
1421                                 bandwidth = e+1;
1422                         } else {
1423                                 log_error("Failed to parse %s value %s.", field, eq);
1424                                 return -EINVAL;
1425                         }
1426
1427                         if (!path_startswith(path, "/dev")) {
1428                                 log_error("%s is not a device file in /dev.", path);
1429                                 return -EINVAL;
1430                         }
1431
1432                         r = parse_size(bandwidth, 1000, &bytes);
1433                         if (r < 0) {
1434                                 log_error("Failed to parse byte value %s.", bandwidth);
1435                                 return -EINVAL;
1436                         }
1437
1438                         r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes);
1439                 }
1440
1441         } else if (streq(field, "BlockIODeviceWeight")) {
1442
1443                 if (isempty(eq))
1444                         r = sd_bus_message_append(m, "v", "a(st)", 0);
1445                 else {
1446                         const char *path, *weight, *e;
1447                         uint64_t u;
1448
1449                         e = strchr(eq, ' ');
1450                         if (e) {
1451                                 path = strndupa(eq, e - eq);
1452                                 weight = e+1;
1453                         } else {
1454                                 log_error("Failed to parse %s value %s.", field, eq);
1455                                 return -EINVAL;
1456                         }
1457
1458                         if (!path_startswith(path, "/dev")) {
1459                                 log_error("%s is not a device file in /dev.", path);
1460                                 return -EINVAL;
1461                         }
1462
1463                         r = safe_atou64(weight, &u);
1464                         if (r < 0) {
1465                                 log_error("Failed to parse %s value %s.", field, weight);
1466                                 return -EINVAL;
1467                         }
1468                         r = sd_bus_message_append(m, "v", "a(st)", path, u);
1469                 }
1470
1471         } else if (rlimit_from_string(field) >= 0) {
1472                 uint64_t rl;
1473
1474                 if (streq(eq, "infinity"))
1475                         rl = (uint64_t) -1;
1476                 else {
1477                         r = safe_atou64(eq, &rl);
1478                         if (r < 0) {
1479                                 log_error("Invalid resource limit: %s", eq);
1480                                 return -EINVAL;
1481                         }
1482                 }
1483
1484                 r = sd_bus_message_append(m, "v", "t", rl);
1485
1486         } else if (streq(field, "Nice")) {
1487                 int32_t i;
1488
1489                 r = safe_atoi32(eq, &i);
1490                 if (r < 0) {
1491                         log_error("Failed to parse %s value %s.", field, eq);
1492                         return -EINVAL;
1493                 }
1494
1495                 r = sd_bus_message_append(m, "v", "i", i);
1496
1497         } else if (streq(field, "Environment")) {
1498
1499                 r = sd_bus_message_append(m, "v", "as", 1, eq);
1500
1501         } else if (streq(field, "KillSignal")) {
1502                 int sig;
1503
1504                 sig = signal_from_string_try_harder(eq);
1505                 if (sig < 0) {
1506                         log_error("Failed to parse %s value %s.", field, eq);
1507                         return -EINVAL;
1508                 }
1509
1510                 r = sd_bus_message_append(m, "v", "i", sig);
1511
1512         } else {
1513                 log_error("Unknown assignment %s.", assignment);
1514                 return -EINVAL;
1515         }
1516
1517         if (r < 0)
1518                 return bus_log_create_error(r);
1519
1520         return 0;
1521 }