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