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