dbus: fix 64-bit compiler warnings
[platform/upstream/dbus.git] / dbus / dbus-signals.c
1 /* signals.c  Bus signal connection implementation
2  *
3  * Copyright (C) 2003, 2005  Red Hat, Inc.
4  * Copyright 2014 Samsung Electronics
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 #include "dbus-signals.h"
26 #include <dbus/dbus-marshal-validate.h>
27 #include "dbus-internals.h"
28 #include "dbus-hash.h"
29 #include "dbus-list.h"
30 #include "kdbus-common.h"
31 #include <stdlib.h>
32 #include <limits.h>
33
34 #define SET_OOM(error) dbus_set_error_const ((error), DBUS_ERROR_NO_MEMORY, "Memory allocation failure in transport, regarding match rules")
35
36 struct MatchRule
37 {
38   int refcount;       /**< reference count */
39
40   DBusConnection *matches_go_to; /**< Owner of the rule */
41
42   unsigned int flags; /**< MatchFlags */
43
44   int   message_type;
45   char *interface;
46   char *member;
47   char *sender;
48   char *destination;
49   char *path;
50
51   unsigned int *arg_lens;
52   char **args;
53   int args_len;
54
55   __u64 kdbus_cookie;
56 };
57
58 #define MATCH_ARG_FLAGS (MATCH_ARG_NAMESPACE |MATCH_ARG_IS_PATH)
59
60 static MatchRule*
61 bus_match_rule_new (DBusConnection *matches_go_to)
62 {
63   MatchRule *rule;
64
65   rule = dbus_new0 (MatchRule, 1);
66   if (rule == NULL)
67     return NULL;
68
69   rule->refcount = 1;
70   rule->matches_go_to = matches_go_to;
71   rule->kdbus_cookie = 0;
72
73 #ifndef DBUS_ENABLE_EMBEDDED_TESTS
74   _dbus_assert (rule->matches_go_to != NULL);
75 #endif
76
77   return rule;
78 }
79
80 static MatchRule *
81 bus_match_rule_ref (MatchRule *rule)
82 {
83   _dbus_assert (rule->refcount > 0);
84
85   rule->refcount += 1;
86
87   return rule;
88 }
89
90 void
91 match_rule_unref (MatchRule *rule)
92 {
93   _dbus_assert (rule->refcount > 0);
94
95   rule->refcount -= 1;
96   if (rule->refcount == 0)
97     {
98       dbus_free (rule->interface);
99       dbus_free (rule->member);
100       dbus_free (rule->sender);
101       dbus_free (rule->destination);
102       dbus_free (rule->path);
103       dbus_free (rule->arg_lens);
104
105       /* can't use dbus_free_string_array() since there
106        * are embedded NULL
107        */
108       if (rule->args)
109         {
110           int i;
111
112           i = 0;
113           while (i < rule->args_len)
114             {
115               if (rule->args[i])
116                 dbus_free (rule->args[i]);
117               ++i;
118             }
119
120           dbus_free (rule->args);
121         }
122
123       dbus_free (rule);
124     }
125 }
126
127 #ifdef DBUS_ENABLE_VERBOSE_MODE
128 /* Note this function does not do escaping, so it's only
129  * good for debug spew at the moment
130  */
131 char*
132 match_rule_to_string (MatchRule *rule)
133 {
134   DBusString str;
135   char *ret;
136
137   if (!_dbus_string_init (&str))
138     {
139       char *s;
140       while ((s = _dbus_strdup ("nomem")) == NULL)
141         ; /* only OK for debug spew... */
142       return s;
143     }
144
145   if (rule->flags & MATCH_MESSAGE_TYPE)
146     {
147       if (!_dbus_string_append_printf (&str, "type='%s'",
148             dbus_message_type_to_string (rule->message_type)))
149         goto nomem;
150     }
151
152   if (rule->flags & MATCH_INTERFACE)
153     {
154       if (_dbus_string_get_length (&str) > 0)
155         {
156           if (!_dbus_string_append (&str, ","))
157             goto nomem;
158         }
159
160       if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface))
161         goto nomem;
162     }
163
164   if (rule->flags & MATCH_MEMBER)
165     {
166       if (_dbus_string_get_length (&str) > 0)
167         {
168           if (!_dbus_string_append (&str, ","))
169             goto nomem;
170         }
171
172       if (!_dbus_string_append_printf (&str, "member='%s'", rule->member))
173         goto nomem;
174     }
175
176   if (rule->flags & MATCH_PATH)
177     {
178       if (_dbus_string_get_length (&str) > 0)
179         {
180           if (!_dbus_string_append (&str, ","))
181             goto nomem;
182         }
183
184       if (!_dbus_string_append_printf (&str, "path='%s'", rule->path))
185         goto nomem;
186     }
187
188   if (rule->flags & MATCH_PATH_NAMESPACE)
189     {
190       if (_dbus_string_get_length (&str) > 0)
191         {
192           if (!_dbus_string_append (&str, ","))
193             goto nomem;
194         }
195
196       if (!_dbus_string_append_printf (&str, "path_namespace='%s'", rule->path))
197         goto nomem;
198     }
199
200   if (rule->flags & MATCH_SENDER)
201     {
202       if (_dbus_string_get_length (&str) > 0)
203         {
204           if (!_dbus_string_append (&str, ","))
205             goto nomem;
206         }
207
208       if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender))
209         goto nomem;
210     }
211
212   if (rule->flags & MATCH_DESTINATION)
213     {
214       if (_dbus_string_get_length (&str) > 0)
215         {
216           if (!_dbus_string_append (&str, ","))
217             goto nomem;
218         }
219
220       if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination))
221         goto nomem;
222     }
223
224   if (rule->flags & MATCH_CLIENT_IS_EAVESDROPPING)
225     {
226       if (_dbus_string_get_length (&str) > 0)
227         {
228           if (!_dbus_string_append (&str, ","))
229             goto nomem;
230         }
231
232       if (!_dbus_string_append_printf (&str, "eavesdrop='%s'",
233             (rule->flags & MATCH_CLIENT_IS_EAVESDROPPING) ?
234             "true" : "false"))
235         goto nomem;
236     }
237
238   if (rule->flags &MATCH_ARGS)
239     {
240       int i;
241
242       _dbus_assert (rule->args != NULL);
243
244       i = 0;
245       while (i < rule->args_len)
246         {
247           if (rule->args[i] != NULL)
248             {
249               dbus_bool_t is_path, is_namespace;
250
251               if (_dbus_string_get_length (&str) > 0)
252                 {
253                   if (!_dbus_string_append (&str, ","))
254                     goto nomem;
255                 }
256
257               is_path = (rule->arg_lens[i] & MATCH_ARG_IS_PATH) != 0;
258               is_namespace = (rule->arg_lens[i] & MATCH_ARG_NAMESPACE) != 0;
259
260               if (!_dbus_string_append_printf (&str,
261                                                "arg%d%s='%s'",
262                                                i,
263                                                is_path ? "path" :
264                                                is_namespace ? "namespace" : "",
265                                                rule->args[i]))
266                 goto nomem;
267             }
268
269           ++i;
270         }
271     }
272
273   if (!_dbus_string_steal_data (&str, &ret))
274     goto nomem;
275
276   _dbus_string_free (&str);
277   return ret;
278
279  nomem:
280   _dbus_string_free (&str);
281   {
282     char *s;
283     while ((s = _dbus_strdup ("nomem")) == NULL)
284       ;  /* only OK for debug spew... */
285     return s;
286   }
287 }
288 #endif /* DBUS_ENABLE_VERBOSE_MODE */
289
290 static dbus_bool_t
291 bus_match_rule_set_message_type (MatchRule *rule,
292                                  int           type)
293 {
294   rule->flags |=MATCH_MESSAGE_TYPE;
295
296   rule->message_type = type;
297
298   return TRUE;
299 }
300
301 static dbus_bool_t
302 bus_match_rule_set_interface (MatchRule *rule,
303                               const char   *interface)
304 {
305   char *new;
306
307   _dbus_assert (interface != NULL);
308
309   new = _dbus_strdup (interface);
310   if (new == NULL)
311     return FALSE;
312
313   rule->flags |=MATCH_INTERFACE;
314   dbus_free (rule->interface);
315   rule->interface = new;
316
317   return TRUE;
318 }
319
320 static dbus_bool_t
321 bus_match_rule_set_member (MatchRule *rule,
322                            const char   *member)
323 {
324   char *new;
325
326   _dbus_assert (member != NULL);
327
328   new = _dbus_strdup (member);
329   if (new == NULL)
330     return FALSE;
331
332   rule->flags |=MATCH_MEMBER;
333   dbus_free (rule->member);
334   rule->member = new;
335
336   return TRUE;
337 }
338
339 static dbus_bool_t
340 bus_match_rule_set_sender (MatchRule *rule,
341                            const char   *sender)
342 {
343   char *new;
344
345   _dbus_assert (sender != NULL);
346
347   new = _dbus_strdup (sender);
348   if (new == NULL)
349     return FALSE;
350
351   rule->flags |=MATCH_SENDER;
352   dbus_free (rule->sender);
353   rule->sender = new;
354
355   return TRUE;
356 }
357
358 static dbus_bool_t
359 bus_match_rule_set_destination (MatchRule *rule,
360                                 const char   *destination)
361 {
362   char *new;
363
364   _dbus_assert (destination != NULL);
365
366   new = _dbus_strdup (destination);
367   if (new == NULL)
368     return FALSE;
369
370   rule->flags |=MATCH_DESTINATION;
371   dbus_free (rule->destination);
372   rule->destination = new;
373
374   return TRUE;
375 }
376
377 static void
378 bus_match_rule_set_client_is_eavesdropping (MatchRule *rule,
379                                             dbus_bool_t is_eavesdropping)
380 {
381   if (is_eavesdropping)
382     rule->flags |= MATCH_CLIENT_IS_EAVESDROPPING;
383   else
384     rule->flags &= ~(MATCH_CLIENT_IS_EAVESDROPPING);
385 }
386
387 static dbus_bool_t
388 bus_match_rule_set_path (MatchRule *rule,
389                          const char   *path,
390                          dbus_bool_t   is_namespace)
391 {
392   char *new;
393
394   _dbus_assert (path != NULL);
395
396   new = _dbus_strdup (path);
397   if (new == NULL)
398     return FALSE;
399
400   rule->flags &= ~(MATCH_PATH | MATCH_PATH_NAMESPACE);
401
402   if (is_namespace)
403     rule->flags |= MATCH_PATH_NAMESPACE;
404   else
405     rule->flags |= MATCH_PATH;
406
407   dbus_free (rule->path);
408   rule->path = new;
409
410   return TRUE;
411 }
412
413 static dbus_bool_t
414 bus_match_rule_set_arg (MatchRule     *rule,
415                         int                arg,
416                         const DBusString *value,
417                         dbus_bool_t       is_path,
418                         dbus_bool_t       is_namespace)
419 {
420   int length;
421   char *new;
422
423   _dbus_assert (value != NULL);
424
425   /* args_len is the number of args not including null termination
426    * in the char**
427    */
428   if (arg >= rule->args_len)
429     {
430       unsigned int *new_arg_lens;
431       char **new_args;
432       int new_args_len;
433       int i;
434
435       new_args_len = arg + 1;
436
437       /* add another + 1 here for null termination */
438       new_args = dbus_realloc (rule->args,
439                                sizeof (char *) * (new_args_len + 1));
440       if (new_args == NULL)
441         return FALSE;
442
443       /* NULL the new slots */
444       i = rule->args_len;
445       while (i <= new_args_len) /* <= for null termination */
446         {
447           new_args[i] = NULL;
448           ++i;
449         }
450
451       rule->args = new_args;
452
453       /* and now add to the lengths */
454       new_arg_lens = dbus_realloc (rule->arg_lens,
455                                    sizeof (int) * (new_args_len + 1));
456
457       if (new_arg_lens == NULL)
458         return FALSE;
459
460       /* zero the new slots */
461       i = rule->args_len;
462       while (i <= new_args_len) /* <= for null termination */
463         {
464           new_arg_lens[i] = 0;
465           ++i;
466         }
467
468       rule->arg_lens = new_arg_lens;
469       rule->args_len = new_args_len;
470     }
471
472   length = _dbus_string_get_length (value);
473   if (!_dbus_string_copy_data (value, &new))
474     return FALSE;
475
476   rule->flags |=MATCH_ARGS;
477
478   dbus_free (rule->args[arg]);
479   rule->arg_lens[arg] = length;
480   rule->args[arg] = new;
481
482   if (is_path)
483     rule->arg_lens[arg] |=MATCH_ARG_IS_PATH;
484
485   if (is_namespace)
486     rule->arg_lens[arg] |=MATCH_ARG_NAMESPACE;
487
488   /* NULL termination didn't get busted */
489   _dbus_assert (rule->args[rule->args_len] == NULL);
490   _dbus_assert (rule->arg_lens[rule->args_len] == 0);
491
492   return TRUE;
493 }
494
495 void
496 match_rule_set_cookie (MatchRule *rule, dbus_uint64_t cookie)
497 {
498   rule->kdbus_cookie = cookie;
499 }
500
501 dbus_uint64_t
502 match_rule_get_cookie (MatchRule *rule)
503 {
504   return rule->kdbus_cookie;
505 }
506
507 #define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
508
509 static dbus_bool_t
510 find_key (const DBusString *str,
511           int               start,
512           DBusString       *key,
513           int              *value_pos,
514           DBusError        *error)
515 {
516   const char *p;
517   const char *s;
518   const char *key_start;
519   const char *key_end;
520
521   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
522
523   s = _dbus_string_get_const_data (str);
524
525   p = s + start;
526
527   while (*p && ISWHITE (*p))
528     ++p;
529
530   key_start = p;
531
532   while (*p && *p != '=' && !ISWHITE (*p))
533     ++p;
534
535   key_end = p;
536
537   while (*p && ISWHITE (*p))
538     ++p;
539
540   if (key_start == key_end)
541     {
542       /* Empty match rules or trailing whitespace are OK */
543       *value_pos = p - s;
544       return TRUE;
545     }
546
547   if (*p != '=')
548     {
549       dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
550                       "Match rule has a key with no subsequent '=' character");
551       return FALSE;
552     }
553   ++p;
554
555   if (!_dbus_string_append_len (key, key_start, key_end - key_start))
556     {
557      SET_OOM (error);
558       return FALSE;
559     }
560
561   *value_pos = p - s;
562
563   return TRUE;
564 }
565
566 static dbus_bool_t
567 find_value (const DBusString *str,
568             int               start,
569             const char       *key,
570             DBusString       *value,
571             int              *value_end,
572             DBusError        *error)
573 {
574   const char *p;
575   const char *s;
576   char quote_char;
577   int orig_len;
578
579   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
580
581   orig_len = _dbus_string_get_length (value);
582
583   s = _dbus_string_get_const_data (str);
584
585   p = s + start;
586
587   quote_char = '\0';
588
589   while (*p)
590     {
591       if (quote_char == '\0')
592         {
593           switch (*p)
594             {
595             case '\0':
596               goto done;
597
598             case '\'':
599               quote_char = '\'';
600               goto next;
601
602             case ',':
603               ++p;
604               goto done;
605
606             case '\\':
607               quote_char = '\\';
608               goto next;
609
610             default:
611               if (!_dbus_string_append_byte (value, *p))
612                 {
613                  SET_OOM (error);
614                   goto failed;
615                 }
616             }
617         }
618       else if (quote_char == '\\')
619         {
620           /* \ only counts as an escape if escaping a quote mark */
621           if (*p != '\'')
622             {
623               if (!_dbus_string_append_byte (value, '\\'))
624                 {
625                  SET_OOM (error);
626                   goto failed;
627                 }
628             }
629
630           if (!_dbus_string_append_byte (value, *p))
631             {
632              SET_OOM (error);
633               goto failed;
634             }
635
636           quote_char = '\0';
637         }
638       else
639         {
640           _dbus_assert (quote_char == '\'');
641
642           if (*p == '\'')
643             {
644               quote_char = '\0';
645             }
646           else
647             {
648               if (!_dbus_string_append_byte (value, *p))
649                 {
650                  SET_OOM (error);
651                   goto failed;
652                 }
653             }
654         }
655
656     next:
657       ++p;
658     }
659
660  done:
661
662   if (quote_char == '\\')
663     {
664       if (!_dbus_string_append_byte (value, '\\'))
665         {
666          SET_OOM (error);
667           goto failed;
668         }
669     }
670   else if (quote_char == '\'')
671     {
672       dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
673                       "Unbalanced quotation marks in match rule");
674       goto failed;
675     }
676   else
677     _dbus_assert (quote_char == '\0');
678
679   /* Zero-length values are allowed */
680
681   *value_end = p - s;
682
683   return TRUE;
684
685  failed:
686   _DBUS_ASSERT_ERROR_IS_SET (error);
687   _dbus_string_set_length (value, orig_len);
688   return FALSE;
689 }
690
691 /* duplicates aren't allowed so the real legitimate max is only 6 or
692  * so. Leaving extra so we don't have to bother to update it.
693  * FIXME this is sort of busted now with arg matching, but we let
694  * you match on up to 10 args for now
695  */
696 #define MAX_RULE_TOKENS 16
697
698 /* this is slightly too high level to be termed a "token"
699  * but let's not be pedantic.
700  */
701 typedef struct
702 {
703   char *key;
704   char *value;
705 } RuleToken;
706
707 static dbus_bool_t
708 tokenize_rule (const DBusString *rule_text,
709                RuleToken         tokens[MAX_RULE_TOKENS],
710                DBusError        *error)
711 {
712   int i;
713   int pos;
714   DBusString key;
715   DBusString value;
716   dbus_bool_t retval;
717
718   retval = FALSE;
719
720   if (!_dbus_string_init (&key))
721     {
722      SET_OOM (error);
723       return FALSE;
724     }
725
726   if (!_dbus_string_init (&value))
727     {
728       _dbus_string_free (&key);
729      SET_OOM (error);
730       return FALSE;
731     }
732
733   i = 0;
734   pos = 0;
735   while (i < MAX_RULE_TOKENS &&
736          pos < _dbus_string_get_length (rule_text))
737     {
738       _dbus_assert (tokens[i].key == NULL);
739       _dbus_assert (tokens[i].value == NULL);
740
741       if (!find_key (rule_text, pos, &key, &pos, error))
742         goto out;
743
744       if (_dbus_string_get_length (&key) == 0)
745         goto next;
746
747       if (!_dbus_string_steal_data (&key, &tokens[i].key))
748         {
749          SET_OOM (error);
750           goto out;
751         }
752
753       if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error))
754         goto out;
755
756       if (!_dbus_string_steal_data (&value, &tokens[i].value))
757         {
758          SET_OOM (error);
759           goto out;
760         }
761
762     next:
763       ++i;
764     }
765
766   retval = TRUE;
767
768  out:
769   if (!retval)
770     {
771       i = 0;
772       while (tokens[i].key || tokens[i].value)
773         {
774           dbus_free (tokens[i].key);
775           dbus_free (tokens[i].value);
776           tokens[i].key = NULL;
777           tokens[i].value = NULL;
778           ++i;
779         }
780     }
781
782   _dbus_string_free (&key);
783   _dbus_string_free (&value);
784
785   return retval;
786 }
787
788 static dbus_bool_t
789 bus_match_rule_parse_arg_match (MatchRule     *rule,
790                                 const char       *key,
791                                 const DBusString *value,
792                                 DBusError        *error)
793 {
794   dbus_bool_t is_path = FALSE;
795   dbus_bool_t is_namespace = FALSE;
796   DBusString key_str;
797   unsigned long arg;
798   int length;
799   int end;
800
801   /* For now, arg0='foo' always implies that 'foo' is a
802    * DBUS_TYPE_STRING. Someday we could add an arg0type='int32' thing
803    * if we wanted, which would specify another type, in which case
804    * arg0='5' would have the 5 parsed as an int rather than string.
805    */
806
807   /* First we need to parse arg0 = 0, arg27 = 27 */
808
809   _dbus_string_init_const (&key_str, key);
810   length = _dbus_string_get_length (&key_str);
811
812   if (_dbus_string_get_length (&key_str) < 4)
813     {
814       dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
815                       "Key '%s' in match rule starts with 'arg' but lacks an arg number. Should be 'arg0' or 'arg7' for example.\n", key);
816       goto failed;
817     }
818
819   if (!_dbus_string_parse_uint (&key_str, 3, &arg, &end))
820     {
821       dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
822                       "Key '%s' in match rule starts with 'arg' but could not parse arg number. Should be 'arg0' or 'arg7' for example.\n", key);
823       goto failed;
824     }
825
826   if (end != length)
827     {
828       if ((end + strlen ("path")) == (size_t)length &&
829           _dbus_string_ends_with_c_str (&key_str, "path"))
830         {
831           is_path = TRUE;
832         }
833       else if (_dbus_string_equal_c_str (&key_str, "arg0namespace"))
834         {
835           int value_len = _dbus_string_get_length (value);
836
837           is_namespace = TRUE;
838
839           if (!_dbus_validate_bus_namespace (value, 0, value_len))
840             {
841               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
842                   "arg0namespace='%s' is not a valid prefix of a bus name",
843                   _dbus_string_get_const_data (value));
844               goto failed;
845             }
846         }
847       else
848         {
849           dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
850               "Key '%s' in match rule contains junk after argument number (%lu). Only 'arg%lupath' (for example) or 'arg0namespace' are valid", key, arg, arg);
851           goto failed;
852         }
853     }
854
855   /* If we didn't check this we could allocate a huge amount of RAM */
856   if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER)
857     {
858       dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
859                       "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);
860       goto failed;
861     }
862
863   if ((rule->flags &MATCH_ARGS) &&
864       rule->args_len > (int) arg &&
865       rule->args[arg] != NULL)
866     {
867       dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
868                       "Argument %s matched more than once in match rule\n", key);
869       goto failed;
870     }
871
872   if (!bus_match_rule_set_arg (rule, arg, value, is_path, is_namespace))
873     {
874      SET_OOM (error);
875       goto failed;
876     }
877
878   return TRUE;
879
880  failed:
881   _DBUS_ASSERT_ERROR_IS_SET (error);
882   return FALSE;
883 }
884
885 /*
886  * The format is comma-separated with strings quoted with single quotes
887  * as for the shell (to escape a literal single quote, use '\'').
888  *
889  * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
890  * path='/bar/foo',destination=':452345.34'
891  *
892  */
893 MatchRule*
894 match_rule_parse (DBusConnection   *matches_go_to,
895                       const DBusString *rule_text,
896                       DBusError        *error)
897 {
898   MatchRule *rule;
899   RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
900   int i;
901
902   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
903
904   if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH)
905     {
906       dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
907                       "Match rule text is %d bytes, maximum is %d",
908                       _dbus_string_get_length (rule_text),
909                       DBUS_MAXIMUM_MATCH_RULE_LENGTH);
910       return NULL;
911     }
912
913   memset (tokens, '\0', sizeof (tokens));
914
915   rule = bus_match_rule_new (matches_go_to);
916   if (rule == NULL)
917     {
918      SET_OOM (error);
919       goto failed;
920     }
921
922   if (!tokenize_rule (rule_text, tokens, error))
923     goto failed;
924
925   i = 0;
926   while (tokens[i].key != NULL)
927     {
928       DBusString tmp_str;
929       int len;
930       const char *key = tokens[i].key;
931       const char *value = tokens[i].value;
932
933       _dbus_string_init_const (&tmp_str, value);
934       len = _dbus_string_get_length (&tmp_str);
935
936       if (strcmp (key, "type") == 0)
937         {
938           int t;
939
940           if (rule->flags & MATCH_MESSAGE_TYPE)
941             {
942               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
943                               "Key %s specified twice in match rule\n", key);
944               goto failed;
945             }
946
947           t = dbus_message_type_from_string (value);
948
949           if (t == DBUS_MESSAGE_TYPE_INVALID)
950             {
951               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
952                               "Invalid message type (%s) in match rule\n", value);
953               goto failed;
954             }
955
956           if (!bus_match_rule_set_message_type (rule, t))
957             {
958              SET_OOM (error);
959               goto failed;
960             }
961         }
962       else if (strcmp (key, "sender") == 0)
963         {
964           if (rule->flags & MATCH_SENDER)
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           if (!_dbus_validate_bus_name (&tmp_str, 0, len))
972             {
973               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
974                               "Sender name '%s' is invalid\n", value);
975               goto failed;
976             }
977
978           if (!bus_match_rule_set_sender (rule, value))
979             {
980              SET_OOM (error);
981               goto failed;
982             }
983         }
984       else if (strcmp (key, "interface") == 0)
985         {
986           if (rule->flags & MATCH_INTERFACE)
987             {
988               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
989                               "Key %s specified twice in match rule\n", key);
990               goto failed;
991             }
992
993           if (!_dbus_validate_interface (&tmp_str, 0, len))
994             {
995               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
996                               "Interface name '%s' is invalid\n", value);
997               goto failed;
998             }
999
1000           if (!bus_match_rule_set_interface (rule, value))
1001             {
1002              SET_OOM (error);
1003               goto failed;
1004             }
1005         }
1006       else if (strcmp (key, "member") == 0)
1007         {
1008           if (rule->flags & MATCH_MEMBER)
1009             {
1010               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1011                               "Key %s specified twice in match rule\n", key);
1012               goto failed;
1013             }
1014
1015           if (!_dbus_validate_member (&tmp_str, 0, len))
1016             {
1017               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1018                               "Member name '%s' is invalid\n", value);
1019               goto failed;
1020             }
1021
1022           if (!bus_match_rule_set_member (rule, value))
1023             {
1024              SET_OOM (error);
1025               goto failed;
1026             }
1027         }
1028       else if (strcmp (key, "path") == 0 ||
1029           strcmp (key, "path_namespace") == 0)
1030         {
1031           dbus_bool_t is_namespace = (strcmp (key, "path_namespace") == 0);
1032
1033           if (rule->flags & (MATCH_PATH | MATCH_PATH_NAMESPACE))
1034             {
1035               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1036                               "path or path_namespace specified twice in match rule\n");
1037               goto failed;
1038             }
1039
1040           if (!_dbus_validate_path (&tmp_str, 0, len))
1041             {
1042               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1043                               "Path '%s' is invalid\n", value);
1044               goto failed;
1045             }
1046
1047           if (!bus_match_rule_set_path (rule, value, is_namespace))
1048             {
1049              SET_OOM (error);
1050               goto failed;
1051             }
1052         }
1053       else if (strcmp (key, "destination") == 0)
1054         {
1055           if (rule->flags & MATCH_DESTINATION)
1056             {
1057               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1058                               "Key %s specified twice in match rule\n", key);
1059               goto failed;
1060             }
1061
1062           if (!_dbus_validate_bus_name (&tmp_str, 0, len))
1063             {
1064               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1065                               "Destination name '%s' is invalid\n", value);
1066               goto failed;
1067             }
1068
1069           if (!bus_match_rule_set_destination (rule, value))
1070             {
1071              SET_OOM (error);
1072               goto failed;
1073             }
1074         }
1075       else if (strcmp (key, "eavesdrop") == 0)
1076         {
1077           /* do not detect "eavesdrop" being used more than once in rule:
1078            * 1) it's not possible, it's only in the flags
1079            * 2) it might be used twice to disable eavesdropping when it's
1080            * automatically added (eg dbus-monitor/bustle) */
1081
1082           /* we accept only "true|false" as possible values */
1083           if ((strcmp (value, "true") == 0))
1084             {
1085               bus_match_rule_set_client_is_eavesdropping (rule, TRUE);
1086             }
1087           else if (strcmp (value, "false") == 0)
1088             {
1089               bus_match_rule_set_client_is_eavesdropping (rule, FALSE);
1090             }
1091           else
1092             {
1093               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1094                               "eavesdrop='%s' is invalid, "
1095                               "it should be 'true' or 'false'\n",
1096                               value);
1097               goto failed;
1098             }
1099         }
1100       else if (strncmp (key, "arg", 3) == 0)
1101         {
1102           if (!bus_match_rule_parse_arg_match (rule, key, &tmp_str, error))
1103             goto failed;
1104         }
1105       else
1106         {
1107           dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1108                           "Unknown key \"%s\" in match rule",
1109                           key);
1110           goto failed;
1111         }
1112
1113       ++i;
1114     }
1115
1116
1117   goto out;
1118
1119  failed:
1120   _DBUS_ASSERT_ERROR_IS_SET (error);
1121   if (rule)
1122     {
1123       match_rule_unref (rule);
1124       rule = NULL;
1125     }
1126
1127  out:
1128
1129   i = 0;
1130   while (tokens[i].key || tokens[i].value)
1131     {
1132       _dbus_assert (i < MAX_RULE_TOKENS);
1133       dbus_free (tokens[i].key);
1134       dbus_free (tokens[i].value);
1135       ++i;
1136     }
1137
1138   return rule;
1139 }
1140
1141 typedef struct RulePool RulePool;
1142 struct RulePool
1143 {
1144   /* Maps non-NULL interface names to non-NULL (DBusList **)s */
1145   DBusHashTable *rules_by_iface;
1146
1147   /* List of MatchRules which don't specify an interface */
1148   DBusList *rules_without_iface;
1149 };
1150
1151 struct Matchmaker
1152 {
1153   int refcount;
1154
1155   /* Pools of rules, grouped by the type of message they match. 0
1156    * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a message
1157    * type.
1158    */
1159   RulePool rules_by_type[DBUS_NUM_MESSAGE_TYPES];
1160
1161   int last_cookie;
1162 };
1163
1164 static void
1165 rule_list_free (DBusList **rules)
1166 {
1167   while (*rules != NULL)
1168     {
1169       MatchRule *rule;
1170
1171       rule = (*rules)->data;
1172       match_rule_unref (rule);
1173       _dbus_list_remove_link (rules, *rules);
1174     }
1175 }
1176
1177 static void
1178 rule_list_ptr_free (DBusList **list)
1179 {
1180   /* We have to cope with NULL because the hash table frees the "existing"
1181    * value (which is NULL) when creating a new table entry...
1182    */
1183   if (list != NULL)
1184     {
1185       rule_list_free (list);
1186       dbus_free (list);
1187     }
1188 }
1189
1190 Matchmaker*
1191 matchmaker_new (void)
1192 {
1193   Matchmaker *matchmaker;
1194   int i;
1195
1196   matchmaker = dbus_new0 (Matchmaker, 1);
1197   if (matchmaker == NULL)
1198     return NULL;
1199
1200   matchmaker->refcount = 1;
1201   matchmaker->last_cookie = 0;
1202
1203   for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1204     {
1205       RulePool *p = matchmaker->rules_by_type + i;
1206
1207       p->rules_by_iface = _dbus_hash_table_new (DBUS_HASH_STRING,
1208           dbus_free, (DBusFreeFunction) rule_list_ptr_free);
1209
1210       if (p->rules_by_iface == NULL)
1211         goto nomem;
1212     }
1213
1214   return matchmaker;
1215
1216  nomem:
1217   for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1218     {
1219       RulePool *p = matchmaker->rules_by_type + i;
1220
1221       if (p->rules_by_iface == NULL)
1222         break;
1223       else
1224         _dbus_hash_table_unref (p->rules_by_iface);
1225     }
1226   dbus_free (matchmaker);
1227
1228   return NULL;
1229 }
1230
1231 DBusList **
1232 matchmaker_get_rules (Matchmaker *matchmaker,
1233                           int            message_type,
1234                           const char    *interface,
1235                           dbus_bool_t    create)
1236 {
1237   RulePool *p;
1238
1239   _dbus_assert (message_type >= 0);
1240   _dbus_assert (message_type < DBUS_NUM_MESSAGE_TYPES);
1241
1242   _dbus_verbose ("Looking up rules for message_type %d, interface %s\n",
1243                  message_type,
1244                  interface != NULL ? interface : "<null>");
1245
1246   p = matchmaker->rules_by_type + message_type;
1247
1248   if (interface == NULL)
1249     {
1250       return &p->rules_without_iface;
1251     }
1252   else
1253     {
1254       DBusList **list;
1255
1256       list = _dbus_hash_table_lookup_string (p->rules_by_iface, interface);
1257
1258       if (list == NULL && create)
1259         {
1260           char *dupped_interface;
1261
1262           list = dbus_new0 (DBusList *, 1);
1263           if (list == NULL)
1264             return NULL;
1265
1266           dupped_interface = _dbus_strdup (interface);
1267           if (dupped_interface == NULL)
1268             {
1269               dbus_free (list);
1270               return NULL;
1271             }
1272
1273           _dbus_verbose ("Adding list for type %d, iface %s\n", message_type,
1274                          interface);
1275
1276           if (!_dbus_hash_table_insert_string (p->rules_by_iface,
1277                                                dupped_interface, list))
1278             {
1279               dbus_free (list);
1280               dbus_free (dupped_interface);
1281               return NULL;
1282             }
1283         }
1284
1285       return list;
1286     }
1287 }
1288
1289 static void
1290 bus_matchmaker_gc_rules (Matchmaker *matchmaker,
1291                          int            message_type,
1292                          const char    *interface,
1293                          DBusList     **rules)
1294 {
1295   RulePool *p;
1296
1297   if (interface == NULL)
1298     return;
1299
1300   if (*rules != NULL)
1301     return;
1302
1303   _dbus_verbose ("GCing HT entry for message_type %u, interface %s\n",
1304                  message_type, interface);
1305
1306   p = matchmaker->rules_by_type + message_type;
1307
1308   _dbus_assert (_dbus_hash_table_lookup_string (p->rules_by_iface, interface)
1309       == rules);
1310
1311   _dbus_hash_table_remove_string (p->rules_by_iface, interface);
1312 }
1313
1314 /* The rule can't be modified after it's added. */
1315 dbus_bool_t
1316 matchmaker_add_rule (Matchmaker   *matchmaker,
1317                      MatchRule    *rule)
1318 {
1319   DBusList **rules;
1320
1321   _dbus_verbose ("Adding rule with message_type %d, interface %s\n",
1322                  rule->message_type,
1323                  rule->interface != NULL ? rule->interface : "<null>");
1324
1325   rules = matchmaker_get_rules (matchmaker, rule->message_type,
1326                                     rule->interface, TRUE);
1327
1328   if (rules == NULL)
1329     return FALSE;
1330
1331   if (!_dbus_list_append (rules, rule))
1332     return FALSE;
1333
1334   rule->kdbus_cookie = ++(matchmaker->last_cookie);
1335
1336   bus_match_rule_ref (rule);
1337
1338 #ifdef DBUS_ENABLE_VERBOSE_MODE
1339   {
1340     char *s = match_rule_to_string (rule);
1341
1342     _dbus_verbose ("Added match rule %s to connection %p\n",
1343                    s, rule->matches_go_to);
1344     dbus_free (s);
1345   }
1346 #endif
1347
1348   return TRUE;
1349 }
1350
1351 DBusList*
1352 matchmaker_get_rules_list (Matchmaker   *matchmaker,
1353                            MatchRule    *rule)
1354 {
1355   DBusList** list;
1356
1357   list = matchmaker_get_rules (matchmaker, rule->message_type,
1358       rule->interface, FALSE);
1359
1360   if(list)
1361     return *list;
1362
1363   return NULL;
1364 }
1365
1366 dbus_bool_t
1367 match_rule_equal_lib (MatchRule *a,
1368                   MatchRule *b)
1369 {
1370   if (a->flags != b->flags)
1371     return FALSE;
1372
1373   if (a->matches_go_to != b->matches_go_to)
1374     return FALSE;
1375
1376   if ((a->flags &MATCH_MESSAGE_TYPE) &&
1377       a->message_type != b->message_type)
1378     return FALSE;
1379
1380   if ((a->flags &MATCH_MEMBER) &&
1381       strcmp (a->member, b->member) != 0)
1382     return FALSE;
1383
1384   if ((a->flags &MATCH_PATH) &&
1385       strcmp (a->path, b->path) != 0)
1386     return FALSE;
1387
1388   if ((a->flags &MATCH_INTERFACE) &&
1389       strcmp (a->interface, b->interface) != 0)
1390     return FALSE;
1391
1392   if ((a->flags &MATCH_SENDER) &&
1393       strcmp (a->sender, b->sender) != 0)
1394     return FALSE;
1395
1396   if ((a->flags &MATCH_DESTINATION) &&
1397       strcmp (a->destination, b->destination) != 0)
1398     return FALSE;
1399
1400   /* we already compared the value of flags, and
1401    *MATCH_CLIENT_IS_EAVESDROPPING does not have another struct member */
1402
1403   if (a->flags &MATCH_ARGS)
1404     {
1405       int i;
1406
1407       if (a->args_len != b->args_len)
1408         return FALSE;
1409
1410       i = 0;
1411       while (i < a->args_len)
1412         {
1413           int length;
1414
1415           if ((a->args[i] != NULL) != (b->args[i] != NULL))
1416             return FALSE;
1417
1418           if (a->arg_lens[i] != b->arg_lens[i])
1419             return FALSE;
1420
1421           length = a->arg_lens[i] & ~MATCH_ARG_FLAGS;
1422
1423           if (a->args[i] != NULL)
1424             {
1425               _dbus_assert (b->args[i] != NULL);
1426               if (memcmp (a->args[i], b->args[i], length) != 0)
1427                 return FALSE;
1428             }
1429
1430           ++i;
1431         }
1432     }
1433
1434   return TRUE;
1435 }
1436
1437 static void
1438 bus_matchmaker_remove_rule_link (DBusList       **rules,
1439                                  DBusList        *link)
1440 {
1441   MatchRule *rule = link->data;
1442
1443   _dbus_list_remove_link (rules, link);
1444
1445 #ifdef DBUS_ENABLE_VERBOSE_MODE
1446   {
1447     char *s = match_rule_to_string (rule);
1448
1449     _dbus_verbose ("Removed match rule %s for connection %p\n",
1450                    s, rule->matches_go_to);
1451     dbus_free (s);
1452   }
1453 #endif
1454
1455   match_rule_unref (rule);
1456 }
1457
1458 /* Remove a single rule which is equal to the given rule by value */
1459 dbus_bool_t
1460 matchmaker_remove_rule_by_value (Matchmaker   *matchmaker,
1461                                      MatchRule    *value,
1462                                      DBusError       *error)
1463 {
1464   DBusList **rules;
1465   DBusList *link = NULL;
1466
1467   _dbus_verbose ("Removing rule by value with message_type %d, interface %s\n",
1468                  value->message_type,
1469                  value->interface != NULL ? value->interface : "<null>");
1470
1471   rules = matchmaker_get_rules (matchmaker, value->message_type,
1472       value->interface, FALSE);
1473
1474   if (rules != NULL)
1475     {
1476       /* we traverse backward because bus_connection_remove_match_rule()
1477        * removes the most-recently-added rule
1478        */
1479       link = _dbus_list_get_last_link (rules);
1480       while (link != NULL)
1481         {
1482           MatchRule *rule;
1483           DBusList *prev;
1484
1485           rule = link->data;
1486           prev = _dbus_list_get_prev_link (rules, link);
1487
1488           if (match_rule_equal_lib (rule, value))
1489             {
1490               bus_matchmaker_remove_rule_link (rules, link);
1491               break;
1492             }
1493
1494           link = prev;
1495         }
1496     }
1497
1498   if (link == NULL)
1499     {
1500       dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND,
1501                       "The given match rule wasn't found and can't be removed");
1502       return FALSE;
1503     }
1504
1505   bus_matchmaker_gc_rules (matchmaker, value->message_type, value->interface,
1506       rules);
1507
1508   return TRUE;
1509 }
1510
1511 static void
1512 rule_list_remove (DBusList **rules)
1513 {
1514   DBusList *link;
1515
1516   link = _dbus_list_get_first_link (rules);
1517   while (link != NULL)
1518     {
1519       DBusList *next;
1520
1521       next = _dbus_list_get_next_link (rules, link);
1522       bus_matchmaker_remove_rule_link (rules, link);
1523       link = next;
1524     }
1525 }
1526
1527 void
1528 free_matchmaker (Matchmaker *matchmaker)
1529 {
1530   int i;
1531
1532   _dbus_verbose ("Removing all rules for connection\n");
1533
1534   for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1535     {
1536       RulePool *p = matchmaker->rules_by_type + i;
1537       DBusHashIter iter;
1538
1539       rule_list_remove (&p->rules_without_iface);
1540
1541       _dbus_hash_iter_init (p->rules_by_iface, &iter);
1542       while (_dbus_hash_iter_next (&iter))
1543         {
1544           DBusList **items = _dbus_hash_iter_get_value (&iter);
1545
1546           rule_list_remove (items);
1547
1548           if (*items == NULL)
1549             _dbus_hash_iter_remove_entry (&iter);
1550         }
1551       _dbus_hash_table_unref (p->rules_by_iface);
1552     }
1553   dbus_free (matchmaker);
1554 }
1555
1556 int
1557 _match_rule_get_message_type (MatchRule *rule)
1558 {
1559   if (rule->flags & MATCH_MESSAGE_TYPE)
1560     return rule->message_type;
1561   else
1562     return DBUS_MESSAGE_TYPE_INVALID;
1563 }
1564
1565 const char *
1566 _match_rule_get_interface (MatchRule *rule)
1567 {
1568   if (rule->flags & MATCH_INTERFACE)
1569     return rule->interface;
1570   else
1571     return NULL;
1572 }
1573
1574 const char *
1575 _match_rule_get_member (MatchRule *rule)
1576 {
1577   if (rule->flags & MATCH_MEMBER)
1578     return rule->member;
1579   else
1580     return NULL;
1581 }
1582
1583 const char *
1584 _match_rule_get_sender (MatchRule *rule)
1585 {
1586   if (rule->flags & MATCH_SENDER)
1587     return rule->sender;
1588   else
1589     return NULL;
1590 }
1591
1592 const char *
1593 _match_rule_get_destination (MatchRule *rule)
1594 {
1595   if (rule->flags & MATCH_DESTINATION)
1596     return rule->destination;
1597   else
1598     return NULL;
1599 }
1600
1601 const char *
1602 _match_rule_get_path (MatchRule *rule)
1603 {
1604   if (rule->flags & MATCH_PATH)
1605     return rule->path;
1606   else
1607     return NULL;
1608 }
1609
1610 const char *
1611 _match_rule_get_path_namespace (MatchRule *rule)
1612 {
1613   if (rule->flags & MATCH_PATH_NAMESPACE)
1614     return rule->path;
1615   else
1616     return NULL;
1617 }
1618
1619 int
1620 _match_rule_get_args_len (MatchRule *rule)
1621 {
1622   return rule->args_len;
1623 }
1624
1625 const char *
1626 _match_rule_get_args (MatchRule *rule, int i)
1627 {
1628   return rule->args[i];
1629 }
1630
1631 unsigned int
1632 _match_rule_get_arg_lens (MatchRule *rule, int i)
1633 {
1634   return rule->arg_lens[i];
1635 }