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