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