]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-match.c
Merge pull request #1542 from keszybz/journal-audit-optional
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-match.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 "bus-internal.h"
23 #include "bus-message.h"
24 #include "bus-match.h"
25 #include "bus-util.h"
26 #include "strv.h"
27
28 /* Example:
29 *
30 * A: type=signal,sender=foo,interface=bar
31 * B: type=signal,sender=quux,interface=fips
32 * C: type=signal,sender=quux,interface=waldo
33 * D: type=signal,member=test
34 * E: sender=miau
35 * F: type=signal
36 * G: type=signal
37 *
38 * results in this tree:
39 *
40 * BUS_MATCH_ROOT
41 * + BUS_MATCH_MESSAGE_TYPE
42 * | ` BUS_MATCH_VALUE: value == signal
43 * | + DBUS_MATCH_SENDER
44 * | | + BUS_MATCH_VALUE: value == foo
45 * | | | ` DBUS_MATCH_INTERFACE
46 * | | | ` BUS_MATCH_VALUE: value == bar
47 * | | | ` BUS_MATCH_LEAF: A
48 * | | ` BUS_MATCH_VALUE: value == quux
49 * | | ` DBUS_MATCH_INTERFACE
50 * | | | BUS_MATCH_VALUE: value == fips
51 * | | | ` BUS_MATCH_LEAF: B
52 * | | ` BUS_MATCH_VALUE: value == waldo
53 * | | ` BUS_MATCH_LEAF: C
54 * | + DBUS_MATCH_MEMBER
55 * | | ` BUS_MATCH_VALUE: value == test
56 * | | ` BUS_MATCH_LEAF: D
57 * | + BUS_MATCH_LEAF: F
58 * | ` BUS_MATCH_LEAF: G
59 * ` BUS_MATCH_SENDER
60 * ` BUS_MATCH_VALUE: value == miau
61 * ` BUS_MATCH_LEAF: E
62 */
63
64 static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) {
65 return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_HAS_LAST;
66 }
67
68 static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) {
69 return (t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_PATH) ||
70 (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST) ||
71 (t >= BUS_MATCH_ARG_HAS && t <= BUS_MATCH_ARG_HAS_LAST);
72 }
73
74 static void bus_match_node_free(struct bus_match_node *node) {
75 assert(node);
76 assert(node->parent);
77 assert(!node->child);
78 assert(node->type != BUS_MATCH_ROOT);
79 assert(node->type < _BUS_MATCH_NODE_TYPE_MAX);
80
81 if (node->parent->child) {
82 /* We are apparently linked into the parent's child
83 * list. Let's remove us from there. */
84 if (node->prev) {
85 assert(node->prev->next == node);
86 node->prev->next = node->next;
87 } else {
88 assert(node->parent->child == node);
89 node->parent->child = node->next;
90 }
91
92 if (node->next)
93 node->next->prev = node->prev;
94 }
95
96 if (node->type == BUS_MATCH_VALUE) {
97 /* We might be in the parent's hash table, so clean
98 * this up */
99
100 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
101 hashmap_remove(node->parent->compare.children, UINT_TO_PTR(node->value.u8));
102 else if (BUS_MATCH_CAN_HASH(node->parent->type) && node->value.str)
103 hashmap_remove(node->parent->compare.children, node->value.str);
104
105 free(node->value.str);
106 }
107
108 if (BUS_MATCH_IS_COMPARE(node->type)) {
109 assert(hashmap_isempty(node->compare.children));
110 hashmap_free(node->compare.children);
111 }
112
113 free(node);
114 }
115
116 static bool bus_match_node_maybe_free(struct bus_match_node *node) {
117 assert(node);
118
119 if (node->type == BUS_MATCH_ROOT)
120 return false;
121
122 if (node->child)
123 return false;
124
125 if (BUS_MATCH_IS_COMPARE(node->type) && !hashmap_isempty(node->compare.children))
126 return true;
127
128 bus_match_node_free(node);
129 return true;
130 }
131
132 static bool value_node_test(
133 struct bus_match_node *node,
134 enum bus_match_node_type parent_type,
135 uint8_t value_u8,
136 const char *value_str,
137 char **value_strv,
138 sd_bus_message *m) {
139
140 assert(node);
141 assert(node->type == BUS_MATCH_VALUE);
142
143 /* Tests parameters against this value node, doing prefix
144 * magic and stuff. */
145
146 switch (parent_type) {
147
148 case BUS_MATCH_MESSAGE_TYPE:
149 return node->value.u8 == value_u8;
150
151 case BUS_MATCH_SENDER:
152 if (streq_ptr(node->value.str, value_str))
153 return true;
154
155 if (m->creds.mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
156 char **i;
157
158 /* on kdbus we have the well known names list
159 * in the credentials, let's make use of that
160 * for an accurate match */
161
162 STRV_FOREACH(i, m->creds.well_known_names)
163 if (streq_ptr(node->value.str, *i))
164 return true;
165
166 } else {
167
168 /* If we don't have kdbus, we don't know the
169 * well-known names of the senders. In that,
170 * let's just hope that dbus-daemon doesn't
171 * send us stuff we didn't want. */
172
173 if (node->value.str[0] != ':' && value_str && value_str[0] == ':')
174 return true;
175 }
176
177 return false;
178
179 case BUS_MATCH_DESTINATION:
180 case BUS_MATCH_INTERFACE:
181 case BUS_MATCH_MEMBER:
182 case BUS_MATCH_PATH:
183 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
184
185 if (value_str)
186 return streq_ptr(node->value.str, value_str);
187
188 return false;
189
190 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST: {
191 char **i;
192
193 STRV_FOREACH(i, value_strv)
194 if (streq_ptr(node->value.str, *i))
195 return true;
196
197 return false;
198 }
199
200 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
201 if (value_str)
202 return namespace_simple_pattern(node->value.str, value_str);
203
204 return false;
205
206 case BUS_MATCH_PATH_NAMESPACE:
207 return path_simple_pattern(node->value.str, value_str);
208
209 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
210 if (value_str)
211 return path_complex_pattern(node->value.str, value_str);
212
213 return false;
214
215 default:
216 assert_not_reached("Invalid node type");
217 }
218 }
219
220 static bool value_node_same(
221 struct bus_match_node *node,
222 enum bus_match_node_type parent_type,
223 uint8_t value_u8,
224 const char *value_str) {
225
226 /* Tests parameters against this value node, not doing prefix
227 * magic and stuff, i.e. this one actually compares the match
228 * itself. */
229
230 assert(node);
231 assert(node->type == BUS_MATCH_VALUE);
232
233 switch (parent_type) {
234
235 case BUS_MATCH_MESSAGE_TYPE:
236 return node->value.u8 == value_u8;
237
238 case BUS_MATCH_SENDER:
239 case BUS_MATCH_DESTINATION:
240 case BUS_MATCH_INTERFACE:
241 case BUS_MATCH_MEMBER:
242 case BUS_MATCH_PATH:
243 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
244 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
245 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
246 case BUS_MATCH_PATH_NAMESPACE:
247 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
248 return streq(node->value.str, value_str);
249
250 default:
251 assert_not_reached("Invalid node type");
252 }
253 }
254
255 int bus_match_run(
256 sd_bus *bus,
257 struct bus_match_node *node,
258 sd_bus_message *m) {
259
260 _cleanup_strv_free_ char **test_strv = NULL;
261 const char *test_str = NULL;
262 uint8_t test_u8 = 0;
263 int r;
264
265 assert(m);
266
267 if (!node)
268 return 0;
269
270 if (bus && bus->match_callbacks_modified)
271 return 0;
272
273 /* Not these special semantics: when traversing the tree we
274 * usually let bus_match_run() when called for a node
275 * recursively invoke bus_match_run(). There's are two
276 * exceptions here though, which are BUS_NODE_ROOT (which
277 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
278 * are invoked anyway by its parent. */
279
280 switch (node->type) {
281
282 case BUS_MATCH_ROOT:
283
284 /* Run all children. Since we cannot have any siblings
285 * we won't call any. The children of the root node
286 * are compares or leaves, they will automatically
287 * call their siblings. */
288 return bus_match_run(bus, node->child, m);
289
290 case BUS_MATCH_VALUE:
291
292 /* Run all children. We don't execute any siblings, we
293 * assume our caller does that. The children of value
294 * nodes are compares or leaves, they will
295 * automatically call their siblings */
296
297 assert(node->child);
298 return bus_match_run(bus, node->child, m);
299
300 case BUS_MATCH_LEAF:
301
302 if (bus) {
303 if (node->leaf.callback->last_iteration == bus->iteration_counter)
304 return 0;
305
306 node->leaf.callback->last_iteration = bus->iteration_counter;
307 }
308
309 r = sd_bus_message_rewind(m, true);
310 if (r < 0)
311 return r;
312
313 /* Run the callback. And then invoke siblings. */
314 if (node->leaf.callback->callback) {
315 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
316 sd_bus_slot *slot;
317
318 slot = container_of(node->leaf.callback, sd_bus_slot, match_callback);
319 if (bus) {
320 bus->current_slot = sd_bus_slot_ref(slot);
321 bus->current_handler = node->leaf.callback->callback;
322 bus->current_userdata = slot->userdata;
323 }
324 r = node->leaf.callback->callback(m, slot->userdata, &error_buffer);
325 if (bus) {
326 bus->current_userdata = NULL;
327 bus->current_handler = NULL;
328 bus->current_slot = sd_bus_slot_unref(slot);
329 }
330
331 r = bus_maybe_reply_error(m, r, &error_buffer);
332 if (r != 0)
333 return r;
334
335 if (bus && bus->match_callbacks_modified)
336 return 0;
337 }
338
339 return bus_match_run(bus, node->next, m);
340
341 case BUS_MATCH_MESSAGE_TYPE:
342 test_u8 = m->header->type;
343 break;
344
345 case BUS_MATCH_SENDER:
346 test_str = m->sender;
347 /* FIXME: resolve test_str from a well-known to a unique name first */
348 break;
349
350 case BUS_MATCH_DESTINATION:
351 test_str = m->destination;
352 break;
353
354 case BUS_MATCH_INTERFACE:
355 test_str = m->interface;
356 break;
357
358 case BUS_MATCH_MEMBER:
359 test_str = m->member;
360 break;
361
362 case BUS_MATCH_PATH:
363 case BUS_MATCH_PATH_NAMESPACE:
364 test_str = m->path;
365 break;
366
367 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
368 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str);
369 break;
370
371 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
372 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str);
373 break;
374
375 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
376 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str);
377 break;
378
379 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
380 (void) bus_message_get_arg_strv(m, node->type - BUS_MATCH_ARG_HAS, &test_strv);
381 break;
382
383 default:
384 assert_not_reached("Unknown match type.");
385 }
386
387 if (BUS_MATCH_CAN_HASH(node->type)) {
388 struct bus_match_node *found;
389
390 /* Lookup via hash table, nice! So let's jump directly. */
391
392 if (test_str)
393 found = hashmap_get(node->compare.children, test_str);
394 else if (test_strv) {
395 char **i;
396
397 STRV_FOREACH(i, test_strv) {
398 found = hashmap_get(node->compare.children, *i);
399 if (found) {
400 r = bus_match_run(bus, found, m);
401 if (r != 0)
402 return r;
403 }
404 }
405
406 found = NULL;
407 } else if (node->type == BUS_MATCH_MESSAGE_TYPE)
408 found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
409 else
410 found = NULL;
411
412 if (found) {
413 r = bus_match_run(bus, found, m);
414 if (r != 0)
415 return r;
416 }
417 } else {
418 struct bus_match_node *c;
419
420 /* No hash table, so let's iterate manually... */
421
422 for (c = node->child; c; c = c->next) {
423 if (!value_node_test(c, node->type, test_u8, test_str, test_strv, m))
424 continue;
425
426 r = bus_match_run(bus, c, m);
427 if (r != 0)
428 return r;
429 }
430 }
431
432 if (bus && bus->match_callbacks_modified)
433 return 0;
434
435 /* And now, let's invoke our siblings */
436 return bus_match_run(bus, node->next, m);
437 }
438
439 static int bus_match_add_compare_value(
440 struct bus_match_node *where,
441 enum bus_match_node_type t,
442 uint8_t value_u8,
443 const char *value_str,
444 struct bus_match_node **ret) {
445
446 struct bus_match_node *c = NULL, *n = NULL;
447 int r;
448
449 assert(where);
450 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
451 assert(BUS_MATCH_IS_COMPARE(t));
452 assert(ret);
453
454 for (c = where->child; c && c->type != t; c = c->next)
455 ;
456
457 if (c) {
458 /* Comparison node already exists? Then let's see if
459 * the value node exists too. */
460
461 if (t == BUS_MATCH_MESSAGE_TYPE)
462 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
463 else if (BUS_MATCH_CAN_HASH(t))
464 n = hashmap_get(c->compare.children, value_str);
465 else {
466 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
467 ;
468 }
469
470 if (n) {
471 *ret = n;
472 return 0;
473 }
474 } else {
475 /* Comparison node, doesn't exist yet? Then let's
476 * create it. */
477
478 c = new0(struct bus_match_node, 1);
479 if (!c) {
480 r = -ENOMEM;
481 goto fail;
482 }
483
484 c->type = t;
485 c->parent = where;
486 c->next = where->child;
487 if (c->next)
488 c->next->prev = c;
489 where->child = c;
490
491 if (t == BUS_MATCH_MESSAGE_TYPE) {
492 c->compare.children = hashmap_new(NULL);
493 if (!c->compare.children) {
494 r = -ENOMEM;
495 goto fail;
496 }
497 } else if (BUS_MATCH_CAN_HASH(t)) {
498 c->compare.children = hashmap_new(&string_hash_ops);
499 if (!c->compare.children) {
500 r = -ENOMEM;
501 goto fail;
502 }
503 }
504 }
505
506 n = new0(struct bus_match_node, 1);
507 if (!n) {
508 r = -ENOMEM;
509 goto fail;
510 }
511
512 n->type = BUS_MATCH_VALUE;
513 n->value.u8 = value_u8;
514 if (value_str) {
515 n->value.str = strdup(value_str);
516 if (!n->value.str) {
517 r = -ENOMEM;
518 goto fail;
519 }
520 }
521
522 n->parent = c;
523 if (c->compare.children) {
524
525 if (t == BUS_MATCH_MESSAGE_TYPE)
526 r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
527 else
528 r = hashmap_put(c->compare.children, n->value.str, n);
529
530 if (r < 0)
531 goto fail;
532 } else {
533 n->next = c->child;
534 if (n->next)
535 n->next->prev = n;
536 c->child = n;
537 }
538
539 *ret = n;
540 return 1;
541
542 fail:
543 if (c)
544 bus_match_node_maybe_free(c);
545
546 if (n) {
547 free(n->value.str);
548 free(n);
549 }
550
551 return r;
552 }
553
554 static int bus_match_find_compare_value(
555 struct bus_match_node *where,
556 enum bus_match_node_type t,
557 uint8_t value_u8,
558 const char *value_str,
559 struct bus_match_node **ret) {
560
561 struct bus_match_node *c, *n;
562
563 assert(where);
564 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
565 assert(BUS_MATCH_IS_COMPARE(t));
566 assert(ret);
567
568 for (c = where->child; c && c->type != t; c = c->next)
569 ;
570
571 if (!c)
572 return 0;
573
574 if (t == BUS_MATCH_MESSAGE_TYPE)
575 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
576 else if (BUS_MATCH_CAN_HASH(t))
577 n = hashmap_get(c->compare.children, value_str);
578 else {
579 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
580 ;
581 }
582
583 if (n) {
584 *ret = n;
585 return 1;
586 }
587
588 return 0;
589 }
590
591 static int bus_match_add_leaf(
592 struct bus_match_node *where,
593 struct match_callback *callback) {
594
595 struct bus_match_node *n;
596
597 assert(where);
598 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
599 assert(callback);
600
601 n = new0(struct bus_match_node, 1);
602 if (!n)
603 return -ENOMEM;
604
605 n->type = BUS_MATCH_LEAF;
606 n->parent = where;
607 n->next = where->child;
608 if (n->next)
609 n->next->prev = n;
610
611 n->leaf.callback = callback;
612 callback->match_node = n;
613
614 where->child = n;
615
616 return 1;
617 }
618
619 static int bus_match_find_leaf(
620 struct bus_match_node *where,
621 sd_bus_message_handler_t callback,
622 void *userdata,
623 struct bus_match_node **ret) {
624
625 struct bus_match_node *c;
626
627 assert(where);
628 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
629 assert(ret);
630
631 for (c = where->child; c; c = c->next) {
632 sd_bus_slot *s;
633
634 s = container_of(c->leaf.callback, sd_bus_slot, match_callback);
635
636 if (c->type == BUS_MATCH_LEAF &&
637 c->leaf.callback->callback == callback &&
638 s->userdata == userdata) {
639 *ret = c;
640 return 1;
641 }
642 }
643
644 return 0;
645 }
646
647 enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
648 assert(k);
649
650 if (n == 4 && startswith(k, "type"))
651 return BUS_MATCH_MESSAGE_TYPE;
652 if (n == 6 && startswith(k, "sender"))
653 return BUS_MATCH_SENDER;
654 if (n == 11 && startswith(k, "destination"))
655 return BUS_MATCH_DESTINATION;
656 if (n == 9 && startswith(k, "interface"))
657 return BUS_MATCH_INTERFACE;
658 if (n == 6 && startswith(k, "member"))
659 return BUS_MATCH_MEMBER;
660 if (n == 4 && startswith(k, "path"))
661 return BUS_MATCH_PATH;
662 if (n == 14 && startswith(k, "path_namespace"))
663 return BUS_MATCH_PATH_NAMESPACE;
664
665 if (n == 4 && startswith(k, "arg")) {
666 int j;
667
668 j = undecchar(k[3]);
669 if (j < 0)
670 return -EINVAL;
671
672 return BUS_MATCH_ARG + j;
673 }
674
675 if (n == 5 && startswith(k, "arg")) {
676 int a, b;
677 enum bus_match_node_type t;
678
679 a = undecchar(k[3]);
680 b = undecchar(k[4]);
681 if (a <= 0 || b < 0)
682 return -EINVAL;
683
684 t = BUS_MATCH_ARG + a * 10 + b;
685 if (t > BUS_MATCH_ARG_LAST)
686 return -EINVAL;
687
688 return t;
689 }
690
691 if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
692 int j;
693
694 j = undecchar(k[3]);
695 if (j < 0)
696 return -EINVAL;
697
698 return BUS_MATCH_ARG_PATH + j;
699 }
700
701 if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
702 enum bus_match_node_type t;
703 int a, b;
704
705 a = undecchar(k[3]);
706 b = undecchar(k[4]);
707 if (a <= 0 || b < 0)
708 return -EINVAL;
709
710 t = BUS_MATCH_ARG_PATH + a * 10 + b;
711 if (t > BUS_MATCH_ARG_PATH_LAST)
712 return -EINVAL;
713
714 return t;
715 }
716
717 if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
718 int j;
719
720 j = undecchar(k[3]);
721 if (j < 0)
722 return -EINVAL;
723
724 return BUS_MATCH_ARG_NAMESPACE + j;
725 }
726
727 if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
728 enum bus_match_node_type t;
729 int a, b;
730
731 a = undecchar(k[3]);
732 b = undecchar(k[4]);
733 if (a <= 0 || b < 0)
734 return -EINVAL;
735
736 t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
737 if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
738 return -EINVAL;
739
740 return t;
741 }
742
743 if (n == 7 && startswith(k, "arg") && startswith(k + 4, "has")) {
744 int j;
745
746 j = undecchar(k[3]);
747 if (j < 0)
748 return -EINVAL;
749
750 return BUS_MATCH_ARG_HAS + j;
751 }
752
753 if (n == 8 && startswith(k, "arg") && startswith(k + 5, "has")) {
754 enum bus_match_node_type t;
755 int a, b;
756
757 a = undecchar(k[3]);
758 b = undecchar(k[4]);
759 if (a <= 0 || b < 0)
760 return -EINVAL;
761
762 t = BUS_MATCH_ARG_HAS + a * 10 + b;
763 if (t > BUS_MATCH_ARG_HAS_LAST)
764 return -EINVAL;
765
766 return t;
767 }
768
769 return -EINVAL;
770 }
771
772 static int match_component_compare(const void *a, const void *b) {
773 const struct bus_match_component *x = a, *y = b;
774
775 if (x->type < y->type)
776 return -1;
777 if (x->type > y->type)
778 return 1;
779
780 return 0;
781 }
782
783 void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
784 unsigned i;
785
786 for (i = 0; i < n_components; i++)
787 free(components[i].value_str);
788
789 free(components);
790 }
791
792 int bus_match_parse(
793 const char *match,
794 struct bus_match_component **_components,
795 unsigned *_n_components) {
796
797 const char *p = match;
798 struct bus_match_component *components = NULL;
799 size_t components_allocated = 0;
800 unsigned n_components = 0, i;
801 _cleanup_free_ char *value = NULL;
802 int r;
803
804 assert(match);
805 assert(_components);
806 assert(_n_components);
807
808 while (*p != 0) {
809 const char *eq, *q;
810 enum bus_match_node_type t;
811 unsigned j = 0;
812 size_t value_allocated = 0;
813 bool escaped = false, quoted;
814 uint8_t u;
815
816 /* Avahi's match rules appear to include whitespace, skip over it */
817 p += strspn(p, " ");
818
819 eq = strchr(p, '=');
820 if (!eq)
821 return -EINVAL;
822
823 t = bus_match_node_type_from_string(p, eq - p);
824 if (t < 0)
825 return -EINVAL;
826
827 quoted = eq[1] == '\'';
828
829 for (q = eq + 1 + quoted;; q++) {
830
831 if (*q == 0) {
832
833 if (quoted) {
834 r = -EINVAL;
835 goto fail;
836 } else {
837 if (value)
838 value[j] = 0;
839 break;
840 }
841 }
842
843 if (!escaped) {
844 if (*q == '\\') {
845 escaped = true;
846 continue;
847 }
848
849 if (quoted) {
850 if (*q == '\'') {
851 if (value)
852 value[j] = 0;
853 break;
854 }
855 } else {
856 if (*q == ',') {
857 if (value)
858 value[j] = 0;
859
860 break;
861 }
862 }
863 }
864
865 if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
866 r = -ENOMEM;
867 goto fail;
868 }
869
870 value[j++] = *q;
871 escaped = false;
872 }
873
874 if (!value) {
875 value = strdup("");
876 if (!value) {
877 r = -ENOMEM;
878 goto fail;
879 }
880 }
881
882 if (t == BUS_MATCH_MESSAGE_TYPE) {
883 r = bus_message_type_from_string(value, &u);
884 if (r < 0)
885 goto fail;
886
887 value = mfree(value);
888 } else
889 u = 0;
890
891 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
892 r = -ENOMEM;
893 goto fail;
894 }
895
896 components[n_components].type = t;
897 components[n_components].value_str = value;
898 components[n_components].value_u8 = u;
899 n_components++;
900
901 value = NULL;
902
903 if (q[quoted] == 0)
904 break;
905
906 if (q[quoted] != ',') {
907 r = -EINVAL;
908 goto fail;
909 }
910
911 p = q + 1 + quoted;
912 }
913
914 /* Order the whole thing, so that we always generate the same tree */
915 qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
916
917 /* Check for duplicates */
918 for (i = 0; i+1 < n_components; i++)
919 if (components[i].type == components[i+1].type) {
920 r = -EINVAL;
921 goto fail;
922 }
923
924 *_components = components;
925 *_n_components = n_components;
926
927 return 0;
928
929 fail:
930 bus_match_parse_free(components, n_components);
931 return r;
932 }
933
934 char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
935 _cleanup_fclose_ FILE *f = NULL;
936 char *buffer = NULL;
937 size_t size = 0;
938 unsigned i;
939 int r;
940
941 if (n_components <= 0)
942 return strdup("");
943
944 assert(components);
945
946 f = open_memstream(&buffer, &size);
947 if (!f)
948 return NULL;
949
950 for (i = 0; i < n_components; i++) {
951 char buf[32];
952
953 if (i != 0)
954 fputc(',', f);
955
956 fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
957 fputc('=', f);
958 fputc('\'', f);
959
960 if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
961 fputs(bus_message_type_to_string(components[i].value_u8), f);
962 else
963 fputs(components[i].value_str, f);
964
965 fputc('\'', f);
966 }
967
968 r = fflush_and_check(f);
969 if (r < 0)
970 return NULL;
971
972 return buffer;
973 }
974
975 int bus_match_add(
976 struct bus_match_node *root,
977 struct bus_match_component *components,
978 unsigned n_components,
979 struct match_callback *callback) {
980
981 unsigned i;
982 struct bus_match_node *n;
983 int r;
984
985 assert(root);
986 assert(callback);
987
988 n = root;
989 for (i = 0; i < n_components; i++) {
990 r = bus_match_add_compare_value(
991 n, components[i].type,
992 components[i].value_u8, components[i].value_str, &n);
993 if (r < 0)
994 return r;
995 }
996
997 return bus_match_add_leaf(n, callback);
998 }
999
1000 int bus_match_remove(
1001 struct bus_match_node *root,
1002 struct match_callback *callback) {
1003
1004 struct bus_match_node *node, *pp;
1005
1006 assert(root);
1007 assert(callback);
1008
1009 node = callback->match_node;
1010 if (!node)
1011 return 0;
1012
1013 assert(node->type == BUS_MATCH_LEAF);
1014
1015 callback->match_node = NULL;
1016
1017 /* Free the leaf */
1018 pp = node->parent;
1019 bus_match_node_free(node);
1020
1021 /* Prune the tree above */
1022 while (pp) {
1023 node = pp;
1024 pp = node->parent;
1025
1026 if (!bus_match_node_maybe_free(node))
1027 break;
1028 }
1029
1030 return 1;
1031 }
1032
1033 int bus_match_find(
1034 struct bus_match_node *root,
1035 struct bus_match_component *components,
1036 unsigned n_components,
1037 sd_bus_message_handler_t callback,
1038 void *userdata,
1039 struct match_callback **ret) {
1040
1041 struct bus_match_node *n, **gc;
1042 unsigned i;
1043 int r;
1044
1045 assert(root);
1046 assert(ret);
1047
1048 gc = newa(struct bus_match_node*, n_components);
1049
1050 n = root;
1051 for (i = 0; i < n_components; i++) {
1052 r = bus_match_find_compare_value(
1053 n, components[i].type,
1054 components[i].value_u8, components[i].value_str,
1055 &n);
1056 if (r <= 0)
1057 return r;
1058
1059 gc[i] = n;
1060 }
1061
1062 r = bus_match_find_leaf(n, callback, userdata, &n);
1063 if (r <= 0)
1064 return r;
1065
1066 *ret = n->leaf.callback;
1067 return 1;
1068 }
1069
1070 void bus_match_free(struct bus_match_node *node) {
1071 struct bus_match_node *c;
1072
1073 if (!node)
1074 return;
1075
1076 if (BUS_MATCH_CAN_HASH(node->type)) {
1077 Iterator i;
1078
1079 HASHMAP_FOREACH(c, node->compare.children, i)
1080 bus_match_free(c);
1081
1082 assert(hashmap_isempty(node->compare.children));
1083 }
1084
1085 while ((c = node->child))
1086 bus_match_free(c);
1087
1088 if (node->type != BUS_MATCH_ROOT)
1089 bus_match_node_free(node);
1090 }
1091
1092 const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
1093 switch (t) {
1094
1095 case BUS_MATCH_ROOT:
1096 return "root";
1097
1098 case BUS_MATCH_VALUE:
1099 return "value";
1100
1101 case BUS_MATCH_LEAF:
1102 return "leaf";
1103
1104 case BUS_MATCH_MESSAGE_TYPE:
1105 return "type";
1106
1107 case BUS_MATCH_SENDER:
1108 return "sender";
1109
1110 case BUS_MATCH_DESTINATION:
1111 return "destination";
1112
1113 case BUS_MATCH_INTERFACE:
1114 return "interface";
1115
1116 case BUS_MATCH_MEMBER:
1117 return "member";
1118
1119 case BUS_MATCH_PATH:
1120 return "path";
1121
1122 case BUS_MATCH_PATH_NAMESPACE:
1123 return "path_namespace";
1124
1125 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
1126 snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
1127 return buf;
1128
1129 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
1130 snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
1131 return buf;
1132
1133 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
1134 snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
1135 return buf;
1136
1137 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
1138 snprintf(buf, l, "arg%ihas", t - BUS_MATCH_ARG_HAS);
1139 return buf;
1140
1141 default:
1142 return NULL;
1143 }
1144 }
1145
1146 void bus_match_dump(struct bus_match_node *node, unsigned level) {
1147 struct bus_match_node *c;
1148 _cleanup_free_ char *pfx = NULL;
1149 char buf[32];
1150
1151 if (!node)
1152 return;
1153
1154 pfx = strrep(" ", level);
1155 printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
1156
1157 if (node->type == BUS_MATCH_VALUE) {
1158 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
1159 printf(" <%u>\n", node->value.u8);
1160 else
1161 printf(" <%s>\n", node->value.str);
1162 } else if (node->type == BUS_MATCH_ROOT)
1163 puts(" root");
1164 else if (node->type == BUS_MATCH_LEAF)
1165 printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata);
1166 else
1167 putchar('\n');
1168
1169 if (BUS_MATCH_CAN_HASH(node->type)) {
1170 Iterator i;
1171
1172 HASHMAP_FOREACH(c, node->compare.children, i)
1173 bus_match_dump(c, level + 1);
1174 }
1175
1176 for (c = node->child; c; c = c->next)
1177 bus_match_dump(c, level + 1);
1178 }
1179
1180 enum bus_match_scope bus_match_get_scope(const struct bus_match_component *components, unsigned n_components) {
1181 bool found_driver = false;
1182 unsigned i;
1183
1184 if (n_components <= 0)
1185 return BUS_MATCH_GENERIC;
1186
1187 assert(components);
1188
1189 /* Checks whether the specified match can only match the
1190 * pseudo-service for local messages, which we detect by
1191 * sender, interface or path. If a match is not restricted to
1192 * local messages, then we check if it only matches on the
1193 * driver. */
1194
1195 for (i = 0; i < n_components; i++) {
1196 const struct bus_match_component *c = components + i;
1197
1198 if (c->type == BUS_MATCH_SENDER) {
1199 if (streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
1200 return BUS_MATCH_LOCAL;
1201
1202 if (streq_ptr(c->value_str, "org.freedesktop.DBus"))
1203 found_driver = true;
1204 }
1205
1206 if (c->type == BUS_MATCH_INTERFACE && streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
1207 return BUS_MATCH_LOCAL;
1208
1209 if (c->type == BUS_MATCH_PATH && streq_ptr(c->value_str, "/org/freedesktop/DBus/Local"))
1210 return BUS_MATCH_LOCAL;
1211 }
1212
1213 return found_driver ? BUS_MATCH_DRIVER : BUS_MATCH_GENERIC;
1214
1215 }