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