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