chiark / gitweb /
sd-bus: Remove bus arg from bus_verify_polkit_async_registry_free()
[elogind.git] / src / libsystemd / sd-bus / bus-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/socket.h>
23 #include <sys/capability.h>
24
25 #include "util.h"
26 #include "strv.h"
27 #include "macro.h"
28 #include "def.h"
29 #include "path-util.h"
30 #include "missing.h"
31
32 #include "sd-event.h"
33 #include "sd-bus.h"
34 #include "bus-error.h"
35 #include "bus-message.h"
36 #include "bus-util.h"
37 #include "bus-internal.h"
38
39 static int name_owner_change_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
40         sd_event *e = userdata;
41
42         assert(bus);
43         assert(m);
44         assert(e);
45
46         sd_bus_close(bus);
47         sd_event_exit(e, 0);
48
49         return 1;
50 }
51
52 int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
53         _cleanup_free_ char *match = NULL;
54         const char *unique;
55         int r;
56
57         assert(e);
58         assert(bus);
59         assert(name);
60
61         /* We unregister the name here and then wait for the
62          * NameOwnerChanged signal for this event to arrive before we
63          * quit. We do this in order to make sure that any queued
64          * requests are still processed before we really exit. */
65
66         r = sd_bus_get_unique_name(bus, &unique);
67         if (r < 0)
68                 return r;
69
70         r = asprintf(&match,
71                      "sender='org.freedesktop.DBus',"
72                      "type='signal',"
73                      "interface='org.freedesktop.DBus',"
74                      "member='NameOwnerChanged',"
75                      "path='/org/freedesktop/DBus',"
76                      "arg0='%s',"
77                      "arg1='%s',"
78                      "arg2=''", name, unique);
79         if (r < 0)
80                 return -ENOMEM;
81
82         r = sd_bus_add_match(bus, NULL, match, name_owner_change_callback, e);
83         if (r < 0)
84                 return r;
85
86         r = sd_bus_release_name(bus, name);
87         if (r < 0)
88                 return r;
89
90         return 0;
91 }
92
93 int bus_event_loop_with_idle(
94                 sd_event *e,
95                 sd_bus *bus,
96                 const char *name,
97                 usec_t timeout,
98                 check_idle_t check_idle,
99                 void *userdata) {
100         bool exiting = false;
101         int r, code;
102
103         assert(e);
104         assert(bus);
105         assert(name);
106
107         for (;;) {
108                 bool idle;
109
110                 r = sd_event_get_state(e);
111                 if (r < 0)
112                         return r;
113                 if (r == SD_EVENT_FINISHED)
114                         break;
115
116                 if (check_idle)
117                         idle = check_idle(userdata);
118                 else
119                         idle = true;
120
121                 r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
122                 if (r < 0)
123                         return r;
124
125                 if (r == 0 && !exiting) {
126
127                         r = sd_bus_try_close(bus);
128                         if (r == -EBUSY)
129                                 continue;
130
131                         if (r == -ENOTSUP) {
132                                 /* Fallback for dbus1 connections: we
133                                  * unregister the name and wait for
134                                  * the response to come through for
135                                  * it */
136
137                                 r = bus_async_unregister_and_exit(e, bus, name);
138                                 if (r < 0)
139                                         return r;
140
141                                 exiting = true;
142                                 continue;
143                         }
144
145                         if (r < 0)
146                                 return r;
147
148                         sd_event_exit(e, 0);
149                         break;
150                 }
151         }
152
153         r = sd_event_get_exit_code(e, &code);
154         if (r < 0)
155                 return r;
156
157         return code;
158 }
159
160 int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
161         _cleanup_bus_message_unref_ sd_bus_message *rep = NULL;
162         int r, has_owner = 0;
163
164         assert(c);
165         assert(name);
166
167         r = sd_bus_call_method(c,
168                                "org.freedesktop.DBus",
169                                "/org/freedesktop/dbus",
170                                "org.freedesktop.DBus",
171                                "NameHasOwner",
172                                error,
173                                &rep,
174                                "s",
175                                name);
176         if (r < 0)
177                 return r;
178
179         r = sd_bus_message_read_basic(rep, 'b', &has_owner);
180         if (r < 0)
181                 return sd_bus_error_set_errno(error, r);
182
183         return has_owner;
184 }
185
186 int bus_verify_polkit(
187                 sd_bus *bus,
188                 sd_bus_message *m,
189                 const char *action,
190                 bool interactive,
191                 bool *_challenge,
192                 sd_bus_error *e) {
193
194         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
195         uid_t uid;
196         int r;
197
198         assert(bus);
199         assert(m);
200         assert(action);
201
202         r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
203         if (r < 0)
204                 return r;
205
206         r = sd_bus_creds_get_uid(creds, &uid);
207         if (r < 0)
208                 return r;
209
210         if (uid == 0)
211                 return 1;
212
213 #ifdef ENABLE_POLKIT
214         else {
215                 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
216                 int authorized = false, challenge = false;
217                 const char *sender;
218
219                 sender = sd_bus_message_get_sender(m);
220                 if (!sender)
221                         return -EBADMSG;
222
223                 r = sd_bus_call_method(
224                                 bus,
225                                 "org.freedesktop.PolicyKit1",
226                                 "/org/freedesktop/PolicyKit1/Authority",
227                                 "org.freedesktop.PolicyKit1.Authority",
228                                 "CheckAuthorization",
229                                 e,
230                                 &reply,
231                                 "(sa{sv})sa{ss}us",
232                                 "system-bus-name", 1, "name", "s", sender,
233                                 action,
234                                 0,
235                                 interactive ? 1 : 0,
236                                 "");
237
238                 if (r < 0) {
239                         /* Treat no PK available as access denied */
240                         if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
241                                 sd_bus_error_free(e);
242                                 return -EACCES;
243                         }
244
245                         return r;
246                 }
247
248                 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
249                 if (r < 0)
250                         return r;
251
252                 r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
253                 if (r < 0)
254                         return r;
255
256                 if (authorized)
257                         return 1;
258
259                 if (_challenge) {
260                         *_challenge = challenge;
261                         return 0;
262                 }
263         }
264 #endif
265
266         return -EACCES;
267 }
268
269 #ifdef ENABLE_POLKIT
270
271 typedef struct AsyncPolkitQuery {
272         sd_bus_message *request, *reply;
273         sd_bus_message_handler_t callback;
274         void *userdata;
275         sd_bus_slot *slot;
276         Hashmap *registry;
277 } AsyncPolkitQuery;
278
279 static void async_polkit_query_free(AsyncPolkitQuery *q) {
280
281         if (!q)
282                 return;
283
284         sd_bus_slot_unref(q->slot);
285
286         if (q->registry && q->request)
287                 hashmap_remove(q->registry, q->request);
288
289         sd_bus_message_unref(q->request);
290         sd_bus_message_unref(q->reply);
291
292         free(q);
293 }
294
295 static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
296         _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
297         AsyncPolkitQuery *q = userdata;
298         int r;
299
300         assert(bus);
301         assert(reply);
302         assert(q);
303
304         q->slot = sd_bus_slot_unref(q->slot);
305         q->reply = sd_bus_message_ref(reply);
306
307         r = sd_bus_message_rewind(q->request, true);
308         if (r < 0) {
309                 r = sd_bus_reply_method_errno(q->request, r, NULL);
310                 goto finish;
311         }
312
313         r = q->callback(bus, q->request, q->userdata, &error_buffer);
314         r = bus_maybe_reply_error(q->request, r, &error_buffer);
315
316 finish:
317         async_polkit_query_free(q);
318
319         return r;
320 }
321
322 #endif
323
324 int bus_verify_polkit_async(
325                 sd_bus *bus,
326                 Hashmap **registry,
327                 sd_bus_message *m,
328                 const char *action,
329                 bool interactive,
330                 sd_bus_error *error,
331                 sd_bus_message_handler_t callback,
332                 void *userdata) {
333
334 #ifdef ENABLE_POLKIT
335         _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
336         AsyncPolkitQuery *q;
337         const char *sender;
338 #endif
339         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
340         uid_t uid;
341         int r;
342
343         assert(bus);
344         assert(registry);
345         assert(m);
346         assert(action);
347
348 #ifdef ENABLE_POLKIT
349         q = hashmap_get(*registry, m);
350         if (q) {
351                 int authorized, challenge;
352
353                 /* This is the second invocation of this function, and
354                  * there's already a response from polkit, let's
355                  * process it */
356                 assert(q->reply);
357
358                 if (sd_bus_message_is_method_error(q->reply, NULL)) {
359                         const sd_bus_error *e;
360
361                         /* Copy error from polkit reply */
362                         e = sd_bus_message_get_error(q->reply);
363                         sd_bus_error_copy(error, e);
364
365                         /* Treat no PK available as access denied */
366                         if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
367                                 return -EACCES;
368
369                         return -sd_bus_error_get_errno(e);
370                 }
371
372                 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
373                 if (r >= 0)
374                         r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
375
376                 if (r < 0)
377                         return r;
378
379                 if (authorized)
380                         return 1;
381
382                 return -EACCES;
383         }
384 #endif
385
386         r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
387         if (r < 0)
388                 return r;
389
390         r = sd_bus_creds_get_uid(creds, &uid);
391         if (r < 0)
392                 return r;
393
394         if (uid == 0)
395                 return 1;
396
397 #ifdef ENABLE_POLKIT
398         sender = sd_bus_message_get_sender(m);
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                         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(m);
432         q->callback = callback;
433         q->userdata = userdata;
434
435         r = hashmap_put(*registry, m, 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(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_map_all_properties(sd_bus *bus,
978                            const char *destination,
979                            const char *path,
980                            const struct bus_properties_map *map,
981                            void *userdata) {
982         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
983         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
984         int r;
985
986         assert(bus);
987         assert(destination);
988         assert(path);
989         assert(map);
990
991         r = sd_bus_call_method(
992                         bus,
993                         destination,
994                         path,
995                         "org.freedesktop.DBus.Properties",
996                         "GetAll",
997                         &error,
998                         &m,
999                         "s", "");
1000         if (r < 0)
1001                 return r;
1002
1003         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
1004         if (r < 0)
1005                 return r;
1006
1007         while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
1008                 const struct bus_properties_map *prop;
1009                 const char *member;
1010                 const char *contents;
1011                 void *v;
1012                 unsigned i;
1013
1014                 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
1015                 if (r < 0)
1016                         return r;
1017
1018                 for (i = 0, prop = NULL; map[i].member; i++)
1019                         if (streq(map[i].member, member)) {
1020                                 prop = &map[i];
1021                                 break;
1022                         }
1023
1024                 if (prop) {
1025                         r = sd_bus_message_peek_type(m, NULL, &contents);
1026                         if (r < 0)
1027                                 return r;
1028
1029                         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1030                         if (r < 0)
1031                                 return r;
1032
1033                         v = (uint8_t *)userdata + prop->offset;
1034                         if (map[i].set)
1035                                 r = prop->set(bus, member, m, &error, v);
1036                         else
1037                                 r = map_basic(bus, member, m, &error, v);
1038                         if (r < 0)
1039                                 return r;
1040
1041                         r = sd_bus_message_exit_container(m);
1042                         if (r < 0)
1043                                 return r;
1044                 } else {
1045                         r = sd_bus_message_skip(m, "v");
1046                         if (r < 0)
1047                                 return r;
1048                 }
1049
1050                 r = sd_bus_message_exit_container(m);
1051                 if (r < 0)
1052                         return r;
1053         }
1054
1055         return r;
1056 }
1057
1058 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1059         int r;
1060
1061         assert(transport >= 0);
1062         assert(transport < _BUS_TRANSPORT_MAX);
1063         assert(bus);
1064
1065         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1066         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1067
1068         switch (transport) {
1069
1070         case BUS_TRANSPORT_LOCAL:
1071                 if (user)
1072                         r = sd_bus_default_user(bus);
1073                 else
1074                         r = sd_bus_default_system(bus);
1075
1076                 break;
1077
1078         case BUS_TRANSPORT_REMOTE:
1079                 r = sd_bus_open_system_remote(bus, host);
1080                 break;
1081
1082         case BUS_TRANSPORT_CONTAINER:
1083                 r = sd_bus_open_system_container(bus, host);
1084                 break;
1085
1086         default:
1087                 assert_not_reached("Hmm, unknown transport type.");
1088         }
1089
1090         return r;
1091 }
1092
1093 int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1094         int r;
1095
1096         assert(transport >= 0);
1097         assert(transport < _BUS_TRANSPORT_MAX);
1098         assert(bus);
1099
1100         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1101         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1102
1103         switch (transport) {
1104
1105         case BUS_TRANSPORT_LOCAL:
1106                 if (user)
1107                         r = bus_open_user_systemd(bus);
1108                 else
1109                         r = bus_open_system_systemd(bus);
1110
1111                 break;
1112
1113         case BUS_TRANSPORT_REMOTE:
1114                 r = sd_bus_open_system_remote(bus, host);
1115                 break;
1116
1117         case BUS_TRANSPORT_CONTAINER:
1118                 r = sd_bus_open_system_container(bus, host);
1119                 break;
1120
1121         default:
1122                 assert_not_reached("Hmm, unknown transport type.");
1123         }
1124
1125         return r;
1126 }
1127
1128 int bus_property_get_bool(
1129                 sd_bus *bus,
1130                 const char *path,
1131                 const char *interface,
1132                 const char *property,
1133                 sd_bus_message *reply,
1134                 void *userdata,
1135                 sd_bus_error *error) {
1136
1137         int b = *(bool*) userdata;
1138
1139         return sd_bus_message_append_basic(reply, 'b', &b);
1140 }
1141
1142 #if __SIZEOF_SIZE_T__ != 8
1143 int bus_property_get_size(
1144                 sd_bus *bus,
1145                 const char *path,
1146                 const char *interface,
1147                 const char *property,
1148                 sd_bus_message *reply,
1149                 void *userdata,
1150                 sd_bus_error *error) {
1151
1152         uint64_t sz = *(size_t*) userdata;
1153
1154         return sd_bus_message_append_basic(reply, 't', &sz);
1155 }
1156 #endif
1157
1158 #if __SIZEOF_LONG__ != 8
1159 int bus_property_get_long(
1160                 sd_bus *bus,
1161                 const char *path,
1162                 const char *interface,
1163                 const char *property,
1164                 sd_bus_message *reply,
1165                 void *userdata,
1166                 sd_bus_error *error) {
1167
1168         int64_t l = *(long*) userdata;
1169
1170         return sd_bus_message_append_basic(reply, 'x', &l);
1171 }
1172
1173 int bus_property_get_ulong(
1174                 sd_bus *bus,
1175                 const char *path,
1176                 const char *interface,
1177                 const char *property,
1178                 sd_bus_message *reply,
1179                 void *userdata,
1180                 sd_bus_error *error) {
1181
1182         uint64_t ul = *(unsigned long*) userdata;
1183
1184         return sd_bus_message_append_basic(reply, 't', &ul);
1185 }
1186 #endif
1187
1188 int bus_log_parse_error(int r) {
1189         log_error("Failed to parse bus message: %s", strerror(-r));
1190         return r;
1191 }
1192
1193 int bus_log_create_error(int r) {
1194         log_error("Failed to create bus message: %s", strerror(-r));
1195         return r;
1196 }
1197
1198 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1199         assert(message);
1200         assert(u);
1201
1202         u->machine = NULL;
1203
1204         return sd_bus_message_read(
1205                         message,
1206                         "(ssssssouso)",
1207                         &u->id,
1208                         &u->description,
1209                         &u->load_state,
1210                         &u->active_state,
1211                         &u->sub_state,
1212                         &u->following,
1213                         &u->unit_path,
1214                         &u->job_id,
1215                         &u->job_type,
1216                         &u->job_path);
1217 }
1218
1219 int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
1220         assert(m);
1221
1222         if (r < 0) {
1223                 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1224                         sd_bus_reply_method_errno(m, r, error);
1225
1226         } else if (sd_bus_error_is_set(error)) {
1227                 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1228                         sd_bus_reply_method_error(m, error);
1229         } else
1230                 return r;
1231
1232         log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
1233                   bus_message_type_to_string(m->header->type),
1234                   strna(m->sender),
1235                   strna(m->path),
1236                   strna(m->interface),
1237                   strna(m->member),
1238                   strna(m->root_container.signature),
1239                   bus_error_message(error, r));
1240
1241         return 1;
1242 }
1243
1244 int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
1245         const char *eq, *field;
1246         int r;
1247
1248         assert(m);
1249         assert(assignment);
1250
1251         eq = strchr(assignment, '=');
1252         if (!eq) {
1253                 log_error("Not an assignment: %s", assignment);
1254                 return -EINVAL;
1255         }
1256
1257         field = strndupa(assignment, eq - assignment);
1258         eq ++;
1259
1260         if (streq(field, "CPUQuota")) {
1261
1262                 if (isempty(eq)) {
1263
1264                         r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1265                         if (r < 0)
1266                                 return bus_log_create_error(r);
1267
1268                         r = sd_bus_message_append(m, "v", "t", USEC_INFINITY);
1269
1270                 } else if (endswith(eq, "%")) {
1271                         double percent;
1272
1273                         if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) {
1274                                 log_error("CPU quota '%s' invalid.", eq);
1275                                 return -EINVAL;
1276                         }
1277
1278                         r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1279                         if (r < 0)
1280                                 return bus_log_create_error(r);
1281
1282                         r = sd_bus_message_append(m, "v", "t", (usec_t) percent * USEC_PER_SEC / 100);
1283                 } else {
1284                         log_error("CPU quota needs to be in percent.");
1285                         return -EINVAL;
1286                 }
1287
1288                 if (r < 0)
1289                         return bus_log_create_error(r);
1290
1291                 return 0;
1292         }
1293
1294         r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1295         if (r < 0)
1296                 return bus_log_create_error(r);
1297
1298         if (STR_IN_SET(field,
1299                        "CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
1300                        "SendSIGHUP", "SendSIGKILL")) {
1301
1302                 r = parse_boolean(eq);
1303                 if (r < 0) {
1304                         log_error("Failed to parse boolean assignment %s.", assignment);
1305                         return -EINVAL;
1306                 }
1307
1308                 r = sd_bus_message_append(m, "v", "b", r);
1309
1310         } else if (streq(field, "MemoryLimit")) {
1311                 off_t bytes;
1312
1313                 r = parse_size(eq, 1024, &bytes);
1314                 if (r < 0) {
1315                         log_error("Failed to parse bytes specification %s", assignment);
1316                         return -EINVAL;
1317                 }
1318
1319                 r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
1320
1321         } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) {
1322                 uint64_t u;
1323
1324                 r = safe_atou64(eq, &u);
1325                 if (r < 0) {
1326                         log_error("Failed to parse %s value %s.", field, eq);
1327                         return -EINVAL;
1328                 }
1329
1330                 r = sd_bus_message_append(m, "v", "t", u);
1331
1332         } else if (STR_IN_SET(field, "User", "Group", "DevicePolicy", "KillMode"))
1333                 r = sd_bus_message_append(m, "v", "s", eq);
1334
1335         else if (streq(field, "DeviceAllow")) {
1336
1337                 if (isempty(eq))
1338                         r = sd_bus_message_append(m, "v", "a(ss)", 0);
1339                 else {
1340                         const char *path, *rwm, *e;
1341
1342                         e = strchr(eq, ' ');
1343                         if (e) {
1344                                 path = strndupa(eq, e - eq);
1345                                 rwm = e+1;
1346                         } else {
1347                                 path = eq;
1348                                 rwm = "";
1349                         }
1350
1351                         if (!path_startswith(path, "/dev")) {
1352                                 log_error("%s is not a device file in /dev.", path);
1353                                 return -EINVAL;
1354                         }
1355
1356                         r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
1357                 }
1358
1359         } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1360
1361                 if (isempty(eq))
1362                         r = sd_bus_message_append(m, "v", "a(st)", 0);
1363                 else {
1364                         const char *path, *bandwidth, *e;
1365                         off_t bytes;
1366
1367                         e = strchr(eq, ' ');
1368                         if (e) {
1369                                 path = strndupa(eq, e - eq);
1370                                 bandwidth = e+1;
1371                         } else {
1372                                 log_error("Failed to parse %s value %s.", field, eq);
1373                                 return -EINVAL;
1374                         }
1375
1376                         if (!path_startswith(path, "/dev")) {
1377                                 log_error("%s is not a device file in /dev.", path);
1378                                 return -EINVAL;
1379                         }
1380
1381                         r = parse_size(bandwidth, 1000, &bytes);
1382                         if (r < 0) {
1383                                 log_error("Failed to parse byte value %s.", bandwidth);
1384                                 return -EINVAL;
1385                         }
1386
1387                         r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes);
1388                 }
1389
1390         } else if (streq(field, "BlockIODeviceWeight")) {
1391
1392                 if (isempty(eq))
1393                         r = sd_bus_message_append(m, "v", "a(st)", 0);
1394                 else {
1395                         const char *path, *weight, *e;
1396                         uint64_t u;
1397
1398                         e = strchr(eq, ' ');
1399                         if (e) {
1400                                 path = strndupa(eq, e - eq);
1401                                 weight = e+1;
1402                         } else {
1403                                 log_error("Failed to parse %s value %s.", field, eq);
1404                                 return -EINVAL;
1405                         }
1406
1407                         if (!path_startswith(path, "/dev")) {
1408                                 log_error("%s is not a device file in /dev.", path);
1409                                 return -EINVAL;
1410                         }
1411
1412                         r = safe_atou64(weight, &u);
1413                         if (r < 0) {
1414                                 log_error("Failed to parse %s value %s.", field, weight);
1415                                 return -EINVAL;
1416                         }
1417                         r = sd_bus_message_append(m, "v", "a(st)", path, u);
1418                 }
1419
1420         } else if (rlimit_from_string(field) >= 0) {
1421                 uint64_t rl;
1422
1423                 if (streq(eq, "infinity"))
1424                         rl = (uint64_t) -1;
1425                 else {
1426                         r = safe_atou64(eq, &rl);
1427                         if (r < 0) {
1428                                 log_error("Invalid resource limit: %s", eq);
1429                                 return -EINVAL;
1430                         }
1431                 }
1432
1433                 r = sd_bus_message_append(m, "v", "t", rl);
1434
1435         } else if (streq(field, "Nice")) {
1436                 int32_t i;
1437
1438                 r = safe_atoi32(eq, &i);
1439                 if (r < 0) {
1440                         log_error("Failed to parse %s value %s.", field, eq);
1441                         return -EINVAL;
1442                 }
1443
1444                 r = sd_bus_message_append(m, "v", "i", i);
1445
1446         } else if (streq(field, "Environment")) {
1447
1448                 r = sd_bus_message_append(m, "v", "as", 1, eq);
1449
1450         } else if (streq(field, "KillSignal")) {
1451                 int sig;
1452
1453                 sig = signal_from_string_try_harder(eq);
1454                 if (sig < 0) {
1455                         log_error("Failed to parse %s value %s.", field, eq);
1456                         return -EINVAL;
1457                 }
1458
1459                 r = sd_bus_message_append(m, "v", "i", sig);
1460
1461         } else {
1462                 log_error("Unknown assignment %s.", assignment);
1463                 return -EINVAL;
1464         }
1465
1466         if (r < 0)
1467                 return bus_log_create_error(r);
1468
1469         return 0;
1470 }