chiark / gitweb /
sd-bus: add new call sd_bus_get_scope() for querying whether one is connected to...
[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                         _cleanup_free_ char *escaped = NULL;
645
646                         escaped = xescape(s, "\n");
647                         if (!escaped)
648                                 return -ENOMEM;
649
650                         printf("%s=%s\n", name, escaped);
651                 }
652
653                 return 1;
654         }
655
656         case SD_BUS_TYPE_BOOLEAN: {
657                 int b;
658
659                 r = sd_bus_message_read_basic(property, type, &b);
660                 if (r < 0)
661                         return r;
662
663                 printf("%s=%s\n", name, yes_no(b));
664
665                 return 1;
666         }
667
668         case SD_BUS_TYPE_UINT64: {
669                 uint64_t u;
670
671                 r = sd_bus_message_read_basic(property, type, &u);
672                 if (r < 0)
673                         return r;
674
675                 /* Yes, heuristics! But we can change this check
676                  * should it turn out to not be sufficient */
677
678                 if (endswith(name, "Timestamp")) {
679                         char timestamp[FORMAT_TIMESTAMP_MAX], *t;
680
681                         t = format_timestamp(timestamp, sizeof(timestamp), u);
682                         if (t || all)
683                                 printf("%s=%s\n", name, strempty(t));
684
685                 } else if (strstr(name, "USec")) {
686                         char timespan[FORMAT_TIMESPAN_MAX];
687
688                         printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
689                 } else
690                         printf("%s=%llu\n", name, (unsigned long long) u);
691
692                 return 1;
693         }
694
695         case SD_BUS_TYPE_UINT32: {
696                 uint32_t u;
697
698                 r = sd_bus_message_read_basic(property, type, &u);
699                 if (r < 0)
700                         return r;
701
702                 if (strstr(name, "UMask") || strstr(name, "Mode"))
703                         printf("%s=%04o\n", name, u);
704                 else
705                         printf("%s=%u\n", name, (unsigned) u);
706
707                 return 1;
708         }
709
710         case SD_BUS_TYPE_INT32: {
711                 int32_t i;
712
713                 r = sd_bus_message_read_basic(property, type, &i);
714                 if (r < 0)
715                         return r;
716
717                 printf("%s=%i\n", name, (int) i);
718                 return 1;
719         }
720
721         case SD_BUS_TYPE_DOUBLE: {
722                 double d;
723
724                 r = sd_bus_message_read_basic(property, type, &d);
725                 if (r < 0)
726                         return r;
727
728                 printf("%s=%g\n", name, d);
729                 return 1;
730         }
731
732         case SD_BUS_TYPE_ARRAY:
733                 if (streq(contents, "s")) {
734                         bool first = true;
735                         const char *str;
736
737                         r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
738                         if (r < 0)
739                                 return r;
740
741                         while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
742                                 _cleanup_free_ char *escaped = NULL;
743
744                                 if (first)
745                                         printf("%s=", name);
746
747                                 escaped = xescape(str, "\n ");
748                                 if (!escaped)
749                                         return -ENOMEM;
750
751                                 printf("%s%s", first ? "" : " ", escaped);
752
753                                 first = false;
754                         }
755                         if (r < 0)
756                                 return r;
757
758                         if (first && all)
759                                 printf("%s=", name);
760                         if (!first || all)
761                                 puts("");
762
763                         r = sd_bus_message_exit_container(property);
764                         if (r < 0)
765                                 return r;
766
767                         return 1;
768
769                 } else if (streq(contents, "y")) {
770                         const uint8_t *u;
771                         size_t n;
772
773                         r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
774                         if (r < 0)
775                                 return r;
776
777                         if (all || n > 0) {
778                                 unsigned int i;
779
780                                 printf("%s=", name);
781
782                                 for (i = 0; i < n; i++)
783                                         printf("%02x", u[i]);
784
785                                 puts("");
786                         }
787
788                         return 1;
789
790                 } else if (streq(contents, "u")) {
791                         uint32_t *u;
792                         size_t n;
793
794                         r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
795                         if (r < 0)
796                                 return r;
797
798                         if (all || n > 0) {
799                                 unsigned int i;
800
801                                 printf("%s=", name);
802
803                                 for (i = 0; i < n; i++)
804                                         printf("%08x", u[i]);
805
806                                 puts("");
807                         }
808
809                         return 1;
810                 }
811
812                 break;
813         }
814
815         return 0;
816 }
817
818 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
819         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
820         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
821         int r;
822
823         assert(bus);
824         assert(path);
825
826         r = sd_bus_call_method(bus,
827                         dest,
828                         path,
829                         "org.freedesktop.DBus.Properties",
830                         "GetAll",
831                         &error,
832                         &reply,
833                         "s", "");
834         if (r < 0)
835                 return r;
836
837         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
838         if (r < 0)
839                 return r;
840
841         while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
842                 const char *name;
843                 const char *contents;
844
845                 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
846                 if (r < 0)
847                         return r;
848
849                 if (!filter || strv_find(filter, name)) {
850                         r = sd_bus_message_peek_type(reply, NULL, &contents);
851                         if (r < 0)
852                                 return r;
853
854                         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
855                         if (r < 0)
856                                 return r;
857
858                         r = bus_print_property(name, reply, all);
859                         if (r < 0)
860                                 return r;
861                         if (r == 0) {
862                                 if (all)
863                                         printf("%s=[unprintable]\n", name);
864                                 /* skip what we didn't read */
865                                 r = sd_bus_message_skip(reply, contents);
866                                 if (r < 0)
867                                         return r;
868                         }
869
870                         r = sd_bus_message_exit_container(reply);
871                         if (r < 0)
872                                 return r;
873                 } else {
874                         r = sd_bus_message_skip(reply, "v");
875                         if (r < 0)
876                                 return r;
877                 }
878
879                 r = sd_bus_message_exit_container(reply);
880                 if (r < 0)
881                         return r;
882         }
883         if (r < 0)
884                 return r;
885
886         r = sd_bus_message_exit_container(reply);
887         if (r < 0)
888                 return r;
889
890         return 0;
891 }
892
893 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
894         sd_id128_t *p = userdata;
895         const void *v;
896         size_t n;
897         int r;
898
899         r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
900         if (r < 0)
901                 return r;
902
903         if (n == 0)
904                 *p = SD_ID128_NULL;
905         else if (n == 16)
906                 memcpy((*p).bytes, v, n);
907         else
908                 return -EINVAL;
909
910         return 0;
911 }
912
913 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
914         char type;
915         int r;
916
917         r = sd_bus_message_peek_type(m, &type, NULL);
918         if (r < 0)
919                 return r;
920
921         switch (type) {
922         case SD_BUS_TYPE_STRING: {
923                 const char *s;
924                 char *str;
925                 char **p = userdata;
926
927                 r = sd_bus_message_read_basic(m, type, &s);
928                 if (r < 0)
929                         break;
930
931                 if (isempty(s))
932                         break;
933
934                 str = strdup(s);
935                 if (!str) {
936                         r = -ENOMEM;
937                         break;
938                 }
939                 free(*p);
940                 *p = str;
941
942                 break;
943         }
944
945         case SD_BUS_TYPE_ARRAY: {
946                _cleanup_strv_free_ char **l = NULL;
947                char ***p = userdata;
948
949                 r = bus_message_read_strv_extend(m, &l);
950                 if (r < 0)
951                         break;
952
953                 strv_free(*p);
954                 *p = l;
955                 l = NULL;
956
957                 break;
958         }
959
960         case SD_BUS_TYPE_BOOLEAN: {
961                 unsigned b;
962                 bool *p = userdata;
963
964                 r = sd_bus_message_read_basic(m, type, &b);
965                 if (r < 0)
966                         break;
967
968                 *p = b;
969
970                 break;
971         }
972
973         case SD_BUS_TYPE_UINT32: {
974                 uint64_t u;
975                 uint32_t *p = userdata;
976
977                 r = sd_bus_message_read_basic(m, type, &u);
978                 if (r < 0)
979                         break;
980
981                 *p = u;
982
983                 break;
984         }
985
986         case SD_BUS_TYPE_UINT64: {
987                 uint64_t t;
988                 uint64_t *p = userdata;
989
990                 r = sd_bus_message_read_basic(m, type, &t);
991                 if (r < 0)
992                         break;
993
994                 *p = t;
995
996                 break;
997         }
998
999         default:
1000                 break;
1001         }
1002
1003         return r;
1004 }
1005
1006 int bus_message_map_all_properties(sd_bus *bus,
1007                                    sd_bus_message *m,
1008                                    const struct bus_properties_map *map,
1009                                    void *userdata) {
1010         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1011         int r;
1012
1013         assert(bus);
1014         assert(m);
1015         assert(map);
1016
1017         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
1018         if (r < 0)
1019                 return r;
1020
1021         while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
1022                 const struct bus_properties_map *prop;
1023                 const char *member;
1024                 const char *contents;
1025                 void *v;
1026                 unsigned i;
1027
1028                 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
1029                 if (r < 0)
1030                         return r;
1031
1032                 for (i = 0, prop = NULL; map[i].member; i++)
1033                         if (streq(map[i].member, member)) {
1034                                 prop = &map[i];
1035                                 break;
1036                         }
1037
1038                 if (prop) {
1039                         r = sd_bus_message_peek_type(m, NULL, &contents);
1040                         if (r < 0)
1041                                 return r;
1042
1043                         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1044                         if (r < 0)
1045                                 return r;
1046
1047                         v = (uint8_t *)userdata + prop->offset;
1048                         if (map[i].set)
1049                                 r = prop->set(bus, member, m, &error, v);
1050                         else
1051                                 r = map_basic(bus, member, m, &error, v);
1052                         if (r < 0)
1053                                 return r;
1054
1055                         r = sd_bus_message_exit_container(m);
1056                         if (r < 0)
1057                                 return r;
1058                 } else {
1059                         r = sd_bus_message_skip(m, "v");
1060                         if (r < 0)
1061                                 return r;
1062                 }
1063
1064                 r = sd_bus_message_exit_container(m);
1065                 if (r < 0)
1066                         return r;
1067         }
1068
1069         return sd_bus_message_exit_container(m);
1070 }
1071
1072 int bus_message_map_properties_changed(sd_bus *bus,
1073                                        sd_bus_message *m,
1074                                        const struct bus_properties_map *map,
1075                                        void *userdata) {
1076         const char *member;
1077         int r, invalidated, i;
1078
1079         assert(bus);
1080         assert(m);
1081         assert(map);
1082
1083         r = bus_message_map_all_properties(bus, m, map, userdata);
1084         if (r < 0)
1085                 return r;
1086
1087         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
1088         if (r < 0)
1089                 return r;
1090
1091         invalidated = 0;
1092         while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member)) > 0)
1093                 for (i = 0; map[i].member; i++)
1094                         if (streq(map[i].member, member)) {
1095                                 ++invalidated;
1096                                 break;
1097                         }
1098
1099         r = sd_bus_message_exit_container(m);
1100         if (r < 0)
1101                 return r;
1102
1103         return invalidated;
1104 }
1105
1106 int bus_map_all_properties(sd_bus *bus,
1107                            const char *destination,
1108                            const char *path,
1109                            const struct bus_properties_map *map,
1110                            void *userdata) {
1111         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1112         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1113         int r;
1114
1115         assert(bus);
1116         assert(destination);
1117         assert(path);
1118         assert(map);
1119
1120         r = sd_bus_call_method(
1121                         bus,
1122                         destination,
1123                         path,
1124                         "org.freedesktop.DBus.Properties",
1125                         "GetAll",
1126                         &error,
1127                         &m,
1128                         "s", "");
1129         if (r < 0)
1130                 return r;
1131
1132         return bus_message_map_all_properties(bus, m, map, userdata);
1133 }
1134
1135 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1136         int r;
1137
1138         assert(transport >= 0);
1139         assert(transport < _BUS_TRANSPORT_MAX);
1140         assert(bus);
1141
1142         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1143         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1144
1145         switch (transport) {
1146
1147         case BUS_TRANSPORT_LOCAL:
1148                 if (user)
1149                         r = sd_bus_default_user(bus);
1150                 else
1151                         r = sd_bus_default_system(bus);
1152
1153                 break;
1154
1155         case BUS_TRANSPORT_REMOTE:
1156                 r = sd_bus_open_system_remote(bus, host);
1157                 break;
1158
1159         case BUS_TRANSPORT_CONTAINER:
1160                 r = sd_bus_open_system_container(bus, host);
1161                 break;
1162
1163         default:
1164                 assert_not_reached("Hmm, unknown transport type.");
1165         }
1166
1167         return r;
1168 }
1169
1170 int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1171         int r;
1172
1173         assert(transport >= 0);
1174         assert(transport < _BUS_TRANSPORT_MAX);
1175         assert(bus);
1176
1177         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1178         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1179
1180         switch (transport) {
1181
1182         case BUS_TRANSPORT_LOCAL:
1183                 if (user)
1184                         r = bus_open_user_systemd(bus);
1185                 else
1186                         r = bus_open_system_systemd(bus);
1187
1188                 break;
1189
1190         case BUS_TRANSPORT_REMOTE:
1191                 r = sd_bus_open_system_remote(bus, host);
1192                 break;
1193
1194         case BUS_TRANSPORT_CONTAINER:
1195                 r = sd_bus_open_system_container(bus, host);
1196                 break;
1197
1198         default:
1199                 assert_not_reached("Hmm, unknown transport type.");
1200         }
1201
1202         return r;
1203 }
1204
1205 int bus_property_get_bool(
1206                 sd_bus *bus,
1207                 const char *path,
1208                 const char *interface,
1209                 const char *property,
1210                 sd_bus_message *reply,
1211                 void *userdata,
1212                 sd_bus_error *error) {
1213
1214         int b = *(bool*) userdata;
1215
1216         return sd_bus_message_append_basic(reply, 'b', &b);
1217 }
1218
1219 #if __SIZEOF_SIZE_T__ != 8
1220 int bus_property_get_size(
1221                 sd_bus *bus,
1222                 const char *path,
1223                 const char *interface,
1224                 const char *property,
1225                 sd_bus_message *reply,
1226                 void *userdata,
1227                 sd_bus_error *error) {
1228
1229         uint64_t sz = *(size_t*) userdata;
1230
1231         return sd_bus_message_append_basic(reply, 't', &sz);
1232 }
1233 #endif
1234
1235 #if __SIZEOF_LONG__ != 8
1236 int bus_property_get_long(
1237                 sd_bus *bus,
1238                 const char *path,
1239                 const char *interface,
1240                 const char *property,
1241                 sd_bus_message *reply,
1242                 void *userdata,
1243                 sd_bus_error *error) {
1244
1245         int64_t l = *(long*) userdata;
1246
1247         return sd_bus_message_append_basic(reply, 'x', &l);
1248 }
1249
1250 int bus_property_get_ulong(
1251                 sd_bus *bus,
1252                 const char *path,
1253                 const char *interface,
1254                 const char *property,
1255                 sd_bus_message *reply,
1256                 void *userdata,
1257                 sd_bus_error *error) {
1258
1259         uint64_t ul = *(unsigned long*) userdata;
1260
1261         return sd_bus_message_append_basic(reply, 't', &ul);
1262 }
1263 #endif
1264
1265 int bus_log_parse_error(int r) {
1266         log_error_errno(r, "Failed to parse bus message: %m");
1267         return r;
1268 }
1269
1270 int bus_log_create_error(int r) {
1271         log_error_errno(r, "Failed to create bus message: %m");
1272         return r;
1273 }
1274
1275 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1276         assert(message);
1277         assert(u);
1278
1279         u->machine = NULL;
1280
1281         return sd_bus_message_read(
1282                         message,
1283                         "(ssssssouso)",
1284                         &u->id,
1285                         &u->description,
1286                         &u->load_state,
1287                         &u->active_state,
1288                         &u->sub_state,
1289                         &u->following,
1290                         &u->unit_path,
1291                         &u->job_id,
1292                         &u->job_type,
1293                         &u->job_path);
1294 }
1295
1296 int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
1297         assert(m);
1298
1299         if (r < 0) {
1300                 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1301                         sd_bus_reply_method_errno(m, r, error);
1302
1303         } else if (sd_bus_error_is_set(error)) {
1304                 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1305                         sd_bus_reply_method_error(m, error);
1306         } else
1307                 return r;
1308
1309         log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
1310                   bus_message_type_to_string(m->header->type),
1311                   strna(m->sender),
1312                   strna(m->path),
1313                   strna(m->interface),
1314                   strna(m->member),
1315                   strna(m->root_container.signature),
1316                   bus_error_message(error, r));
1317
1318         return 1;
1319 }
1320
1321 int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
1322         const char *eq, *field;
1323         int r;
1324
1325         assert(m);
1326         assert(assignment);
1327
1328         eq = strchr(assignment, '=');
1329         if (!eq) {
1330                 log_error("Not an assignment: %s", assignment);
1331                 return -EINVAL;
1332         }
1333
1334         field = strndupa(assignment, eq - assignment);
1335         eq ++;
1336
1337         if (streq(field, "CPUQuota")) {
1338
1339                 if (isempty(eq)) {
1340
1341                         r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1342                         if (r < 0)
1343                                 return bus_log_create_error(r);
1344
1345                         r = sd_bus_message_append(m, "v", "t", USEC_INFINITY);
1346
1347                 } else if (endswith(eq, "%")) {
1348                         double percent;
1349
1350                         if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) {
1351                                 log_error("CPU quota '%s' invalid.", eq);
1352                                 return -EINVAL;
1353                         }
1354
1355                         r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1356                         if (r < 0)
1357                                 return bus_log_create_error(r);
1358
1359                         r = sd_bus_message_append(m, "v", "t", (usec_t) percent * USEC_PER_SEC / 100);
1360                 } else {
1361                         log_error("CPU quota needs to be in percent.");
1362                         return -EINVAL;
1363                 }
1364
1365                 if (r < 0)
1366                         return bus_log_create_error(r);
1367
1368                 return 0;
1369         }
1370
1371         r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1372         if (r < 0)
1373                 return bus_log_create_error(r);
1374
1375         if (STR_IN_SET(field,
1376                        "CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
1377                        "SendSIGHUP", "SendSIGKILL")) {
1378
1379                 r = parse_boolean(eq);
1380                 if (r < 0) {
1381                         log_error("Failed to parse boolean assignment %s.", assignment);
1382                         return -EINVAL;
1383                 }
1384
1385                 r = sd_bus_message_append(m, "v", "b", r);
1386
1387         } else if (streq(field, "MemoryLimit")) {
1388                 off_t bytes;
1389
1390                 r = parse_size(eq, 1024, &bytes);
1391                 if (r < 0) {
1392                         log_error("Failed to parse bytes specification %s", assignment);
1393                         return -EINVAL;
1394                 }
1395
1396                 r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
1397
1398         } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) {
1399                 uint64_t u;
1400
1401                 r = safe_atou64(eq, &u);
1402                 if (r < 0) {
1403                         log_error("Failed to parse %s value %s.", field, eq);
1404                         return -EINVAL;
1405                 }
1406
1407                 r = sd_bus_message_append(m, "v", "t", u);
1408
1409         } else if (STR_IN_SET(field, "User", "Group", "DevicePolicy", "KillMode"))
1410                 r = sd_bus_message_append(m, "v", "s", eq);
1411
1412         else if (streq(field, "DeviceAllow")) {
1413
1414                 if (isempty(eq))
1415                         r = sd_bus_message_append(m, "v", "a(ss)", 0);
1416                 else {
1417                         const char *path, *rwm, *e;
1418
1419                         e = strchr(eq, ' ');
1420                         if (e) {
1421                                 path = strndupa(eq, e - eq);
1422                                 rwm = e+1;
1423                         } else {
1424                                 path = eq;
1425                                 rwm = "";
1426                         }
1427
1428                         if (!path_startswith(path, "/dev")) {
1429                                 log_error("%s is not a device file in /dev.", path);
1430                                 return -EINVAL;
1431                         }
1432
1433                         r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
1434                 }
1435
1436         } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1437
1438                 if (isempty(eq))
1439                         r = sd_bus_message_append(m, "v", "a(st)", 0);
1440                 else {
1441                         const char *path, *bandwidth, *e;
1442                         off_t bytes;
1443
1444                         e = strchr(eq, ' ');
1445                         if (e) {
1446                                 path = strndupa(eq, e - eq);
1447                                 bandwidth = e+1;
1448                         } else {
1449                                 log_error("Failed to parse %s value %s.", field, eq);
1450                                 return -EINVAL;
1451                         }
1452
1453                         if (!path_startswith(path, "/dev")) {
1454                                 log_error("%s is not a device file in /dev.", path);
1455                                 return -EINVAL;
1456                         }
1457
1458                         r = parse_size(bandwidth, 1000, &bytes);
1459                         if (r < 0) {
1460                                 log_error("Failed to parse byte value %s.", bandwidth);
1461                                 return -EINVAL;
1462                         }
1463
1464                         r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes);
1465                 }
1466
1467         } else if (streq(field, "BlockIODeviceWeight")) {
1468
1469                 if (isempty(eq))
1470                         r = sd_bus_message_append(m, "v", "a(st)", 0);
1471                 else {
1472                         const char *path, *weight, *e;
1473                         uint64_t u;
1474
1475                         e = strchr(eq, ' ');
1476                         if (e) {
1477                                 path = strndupa(eq, e - eq);
1478                                 weight = e+1;
1479                         } else {
1480                                 log_error("Failed to parse %s value %s.", field, eq);
1481                                 return -EINVAL;
1482                         }
1483
1484                         if (!path_startswith(path, "/dev")) {
1485                                 log_error("%s is not a device file in /dev.", path);
1486                                 return -EINVAL;
1487                         }
1488
1489                         r = safe_atou64(weight, &u);
1490                         if (r < 0) {
1491                                 log_error("Failed to parse %s value %s.", field, weight);
1492                                 return -EINVAL;
1493                         }
1494                         r = sd_bus_message_append(m, "v", "a(st)", path, u);
1495                 }
1496
1497         } else if (rlimit_from_string(field) >= 0) {
1498                 uint64_t rl;
1499
1500                 if (streq(eq, "infinity"))
1501                         rl = (uint64_t) -1;
1502                 else {
1503                         r = safe_atou64(eq, &rl);
1504                         if (r < 0) {
1505                                 log_error("Invalid resource limit: %s", eq);
1506                                 return -EINVAL;
1507                         }
1508                 }
1509
1510                 r = sd_bus_message_append(m, "v", "t", rl);
1511
1512         } else if (streq(field, "Nice")) {
1513                 int32_t i;
1514
1515                 r = safe_atoi32(eq, &i);
1516                 if (r < 0) {
1517                         log_error("Failed to parse %s value %s.", field, eq);
1518                         return -EINVAL;
1519                 }
1520
1521                 r = sd_bus_message_append(m, "v", "i", i);
1522
1523         } else if (streq(field, "Environment")) {
1524
1525                 r = sd_bus_message_append(m, "v", "as", 1, eq);
1526
1527         } else if (streq(field, "KillSignal")) {
1528                 int sig;
1529
1530                 sig = signal_from_string_try_harder(eq);
1531                 if (sig < 0) {
1532                         log_error("Failed to parse %s value %s.", field, eq);
1533                         return -EINVAL;
1534                 }
1535
1536                 r = sd_bus_message_append(m, "v", "i", sig);
1537
1538         } else {
1539                 log_error("Unknown assignment %s.", assignment);
1540                 return -EINVAL;
1541         }
1542
1543         if (r < 0)
1544                 return bus_log_create_error(r);
1545
1546         return 0;
1547 }