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