1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* signals.c Bus signal connection implementation
3 *
4 * Copyright (C) 2003, 2005 Red Hat, Inc.
5 *
6 * Licensed under the Academic Free License version 2.1
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 */
23
24 #include <config.h>
25
26 #include <string.h>
27
28 #include "signals.h"
29 #include "services.h"
30 #include "utils.h"
31 #include <dbus/dbus-marshal-validate.h>
32
33 struct BusMatchRule
34 {
35 int refcount; /**< reference count */
36
37 DBusConnection *matches_go_to; /**< Owner of the rule */
38
39 unsigned int flags; /**< BusMatchFlags */
40
41 int message_type;
42 char *interface;
43 char *member;
44 char *sender;
45 char *destination;
46 char *path;
47
48 unsigned int *arg_lens;
49 char **args;
50 int args_len;
51 };
52
53 #define BUS_MATCH_ARG_NAMESPACE 0x4000000u
54 #define BUS_MATCH_ARG_IS_PATH 0x8000000u
55
56 #define BUS_MATCH_ARG_FLAGS (BUS_MATCH_ARG_NAMESPACE | BUS_MATCH_ARG_IS_PATH)
57
58 BusMatchRule*
bus_match_rule_new(DBusConnection * matches_go_to)59 bus_match_rule_new (DBusConnection *matches_go_to)
60 {
61 BusMatchRule *rule;
62
63 rule = dbus_new0 (BusMatchRule, 1);
64 if (rule == NULL)
65 return NULL;
66
67 rule->refcount = 1;
68 rule->matches_go_to = matches_go_to;
69
70 #ifndef DBUS_ENABLE_EMBEDDED_TESTS
71 _dbus_assert (rule->matches_go_to != NULL);
72 #endif
73
74 return rule;
75 }
76
77 BusMatchRule *
bus_match_rule_ref(BusMatchRule * rule)78 bus_match_rule_ref (BusMatchRule *rule)
79 {
80 _dbus_assert (rule->refcount > 0);
81
82 rule->refcount += 1;
83
84 return rule;
85 }
86
87 void
bus_match_rule_unref(BusMatchRule * rule)88 bus_match_rule_unref (BusMatchRule *rule)
89 {
90 _dbus_assert (rule->refcount > 0);
91
92 rule->refcount -= 1;
93 if (rule->refcount == 0)
94 {
95 dbus_free (rule->interface);
96 dbus_free (rule->member);
97 dbus_free (rule->sender);
98 dbus_free (rule->destination);
99 dbus_free (rule->path);
100 dbus_free (rule->arg_lens);
101
102 /* can't use dbus_free_string_array() since there
103 * are embedded NULL
104 */
105 if (rule->args)
106 {
107 int i;
108
109 i = 0;
110 while (i < rule->args_len)
111 {
112 if (rule->args[i])
113 dbus_free (rule->args[i]);
114 ++i;
115 }
116
117 dbus_free (rule->args);
118 }
119
120 dbus_free (rule);
121 }
122 }
123
124 #if defined(DBUS_ENABLE_VERBOSE_MODE) || defined(DBUS_ENABLE_STATS)
125 static dbus_bool_t
append_key_and_escaped_value(DBusString * str,const char * token,const char * value)126 append_key_and_escaped_value (DBusString *str, const char *token, const char *value)
127 {
128 const char *p = value;
129
130 if (!_dbus_string_append_printf (str, "%s='", token))
131 return FALSE;
132
133 while (*p != '\0')
134 {
135 const char *next = strchr (p, '\'');
136
137 if (next)
138 {
139 if (!_dbus_string_append_printf (str, "%.*s", (int) (next - p), p))
140 return FALSE;
141 /* Horrible escape sequence: single quote cannot be escaped inside
142 * a single quoted string. So we close the single quote, escape the
143 * single quote, and reopen a single quote.
144 */
145 if (!_dbus_string_append_printf (str, "'\\''"))
146 return FALSE;
147 p = next + 1;
148 }
149 else
150 {
151 if (!_dbus_string_append_printf (str, "%s", p))
152 return FALSE;
153 break;
154 }
155 }
156
157 if (!_dbus_string_append_byte (str, '\''))
158 return FALSE;
159
160 return TRUE;
161 }
162
163 /* returns NULL if no memory */
164 static char*
match_rule_to_string(BusMatchRule * rule)165 match_rule_to_string (BusMatchRule *rule)
166 {
167 DBusString str;
168 char *ret;
169
170 if (!_dbus_string_init (&str))
171 {
172 return NULL;
173 }
174
175 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
176 {
177 if (!append_key_and_escaped_value (&str, "type",
178 dbus_message_type_to_string (rule->message_type)))
179 goto nomem;
180 }
181
182 if (rule->flags & BUS_MATCH_INTERFACE)
183 {
184 if (_dbus_string_get_length (&str) > 0)
185 {
186 if (!_dbus_string_append (&str, ","))
187 goto nomem;
188 }
189
190 if (!append_key_and_escaped_value (&str, "interface", rule->interface))
191 goto nomem;
192 }
193
194 if (rule->flags & BUS_MATCH_MEMBER)
195 {
196 if (_dbus_string_get_length (&str) > 0)
197 {
198 if (!_dbus_string_append (&str, ","))
199 goto nomem;
200 }
201
202 if (!append_key_and_escaped_value (&str, "member", rule->member))
203 goto nomem;
204 }
205
206 if (rule->flags & BUS_MATCH_PATH)
207 {
208 if (_dbus_string_get_length (&str) > 0)
209 {
210 if (!_dbus_string_append (&str, ","))
211 goto nomem;
212 }
213
214 if (!append_key_and_escaped_value (&str, "path", rule->path))
215 goto nomem;
216 }
217
218 if (rule->flags & BUS_MATCH_PATH_NAMESPACE)
219 {
220 if (_dbus_string_get_length (&str) > 0)
221 {
222 if (!_dbus_string_append (&str, ","))
223 goto nomem;
224 }
225
226 if (!append_key_and_escaped_value (&str, "path_namespace", rule->path))
227 goto nomem;
228 }
229
230 if (rule->flags & BUS_MATCH_SENDER)
231 {
232 if (_dbus_string_get_length (&str) > 0)
233 {
234 if (!_dbus_string_append (&str, ","))
235 goto nomem;
236 }
237
238 if (!append_key_and_escaped_value (&str, "sender", rule->sender))
239 goto nomem;
240 }
241
242 if (rule->flags & BUS_MATCH_DESTINATION)
243 {
244 if (_dbus_string_get_length (&str) > 0)
245 {
246 if (!_dbus_string_append (&str, ","))
247 goto nomem;
248 }
249
250 if (!append_key_and_escaped_value (&str, "destination", rule->destination))
251 goto nomem;
252 }
253
254 if (rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING)
255 {
256 if (_dbus_string_get_length (&str) > 0)
257 {
258 if (!_dbus_string_append (&str, ","))
259 goto nomem;
260 }
261
262 if (!append_key_and_escaped_value (&str, "eavesdrop",
263 (rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING) ?
264 "true" : "false"))
265 goto nomem;
266 }
267
268 if (rule->flags & BUS_MATCH_ARGS)
269 {
270 int i;
271
272 _dbus_assert (rule->args != NULL);
273
274 i = 0;
275 while (i < rule->args_len)
276 {
277 if (rule->args[i] != NULL)
278 {
279 dbus_bool_t is_path, is_namespace;
280
281 if (_dbus_string_get_length (&str) > 0)
282 {
283 if (!_dbus_string_append (&str, ","))
284 goto nomem;
285 }
286
287 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
288 is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
289
290 if (!_dbus_string_append_printf (&str,
291 "arg%d%s",
292 i,
293 is_path ? "path" :
294 is_namespace ? "namespace" : ""))
295 goto nomem;
296 if (!append_key_and_escaped_value (&str, "", rule->args[i]))
297 goto nomem;
298 }
299
300 ++i;
301 }
302 }
303
304 if (!_dbus_string_steal_data (&str, &ret))
305 goto nomem;
306
307 _dbus_string_free (&str);
308 return ret;
309
310 nomem:
311 _dbus_string_free (&str);
312 return NULL;
313 }
314 #endif /* defined(DBUS_ENABLE_VERBOSE_MODE) || defined(DBUS_ENABLE_STATS) */
315
316 dbus_bool_t
bus_match_rule_set_message_type(BusMatchRule * rule,int type)317 bus_match_rule_set_message_type (BusMatchRule *rule,
318 int type)
319 {
320 rule->flags |= BUS_MATCH_MESSAGE_TYPE;
321
322 rule->message_type = type;
323
324 return TRUE;
325 }
326
327 dbus_bool_t
bus_match_rule_set_interface(BusMatchRule * rule,const char * interface)328 bus_match_rule_set_interface (BusMatchRule *rule,
329 const char *interface)
330 {
331 char *new;
332
333 _dbus_assert (interface != NULL);
334
335 new = _dbus_strdup (interface);
336 if (new == NULL)
337 return FALSE;
338
339 rule->flags |= BUS_MATCH_INTERFACE;
340 dbus_free (rule->interface);
341 rule->interface = new;
342
343 return TRUE;
344 }
345
346 dbus_bool_t
bus_match_rule_set_member(BusMatchRule * rule,const char * member)347 bus_match_rule_set_member (BusMatchRule *rule,
348 const char *member)
349 {
350 char *new;
351
352 _dbus_assert (member != NULL);
353
354 new = _dbus_strdup (member);
355 if (new == NULL)
356 return FALSE;
357
358 rule->flags |= BUS_MATCH_MEMBER;
359 dbus_free (rule->member);
360 rule->member = new;
361
362 return TRUE;
363 }
364
365 dbus_bool_t
bus_match_rule_set_sender(BusMatchRule * rule,const char * sender)366 bus_match_rule_set_sender (BusMatchRule *rule,
367 const char *sender)
368 {
369 char *new;
370
371 _dbus_assert (sender != NULL);
372
373 new = _dbus_strdup (sender);
374 if (new == NULL)
375 return FALSE;
376
377 rule->flags |= BUS_MATCH_SENDER;
378 dbus_free (rule->sender);
379 rule->sender = new;
380
381 return TRUE;
382 }
383
384 dbus_bool_t
bus_match_rule_set_destination(BusMatchRule * rule,const char * destination)385 bus_match_rule_set_destination (BusMatchRule *rule,
386 const char *destination)
387 {
388 char *new;
389
390 _dbus_assert (destination != NULL);
391
392 new = _dbus_strdup (destination);
393 if (new == NULL)
394 return FALSE;
395
396 rule->flags |= BUS_MATCH_DESTINATION;
397 dbus_free (rule->destination);
398 rule->destination = new;
399
400 return TRUE;
401 }
402
403 void
bus_match_rule_set_client_is_eavesdropping(BusMatchRule * rule,dbus_bool_t is_eavesdropping)404 bus_match_rule_set_client_is_eavesdropping (BusMatchRule *rule,
405 dbus_bool_t is_eavesdropping)
406 {
407 if (is_eavesdropping)
408 rule->flags |= BUS_MATCH_CLIENT_IS_EAVESDROPPING;
409 else
410 rule->flags &= ~(BUS_MATCH_CLIENT_IS_EAVESDROPPING);
411 }
412
413 dbus_bool_t
bus_match_rule_get_client_is_eavesdropping(BusMatchRule * rule)414 bus_match_rule_get_client_is_eavesdropping (BusMatchRule *rule)
415 {
416 if (rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING)
417 return TRUE;
418 else
419 return FALSE;
420 }
421
422 dbus_bool_t
bus_match_rule_set_path(BusMatchRule * rule,const char * path,dbus_bool_t is_namespace)423 bus_match_rule_set_path (BusMatchRule *rule,
424 const char *path,
425 dbus_bool_t is_namespace)
426 {
427 char *new;
428
429 _dbus_assert (path != NULL);
430
431 new = _dbus_strdup (path);
432 if (new == NULL)
433 return FALSE;
434
435 rule->flags &= ~(BUS_MATCH_PATH|BUS_MATCH_PATH_NAMESPACE);
436
437 if (is_namespace)
438 rule->flags |= BUS_MATCH_PATH_NAMESPACE;
439 else
440 rule->flags |= BUS_MATCH_PATH;
441
442 dbus_free (rule->path);
443 rule->path = new;
444
445 return TRUE;
446 }
447
448 dbus_bool_t
bus_match_rule_set_arg(BusMatchRule * rule,int arg,const DBusString * value,dbus_bool_t is_path,dbus_bool_t is_namespace)449 bus_match_rule_set_arg (BusMatchRule *rule,
450 int arg,
451 const DBusString *value,
452 dbus_bool_t is_path,
453 dbus_bool_t is_namespace)
454 {
455 int length;
456 char *new;
457
458 _dbus_assert (value != NULL);
459
460 /* args_len is the number of args not including null termination
461 * in the char**
462 */
463 if (arg >= rule->args_len)
464 {
465 unsigned int *new_arg_lens;
466 char **new_args;
467 int new_args_len;
468 int i;
469
470 new_args_len = arg + 1;
471
472 /* add another + 1 here for null termination */
473 new_args = dbus_realloc (rule->args,
474 sizeof (char *) * (new_args_len + 1));
475 if (new_args == NULL)
476 return FALSE;
477
478 /* NULL the new slots */
479 i = rule->args_len;
480 while (i <= new_args_len) /* <= for null termination */
481 {
482 new_args[i] = NULL;
483 ++i;
484 }
485
486 rule->args = new_args;
487
488 /* and now add to the lengths */
489 new_arg_lens = dbus_realloc (rule->arg_lens,
490 sizeof (int) * (new_args_len + 1));
491
492 if (new_arg_lens == NULL)
493 return FALSE;
494
495 /* zero the new slots */
496 i = rule->args_len;
497 while (i <= new_args_len) /* <= for null termination */
498 {
499 new_arg_lens[i] = 0;
500 ++i;
501 }
502
503 rule->arg_lens = new_arg_lens;
504 rule->args_len = new_args_len;
505 }
506
507 length = _dbus_string_get_length (value);
508 if (!_dbus_string_copy_data (value, &new))
509 return FALSE;
510
511 rule->flags |= BUS_MATCH_ARGS;
512
513 dbus_free (rule->args[arg]);
514 rule->arg_lens[arg] = length;
515 rule->args[arg] = new;
516
517 if (is_path)
518 rule->arg_lens[arg] |= BUS_MATCH_ARG_IS_PATH;
519
520 if (is_namespace)
521 rule->arg_lens[arg] |= BUS_MATCH_ARG_NAMESPACE;
522
523 /* NULL termination didn't get busted */
524 _dbus_assert (rule->args[rule->args_len] == NULL);
525 _dbus_assert (rule->arg_lens[rule->args_len] == 0);
526
527 return TRUE;
528 }
529
530 #define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
531
532 static dbus_bool_t
find_key(const DBusString * str,int start,DBusString * key,int * value_pos,DBusError * error)533 find_key (const DBusString *str,
534 int start,
535 DBusString *key,
536 int *value_pos,
537 DBusError *error)
538 {
539 const char *p;
540 const char *s;
541 const char *key_start;
542 const char *key_end;
543
544 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
545
546 s = _dbus_string_get_const_data (str);
547
548 p = s + start;
549
550 while (*p && ISWHITE (*p))
551 ++p;
552
553 key_start = p;
554
555 while (*p && *p != '=' && !ISWHITE (*p))
556 ++p;
557
558 key_end = p;
559
560 while (*p && ISWHITE (*p))
561 ++p;
562
563 if (key_start == key_end)
564 {
565 /* Empty match rules or trailing whitespace are OK */
566 *value_pos = p - s;
567 return TRUE;
568 }
569
570 if (*p != '=')
571 {
572 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
573 "Match rule has a key with no subsequent '=' character");
574 return FALSE;
575 }
576 ++p;
577
578 if (!_dbus_string_append_len (key, key_start, key_end - key_start))
579 {
580 BUS_SET_OOM (error);
581 return FALSE;
582 }
583
584 *value_pos = p - s;
585
586 return TRUE;
587 }
588
589 static dbus_bool_t
find_value(const DBusString * str,int start,const char * key,DBusString * value,int * value_end,DBusError * error)590 find_value (const DBusString *str,
591 int start,
592 const char *key,
593 DBusString *value,
594 int *value_end,
595 DBusError *error)
596 {
597 const char *p;
598 const char *s;
599 char quote_char;
600 int orig_len;
601
602 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
603
604 orig_len = _dbus_string_get_length (value);
605
606 s = _dbus_string_get_const_data (str);
607
608 p = s + start;
609
610 quote_char = '\0';
611
612 while (*p)
613 {
614 if (quote_char == '\0')
615 {
616 switch (*p)
617 {
618 case '\0':
619 goto done;
620
621 case '\'':
622 quote_char = '\'';
623 goto next;
624
625 case ',':
626 ++p;
627 goto done;
628
629 case '\\':
630 quote_char = '\\';
631 goto next;
632
633 default:
634 if (!_dbus_string_append_byte (value, *p))
635 {
636 BUS_SET_OOM (error);
637 goto failed;
638 }
639 }
640 }
641 else if (quote_char == '\\')
642 {
643 /* \ only counts as an escape if escaping a quote mark */
644 if (*p != '\'')
645 {
646 if (!_dbus_string_append_byte (value, '\\'))
647 {
648 BUS_SET_OOM (error);
649 goto failed;
650 }
651 }
652
653 if (!_dbus_string_append_byte (value, *p))
654 {
655 BUS_SET_OOM (error);
656 goto failed;
657 }
658
659 quote_char = '\0';
660 }
661 else
662 {
663 _dbus_assert (quote_char == '\'');
664
665 if (*p == '\'')
666 {
667 quote_char = '\0';
668 }
669 else
670 {
671 if (!_dbus_string_append_byte (value, *p))
672 {
673 BUS_SET_OOM (error);
674 goto failed;
675 }
676 }
677 }
678
679 next:
680 ++p;
681 }
682
683 done:
684
685 if (quote_char == '\\')
686 {
687 if (!_dbus_string_append_byte (value, '\\'))
688 {
689 BUS_SET_OOM (error);
690 goto failed;
691 }
692 }
693 else if (quote_char == '\'')
694 {
695 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
696 "Unbalanced quotation marks in match rule");
697 goto failed;
698 }
699 else
700 _dbus_assert (quote_char == '\0');
701
702 /* Zero-length values are allowed */
703
704 *value_end = p - s;
705
706 return TRUE;
707
708 failed:
709 _DBUS_ASSERT_ERROR_IS_SET (error);
710 _dbus_string_set_length (value, orig_len);
711 return FALSE;
712 }
713
714 /* duplicates aren't allowed so the real legitimate max is only 6 or
715 * so. Leaving extra so we don't have to bother to update it.
716 * FIXME this is sort of busted now with arg matching, but we let
717 * you match on up to 10 args for now
718 */
719 #define MAX_RULE_TOKENS 16
720
721 /* this is slightly too high level to be termed a "token"
722 * but let's not be pedantic.
723 */
724 typedef struct
725 {
726 char *key;
727 char *value;
728 } RuleToken;
729
730 static dbus_bool_t
tokenize_rule(const DBusString * rule_text,RuleToken tokens[MAX_RULE_TOKENS],DBusError * error)731 tokenize_rule (const DBusString *rule_text,
732 RuleToken tokens[MAX_RULE_TOKENS],
733 DBusError *error)
734 {
735 int i;
736 int pos;
737 DBusString key;
738 DBusString value;
739 dbus_bool_t retval;
740
741 retval = FALSE;
742
743 if (!_dbus_string_init (&key))
744 {
745 BUS_SET_OOM (error);
746 return FALSE;
747 }
748
749 if (!_dbus_string_init (&value))
750 {
751 _dbus_string_free (&key);
752 BUS_SET_OOM (error);
753 return FALSE;
754 }
755
756 i = 0;
757 pos = 0;
758 while (i < MAX_RULE_TOKENS &&
759 pos < _dbus_string_get_length (rule_text))
760 {
761 _dbus_assert (tokens[i].key == NULL);
762 _dbus_assert (tokens[i].value == NULL);
763
764 if (!find_key (rule_text, pos, &key, &pos, error))
765 goto out;
766
767 if (_dbus_string_get_length (&key) == 0)
768 goto next;
769
770 if (!_dbus_string_steal_data (&key, &tokens[i].key))
771 {
772 BUS_SET_OOM (error);
773 goto out;
774 }
775
776 if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error))
777 goto out;
778
779 if (!_dbus_string_steal_data (&value, &tokens[i].value))
780 {
781 BUS_SET_OOM (error);
782 goto out;
783 }
784
785 next:
786 ++i;
787 }
788
789 retval = TRUE;
790
791 out:
792 if (!retval)
793 {
794 i = 0;
795 while (tokens[i].key || tokens[i].value)
796 {
797 dbus_free (tokens[i].key);
798 dbus_free (tokens[i].value);
799 tokens[i].key = NULL;
800 tokens[i].value = NULL;
801 ++i;
802 }
803 }
804
805 _dbus_string_free (&key);
806 _dbus_string_free (&value);
807
808 return retval;
809 }
810
811 static dbus_bool_t
bus_match_rule_parse_arg_match(BusMatchRule * rule,const char * key,const DBusString * value,DBusError * error)812 bus_match_rule_parse_arg_match (BusMatchRule *rule,
813 const char *key,
814 const DBusString *value,
815 DBusError *error)
816 {
817 dbus_bool_t is_path = FALSE;
818 dbus_bool_t is_namespace = FALSE;
819 DBusString key_str;
820 unsigned long arg;
821 int length;
822 int end;
823
824 /* For now, arg0='foo' always implies that 'foo' is a
825 * DBUS_TYPE_STRING. Someday we could add an arg0type='int32' thing
826 * if we wanted, which would specify another type, in which case
827 * arg0='5' would have the 5 parsed as an int rather than string.
828 */
829
830 /* First we need to parse arg0 = 0, arg27 = 27 */
831
832 _dbus_string_init_const (&key_str, key);
833 length = _dbus_string_get_length (&key_str);
834
835 if (_dbus_string_get_length (&key_str) < 4)
836 {
837 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
838 "Key '%s' in match rule starts with 'arg' but lacks an arg number. Should be 'arg0' or 'arg7' for example.\n", key);
839 goto failed;
840 }
841
842 if (!_dbus_string_parse_uint (&key_str, 3, &arg, &end))
843 {
844 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
845 "Key '%s' in match rule starts with 'arg' but could not parse arg number. Should be 'arg0' or 'arg7' for example.\n", key);
846 goto failed;
847 }
848
849 if (end != length)
850 {
851 int len1 = strlen ("path");
852 if ((end + len1) == length &&
853 _dbus_string_ends_with_c_str (&key_str, "path"))
854 {
855 is_path = TRUE;
856 }
857 else if (_dbus_string_equal_c_str (&key_str, "arg0namespace"))
858 {
859 int value_len = _dbus_string_get_length (value);
860
861 is_namespace = TRUE;
862
863 if (!_dbus_validate_bus_namespace (value, 0, value_len))
864 {
865 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
866 "arg0namespace='%s' is not a valid prefix of a bus name",
867 _dbus_string_get_const_data (value));
868 goto failed;
869 }
870 }
871 else
872 {
873 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
874 "Key '%s' in match rule contains junk after argument number (%lu). Only 'arg%lupath' (for example) or 'arg0namespace' are valid", key, arg, arg);
875 goto failed;
876 }
877 }
878
879 /* If we didn't check this we could allocate a huge amount of RAM */
880 if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER)
881 {
882 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
883 "Key '%s' in match rule has arg number %lu but the maximum is %d.\n", key, (unsigned long) arg, DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER);
884 goto failed;
885 }
886
887 if ((rule->flags & BUS_MATCH_ARGS) &&
888 rule->args_len > (int) arg &&
889 rule->args[arg] != NULL)
890 {
891 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
892 "Argument %s matched more than once in match rule\n", key);
893 goto failed;
894 }
895
896 if (!bus_match_rule_set_arg (rule, arg, value, is_path, is_namespace))
897 {
898 BUS_SET_OOM (error);
899 goto failed;
900 }
901
902 return TRUE;
903
904 failed:
905 _DBUS_ASSERT_ERROR_IS_SET (error);
906 return FALSE;
907 }
908
909 /*
910 * The format is comma-separated with strings quoted with single quotes
911 * as for the shell (to escape a literal single quote, use '\'').
912 *
913 * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
914 * path='/bar/foo',destination=':452345.34'
915 *
916 */
917 BusMatchRule*
bus_match_rule_parse(DBusConnection * matches_go_to,const DBusString * rule_text,DBusError * error)918 bus_match_rule_parse (DBusConnection *matches_go_to,
919 const DBusString *rule_text,
920 DBusError *error)
921 {
922 BusMatchRule *rule;
923 RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
924 int i;
925
926 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
927
928 if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH)
929 {
930 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
931 "Match rule text is %d bytes, maximum is %d",
932 _dbus_string_get_length (rule_text),
933 DBUS_MAXIMUM_MATCH_RULE_LENGTH);
934 return NULL;
935 }
936
937 memset (tokens, '\0', sizeof (tokens));
938
939 rule = bus_match_rule_new (matches_go_to);
940 if (rule == NULL)
941 {
942 BUS_SET_OOM (error);
943 goto failed;
944 }
945
946 if (!tokenize_rule (rule_text, tokens, error))
947 goto failed;
948
949 i = 0;
950 while (tokens[i].key != NULL)
951 {
952 DBusString tmp_str;
953 int len;
954 const char *key = tokens[i].key;
955 const char *value = tokens[i].value;
956
957 _dbus_string_init_const (&tmp_str, value);
958 len = _dbus_string_get_length (&tmp_str);
959
960 if (strcmp (key, "type") == 0)
961 {
962 int t;
963
964 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
965 {
966 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
967 "Key %s specified twice in match rule\n", key);
968 goto failed;
969 }
970
971 t = dbus_message_type_from_string (value);
972
973 if (t == DBUS_MESSAGE_TYPE_INVALID)
974 {
975 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
976 "Invalid message type (%s) in match rule\n", value);
977 goto failed;
978 }
979
980 if (!bus_match_rule_set_message_type (rule, t))
981 {
982 BUS_SET_OOM (error);
983 goto failed;
984 }
985 }
986 else if (strcmp (key, "sender") == 0)
987 {
988 if (rule->flags & BUS_MATCH_SENDER)
989 {
990 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
991 "Key %s specified twice in match rule\n", key);
992 goto failed;
993 }
994
995 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
996 {
997 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
998 "Sender name '%s' is invalid\n", value);
999 goto failed;
1000 }
1001
1002 if (!bus_match_rule_set_sender (rule, value))
1003 {
1004 BUS_SET_OOM (error);
1005 goto failed;
1006 }
1007 }
1008 else if (strcmp (key, "interface") == 0)
1009 {
1010 if (rule->flags & BUS_MATCH_INTERFACE)
1011 {
1012 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1013 "Key %s specified twice in match rule\n", key);
1014 goto failed;
1015 }
1016
1017 if (!_dbus_validate_interface (&tmp_str, 0, len))
1018 {
1019 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1020 "Interface name '%s' is invalid\n", value);
1021 goto failed;
1022 }
1023
1024 if (!bus_match_rule_set_interface (rule, value))
1025 {
1026 BUS_SET_OOM (error);
1027 goto failed;
1028 }
1029 }
1030 else if (strcmp (key, "member") == 0)
1031 {
1032 if (rule->flags & BUS_MATCH_MEMBER)
1033 {
1034 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1035 "Key %s specified twice in match rule\n", key);
1036 goto failed;
1037 }
1038
1039 if (!_dbus_validate_member (&tmp_str, 0, len))
1040 {
1041 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1042 "Member name '%s' is invalid\n", value);
1043 goto failed;
1044 }
1045
1046 if (!bus_match_rule_set_member (rule, value))
1047 {
1048 BUS_SET_OOM (error);
1049 goto failed;
1050 }
1051 }
1052 else if (strcmp (key, "path") == 0 ||
1053 strcmp (key, "path_namespace") == 0)
1054 {
1055 dbus_bool_t is_namespace = (strcmp (key, "path_namespace") == 0);
1056
1057 if (rule->flags & (BUS_MATCH_PATH | BUS_MATCH_PATH_NAMESPACE))
1058 {
1059 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1060 "path or path_namespace specified twice in match rule\n");
1061 goto failed;
1062 }
1063
1064 if (!_dbus_validate_path (&tmp_str, 0, len))
1065 {
1066 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1067 "Path '%s' is invalid\n", value);
1068 goto failed;
1069 }
1070
1071 if (!bus_match_rule_set_path (rule, value, is_namespace))
1072 {
1073 BUS_SET_OOM (error);
1074 goto failed;
1075 }
1076 }
1077 else if (strcmp (key, "destination") == 0)
1078 {
1079 if (rule->flags & BUS_MATCH_DESTINATION)
1080 {
1081 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1082 "Key %s specified twice in match rule\n", key);
1083 goto failed;
1084 }
1085
1086 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
1087 {
1088 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1089 "Destination name '%s' is invalid\n", value);
1090 goto failed;
1091 }
1092
1093 if (!bus_match_rule_set_destination (rule, value))
1094 {
1095 BUS_SET_OOM (error);
1096 goto failed;
1097 }
1098 }
1099 else if (strcmp (key, "eavesdrop") == 0)
1100 {
1101 /* do not detect "eavesdrop" being used more than once in rule:
1102 * 1) it's not possible, it's only in the flags
1103 * 2) it might be used twice to disable eavesdropping when it's
1104 * automatically added (eg dbus-monitor/bustle) */
1105
1106 /* we accept only "true|false" as possible values */
1107 if ((strcmp (value, "true") == 0))
1108 {
1109 bus_match_rule_set_client_is_eavesdropping (rule, TRUE);
1110 }
1111 else if (strcmp (value, "false") == 0)
1112 {
1113 bus_match_rule_set_client_is_eavesdropping (rule, FALSE);
1114 }
1115 else
1116 {
1117 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1118 "eavesdrop='%s' is invalid, "
1119 "it should be 'true' or 'false'\n",
1120 value);
1121 goto failed;
1122 }
1123 }
1124 else if (strncmp (key, "arg", 3) == 0)
1125 {
1126 if (!bus_match_rule_parse_arg_match (rule, key, &tmp_str, error))
1127 goto failed;
1128 }
1129 else
1130 {
1131 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1132 "Unknown key \"%s\" in match rule",
1133 key);
1134 goto failed;
1135 }
1136
1137 ++i;
1138 }
1139
1140
1141 goto out;
1142
1143 failed:
1144 _DBUS_ASSERT_ERROR_IS_SET (error);
1145 if (rule)
1146 {
1147 bus_match_rule_unref (rule);
1148 rule = NULL;
1149 }
1150
1151 out:
1152
1153 i = 0;
1154 while (tokens[i].key || tokens[i].value)
1155 {
1156 _dbus_assert (i < MAX_RULE_TOKENS);
1157 dbus_free (tokens[i].key);
1158 dbus_free (tokens[i].value);
1159 ++i;
1160 }
1161
1162 return rule;
1163 }
1164
1165 typedef struct RulePool RulePool;
1166 struct RulePool
1167 {
1168 /* Maps non-NULL interface names to non-NULL (DBusList **)s */
1169 DBusHashTable *rules_by_iface;
1170
1171 /* List of BusMatchRules which don't specify an interface */
1172 DBusList *rules_without_iface;
1173 };
1174
1175 struct BusMatchmaker
1176 {
1177 int refcount;
1178
1179 /* Pools of rules, grouped by the type of message they match. 0
1180 * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a message
1181 * type.
1182 */
1183 RulePool rules_by_type[DBUS_NUM_MESSAGE_TYPES];
1184 };
1185
1186 #ifdef DBUS_ENABLE_STATS
1187 dbus_bool_t
bus_match_rule_dump(BusMatchmaker * matchmaker,DBusConnection * conn_filter,DBusMessageIter * arr_iter)1188 bus_match_rule_dump (BusMatchmaker *matchmaker,
1189 DBusConnection *conn_filter,
1190 DBusMessageIter *arr_iter)
1191 {
1192 int i;
1193
1194 for (i = 0 ; i < DBUS_NUM_MESSAGE_TYPES ; i++)
1195 {
1196 DBusHashIter iter;
1197 DBusList **list;
1198 DBusList *link;
1199
1200 _dbus_hash_iter_init (matchmaker->rules_by_type[i].rules_by_iface, &iter);
1201 while (_dbus_hash_iter_next (&iter))
1202 {
1203 list = _dbus_hash_iter_get_value (&iter);
1204 for (link = _dbus_list_get_first_link (list);
1205 link != NULL;
1206 link = _dbus_list_get_next_link (list, link))
1207 {
1208 BusMatchRule *rule = link->data;
1209
1210 if (rule->matches_go_to == conn_filter)
1211 {
1212 char *s = match_rule_to_string (rule);
1213
1214 if (s == NULL)
1215 return FALSE;
1216
1217 if (!dbus_message_iter_append_basic (arr_iter, DBUS_TYPE_STRING, &s))
1218 {
1219 dbus_free (s);
1220 return FALSE;
1221 }
1222 dbus_free (s);
1223 }
1224 }
1225 }
1226 list = &matchmaker->rules_by_type[i].rules_without_iface;
1227 for (link = _dbus_list_get_first_link (list);
1228 link != NULL;
1229 link = _dbus_list_get_next_link (list, link))
1230 {
1231 BusMatchRule *rule = link->data;
1232
1233 if (rule->matches_go_to == conn_filter)
1234 {
1235 char *s = match_rule_to_string (rule);
1236
1237 if (s == NULL)
1238 return FALSE;
1239
1240 if (!dbus_message_iter_append_basic (arr_iter, DBUS_TYPE_STRING, &s))
1241 {
1242 dbus_free (s);
1243 return FALSE;
1244 }
1245 dbus_free (s);
1246 }
1247 }
1248 }
1249
1250 return TRUE;
1251 }
1252 #endif
1253
1254 static void
rule_list_free(DBusList ** rules)1255 rule_list_free (DBusList **rules)
1256 {
1257 while (*rules != NULL)
1258 {
1259 BusMatchRule *rule;
1260
1261 rule = (*rules)->data;
1262 bus_match_rule_unref (rule);
1263 _dbus_list_remove_link (rules, *rules);
1264 }
1265 }
1266
1267 static void
rule_list_ptr_free(DBusList ** list)1268 rule_list_ptr_free (DBusList **list)
1269 {
1270 /* We have to cope with NULL because the hash table frees the "existing"
1271 * value (which is NULL) when creating a new table entry...
1272 */
1273 if (list != NULL)
1274 {
1275 rule_list_free (list);
1276 dbus_free (list);
1277 }
1278 }
1279
1280 BusMatchmaker*
bus_matchmaker_new(void)1281 bus_matchmaker_new (void)
1282 {
1283 BusMatchmaker *matchmaker;
1284 int i;
1285
1286 matchmaker = dbus_new0 (BusMatchmaker, 1);
1287 if (matchmaker == NULL)
1288 return NULL;
1289
1290 matchmaker->refcount = 1;
1291
1292 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1293 {
1294 RulePool *p = matchmaker->rules_by_type + i;
1295
1296 p->rules_by_iface = _dbus_hash_table_new (DBUS_HASH_STRING,
1297 dbus_free, (DBusFreeFunction) rule_list_ptr_free);
1298
1299 if (p->rules_by_iface == NULL)
1300 goto nomem;
1301 }
1302
1303 return matchmaker;
1304
1305 nomem:
1306 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1307 {
1308 RulePool *p = matchmaker->rules_by_type + i;
1309
1310 if (p->rules_by_iface == NULL)
1311 break;
1312 else
1313 _dbus_hash_table_unref (p->rules_by_iface);
1314 }
1315 dbus_free (matchmaker);
1316
1317 return NULL;
1318 }
1319
1320 static DBusList **
bus_matchmaker_get_rules(BusMatchmaker * matchmaker,int message_type,const char * interface,dbus_bool_t create)1321 bus_matchmaker_get_rules (BusMatchmaker *matchmaker,
1322 int message_type,
1323 const char *interface,
1324 dbus_bool_t create)
1325 {
1326 RulePool *p;
1327
1328 _dbus_assert (message_type >= 0);
1329 _dbus_assert (message_type < DBUS_NUM_MESSAGE_TYPES);
1330
1331 _dbus_verbose ("Looking up rules for message_type %d, interface %s\n",
1332 message_type,
1333 interface != NULL ? interface : "<null>");
1334
1335 p = matchmaker->rules_by_type + message_type;
1336
1337 if (interface == NULL)
1338 {
1339 return &p->rules_without_iface;
1340 }
1341 else
1342 {
1343 DBusList **list;
1344
1345 list = _dbus_hash_table_lookup_string (p->rules_by_iface, interface);
1346
1347 if (list == NULL && create)
1348 {
1349 char *dupped_interface;
1350
1351 list = dbus_new0 (DBusList *, 1);
1352 if (list == NULL)
1353 return NULL;
1354
1355 dupped_interface = _dbus_strdup (interface);
1356 if (dupped_interface == NULL)
1357 {
1358 dbus_free (list);
1359 return NULL;
1360 }
1361
1362 _dbus_verbose ("Adding list for type %d, iface %s\n", message_type,
1363 interface);
1364
1365 if (!_dbus_hash_table_insert_string (p->rules_by_iface,
1366 dupped_interface, list))
1367 {
1368 dbus_free (list);
1369 dbus_free (dupped_interface);
1370 return NULL;
1371 }
1372 }
1373
1374 return list;
1375 }
1376 }
1377
1378 static void
bus_matchmaker_gc_rules(BusMatchmaker * matchmaker,int message_type,const char * interface,DBusList ** rules)1379 bus_matchmaker_gc_rules (BusMatchmaker *matchmaker,
1380 int message_type,
1381 const char *interface,
1382 DBusList **rules)
1383 {
1384 RulePool *p;
1385
1386 if (interface == NULL)
1387 return;
1388
1389 if (*rules != NULL)
1390 return;
1391
1392 _dbus_verbose ("GCing HT entry for message_type %u, interface %s\n",
1393 message_type, interface);
1394
1395 p = matchmaker->rules_by_type + message_type;
1396
1397 _dbus_assert (_dbus_hash_table_lookup_string (p->rules_by_iface, interface)
1398 == rules);
1399
1400 _dbus_hash_table_remove_string (p->rules_by_iface, interface);
1401 }
1402
1403 BusMatchmaker *
bus_matchmaker_ref(BusMatchmaker * matchmaker)1404 bus_matchmaker_ref (BusMatchmaker *matchmaker)
1405 {
1406 _dbus_assert (matchmaker->refcount > 0);
1407
1408 matchmaker->refcount += 1;
1409
1410 return matchmaker;
1411 }
1412
1413 void
bus_matchmaker_unref(BusMatchmaker * matchmaker)1414 bus_matchmaker_unref (BusMatchmaker *matchmaker)
1415 {
1416 _dbus_assert (matchmaker->refcount > 0);
1417
1418 matchmaker->refcount -= 1;
1419 if (matchmaker->refcount == 0)
1420 {
1421 int i;
1422
1423 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1424 {
1425 RulePool *p = matchmaker->rules_by_type + i;
1426
1427 _dbus_hash_table_unref (p->rules_by_iface);
1428 rule_list_free (&p->rules_without_iface);
1429 }
1430
1431 dbus_free (matchmaker);
1432 }
1433 }
1434
1435 /* The rule can't be modified after it's added. */
1436 dbus_bool_t
bus_matchmaker_add_rule(BusMatchmaker * matchmaker,BusMatchRule * rule)1437 bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
1438 BusMatchRule *rule)
1439 {
1440 DBusList **rules;
1441
1442 _dbus_assert (bus_connection_is_active (rule->matches_go_to));
1443
1444 _dbus_verbose ("Adding rule with message_type %d, interface %s\n",
1445 rule->message_type,
1446 rule->interface != NULL ? rule->interface : "<null>");
1447
1448 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
1449 rule->interface, TRUE);
1450
1451 if (rules == NULL)
1452 return FALSE;
1453
1454 if (!_dbus_list_append (rules, rule))
1455 return FALSE;
1456
1457 if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
1458 {
1459 _dbus_list_remove_last (rules, rule);
1460 bus_matchmaker_gc_rules (matchmaker, rule->message_type,
1461 rule->interface, rules);
1462 return FALSE;
1463 }
1464
1465 bus_match_rule_ref (rule);
1466
1467 #ifdef DBUS_ENABLE_VERBOSE_MODE
1468 {
1469 char *s = match_rule_to_string (rule);
1470
1471 _dbus_verbose ("Added match rule %s to connection %p\n",
1472 s ? s : "nomem", rule->matches_go_to);
1473 dbus_free (s);
1474 }
1475 #endif
1476
1477 return TRUE;
1478 }
1479
1480 static dbus_bool_t
match_rule_equal(BusMatchRule * a,BusMatchRule * b)1481 match_rule_equal (BusMatchRule *a,
1482 BusMatchRule *b)
1483 {
1484 if (a->flags != b->flags)
1485 return FALSE;
1486
1487 if (a->matches_go_to != b->matches_go_to)
1488 return FALSE;
1489
1490 if ((a->flags & BUS_MATCH_MESSAGE_TYPE) &&
1491 a->message_type != b->message_type)
1492 return FALSE;
1493
1494 if ((a->flags & BUS_MATCH_MEMBER) &&
1495 strcmp (a->member, b->member) != 0)
1496 return FALSE;
1497
1498 if ((a->flags & BUS_MATCH_PATH) &&
1499 strcmp (a->path, b->path) != 0)
1500 return FALSE;
1501
1502 if ((a->flags & BUS_MATCH_INTERFACE) &&
1503 strcmp (a->interface, b->interface) != 0)
1504 return FALSE;
1505
1506 if ((a->flags & BUS_MATCH_SENDER) &&
1507 strcmp (a->sender, b->sender) != 0)
1508 return FALSE;
1509
1510 if ((a->flags & BUS_MATCH_DESTINATION) &&
1511 strcmp (a->destination, b->destination) != 0)
1512 return FALSE;
1513
1514 /* we already compared the value of flags, and
1515 * BUS_MATCH_CLIENT_IS_EAVESDROPPING does not have another struct member */
1516
1517 if (a->flags & BUS_MATCH_ARGS)
1518 {
1519 int i;
1520
1521 if (a->args_len != b->args_len)
1522 return FALSE;
1523
1524 i = 0;
1525 while (i < a->args_len)
1526 {
1527 int length;
1528
1529 if ((a->args[i] != NULL) != (b->args[i] != NULL))
1530 return FALSE;
1531
1532 if (a->arg_lens[i] != b->arg_lens[i])
1533 return FALSE;
1534
1535 length = a->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS;
1536
1537 if (a->args[i] != NULL)
1538 {
1539 _dbus_assert (b->args[i] != NULL);
1540 if (memcmp (a->args[i], b->args[i], length) != 0)
1541 return FALSE;
1542 }
1543
1544 ++i;
1545 }
1546 }
1547
1548 return TRUE;
1549 }
1550
1551 static void
bus_matchmaker_remove_rule_link(DBusList ** rules,DBusList * link)1552 bus_matchmaker_remove_rule_link (DBusList **rules,
1553 DBusList *link)
1554 {
1555 BusMatchRule *rule = link->data;
1556
1557 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1558 _dbus_list_remove_link (rules, link);
1559
1560 #ifdef DBUS_ENABLE_VERBOSE_MODE
1561 {
1562 char *s = match_rule_to_string (rule);
1563
1564 _dbus_verbose ("Removed match rule %s for connection %p\n",
1565 s ? s : "nomem", rule->matches_go_to);
1566 dbus_free (s);
1567 }
1568 #endif
1569
1570 bus_match_rule_unref (rule);
1571 }
1572
1573 void
bus_matchmaker_remove_rule(BusMatchmaker * matchmaker,BusMatchRule * rule)1574 bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
1575 BusMatchRule *rule)
1576 {
1577 DBusList **rules;
1578
1579 _dbus_verbose ("Removing rule with message_type %d, interface %s\n",
1580 rule->message_type,
1581 rule->interface != NULL ? rule->interface : "<null>");
1582
1583 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1584
1585 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
1586 rule->interface, FALSE);
1587
1588 /* We should only be asked to remove a rule by identity right after it was
1589 * added, so there should be a list for it.
1590 */
1591 _dbus_assert (rules != NULL);
1592
1593 _dbus_list_remove (rules, rule);
1594 bus_matchmaker_gc_rules (matchmaker, rule->message_type, rule->interface,
1595 rules);
1596
1597 #ifdef DBUS_ENABLE_VERBOSE_MODE
1598 {
1599 char *s = match_rule_to_string (rule);
1600
1601 _dbus_verbose ("Removed match rule %s for connection %p\n",
1602 s ? s : "nomem", rule->matches_go_to);
1603 dbus_free (s);
1604 }
1605 #endif
1606
1607 bus_match_rule_unref (rule);
1608 }
1609
1610 /* Remove a single rule which is equal to the given rule by value */
1611 dbus_bool_t
bus_matchmaker_remove_rule_by_value(BusMatchmaker * matchmaker,BusMatchRule * value,DBusError * error)1612 bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker,
1613 BusMatchRule *value,
1614 DBusError *error)
1615 {
1616 DBusList **rules;
1617 DBusList *link = NULL;
1618
1619 _dbus_verbose ("Removing rule by value with message_type %d, interface %s\n",
1620 value->message_type,
1621 value->interface != NULL ? value->interface : "<null>");
1622
1623 rules = bus_matchmaker_get_rules (matchmaker, value->message_type,
1624 value->interface, FALSE);
1625
1626 if (rules != NULL)
1627 {
1628 /* we traverse backward because bus_connection_remove_match_rule()
1629 * removes the most-recently-added rule
1630 */
1631 link = _dbus_list_get_last_link (rules);
1632 while (link != NULL)
1633 {
1634 BusMatchRule *rule;
1635 DBusList *prev;
1636
1637 rule = link->data;
1638 prev = _dbus_list_get_prev_link (rules, link);
1639
1640 if (match_rule_equal (rule, value))
1641 {
1642 bus_matchmaker_remove_rule_link (rules, link);
1643 break;
1644 }
1645
1646 link = prev;
1647 }
1648 }
1649
1650 if (link == NULL)
1651 {
1652 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND,
1653 "The given match rule wasn't found and can't be removed");
1654 return FALSE;
1655 }
1656
1657 bus_matchmaker_gc_rules (matchmaker, value->message_type, value->interface,
1658 rules);
1659
1660 return TRUE;
1661 }
1662
1663 static void
rule_list_remove_by_connection(DBusList ** rules,DBusConnection * connection)1664 rule_list_remove_by_connection (DBusList **rules,
1665 DBusConnection *connection)
1666 {
1667 DBusList *link;
1668
1669 link = _dbus_list_get_first_link (rules);
1670 while (link != NULL)
1671 {
1672 BusMatchRule *rule;
1673 DBusList *next;
1674
1675 rule = link->data;
1676 next = _dbus_list_get_next_link (rules, link);
1677
1678 if (rule->matches_go_to == connection)
1679 {
1680 bus_matchmaker_remove_rule_link (rules, link);
1681 }
1682 else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
1683 ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
1684 {
1685 /* The rule matches to/from a base service, see if it's the
1686 * one being disconnected, since we know this service name
1687 * will never be recycled.
1688 */
1689 const char *name;
1690
1691 name = bus_connection_get_name (connection);
1692 _dbus_assert (name != NULL); /* because we're an active connection */
1693
1694 if (((rule->flags & BUS_MATCH_SENDER) &&
1695 strcmp (rule->sender, name) == 0) ||
1696 ((rule->flags & BUS_MATCH_DESTINATION) &&
1697 strcmp (rule->destination, name) == 0))
1698 {
1699 bus_matchmaker_remove_rule_link (rules, link);
1700 }
1701 }
1702
1703 link = next;
1704 }
1705 }
1706
1707 void
bus_matchmaker_disconnected(BusMatchmaker * matchmaker,DBusConnection * connection)1708 bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
1709 DBusConnection *connection)
1710 {
1711 int i;
1712
1713 /* FIXME
1714 *
1715 * This scans all match rules on the bus. We could avoid that
1716 * for the rules belonging to the connection, since we keep
1717 * a list of those; but for the rules that just refer to
1718 * the connection we'd need to do something more elaborate.
1719 */
1720
1721 _dbus_assert (bus_connection_is_active (connection));
1722
1723 _dbus_verbose ("Removing all rules for connection %p\n", connection);
1724
1725 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1726 {
1727 RulePool *p = matchmaker->rules_by_type + i;
1728 DBusHashIter iter;
1729
1730 rule_list_remove_by_connection (&p->rules_without_iface, connection);
1731
1732 _dbus_hash_iter_init (p->rules_by_iface, &iter);
1733 while (_dbus_hash_iter_next (&iter))
1734 {
1735 DBusList **items = _dbus_hash_iter_get_value (&iter);
1736
1737 rule_list_remove_by_connection (items, connection);
1738
1739 if (*items == NULL)
1740 _dbus_hash_iter_remove_entry (&iter);
1741 }
1742 }
1743 }
1744
1745 static dbus_bool_t
connection_is_primary_owner(DBusConnection * connection,const char * service_name)1746 connection_is_primary_owner (DBusConnection *connection,
1747 const char *service_name)
1748 {
1749 BusService *service;
1750 DBusString str;
1751 BusRegistry *registry;
1752
1753 _dbus_assert (connection != NULL);
1754
1755 registry = bus_connection_get_registry (connection);
1756
1757 _dbus_string_init_const (&str, service_name);
1758 service = bus_registry_lookup (registry, &str);
1759
1760 if (service == NULL)
1761 return FALSE; /* Service doesn't exist so connection can't own it. */
1762
1763 return bus_service_get_primary_owners_connection (service) == connection;
1764 }
1765
1766 static dbus_bool_t
str_has_prefix(const char * str,const char * prefix)1767 str_has_prefix (const char *str, const char *prefix)
1768 {
1769 size_t prefix_len;
1770 prefix_len = strlen (prefix);
1771 if (strncmp (str, prefix, prefix_len) == 0)
1772 return TRUE;
1773 else
1774 return FALSE;
1775 }
1776
1777 static dbus_bool_t
match_rule_matches(BusMatchRule * rule,DBusConnection * sender,DBusConnection * addressed_recipient,DBusMessage * message,BusMatchFlags already_matched)1778 match_rule_matches (BusMatchRule *rule,
1779 DBusConnection *sender,
1780 DBusConnection *addressed_recipient,
1781 DBusMessage *message,
1782 BusMatchFlags already_matched)
1783 {
1784 dbus_bool_t wants_to_eavesdrop = FALSE;
1785 int flags;
1786
1787 /* All features of the match rule are AND'd together,
1788 * so FALSE if any of them don't match.
1789 */
1790
1791 /* sender/addressed_recipient of #NULL may mean bus driver,
1792 * or for addressed_recipient may mean a message with no
1793 * specific recipient (i.e. a signal)
1794 */
1795
1796 /* Don't bother re-matching features we've already checked implicitly. */
1797 flags = rule->flags & (~already_matched);
1798
1799 if (flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING)
1800 wants_to_eavesdrop = TRUE;
1801
1802 if (flags & BUS_MATCH_MESSAGE_TYPE)
1803 {
1804 _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
1805
1806 if (rule->message_type != dbus_message_get_type (message))
1807 return FALSE;
1808 }
1809
1810 if (flags & BUS_MATCH_INTERFACE)
1811 {
1812 const char *iface;
1813
1814 _dbus_assert (rule->interface != NULL);
1815
1816 iface = dbus_message_get_interface (message);
1817 if (iface == NULL)
1818 return FALSE;
1819
1820 if (strcmp (iface, rule->interface) != 0)
1821 return FALSE;
1822 }
1823
1824 if (flags & BUS_MATCH_MEMBER)
1825 {
1826 const char *member;
1827
1828 _dbus_assert (rule->member != NULL);
1829
1830 member = dbus_message_get_member (message);
1831 if (member == NULL)
1832 return FALSE;
1833
1834 if (strcmp (member, rule->member) != 0)
1835 return FALSE;
1836 }
1837
1838 if (flags & BUS_MATCH_SENDER)
1839 {
1840 _dbus_assert (rule->sender != NULL);
1841
1842 if (sender == NULL)
1843 {
1844 if (strcmp (rule->sender,
1845 DBUS_SERVICE_DBUS) != 0)
1846 return FALSE;
1847 }
1848 else
1849 {
1850 if (!connection_is_primary_owner (sender, rule->sender))
1851 return FALSE;
1852 }
1853 }
1854
1855 /* Note: this part is relevant for eavesdropper rules:
1856 * Two cases:
1857 * 1) rule has a destination to be matched
1858 * (flag BUS_MATCH_DESTINATION present). Rule will match if:
1859 * - rule->destination matches the addressed_recipient
1860 * AND
1861 * - wants_to_eavesdrop=TRUE
1862 *
1863 * Note: (the case in which addressed_recipient is the actual rule owner
1864 * is handled elsewere in dispatch.c:bus_dispatch_matches().
1865 *
1866 * 2) rule has no destination. Rule will match if:
1867 * - message has no specified destination (ie broadcasts)
1868 * (Note: this will rule out unicast method calls and unicast signals,
1869 * fixing FDO#269748)
1870 * OR
1871 * - wants_to_eavesdrop=TRUE (destination-catch-all situation)
1872 */
1873 if (flags & BUS_MATCH_DESTINATION)
1874 {
1875 const char *destination;
1876
1877 _dbus_assert (rule->destination != NULL);
1878
1879 destination = dbus_message_get_destination (message);
1880 if (destination == NULL)
1881 /* broadcast, but this rule specified a destination: no match */
1882 return FALSE;
1883
1884 /* rule owner does not intend to eavesdrop: we'll deliver only msgs
1885 * directed to it, NOT MATCHING */
1886 if (!wants_to_eavesdrop)
1887 return FALSE;
1888
1889 if (addressed_recipient == NULL)
1890 {
1891 /* If the message is going to be delivered to the dbus-daemon
1892 * itself, its destination will be "org.freedesktop.DBus",
1893 * which we again match against the rule (see bus_dispatch()
1894 * in bus/dispatch.c, which checks for o.fd.DBus first).
1895 *
1896 * If we are monitoring and we don't know who is going to receive
1897 * the message (for instance because they haven't been activated yet),
1898 * assume they will own the requested destination name and no other,
1899 * and match the rule's destination against that.
1900 */
1901 if (strcmp (rule->destination, destination) != 0)
1902 return FALSE;
1903 }
1904 else
1905 {
1906 if (!connection_is_primary_owner (addressed_recipient, rule->destination))
1907 return FALSE;
1908 }
1909 } else { /* no destination in rule */
1910 dbus_bool_t msg_is_broadcast;
1911
1912 _dbus_assert (rule->destination == NULL);
1913
1914 msg_is_broadcast = (dbus_message_get_destination (message) == NULL);
1915
1916 if (!wants_to_eavesdrop && !msg_is_broadcast)
1917 return FALSE;
1918
1919 /* if we are here rule owner intends to eavesdrop
1920 * OR
1921 * message is being broadcasted */
1922 }
1923
1924 if (flags & BUS_MATCH_PATH)
1925 {
1926 const char *path;
1927
1928 _dbus_assert (rule->path != NULL);
1929
1930 path = dbus_message_get_path (message);
1931 if (path == NULL)
1932 return FALSE;
1933
1934 if (strcmp (path, rule->path) != 0)
1935 return FALSE;
1936 }
1937
1938 if (flags & BUS_MATCH_PATH_NAMESPACE)
1939 {
1940 const char *path;
1941 int len;
1942
1943 _dbus_assert (rule->path != NULL);
1944
1945 path = dbus_message_get_path (message);
1946 if (path == NULL)
1947 return FALSE;
1948
1949 if (!str_has_prefix (path, rule->path))
1950 return FALSE;
1951
1952 len = strlen (rule->path);
1953
1954 /* Check that the actual argument is within the expected
1955 * namespace, rather than just starting with that string,
1956 * by checking that the matched prefix is followed by a '/'
1957 * or the end of the path.
1958 *
1959 * Special case: the only valid path of length 1, "/",
1960 * matches everything.
1961 */
1962 if (len > 1 && path[len] != '\0' && path[len] != '/')
1963 return FALSE;
1964 }
1965
1966 if (flags & BUS_MATCH_ARGS)
1967 {
1968 int i;
1969 DBusMessageIter iter;
1970
1971 _dbus_assert (rule->args != NULL);
1972
1973 dbus_message_iter_init (message, &iter);
1974
1975 i = 0;
1976 while (i < rule->args_len)
1977 {
1978 int current_type;
1979 const char *expected_arg;
1980 int expected_length;
1981 dbus_bool_t is_path, is_namespace;
1982
1983 expected_arg = rule->args[i];
1984 expected_length = rule->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS;
1985 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
1986 is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
1987
1988 current_type = dbus_message_iter_get_arg_type (&iter);
1989
1990 if (expected_arg != NULL)
1991 {
1992 const char *actual_arg;
1993 int actual_length;
1994
1995 if (current_type != DBUS_TYPE_STRING &&
1996 (!is_path || current_type != DBUS_TYPE_OBJECT_PATH))
1997 return FALSE;
1998
1999 actual_arg = NULL;
2000 dbus_message_iter_get_basic (&iter, &actual_arg);
2001 _dbus_assert (actual_arg != NULL);
2002
2003 actual_length = strlen (actual_arg);
2004
2005 if (is_path)
2006 {
2007 if (actual_length < expected_length &&
2008 actual_arg[actual_length - 1] != '/')
2009 return FALSE;
2010
2011 if (expected_length < actual_length &&
2012 expected_arg[expected_length - 1] != '/')
2013 return FALSE;
2014
2015 if (memcmp (actual_arg, expected_arg,
2016 MIN (actual_length, expected_length)) != 0)
2017 return FALSE;
2018 }
2019 else if (is_namespace)
2020 {
2021 if (expected_length > actual_length)
2022 return FALSE;
2023
2024 /* If the actual argument doesn't start with the expected
2025 * namespace, then we don't match.
2026 */
2027 if (memcmp (expected_arg, actual_arg, expected_length) != 0)
2028 return FALSE;
2029
2030 if (expected_length < actual_length)
2031 {
2032 /* Check that the actual argument is within the expected
2033 * namespace, rather than just starting with that string,
2034 * by checking that the matched prefix ends in a '.'.
2035 *
2036 * This doesn't stop "foo.bar." matching "foo.bar..baz"
2037 * which is an invalid namespace, but at some point the
2038 * daemon can't cover up for broken services.
2039 */
2040 if (actual_arg[expected_length] != '.')
2041 return FALSE;
2042 }
2043 /* otherwise we had an exact match. */
2044 }
2045 else
2046 {
2047 if (expected_length != actual_length ||
2048 memcmp (expected_arg, actual_arg, expected_length) != 0)
2049 return FALSE;
2050 }
2051
2052 }
2053
2054 if (current_type != DBUS_TYPE_INVALID)
2055 dbus_message_iter_next (&iter);
2056
2057 ++i;
2058 }
2059 }
2060
2061 return TRUE;
2062 }
2063
2064 static dbus_bool_t
get_recipients_from_list(DBusList ** rules,DBusConnection * sender,DBusConnection * addressed_recipient,DBusMessage * message,DBusList ** recipients_p)2065 get_recipients_from_list (DBusList **rules,
2066 DBusConnection *sender,
2067 DBusConnection *addressed_recipient,
2068 DBusMessage *message,
2069 DBusList **recipients_p)
2070 {
2071 DBusList *link;
2072
2073 if (rules == NULL)
2074 return TRUE;
2075
2076 link = _dbus_list_get_first_link (rules);
2077 while (link != NULL)
2078 {
2079 BusMatchRule *rule;
2080
2081 rule = link->data;
2082
2083 #ifdef DBUS_ENABLE_VERBOSE_MODE
2084 {
2085 char *s = match_rule_to_string (rule);
2086
2087 _dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
2088 s ? s : "nomem", rule->matches_go_to);
2089 dbus_free (s);
2090 }
2091 #endif
2092
2093 if (match_rule_matches (rule,
2094 sender, addressed_recipient, message,
2095 BUS_MATCH_MESSAGE_TYPE | BUS_MATCH_INTERFACE))
2096 {
2097 _dbus_verbose ("Rule matched\n");
2098
2099 /* Append to the list if we haven't already */
2100 if (bus_connection_mark_stamp (rule->matches_go_to))
2101 {
2102 if (!_dbus_list_append (recipients_p, rule->matches_go_to))
2103 return FALSE;
2104 }
2105 else
2106 {
2107 _dbus_verbose ("Connection already receiving this message, so not adding again\n");
2108 }
2109 }
2110
2111 link = _dbus_list_get_next_link (rules, link);
2112 }
2113
2114 return TRUE;
2115 }
2116
2117 dbus_bool_t
bus_matchmaker_get_recipients(BusMatchmaker * matchmaker,BusConnections * connections,DBusConnection * sender,DBusConnection * addressed_recipient,DBusMessage * message,DBusList ** recipients_p)2118 bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
2119 BusConnections *connections,
2120 DBusConnection *sender,
2121 DBusConnection *addressed_recipient,
2122 DBusMessage *message,
2123 DBusList **recipients_p)
2124 {
2125 int type;
2126 const char *interface;
2127 DBusList **neither, **just_type, **just_iface, **both;
2128
2129 _dbus_assert (*recipients_p == NULL);
2130
2131 /* This avoids sending same message to the same connection twice.
2132 * Purpose of the stamp instead of a bool is to avoid iterating over
2133 * all connections resetting the bool each time.
2134 */
2135 bus_connections_increment_stamp (connections);
2136
2137 /* addressed_recipient is already receiving the message, don't add to list.
2138 * NULL addressed_recipient means either bus driver, or this is a signal
2139 * and thus lacks a specific addressed_recipient.
2140 */
2141 if (addressed_recipient != NULL)
2142 bus_connection_mark_stamp (addressed_recipient);
2143
2144 type = dbus_message_get_type (message);
2145 interface = dbus_message_get_interface (message);
2146
2147 neither = bus_matchmaker_get_rules (matchmaker, DBUS_MESSAGE_TYPE_INVALID,
2148 NULL, FALSE);
2149 just_type = just_iface = both = NULL;
2150
2151 if (interface != NULL)
2152 just_iface = bus_matchmaker_get_rules (matchmaker,
2153 DBUS_MESSAGE_TYPE_INVALID, interface, FALSE);
2154
2155 if (type > DBUS_MESSAGE_TYPE_INVALID && type < DBUS_NUM_MESSAGE_TYPES)
2156 {
2157 just_type = bus_matchmaker_get_rules (matchmaker, type, NULL, FALSE);
2158
2159 if (interface != NULL)
2160 both = bus_matchmaker_get_rules (matchmaker, type, interface, FALSE);
2161 }
2162
2163 if (!(get_recipients_from_list (neither, sender, addressed_recipient,
2164 message, recipients_p) &&
2165 get_recipients_from_list (just_iface, sender, addressed_recipient,
2166 message, recipients_p) &&
2167 get_recipients_from_list (just_type, sender, addressed_recipient,
2168 message, recipients_p) &&
2169 get_recipients_from_list (both, sender, addressed_recipient,
2170 message, recipients_p)))
2171 {
2172 _dbus_list_clear (recipients_p);
2173 return FALSE;
2174 }
2175
2176 return TRUE;
2177 }
2178
2179 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
2180 #include "test.h"
2181 #include <stdlib.h>
2182
2183 static BusMatchRule*
check_parse(dbus_bool_t should_succeed,const char * text)2184 check_parse (dbus_bool_t should_succeed,
2185 const char *text)
2186 {
2187 BusMatchRule *rule;
2188 DBusString str;
2189 DBusError error;
2190
2191 dbus_error_init (&error);
2192
2193 _dbus_string_init_const (&str, text);
2194
2195 rule = bus_match_rule_parse (NULL, &str, &error);
2196 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
2197 {
2198 dbus_error_free (&error);
2199 return NULL;
2200 }
2201
2202 if (should_succeed && rule == NULL)
2203 {
2204 _dbus_warn ("Failed to parse: %s: %s: \"%s\"",
2205 error.name, error.message,
2206 _dbus_string_get_const_data (&str));
2207 exit (1);
2208 }
2209
2210 if (!should_succeed && rule != NULL)
2211 {
2212 _dbus_warn ("Failed to fail to parse: \"%s\"",
2213 _dbus_string_get_const_data (&str));
2214 exit (1);
2215 }
2216
2217 dbus_error_free (&error);
2218
2219 return rule;
2220 }
2221
2222 static void
assert_large_rule(BusMatchRule * rule)2223 assert_large_rule (BusMatchRule *rule)
2224 {
2225 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
2226 _dbus_assert (rule->flags & BUS_MATCH_SENDER);
2227 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
2228 _dbus_assert (rule->flags & BUS_MATCH_MEMBER);
2229 _dbus_assert (rule->flags & BUS_MATCH_DESTINATION);
2230 _dbus_assert (rule->flags & BUS_MATCH_PATH);
2231
2232 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
2233 _dbus_assert (rule->interface != NULL);
2234 _dbus_assert (rule->member != NULL);
2235 _dbus_assert (rule->sender != NULL);
2236 _dbus_assert (rule->destination != NULL);
2237 _dbus_assert (rule->path != NULL);
2238
2239 _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0);
2240 _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0);
2241 _dbus_assert (strcmp (rule->member, "Foo") == 0);
2242 _dbus_assert (strcmp (rule->path, "/bar/foo") == 0);
2243 _dbus_assert (strcmp (rule->destination, ":452345.34") == 0);
2244 }
2245
2246 static dbus_bool_t
test_parsing(void * data)2247 test_parsing (void *data)
2248 {
2249 BusMatchRule *rule;
2250
2251 rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345.34'");
2252 if (rule != NULL)
2253 {
2254 assert_large_rule (rule);
2255 bus_match_rule_unref (rule);
2256 }
2257
2258 /* With extra whitespace and useless quotes */
2259 rule = check_parse (TRUE, " type='signal', \tsender='org.freedes''ktop.DBusSender', interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345.34'''''");
2260 if (rule != NULL)
2261 {
2262 assert_large_rule (rule);
2263 bus_match_rule_unref (rule);
2264 }
2265
2266
2267 /* A simple signal connection */
2268 rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'");
2269 if (rule != NULL)
2270 {
2271 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
2272 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
2273 _dbus_assert (rule->flags & BUS_MATCH_PATH);
2274
2275 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
2276 _dbus_assert (rule->interface != NULL);
2277 _dbus_assert (rule->path != NULL);
2278
2279 _dbus_assert (strcmp (rule->interface, "org.Bar") == 0);
2280 _dbus_assert (strcmp (rule->path, "/foo") == 0);
2281
2282 bus_match_rule_unref (rule);
2283 }
2284
2285 /* argN */
2286 rule = check_parse (TRUE, "arg0='foo'");
2287 if (rule != NULL)
2288 {
2289 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2290 _dbus_assert (rule->args != NULL);
2291 _dbus_assert (rule->args_len == 1);
2292 _dbus_assert (rule->args[0] != NULL);
2293 _dbus_assert (rule->args[1] == NULL);
2294 _dbus_assert (strcmp (rule->args[0], "foo") == 0);
2295
2296 bus_match_rule_unref (rule);
2297 }
2298
2299 rule = check_parse (TRUE, "arg1='foo'");
2300 if (rule != NULL)
2301 {
2302 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2303 _dbus_assert (rule->args != NULL);
2304 _dbus_assert (rule->args_len == 2);
2305 _dbus_assert (rule->args[0] == NULL);
2306 _dbus_assert (rule->args[1] != NULL);
2307 _dbus_assert (rule->args[2] == NULL);
2308 _dbus_assert (strcmp (rule->args[1], "foo") == 0);
2309
2310 bus_match_rule_unref (rule);
2311 }
2312
2313 rule = check_parse (TRUE, "arg2='foo'");
2314 if (rule != NULL)
2315 {
2316 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2317 _dbus_assert (rule->args != NULL);
2318 _dbus_assert (rule->args_len == 3);
2319 _dbus_assert (rule->args[0] == NULL);
2320 _dbus_assert (rule->args[1] == NULL);
2321 _dbus_assert (rule->args[2] != NULL);
2322 _dbus_assert (rule->args[3] == NULL);
2323 _dbus_assert (strcmp (rule->args[2], "foo") == 0);
2324
2325 bus_match_rule_unref (rule);
2326 }
2327
2328 rule = check_parse (TRUE, "arg40='foo'");
2329 if (rule != NULL)
2330 {
2331 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2332 _dbus_assert (rule->args != NULL);
2333 _dbus_assert (rule->args_len == 41);
2334 _dbus_assert (rule->args[0] == NULL);
2335 _dbus_assert (rule->args[1] == NULL);
2336 _dbus_assert (rule->args[40] != NULL);
2337 _dbus_assert (rule->args[41] == NULL);
2338 _dbus_assert (strcmp (rule->args[40], "foo") == 0);
2339
2340 bus_match_rule_unref (rule);
2341 }
2342
2343 rule = check_parse (TRUE, "arg63='foo'");
2344 if (rule != NULL)
2345 {
2346 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2347 _dbus_assert (rule->args != NULL);
2348 _dbus_assert (rule->args_len == 64);
2349 _dbus_assert (rule->args[0] == NULL);
2350 _dbus_assert (rule->args[1] == NULL);
2351 _dbus_assert (rule->args[63] != NULL);
2352 _dbus_assert (rule->args[64] == NULL);
2353 _dbus_assert (strcmp (rule->args[63], "foo") == 0);
2354
2355 bus_match_rule_unref (rule);
2356 }
2357
2358 rule = check_parse (TRUE, "arg7path='/foo'");
2359 if (rule != NULL)
2360 {
2361 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2362 _dbus_assert (rule->args != NULL);
2363 _dbus_assert (rule->args_len == 8);
2364 _dbus_assert (rule->args[7] != NULL);
2365 _dbus_assert (rule->args[8] == NULL);
2366 _dbus_assert (strcmp (rule->args[7], "/foo") == 0);
2367 _dbus_assert ((rule->arg_lens[7] & BUS_MATCH_ARG_IS_PATH)
2368 == BUS_MATCH_ARG_IS_PATH);
2369
2370 bus_match_rule_unref (rule);
2371 }
2372
2373 /* Arg 0 namespace matches */
2374 rule = check_parse (TRUE, "arg0namespace='foo'");
2375 if (rule != NULL)
2376 {
2377 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2378 _dbus_assert (rule->args != NULL);
2379 _dbus_assert (rule->args_len == 1);
2380 _dbus_assert (strcmp (rule->args[0], "foo") == 0);
2381 _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE)
2382 == BUS_MATCH_ARG_NAMESPACE);
2383
2384 bus_match_rule_unref (rule);
2385 }
2386
2387 rule = check_parse (TRUE, "arg0namespace='foo.bar'");
2388 if (rule != NULL)
2389 {
2390 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2391 _dbus_assert (rule->args != NULL);
2392 _dbus_assert (rule->args_len == 1);
2393 _dbus_assert (strcmp (rule->args[0], "foo.bar") == 0);
2394 _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE)
2395 == BUS_MATCH_ARG_NAMESPACE);
2396
2397 bus_match_rule_unref (rule);
2398 }
2399
2400 /* Only arg0namespace is supported. */
2401 rule = check_parse (FALSE, "arg1namespace='foo'");
2402 _dbus_assert (rule == NULL);
2403
2404 /* An empty string isn't a valid namespace prefix (you should just not
2405 * specify this key at all).
2406 */
2407 rule = check_parse (FALSE, "arg0namespace=''");
2408 _dbus_assert (rule == NULL);
2409
2410 /* Trailing periods aren't allowed (earlier versions of the arg0namespace
2411 * spec allowed a single trailing period, which altered the semantics) */
2412 rule = check_parse (FALSE, "arg0namespace='foo.'");
2413 _dbus_assert (rule == NULL);
2414
2415 rule = check_parse (FALSE, "arg0namespace='foo.bar.'");
2416 _dbus_assert (rule == NULL);
2417
2418 rule = check_parse (FALSE, "arg0namespace='foo..'");
2419 _dbus_assert (rule == NULL);
2420
2421 rule = check_parse (FALSE, "arg0namespace='foo.bar..'");
2422 _dbus_assert (rule == NULL);
2423
2424 /* Too-large argN */
2425 rule = check_parse (FALSE, "arg300='foo'");
2426 _dbus_assert (rule == NULL);
2427 rule = check_parse (FALSE, "arg64='foo'");
2428 _dbus_assert (rule == NULL);
2429
2430 /* No N in argN */
2431 rule = check_parse (FALSE, "arg='foo'");
2432 _dbus_assert (rule == NULL);
2433 rule = check_parse (FALSE, "argv='foo'");
2434 _dbus_assert (rule == NULL);
2435 rule = check_parse (FALSE, "arg3junk='foo'");
2436 _dbus_assert (rule == NULL);
2437 rule = check_parse (FALSE, "argument='foo'");
2438 _dbus_assert (rule == NULL);
2439
2440 /* Reject duplicates */
2441 rule = check_parse (FALSE, "type='signal',type='method_call'");
2442 _dbus_assert (rule == NULL);
2443
2444 rule = check_parse (TRUE, "path_namespace='/foo/bar'");
2445 if (rule != NULL)
2446 {
2447 _dbus_assert (rule->flags == BUS_MATCH_PATH_NAMESPACE);
2448 _dbus_assert (rule->path != NULL);
2449 _dbus_assert (strcmp (rule->path, "/foo/bar") == 0);
2450
2451 bus_match_rule_unref (rule);
2452 }
2453
2454 /* Almost a duplicate */
2455 rule = check_parse (FALSE, "path='/foo',path_namespace='/foo'");
2456 _dbus_assert (rule == NULL);
2457
2458 /* Trailing / was supported in the initial proposal, but now isn't */
2459 rule = check_parse (FALSE, "path_namespace='/foo/'");
2460 _dbus_assert (rule == NULL);
2461
2462 /* Duplicates with the argN code */
2463 rule = check_parse (FALSE, "arg0='foo',arg0='bar'");
2464 _dbus_assert (rule == NULL);
2465 rule = check_parse (FALSE, "arg3='foo',arg3='bar'");
2466 _dbus_assert (rule == NULL);
2467 rule = check_parse (FALSE, "arg30='foo',arg30='bar'");
2468 _dbus_assert (rule == NULL);
2469
2470 /* Reject broken keys */
2471 rule = check_parse (FALSE, "blah='signal'");
2472 _dbus_assert (rule == NULL);
2473
2474 /* Reject broken values */
2475 rule = check_parse (FALSE, "type='chouin'");
2476 _dbus_assert (rule == NULL);
2477 rule = check_parse (FALSE, "interface='abc@def++'");
2478 _dbus_assert (rule == NULL);
2479 rule = check_parse (FALSE, "service='youpi'");
2480 _dbus_assert (rule == NULL);
2481
2482 /* Allow empty rule */
2483 rule = check_parse (TRUE, "");
2484 if (rule != NULL)
2485 {
2486 _dbus_assert (rule->flags == 0);
2487
2488 bus_match_rule_unref (rule);
2489 }
2490
2491 /* All-whitespace rule is the same as empty */
2492 rule = check_parse (TRUE, " \t");
2493 if (rule != NULL)
2494 {
2495 _dbus_assert (rule->flags == 0);
2496
2497 bus_match_rule_unref (rule);
2498 }
2499
2500 /* But with non-whitespace chars and no =value, it's not OK */
2501 rule = check_parse (FALSE, "type");
2502 _dbus_assert (rule == NULL);
2503
2504 return TRUE;
2505 }
2506
2507 static struct {
2508 const char *first;
2509 const char *second;
2510 } equality_tests[] = {
2511 { "type='signal'", "type='signal'" },
2512 { "type='signal',interface='foo.bar'", "interface='foo.bar',type='signal'" },
2513 { "type='signal',member='bar'", "member='bar',type='signal'" },
2514 { "type='method_call',sender=':1.0'", "sender=':1.0',type='method_call'" },
2515 { "type='method_call',destination=':1.0'", "destination=':1.0',type='method_call'" },
2516 { "type='method_call',path='/foo/bar'", "path='/foo/bar',type='method_call'" },
2517 { "type='method_call',arg0='blah'", "arg0='blah',type='method_call'" },
2518 { "type='method_call',arg0='boo'", "arg0='boo',type='method_call'" },
2519 { "type='method_call',arg0='blah',arg1='baz'", "arg0='blah',arg1='baz',type='method_call'" },
2520 { "type='method_call',arg3='foosh'", "arg3='foosh',type='method_call'" },
2521 { "arg3='fool'", "arg3='fool'" },
2522 { "arg0namespace='fool'", "arg0namespace='fool'" },
2523 { "member='food'", "member='food'" },
2524 { "member=escape", "member='escape'" },
2525 { "member=icecream", "member=ice'cream'" },
2526 { "arg0='comma,type=comma',type=signal", "type=signal,arg0='comma,type=comma'" },
2527 { "arg0=escap\\e", "arg0='escap\\e'" },
2528 { "arg0=Time: 8 o\\'clock", "arg0='Time: 8 o'\\''clock'" },
2529 };
2530
2531 static void
test_equality(void)2532 test_equality (void)
2533 {
2534 int i;
2535
2536 i = 0;
2537 while (i < _DBUS_N_ELEMENTS (equality_tests))
2538 {
2539 BusMatchRule *first;
2540 BusMatchRule *second;
2541 char *first_str, *second_str;
2542 BusMatchRule *first_reparsed, *second_reparsed;
2543 int j;
2544
2545 first = check_parse (TRUE, equality_tests[i].first);
2546 _dbus_assert (first != NULL);
2547 second = check_parse (TRUE, equality_tests[i].second);
2548 _dbus_assert (second != NULL);
2549
2550 if (!match_rule_equal (first, second))
2551 {
2552 _dbus_warn ("rule %s and %s should have been equal",
2553 equality_tests[i].first,
2554 equality_tests[i].second);
2555 exit (1);
2556 }
2557
2558 /* Check match_rule_to_string */
2559 first_str = match_rule_to_string (first);
2560 _dbus_assert (first_str != NULL);
2561 second_str = match_rule_to_string (second);
2562 _dbus_assert (second_str != NULL);
2563 _dbus_assert (strcmp (first_str, second_str) == 0);
2564 first_reparsed = check_parse (TRUE, first_str);
2565 _dbus_assert (first_reparsed != NULL);
2566 second_reparsed = check_parse (TRUE, second_str);
2567 _dbus_assert (second_reparsed != NULL);
2568 _dbus_assert (match_rule_equal (first, first_reparsed));
2569 _dbus_assert (match_rule_equal (second, second_reparsed));
2570 bus_match_rule_unref (first_reparsed);
2571 bus_match_rule_unref (second_reparsed);
2572 dbus_free (first_str);
2573 dbus_free (second_str);
2574
2575 bus_match_rule_unref (second);
2576
2577 /* Check that the rule is not equal to any of the
2578 * others besides its pair match
2579 */
2580 j = 0;
2581 while (j < _DBUS_N_ELEMENTS (equality_tests))
2582 {
2583 if (i != j)
2584 {
2585 second = check_parse (TRUE, equality_tests[j].second);
2586 _dbus_assert (second != NULL);
2587
2588 if (match_rule_equal (first, second))
2589 {
2590 _dbus_warn ("rule %s and %s should not have been equal",
2591 equality_tests[i].first,
2592 equality_tests[j].second);
2593 exit (1);
2594 }
2595
2596 bus_match_rule_unref (second);
2597 }
2598
2599 ++j;
2600 }
2601
2602 bus_match_rule_unref (first);
2603
2604 ++i;
2605 }
2606 }
2607
2608 static const char*
2609 should_match_message_1[] = {
2610 "type='signal'",
2611 "member='Frobated'",
2612 "arg0='foobar'",
2613 "type='signal',member='Frobated'",
2614 "type='signal',member='Frobated',arg0='foobar'",
2615 "member='Frobated',arg0='foobar'",
2616 "type='signal',arg0='foobar'",
2617 /* The definition of argXpath matches says: "As with normal argument matches,
2618 * if the argument is exactly equal to the string given in the match rule
2619 * then the rule is satisfied." So this should match (even though the
2620 * argument is not a valid path)!
2621 */
2622 "arg0path='foobar'",
2623 "arg0namespace='foobar'",
2624 NULL
2625 };
2626
2627 static const char*
2628 should_not_match_message_1[] = {
2629 "type='method_call'",
2630 "type='error'",
2631 "type='method_return'",
2632 "type='signal',member='Oopsed'",
2633 "arg0='blah'",
2634 "arg1='foobar'",
2635 "arg2='foobar'",
2636 "arg3='foobar'",
2637 "arg0='3'",
2638 "arg1='3'",
2639 "arg0='foobar',arg1='abcdef'",
2640 "arg0='foobar',arg1='abcdef',arg2='abcdefghi',arg3='abcdefghi',arg4='abcdefghi'",
2641 "arg0='foobar',arg1='abcdef',arg4='abcdefghi',arg3='abcdefghi',arg2='abcdefghi'",
2642 "arg0path='foo'",
2643 "arg0path='foobar/'",
2644 "arg1path='3'",
2645 "arg0namespace='foo'",
2646 "arg0namespace='foo',arg1='abcdef'",
2647 "arg0namespace='moo'",
2648 NULL
2649 };
2650
2651 #define EXAMPLE_NAME "com.example.backend.foo"
2652
2653 static const char *
2654 should_match_message_2[] = {
2655 /* EXAMPLE_NAME is in all of these namespaces */
2656 "arg0namespace='com.example.backend'",
2657 "arg0namespace='com.example'",
2658 "arg0namespace='com'",
2659
2660 /* If the client specifies the name exactly, with no trailing period, then
2661 * it should match.
2662 */
2663 "arg0namespace='com.example.backend.foo'",
2664
2665 NULL
2666 };
2667
2668 static const char *
2669 should_not_match_message_2[] = {
2670 /* These are not even prefixes */
2671 "arg0namespace='com.example.backend.foo.bar'",
2672 "arg0namespace='com.example.backend.foobar'",
2673
2674 /* These are prefixes, but they're not parent namespaces. */
2675 "arg0namespace='com.example.backend.fo'",
2676 "arg0namespace='com.example.backen'",
2677 "arg0namespace='com.exampl'",
2678 "arg0namespace='co'",
2679
2680 NULL
2681 };
2682
2683 static void
check_matches(dbus_bool_t expected_to_match,int number,DBusMessage * message,const char * rule_text)2684 check_matches (dbus_bool_t expected_to_match,
2685 int number,
2686 DBusMessage *message,
2687 const char *rule_text)
2688 {
2689 BusMatchRule *rule;
2690 dbus_bool_t matched;
2691
2692 rule = check_parse (TRUE, rule_text);
2693 _dbus_assert (rule != NULL);
2694
2695 /* We can't test sender/destination rules since we pass NULL here */
2696 matched = match_rule_matches (rule, NULL, NULL, message, 0);
2697
2698 if (matched != expected_to_match)
2699 {
2700 _dbus_warn ("Expected rule %s to %s message %d, failed",
2701 rule_text, expected_to_match ?
2702 "match" : "not match", number);
2703 exit (1);
2704 }
2705
2706 bus_match_rule_unref (rule);
2707 }
2708
2709 static void
check_matching(DBusMessage * message,int number,const char ** should_match,const char ** should_not_match)2710 check_matching (DBusMessage *message,
2711 int number,
2712 const char **should_match,
2713 const char **should_not_match)
2714 {
2715 int i;
2716
2717 i = 0;
2718 while (should_match[i] != NULL)
2719 {
2720 check_matches (TRUE, number, message, should_match[i]);
2721 ++i;
2722 }
2723
2724 i = 0;
2725 while (should_not_match[i] != NULL)
2726 {
2727 check_matches (FALSE, number, message, should_not_match[i]);
2728 ++i;
2729 }
2730 }
2731
2732 static void
test_matching(void)2733 test_matching (void)
2734 {
2735 DBusMessage *message1, *message2;
2736 const char *v_STRING;
2737 dbus_int32_t v_INT32;
2738
2739 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2740 _dbus_assert (message1 != NULL);
2741 if (!dbus_message_set_member (message1, "Frobated"))
2742 _dbus_assert_not_reached ("oom");
2743
2744 v_STRING = "foobar";
2745 v_INT32 = 3;
2746 if (!dbus_message_append_args (message1,
2747 DBUS_TYPE_STRING, &v_STRING,
2748 DBUS_TYPE_INT32, &v_INT32,
2749 NULL))
2750 _dbus_assert_not_reached ("oom");
2751
2752 check_matching (message1, 1,
2753 should_match_message_1,
2754 should_not_match_message_1);
2755
2756 dbus_message_unref (message1);
2757
2758 message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2759 _dbus_assert (message2 != NULL);
2760 if (!dbus_message_set_member (message2, "NameOwnerChanged"))
2761 _dbus_assert_not_reached ("oom");
2762
2763 /* Obviously this isn't really a NameOwnerChanged signal. */
2764 v_STRING = EXAMPLE_NAME;
2765 if (!dbus_message_append_args (message2,
2766 DBUS_TYPE_STRING, &v_STRING,
2767 NULL))
2768 _dbus_assert_not_reached ("oom");
2769
2770 check_matching (message2, 2,
2771 should_match_message_2,
2772 should_not_match_message_2);
2773
2774 dbus_message_unref (message2);
2775 }
2776
2777 #define PATH_MATCH_RULE "arg0path='/aa/bb/'"
2778
2779 /* This is a list of paths that should be matched by PATH_MATCH_RULE, taken
2780 * from the specification. Notice that not all of them are actually legal D-Bus
2781 * paths.
2782 *
2783 * The author of this test takes no responsibility for the semantics of
2784 * this match rule key.
2785 */
2786 static const char *paths_that_should_be_matched[] = {
2787 "/aa/",
2788 "/aa/bb/",
2789 "/aa/bb/cc/",
2790 #define FIRST_VALID_PATH_WHICH_SHOULD_MATCH 3
2791 "/",
2792 "/aa/bb/cc",
2793 NULL
2794 };
2795
2796 /* These paths should not be matched by PATH_MATCH_RULE. */
2797 static const char *paths_that_should_not_be_matched[] = {
2798 "/aa/b",
2799 "/aa",
2800 /* or even... */
2801 "/aa/bb",
2802 NULL
2803 };
2804
2805 static void
test_path_match(int type,const char * path,const char * rule_text,BusMatchRule * rule,dbus_bool_t should_match)2806 test_path_match (int type,
2807 const char *path,
2808 const char *rule_text,
2809 BusMatchRule *rule,
2810 dbus_bool_t should_match)
2811 {
2812 DBusMessage *message = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2813 dbus_bool_t matched;
2814
2815 _dbus_assert (message != NULL);
2816 if (!dbus_message_set_member (message, "Foo"))
2817 _dbus_assert_not_reached ("oom");
2818
2819 if (!dbus_message_append_args (message,
2820 type, &path,
2821 NULL))
2822 _dbus_assert_not_reached ("oom");
2823
2824 matched = match_rule_matches (rule, NULL, NULL, message, 0);
2825
2826 if (matched != should_match)
2827 {
2828 _dbus_warn ("Expected rule %s to %s message "
2829 "with first arg %s of type '%c', failed",
2830 rule_text,
2831 should_match ? "match" : "not match",
2832 path,
2833 (char) type);
2834 exit (1);
2835 }
2836
2837 dbus_message_unref (message);
2838 }
2839
2840 static void
test_path_matching(void)2841 test_path_matching (void)
2842 {
2843 BusMatchRule *rule;
2844 const char **s;
2845
2846 rule = check_parse (TRUE, PATH_MATCH_RULE);
2847 _dbus_assert (rule != NULL);
2848
2849 for (s = paths_that_should_be_matched; *s != NULL; s++)
2850 test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, TRUE);
2851
2852 for (s = paths_that_should_be_matched + FIRST_VALID_PATH_WHICH_SHOULD_MATCH;
2853 *s != NULL; s++)
2854 test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, TRUE);
2855
2856 for (s = paths_that_should_not_be_matched; *s != NULL; s++)
2857 {
2858 test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, FALSE);
2859 test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, FALSE);
2860 }
2861
2862 bus_match_rule_unref (rule);
2863 }
2864
2865 static const char*
2866 path_namespace_should_match_message_1[] = {
2867 "type='signal',path_namespace='/'",
2868 "type='signal',path_namespace='/foo'",
2869 "type='signal',path_namespace='/foo/TheObjectManager'",
2870 NULL
2871 };
2872
2873 static const char*
2874 path_namespace_should_not_match_message_1[] = {
2875 "type='signal',path_namespace='/bar'",
2876 "type='signal',path_namespace='/bar/TheObjectManager'",
2877 NULL
2878 };
2879
2880 static const char*
2881 path_namespace_should_match_message_2[] = {
2882 "type='signal',path_namespace='/'",
2883 "type='signal',path_namespace='/foo/TheObjectManager'",
2884 NULL
2885 };
2886
2887 static const char*
2888 path_namespace_should_not_match_message_2[] = {
2889 NULL
2890 };
2891
2892 static const char*
2893 path_namespace_should_match_message_3[] = {
2894 "type='signal',path_namespace='/'",
2895 NULL
2896 };
2897
2898 static const char*
2899 path_namespace_should_not_match_message_3[] = {
2900 "type='signal',path_namespace='/foo/TheObjectManager'",
2901 NULL
2902 };
2903
2904 static const char*
2905 path_namespace_should_match_message_4[] = {
2906 "type='signal',path_namespace='/'",
2907 NULL
2908 };
2909
2910 static const char*
2911 path_namespace_should_not_match_message_4[] = {
2912 "type='signal',path_namespace='/foo/TheObjectManager'",
2913 NULL
2914 };
2915
2916 static void
test_matching_path_namespace(void)2917 test_matching_path_namespace (void)
2918 {
2919 DBusMessage *message1;
2920 DBusMessage *message2;
2921 DBusMessage *message3;
2922 DBusMessage *message4;
2923
2924 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2925 _dbus_assert (message1 != NULL);
2926 if (!dbus_message_set_path (message1, "/foo/TheObjectManager"))
2927 _dbus_assert_not_reached ("oom");
2928
2929 message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2930 _dbus_assert (message2 != NULL);
2931 if (!dbus_message_set_path (message2, "/foo/TheObjectManager/child_object"))
2932 _dbus_assert_not_reached ("oom");
2933
2934 message3 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2935 _dbus_assert (message3 != NULL);
2936 if (!dbus_message_set_path (message3, "/foo/TheObjectManagerOther"))
2937 _dbus_assert_not_reached ("oom");
2938
2939 message4 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2940 _dbus_assert (message4 != NULL);
2941 if (!dbus_message_set_path (message4, "/"))
2942 _dbus_assert_not_reached ("oom");
2943
2944 check_matching (message1, 1,
2945 path_namespace_should_match_message_1,
2946 path_namespace_should_not_match_message_1);
2947 check_matching (message2, 2,
2948 path_namespace_should_match_message_2,
2949 path_namespace_should_not_match_message_2);
2950 check_matching (message3, 3,
2951 path_namespace_should_match_message_3,
2952 path_namespace_should_not_match_message_3);
2953 check_matching (message4, 4,
2954 path_namespace_should_match_message_4,
2955 path_namespace_should_not_match_message_4);
2956
2957 dbus_message_unref (message4);
2958 dbus_message_unref (message3);
2959 dbus_message_unref (message2);
2960 dbus_message_unref (message1);
2961 }
2962
2963 dbus_bool_t
bus_signals_test(const DBusString * test_data_dir)2964 bus_signals_test (const DBusString *test_data_dir)
2965 {
2966 BusMatchmaker *matchmaker;
2967
2968 matchmaker = bus_matchmaker_new ();
2969 bus_matchmaker_ref (matchmaker);
2970 bus_matchmaker_unref (matchmaker);
2971 bus_matchmaker_unref (matchmaker);
2972
2973 if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL))
2974 _dbus_assert_not_reached ("Parsing match rules test failed");
2975
2976 test_equality ();
2977 test_matching ();
2978 test_path_matching ();
2979 test_matching_path_namespace ();
2980
2981 return TRUE;
2982 }
2983
2984 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */
2985
2986