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