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