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