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