summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-10-10 02:42:21 +0000
committerHavoc Pennington <hp@redhat.com>2003-10-10 02:42:21 +0000
commit6a65f4802e95ba442c520f8e225da837e0a9f73b (patch)
tree734e69da90869b3788d381e75911d720ad8cfd0f
parent79d03f94fec278d270a33792aeffb33ba239bb01 (diff)
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
-rw-r--r--ChangeLog19
-rw-r--r--bus/bus.c25
-rw-r--r--bus/config-parser.c19
-rw-r--r--bus/dispatch.c3
-rw-r--r--bus/policy.c17
-rw-r--r--bus/signals.c623
-rw-r--r--dbus/dbus-errors.h1
-rw-r--r--dbus/dbus-message.c28
-rw-r--r--dbus/dbus-message.h2
-rw-r--r--tools/dbus-send.c8
10 files changed, 689 insertions, 56 deletions
diff --git a/ChangeLog b/ChangeLog
index d062f3f8..920c23f4 100644
--- 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
diff --git a/bus/bus.c b/bus/bus.c
index 4087334e..d649199e 100644
--- 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)
{
diff --git a/bus/config-parser.c b/bus/config-parser.c
index 7b9b962d..3ff3ec50 100644
--- a/bus/config-parser.c
+++ b/bus/config-parser.c
@@ -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,
diff --git a/bus/dispatch.c b/bus/dispatch.c
index 606c68ef..e238cb4c 100644
--- a/bus/dispatch.c
+++ b/bus/dispatch.c
@@ -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);
diff --git a/bus/policy.c b/bus/policy.c
index 2d462fb6..71137ca9 100644
--- a/bus/policy.c
+++ b/bus/policy.c
@@ -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
diff --git a/bus/signals.c b/bus/signals.c
index 30d977c3..960d846c 100644
--- a/bus/signals.c
+++ b/bus/signals.c
@@ -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;
}
diff --git a/dbus/dbus-errors.h b/dbus/dbus-errors.h
index f229188a..b7b601bf 100644
--- a/dbus/dbus-errors.h
+++ b/dbus/dbus-errors.h
@@ -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"
diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c
index 19457468..38fd3790 100644
--- a/dbus/dbus-message.c
+++ b/dbus/dbus-message.c
@@ -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"
diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h
index 888fe862..bfaf2f0d 100644
--- a/dbus/dbus-message.h
+++ b/dbus/dbus-message.h
@@ -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 */
diff --git a/tools/dbus-send.c b/tools/dbus-send.c
index 06a87adb..d0cca2fd 100644
--- a/tools/dbus-send.c
+++ b/tools/dbus-send.c
@@ -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);