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