chiark / gitweb /
bus: introduce "trusted" bus concept and encode access control in object vtables
[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         for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
637                 if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
638                         continue;
639
640                 r = sd_bus_message_open_container(reply, 'e', "sv");
641                 if (r < 0)
642                         return r;
643
644                 r = sd_bus_message_append(reply, "s", v->x.property.member);
645                 if (r < 0)
646                         return r;
647
648                 r = sd_bus_message_open_container(reply, 'v', v->x.property.signature);
649                 if (r < 0)
650                         return r;
651
652                 r = invoke_property_get(bus, v, path, c->interface, v->x.property.member, reply, vtable_property_convert_userdata(v, userdata), error);
653                 if (r < 0)
654                         return r;
655                 if (bus->nodes_modified)
656                         return 0;
657
658                 r = sd_bus_message_close_container(reply);
659                 if (r < 0)
660                         return r;
661
662                 r = sd_bus_message_close_container(reply);
663                 if (r < 0)
664                         return r;
665         }
666
667         return 1;
668 }
669
670 static int property_get_all_callbacks_run(
671                 sd_bus *bus,
672                 sd_bus_message *m,
673                 struct node_vtable *first,
674                 bool require_fallback,
675                 const char *iface,
676                 bool *found_object) {
677
678         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
679         struct node_vtable *c;
680         bool found_interface;
681         int r;
682
683         assert(bus);
684         assert(m);
685         assert(found_object);
686
687         r = sd_bus_message_new_method_return(m, &reply);
688         if (r < 0)
689                 return r;
690
691         r = sd_bus_message_open_container(reply, 'a', "{sv}");
692         if (r < 0)
693                 return r;
694
695         found_interface = !iface ||
696                 streq(iface, "org.freedesktop.DBus.Properties") ||
697                 streq(iface, "org.freedesktop.DBus.Peer") ||
698                 streq(iface, "org.freedesktop.DBus.Introspectable");
699
700         LIST_FOREACH(vtables, c, first) {
701                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
702                 void *u;
703
704                 if (require_fallback && !c->is_fallback)
705                         continue;
706
707                 r = node_vtable_get_userdata(bus, m->path, c, &u, &error);
708                 if (r < 0)
709                         return bus_maybe_reply_error(m, r, &error);
710                 if (bus->nodes_modified)
711                         return 0;
712                 if (r == 0)
713                         continue;
714
715                 *found_object = true;
716
717                 if (iface && !streq(c->interface, iface))
718                         continue;
719                 found_interface = true;
720
721                 r = vtable_append_all_properties(bus, reply, m->path, c, u, &error);
722                 if (r < 0)
723                         return bus_maybe_reply_error(m, r, &error);
724                 if (bus->nodes_modified)
725                         return 0;
726         }
727
728         if (!found_interface) {
729                 r = sd_bus_reply_method_errorf(
730                                 m,
731                                 SD_BUS_ERROR_UNKNOWN_INTERFACE,
732                                 "Unknown interface '%s'.", iface);
733                 if (r < 0)
734                         return r;
735
736                 return 1;
737         }
738
739         r = sd_bus_message_close_container(reply);
740         if (r < 0)
741                 return r;
742
743         r = sd_bus_send(bus, reply, NULL);
744         if (r < 0)
745                 return r;
746
747         return 1;
748 }
749
750 static bool bus_node_with_object_manager(sd_bus *bus, struct node *n) {
751         assert(bus);
752         assert(n);
753
754         if (n->object_manager)
755                 return true;
756
757         if (n->parent)
758                 return bus_node_with_object_manager(bus, n->parent);
759
760         return false;
761 }
762
763 static bool bus_node_exists(
764                 sd_bus *bus,
765                 struct node *n,
766                 const char *path,
767                 bool require_fallback) {
768
769         struct node_vtable *c;
770         struct node_callback *k;
771
772         assert(bus);
773         assert(n);
774         assert(path);
775
776         /* Tests if there's anything attached directly to this node
777          * for the specified path */
778
779         LIST_FOREACH(callbacks, k, n->callbacks) {
780                 if (require_fallback && !k->is_fallback)
781                         continue;
782
783                 return true;
784         }
785
786         LIST_FOREACH(vtables, c, n->vtables) {
787                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
788
789                 if (require_fallback && !c->is_fallback)
790                         continue;
791
792                 if (node_vtable_get_userdata(bus, path, c, NULL, &error) > 0)
793                         return true;
794                 if (bus->nodes_modified)
795                         return false;
796         }
797
798         return !require_fallback && (n->enumerators || n->object_manager);
799 }
800
801 static int process_introspect(
802                 sd_bus *bus,
803                 sd_bus_message *m,
804                 struct node *n,
805                 bool require_fallback,
806                 bool *found_object) {
807
808         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
809         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
810         _cleanup_set_free_free_ Set *s = NULL;
811         const char *previous_interface = NULL;
812         struct introspect intro;
813         struct node_vtable *c;
814         bool empty;
815         int r;
816
817         assert(bus);
818         assert(m);
819         assert(n);
820         assert(found_object);
821
822         r = get_child_nodes(bus, m->path, n, &s, &error);
823         if (r < 0)
824                 return bus_maybe_reply_error(m, r, &error);
825         if (bus->nodes_modified)
826                 return 0;
827
828         r = introspect_begin(&intro);
829         if (r < 0)
830                 return r;
831
832         r = introspect_write_default_interfaces(&intro, bus_node_with_object_manager(bus, n));
833         if (r < 0)
834                 return r;
835
836         empty = set_isempty(s);
837
838         LIST_FOREACH(vtables, c, n->vtables) {
839                 if (require_fallback && !c->is_fallback)
840                         continue;
841
842                 r = node_vtable_get_userdata(bus, m->path, c, NULL, &error);
843                 if (r < 0) {
844                         r = bus_maybe_reply_error(m, r, &error);
845                         goto finish;
846                 }
847                 if (bus->nodes_modified) {
848                         r = 0;
849                         goto finish;
850                 }
851                 if (r == 0)
852                         continue;
853
854                 empty = false;
855
856                 if (!streq_ptr(previous_interface, c->interface)) {
857
858                         if (previous_interface)
859                                 fputs(" </interface>\n", intro.f);
860
861                         fprintf(intro.f, " <interface name=\"%s\">\n", c->interface);
862                 }
863
864                 r = introspect_write_interface(&intro, c->vtable);
865                 if (r < 0)
866                         goto finish;
867
868                 previous_interface = c->interface;
869         }
870
871         if (previous_interface)
872                 fputs(" </interface>\n", intro.f);
873
874         if (empty) {
875                 /* Nothing?, let's see if we exist at all, and if not
876                  * refuse to do anything */
877                 r = bus_node_exists(bus, n, m->path, require_fallback);
878                 if (r < 0)
879                         return r;
880                 if (bus->nodes_modified)
881                         return 0;
882                 if (r == 0)
883                         goto finish;
884         }
885
886         *found_object = true;
887
888         r = introspect_write_child_nodes(&intro, s, m->path);
889         if (r < 0)
890                 goto finish;
891
892         r = introspect_finish(&intro, bus, m, &reply);
893         if (r < 0)
894                 goto finish;
895
896         r = sd_bus_send(bus, reply, NULL);
897         if (r < 0)
898                 goto finish;
899
900         r = 1;
901
902 finish:
903         introspect_free(&intro);
904         return r;
905 }
906
907 static int object_manager_serialize_path(
908                 sd_bus *bus,
909                 sd_bus_message *reply,
910                 const char *prefix,
911                 const char *path,
912                 bool require_fallback,
913                 sd_bus_error *error) {
914
915         const char *previous_interface = NULL;
916         bool found_something = false;
917         struct node_vtable *i;
918         struct node *n;
919         int r;
920
921         assert(bus);
922         assert(reply);
923         assert(prefix);
924         assert(path);
925         assert(error);
926
927         n = hashmap_get(bus->nodes, prefix);
928         if (!n)
929                 return 0;
930
931         LIST_FOREACH(vtables, i, n->vtables) {
932                 void *u;
933
934                 if (require_fallback && !i->is_fallback)
935                         continue;
936
937                 r = node_vtable_get_userdata(bus, path, i, &u, error);
938                 if (r < 0)
939                         return r;
940                 if (bus->nodes_modified)
941                         return 0;
942                 if (r == 0)
943                         continue;
944
945                 if (!found_something) {
946
947                         /* Open the object part */
948
949                         r = sd_bus_message_open_container(reply, 'e', "oa{sa{sv}}");
950                         if (r < 0)
951                                 return r;
952
953                         r = sd_bus_message_append(reply, "o", path);
954                         if (r < 0)
955                                 return r;
956
957                         r = sd_bus_message_open_container(reply, 'a', "{sa{sv}}");
958                         if (r < 0)
959                                 return r;
960
961                         found_something = true;
962                 }
963
964                 if (!streq_ptr(previous_interface, i->interface)) {
965
966                         /* Maybe close the previous interface part */
967
968                         if (previous_interface) {
969                                 r = sd_bus_message_close_container(reply);
970                                 if (r < 0)
971                                         return r;
972
973                                 r = sd_bus_message_close_container(reply);
974                                 if (r < 0)
975                                         return r;
976                         }
977
978                         /* Open the new interface part */
979
980                         r = sd_bus_message_open_container(reply, 'e', "sa{sv}");
981                         if (r < 0)
982                                 return r;
983
984                         r = sd_bus_message_append(reply, "s", i->interface);
985                         if (r < 0)
986                                 return r;
987
988                         r = sd_bus_message_open_container(reply, 'a', "{sv}");
989                         if (r < 0)
990                                 return r;
991                 }
992
993                 r = vtable_append_all_properties(bus, reply, path, i, u, error);
994                 if (r < 0)
995                         return r;
996                 if (bus->nodes_modified)
997                         return 0;
998
999                 previous_interface = i->interface;
1000         }
1001
1002         if (previous_interface) {
1003                 r = sd_bus_message_close_container(reply);
1004                 if (r < 0)
1005                         return r;
1006
1007                 r = sd_bus_message_close_container(reply);
1008                 if (r < 0)
1009                         return r;
1010         }
1011
1012         if (found_something) {
1013                 r = sd_bus_message_close_container(reply);
1014                 if (r < 0)
1015                         return r;
1016
1017                 r = sd_bus_message_close_container(reply);
1018                 if (r < 0)
1019                         return r;
1020         }
1021
1022         return 1;
1023 }
1024
1025 static int object_manager_serialize_path_and_fallbacks(
1026                 sd_bus *bus,
1027                 sd_bus_message *reply,
1028                 const char *path,
1029                 sd_bus_error *error) {
1030
1031         char *prefix;
1032         int r;
1033
1034         assert(bus);
1035         assert(reply);
1036         assert(path);
1037         assert(error);
1038
1039         /* First, add all vtables registered for this path */
1040         r = object_manager_serialize_path(bus, reply, path, path, false, error);
1041         if (r < 0)
1042                 return r;
1043         if (bus->nodes_modified)
1044                 return 0;
1045
1046         /* Second, add fallback vtables registered for any of the prefixes */
1047         prefix = alloca(strlen(path) + 1);
1048         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
1049                 r = object_manager_serialize_path(bus, reply, prefix, path, true, error);
1050                 if (r < 0)
1051                         return r;
1052                 if (bus->nodes_modified)
1053                         return 0;
1054         }
1055
1056         return 0;
1057 }
1058
1059 static int process_get_managed_objects(
1060                 sd_bus *bus,
1061                 sd_bus_message *m,
1062                 struct node *n,
1063                 bool require_fallback,
1064                 bool *found_object) {
1065
1066         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1067         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1068         _cleanup_set_free_free_ Set *s = NULL;
1069         bool empty;
1070         int r;
1071
1072         assert(bus);
1073         assert(m);
1074         assert(n);
1075         assert(found_object);
1076
1077         if (!bus_node_with_object_manager(bus, n))
1078                 return 0;
1079
1080         r = get_child_nodes(bus, m->path, n, &s, &error);
1081         if (r < 0)
1082                 return r;
1083         if (bus->nodes_modified)
1084                 return 0;
1085
1086         r = sd_bus_message_new_method_return(m, &reply);
1087         if (r < 0)
1088                 return r;
1089
1090         r = sd_bus_message_open_container(reply, 'a', "{oa{sa{sv}}}");
1091         if (r < 0)
1092                 return r;
1093
1094         empty = set_isempty(s);
1095         if (empty) {
1096                 struct node_vtable *c;
1097
1098                 /* Hmm, so we have no children? Then let's check
1099                  * whether we exist at all, i.e. whether at least one
1100                  * vtable exists. */
1101
1102                 LIST_FOREACH(vtables, c, n->vtables) {
1103
1104                         if (require_fallback && !c->is_fallback)
1105                                 continue;
1106
1107                         if (r < 0)
1108                                 return r;
1109                         if (r == 0)
1110                                 continue;
1111
1112                         empty = false;
1113                         break;
1114                 }
1115
1116                 if (empty)
1117                         return 0;
1118         } else {
1119                 Iterator i;
1120                 char *path;
1121
1122                 SET_FOREACH(path, s, i) {
1123                         r = object_manager_serialize_path_and_fallbacks(bus, reply, path, &error);
1124                         if (r < 0)
1125                                 return r;
1126
1127                         if (bus->nodes_modified)
1128                                 return 0;
1129                 }
1130         }
1131
1132         r = sd_bus_message_close_container(reply);
1133         if (r < 0)
1134                 return r;
1135
1136         r = sd_bus_send(bus, reply, NULL);
1137         if (r < 0)
1138                 return r;
1139
1140         return 1;
1141 }
1142
1143 static int object_find_and_run(
1144                 sd_bus *bus,
1145                 sd_bus_message *m,
1146                 const char *p,
1147                 bool require_fallback,
1148                 bool *found_object) {
1149
1150         struct node *n;
1151         struct vtable_member vtable_key, *v;
1152         int r;
1153
1154         assert(bus);
1155         assert(m);
1156         assert(p);
1157         assert(found_object);
1158
1159         n = hashmap_get(bus->nodes, p);
1160         if (!n)
1161                 return 0;
1162
1163         /* First, try object callbacks */
1164         r = node_callbacks_run(bus, m, n->callbacks, require_fallback, found_object);
1165         if (r != 0)
1166                 return r;
1167         if (bus->nodes_modified)
1168                 return 0;
1169
1170         if (!m->interface || !m->member)
1171                 return 0;
1172
1173         /* Then, look for a known method */
1174         vtable_key.path = (char*) p;
1175         vtable_key.interface = m->interface;
1176         vtable_key.member = m->member;
1177
1178         v = hashmap_get(bus->vtable_methods, &vtable_key);
1179         if (v) {
1180                 r = method_callbacks_run(bus, m, v, require_fallback, found_object);
1181                 if (r != 0)
1182                         return r;
1183                 if (bus->nodes_modified)
1184                         return 0;
1185         }
1186
1187         /* Then, look for a known property */
1188         if (streq(m->interface, "org.freedesktop.DBus.Properties")) {
1189                 bool get = false;
1190
1191                 get = streq(m->member, "Get");
1192
1193                 if (get || streq(m->member, "Set")) {
1194
1195                         r = sd_bus_message_rewind(m, true);
1196                         if (r < 0)
1197                                 return r;
1198
1199                         vtable_key.path = (char*) p;
1200
1201                         r = sd_bus_message_read(m, "ss", &vtable_key.interface, &vtable_key.member);
1202                         if (r < 0)
1203                                 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected interface and member parameters");
1204
1205                         v = hashmap_get(bus->vtable_properties, &vtable_key);
1206                         if (v) {
1207                                 r = property_get_set_callbacks_run(bus, m, v, require_fallback, get, found_object);
1208                                 if (r != 0)
1209                                         return r;
1210                         }
1211
1212                 } else if (streq(m->member, "GetAll")) {
1213                         const char *iface;
1214
1215                         r = sd_bus_message_rewind(m, true);
1216                         if (r < 0)
1217                                 return r;
1218
1219                         r = sd_bus_message_read(m, "s", &iface);
1220                         if (r < 0)
1221                                 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected interface parameter");
1222
1223                         if (iface[0] == 0)
1224                                 iface = NULL;
1225
1226                         r = property_get_all_callbacks_run(bus, m, n->vtables, require_fallback, iface, found_object);
1227                         if (r != 0)
1228                                 return r;
1229                 }
1230
1231         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1232
1233                 if (!isempty(sd_bus_message_get_signature(m, true)))
1234                         return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
1235
1236                 r = process_introspect(bus, m, n, require_fallback, found_object);
1237                 if (r != 0)
1238                         return r;
1239
1240         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.ObjectManager", "GetManagedObjects")) {
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_get_managed_objects(bus, m, n, require_fallback, found_object);
1246                 if (r != 0)
1247                         return r;
1248         }
1249
1250         if (bus->nodes_modified)
1251                 return 0;
1252
1253         if (!*found_object) {
1254                 r = bus_node_exists(bus, n, m->path, require_fallback);
1255                 if (r < 0)
1256                         return r;
1257                 if (r > 0)
1258                         *found_object = true;
1259         }
1260
1261         return 0;
1262 }
1263
1264 int bus_process_object(sd_bus *bus, sd_bus_message *m) {
1265         int r;
1266         size_t pl;
1267         bool found_object = false;
1268
1269         assert(bus);
1270         assert(m);
1271
1272         if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
1273                 return 0;
1274
1275         if (hashmap_isempty(bus->nodes))
1276                 return 0;
1277
1278         assert(m->path);
1279         assert(m->member);
1280
1281         pl = strlen(m->path);
1282         do {
1283                 char prefix[pl+1];
1284
1285                 bus->nodes_modified = false;
1286
1287                 r = object_find_and_run(bus, m, m->path, false, &found_object);
1288                 if (r != 0)
1289                         return r;
1290
1291                 /* Look for fallback prefixes */
1292                 OBJECT_PATH_FOREACH_PREFIX(prefix, m->path) {
1293
1294                         if (bus->nodes_modified)
1295                                 break;
1296
1297                         r = object_find_and_run(bus, m, prefix, true, &found_object);
1298                         if (r != 0)
1299                                 return r;
1300                 }
1301
1302         } while (bus->nodes_modified);
1303
1304         if (!found_object)
1305                 return 0;
1306
1307         if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get") ||
1308             sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set"))
1309                 r = sd_bus_reply_method_errorf(
1310                                 m,
1311                                 SD_BUS_ERROR_UNKNOWN_PROPERTY,
1312                                 "Unknown property or interface.");
1313         else
1314                 r = sd_bus_reply_method_errorf(
1315                                 m,
1316                                 SD_BUS_ERROR_UNKNOWN_METHOD,
1317                                 "Unknown method '%s' or interface '%s'.", m->member, m->interface);
1318
1319         if (r < 0)
1320                 return r;
1321
1322         return 1;
1323 }
1324
1325 static struct node *bus_node_allocate(sd_bus *bus, const char *path) {
1326         struct node *n, *parent;
1327         const char *e;
1328         char *s, *p;
1329         int r;
1330
1331         assert(bus);
1332         assert(path);
1333         assert(path[0] == '/');
1334
1335         n = hashmap_get(bus->nodes, path);
1336         if (n)
1337                 return n;
1338
1339         r = hashmap_ensure_allocated(&bus->nodes, string_hash_func, string_compare_func);
1340         if (r < 0)
1341                 return NULL;
1342
1343         s = strdup(path);
1344         if (!s)
1345                 return NULL;
1346
1347         if (streq(path, "/"))
1348                 parent = NULL;
1349         else {
1350                 e = strrchr(path, '/');
1351                 assert(e);
1352
1353                 p = strndupa(path, MAX(1, path - e));
1354
1355                 parent = bus_node_allocate(bus, p);
1356                 if (!parent) {
1357                         free(s);
1358                         return NULL;
1359                 }
1360         }
1361
1362         n = new0(struct node, 1);
1363         if (!n)
1364                 return NULL;
1365
1366         n->parent = parent;
1367         n->path = s;
1368
1369         r = hashmap_put(bus->nodes, s, n);
1370         if (r < 0) {
1371                 free(s);
1372                 free(n);
1373                 return NULL;
1374         }
1375
1376         if (parent)
1377                 LIST_PREPEND(siblings, parent->child, n);
1378
1379         return n;
1380 }
1381
1382 static void bus_node_gc(sd_bus *b, struct node *n) {
1383         assert(b);
1384
1385         if (!n)
1386                 return;
1387
1388         if (n->child ||
1389             n->callbacks ||
1390             n->vtables ||
1391             n->enumerators ||
1392             n->object_manager)
1393                 return;
1394
1395         assert(hashmap_remove(b->nodes, n->path) == n);
1396
1397         if (n->parent)
1398                 LIST_REMOVE(siblings, n->parent->child, n);
1399
1400         free(n->path);
1401         bus_node_gc(b, n->parent);
1402         free(n);
1403 }
1404
1405 static int bus_add_object(
1406                 sd_bus *bus,
1407                 bool fallback,
1408                 const char *path,
1409                 sd_bus_message_handler_t callback,
1410                 void *userdata) {
1411
1412         struct node_callback *c;
1413         struct node *n;
1414         int r;
1415
1416         assert_return(bus, -EINVAL);
1417         assert_return(object_path_is_valid(path), -EINVAL);
1418         assert_return(callback, -EINVAL);
1419         assert_return(!bus_pid_changed(bus), -ECHILD);
1420
1421         n = bus_node_allocate(bus, path);
1422         if (!n)
1423                 return -ENOMEM;
1424
1425         c = new0(struct node_callback, 1);
1426         if (!c) {
1427                 r = -ENOMEM;
1428                 goto fail;
1429         }
1430
1431         c->node = n;
1432         c->callback = callback;
1433         c->userdata = userdata;
1434         c->is_fallback = fallback;
1435
1436         LIST_PREPEND(callbacks, n->callbacks, c);
1437         bus->nodes_modified = true;
1438
1439         return 0;
1440
1441 fail:
1442         free(c);
1443         bus_node_gc(bus, n);
1444         return r;
1445 }
1446
1447 static int bus_remove_object(
1448                 sd_bus *bus,
1449                 bool fallback,
1450                 const char *path,
1451                 sd_bus_message_handler_t callback,
1452                 void *userdata) {
1453
1454         struct node_callback *c;
1455         struct node *n;
1456
1457         assert_return(bus, -EINVAL);
1458         assert_return(object_path_is_valid(path), -EINVAL);
1459         assert_return(callback, -EINVAL);
1460         assert_return(!bus_pid_changed(bus), -ECHILD);
1461
1462         n = hashmap_get(bus->nodes, path);
1463         if (!n)
1464                 return 0;
1465
1466         LIST_FOREACH(callbacks, c, n->callbacks)
1467                 if (c->callback == callback && c->userdata == userdata && c->is_fallback == fallback)
1468                         break;
1469         if (!c)
1470                 return 0;
1471
1472         LIST_REMOVE(callbacks, n->callbacks, c);
1473         free(c);
1474
1475         bus_node_gc(bus, n);
1476         bus->nodes_modified = true;
1477
1478         return 1;
1479 }
1480
1481 _public_ int sd_bus_add_object(sd_bus *bus,
1482                                const char *path,
1483                                sd_bus_message_handler_t callback,
1484                                void *userdata) {
1485
1486         return bus_add_object(bus, false, path, callback, userdata);
1487 }
1488
1489 _public_ int sd_bus_remove_object(sd_bus *bus,
1490                                   const char *path,
1491                                   sd_bus_message_handler_t callback,
1492                                   void *userdata) {
1493
1494         return bus_remove_object(bus, false, path, callback, userdata);
1495 }
1496
1497 _public_ int sd_bus_add_fallback(sd_bus *bus,
1498                                  const char *prefix,
1499                                  sd_bus_message_handler_t callback,
1500                                  void *userdata) {
1501
1502         return bus_add_object(bus, true, prefix, callback, userdata);
1503 }
1504
1505 _public_ int sd_bus_remove_fallback(sd_bus *bus,
1506                                     const char *prefix,
1507                                     sd_bus_message_handler_t callback,
1508                                     void *userdata) {
1509
1510         return bus_remove_object(bus, true, prefix, callback, userdata);
1511 }
1512
1513 static void free_node_vtable(sd_bus *bus, struct node_vtable *w) {
1514         assert(bus);
1515
1516         if (!w)
1517                 return;
1518
1519         if (w->interface && w->node && w->vtable) {
1520                 const sd_bus_vtable *v;
1521
1522                 for (v = w->vtable; v->type != _SD_BUS_VTABLE_END; v++) {
1523                         struct vtable_member *x = NULL;
1524
1525                         switch (v->type) {
1526
1527                         case _SD_BUS_VTABLE_METHOD: {
1528                                 struct vtable_member key;
1529
1530                                 key.path = w->node->path;
1531                                 key.interface = w->interface;
1532                                 key.member = v->x.method.member;
1533
1534                                 x = hashmap_remove(bus->vtable_methods, &key);
1535                                 break;
1536                         }
1537
1538                         case _SD_BUS_VTABLE_PROPERTY:
1539                         case _SD_BUS_VTABLE_WRITABLE_PROPERTY: {
1540                                 struct vtable_member key;
1541
1542                                 key.path = w->node->path;
1543                                 key.interface = w->interface;
1544                                 key.member = v->x.property.member;
1545                                 x = hashmap_remove(bus->vtable_properties, &key);
1546                                 break;
1547                         }}
1548
1549                         free(x);
1550                 }
1551         }
1552
1553         free(w->interface);
1554         free(w);
1555 }
1556
1557 static unsigned vtable_member_hash_func(const void *a) {
1558         const struct vtable_member *m = a;
1559
1560         assert(m);
1561
1562         return
1563                 string_hash_func(m->path) ^
1564                 string_hash_func(m->interface) ^
1565                 string_hash_func(m->member);
1566 }
1567
1568 static int vtable_member_compare_func(const void *a, const void *b) {
1569         const struct vtable_member *x = a, *y = b;
1570         int r;
1571
1572         assert(x);
1573         assert(y);
1574
1575         r = strcmp(x->path, y->path);
1576         if (r != 0)
1577                 return r;
1578
1579         r = strcmp(x->interface, y->interface);
1580         if (r != 0)
1581                 return r;
1582
1583         return strcmp(x->member, y->member);
1584 }
1585
1586 static int add_object_vtable_internal(
1587                 sd_bus *bus,
1588                 const char *path,
1589                 const char *interface,
1590                 const sd_bus_vtable *vtable,
1591                 bool fallback,
1592                 sd_bus_object_find_t find,
1593                 void *userdata) {
1594
1595         struct node_vtable *c = NULL, *i, *existing = NULL;
1596         const sd_bus_vtable *v;
1597         struct node *n;
1598         int r;
1599
1600         assert_return(bus, -EINVAL);
1601         assert_return(object_path_is_valid(path), -EINVAL);
1602         assert_return(interface_name_is_valid(interface), -EINVAL);
1603         assert_return(vtable, -EINVAL);
1604         assert_return(vtable[0].type == _SD_BUS_VTABLE_START, -EINVAL);
1605         assert_return(vtable[0].x.start.element_size == sizeof(struct sd_bus_vtable), -EINVAL);
1606         assert_return(!bus_pid_changed(bus), -ECHILD);
1607         assert_return(!streq(interface, "org.freedesktop.DBus.Properties") &&
1608                       !streq(interface, "org.freedesktop.DBus.Introspectable") &&
1609                       !streq(interface, "org.freedesktop.DBus.Peer") &&
1610                       !streq(interface, "org.freedesktop.DBus.ObjectManager"), -EINVAL);
1611
1612         r = hashmap_ensure_allocated(&bus->vtable_methods, vtable_member_hash_func, vtable_member_compare_func);
1613         if (r < 0)
1614                 return r;
1615
1616         r = hashmap_ensure_allocated(&bus->vtable_properties, vtable_member_hash_func, vtable_member_compare_func);
1617         if (r < 0)
1618                 return r;
1619
1620         n = bus_node_allocate(bus, path);
1621         if (!n)
1622                 return -ENOMEM;
1623
1624         LIST_FOREACH(vtables, i, n->vtables) {
1625                 if (i->is_fallback != fallback) {
1626                         r = -EPROTOTYPE;
1627                         goto fail;
1628                 }
1629
1630                 if (streq(i->interface, interface)) {
1631
1632                         if (i->vtable == vtable) {
1633                                 r = -EEXIST;
1634                                 goto fail;
1635                         }
1636
1637                         existing = i;
1638                 }
1639         }
1640
1641         c = new0(struct node_vtable, 1);
1642         if (!c) {
1643                 r = -ENOMEM;
1644                 goto fail;
1645         }
1646
1647         c->node = n;
1648         c->is_fallback = fallback;
1649         c->vtable = vtable;
1650         c->userdata = userdata;
1651         c->find = find;
1652
1653         c->interface = strdup(interface);
1654         if (!c->interface) {
1655                 r = -ENOMEM;
1656                 goto fail;
1657         }
1658
1659         for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
1660
1661                 switch (v->type) {
1662
1663                 case _SD_BUS_VTABLE_METHOD: {
1664                         struct vtable_member *m;
1665
1666                         if (!member_name_is_valid(v->x.method.member) ||
1667                             !signature_is_valid(strempty(v->x.method.signature), false) ||
1668                             !signature_is_valid(strempty(v->x.method.result), false) ||
1669                             !(v->x.method.handler || (isempty(v->x.method.signature) && isempty(v->x.method.result))) ||
1670                             v->flags & (SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY)) {
1671                                 r = -EINVAL;
1672                                 goto fail;
1673                         }
1674
1675                         m = new0(struct vtable_member, 1);
1676                         if (!m) {
1677                                 r = -ENOMEM;
1678                                 goto fail;
1679                         }
1680
1681                         m->parent = c;
1682                         m->path = n->path;
1683                         m->interface = c->interface;
1684                         m->member = v->x.method.member;
1685                         m->vtable = v;
1686
1687                         r = hashmap_put(bus->vtable_methods, m, m);
1688                         if (r < 0) {
1689                                 free(m);
1690                                 goto fail;
1691                         }
1692
1693                         break;
1694                 }
1695
1696                 case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
1697
1698                         if (!(v->x.property.set || bus_type_is_basic(v->x.property.signature[0]))) {
1699                                 r = -EINVAL;
1700                                 goto fail;
1701                         }
1702
1703                         /* Fall through */
1704
1705                 case _SD_BUS_VTABLE_PROPERTY: {
1706                         struct vtable_member *m;
1707
1708                         if (!member_name_is_valid(v->x.property.member) ||
1709                             !signature_is_single(v->x.property.signature, false) ||
1710                             !(v->x.property.get || bus_type_is_basic(v->x.property.signature[0]) || streq(v->x.property.signature, "as")) ||
1711                             v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY ||
1712                             (v->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY && !(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE)) ||
1713                             (v->flags & SD_BUS_VTABLE_UNPRIVILEGED && v->type == _SD_BUS_VTABLE_PROPERTY)) {
1714                                 r = -EINVAL;
1715                                 goto fail;
1716                         }
1717
1718
1719                         m = new0(struct vtable_member, 1);
1720                         if (!m) {
1721                                 r = -ENOMEM;
1722                                 goto fail;
1723                         }
1724
1725                         m->parent = c;
1726                         m->path = n->path;
1727                         m->interface = c->interface;
1728                         m->member = v->x.property.member;
1729                         m->vtable = v;
1730
1731                         r = hashmap_put(bus->vtable_properties, m, m);
1732                         if (r < 0) {
1733                                 free(m);
1734                                 goto fail;
1735                         }
1736
1737                         break;
1738                 }
1739
1740                 case _SD_BUS_VTABLE_SIGNAL:
1741
1742                         if (!member_name_is_valid(v->x.signal.member) ||
1743                             !signature_is_valid(strempty(v->x.signal.signature), false) ||
1744                             v->flags & SD_BUS_VTABLE_UNPRIVILEGED) {
1745                                 r = -EINVAL;
1746                                 goto fail;
1747                         }
1748
1749                         break;
1750
1751                 default:
1752                         r = -EINVAL;
1753                         goto fail;
1754                 }
1755         }
1756
1757         LIST_INSERT_AFTER(vtables, n->vtables, existing, c);
1758         bus->nodes_modified = true;
1759
1760         return 0;
1761
1762 fail:
1763         if (c)
1764                 free_node_vtable(bus, c);
1765
1766         bus_node_gc(bus, n);
1767         return r;
1768 }
1769
1770 static int remove_object_vtable_internal(
1771                 sd_bus *bus,
1772                 const char *path,
1773                 const char *interface,
1774                 const sd_bus_vtable *vtable,
1775                 bool fallback,
1776                 sd_bus_object_find_t find,
1777                 void *userdata) {
1778
1779         struct node_vtable *c;
1780         struct node *n;
1781
1782         assert_return(bus, -EINVAL);
1783         assert_return(object_path_is_valid(path), -EINVAL);
1784         assert_return(interface_name_is_valid(interface), -EINVAL);
1785         assert_return(!bus_pid_changed(bus), -ECHILD);
1786
1787         n = hashmap_get(bus->nodes, path);
1788         if (!n)
1789                 return 0;
1790
1791         LIST_FOREACH(vtables, c, n->vtables)
1792                 if (streq(c->interface, interface) &&
1793                     c->is_fallback == fallback &&
1794                     c->vtable == vtable &&
1795                     c->find == find &&
1796                     c->userdata == userdata)
1797                         break;
1798
1799         if (!c)
1800                 return 0;
1801
1802         LIST_REMOVE(vtables, n->vtables, c);
1803
1804         free_node_vtable(bus, c);
1805         bus_node_gc(bus, n);
1806
1807         bus->nodes_modified = true;
1808
1809         return 1;
1810 }
1811
1812 _public_ int sd_bus_add_object_vtable(
1813                 sd_bus *bus,
1814                 const char *path,
1815                 const char *interface,
1816                 const sd_bus_vtable *vtable,
1817                 void *userdata) {
1818
1819         return add_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata);
1820 }
1821
1822 _public_ int sd_bus_remove_object_vtable(
1823                 sd_bus *bus,
1824                 const char *path,
1825                 const char *interface,
1826                 const sd_bus_vtable *vtable,
1827                 void *userdata) {
1828
1829         return remove_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata);
1830 }
1831
1832 _public_ int sd_bus_add_fallback_vtable(
1833                 sd_bus *bus,
1834                 const char *path,
1835                 const char *interface,
1836                 const sd_bus_vtable *vtable,
1837                 sd_bus_object_find_t find,
1838                 void *userdata) {
1839
1840         return add_object_vtable_internal(bus, path, interface, vtable, true, find, userdata);
1841 }
1842
1843 _public_ int sd_bus_remove_fallback_vtable(
1844                 sd_bus *bus,
1845                 const char *path,
1846                 const char *interface,
1847                 const sd_bus_vtable *vtable,
1848                 sd_bus_object_find_t find,
1849                 void *userdata) {
1850
1851         return remove_object_vtable_internal(bus, path, interface, vtable, true, find, userdata);
1852 }
1853
1854 _public_ int sd_bus_add_node_enumerator(
1855                 sd_bus *bus,
1856                 const char *path,
1857                 sd_bus_node_enumerator_t callback,
1858                 void *userdata) {
1859
1860         struct node_enumerator *c;
1861         struct node *n;
1862         int r;
1863
1864         assert_return(bus, -EINVAL);
1865         assert_return(object_path_is_valid(path), -EINVAL);
1866         assert_return(callback, -EINVAL);
1867         assert_return(!bus_pid_changed(bus), -ECHILD);
1868
1869         n = bus_node_allocate(bus, path);
1870         if (!n)
1871                 return -ENOMEM;
1872
1873         c = new0(struct node_enumerator, 1);
1874         if (!c) {
1875                 r = -ENOMEM;
1876                 goto fail;
1877         }
1878
1879         c->node = n;
1880         c->callback = callback;
1881         c->userdata = userdata;
1882
1883         LIST_PREPEND(enumerators, n->enumerators, c);
1884
1885         bus->nodes_modified = true;
1886
1887         return 0;
1888
1889 fail:
1890         free(c);
1891         bus_node_gc(bus, n);
1892         return r;
1893 }
1894
1895 _public_ int sd_bus_remove_node_enumerator(
1896                 sd_bus *bus,
1897                 const char *path,
1898                 sd_bus_node_enumerator_t callback,
1899                 void *userdata) {
1900
1901         struct node_enumerator *c;
1902         struct node *n;
1903
1904         assert_return(bus, -EINVAL);
1905         assert_return(object_path_is_valid(path), -EINVAL);
1906         assert_return(callback, -EINVAL);
1907         assert_return(!bus_pid_changed(bus), -ECHILD);
1908
1909         n = hashmap_get(bus->nodes, path);
1910         if (!n)
1911                 return 0;
1912
1913         LIST_FOREACH(enumerators, c, n->enumerators)
1914                 if (c->callback == callback && c->userdata == userdata)
1915                         break;
1916
1917         if (!c)
1918                 return 0;
1919
1920         LIST_REMOVE(enumerators, n->enumerators, c);
1921         free(c);
1922
1923         bus_node_gc(bus, n);
1924
1925         bus->nodes_modified = true;
1926
1927         return 1;
1928 }
1929
1930 static int emit_properties_changed_on_interface(
1931                 sd_bus *bus,
1932                 const char *prefix,
1933                 const char *path,
1934                 const char *interface,
1935                 bool require_fallback,
1936                 char **names) {
1937
1938         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1939         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1940         bool has_invalidating = false, has_changing = false;
1941         struct vtable_member key = {};
1942         struct node_vtable *c;
1943         struct node *n;
1944         char **property;
1945         void *u = NULL;
1946         int r;
1947
1948         assert(bus);
1949         assert(prefix);
1950         assert(path);
1951         assert(interface);
1952
1953         n = hashmap_get(bus->nodes, prefix);
1954         if (!n)
1955                 return 0;
1956
1957         r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.Properties", "PropertiesChanged", &m);
1958         if (r < 0)
1959                 return r;
1960
1961         r = sd_bus_message_append(m, "s", interface);
1962         if (r < 0)
1963                 return r;
1964
1965         r = sd_bus_message_open_container(m, 'a', "{sv}");
1966         if (r < 0)
1967                 return r;
1968
1969         key.path = prefix;
1970         key.interface = interface;
1971
1972         LIST_FOREACH(vtables, c, n->vtables) {
1973                 if (require_fallback && !c->is_fallback)
1974                         continue;
1975
1976                 if (!streq(c->interface, interface))
1977                         continue;
1978
1979                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
1980                 if (r < 0)
1981                         return r;
1982                 if (bus->nodes_modified)
1983                         return 0;
1984                 if (r == 0)
1985                         continue;
1986
1987                 STRV_FOREACH(property, names) {
1988                         struct vtable_member *v;
1989
1990                         assert_return(member_name_is_valid(*property), -EINVAL);
1991
1992                         key.member = *property;
1993                         v = hashmap_get(bus->vtable_properties, &key);
1994                         if (!v)
1995                                 return -ENOENT;
1996
1997                         /* If there are two vtables for the same
1998                          * interface, let's handle this property when
1999                          * we come to that vtable. */
2000                         if (c != v->parent)
2001                                 continue;
2002
2003                         assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE, -EDOM);
2004
2005                         if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY) {
2006                                 has_invalidating = true;
2007                                 continue;
2008                         }
2009
2010                         has_changing = true;
2011
2012                         r = sd_bus_message_open_container(m, 'e', "sv");
2013                         if (r < 0)
2014                                 return r;
2015
2016                         r = sd_bus_message_append(m, "s", *property);
2017                         if (r < 0)
2018                                 return r;
2019
2020                         r = sd_bus_message_open_container(m, 'v', v->vtable->x.property.signature);
2021                         if (r < 0)
2022                                 return r;
2023
2024                         r = invoke_property_get(bus, v->vtable, m->path, interface, *property, m, vtable_property_convert_userdata(v->vtable, u), &error);
2025                         if (r < 0)
2026                                 return r;
2027                         if (bus->nodes_modified)
2028                                 return 0;
2029
2030                         r = sd_bus_message_close_container(m);
2031                         if (r < 0)
2032                                 return r;
2033
2034                         r = sd_bus_message_close_container(m);
2035                         if (r < 0)
2036                                 return r;
2037                 }
2038         }
2039
2040         if (!has_invalidating && !has_changing)
2041                 return 0;
2042
2043         r = sd_bus_message_close_container(m);
2044         if (r < 0)
2045                 return r;
2046
2047         r = sd_bus_message_open_container(m, 'a', "s");
2048         if (r < 0)
2049                 return r;
2050
2051         if (has_invalidating) {
2052                 LIST_FOREACH(vtables, c, n->vtables) {
2053                         if (require_fallback && !c->is_fallback)
2054                                 continue;
2055
2056                         if (!streq(c->interface, interface))
2057                                 continue;
2058
2059                         r = node_vtable_get_userdata(bus, path, c, &u, &error);
2060                         if (r < 0)
2061                                 return r;
2062                         if (bus->nodes_modified)
2063                                 return 0;
2064                         if (r == 0)
2065                                 continue;
2066
2067                         STRV_FOREACH(property, names) {
2068                                 struct vtable_member *v;
2069
2070                                 key.member = *property;
2071                                 assert_se(v = hashmap_get(bus->vtable_properties, &key));
2072                                 assert(c == v->parent);
2073
2074                                 if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY))
2075                                         continue;
2076
2077                                 r = sd_bus_message_append(m, "s", *property);
2078                                 if (r < 0)
2079                                         return r;
2080                         }
2081                 }
2082         }
2083
2084         r = sd_bus_message_close_container(m);
2085         if (r < 0)
2086                 return r;
2087
2088         r = sd_bus_send(bus, m, NULL);
2089         if (r < 0)
2090                 return r;
2091
2092         return 1;
2093 }
2094
2095 _public_ int sd_bus_emit_properties_changed_strv(
2096                 sd_bus *bus,
2097                 const char *path,
2098                 const char *interface,
2099                 char **names) {
2100
2101         BUS_DONT_DESTROY(bus);
2102         char *prefix;
2103         int r;
2104
2105         assert_return(bus, -EINVAL);
2106         assert_return(object_path_is_valid(path), -EINVAL);
2107         assert_return(interface_name_is_valid(interface), -EINVAL);
2108         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2109         assert_return(!bus_pid_changed(bus), -ECHILD);
2110
2111         if (strv_isempty(names))
2112                 return 0;
2113
2114         do {
2115                 bus->nodes_modified = false;
2116
2117                 r = emit_properties_changed_on_interface(bus, path, path, interface, false, names);
2118                 if (r != 0)
2119                         return r;
2120                 if (bus->nodes_modified)
2121                         continue;
2122
2123                 prefix = alloca(strlen(path) + 1);
2124                 OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2125                         r = emit_properties_changed_on_interface(bus, prefix, path, interface, true, names);
2126                         if (r != 0)
2127                                 return r;
2128                         if (bus->nodes_modified)
2129                                 break;
2130                 }
2131
2132         } while (bus->nodes_modified);
2133
2134         return -ENOENT;
2135 }
2136
2137 _public_ int sd_bus_emit_properties_changed(
2138                 sd_bus *bus,
2139                 const char *path,
2140                 const char *interface,
2141                 const char *name, ...)  {
2142
2143         char **names;
2144
2145         assert_return(bus, -EINVAL);
2146         assert_return(object_path_is_valid(path), -EINVAL);
2147         assert_return(interface_name_is_valid(interface), -EINVAL);
2148         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2149         assert_return(!bus_pid_changed(bus), -ECHILD);
2150
2151         if (!name)
2152                 return 0;
2153
2154         names = strv_from_stdarg_alloca(name);
2155
2156         return sd_bus_emit_properties_changed_strv(bus, path, interface, names);
2157 }
2158
2159 static int interfaces_added_append_one_prefix(
2160                 sd_bus *bus,
2161                 sd_bus_message *m,
2162                 const char *prefix,
2163                 const char *path,
2164                 const char *interface,
2165                 bool require_fallback) {
2166
2167         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2168         bool found_interface = false;
2169         struct node_vtable *c;
2170         struct node *n;
2171         void *u = NULL;
2172         int r;
2173
2174         assert(bus);
2175         assert(m);
2176         assert(prefix);
2177         assert(path);
2178         assert(interface);
2179
2180         n = hashmap_get(bus->nodes, prefix);
2181         if (!n)
2182                 return 0;
2183
2184         LIST_FOREACH(vtables, c, n->vtables) {
2185                 if (require_fallback && !c->is_fallback)
2186                         continue;
2187
2188                 if (!streq(c->interface, interface))
2189                         continue;
2190
2191                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
2192                 if (r < 0)
2193                         return r;
2194                 if (bus->nodes_modified)
2195                         return 0;
2196                 if (r == 0)
2197                         continue;
2198
2199                 if (!found_interface) {
2200                         r = sd_bus_message_append_basic(m, 's', interface);
2201                         if (r < 0)
2202                                 return r;
2203
2204                         r = sd_bus_message_open_container(m, 'a', "{sv}");
2205                         if (r < 0)
2206                                 return r;
2207
2208                         found_interface = true;
2209                 }
2210
2211                 r = vtable_append_all_properties(bus, m, path, c, u, &error);
2212                 if (r < 0)
2213                         return r;
2214                 if (bus->nodes_modified)
2215                         return 0;
2216         }
2217
2218         if (found_interface) {
2219                 r = sd_bus_message_close_container(m);
2220                 if (r < 0)
2221                         return r;
2222         }
2223
2224         return found_interface;
2225 }
2226
2227 static int interfaces_added_append_one(
2228                 sd_bus *bus,
2229                 sd_bus_message *m,
2230                 const char *path,
2231                 const char *interface) {
2232
2233         char *prefix;
2234         int r;
2235
2236         assert(bus);
2237         assert(m);
2238         assert(path);
2239         assert(interface);
2240
2241         r = interfaces_added_append_one_prefix(bus, m, path, path, interface, false);
2242         if (r != 0)
2243                 return r;
2244         if (bus->nodes_modified)
2245                 return 0;
2246
2247         prefix = alloca(strlen(path) + 1);
2248         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2249                 r = interfaces_added_append_one_prefix(bus, m, prefix, path, interface, true);
2250                 if (r != 0)
2251                         return r;
2252                 if (bus->nodes_modified)
2253                         return 0;
2254         }
2255
2256         return -ENOENT;
2257 }
2258
2259 _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) {
2260         BUS_DONT_DESTROY(bus);
2261
2262         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2263         char **i;
2264         int r;
2265
2266         assert_return(bus, -EINVAL);
2267         assert_return(object_path_is_valid(path), -EINVAL);
2268         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2269         assert_return(!bus_pid_changed(bus), -ECHILD);
2270
2271         if (strv_isempty(interfaces))
2272                 return 0;
2273
2274         do {
2275                 bus->nodes_modified = false;
2276
2277                 if (m)
2278                         m = sd_bus_message_unref(m);
2279
2280                 r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded", &m);
2281                 if (r < 0)
2282                         return r;
2283
2284                 r = sd_bus_message_append_basic(m, 'o', path);
2285                 if (r < 0)
2286                         return r;
2287
2288                 r = sd_bus_message_open_container(m, 'a', "{sa{sv}}");
2289                 if (r < 0)
2290                         return r;
2291
2292                 STRV_FOREACH(i, interfaces) {
2293                         assert_return(interface_name_is_valid(*i), -EINVAL);
2294
2295                         r = sd_bus_message_open_container(m, 'e', "sa{sv}");
2296                         if (r < 0)
2297                                 return r;
2298
2299                         r = interfaces_added_append_one(bus, m, path, *i);
2300                         if (r < 0)
2301                                 return r;
2302
2303                         if (bus->nodes_modified)
2304                                 break;
2305
2306                         r = sd_bus_message_close_container(m);
2307                         if (r < 0)
2308                                 return r;
2309                 }
2310
2311                 if (bus->nodes_modified)
2312                         continue;
2313
2314                 r = sd_bus_message_close_container(m);
2315                 if (r < 0)
2316                         return r;
2317
2318         } while (bus->nodes_modified);
2319
2320         return sd_bus_send(bus, m, NULL);
2321 }
2322
2323 _public_ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...) {
2324         char **interfaces;
2325
2326         assert_return(bus, -EINVAL);
2327         assert_return(object_path_is_valid(path), -EINVAL);
2328         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2329         assert_return(!bus_pid_changed(bus), -ECHILD);
2330
2331         interfaces = strv_from_stdarg_alloca(interface);
2332
2333         return sd_bus_emit_interfaces_added_strv(bus, path, interfaces);
2334 }
2335
2336 _public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) {
2337         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2338         int r;
2339
2340         assert_return(bus, -EINVAL);
2341         assert_return(object_path_is_valid(path), -EINVAL);
2342         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2343         assert_return(!bus_pid_changed(bus), -ECHILD);
2344
2345         if (strv_isempty(interfaces))
2346                 return 0;
2347
2348         r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved", &m);
2349         if (r < 0)
2350                 return r;
2351
2352         r = sd_bus_message_append_basic(m, 'o', path);
2353         if (r < 0)
2354                 return r;
2355
2356         r = sd_bus_message_append_strv(m, interfaces);
2357         if (r < 0)
2358                 return r;
2359
2360         return sd_bus_send(bus, m, NULL);
2361 }
2362
2363 _public_ int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) {
2364         char **interfaces;
2365
2366         assert_return(bus, -EINVAL);
2367         assert_return(object_path_is_valid(path), -EINVAL);
2368         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2369         assert_return(!bus_pid_changed(bus), -ECHILD);
2370
2371         interfaces = strv_from_stdarg_alloca(interface);
2372
2373         return sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
2374 }
2375
2376 _public_ int sd_bus_add_object_manager(sd_bus *bus, const char *path) {
2377         struct node *n;
2378
2379         assert_return(bus, -EINVAL);
2380         assert_return(object_path_is_valid(path), -EINVAL);
2381         assert_return(!bus_pid_changed(bus), -ECHILD);
2382
2383         n = bus_node_allocate(bus, path);
2384         if (!n)
2385                 return -ENOMEM;
2386
2387         n->object_manager = true;
2388         bus->nodes_modified = true;
2389         return 0;
2390 }
2391
2392 _public_ int sd_bus_remove_object_manager(sd_bus *bus, const char *path) {
2393         struct node *n;
2394
2395         assert_return(bus, -EINVAL);
2396         assert_return(object_path_is_valid(path), -EINVAL);
2397         assert_return(!bus_pid_changed(bus), -ECHILD);
2398
2399         n = hashmap_get(bus->nodes, path);
2400         if (!n)
2401                 return 0;
2402
2403         if (!n->object_manager)
2404                 return 0;
2405
2406         n->object_manager = false;
2407         bus->nodes_modified = true;
2408         bus_node_gc(bus, n);
2409
2410         return 1;
2411 }