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