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