2003-10-09 Havoc Pennington <hp@redhat.com>
authorHavoc Pennington <hp@redhat.com>
Fri, 10 Oct 2003 02:42:21 +0000 (02:42 +0000)
committerHavoc Pennington <hp@redhat.com>
Fri, 10 Oct 2003 02:42:21 +0000 (02:42 +0000)
        Make matching rules theoretically work (add parser).

* bus/bus.c (bus_context_check_security_policy): fix up to handle
the case where destination is explicitly specified as bus driver
and someone else is eavesdropping.

* bus/policy.c (bus_client_policy_check_can_receive): fix up
definition of eavesdropping and assertion

* tools/dbus-send.c (main): use dbus_message_type_from_string

* bus/signals.c (bus_match_rule_parse): implement

* dbus/dbus-message.c (dbus_message_type_from_string): new

* dbus/dbus-errors.h (DBUS_ERROR_MATCH_RULE_INVALID): add

ChangeLog
bus/bus.c
bus/config-parser.c
bus/dispatch.c
bus/policy.c
bus/signals.c
dbus/dbus-errors.h
dbus/dbus-message.c
dbus/dbus-message.h
tools/dbus-send.c

index d062f3f..920c23f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2003-10-09  Havoc Pennington  <hp@redhat.com>
+
+        Make matching rules theoretically work (add parser).
+       
+       * bus/bus.c (bus_context_check_security_policy): fix up to handle
+       the case where destination is explicitly specified as bus driver
+       and someone else is eavesdropping.
+       
+       * bus/policy.c (bus_client_policy_check_can_receive): fix up
+       definition of eavesdropping and assertion
+
+       * tools/dbus-send.c (main): use dbus_message_type_from_string
+
+       * bus/signals.c (bus_match_rule_parse): implement
+
+       * dbus/dbus-message.c (dbus_message_type_from_string): new
+
+       * dbus/dbus-errors.h (DBUS_ERROR_MATCH_RULE_INVALID): add
+
 2003-10-02  Havoc Pennington  <hp@pobox.com>
 
        * glib/dbus-gproxy.c (dbus_gproxy_call_no_reply): rename from
index 4087334..d649199 100644 (file)
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -872,6 +872,19 @@ bus_context_get_max_match_rules_per_connection (BusContext *context)
   return context->limits.max_match_rules_per_connection;
 }
 
+/*
+ * addressed_recipient is the recipient specified in the message.
+ *
+ * proposed_recipient is the recipient we're considering sending
+ * to right this second, and may be an eavesdropper.
+ *
+ * sender is the sender of the message.
+ *
+ * NULL for proposed_recipient or sender definitely means the bus driver.
+ *
+ * NULL for addressed_recipient may mean the bus driver, or may mean
+ * no destination was specified in the message (e.g. a signal).
+ */
 dbus_bool_t
 bus_context_check_security_policy (BusContext     *context,
                                    DBusConnection *sender,
@@ -883,15 +896,9 @@ bus_context_check_security_policy (BusContext     *context,
   BusClientPolicy *sender_policy;
   BusClientPolicy *recipient_policy;
 
-  /* NULL sender, proposed_recipient means the bus driver.  NULL
-   * addressed_recipient means the message didn't specify an explicit
-   * target. If proposed_recipient is NULL, then addressed_recipient
-   * is also NULL but is implicitly the bus driver.
-   */
-
-  _dbus_assert (proposed_recipient == NULL ||
-                (dbus_message_get_destination (message) == NULL ||
-                 addressed_recipient != NULL));
+  _dbus_assert (dbus_message_get_destination (message) == NULL || /* Signal */
+                (addressed_recipient != NULL ||
+                 strcmp (dbus_message_get_destination (message), DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) == 0)); /* Destination specified or is the bus driver */
   
   if (sender != NULL)
     {
index 7b9b962..3ff3ec5 100644 (file)
@@ -813,21 +813,6 @@ start_busconfig_child (BusConfigParser   *parser,
     }
 }
 
-static int
-message_type_from_string (const char *type_str)
-{
-  if (strcmp (type_str, "method_call") == 0)
-    return DBUS_MESSAGE_TYPE_METHOD_CALL;
-  if (strcmp (type_str, "method_return") == 0)
-    return DBUS_MESSAGE_TYPE_METHOD_RETURN;
-  else if (strcmp (type_str, "signal") == 0)
-    return DBUS_MESSAGE_TYPE_SIGNAL;
-  else if (strcmp (type_str, "error") == 0)
-    return DBUS_MESSAGE_TYPE_ERROR;
-  else
-    return DBUS_MESSAGE_TYPE_INVALID;
-}
-
 static dbus_bool_t
 append_rule_from_element (BusConfigParser   *parser,
                           const char        *element_name,
@@ -1027,7 +1012,7 @@ append_rule_from_element (BusConfigParser   *parser,
       message_type = DBUS_MESSAGE_TYPE_INVALID;
       if (send_type != NULL)
         {
-          message_type = message_type_from_string (send_type);
+          message_type = dbus_message_type_from_string (send_type);
           if (message_type == DBUS_MESSAGE_TYPE_INVALID)
             {
               dbus_set_error (error, DBUS_ERROR_FAILED,
@@ -1079,7 +1064,7 @@ append_rule_from_element (BusConfigParser   *parser,
       message_type = DBUS_MESSAGE_TYPE_INVALID;
       if (receive_type != NULL)
         {
-          message_type = message_type_from_string (receive_type);
+          message_type = dbus_message_type_from_string (receive_type);
           if (message_type == DBUS_MESSAGE_TYPE_INVALID)
             {
               dbus_set_error (error, DBUS_ERROR_FAILED,
index 606c68e..e238cb4 100644 (file)
@@ -920,7 +920,8 @@ check_add_match_all (BusContext     *context,
   if (message == NULL)
     return TRUE;
 
-  if (!dbus_message_append_args (message, DBUS_TYPE_STRING, "", /* FIXME */
+  /* empty string match rule matches everything */
+  if (!dbus_message_append_args (message, DBUS_TYPE_STRING, "",
                                  DBUS_TYPE_INVALID))
     {
       dbus_message_unref (message);
index 2d462fb..71137ca 100644 (file)
@@ -913,6 +913,9 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
   return allowed;
 }
 
+/* See docs on what the args mean on bus_context_check_security_policy()
+ * comment
+ */
 dbus_bool_t
 bus_client_policy_check_can_receive (BusClientPolicy *policy,
                                      BusRegistry     *registry,
@@ -924,20 +927,10 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
   DBusList *link;
   dbus_bool_t allowed;
   dbus_bool_t eavesdropping;
-  
-  /* NULL sender, proposed_recipient means the bus driver.  NULL
-   * addressed_recipient means the message didn't specify an explicit
-   * target. If proposed_recipient is NULL, then addressed_recipient
-   * is also NULL but is implicitly the bus driver.
-   */
 
-  _dbus_assert (proposed_recipient == NULL ||
-                (dbus_message_get_destination (message) == NULL ||
-                 addressed_recipient != NULL));
-  
   eavesdropping =
-    (proposed_recipient == NULL || /* explicitly to bus driver */
-     (addressed_recipient && addressed_recipient != proposed_recipient)); /* explicitly to a different recipient */
+    addressed_recipient != proposed_recipient &&
+    dbus_message_get_destination (message) != NULL;
   
   /* policy->rules is in the order the rules appeared
    * in the config file, i.e. last rule that applies wins
index 30d977c..960d846 100644 (file)
@@ -52,6 +52,10 @@ bus_match_rule_new (DBusConnection *matches_go_to)
   rule->refcount = 1;
   rule->matches_go_to = matches_go_to;
 
+#ifndef DBUS_BUILD_TESTS
+  _dbus_assert (rule->matches_go_to != NULL);
+#endif
+  
   return rule;
 }
 
@@ -285,6 +289,285 @@ bus_match_rule_set_path (BusMatchRule *rule,
   return TRUE;
 }
 
+#define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
+
+static dbus_bool_t
+find_key (const DBusString *str,
+          int               start,
+          DBusString       *key,
+          int              *value_pos,
+          DBusError        *error)
+{
+  const char *p;
+  const char *s;
+  const char *key_start;
+  const char *key_end;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+  
+  s = _dbus_string_get_const_data (str);
+
+  p = s + start;
+
+  while (*p && ISWHITE (*p))
+    ++p;
+
+  key_start = p;
+
+  while (*p && *p != '=' && !ISWHITE (*p))
+    ++p;
+
+  key_end = p;
+
+  while (*p && ISWHITE (*p))
+    ++p;
+  
+  if (key_start == key_end)
+    {
+      /* Empty match rules or trailing whitespace are OK */
+      *value_pos = p - s;
+      return TRUE;
+    }
+
+  if (*p != '=')
+    {
+      dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
+                      "Match rule has a key with no subsequent '=' character");
+      return FALSE;
+    }
+  ++p;
+  
+  if (!_dbus_string_append_len (key, key_start, key_end - key_start))
+    {
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+
+  *value_pos = p - s;
+  
+  return TRUE;
+}
+
+static dbus_bool_t
+find_value (const DBusString *str,
+            int               start,
+            const char       *key,
+            DBusString       *value,
+            int              *value_end,
+            DBusError        *error)
+{
+  const char *p;
+  const char *s;
+  char quote_char;
+  int orig_len;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+  
+  orig_len = _dbus_string_get_length (value);
+  
+  s = _dbus_string_get_const_data (str);
+
+  p = s + start;
+
+  quote_char = '\0';
+
+  while (*p)
+    {
+      if (quote_char == '\0')
+        {
+          switch (*p)
+            {
+            case '\0':
+              goto done;
+
+            case '\'':
+              quote_char = '\'';
+              goto next;
+              
+            case ',':
+              ++p;
+              goto done;
+
+            case '\\':
+              quote_char = '\\';
+              goto next;
+              
+            default:
+              if (!_dbus_string_append_byte (value, *p))
+                {
+                  BUS_SET_OOM (error);
+                  goto failed;
+                }
+            }
+        }
+      else if (quote_char == '\\')
+        {
+          /* \ only counts as an escape if escaping a quote mark */
+          if (*p != '\'')
+            {
+              if (!_dbus_string_append_byte (value, '\\'))
+                {
+                  BUS_SET_OOM (error);
+                  goto failed;
+                }
+            }
+
+          if (!_dbus_string_append_byte (value, *p))
+            {
+              BUS_SET_OOM (error);
+              goto failed;
+            }
+          
+          quote_char = '\0';
+        }
+      else
+        {
+          _dbus_assert (quote_char == '\'');
+
+          if (*p == '\'')
+            {
+              quote_char = '\0';
+            }
+          else
+            {
+              if (!_dbus_string_append_byte (value, *p))
+                {
+                  BUS_SET_OOM (error);
+                  goto failed;
+                }
+            }
+        }
+
+    next:
+      ++p;
+    }
+
+ done:
+
+  if (quote_char == '\\')
+    {
+      if (!_dbus_string_append_byte (value, '\\'))
+        {
+          BUS_SET_OOM (error);
+          goto failed;
+        }
+    }
+  else if (quote_char == '\'')
+    {
+      dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
+                      "Unbalanced quotation marks in match rule");
+      goto failed;
+    }
+  else
+    _dbus_assert (quote_char == '\0');
+
+  /* Zero-length values are allowed */
+  
+  *value_end = p - s;
+  
+  return TRUE;
+
+ failed:
+  _DBUS_ASSERT_ERROR_IS_SET (error);
+  _dbus_string_set_length (value, orig_len);
+  return FALSE;
+}
+
+/* duplicates aren't allowed so the real legitimate max is only 6 or
+ * so. Leaving extra so we don't have to bother to update it.
+ */
+#define MAX_RULE_TOKENS 16
+
+/* this is slightly too high level to be termed a "token"
+ * but let's not be pedantic.
+ */
+typedef struct
+{
+  char *key;
+  char *value;
+} RuleToken;
+
+static dbus_bool_t
+tokenize_rule (const DBusString *rule_text,
+               RuleToken         tokens[MAX_RULE_TOKENS],
+               DBusError        *error) 
+{
+  int i;
+  int pos;
+  DBusString key;
+  DBusString value;
+  dbus_bool_t retval;
+
+  retval = FALSE;
+  
+  if (!_dbus_string_init (&key))
+    {
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+
+  if (!_dbus_string_init (&value))
+    {
+      _dbus_string_free (&key);
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+
+  i = 0;
+  pos = 0;
+  while (i < MAX_RULE_TOKENS &&
+         pos < _dbus_string_get_length (rule_text))
+    {
+      _dbus_assert (tokens[i].key == NULL);
+      _dbus_assert (tokens[i].value == NULL);
+
+      if (!find_key (rule_text, pos, &key, &pos, error))
+        goto out;
+
+      if (_dbus_string_get_length (&key) == 0)
+        goto next;
+      
+      if (!_dbus_string_steal_data (&key, &tokens[i].key))
+        {
+          BUS_SET_OOM (error);
+          goto out;
+        }
+
+      if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error))
+        goto out;
+
+      if (!_dbus_string_steal_data (&value, &tokens[i].value))
+        {
+          BUS_SET_OOM (error);
+          goto out;
+        }
+
+    next:
+      ++i;
+    }
+
+  retval = TRUE;
+  
+ out:
+  if (!retval)
+    {
+      i = 0;
+      while (tokens[i].key || tokens[i].value)
+        {
+          dbus_free (tokens[i].key);
+          dbus_free (tokens[i].value);
+          tokens[i].key = NULL;
+          tokens[i].value = NULL;
+          ++i;
+        }
+    }
+  
+  _dbus_string_free (&key);
+  _dbus_string_free (&value);
+  
+  return retval;
+}
+
 /*
  * The format is comma-separated with strings quoted with single quotes
  * as for the shell (to escape a literal single quote, use '\'').
@@ -299,24 +582,157 @@ bus_match_rule_parse (DBusConnection   *matches_go_to,
                       DBusError        *error)
 {
   BusMatchRule *rule;
-
+  RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
+  int i;
+  
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+  
+  memset (tokens, '\0', sizeof (tokens));
+  
   rule = bus_match_rule_new (matches_go_to);
   if (rule == NULL)
-    goto oom;
-
-  /* FIXME implement for real */
+    {
+      BUS_SET_OOM (error);
+      goto failed;
+    }
   
-  if (!bus_match_rule_set_message_type (rule,
-                                        DBUS_MESSAGE_TYPE_SIGNAL))
-    goto oom;
+  if (!tokenize_rule (rule_text, tokens, error))
+    goto failed;
   
-  return rule;
+  i = 0;
+  while (tokens[i].key != NULL)
+    {
+      const char *key = tokens[i].key;
+      const char *value = tokens[i].value;
+      
+      if (strcmp (key, "type") == 0)
+        {
+          int t;
+
+          if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
+            {
+              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
+                              "Key %s specified twice in match rule\n", key);
+              goto failed;
+            }
+          
+          t = dbus_message_type_from_string (value);
+          
+          if (!bus_match_rule_set_message_type (rule, t))
+            {
+              BUS_SET_OOM (error);
+              goto failed;
+            }
+        }
+      else if (strcmp (key, "sender") == 0)
+        {
+          if (rule->flags & BUS_MATCH_SENDER)
+            {
+              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
+                              "Key %s specified twice in match rule\n", key);
+              goto failed;
+            }
+
+          if (!bus_match_rule_set_sender (rule, value))
+            {
+              BUS_SET_OOM (error);
+              goto failed;
+            }
+        }
+      else if (strcmp (key, "interface") == 0)
+        {
+          if (rule->flags & BUS_MATCH_INTERFACE)
+            {
+              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
+                              "Key %s specified twice in match rule\n", key);
+              goto failed;
+            }
+
+          if (!bus_match_rule_set_interface (rule, value))
+            {
+              BUS_SET_OOM (error);
+              goto failed;
+            }
+        }
+      else if (strcmp (key, "member") == 0)
+        {
+          if (rule->flags & BUS_MATCH_MEMBER)
+            {
+              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
+                              "Key %s specified twice in match rule\n", key);
+              goto failed;
+            }
+
+          if (!bus_match_rule_set_member (rule, value))
+            {
+              BUS_SET_OOM (error);
+              goto failed;
+            }
+        }
+      else if (strcmp (key, "path") == 0)
+        {
+          if (rule->flags & BUS_MATCH_PATH)
+            {
+              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
+                              "Key %s specified twice in match rule\n", key);
+              goto failed;
+            }
+
+          if (!bus_match_rule_set_path (rule, value))
+            {
+              BUS_SET_OOM (error);
+              goto failed;
+            }
+        }
+      else if (strcmp (key, "destination") == 0)
+        {
+          if (rule->flags & BUS_MATCH_DESTINATION)
+            {
+              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
+                              "Key %s specified twice in match rule\n", key);
+              goto failed;
+            }
+
+          if (!bus_match_rule_set_destination (rule, value))
+            {
+              BUS_SET_OOM (error);
+              goto failed;
+            }
+        }
+      else
+        {
+          dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
+                          "Unknown key \"%s\" in match rule",
+                          key);
+          goto failed;
+        }
+
+      ++i;
+    }
+  
+
+  goto out;
   
- oom:
+ failed:
+  _DBUS_ASSERT_ERROR_IS_SET (error);
   if (rule)
-    bus_match_rule_unref (rule);
-  BUS_SET_OOM (error);
-  return NULL;
+    {
+      bus_match_rule_unref (rule);
+      rule = NULL;
+    }
+
+ out:
+  
+  i = 0;
+  while (tokens[i].key || tokens[i].value)
+    {
+      _dbus_assert (i < MAX_RULE_TOKENS);
+      dbus_free (tokens[i].key);
+      dbus_free (tokens[i].value);
+      ++i;
+    }
+  
+  return rule;
 }
 
 struct BusMatchmaker
@@ -760,6 +1176,186 @@ bus_matchmaker_get_recipients (BusMatchmaker   *matchmaker,
 
 #ifdef DBUS_BUILD_TESTS
 #include "test.h"
+#include <stdlib.h>
+
+static BusMatchRule*
+check_parse (dbus_bool_t should_succeed,
+             const char *text)
+{
+  BusMatchRule *rule;
+  DBusString str;
+  DBusError error;
+
+  dbus_error_init (&error);
+
+  _dbus_string_init_const (&str, text);
+  
+  rule = bus_match_rule_parse (NULL, &str, &error);
+  if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
+    {
+      dbus_error_free (&error);
+      return NULL;
+    }
+
+  if (should_succeed && rule == NULL)
+    {
+      _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n",
+                  error.name, error.message,
+                  _dbus_string_get_const_data (&str));
+      exit (1);
+    }
+
+  if (!should_succeed && rule != NULL)
+    {
+      _dbus_warn ("Failed to fail to parse: \"%s\"\n",
+                  _dbus_string_get_const_data (&str));
+      exit (1);
+    }
+
+  dbus_error_free (&error);
+
+  return rule;
+}
+
+static void
+assert_large_rule (BusMatchRule *rule)
+{
+  _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
+  _dbus_assert (rule->flags & BUS_MATCH_SENDER);
+  _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
+  _dbus_assert (rule->flags & BUS_MATCH_MEMBER);
+  _dbus_assert (rule->flags & BUS_MATCH_DESTINATION);
+  _dbus_assert (rule->flags & BUS_MATCH_PATH);
+
+  _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
+  _dbus_assert (rule->interface != NULL);
+  _dbus_assert (rule->member != NULL);
+  _dbus_assert (rule->sender != NULL);
+  _dbus_assert (rule->destination != NULL);
+  _dbus_assert (rule->path != NULL);
+
+  _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0);
+  _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0);
+  _dbus_assert (strcmp (rule->member, "Foo") == 0);
+  _dbus_assert (strcmp (rule->path, "/bar/foo") == 0);
+  _dbus_assert (strcmp (rule->destination, ":452345-34") == 0);
+}
+
+static dbus_bool_t
+test_parsing (void *data)
+{
+  BusMatchRule *rule;
+
+  rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345-34'");
+  if (rule != NULL)
+    {
+      assert_large_rule (rule);
+      bus_match_rule_unref (rule);
+    }
+
+  /* With extra whitespace and useless quotes */
+  rule = check_parse (TRUE, "    type='signal',  \tsender='org.freedes''ktop.DBusSender',   interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345-34'''''");
+  if (rule != NULL)
+    {
+      assert_large_rule (rule);
+      bus_match_rule_unref (rule);
+    }
+
+
+  /* A simple signal connection */
+  rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'");
+  if (rule != NULL)
+    {
+      _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
+      _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
+      _dbus_assert (rule->flags & BUS_MATCH_PATH);
+
+      _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
+      _dbus_assert (rule->interface != NULL);
+      _dbus_assert (rule->path != NULL);
+
+      _dbus_assert (strcmp (rule->interface, "org.Bar") == 0);
+      _dbus_assert (strcmp (rule->path, "/foo") == 0);
+  
+      bus_match_rule_unref (rule);
+    }
+
+  /* Reject duplicates */
+  rule = check_parse (FALSE, "type='signal',type='method_call'");
+  _dbus_assert (rule == NULL);
+
+  /* Reject broken keys */
+  rule = check_parse (FALSE, "blah='signal'");
+  _dbus_assert (rule == NULL);
+
+  /* Allow empty rule */
+  rule = check_parse (TRUE, "");
+  if (rule != NULL)
+    {
+      _dbus_assert (rule->flags == 0);
+      
+      bus_match_rule_unref (rule);
+    }
+
+  /* All-whitespace rule is the same as empty */
+  rule = check_parse (TRUE, "    \t");
+  if (rule != NULL)
+    {
+      _dbus_assert (rule->flags == 0);
+      
+      bus_match_rule_unref (rule);
+    }
+
+  /* But with non-whitespace chars and no =value, it's not OK */
+  rule = check_parse (FALSE, "type");
+  _dbus_assert (rule == NULL);
+
+  /* Empty string values are allowed at the moment */
+  rule = check_parse (TRUE, "interface=");
+  if (rule != NULL)
+    {
+      _dbus_assert (rule->flags == BUS_MATCH_INTERFACE);
+      _dbus_assert (rule->interface);
+      _dbus_assert (strlen (rule->interface) == 0);
+      
+      bus_match_rule_unref (rule);
+    }
+
+  /* Empty string expressed with quotes */
+  rule = check_parse (TRUE, "interface=''");
+  if (rule != NULL)
+    {
+      _dbus_assert (rule->flags == BUS_MATCH_INTERFACE);
+      _dbus_assert (rule->interface);
+      _dbus_assert (strlen (rule->interface) == 0);
+      
+      bus_match_rule_unref (rule);
+    }
+
+  /* Check whitespace in a value */
+  rule = check_parse (TRUE, "interface=   ");
+  if (rule != NULL)
+    {
+      _dbus_assert (rule->flags == BUS_MATCH_INTERFACE);
+      _dbus_assert (rule->interface);
+      _dbus_assert (strcmp (rule->interface, "   ") == 0);
+      
+      bus_match_rule_unref (rule);
+    }
+
+  /* Check whitespace mixed with non-whitespace in a value */
+  rule = check_parse (TRUE, "interface= foo ");
+  if (rule != NULL)
+    {
+      _dbus_assert (rule->flags == BUS_MATCH_INTERFACE);
+      _dbus_assert (rule->interface);
+      _dbus_assert (strcmp (rule->interface, " foo ") == 0);
+      
+      bus_match_rule_unref (rule);
+    }
+  
+  return TRUE;
+}
 
 dbus_bool_t
 bus_signals_test (const DBusString *test_data_dir)
@@ -770,6 +1366,9 @@ bus_signals_test (const DBusString *test_data_dir)
   bus_matchmaker_ref (matchmaker);
   bus_matchmaker_unref (matchmaker);
   bus_matchmaker_unref (matchmaker);
+
+  if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL))
+    _dbus_assert_not_reached ("Parsing match rules test failed");
   
   return TRUE;
 }
index f229188..b7b601b 100644 (file)
@@ -73,6 +73,7 @@ struct DBusError
 #define DBUS_ERROR_UNKNOWN_METHOD             "org.freedesktop.DBus.Error.UnknownMethod"
 #define DBUS_ERROR_TIMED_OUT                  "org.freedesktop.DBus.Error.TimedOut"
 #define DBUS_ERROR_MATCH_RULE_NOT_FOUND       "org.freedesktop.DBus.Error.MatchRuleNotFound"
+#define DBUS_ERROR_MATCH_RULE_INVALID         "org.freedesktop.DBus.Error.MatchRuleInvalid"
 #define DBUS_ERROR_SPAWN_EXEC_FAILED          "org.freedesktop.DBus.Error.Spawn.ExecFailed"
 #define DBUS_ERROR_SPAWN_FORK_FAILED          "org.freedesktop.DBus.Error.Spawn.ForkFailed"
 #define DBUS_ERROR_SPAWN_CHILD_EXITED         "org.freedesktop.DBus.Error.Spawn.ChildExited"
index 1945746..38fd379 100644 (file)
@@ -5416,6 +5416,34 @@ dbus_message_get_data (DBusMessage   *message,
   return res;
 }
 
+/**
+ * Utility function to convert a machine-readable (not translated)
+ * string into a D-BUS message type.
+ *
+ * @code
+ *   "method_call"    -> DBUS_MESSAGE_TYPE_METHOD_CALL
+ *   "method_return"  -> DBUS_MESSAGE_TYPE_METHOD_RETURN
+ *   "signal"         -> DBUS_MESSAGE_TYPE_SIGNAL
+ *   "error"          -> DBUS_MESSAGE_TYPE_ERROR
+ *   anything else    -> DBUS_MESSAGE_TYPE_INVALID
+ * @endcode
+ * 
+ */
+int
+dbus_message_type_from_string (const char *type_str)
+{
+  if (strcmp (type_str, "method_call") == 0)
+    return DBUS_MESSAGE_TYPE_METHOD_CALL;
+  if (strcmp (type_str, "method_return") == 0)
+    return DBUS_MESSAGE_TYPE_METHOD_RETURN;
+  else if (strcmp (type_str, "signal") == 0)
+    return DBUS_MESSAGE_TYPE_SIGNAL;
+  else if (strcmp (type_str, "error") == 0)
+    return DBUS_MESSAGE_TYPE_ERROR;
+  else
+    return DBUS_MESSAGE_TYPE_INVALID;
+}
+
 /** @} */
 #ifdef DBUS_BUILD_TESTS
 #include "dbus-test.h"
index 888fe86..bfaf2f0 100644 (file)
@@ -275,6 +275,8 @@ dbus_bool_t dbus_message_set_data           (DBusMessage      *message,
 void*       dbus_message_get_data           (DBusMessage      *message,
                                              dbus_int32_t      slot);
 
+int dbus_message_type_from_string (const char *type_str);
+
 DBUS_END_DECLS;
 
 #endif /* DBUS_MESSAGE_H */
index 06a87ad..d0cca2f 100644 (file)
@@ -86,11 +86,9 @@ main (int argc, char *argv[])
 
   if (type_str != NULL)
     {
-      if (strcmp (type_str, "method_call") == 0)
-        message_type = DBUS_MESSAGE_TYPE_METHOD_CALL;
-      else if (strcmp (type_str, "signal") == 0)
-        message_type = DBUS_MESSAGE_TYPE_SIGNAL;
-      else
+      message_type = dbus_message_type_from_string (type_str);
+      if (!(message_type == DBUS_MESSAGE_TYPE_METHOD_CALL ||
+            message_type == DBUS_MESSAGE_TYPE_SIGNAL))
         {
           fprintf (stderr, "Message type \"%s\" is not supported\n",
                    type_str);