chiark / gitweb /
ecac73a94dd8fe1a1acae4470e78c464685969c7
[elogind.git] / src / libsystemd / sd-bus / bus-objects.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/capability.h>
23
24 #include "strv.h"
25 #include "set.h"
26 #include "bus-internal.h"
27 #include "bus-message.h"
28 #include "bus-type.h"
29 #include "bus-signature.h"
30 #include "bus-introspect.h"
31 #include "bus-util.h"
32 #include "bus-slot.h"
33 #include "bus-objects.h"
34
35 static int node_vtable_get_userdata(
36                 sd_bus *bus,
37                 const char *path,
38                 struct node_vtable *c,
39                 void **userdata,
40                 sd_bus_error *error) {
41
42         sd_bus_slot *s;
43         void *u;
44         int r;
45
46         assert(bus);
47         assert(path);
48         assert(c);
49
50         s = container_of(c, sd_bus_slot, node_vtable);
51         u = s->userdata;
52         if (c->find) {
53                 bus->current_slot = sd_bus_slot_ref(s);
54                 bus->current_userdata = u;
55                 r = c->find(bus, path, c->interface, u, &u, error);
56                 bus->current_userdata = NULL;
57                 bus->current_slot = sd_bus_slot_unref(s);
58
59                 if (r < 0)
60                         return r;
61                 if (sd_bus_error_is_set(error))
62                         return -sd_bus_error_get_errno(error);
63                 if (r == 0)
64                         return r;
65         }
66
67         if (userdata)
68                 *userdata = u;
69
70         return 1;
71 }
72
73 static void *vtable_property_convert_userdata(const sd_bus_vtable *p, void *u) {
74         assert(p);
75
76         return (uint8_t*) u + p->x.property.offset;
77 }
78
79 static int vtable_property_get_userdata(
80                 sd_bus *bus,
81                 const char *path,
82                 struct vtable_member *p,
83                 void **userdata,
84                 sd_bus_error *error) {
85
86         void *u;
87         int r;
88
89         assert(bus);
90         assert(path);
91         assert(p);
92         assert(userdata);
93
94         r = node_vtable_get_userdata(bus, path, p->parent, &u, error);
95         if (r <= 0)
96                 return r;
97         if (bus->nodes_modified)
98                 return 0;
99
100         *userdata = vtable_property_convert_userdata(p->vtable, u);
101         return 1;
102 }
103
104 static int add_enumerated_to_set(
105                 sd_bus *bus,
106                 const char *prefix,
107                 struct node_enumerator *first,
108                 Set *s,
109                 sd_bus_error *error) {
110
111         struct node_enumerator *c;
112         int r;
113
114         assert(bus);
115         assert(prefix);
116         assert(s);
117
118         LIST_FOREACH(enumerators, c, first) {
119                 char **children = NULL, **k;
120                 sd_bus_slot *slot;
121
122                 if (bus->nodes_modified)
123                         return 0;
124
125                 slot = container_of(c, sd_bus_slot, node_enumerator);
126
127                 bus->current_slot = sd_bus_slot_ref(slot);
128                 bus->current_userdata = slot->userdata;
129                 r = c->callback(bus, prefix, slot->userdata, &children, error);
130                 bus->current_userdata = NULL;
131                 bus->current_slot = sd_bus_slot_unref(slot);
132
133                 if (r < 0)
134                         return r;
135                 if (sd_bus_error_is_set(error))
136                         return -sd_bus_error_get_errno(error);
137
138                 STRV_FOREACH(k, children) {
139                         if (r < 0) {
140                                 free(*k);
141                                 continue;
142                         }
143
144                         if (!object_path_is_valid(*k)){
145                                 free(*k);
146                                 r = -EINVAL;
147                                 continue;
148                         }
149
150                         if (!object_path_startswith(*k, prefix)) {
151                                 free(*k);
152                                 continue;
153                         }
154
155                         r = set_consume(s, *k);
156                         if (r == -EEXIST)
157                                 r = 0;
158                 }
159
160                 free(children);
161                 if (r < 0)
162                         return r;
163         }
164
165         return 0;
166 }
167
168 static int add_subtree_to_set(
169                 sd_bus *bus,
170                 const char *prefix,
171                 struct node *n,
172                 Set *s,
173                 sd_bus_error *error) {
174
175         struct node *i;
176         int r;
177
178         assert(bus);
179         assert(prefix);
180         assert(n);
181         assert(s);
182
183         r = add_enumerated_to_set(bus, prefix, n->enumerators, s, error);
184         if (r < 0)
185                 return r;
186         if (bus->nodes_modified)
187                 return 0;
188
189         LIST_FOREACH(siblings, i, n->child) {
190                 char *t;
191
192                 if (!object_path_startswith(i->path, prefix))
193                         continue;
194
195                 t = strdup(i->path);
196                 if (!t)
197                         return -ENOMEM;
198
199                 r = set_consume(s, t);
200                 if (r < 0 && r != -EEXIST)
201                         return r;
202
203                 r = add_subtree_to_set(bus, prefix, i, s, error);
204                 if (r < 0)
205                         return r;
206                 if (bus->nodes_modified)
207                         return 0;
208         }
209
210         return 0;
211 }
212
213 static int get_child_nodes(
214                 sd_bus *bus,
215                 const char *prefix,
216                 struct node *n,
217                 Set **_s,
218                 sd_bus_error *error) {
219
220         Set *s = NULL;
221         int r;
222
223         assert(bus);
224         assert(prefix);
225         assert(n);
226         assert(_s);
227
228         s = set_new(&string_hash_ops);
229         if (!s)
230                 return -ENOMEM;
231
232         r = add_subtree_to_set(bus, prefix, n, s, error);
233         if (r < 0) {
234                 set_free_free(s);
235                 return r;
236         }
237
238         *_s = s;
239         return 0;
240 }
241
242 static int node_callbacks_run(
243                 sd_bus *bus,
244                 sd_bus_message *m,
245                 struct node_callback *first,
246                 bool require_fallback,
247                 bool *found_object) {
248
249         struct node_callback *c;
250         int r;
251
252         assert(bus);
253         assert(m);
254         assert(found_object);
255
256         LIST_FOREACH(callbacks, c, first) {
257                 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
258                 sd_bus_slot *slot;
259
260                 if (bus->nodes_modified)
261                         return 0;
262
263                 if (require_fallback && !c->is_fallback)
264                         continue;
265
266                 *found_object = true;
267
268                 if (c->last_iteration == bus->iteration_counter)
269                         continue;
270
271                 c->last_iteration = bus->iteration_counter;
272
273                 r = sd_bus_message_rewind(m, true);
274                 if (r < 0)
275                         return r;
276
277                 slot = container_of(c, sd_bus_slot, node_callback);
278
279                 bus->current_slot = sd_bus_slot_ref(slot);
280                 bus->current_handler = c->callback;
281                 bus->current_userdata = slot->userdata;
282                 r = c->callback(bus, m, slot->userdata, &error_buffer);
283                 bus->current_userdata = NULL;
284                 bus->current_handler = NULL;
285                 bus->current_slot = sd_bus_slot_unref(slot);
286
287                 r = bus_maybe_reply_error(m, r, &error_buffer);
288                 if (r != 0)
289                         return r;
290         }
291
292         return 0;
293 }
294
295 #define CAPABILITY_SHIFT(x) (((x) >> __builtin_ctzll(_SD_BUS_VTABLE_CAPABILITY_MASK)) & 0xFFFF)
296
297 static int check_access(sd_bus *bus, sd_bus_message *m, struct vtable_member *c, sd_bus_error *error) {
298         uint64_t cap;
299         int r;
300
301         assert(bus);
302         assert(m);
303         assert(c);
304
305         /* If the entire bus is trusted let's grant access */
306         if (bus->trusted)
307                 return 0;
308
309         /* If the member is marked UNPRIVILEGED let's grant access */
310         if (c->vtable->flags & SD_BUS_VTABLE_UNPRIVILEGED)
311                 return 0;
312
313         /* Check have the caller has the requested capability
314          * set. Note that the flags value contains the capability
315          * number plus one, which we need to subtract here. We do this
316          * so that we have 0 as special value for "default
317          * capability". */
318         cap = CAPABILITY_SHIFT(c->vtable->flags);
319         if (cap == 0)
320                 cap = CAPABILITY_SHIFT(c->parent->vtable[0].flags);
321         if (cap == 0)
322                 cap = CAP_SYS_ADMIN;
323         else
324                 cap --;
325
326         r = sd_bus_query_sender_privilege(m, cap);
327         if (r < 0)
328                 return r;
329         if (r > 0)
330                 return 0;
331
332         return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Access to %s.%s() not permitted.", c->interface, c->member);
333 }
334
335 static int method_callbacks_run(
336                 sd_bus *bus,
337                 sd_bus_message *m,
338                 struct vtable_member *c,
339                 bool require_fallback,
340                 bool *found_object) {
341
342         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
343         const char *signature;
344         void *u;
345         int r;
346
347         assert(bus);
348         assert(m);
349         assert(c);
350         assert(found_object);
351
352         if (require_fallback && !c->parent->is_fallback)
353                 return 0;
354
355         r = check_access(bus, m, c, &error);
356         if (r < 0)
357                 return bus_maybe_reply_error(m, r, &error);
358
359         r = node_vtable_get_userdata(bus, m->path, c->parent, &u, &error);
360         if (r <= 0)
361                 return bus_maybe_reply_error(m, r, &error);
362         if (bus->nodes_modified)
363                 return 0;
364
365         *found_object = true;
366
367         if (c->last_iteration == bus->iteration_counter)
368                 return 0;
369
370         c->last_iteration = bus->iteration_counter;
371
372         r = sd_bus_message_rewind(m, true);
373         if (r < 0)
374                 return r;
375
376         signature = sd_bus_message_get_signature(m, true);
377         if (!signature)
378                 return -EINVAL;
379
380         if (!streq(strempty(c->vtable->x.method.signature), signature))
381                 return sd_bus_reply_method_errorf(
382                                 m,
383                                 SD_BUS_ERROR_INVALID_ARGS,
384                                 "Invalid arguments '%s' to call %s.%s(), expecting '%s'.",
385                                 signature, c->interface, c->member, strempty(c->vtable->x.method.signature));
386
387         /* Keep track what the signature of the reply to this message
388          * should be, so that this can be enforced when sealing the
389          * reply. */
390         m->enforced_reply_signature = strempty(c->vtable->x.method.result);
391
392         if (c->vtable->x.method.handler) {
393                 sd_bus_slot *slot;
394
395                 slot = container_of(c->parent, sd_bus_slot, node_vtable);
396
397                 bus->current_slot = sd_bus_slot_ref(slot);
398                 bus->current_handler = c->vtable->x.method.handler;
399                 bus->current_userdata = u;
400                 r = c->vtable->x.method.handler(bus, m, u, &error);
401                 bus->current_userdata = NULL;
402                 bus->current_handler = NULL;
403                 bus->current_slot = sd_bus_slot_unref(slot);
404
405                 return bus_maybe_reply_error(m, r, &error);
406         }
407
408         /* If the method callback is NULL, make this a successful NOP */
409         r = sd_bus_reply_method_return(m, NULL);
410         if (r < 0)
411                 return r;
412
413         return 1;
414 }
415
416 static int invoke_property_get(
417                 sd_bus *bus,
418                 sd_bus_slot *slot,
419                 const sd_bus_vtable *v,
420                 const char *path,
421                 const char *interface,
422                 const char *property,
423                 sd_bus_message *reply,
424                 void *userdata,
425                 sd_bus_error *error) {
426
427         const void *p;
428         int r;
429
430         assert(bus);
431         assert(slot);
432         assert(v);
433         assert(path);
434         assert(interface);
435         assert(property);
436         assert(reply);
437
438         if (v->x.property.get) {
439
440                 bus->current_slot = sd_bus_slot_ref(slot);
441                 bus->current_userdata = userdata;
442                 r = v->x.property.get(bus, path, interface, property, reply, userdata, error);
443                 bus->current_userdata = NULL;
444                 bus->current_slot = sd_bus_slot_unref(slot);
445
446                 if (r < 0)
447                         return r;
448                 if (sd_bus_error_is_set(error))
449                         return -sd_bus_error_get_errno(error);
450                 return r;
451         }
452
453         /* Automatic handling if no callback is defined. */
454
455         if (streq(v->x.property.signature, "as"))
456                 return sd_bus_message_append_strv(reply, *(char***) userdata);
457
458         assert(signature_is_single(v->x.property.signature, false));
459         assert(bus_type_is_basic(v->x.property.signature[0]));
460
461         switch (v->x.property.signature[0]) {
462
463         case SD_BUS_TYPE_STRING:
464         case SD_BUS_TYPE_SIGNATURE:
465                 p = strempty(*(char**) userdata);
466                 break;
467
468         case SD_BUS_TYPE_OBJECT_PATH:
469                 p = *(char**) userdata;
470                 assert(p);
471                 break;
472
473         default:
474                 p = userdata;
475                 break;
476         }
477
478         return sd_bus_message_append_basic(reply, v->x.property.signature[0], p);
479 }
480
481 static int invoke_property_set(
482                 sd_bus *bus,
483                 sd_bus_slot *slot,
484                 const sd_bus_vtable *v,
485                 const char *path,
486                 const char *interface,
487                 const char *property,
488                 sd_bus_message *value,
489                 void *userdata,
490                 sd_bus_error *error) {
491
492         int r;
493
494         assert(bus);
495         assert(slot);
496         assert(v);
497         assert(path);
498         assert(interface);
499         assert(property);
500         assert(value);
501
502         if (v->x.property.set) {
503
504                 bus->current_slot = sd_bus_slot_ref(slot);
505                 bus->current_userdata = userdata;
506                 r = v->x.property.set(bus, path, interface, property, value, userdata, error);
507                 bus->current_userdata = NULL;
508                 bus->current_slot = sd_bus_slot_unref(slot);
509
510                 if (r < 0)
511                         return r;
512                 if (sd_bus_error_is_set(error))
513                         return -sd_bus_error_get_errno(error);
514                 return r;
515         }
516
517         /*  Automatic handling if no callback is defined. */
518
519         assert(signature_is_single(v->x.property.signature, false));
520         assert(bus_type_is_basic(v->x.property.signature[0]));
521
522         switch (v->x.property.signature[0]) {
523
524         case SD_BUS_TYPE_STRING:
525         case SD_BUS_TYPE_OBJECT_PATH:
526         case SD_BUS_TYPE_SIGNATURE: {
527                 const char *p;
528                 char *n;
529
530                 r = sd_bus_message_read_basic(value, v->x.property.signature[0], &p);
531                 if (r < 0)
532                         return r;
533
534                 n = strdup(p);
535                 if (!n)
536                         return -ENOMEM;
537
538                 free(*(char**) userdata);
539                 *(char**) userdata = n;
540
541                 break;
542         }
543
544         default:
545                 r = sd_bus_message_read_basic(value, v->x.property.signature[0], userdata);
546                 if (r < 0)
547                         return r;
548
549                 break;
550         }
551
552         return 1;
553 }
554
555 static int property_get_set_callbacks_run(
556                 sd_bus *bus,
557                 sd_bus_message *m,
558                 struct vtable_member *c,
559                 bool require_fallback,
560                 bool is_get,
561                 bool *found_object) {
562
563         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
564         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
565         sd_bus_slot *slot;
566         void *u = NULL;
567         int r;
568
569         assert(bus);
570         assert(m);
571         assert(c);
572         assert(found_object);
573
574         if (require_fallback && !c->parent->is_fallback)
575                 return 0;
576
577         r = vtable_property_get_userdata(bus, m->path, c, &u, &error);
578         if (r <= 0)
579                 return bus_maybe_reply_error(m, r, &error);
580         if (bus->nodes_modified)
581                 return 0;
582
583         slot = container_of(c->parent, sd_bus_slot, node_vtable);
584
585         *found_object = true;
586
587         r = sd_bus_message_new_method_return(m, &reply);
588         if (r < 0)
589                 return r;
590
591         if (is_get) {
592                 /* Note that we do not protect against reexecution
593                  * here (using the last_iteration check, see below),
594                  * should the node tree have changed and we got called
595                  * again. We assume that property Get() calls are
596                  * ultimately without side-effects or if they aren't
597                  * then at least idempotent. */
598
599                 r = sd_bus_message_open_container(reply, 'v', c->vtable->x.property.signature);
600                 if (r < 0)
601                         return r;
602
603                 /* Note that we do not do an access check here. Read
604                  * access to properties is always unrestricted, since
605                  * PropertiesChanged signals broadcast contents
606                  * anyway. */
607
608                 r = invoke_property_get(bus, slot, c->vtable, m->path, c->interface, c->member, reply, u, &error);
609                 if (r < 0)
610                         return bus_maybe_reply_error(m, r, &error);
611
612                 if (bus->nodes_modified)
613                         return 0;
614
615                 r = sd_bus_message_close_container(reply);
616                 if (r < 0)
617                         return r;
618
619         } else {
620                 if (c->vtable->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
621                         return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Property '%s' is not writable.", c->member);
622
623                 /* Avoid that we call the set routine more than once
624                  * if the processing of this message got restarted
625                  * because the node tree changed. */
626                 if (c->last_iteration == bus->iteration_counter)
627                         return 0;
628
629                 c->last_iteration = bus->iteration_counter;
630
631                 r = sd_bus_message_enter_container(m, 'v', c->vtable->x.property.signature);
632                 if (r < 0)
633                         return r;
634
635                 r = check_access(bus, m, c, &error);
636                 if (r < 0)
637                         return bus_maybe_reply_error(m, r, &error);
638
639                 r = invoke_property_set(bus, slot, c->vtable, m->path, c->interface, c->member, m, u, &error);
640                 if (r < 0)
641                         return bus_maybe_reply_error(m, r, &error);
642
643                 if (bus->nodes_modified)
644                         return 0;
645
646                 r = sd_bus_message_exit_container(m);
647                 if (r < 0)
648                         return r;
649         }
650
651         r = sd_bus_send(bus, reply, NULL);
652         if (r < 0)
653                 return r;
654
655         return 1;
656 }
657
658 static int vtable_append_one_property(
659                 sd_bus *bus,
660                 sd_bus_message *reply,
661                 const char *path,
662                 struct node_vtable *c,
663                 const sd_bus_vtable *v,
664                 void *userdata,
665                 sd_bus_error *error) {
666
667         sd_bus_slot *slot;
668         int r;
669
670         assert(bus);
671         assert(reply);
672         assert(path);
673         assert(c);
674         assert(v);
675
676         r = sd_bus_message_open_container(reply, 'e', "sv");
677         if (r < 0)
678                 return r;
679
680         r = sd_bus_message_append(reply, "s", v->x.property.member);
681         if (r < 0)
682                 return r;
683
684         r = sd_bus_message_open_container(reply, 'v', v->x.property.signature);
685         if (r < 0)
686                 return r;
687
688         slot = container_of(c, sd_bus_slot, node_vtable);
689
690         r = invoke_property_get(bus, slot, v, path, c->interface, v->x.property.member, reply, vtable_property_convert_userdata(v, userdata), error);
691         if (r < 0)
692                 return r;
693         if (bus->nodes_modified)
694                 return 0;
695
696         r = sd_bus_message_close_container(reply);
697         if (r < 0)
698                 return r;
699
700         r = sd_bus_message_close_container(reply);
701         if (r < 0)
702                 return r;
703
704         return 0;
705 }
706
707 static int vtable_append_all_properties(
708                 sd_bus *bus,
709                 sd_bus_message *reply,
710                 const char *path,
711                 struct node_vtable *c,
712                 void *userdata,
713                 sd_bus_error *error) {
714
715         const sd_bus_vtable *v;
716         int r;
717
718         assert(bus);
719         assert(reply);
720         assert(path);
721         assert(c);
722
723         if (c->vtable[0].flags & SD_BUS_VTABLE_HIDDEN)
724                 return 1;
725
726         for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
727                 if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
728                         continue;
729
730                 if (v->flags & SD_BUS_VTABLE_HIDDEN)
731                         continue;
732
733                 r = vtable_append_one_property(bus, reply, path, c, v, userdata, error);
734                 if (r < 0)
735                         return r;
736                 if (bus->nodes_modified)
737                         return 0;
738         }
739
740         return 1;
741 }
742
743 static int property_get_all_callbacks_run(
744                 sd_bus *bus,
745                 sd_bus_message *m,
746                 struct node_vtable *first,
747                 bool require_fallback,
748                 const char *iface,
749                 bool *found_object) {
750
751         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
752         struct node_vtable *c;
753         bool found_interface;
754         int r;
755
756         assert(bus);
757         assert(m);
758         assert(found_object);
759
760         r = sd_bus_message_new_method_return(m, &reply);
761         if (r < 0)
762                 return r;
763
764         r = sd_bus_message_open_container(reply, 'a', "{sv}");
765         if (r < 0)
766                 return r;
767
768         found_interface = !iface ||
769                 streq(iface, "org.freedesktop.DBus.Properties") ||
770                 streq(iface, "org.freedesktop.DBus.Peer") ||
771                 streq(iface, "org.freedesktop.DBus.Introspectable");
772
773         LIST_FOREACH(vtables, c, first) {
774                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
775                 void *u;
776
777                 if (require_fallback && !c->is_fallback)
778                         continue;
779
780                 r = node_vtable_get_userdata(bus, m->path, c, &u, &error);
781                 if (r < 0)
782                         return bus_maybe_reply_error(m, r, &error);
783                 if (bus->nodes_modified)
784                         return 0;
785                 if (r == 0)
786                         continue;
787
788                 *found_object = true;
789
790                 if (iface && !streq(c->interface, iface))
791                         continue;
792                 found_interface = true;
793
794                 r = vtable_append_all_properties(bus, reply, m->path, c, u, &error);
795                 if (r < 0)
796                         return bus_maybe_reply_error(m, r, &error);
797                 if (bus->nodes_modified)
798                         return 0;
799         }
800
801         if (!found_interface) {
802                 r = sd_bus_reply_method_errorf(
803                                 m,
804                                 SD_BUS_ERROR_UNKNOWN_INTERFACE,
805                                 "Unknown interface '%s'.", iface);
806                 if (r < 0)
807                         return r;
808
809                 return 1;
810         }
811
812         r = sd_bus_message_close_container(reply);
813         if (r < 0)
814                 return r;
815
816         r = sd_bus_send(bus, reply, NULL);
817         if (r < 0)
818                 return r;
819
820         return 1;
821 }
822
823 static bool bus_node_exists(
824                 sd_bus *bus,
825                 struct node *n,
826                 const char *path,
827                 bool require_fallback) {
828
829         struct node_vtable *c;
830         struct node_callback *k;
831
832         assert(bus);
833         assert(n);
834         assert(path);
835
836         /* Tests if there's anything attached directly to this node
837          * for the specified path */
838
839         LIST_FOREACH(callbacks, k, n->callbacks) {
840                 if (require_fallback && !k->is_fallback)
841                         continue;
842
843                 return true;
844         }
845
846         LIST_FOREACH(vtables, c, n->vtables) {
847                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
848
849                 if (require_fallback && !c->is_fallback)
850                         continue;
851
852                 if (node_vtable_get_userdata(bus, path, c, NULL, &error) > 0)
853                         return true;
854                 if (bus->nodes_modified)
855                         return false;
856         }
857
858         return !require_fallback && (n->enumerators || n->object_managers);
859 }
860
861 static int process_introspect(
862                 sd_bus *bus,
863                 sd_bus_message *m,
864                 struct node *n,
865                 bool require_fallback,
866                 bool *found_object) {
867
868         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
869         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
870         _cleanup_set_free_free_ Set *s = NULL;
871         const char *previous_interface = NULL;
872         struct introspect intro;
873         struct node_vtable *c;
874         bool empty;
875         int r;
876
877         assert(bus);
878         assert(m);
879         assert(n);
880         assert(found_object);
881
882         r = get_child_nodes(bus, m->path, n, &s, &error);
883         if (r < 0)
884                 return bus_maybe_reply_error(m, r, &error);
885         if (bus->nodes_modified)
886                 return 0;
887
888         r = introspect_begin(&intro, bus->trusted);
889         if (r < 0)
890                 return r;
891
892         r = introspect_write_default_interfaces(&intro, !require_fallback && n->object_managers);
893         if (r < 0)
894                 return r;
895
896         empty = set_isempty(s);
897
898         LIST_FOREACH(vtables, c, n->vtables) {
899                 if (require_fallback && !c->is_fallback)
900                         continue;
901
902                 r = node_vtable_get_userdata(bus, m->path, c, NULL, &error);
903                 if (r < 0) {
904                         r = bus_maybe_reply_error(m, r, &error);
905                         goto finish;
906                 }
907                 if (bus->nodes_modified) {
908                         r = 0;
909                         goto finish;
910                 }
911                 if (r == 0)
912                         continue;
913
914                 empty = false;
915
916                 if (c->vtable[0].flags & SD_BUS_VTABLE_HIDDEN)
917                         continue;
918
919                 if (!streq_ptr(previous_interface, c->interface)) {
920
921                         if (previous_interface)
922                                 fputs(" </interface>\n", intro.f);
923
924                         fprintf(intro.f, " <interface name=\"%s\">\n", c->interface);
925                 }
926
927                 r = introspect_write_interface(&intro, c->vtable);
928                 if (r < 0)
929                         goto finish;
930
931                 previous_interface = c->interface;
932         }
933
934         if (previous_interface)
935                 fputs(" </interface>\n", intro.f);
936
937         if (empty) {
938                 /* Nothing?, let's see if we exist at all, and if not
939                  * refuse to do anything */
940                 r = bus_node_exists(bus, n, m->path, require_fallback);
941                 if (r < 0)
942                         return r;
943                 if (bus->nodes_modified)
944                         return 0;
945                 if (r == 0)
946                         goto finish;
947         }
948
949         *found_object = true;
950
951         r = introspect_write_child_nodes(&intro, s, m->path);
952         if (r < 0)
953                 goto finish;
954
955         r = introspect_finish(&intro, bus, m, &reply);
956         if (r < 0)
957                 goto finish;
958
959         r = sd_bus_send(bus, reply, NULL);
960         if (r < 0)
961                 goto finish;
962
963         r = 1;
964
965 finish:
966         introspect_free(&intro);
967         return r;
968 }
969
970 static int object_manager_serialize_path(
971                 sd_bus *bus,
972                 sd_bus_message *reply,
973                 const char *prefix,
974                 const char *path,
975                 bool require_fallback,
976                 sd_bus_error *error) {
977
978         const char *previous_interface = NULL;
979         bool found_something = false;
980         struct node_vtable *i;
981         struct node *n;
982         int r;
983
984         assert(bus);
985         assert(reply);
986         assert(prefix);
987         assert(path);
988         assert(error);
989
990         n = hashmap_get(bus->nodes, prefix);
991         if (!n)
992                 return 0;
993
994         LIST_FOREACH(vtables, i, n->vtables) {
995                 void *u;
996
997                 if (require_fallback && !i->is_fallback)
998                         continue;
999
1000                 r = node_vtable_get_userdata(bus, path, i, &u, error);
1001                 if (r < 0)
1002                         return r;
1003                 if (bus->nodes_modified)
1004                         return 0;
1005                 if (r == 0)
1006                         continue;
1007
1008                 if (!found_something) {
1009
1010                         /* Open the object part */
1011
1012                         r = sd_bus_message_open_container(reply, 'e', "oa{sa{sv}}");
1013                         if (r < 0)
1014                                 return r;
1015
1016                         r = sd_bus_message_append(reply, "o", path);
1017                         if (r < 0)
1018                                 return r;
1019
1020                         r = sd_bus_message_open_container(reply, 'a', "{sa{sv}}");
1021                         if (r < 0)
1022                                 return r;
1023
1024                         found_something = true;
1025                 }
1026
1027                 if (!streq_ptr(previous_interface, i->interface)) {
1028
1029                         /* Maybe close the previous interface part */
1030
1031                         if (previous_interface) {
1032                                 r = sd_bus_message_close_container(reply);
1033                                 if (r < 0)
1034                                         return r;
1035
1036                                 r = sd_bus_message_close_container(reply);
1037                                 if (r < 0)
1038                                         return r;
1039                         }
1040
1041                         /* Open the new interface part */
1042
1043                         r = sd_bus_message_open_container(reply, 'e', "sa{sv}");
1044                         if (r < 0)
1045                                 return r;
1046
1047                         r = sd_bus_message_append(reply, "s", i->interface);
1048                         if (r < 0)
1049                                 return r;
1050
1051                         r = sd_bus_message_open_container(reply, 'a', "{sv}");
1052                         if (r < 0)
1053                                 return r;
1054                 }
1055
1056                 r = vtable_append_all_properties(bus, reply, path, i, u, error);
1057                 if (r < 0)
1058                         return r;
1059                 if (bus->nodes_modified)
1060                         return 0;
1061
1062                 previous_interface = i->interface;
1063         }
1064
1065         if (previous_interface) {
1066                 r = sd_bus_message_close_container(reply);
1067                 if (r < 0)
1068                         return r;
1069
1070                 r = sd_bus_message_close_container(reply);
1071                 if (r < 0)
1072                         return r;
1073         }
1074
1075         if (found_something) {
1076                 r = sd_bus_message_close_container(reply);
1077                 if (r < 0)
1078                         return r;
1079
1080                 r = sd_bus_message_close_container(reply);
1081                 if (r < 0)
1082                         return r;
1083         }
1084
1085         return 1;
1086 }
1087
1088 static int object_manager_serialize_path_and_fallbacks(
1089                 sd_bus *bus,
1090                 sd_bus_message *reply,
1091                 const char *path,
1092                 sd_bus_error *error) {
1093
1094         char *prefix;
1095         int r;
1096
1097         assert(bus);
1098         assert(reply);
1099         assert(path);
1100         assert(error);
1101
1102         /* First, add all vtables registered for this path */
1103         r = object_manager_serialize_path(bus, reply, path, path, false, error);
1104         if (r < 0)
1105                 return r;
1106         if (bus->nodes_modified)
1107                 return 0;
1108
1109         /* Second, add fallback vtables registered for any of the prefixes */
1110         prefix = alloca(strlen(path) + 1);
1111         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
1112                 r = object_manager_serialize_path(bus, reply, prefix, path, true, error);
1113                 if (r < 0)
1114                         return r;
1115                 if (bus->nodes_modified)
1116                         return 0;
1117         }
1118
1119         return 0;
1120 }
1121
1122 static int process_get_managed_objects(
1123                 sd_bus *bus,
1124                 sd_bus_message *m,
1125                 struct node *n,
1126                 bool require_fallback,
1127                 bool *found_object) {
1128
1129         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1130         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1131         _cleanup_set_free_free_ Set *s = NULL;
1132         Iterator i;
1133         char *path;
1134         int r;
1135
1136         assert(bus);
1137         assert(m);
1138         assert(n);
1139         assert(found_object);
1140
1141         /* Spec says, GetManagedObjects() is only implemented on the root of a
1142          * sub-tree. Therefore, we require a registered object-manager on
1143          * exactly the queried path, otherwise, we refuse to respond. */
1144
1145         if (require_fallback || !n->object_managers)
1146                 return 0;
1147
1148         r = get_child_nodes(bus, m->path, n, &s, &error);
1149         if (r < 0)
1150                 return r;
1151         if (bus->nodes_modified)
1152                 return 0;
1153
1154         r = sd_bus_message_new_method_return(m, &reply);
1155         if (r < 0)
1156                 return r;
1157
1158         r = sd_bus_message_open_container(reply, 'a', "{oa{sa{sv}}}");
1159         if (r < 0)
1160                 return r;
1161
1162         SET_FOREACH(path, s, i) {
1163                 r = object_manager_serialize_path_and_fallbacks(bus, reply, path, &error);
1164                 if (r < 0)
1165                         return r;
1166
1167                 if (bus->nodes_modified)
1168                         return 0;
1169         }
1170
1171         r = sd_bus_message_close_container(reply);
1172         if (r < 0)
1173                 return r;
1174
1175         r = sd_bus_send(bus, reply, NULL);
1176         if (r < 0)
1177                 return r;
1178
1179         return 1;
1180 }
1181
1182 static int object_find_and_run(
1183                 sd_bus *bus,
1184                 sd_bus_message *m,
1185                 const char *p,
1186                 bool require_fallback,
1187                 bool *found_object) {
1188
1189         struct node *n;
1190         struct vtable_member vtable_key, *v;
1191         int r;
1192
1193         assert(bus);
1194         assert(m);
1195         assert(p);
1196         assert(found_object);
1197
1198         n = hashmap_get(bus->nodes, p);
1199         if (!n)
1200                 return 0;
1201
1202         /* First, try object callbacks */
1203         r = node_callbacks_run(bus, m, n->callbacks, require_fallback, found_object);
1204         if (r != 0)
1205                 return r;
1206         if (bus->nodes_modified)
1207                 return 0;
1208
1209         if (!m->interface || !m->member)
1210                 return 0;
1211
1212         /* Then, look for a known method */
1213         vtable_key.path = (char*) p;
1214         vtable_key.interface = m->interface;
1215         vtable_key.member = m->member;
1216
1217         v = hashmap_get(bus->vtable_methods, &vtable_key);
1218         if (v) {
1219                 r = method_callbacks_run(bus, m, v, require_fallback, found_object);
1220                 if (r != 0)
1221                         return r;
1222                 if (bus->nodes_modified)
1223                         return 0;
1224         }
1225
1226         /* Then, look for a known property */
1227         if (streq(m->interface, "org.freedesktop.DBus.Properties")) {
1228                 bool get = false;
1229
1230                 get = streq(m->member, "Get");
1231
1232                 if (get || streq(m->member, "Set")) {
1233
1234                         r = sd_bus_message_rewind(m, true);
1235                         if (r < 0)
1236                                 return r;
1237
1238                         vtable_key.path = (char*) p;
1239
1240                         r = sd_bus_message_read(m, "ss", &vtable_key.interface, &vtable_key.member);
1241                         if (r < 0)
1242                                 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected interface and member parameters");
1243
1244                         v = hashmap_get(bus->vtable_properties, &vtable_key);
1245                         if (v) {
1246                                 r = property_get_set_callbacks_run(bus, m, v, require_fallback, get, found_object);
1247                                 if (r != 0)
1248                                         return r;
1249                         }
1250
1251                 } else if (streq(m->member, "GetAll")) {
1252                         const char *iface;
1253
1254                         r = sd_bus_message_rewind(m, true);
1255                         if (r < 0)
1256                                 return r;
1257
1258                         r = sd_bus_message_read(m, "s", &iface);
1259                         if (r < 0)
1260                                 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected interface parameter");
1261
1262                         if (iface[0] == 0)
1263                                 iface = NULL;
1264
1265                         r = property_get_all_callbacks_run(bus, m, n->vtables, require_fallback, iface, found_object);
1266                         if (r != 0)
1267                                 return r;
1268                 }
1269
1270         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1271
1272                 if (!isempty(sd_bus_message_get_signature(m, true)))
1273                         return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
1274
1275                 r = process_introspect(bus, m, n, require_fallback, found_object);
1276                 if (r != 0)
1277                         return r;
1278
1279         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.ObjectManager", "GetManagedObjects")) {
1280
1281                 if (!isempty(sd_bus_message_get_signature(m, true)))
1282                         return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
1283
1284                 r = process_get_managed_objects(bus, m, n, require_fallback, found_object);
1285                 if (r != 0)
1286                         return r;
1287         }
1288
1289         if (bus->nodes_modified)
1290                 return 0;
1291
1292         if (!*found_object) {
1293                 r = bus_node_exists(bus, n, m->path, require_fallback);
1294                 if (r < 0)
1295                         return r;
1296                 if (r > 0)
1297                         *found_object = true;
1298         }
1299
1300         return 0;
1301 }
1302
1303 int bus_process_object(sd_bus *bus, sd_bus_message *m) {
1304         int r;
1305         size_t pl;
1306         bool found_object = false;
1307
1308         assert(bus);
1309         assert(m);
1310
1311         if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1312                 return 0;
1313
1314         if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
1315                 return 0;
1316
1317         if (hashmap_isempty(bus->nodes))
1318                 return 0;
1319
1320         /* Never respond to broadcast messages */
1321         if (bus->bus_client && !m->destination)
1322                 return 0;
1323
1324         assert(m->path);
1325         assert(m->member);
1326
1327         pl = strlen(m->path);
1328         do {
1329                 char prefix[pl+1];
1330
1331                 bus->nodes_modified = false;
1332
1333                 r = object_find_and_run(bus, m, m->path, false, &found_object);
1334                 if (r != 0)
1335                         return r;
1336
1337                 /* Look for fallback prefixes */
1338                 OBJECT_PATH_FOREACH_PREFIX(prefix, m->path) {
1339
1340                         if (bus->nodes_modified)
1341                                 break;
1342
1343                         r = object_find_and_run(bus, m, prefix, true, &found_object);
1344                         if (r != 0)
1345                                 return r;
1346                 }
1347
1348         } while (bus->nodes_modified);
1349
1350         if (!found_object)
1351                 return 0;
1352
1353         if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get") ||
1354             sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set"))
1355                 r = sd_bus_reply_method_errorf(
1356                                 m,
1357                                 SD_BUS_ERROR_UNKNOWN_PROPERTY,
1358                                 "Unknown property or interface.");
1359         else
1360                 r = sd_bus_reply_method_errorf(
1361                                 m,
1362                                 SD_BUS_ERROR_UNKNOWN_METHOD,
1363                                 "Unknown method '%s' or interface '%s'.", m->member, m->interface);
1364
1365         if (r < 0)
1366                 return r;
1367
1368         return 1;
1369 }
1370
1371 static struct node *bus_node_allocate(sd_bus *bus, const char *path) {
1372         struct node *n, *parent;
1373         const char *e;
1374         _cleanup_free_ char *s = NULL;
1375         char *p;
1376         int r;
1377
1378         assert(bus);
1379         assert(path);
1380         assert(path[0] == '/');
1381
1382         n = hashmap_get(bus->nodes, path);
1383         if (n)
1384                 return n;
1385
1386         r = hashmap_ensure_allocated(&bus->nodes, &string_hash_ops);
1387         if (r < 0)
1388                 return NULL;
1389
1390         s = strdup(path);
1391         if (!s)
1392                 return NULL;
1393
1394         if (streq(path, "/"))
1395                 parent = NULL;
1396         else {
1397                 e = strrchr(path, '/');
1398                 assert(e);
1399
1400                 p = strndupa(path, MAX(1, path - e));
1401
1402                 parent = bus_node_allocate(bus, p);
1403                 if (!parent)
1404                         return NULL;
1405         }
1406
1407         n = new0(struct node, 1);
1408         if (!n)
1409                 return NULL;
1410
1411         n->parent = parent;
1412         n->path = s;
1413         s = NULL; /* do not free */
1414
1415         r = hashmap_put(bus->nodes, n->path, n);
1416         if (r < 0) {
1417                 free(n->path);
1418                 free(n);
1419                 return NULL;
1420         }
1421
1422         if (parent)
1423                 LIST_PREPEND(siblings, parent->child, n);
1424
1425         return n;
1426 }
1427
1428 void bus_node_gc(sd_bus *b, struct node *n) {
1429         assert(b);
1430
1431         if (!n)
1432                 return;
1433
1434         if (n->child ||
1435             n->callbacks ||
1436             n->vtables ||
1437             n->enumerators ||
1438             n->object_managers)
1439                 return;
1440
1441         assert(hashmap_remove(b->nodes, n->path) == n);
1442
1443         if (n->parent)
1444                 LIST_REMOVE(siblings, n->parent->child, n);
1445
1446         free(n->path);
1447         bus_node_gc(b, n->parent);
1448         free(n);
1449 }
1450
1451 static int bus_add_object(
1452                 sd_bus *bus,
1453                 sd_bus_slot **slot,
1454                 bool fallback,
1455                 const char *path,
1456                 sd_bus_message_handler_t callback,
1457                 void *userdata) {
1458
1459         sd_bus_slot *s;
1460         struct node *n;
1461         int r;
1462
1463         assert_return(bus, -EINVAL);
1464         assert_return(object_path_is_valid(path), -EINVAL);
1465         assert_return(callback, -EINVAL);
1466         assert_return(!bus_pid_changed(bus), -ECHILD);
1467
1468         n = bus_node_allocate(bus, path);
1469         if (!n)
1470                 return -ENOMEM;
1471
1472         s = bus_slot_allocate(bus, !slot, BUS_NODE_CALLBACK, sizeof(struct node_callback), userdata);
1473         if (!s) {
1474                 r = -ENOMEM;
1475                 goto fail;
1476         }
1477
1478         s->node_callback.callback = callback;
1479         s->node_callback.is_fallback = fallback;
1480
1481         s->node_callback.node = n;
1482         LIST_PREPEND(callbacks, n->callbacks, &s->node_callback);
1483         bus->nodes_modified = true;
1484
1485         if (slot)
1486                 *slot = s;
1487
1488         return 0;
1489
1490 fail:
1491         sd_bus_slot_unref(s);
1492         bus_node_gc(bus, n);
1493
1494         return r;
1495 }
1496
1497 _public_ int sd_bus_add_object(
1498                 sd_bus *bus,
1499                 sd_bus_slot **slot,
1500                 const char *path,
1501                 sd_bus_message_handler_t callback,
1502                 void *userdata) {
1503
1504         return bus_add_object(bus, slot, false, path, callback, userdata);
1505 }
1506
1507 _public_ int sd_bus_add_fallback(
1508                 sd_bus *bus,
1509                 sd_bus_slot **slot,
1510                 const char *prefix,
1511                 sd_bus_message_handler_t callback,
1512                 void *userdata) {
1513
1514         return bus_add_object(bus, slot, true, prefix, callback, userdata);
1515 }
1516
1517 static unsigned long vtable_member_hash_func(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) {
1518         const struct vtable_member *m = a;
1519         uint8_t hash_key2[HASH_KEY_SIZE];
1520         unsigned long ret;
1521
1522         assert(m);
1523
1524         ret = string_hash_func(m->path, hash_key);
1525
1526         /* Use a slightly different hash key for the interface */
1527         memcpy(hash_key2, hash_key, HASH_KEY_SIZE);
1528         hash_key2[0]++;
1529         ret ^= string_hash_func(m->interface, hash_key2);
1530
1531         /* And an even different one for the  member */
1532         hash_key2[0]++;
1533         ret ^= string_hash_func(m->member, hash_key2);
1534
1535         return ret;
1536 }
1537
1538 static int vtable_member_compare_func(const void *a, const void *b) {
1539         const struct vtable_member *x = a, *y = b;
1540         int r;
1541
1542         assert(x);
1543         assert(y);
1544
1545         r = strcmp(x->path, y->path);
1546         if (r != 0)
1547                 return r;
1548
1549         r = strcmp(x->interface, y->interface);
1550         if (r != 0)
1551                 return r;
1552
1553         return strcmp(x->member, y->member);
1554 }
1555
1556 static const struct hash_ops vtable_member_hash_ops = {
1557         .hash = vtable_member_hash_func,
1558         .compare = vtable_member_compare_func
1559 };
1560
1561 static int add_object_vtable_internal(
1562                 sd_bus *bus,
1563                 sd_bus_slot **slot,
1564                 const char *path,
1565                 const char *interface,
1566                 const sd_bus_vtable *vtable,
1567                 bool fallback,
1568                 sd_bus_object_find_t find,
1569                 void *userdata) {
1570
1571         sd_bus_slot *s = NULL;
1572         struct node_vtable *i, *existing = NULL;
1573         const sd_bus_vtable *v;
1574         struct node *n;
1575         int r;
1576
1577         assert_return(bus, -EINVAL);
1578         assert_return(object_path_is_valid(path), -EINVAL);
1579         assert_return(interface_name_is_valid(interface), -EINVAL);
1580         assert_return(vtable, -EINVAL);
1581         assert_return(vtable[0].type == _SD_BUS_VTABLE_START, -EINVAL);
1582         assert_return(vtable[0].x.start.element_size == sizeof(struct sd_bus_vtable), -EINVAL);
1583         assert_return(!bus_pid_changed(bus), -ECHILD);
1584         assert_return(!streq(interface, "org.freedesktop.DBus.Properties") &&
1585                       !streq(interface, "org.freedesktop.DBus.Introspectable") &&
1586                       !streq(interface, "org.freedesktop.DBus.Peer") &&
1587                       !streq(interface, "org.freedesktop.DBus.ObjectManager"), -EINVAL);
1588
1589         r = hashmap_ensure_allocated(&bus->vtable_methods, &vtable_member_hash_ops);
1590         if (r < 0)
1591                 return r;
1592
1593         r = hashmap_ensure_allocated(&bus->vtable_properties, &vtable_member_hash_ops);
1594         if (r < 0)
1595                 return r;
1596
1597         n = bus_node_allocate(bus, path);
1598         if (!n)
1599                 return -ENOMEM;
1600
1601         LIST_FOREACH(vtables, i, n->vtables) {
1602                 if (i->is_fallback != fallback) {
1603                         r = -EPROTOTYPE;
1604                         goto fail;
1605                 }
1606
1607                 if (streq(i->interface, interface)) {
1608
1609                         if (i->vtable == vtable) {
1610                                 r = -EEXIST;
1611                                 goto fail;
1612                         }
1613
1614                         existing = i;
1615                 }
1616         }
1617
1618         s = bus_slot_allocate(bus, !slot, BUS_NODE_VTABLE, sizeof(struct node_vtable), userdata);
1619         if (!s) {
1620                 r = -ENOMEM;
1621                 goto fail;
1622         }
1623
1624         s->node_vtable.is_fallback = fallback;
1625         s->node_vtable.vtable = vtable;
1626         s->node_vtable.find = find;
1627
1628         s->node_vtable.interface = strdup(interface);
1629         if (!s->node_vtable.interface) {
1630                 r = -ENOMEM;
1631                 goto fail;
1632         }
1633
1634         for (v = s->node_vtable.vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
1635
1636                 switch (v->type) {
1637
1638                 case _SD_BUS_VTABLE_METHOD: {
1639                         struct vtable_member *m;
1640
1641                         if (!member_name_is_valid(v->x.method.member) ||
1642                             !signature_is_valid(strempty(v->x.method.signature), false) ||
1643                             !signature_is_valid(strempty(v->x.method.result), false) ||
1644                             !(v->x.method.handler || (isempty(v->x.method.signature) && isempty(v->x.method.result))) ||
1645                             v->flags & (SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) {
1646                                 r = -EINVAL;
1647                                 goto fail;
1648                         }
1649
1650                         m = new0(struct vtable_member, 1);
1651                         if (!m) {
1652                                 r = -ENOMEM;
1653                                 goto fail;
1654                         }
1655
1656                         m->parent = &s->node_vtable;
1657                         m->path = n->path;
1658                         m->interface = s->node_vtable.interface;
1659                         m->member = v->x.method.member;
1660                         m->vtable = v;
1661
1662                         r = hashmap_put(bus->vtable_methods, m, m);
1663                         if (r < 0) {
1664                                 free(m);
1665                                 goto fail;
1666                         }
1667
1668                         break;
1669                 }
1670
1671                 case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
1672
1673                         if (!(v->x.property.set || bus_type_is_basic(v->x.property.signature[0]))) {
1674                                 r = -EINVAL;
1675                                 goto fail;
1676                         }
1677
1678                         /* Fall through */
1679
1680                 case _SD_BUS_VTABLE_PROPERTY: {
1681                         struct vtable_member *m;
1682
1683                         if (!member_name_is_valid(v->x.property.member) ||
1684                             !signature_is_single(v->x.property.signature, false) ||
1685                             !(v->x.property.get || bus_type_is_basic(v->x.property.signature[0]) || streq(v->x.property.signature, "as")) ||
1686                             v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY ||
1687                             (!!(v->flags & SD_BUS_VTABLE_PROPERTY_CONST) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) > 1 ||
1688                             (v->flags & SD_BUS_VTABLE_UNPRIVILEGED && v->type == _SD_BUS_VTABLE_PROPERTY)) {
1689                                 r = -EINVAL;
1690                                 goto fail;
1691                         }
1692
1693                         m = new0(struct vtable_member, 1);
1694                         if (!m) {
1695                                 r = -ENOMEM;
1696                                 goto fail;
1697                         }
1698
1699                         m->parent = &s->node_vtable;
1700                         m->path = n->path;
1701                         m->interface = s->node_vtable.interface;
1702                         m->member = v->x.property.member;
1703                         m->vtable = v;
1704
1705                         r = hashmap_put(bus->vtable_properties, m, m);
1706                         if (r < 0) {
1707                                 free(m);
1708                                 goto fail;
1709                         }
1710
1711                         break;
1712                 }
1713
1714                 case _SD_BUS_VTABLE_SIGNAL:
1715
1716                         if (!member_name_is_valid(v->x.signal.member) ||
1717                             !signature_is_valid(strempty(v->x.signal.signature), false) ||
1718                             v->flags & SD_BUS_VTABLE_UNPRIVILEGED) {
1719                                 r = -EINVAL;
1720                                 goto fail;
1721                         }
1722
1723                         break;
1724
1725                 default:
1726                         r = -EINVAL;
1727                         goto fail;
1728                 }
1729         }
1730
1731         s->node_vtable.node = n;
1732         LIST_INSERT_AFTER(vtables, n->vtables, existing, &s->node_vtable);
1733         bus->nodes_modified = true;
1734
1735         if (slot)
1736                 *slot = s;
1737
1738         return 0;
1739
1740 fail:
1741         sd_bus_slot_unref(s);
1742         bus_node_gc(bus, n);
1743
1744         return r;
1745 }
1746
1747 _public_ int sd_bus_add_object_vtable(
1748                 sd_bus *bus,
1749                 sd_bus_slot **slot,
1750                 const char *path,
1751                 const char *interface,
1752                 const sd_bus_vtable *vtable,
1753                 void *userdata) {
1754
1755         return add_object_vtable_internal(bus, slot, path, interface, vtable, false, NULL, userdata);
1756 }
1757
1758 _public_ int sd_bus_add_fallback_vtable(
1759                 sd_bus *bus,
1760                 sd_bus_slot **slot,
1761                 const char *prefix,
1762                 const char *interface,
1763                 const sd_bus_vtable *vtable,
1764                 sd_bus_object_find_t find,
1765                 void *userdata) {
1766
1767         return add_object_vtable_internal(bus, slot, prefix, interface, vtable, true, find, userdata);
1768 }
1769
1770 _public_ int sd_bus_add_node_enumerator(
1771                 sd_bus *bus,
1772                 sd_bus_slot **slot,
1773                 const char *path,
1774                 sd_bus_node_enumerator_t callback,
1775                 void *userdata) {
1776
1777         sd_bus_slot *s;
1778         struct node *n;
1779         int r;
1780
1781         assert_return(bus, -EINVAL);
1782         assert_return(object_path_is_valid(path), -EINVAL);
1783         assert_return(callback, -EINVAL);
1784         assert_return(!bus_pid_changed(bus), -ECHILD);
1785
1786         n = bus_node_allocate(bus, path);
1787         if (!n)
1788                 return -ENOMEM;
1789
1790         s = bus_slot_allocate(bus, !slot, BUS_NODE_ENUMERATOR, sizeof(struct node_enumerator), userdata);
1791         if (!s) {
1792                 r = -ENOMEM;
1793                 goto fail;
1794         }
1795
1796         s->node_enumerator.callback = callback;
1797
1798         s->node_enumerator.node = n;
1799         LIST_PREPEND(enumerators, n->enumerators, &s->node_enumerator);
1800         bus->nodes_modified = true;
1801
1802         if (slot)
1803                 *slot = s;
1804
1805         return 0;
1806
1807 fail:
1808         sd_bus_slot_unref(s);
1809         bus_node_gc(bus, n);
1810
1811         return r;
1812 }
1813
1814 static int emit_properties_changed_on_interface(
1815                 sd_bus *bus,
1816                 const char *prefix,
1817                 const char *path,
1818                 const char *interface,
1819                 bool require_fallback,
1820                 bool *found_interface,
1821                 char **names) {
1822
1823         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1824         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1825         bool has_invalidating = false, has_changing = false;
1826         struct vtable_member key = {};
1827         struct node_vtable *c;
1828         struct node *n;
1829         char **property;
1830         void *u = NULL;
1831         int r;
1832
1833         assert(bus);
1834         assert(prefix);
1835         assert(path);
1836         assert(interface);
1837         assert(found_interface);
1838
1839         n = hashmap_get(bus->nodes, prefix);
1840         if (!n)
1841                 return 0;
1842
1843         r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
1844         if (r < 0)
1845                 return r;
1846
1847         r = sd_bus_message_append(m, "s", interface);
1848         if (r < 0)
1849                 return r;
1850
1851         r = sd_bus_message_open_container(m, 'a', "{sv}");
1852         if (r < 0)
1853                 return r;
1854
1855         key.path = prefix;
1856         key.interface = interface;
1857
1858         LIST_FOREACH(vtables, c, n->vtables) {
1859                 if (require_fallback && !c->is_fallback)
1860                         continue;
1861
1862                 if (!streq(c->interface, interface))
1863                         continue;
1864
1865                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
1866                 if (r < 0)
1867                         return r;
1868                 if (bus->nodes_modified)
1869                         return 0;
1870                 if (r == 0)
1871                         continue;
1872
1873                 *found_interface = true;
1874
1875                 if (names) {
1876                         /* If the caller specified a list of
1877                          * properties we include exactly those in the
1878                          * PropertiesChanged message */
1879
1880                         STRV_FOREACH(property, names) {
1881                                 struct vtable_member *v;
1882
1883                                 assert_return(member_name_is_valid(*property), -EINVAL);
1884
1885                                 key.member = *property;
1886                                 v = hashmap_get(bus->vtable_properties, &key);
1887                                 if (!v)
1888                                         return -ENOENT;
1889
1890                                 /* If there are two vtables for the same
1891                                  * interface, let's handle this property when
1892                                  * we come to that vtable. */
1893                                 if (c != v->parent)
1894                                         continue;
1895
1896                                 assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ||
1897                                               v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION, -EDOM);
1898
1899                                 assert_return(!(v->vtable->flags & SD_BUS_VTABLE_HIDDEN), -EDOM);
1900
1901                                 if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
1902                                         has_invalidating = true;
1903                                         continue;
1904                                 }
1905
1906                                 has_changing = true;
1907
1908                                 r = vtable_append_one_property(bus, m, m->path, c, v->vtable, u, &error);
1909                                 if (r < 0)
1910                                         return r;
1911                                 if (bus->nodes_modified)
1912                                         return 0;
1913                         }
1914                 } else {
1915                         const sd_bus_vtable *v;
1916
1917                         /* If the caller specified no properties list
1918                          * we include all properties that are marked
1919                          * as changing in the message. */
1920
1921                         for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
1922                                 if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
1923                                         continue;
1924
1925                                 if (v->flags & SD_BUS_VTABLE_HIDDEN)
1926                                         continue;
1927
1928                                 if (v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
1929                                         has_invalidating = true;
1930                                         continue;
1931                                 }
1932
1933                                 if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
1934                                         continue;
1935
1936                                 has_changing = true;
1937
1938                                 r = vtable_append_one_property(bus, m, m->path, c, v, u, &error);
1939                                 if (r < 0)
1940                                         return r;
1941                                 if (bus->nodes_modified)
1942                                         return 0;
1943                         }
1944                 }
1945         }
1946
1947         if (!has_invalidating && !has_changing)
1948                 return 0;
1949
1950         r = sd_bus_message_close_container(m);
1951         if (r < 0)
1952                 return r;
1953
1954         r = sd_bus_message_open_container(m, 'a', "s");
1955         if (r < 0)
1956                 return r;
1957
1958         if (has_invalidating) {
1959                 LIST_FOREACH(vtables, c, n->vtables) {
1960                         if (require_fallback && !c->is_fallback)
1961                                 continue;
1962
1963                         if (!streq(c->interface, interface))
1964                                 continue;
1965
1966                         r = node_vtable_get_userdata(bus, path, c, &u, &error);
1967                         if (r < 0)
1968                                 return r;
1969                         if (bus->nodes_modified)
1970                                 return 0;
1971                         if (r == 0)
1972                                 continue;
1973
1974                         if (names) {
1975                                 STRV_FOREACH(property, names) {
1976                                         struct vtable_member *v;
1977
1978                                         key.member = *property;
1979                                         assert_se(v = hashmap_get(bus->vtable_properties, &key));
1980                                         assert(c == v->parent);
1981
1982                                         if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
1983                                                 continue;
1984
1985                                         r = sd_bus_message_append(m, "s", *property);
1986                                         if (r < 0)
1987                                                 return r;
1988                                 }
1989                         } else {
1990                                 const sd_bus_vtable *v;
1991
1992                                 for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
1993                                         if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
1994                                                 continue;
1995
1996                                         if (v->flags & SD_BUS_VTABLE_HIDDEN)
1997                                                 continue;
1998
1999                                         if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
2000                                                 continue;
2001
2002                                         r = sd_bus_message_append(m, "s", v->x.property.member);
2003                                         if (r < 0)
2004                                                 return r;
2005                                 }
2006                         }
2007                 }
2008         }
2009
2010         r = sd_bus_message_close_container(m);
2011         if (r < 0)
2012                 return r;
2013
2014         r = sd_bus_send(bus, m, NULL);
2015         if (r < 0)
2016                 return r;
2017
2018         return 1;
2019 }
2020
2021 _public_ int sd_bus_emit_properties_changed_strv(
2022                 sd_bus *bus,
2023                 const char *path,
2024                 const char *interface,
2025                 char **names) {
2026
2027         BUS_DONT_DESTROY(bus);
2028         bool found_interface = false;
2029         char *prefix;
2030         int r;
2031
2032         assert_return(bus, -EINVAL);
2033         assert_return(object_path_is_valid(path), -EINVAL);
2034         assert_return(interface_name_is_valid(interface), -EINVAL);
2035         assert_return(!bus_pid_changed(bus), -ECHILD);
2036
2037         if (!BUS_IS_OPEN(bus->state))
2038                 return -ENOTCONN;
2039
2040         /* A non-NULL but empty names list means nothing needs to be
2041            generated. A NULL list OTOH indicates that all properties
2042            that are set to EMITS_CHANGE or EMITS_INVALIDATION shall be
2043            included in the PropertiesChanged message. */
2044         if (names && names[0] == NULL)
2045                 return 0;
2046
2047         do {
2048                 bus->nodes_modified = false;
2049
2050                 r = emit_properties_changed_on_interface(bus, path, path, interface, false, &found_interface, names);
2051                 if (r != 0)
2052                         return r;
2053                 if (bus->nodes_modified)
2054                         continue;
2055
2056                 prefix = alloca(strlen(path) + 1);
2057                 OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2058                         r = emit_properties_changed_on_interface(bus, prefix, path, interface, true, &found_interface, names);
2059                         if (r != 0)
2060                                 return r;
2061                         if (bus->nodes_modified)
2062                                 break;
2063                 }
2064
2065         } while (bus->nodes_modified);
2066
2067         return found_interface ? 0 : -ENOENT;
2068 }
2069
2070 _public_ int sd_bus_emit_properties_changed(
2071                 sd_bus *bus,
2072                 const char *path,
2073                 const char *interface,
2074                 const char *name, ...)  {
2075
2076         char **names;
2077
2078         assert_return(bus, -EINVAL);
2079         assert_return(object_path_is_valid(path), -EINVAL);
2080         assert_return(interface_name_is_valid(interface), -EINVAL);
2081         assert_return(!bus_pid_changed(bus), -ECHILD);
2082
2083         if (!BUS_IS_OPEN(bus->state))
2084                 return -ENOTCONN;
2085
2086         if (!name)
2087                 return 0;
2088
2089         names = strv_from_stdarg_alloca(name);
2090
2091         return sd_bus_emit_properties_changed_strv(bus, path, interface, names);
2092 }
2093
2094 static int interfaces_added_append_one_prefix(
2095                 sd_bus *bus,
2096                 sd_bus_message *m,
2097                 const char *prefix,
2098                 const char *path,
2099                 const char *interface,
2100                 bool require_fallback) {
2101
2102         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2103         bool found_interface = false;
2104         struct node_vtable *c;
2105         struct node *n;
2106         void *u = NULL;
2107         int r;
2108
2109         assert(bus);
2110         assert(m);
2111         assert(prefix);
2112         assert(path);
2113         assert(interface);
2114
2115         n = hashmap_get(bus->nodes, prefix);
2116         if (!n)
2117                 return 0;
2118
2119         LIST_FOREACH(vtables, c, n->vtables) {
2120                 if (require_fallback && !c->is_fallback)
2121                         continue;
2122
2123                 if (!streq(c->interface, interface))
2124                         continue;
2125
2126                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
2127                 if (r < 0)
2128                         return r;
2129                 if (bus->nodes_modified)
2130                         return 0;
2131                 if (r == 0)
2132                         continue;
2133
2134                 if (!found_interface) {
2135                         r = sd_bus_message_append_basic(m, 's', interface);
2136                         if (r < 0)
2137                                 return r;
2138
2139                         r = sd_bus_message_open_container(m, 'a', "{sv}");
2140                         if (r < 0)
2141                                 return r;
2142
2143                         found_interface = true;
2144                 }
2145
2146                 r = vtable_append_all_properties(bus, m, path, c, u, &error);
2147                 if (r < 0)
2148                         return r;
2149                 if (bus->nodes_modified)
2150                         return 0;
2151         }
2152
2153         if (found_interface) {
2154                 r = sd_bus_message_close_container(m);
2155                 if (r < 0)
2156                         return r;
2157         }
2158
2159         return found_interface;
2160 }
2161
2162 static int interfaces_added_append_one(
2163                 sd_bus *bus,
2164                 sd_bus_message *m,
2165                 const char *path,
2166                 const char *interface) {
2167
2168         char *prefix;
2169         int r;
2170
2171         assert(bus);
2172         assert(m);
2173         assert(path);
2174         assert(interface);
2175
2176         r = interfaces_added_append_one_prefix(bus, m, path, path, interface, false);
2177         if (r != 0)
2178                 return r;
2179         if (bus->nodes_modified)
2180                 return 0;
2181
2182         prefix = alloca(strlen(path) + 1);
2183         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2184                 r = interfaces_added_append_one_prefix(bus, m, prefix, path, interface, true);
2185                 if (r != 0)
2186                         return r;
2187                 if (bus->nodes_modified)
2188                         return 0;
2189         }
2190
2191         return -ENOENT;
2192 }
2193
2194 _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) {
2195         BUS_DONT_DESTROY(bus);
2196
2197         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2198         char **i;
2199         int r;
2200
2201         assert_return(bus, -EINVAL);
2202         assert_return(object_path_is_valid(path), -EINVAL);
2203         assert_return(!bus_pid_changed(bus), -ECHILD);
2204
2205         if (!BUS_IS_OPEN(bus->state))
2206                 return -ENOTCONN;
2207
2208         if (strv_isempty(interfaces))
2209                 return 0;
2210
2211         do {
2212                 bus->nodes_modified = false;
2213                 m = sd_bus_message_unref(m);
2214
2215                 r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded");
2216                 if (r < 0)
2217                         return r;
2218
2219                 r = sd_bus_message_append_basic(m, 'o', path);
2220                 if (r < 0)
2221                         return r;
2222
2223                 r = sd_bus_message_open_container(m, 'a', "{sa{sv}}");
2224                 if (r < 0)
2225                         return r;
2226
2227                 STRV_FOREACH(i, interfaces) {
2228                         assert_return(interface_name_is_valid(*i), -EINVAL);
2229
2230                         r = sd_bus_message_open_container(m, 'e', "sa{sv}");
2231                         if (r < 0)
2232                                 return r;
2233
2234                         r = interfaces_added_append_one(bus, m, path, *i);
2235                         if (r < 0)
2236                                 return r;
2237
2238                         if (bus->nodes_modified)
2239                                 break;
2240
2241                         r = sd_bus_message_close_container(m);
2242                         if (r < 0)
2243                                 return r;
2244                 }
2245
2246                 if (bus->nodes_modified)
2247                         continue;
2248
2249                 r = sd_bus_message_close_container(m);
2250                 if (r < 0)
2251                         return r;
2252
2253         } while (bus->nodes_modified);
2254
2255         return sd_bus_send(bus, m, NULL);
2256 }
2257
2258 _public_ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...) {
2259         char **interfaces;
2260
2261         assert_return(bus, -EINVAL);
2262         assert_return(object_path_is_valid(path), -EINVAL);
2263         assert_return(!bus_pid_changed(bus), -ECHILD);
2264
2265         if (!BUS_IS_OPEN(bus->state))
2266                 return -ENOTCONN;
2267
2268         interfaces = strv_from_stdarg_alloca(interface);
2269
2270         return sd_bus_emit_interfaces_added_strv(bus, path, interfaces);
2271 }
2272
2273 _public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) {
2274         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2275         int r;
2276
2277         assert_return(bus, -EINVAL);
2278         assert_return(object_path_is_valid(path), -EINVAL);
2279         assert_return(!bus_pid_changed(bus), -ECHILD);
2280
2281         if (!BUS_IS_OPEN(bus->state))
2282                 return -ENOTCONN;
2283
2284         if (strv_isempty(interfaces))
2285                 return 0;
2286
2287         r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved");
2288         if (r < 0)
2289                 return r;
2290
2291         r = sd_bus_message_append_basic(m, 'o', path);
2292         if (r < 0)
2293                 return r;
2294
2295         r = sd_bus_message_append_strv(m, interfaces);
2296         if (r < 0)
2297                 return r;
2298
2299         return sd_bus_send(bus, m, NULL);
2300 }
2301
2302 _public_ int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) {
2303         char **interfaces;
2304
2305         assert_return(bus, -EINVAL);
2306         assert_return(object_path_is_valid(path), -EINVAL);
2307         assert_return(!bus_pid_changed(bus), -ECHILD);
2308
2309         if (!BUS_IS_OPEN(bus->state))
2310                 return -ENOTCONN;
2311
2312         interfaces = strv_from_stdarg_alloca(interface);
2313
2314         return sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
2315 }
2316
2317 _public_ int sd_bus_add_object_manager(sd_bus *bus, sd_bus_slot **slot, const char *path) {
2318         sd_bus_slot *s;
2319         struct node *n;
2320         int r;
2321
2322         assert_return(bus, -EINVAL);
2323         assert_return(object_path_is_valid(path), -EINVAL);
2324         assert_return(!bus_pid_changed(bus), -ECHILD);
2325
2326         n = bus_node_allocate(bus, path);
2327         if (!n)
2328                 return -ENOMEM;
2329
2330         s = bus_slot_allocate(bus, !slot, BUS_NODE_OBJECT_MANAGER, sizeof(struct node_object_manager), NULL);
2331         if (!s) {
2332                 r = -ENOMEM;
2333                 goto fail;
2334         }
2335
2336         s->node_object_manager.node = n;
2337         LIST_PREPEND(object_managers, n->object_managers, &s->node_object_manager);
2338         bus->nodes_modified = true;
2339
2340         if (slot)
2341                 *slot = s;
2342
2343         return 0;
2344
2345 fail:
2346         sd_bus_slot_unref(s);
2347         bus_node_gc(bus, n);
2348
2349         return r;
2350 }