From 7f39b487d116dc61b43254c980bc81822c7a1f5c Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Wed, 3 Nov 2010 17:21:01 +0000 Subject: Add test cases for argXpath matching --- bus/signals.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 3 deletions(-) (limited to 'bus') diff --git a/bus/signals.c b/bus/signals.c index 6f97b2b3..15a86da2 100644 --- a/bus/signals.c +++ b/bus/signals.c @@ -2025,7 +2025,22 @@ test_parsing (void *data) bus_match_rule_unref (rule); } - + + rule = check_parse (TRUE, "arg7path='/foo'"); + if (rule != NULL) + { + _dbus_assert (rule->flags = BUS_MATCH_ARGS); + _dbus_assert (rule->args != NULL); + _dbus_assert (rule->args_len == 8); + _dbus_assert (rule->args[7] != NULL); + _dbus_assert (rule->args[8] == NULL); + _dbus_assert (strcmp (rule->args[7], "/foo") == 0); + _dbus_assert ((rule->arg_lens[7] & BUS_MATCH_ARG_IS_PATH) + == BUS_MATCH_ARG_IS_PATH); + + bus_match_rule_unref (rule); + } + /* Too-large argN */ rule = check_parse (FALSE, "arg300='foo'"); _dbus_assert (rule == NULL); @@ -2175,6 +2190,12 @@ should_match_message_1[] = { "type='signal',member='Frobated',arg0='foobar'", "member='Frobated',arg0='foobar'", "type='signal',arg0='foobar'", + /* The definition of argXpath matches says: "As with normal argument matches, + * if the argument is exactly equal to the string given in the match rule + * then the rule is satisfied." So this should match (even though the + * argument is not a valid path)! + */ + "arg0path='foobar'", NULL }; @@ -2193,6 +2214,9 @@ should_not_match_message_1[] = { "arg0='foobar',arg1='abcdef'", "arg0='foobar',arg1='abcdef',arg2='abcdefghi',arg3='abcdefghi',arg4='abcdefghi'", "arg0='foobar',arg1='abcdef',arg4='abcdefghi',arg3='abcdefghi',arg2='abcdefghi'", + "arg0path='foo'", + "arg0path='foobar/'", + "arg1path='3'", NULL }; @@ -2272,6 +2296,81 @@ test_matching (void) dbus_message_unref (message1); } +#define PATH_MATCH_RULE "arg0path='/aa/bb/'" + +/* This is a list of paths that should be matched by PATH_MATCH_RULE, taken + * from the specification. Notice that not all of them are actually legal D-Bus + * paths. The author of this test takes no responsibility for the semantics of + * this match rule key. + */ +static const char *paths_that_should_be_matched[] = { + "/", + "/aa/", + "/aa/bb/", + "/aa/bb/cc/", + "/aa/bb/cc", + NULL +}; + +/* These paths should not be matched by PATH_MATCH_RULE. */ +static const char *paths_that_should_not_be_matched[] = { + "/aa/b", + "/aa", + /* or even... */ + "/aa/bb", + NULL +}; + +static void +test_path_match (const char *path, + const char *rule_text, + BusMatchRule *rule, + dbus_bool_t should_match) +{ + DBusMessage *message = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL); + dbus_bool_t matched; + + _dbus_assert (message != NULL); + if (!dbus_message_set_member (message, "Foo")) + _dbus_assert_not_reached ("oom"); + + if (!dbus_message_append_args (message, + DBUS_TYPE_STRING, &path, + NULL)) + _dbus_assert_not_reached ("oom"); + + matched = match_rule_matches (rule, NULL, NULL, message, 0); + + if (matched != should_match) + { + _dbus_warn ("Expected rule %s to %s message with first arg %s, failed\n", + rule_text, + should_match ? "match" : "not match", + path); + exit (1); + } + + dbus_message_unref (message); +} + +static void +test_path_matching (void) +{ + BusMatchRule *rule; + const char **s; + + rule = check_parse (TRUE, PATH_MATCH_RULE); + _dbus_assert (rule != NULL); + + for (s = paths_that_should_be_matched; *s != NULL; s++) + test_path_match (*s, PATH_MATCH_RULE, rule, TRUE); + + for (s = paths_that_should_not_be_matched; *s != NULL; s++) + test_path_match (*s, PATH_MATCH_RULE, rule, FALSE); + + bus_match_rule_unref (rule); +} + dbus_bool_t bus_signals_test (const DBusString *test_data_dir) { @@ -2286,9 +2385,9 @@ bus_signals_test (const DBusString *test_data_dir) _dbus_assert_not_reached ("Parsing match rules test failed"); test_equality (); - test_matching (); - + test_path_matching (); + return TRUE; } -- cgit v1.2.3 From fe79973f0a39f68a675b7470932d10b1e1262331 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Fri, 5 Nov 2010 14:14:54 -0400 Subject: Support matching path arguments with argXpath The existing implementation only matched arguments of type 's', not of type 'o'! --- bus/signals.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) (limited to 'bus') diff --git a/bus/signals.c b/bus/signals.c index 15a86da2..f059d30f 100644 --- a/bus/signals.c +++ b/bus/signals.c @@ -1687,8 +1687,9 @@ match_rule_matches (BusMatchRule *rule, { const char *actual_arg; int actual_length; - - if (current_type != DBUS_TYPE_STRING) + + if (current_type != DBUS_TYPE_STRING && + (!is_path || current_type != DBUS_TYPE_OBJECT_PATH)) return FALSE; actual_arg = NULL; @@ -2300,14 +2301,17 @@ test_matching (void) /* This is a list of paths that should be matched by PATH_MATCH_RULE, taken * from the specification. Notice that not all of them are actually legal D-Bus - * paths. The author of this test takes no responsibility for the semantics of + * paths. + * + * The author of this test takes no responsibility for the semantics of * this match rule key. */ static const char *paths_that_should_be_matched[] = { - "/", "/aa/", "/aa/bb/", "/aa/bb/cc/", +#define FIRST_VALID_PATH_WHICH_SHOULD_MATCH 3 + "/", "/aa/bb/cc", NULL }; @@ -2322,7 +2326,8 @@ static const char *paths_that_should_not_be_matched[] = { }; static void -test_path_match (const char *path, +test_path_match (int type, + const char *path, const char *rule_text, BusMatchRule *rule, dbus_bool_t should_match) @@ -2335,7 +2340,7 @@ test_path_match (const char *path, _dbus_assert_not_reached ("oom"); if (!dbus_message_append_args (message, - DBUS_TYPE_STRING, &path, + type, &path, NULL)) _dbus_assert_not_reached ("oom"); @@ -2343,10 +2348,12 @@ test_path_match (const char *path, if (matched != should_match) { - _dbus_warn ("Expected rule %s to %s message with first arg %s, failed\n", + _dbus_warn ("Expected rule %s to %s message " + "with first arg %s of type '%c', failed\n", rule_text, should_match ? "match" : "not match", - path); + path, + (char) type); exit (1); } @@ -2363,10 +2370,17 @@ test_path_matching (void) _dbus_assert (rule != NULL); for (s = paths_that_should_be_matched; *s != NULL; s++) - test_path_match (*s, PATH_MATCH_RULE, rule, TRUE); + test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, TRUE); + + for (s = paths_that_should_be_matched + FIRST_VALID_PATH_WHICH_SHOULD_MATCH; + *s != NULL; s++) + test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, TRUE); for (s = paths_that_should_not_be_matched; *s != NULL; s++) - test_path_match (*s, PATH_MATCH_RULE, rule, FALSE); + { + test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, FALSE); + test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, FALSE); + } bus_match_rule_unref (rule); } -- cgit v1.2.3 From 2f7b11158b497e759cd03664b1881f88157a9f1a Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Thu, 9 Jul 2009 21:33:24 +0100 Subject: Supporting matching argument 0 as a namespace Rather like "arg0path='/foo/'" matching all object paths starting with "/foo/", this adds support for matching a prefix of a string argument with "arg0namespace='org.freedesktop.Telepathy.Client.'" (for example). This is mostly intended for use with NameOwnerChanged and PropertiesChanged; thus, only matching the 0th argument is permitted. (This also means it could work with the multicast-plus-socket-filters model being considered for DBus-in-the-kernel without having to hash every period-separated prefix of every string argument.) --- bus/signals.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ bus/signals.h | 3 +- 2 files changed, 154 insertions(+), 18 deletions(-) (limited to 'bus') diff --git a/bus/signals.c b/bus/signals.c index f059d30f..9939a23e 100644 --- a/bus/signals.c +++ b/bus/signals.c @@ -47,8 +47,11 @@ struct BusMatchRule int args_len; }; +#define BUS_MATCH_ARG_NAMESPACE 0x4000000u #define BUS_MATCH_ARG_IS_PATH 0x8000000u +#define BUS_MATCH_ARG_FLAGS (BUS_MATCH_ARG_NAMESPACE | BUS_MATCH_ARG_IS_PATH) + BusMatchRule* bus_match_rule_new (DBusConnection *matches_go_to) { @@ -211,7 +214,7 @@ match_rule_to_string (BusMatchRule *rule) { if (rule->args[i] != NULL) { - dbus_bool_t is_path; + dbus_bool_t is_path, is_namespace; if (_dbus_string_get_length (&str) > 0) { @@ -220,10 +223,13 @@ match_rule_to_string (BusMatchRule *rule) } is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0; + is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0; if (!_dbus_string_append_printf (&str, "arg%d%s='%s'", - i, is_path ? "path" : "", + i, + is_path ? "path" : + is_namespace ? "namespace" : "", rule->args[i])) goto nomem; } @@ -359,7 +365,8 @@ dbus_bool_t bus_match_rule_set_arg (BusMatchRule *rule, int arg, const DBusString *value, - dbus_bool_t is_path) + dbus_bool_t is_path, + dbus_bool_t is_namespace) { int length; char *new; @@ -426,6 +433,9 @@ bus_match_rule_set_arg (BusMatchRule *rule, if (is_path) rule->arg_lens[arg] |= BUS_MATCH_ARG_IS_PATH; + if (is_namespace) + rule->arg_lens[arg] |= BUS_MATCH_ARG_NAMESPACE; + /* NULL termination didn't get busted */ _dbus_assert (rule->args[rule->args_len] == NULL); _dbus_assert (rule->arg_lens[rule->args_len] == 0); @@ -720,7 +730,8 @@ bus_match_rule_parse_arg_match (BusMatchRule *rule, const DBusString *value, DBusError *error) { - dbus_bool_t is_path; + dbus_bool_t is_path = FALSE; + dbus_bool_t is_namespace = FALSE; DBusString key_str; unsigned long arg; int length; @@ -751,17 +762,25 @@ bus_match_rule_parse_arg_match (BusMatchRule *rule, goto failed; } - if (end != length && - ((end + 4) != length || - !_dbus_string_ends_with_c_str (&key_str, "path"))) + if (end != length) { - dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, - "Key '%s' in match rule contains junk after argument number. Only 'path' is optionally valid ('arg0path' for example).\n", key); - goto failed; + if ((end + strlen ("path")) == length && + _dbus_string_ends_with_c_str (&key_str, "path")) + { + is_path = TRUE; + } + else if (_dbus_string_equal_c_str (&key_str, "arg0namespace")) + { + is_namespace = TRUE; + } + else + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Key '%s' in match rule contains junk after argument number (%u). Only 'arg%upath' (for example) or 'arg0namespace' are valid", key, arg, arg); + goto failed; + } } - is_path = end != length; - /* If we didn't check this we could allocate a huge amount of RAM */ if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER) { @@ -779,7 +798,7 @@ bus_match_rule_parse_arg_match (BusMatchRule *rule, goto failed; } - if (!bus_match_rule_set_arg (rule, arg, value, is_path)) + if (!bus_match_rule_set_arg (rule, arg, value, is_path, is_namespace)) { BUS_SET_OOM (error); goto failed; @@ -1318,7 +1337,7 @@ match_rule_equal (BusMatchRule *a, if (a->arg_lens[i] != b->arg_lens[i]) return FALSE; - length = a->arg_lens[i] & ~BUS_MATCH_ARG_IS_PATH; + length = a->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS; if (a->args[i] != NULL) { @@ -1675,11 +1694,12 @@ match_rule_matches (BusMatchRule *rule, int current_type; const char *expected_arg; int expected_length; - dbus_bool_t is_path; + dbus_bool_t is_path, is_namespace; expected_arg = rule->args[i]; - expected_length = rule->arg_lens[i] & ~BUS_MATCH_ARG_IS_PATH; + expected_length = rule->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS; is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0; + is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0; current_type = dbus_message_iter_get_arg_type (&iter); @@ -1712,6 +1732,39 @@ match_rule_matches (BusMatchRule *rule, MIN (actual_length, expected_length)) != 0) return FALSE; } + else if (is_namespace) + { + if (expected_length > actual_length) + return FALSE; + + /* If the actual argument doesn't start with the expected + * namespace, then we don't match. + */ + if (memcmp (expected_arg, actual_arg, expected_length) != 0) + return FALSE; + + if (expected_length < actual_length) + { + /* Check that the actual argument is within the expected + * namespace, rather than just starting with that string, + * by checking that the matched prefix ends in a '.'. + * + * This doesn't stop "foo.bar." matching "foo.bar..baz" + * which is an invalid namespace, but at some point the + * daemon can't cover up for broken services. + */ + int expected_period_index; + + if (expected_arg[expected_length - 1] == '.') + expected_period_index = expected_length - 1; + else + expected_period_index = expected_length; + + if (actual_arg[expected_period_index] != '.') + return FALSE; + } + /* otherwise we had an exact match. */ + } else { if (expected_length != actual_length || @@ -2042,6 +2095,23 @@ test_parsing (void *data) bus_match_rule_unref (rule); } + /* Arg 0 namespace matches */ + rule = check_parse (TRUE, "arg0namespace='foo'"); + if (rule != NULL) + { + _dbus_assert (rule->flags == BUS_MATCH_ARGS); + _dbus_assert (rule->args != NULL); + _dbus_assert (rule->args_len == 1); + _dbus_assert (strcmp (rule->args[0], "foo") == 0); + _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE) + == BUS_MATCH_ARG_NAMESPACE); + + bus_match_rule_unref (rule); + } + + rule = check_parse (FALSE, "arg1namespace='foo'"); + _dbus_assert (rule == NULL); + /* Too-large argN */ rule = check_parse (FALSE, "arg300='foo'"); _dbus_assert (rule == NULL); @@ -2122,6 +2192,7 @@ static struct { { "type='method_call',arg0='blah',arg1='baz'", "arg0='blah',arg1='baz',type='method_call'" }, { "type='method_call',arg3='foosh'", "arg3='foosh',type='method_call'" }, { "arg3='fool'", "arg3='fool'" }, + { "arg0namespace='fool'", "arg0namespace='fool'" }, { "member='food'", "member='food'" } }; @@ -2197,6 +2268,7 @@ should_match_message_1[] = { * argument is not a valid path)! */ "arg0path='foobar'", + "arg0namespace='foobar'", NULL }; @@ -2218,6 +2290,51 @@ should_not_match_message_1[] = { "arg0path='foo'", "arg0path='foobar/'", "arg1path='3'", + "arg0namespace='foo'", + "arg0namespace='foo',arg1='abcdef'", + "arg0namespace='moo'", + NULL +}; + +#define EXAMPLE_NAME "com.example.backend.foo" + +static const char * +should_match_message_2[] = { + /* EXAMPLE_NAME is in all of these namespaces, specified with and without a + * trailing period */ + "arg0namespace='com.example.backend.'", + "arg0namespace='com.example.backend'", + "arg0namespace='com.example.'", + "arg0namespace='com.example'", + "arg0namespace='com.'", + "arg0namespace='com'", + + /* If the client specifies the name exactly, with no trailing period, then + * it should match. + */ + "arg0namespace='com.example.backend.foo'", + + NULL +}; + +static const char * +should_not_match_message_2[] = { + /* These are not even prefixes */ + "arg0namespace='com.example.backend.foo.bar'", + "arg0namespace='com.example.backend.foobar'", + "arg0namespace='com.example.backend.fo.'", + + /* This should match anything within the namespace com.example.backend.foo, + * not including com.example.backend.foo itself. + */ + "arg0namespace='com.example.backend.foo.'", + + /* These are prefixes, but they're not parent namespaces. */ + "arg0namespace='com.example.backend.fo'", + "arg0namespace='com.example.backen'", + "arg0namespace='com.exampl'", + "arg0namespace='co'", + NULL }; @@ -2273,7 +2390,7 @@ check_matching (DBusMessage *message, static void test_matching (void) { - DBusMessage *message1; + DBusMessage *message1, *message2; const char *v_STRING; dbus_int32_t v_INT32; @@ -2295,6 +2412,24 @@ test_matching (void) should_not_match_message_1); dbus_message_unref (message1); + + message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL); + _dbus_assert (message2 != NULL); + if (!dbus_message_set_member (message2, "NameOwnerChanged")) + _dbus_assert_not_reached ("oom"); + + /* Obviously this isn't really a NameOwnerChanged signal. */ + v_STRING = EXAMPLE_NAME; + if (!dbus_message_append_args (message2, + DBUS_TYPE_STRING, &v_STRING, + NULL)) + _dbus_assert_not_reached ("oom"); + + check_matching (message2, 2, + should_match_message_2, + should_not_match_message_2); + + dbus_message_unref (message2); } #define PATH_MATCH_RULE "arg0path='/aa/bb/'" diff --git a/bus/signals.h b/bus/signals.h index eeb1d2d0..81590b5f 100644 --- a/bus/signals.h +++ b/bus/signals.h @@ -59,7 +59,8 @@ dbus_bool_t bus_match_rule_set_path (BusMatchRule *rule, dbus_bool_t bus_match_rule_set_arg (BusMatchRule *rule, int arg, const DBusString *value, - dbus_bool_t is_path); + dbus_bool_t is_path, + dbus_bool_t prefix); BusMatchRule* bus_match_rule_parse (DBusConnection *matches_go_to, const DBusString *rule_text, -- cgit v1.2.3 From 613ecbfba04965bf48f78c3afbb9a99144cb6036 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Sun, 21 Nov 2010 16:34:51 +0000 Subject: Validate arg0namespace matches' values. I could be convinced that this is overkill, but it seems sensible to forbid obviously-broken arg0namespace matches. --- bus/signals.c | 68 ++++++++++++++++++++++++++++++++++++++++++++ dbus/dbus-marshal-validate.c | 66 ++++++++++++++++++++++++++++++------------ dbus/dbus-marshal-validate.h | 3 ++ 3 files changed, 119 insertions(+), 18 deletions(-) (limited to 'bus') diff --git a/bus/signals.c b/bus/signals.c index 9939a23e..daf85403 100644 --- a/bus/signals.c +++ b/bus/signals.c @@ -771,7 +771,22 @@ bus_match_rule_parse_arg_match (BusMatchRule *rule, } else if (_dbus_string_equal_c_str (&key_str, "arg0namespace")) { + int value_len = _dbus_string_get_length (value); + is_namespace = TRUE; + + if (value_len > 0 && + _dbus_string_get_byte (value, value_len - 1) == '.') + value_len--; + + if (!_dbus_validate_bus_namespace (value, 0, value_len)) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "arg0namespace='%s' is not a valid (optionally " + "period-terminated) prefix of a bus name", + _dbus_string_get_const_data (value)); + goto failed; + } } else { @@ -2109,9 +2124,62 @@ test_parsing (void *data) bus_match_rule_unref (rule); } + rule = check_parse (TRUE, "arg0namespace='foo.'"); + if (rule != NULL) + { + _dbus_assert (rule->flags == BUS_MATCH_ARGS); + _dbus_assert (rule->args != NULL); + _dbus_assert (rule->args_len == 1); + _dbus_assert (strcmp (rule->args[0], "foo.") == 0); + _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE) + == BUS_MATCH_ARG_NAMESPACE); + + bus_match_rule_unref (rule); + } + + rule = check_parse (TRUE, "arg0namespace='foo.bar'"); + if (rule != NULL) + { + _dbus_assert (rule->flags == BUS_MATCH_ARGS); + _dbus_assert (rule->args != NULL); + _dbus_assert (rule->args_len == 1); + _dbus_assert (strcmp (rule->args[0], "foo.bar") == 0); + _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE) + == BUS_MATCH_ARG_NAMESPACE); + + bus_match_rule_unref (rule); + } + + rule = check_parse (TRUE, "arg0namespace='foo.bar.'"); + if (rule != NULL) + { + _dbus_assert (rule->flags == BUS_MATCH_ARGS); + _dbus_assert (rule->args != NULL); + _dbus_assert (rule->args_len == 1); + _dbus_assert (strcmp (rule->args[0], "foo.bar.") == 0); + _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE) + == BUS_MATCH_ARG_NAMESPACE); + + bus_match_rule_unref (rule); + } + + /* Only arg0namespace is supported. */ rule = check_parse (FALSE, "arg1namespace='foo'"); _dbus_assert (rule == NULL); + /* An empty string isn't a valid namespace prefix (you should just not + * specify this key at all). + */ + rule = check_parse (FALSE, "arg0namespace=''"); + _dbus_assert (rule == NULL); + + /* Two trailing periods on otherwise-valid namespaces aren't allowed. */ + rule = check_parse (FALSE, "arg0namespace='foo..'"); + _dbus_assert (rule == NULL); + + rule = check_parse (FALSE, "arg0namespace='foo.bar..'"); + _dbus_assert (rule == NULL); + /* Too-large argN */ rule = check_parse (FALSE, "arg300='foo'"); _dbus_assert (rule == NULL); diff --git a/dbus/dbus-marshal-validate.c b/dbus/dbus-marshal-validate.c index aa470fc8..7d49624b 100644 --- a/dbus/dbus-marshal-validate.c +++ b/dbus/dbus-marshal-validate.c @@ -1062,23 +1062,11 @@ _dbus_validate_error_name (const DBusString *str, ((c) >= 'a' && (c) <= 'z') || \ ((c) == '_') || ((c) == '-')) -/** - * Checks that the given range of the string is a valid bus name in - * the D-Bus protocol. This includes a length restriction, etc., see - * the specification. - * - * @todo this is inconsistent with most of DBusString in that - * it allows a start,len range that extends past the string end. - * - * @param str the string - * @param start first byte index to check - * @param len number of bytes to check - * @returns #TRUE if the byte range exists and is a valid name - */ -dbus_bool_t -_dbus_validate_bus_name (const DBusString *str, - int start, - int len) +static dbus_bool_t +_dbus_validate_bus_name_full (const DBusString *str, + int start, + int len, + dbus_bool_t is_namespace) { const unsigned char *s; const unsigned char *end; @@ -1156,12 +1144,54 @@ _dbus_validate_bus_name (const DBusString *str, ++s; } - if (_DBUS_UNLIKELY (last_dot == NULL)) + if (!is_namespace && _DBUS_UNLIKELY (last_dot == NULL)) return FALSE; return TRUE; } +/** + * Checks that the given range of the string is a valid bus name in + * the D-Bus protocol. This includes a length restriction, etc., see + * the specification. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that extends past the string end. + * + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is a valid name + */ +dbus_bool_t +_dbus_validate_bus_name (const DBusString *str, + int start, + int len) +{ + return _dbus_validate_bus_name_full (str, start, len, FALSE); +} + +/** + * Checks that the given range of the string is a prefix of a valid bus name in + * the D-Bus protocol. Unlike _dbus_validate_bus_name(), this accepts strings + * with only one period-separated component. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that extends past the string end. + * + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is a valid name + */ +dbus_bool_t +_dbus_validate_bus_namespace (const DBusString *str, + int start, + int len) +{ + return _dbus_validate_bus_name_full (str, start, len, TRUE); +} + /** * Checks that the given range of the string is a valid message type * signature in the D-Bus protocol. diff --git a/dbus/dbus-marshal-validate.h b/dbus/dbus-marshal-validate.h index 5817de32..9b896085 100644 --- a/dbus/dbus-marshal-validate.h +++ b/dbus/dbus-marshal-validate.h @@ -143,6 +143,9 @@ dbus_bool_t _dbus_validate_error_name (const DBusString *str, dbus_bool_t _dbus_validate_bus_name (const DBusString *str, int start, int len); +dbus_bool_t _dbus_validate_bus_namespace (const DBusString *str, + int start, + int len); dbus_bool_t _dbus_validate_signature (const DBusString *str, int start, int len); -- cgit v1.2.3 From 08b251f0bcf4a6fd6d87598b9f6e420aab21fe4f Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Thu, 7 Apr 2011 12:41:52 +0100 Subject: signals.h: rename argument in declaration to match implementation --- bus/signals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bus') diff --git a/bus/signals.h b/bus/signals.h index 81590b5f..4702b9e2 100644 --- a/bus/signals.h +++ b/bus/signals.h @@ -60,7 +60,7 @@ dbus_bool_t bus_match_rule_set_arg (BusMatchRule *rule, int arg, const DBusString *value, dbus_bool_t is_path, - dbus_bool_t prefix); + dbus_bool_t is_namespace); BusMatchRule* bus_match_rule_parse (DBusConnection *matches_go_to, const DBusString *rule_text, -- cgit v1.2.3 From 0980e63aacf52201bdf913e706d8ea0accc22610 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Tue, 8 Mar 2011 10:32:34 -0500 Subject: Add path_prefix match rule Add a new path_prefix match rule that can be used for efficient implementations of the org.freedesktop.DBus.ObjectManager interface (see bug 34869). https://bugs.freedesktop.org/show_bug.cgi?id=34870 Signed-off-by: David Zeuthen --- bus/signals.c | 168 +++++++++++++++++++++++++++++++++++++++++++++ bus/signals.h | 5 +- doc/dbus-specification.xml | 20 ++++++ 3 files changed, 192 insertions(+), 1 deletion(-) (limited to 'bus') diff --git a/bus/signals.c b/bus/signals.c index 56a7d6c1..0d18dc6f 100644 --- a/bus/signals.c +++ b/bus/signals.c @@ -41,6 +41,7 @@ struct BusMatchRule char *sender; char *destination; char *path; + char *path_prefix; unsigned int *arg_lens; char **args; @@ -94,6 +95,7 @@ bus_match_rule_unref (BusMatchRule *rule) dbus_free (rule->sender); dbus_free (rule->destination); dbus_free (rule->path); + dbus_free (rule->path_prefix); dbus_free (rule->arg_lens); /* can't use dbus_free_string_array() since there @@ -206,6 +208,18 @@ match_rule_to_string (BusMatchRule *rule) goto nomem; } + if (rule->flags & BUS_MATCH_PATH_PREFIX) + { + if (_dbus_string_get_length (&str) > 0) + { + if (!_dbus_string_append (&str, ",")) + goto nomem; + } + + if (!_dbus_string_append_printf (&str, "path_prefix='%s'", rule->path_prefix)) + goto nomem; + } + if (rule->flags & BUS_MATCH_SENDER) { if (_dbus_string_get_length (&str) > 0) @@ -388,6 +402,25 @@ bus_match_rule_set_path (BusMatchRule *rule, return TRUE; } +dbus_bool_t +bus_match_rule_set_path_prefix (BusMatchRule *rule, + const char *path_prefix) +{ + char *new; + + _dbus_assert (path_prefix != NULL); + + new = _dbus_strdup (path_prefix); + if (new == NULL) + return FALSE; + + rule->flags |= BUS_MATCH_PATH_PREFIX; + dbus_free (rule->path_prefix); + rule->path_prefix = new; + + return TRUE; +} + dbus_bool_t bus_match_rule_set_arg (BusMatchRule *rule, int arg, @@ -1018,6 +1051,34 @@ bus_match_rule_parse (DBusConnection *matches_go_to, goto failed; } } + else if (strcmp (key, "path_prefix") == 0) + { + int path_prefix_len; + + if (rule->flags & BUS_MATCH_PATH_PREFIX) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Key %s specified twice in match rule\n", key); + goto failed; + } + + path_prefix_len = len; + if (_dbus_string_ends_with_c_str (&tmp_str, "/")) + path_prefix_len--; + + if (!_dbus_validate_path (&tmp_str, 0, path_prefix_len)) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Path prefix '%s' is invalid\n", value); + goto failed; + } + + if (!bus_match_rule_set_path_prefix (rule, value)) + { + BUS_SET_OOM (error); + goto failed; + } + } else if (strcmp (key, "destination") == 0) { if (rule->flags & BUS_MATCH_DESTINATION) @@ -1349,6 +1410,10 @@ match_rule_equal (BusMatchRule *a, if ((a->flags & BUS_MATCH_PATH) && strcmp (a->path, b->path) != 0) return FALSE; + + if ((a->flags & BUS_MATCH_PATH_PREFIX) && + strcmp (a->path_prefix, b->path_prefix) != 0) + return FALSE; if ((a->flags & BUS_MATCH_INTERFACE) && strcmp (a->interface, b->interface) != 0) @@ -1611,6 +1676,17 @@ connection_is_primary_owner (DBusConnection *connection, return bus_service_get_primary_owners_connection (service) == connection; } +static dbus_bool_t +str_has_prefix (const char *str, const char *prefix) +{ + size_t prefix_len; + prefix_len = strlen (prefix); + if (strncmp (str, prefix, prefix_len) == 0) + return TRUE; + else + return FALSE; +} + static dbus_bool_t match_rule_matches (BusMatchRule *rule, DBusConnection *sender, @@ -1722,6 +1798,20 @@ match_rule_matches (BusMatchRule *rule, return FALSE; } + if (flags & BUS_MATCH_PATH_PREFIX) + { + const char *path; + + _dbus_assert (rule->path_prefix != NULL); + + path = dbus_message_get_path (message); + if (path == NULL) + return FALSE; + + if (!str_has_prefix (path, rule->path_prefix)) + return FALSE; + } + if (flags & BUS_MATCH_ARGS) { int i; @@ -2616,6 +2706,83 @@ test_path_matching (void) bus_match_rule_unref (rule); } +static const char* +path_prefix_should_match_message_1[] = { + "type='signal',path_prefix='/foo'", + "type='signal',path_prefix='/foo/'", + "type='signal',path_prefix='/foo/TheObjectManager'", + NULL +}; + +static const char* +path_prefix_should_not_match_message_1[] = { + "type='signal',path_prefix='/bar'", + "type='signal',path_prefix='/bar/'", + "type='signal',path_prefix='/bar/TheObjectManager'", + NULL +}; + +static const char* +path_prefix_should_match_message_2[] = { + "type='signal',path_prefix='/foo/TheObjectManager'", + "type='signal',path_prefix='/foo/TheObjectManager/'", + NULL +}; + +static const char* +path_prefix_should_not_match_message_2[] = { + NULL +}; + +static const char* +path_prefix_should_match_message_3[] = { + "type='signal',path_prefix='/foo/TheObjectManager'", + NULL +}; + +static const char* +path_prefix_should_not_match_message_3[] = { + "type='signal',path_prefix='/foo/TheObjectManager/'", + NULL +}; + +static void +test_matching_path_prefix (void) +{ + DBusMessage *message1; + DBusMessage *message2; + DBusMessage *message3; + + message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL); + _dbus_assert (message1 != NULL); + if (!dbus_message_set_path (message1, "/foo/TheObjectManager")) + _dbus_assert_not_reached ("oom"); + + message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL); + _dbus_assert (message2 != NULL); + if (!dbus_message_set_path (message2, "/foo/TheObjectManager/child_object")) + _dbus_assert_not_reached ("oom"); + + message3 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL); + _dbus_assert (message3 != NULL); + if (!dbus_message_set_path (message3, "/foo/TheObjectManagerOther")) + _dbus_assert_not_reached ("oom"); + + check_matching (message1, 1, + path_prefix_should_match_message_1, + path_prefix_should_not_match_message_1); + check_matching (message2, 2, + path_prefix_should_match_message_2, + path_prefix_should_not_match_message_2); + check_matching (message3, 3, + path_prefix_should_match_message_3, + path_prefix_should_not_match_message_3); + + dbus_message_unref (message3); + dbus_message_unref (message2); + dbus_message_unref (message1); +} + dbus_bool_t bus_signals_test (const DBusString *test_data_dir) { @@ -2632,6 +2799,7 @@ bus_signals_test (const DBusString *test_data_dir) test_equality (); test_matching (); test_path_matching (); + test_matching_path_prefix (); return TRUE; } diff --git a/bus/signals.h b/bus/signals.h index 4702b9e2..0053bd5d 100644 --- a/bus/signals.h +++ b/bus/signals.h @@ -37,7 +37,8 @@ typedef enum BUS_MATCH_SENDER = 1 << 3, BUS_MATCH_DESTINATION = 1 << 4, BUS_MATCH_PATH = 1 << 5, - BUS_MATCH_ARGS = 1 << 6 + BUS_MATCH_ARGS = 1 << 6, + BUS_MATCH_PATH_PREFIX = 1 << 7 } BusMatchFlags; BusMatchRule* bus_match_rule_new (DBusConnection *matches_go_to); @@ -56,6 +57,8 @@ dbus_bool_t bus_match_rule_set_destination (BusMatchRule *rule, const char *destination); dbus_bool_t bus_match_rule_set_path (BusMatchRule *rule, const char *path); +dbus_bool_t bus_match_rule_set_path_prefix (BusMatchRule *rule, + const char *path_prefix); dbus_bool_t bus_match_rule_set_arg (BusMatchRule *rule, int arg, const DBusString *value, diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml index ad731c9e..1c19a4a5 100644 --- a/doc/dbus-specification.xml +++ b/doc/dbus-specification.xml @@ -3721,6 +3721,26 @@ Matches messages which are sent from or to the given object. An example of a path match is path='/org/freedesktop/Hal/Manager' + + path_prefix + An object path optionally ending in a slash + + + Matches messages which are sent from or to an + object for which the object path is a prefix of + the given value. Examples of matches are + path_prefix='/org/Application/ObjectManager' or + path_prefix='/org/Application/ContactObjects/'. + + + + This match key was added in version 0.15 of the + D-Bus specification and implemented by the bus + daemon in dbus 1.4.7 and later. + + + + destination A unique name (see ) -- cgit v1.2.3 From d23cdacb0da95a177dc7708bd26f284af732e508 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Thu, 7 Apr 2011 14:45:19 +0100 Subject: path_prefix: anchor matches at path-component boundaries, and give examples It seems wrong that path_prefix="/foo" matches /foobar, and it isn't difficult or expensive to check. --- bus/signals.c | 14 +++++++++++++- doc/dbus-specification.xml | 31 +++++++++++++++++++++++++++---- 2 files changed, 40 insertions(+), 5 deletions(-) (limited to 'bus') diff --git a/bus/signals.c b/bus/signals.c index 0d18dc6f..59133344 100644 --- a/bus/signals.c +++ b/bus/signals.c @@ -1801,6 +1801,7 @@ match_rule_matches (BusMatchRule *rule, if (flags & BUS_MATCH_PATH_PREFIX) { const char *path; + int len; _dbus_assert (rule->path_prefix != NULL); @@ -1810,6 +1811,17 @@ match_rule_matches (BusMatchRule *rule, if (!str_has_prefix (path, rule->path_prefix)) return FALSE; + + len = strlen (rule->path_prefix); + + /* Check that the actual argument is within the expected + * namespace, rather than just starting with that string, + * by checking that the matched prefix either ends in a '/', + * or is followed by a '/' or the end of the path. + */ + if (rule->path_prefix[len - 1] != '/' && + path[len] != '\0' && path[len] != '/') + return FALSE; } if (flags & BUS_MATCH_ARGS) @@ -2736,12 +2748,12 @@ path_prefix_should_not_match_message_2[] = { static const char* path_prefix_should_match_message_3[] = { - "type='signal',path_prefix='/foo/TheObjectManager'", NULL }; static const char* path_prefix_should_not_match_message_3[] = { + "type='signal',path_prefix='/foo/TheObjectManager'", "type='signal',path_prefix='/foo/TheObjectManager/'", NULL }; diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml index 1c19a4a5..63146bb7 100644 --- a/doc/dbus-specification.xml +++ b/doc/dbus-specification.xml @@ -3727,10 +3727,33 @@ Matches messages which are sent from or to an - object for which the object path is a prefix of - the given value. Examples of matches are - path_prefix='/org/Application/ObjectManager' or - path_prefix='/org/Application/ContactObjects/'. + object for which the object path is a descendant of + the given value. If the prefix ends with a slash, it + matches all paths starting with that string; + if it does not end with a slash, it matches either + that exact path, or that path followed by one or + more path components. + + + + For example, + path_prefix='/com/example/foo' + would match signals sent by + /com/example/foo + or by + /com/example/foo/bar, + but not by + /com/example/foobar. + + + + However, + path_prefix='/com/example/foo/' + would still match signals sent by + /com/example/foo/bar, + but would not match signals sent by + /com/example/foo or + /com/example/foobar. -- cgit v1.2.3 From 97bf0b2b4876bad135c7ea9eee30c2ddecc51ada Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Thu, 7 Apr 2011 16:12:22 +0100 Subject: Rename path_prefix to path_namespace and disallow trailing '/' Also disallow having both path and path_namespace in the same match rule (it wouldn't make sense, path is more specific than path_namespace). As per IRC discussion with davidz and wjt. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=34870 --- bus/signals.c | 138 +++++++++++++++------------------------------ bus/signals.h | 21 ++++--- doc/dbus-specification.xml | 24 +++----- 3 files changed, 64 insertions(+), 119 deletions(-) (limited to 'bus') diff --git a/bus/signals.c b/bus/signals.c index 59133344..d0e72bf6 100644 --- a/bus/signals.c +++ b/bus/signals.c @@ -41,7 +41,6 @@ struct BusMatchRule char *sender; char *destination; char *path; - char *path_prefix; unsigned int *arg_lens; char **args; @@ -95,7 +94,6 @@ bus_match_rule_unref (BusMatchRule *rule) dbus_free (rule->sender); dbus_free (rule->destination); dbus_free (rule->path); - dbus_free (rule->path_prefix); dbus_free (rule->arg_lens); /* can't use dbus_free_string_array() since there @@ -208,7 +206,7 @@ match_rule_to_string (BusMatchRule *rule) goto nomem; } - if (rule->flags & BUS_MATCH_PATH_PREFIX) + if (rule->flags & BUS_MATCH_PATH_NAMESPACE) { if (_dbus_string_get_length (&str) > 0) { @@ -216,7 +214,7 @@ match_rule_to_string (BusMatchRule *rule) goto nomem; } - if (!_dbus_string_append_printf (&str, "path_prefix='%s'", rule->path_prefix)) + if (!_dbus_string_append_printf (&str, "path_namespace='%s'", rule->path)) goto nomem; } @@ -385,7 +383,8 @@ bus_match_rule_set_destination (BusMatchRule *rule, dbus_bool_t bus_match_rule_set_path (BusMatchRule *rule, - const char *path) + const char *path, + dbus_bool_t is_namespace) { char *new; @@ -395,28 +394,15 @@ bus_match_rule_set_path (BusMatchRule *rule, if (new == NULL) return FALSE; - rule->flags |= BUS_MATCH_PATH; - dbus_free (rule->path); - rule->path = new; - - return TRUE; -} - -dbus_bool_t -bus_match_rule_set_path_prefix (BusMatchRule *rule, - const char *path_prefix) -{ - char *new; - - _dbus_assert (path_prefix != NULL); + rule->flags &= ~(BUS_MATCH_PATH|BUS_MATCH_PATH_NAMESPACE); - new = _dbus_strdup (path_prefix); - if (new == NULL) - return FALSE; + if (is_namespace) + rule->flags |= BUS_MATCH_PATH_NAMESPACE; + else + rule->flags |= BUS_MATCH_PATH; - rule->flags |= BUS_MATCH_PATH_PREFIX; - dbus_free (rule->path_prefix); - rule->path_prefix = new; + dbus_free (rule->path); + rule->path = new; return TRUE; } @@ -1029,12 +1015,15 @@ bus_match_rule_parse (DBusConnection *matches_go_to, goto failed; } } - else if (strcmp (key, "path") == 0) + else if (strcmp (key, "path") == 0 || + strcmp (key, "path_namespace") == 0) { - if (rule->flags & BUS_MATCH_PATH) + dbus_bool_t is_namespace = (strcmp (key, "path_namespace") == 0); + + if (rule->flags & (BUS_MATCH_PATH | BUS_MATCH_PATH_NAMESPACE)) { dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, - "Key %s specified twice in match rule\n", key); + "path or path_namespace specified twice in match rule\n"); goto failed; } @@ -1045,35 +1034,7 @@ bus_match_rule_parse (DBusConnection *matches_go_to, goto failed; } - if (!bus_match_rule_set_path (rule, value)) - { - BUS_SET_OOM (error); - goto failed; - } - } - else if (strcmp (key, "path_prefix") == 0) - { - int path_prefix_len; - - if (rule->flags & BUS_MATCH_PATH_PREFIX) - { - dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, - "Key %s specified twice in match rule\n", key); - goto failed; - } - - path_prefix_len = len; - if (_dbus_string_ends_with_c_str (&tmp_str, "/")) - path_prefix_len--; - - if (!_dbus_validate_path (&tmp_str, 0, path_prefix_len)) - { - dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, - "Path prefix '%s' is invalid\n", value); - goto failed; - } - - if (!bus_match_rule_set_path_prefix (rule, value)) + if (!bus_match_rule_set_path (rule, value, is_namespace)) { BUS_SET_OOM (error); goto failed; @@ -1411,10 +1372,6 @@ match_rule_equal (BusMatchRule *a, strcmp (a->path, b->path) != 0) return FALSE; - if ((a->flags & BUS_MATCH_PATH_PREFIX) && - strcmp (a->path_prefix, b->path_prefix) != 0) - return FALSE; - if ((a->flags & BUS_MATCH_INTERFACE) && strcmp (a->interface, b->interface) != 0) return FALSE; @@ -1798,29 +1755,28 @@ match_rule_matches (BusMatchRule *rule, return FALSE; } - if (flags & BUS_MATCH_PATH_PREFIX) + if (flags & BUS_MATCH_PATH_NAMESPACE) { const char *path; int len; - _dbus_assert (rule->path_prefix != NULL); + _dbus_assert (rule->path != NULL); path = dbus_message_get_path (message); if (path == NULL) return FALSE; - if (!str_has_prefix (path, rule->path_prefix)) + if (!str_has_prefix (path, rule->path)) return FALSE; - len = strlen (rule->path_prefix); + len = strlen (rule->path); /* Check that the actual argument is within the expected * namespace, rather than just starting with that string, - * by checking that the matched prefix either ends in a '/', - * or is followed by a '/' or the end of the path. + * by checking that the matched prefix is followed by a '/' + * or the end of the path. */ - if (rule->path_prefix[len - 1] != '/' && - path[len] != '\0' && path[len] != '/') + if (path[len] != '\0' && path[len] != '/') return FALSE; } @@ -2719,47 +2675,43 @@ test_path_matching (void) } static const char* -path_prefix_should_match_message_1[] = { - "type='signal',path_prefix='/foo'", - "type='signal',path_prefix='/foo/'", - "type='signal',path_prefix='/foo/TheObjectManager'", +path_namespace_should_match_message_1[] = { + "type='signal',path_namespace='/foo'", + "type='signal',path_namespace='/foo/TheObjectManager'", NULL }; static const char* -path_prefix_should_not_match_message_1[] = { - "type='signal',path_prefix='/bar'", - "type='signal',path_prefix='/bar/'", - "type='signal',path_prefix='/bar/TheObjectManager'", +path_namespace_should_not_match_message_1[] = { + "type='signal',path_namespace='/bar'", + "type='signal',path_namespace='/bar/TheObjectManager'", NULL }; static const char* -path_prefix_should_match_message_2[] = { - "type='signal',path_prefix='/foo/TheObjectManager'", - "type='signal',path_prefix='/foo/TheObjectManager/'", +path_namespace_should_match_message_2[] = { + "type='signal',path_namespace='/foo/TheObjectManager'", NULL }; static const char* -path_prefix_should_not_match_message_2[] = { +path_namespace_should_not_match_message_2[] = { NULL }; static const char* -path_prefix_should_match_message_3[] = { +path_namespace_should_match_message_3[] = { NULL }; static const char* -path_prefix_should_not_match_message_3[] = { - "type='signal',path_prefix='/foo/TheObjectManager'", - "type='signal',path_prefix='/foo/TheObjectManager/'", +path_namespace_should_not_match_message_3[] = { + "type='signal',path_namespace='/foo/TheObjectManager'", NULL }; static void -test_matching_path_prefix (void) +test_matching_path_namespace (void) { DBusMessage *message1; DBusMessage *message2; @@ -2781,14 +2733,14 @@ test_matching_path_prefix (void) _dbus_assert_not_reached ("oom"); check_matching (message1, 1, - path_prefix_should_match_message_1, - path_prefix_should_not_match_message_1); + path_namespace_should_match_message_1, + path_namespace_should_not_match_message_1); check_matching (message2, 2, - path_prefix_should_match_message_2, - path_prefix_should_not_match_message_2); + path_namespace_should_match_message_2, + path_namespace_should_not_match_message_2); check_matching (message3, 3, - path_prefix_should_match_message_3, - path_prefix_should_not_match_message_3); + path_namespace_should_match_message_3, + path_namespace_should_not_match_message_3); dbus_message_unref (message3); dbus_message_unref (message2); @@ -2811,7 +2763,7 @@ bus_signals_test (const DBusString *test_data_dir) test_equality (); test_matching (); test_path_matching (); - test_matching_path_prefix (); + test_matching_path_namespace (); return TRUE; } diff --git a/bus/signals.h b/bus/signals.h index 0053bd5d..5b086f04 100644 --- a/bus/signals.h +++ b/bus/signals.h @@ -31,14 +31,14 @@ typedef enum { - BUS_MATCH_MESSAGE_TYPE = 1 << 0, - BUS_MATCH_INTERFACE = 1 << 1, - BUS_MATCH_MEMBER = 1 << 2, - BUS_MATCH_SENDER = 1 << 3, - BUS_MATCH_DESTINATION = 1 << 4, - BUS_MATCH_PATH = 1 << 5, - BUS_MATCH_ARGS = 1 << 6, - BUS_MATCH_PATH_PREFIX = 1 << 7 + BUS_MATCH_MESSAGE_TYPE = 1 << 0, + BUS_MATCH_INTERFACE = 1 << 1, + BUS_MATCH_MEMBER = 1 << 2, + BUS_MATCH_SENDER = 1 << 3, + BUS_MATCH_DESTINATION = 1 << 4, + BUS_MATCH_PATH = 1 << 5, + BUS_MATCH_ARGS = 1 << 6, + BUS_MATCH_PATH_NAMESPACE = 1 << 7 } BusMatchFlags; BusMatchRule* bus_match_rule_new (DBusConnection *matches_go_to); @@ -56,9 +56,8 @@ dbus_bool_t bus_match_rule_set_sender (BusMatchRule *rule, dbus_bool_t bus_match_rule_set_destination (BusMatchRule *rule, const char *destination); dbus_bool_t bus_match_rule_set_path (BusMatchRule *rule, - const char *path); -dbus_bool_t bus_match_rule_set_path_prefix (BusMatchRule *rule, - const char *path_prefix); + const char *path, + dbus_bool_t is_namespace); dbus_bool_t bus_match_rule_set_arg (BusMatchRule *rule, int arg, const DBusString *value, diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml index 6b446dd1..bef98871 100644 --- a/doc/dbus-specification.xml +++ b/doc/dbus-specification.xml @@ -3722,22 +3722,19 @@ path match is path='/org/freedesktop/Hal/Manager' - path_prefix - An object path optionally ending in a slash + path_namespace + An object path Matches messages which are sent from or to an - object for which the object path is a descendant of - the given value. If the prefix ends with a slash, it - matches all paths starting with that string; - if it does not end with a slash, it matches either - that exact path, or that path followed by one or + object for which the object path is either the + given value, or that value followed by one or more path components. For example, - path_prefix='/com/example/foo' + path_namespace='/com/example/foo' would match signals sent by /com/example/foo or by @@ -3747,14 +3744,11 @@ - However, - path_prefix='/com/example/foo/' - would still match signals sent by - /com/example/foo/bar, - but would not match signals sent by - /com/example/foo or - /com/example/foobar. + Using both path and + path_namespace in the same match + rule is not allowed. + This match key was added in version 0.16 of the -- cgit v1.2.3 From b92f2224bfd3e03cc935651f9d0464e8e08e26e7 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Thu, 7 Apr 2011 13:13:56 +0100 Subject: Remove support for trailing "." on arg0namespace --- bus/signals.c | 63 ++++++++-------------------------------------- doc/dbus-specification.xml | 12 --------- 2 files changed, 11 insertions(+), 64 deletions(-) (limited to 'bus') diff --git a/bus/signals.c b/bus/signals.c index d0e72bf6..d7bddca3 100644 --- a/bus/signals.c +++ b/bus/signals.c @@ -821,15 +821,10 @@ bus_match_rule_parse_arg_match (BusMatchRule *rule, is_namespace = TRUE; - if (value_len > 0 && - _dbus_string_get_byte (value, value_len - 1) == '.') - value_len--; - if (!_dbus_validate_bus_namespace (value, 0, value_len)) { dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, - "arg0namespace='%s' is not a valid (optionally " - "period-terminated) prefix of a bus name", + "arg0namespace='%s' is not a valid prefix of a bus name", _dbus_string_get_const_data (value)); goto failed; } @@ -1854,14 +1849,7 @@ match_rule_matches (BusMatchRule *rule, * which is an invalid namespace, but at some point the * daemon can't cover up for broken services. */ - int expected_period_index; - - if (expected_arg[expected_length - 1] == '.') - expected_period_index = expected_length - 1; - else - expected_period_index = expected_length; - - if (actual_arg[expected_period_index] != '.') + if (actual_arg[expected_length] != '.') return FALSE; } /* otherwise we had an exact match. */ @@ -2210,19 +2198,6 @@ test_parsing (void *data) bus_match_rule_unref (rule); } - rule = check_parse (TRUE, "arg0namespace='foo.'"); - if (rule != NULL) - { - _dbus_assert (rule->flags == BUS_MATCH_ARGS); - _dbus_assert (rule->args != NULL); - _dbus_assert (rule->args_len == 1); - _dbus_assert (strcmp (rule->args[0], "foo.") == 0); - _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE) - == BUS_MATCH_ARG_NAMESPACE); - - bus_match_rule_unref (rule); - } - rule = check_parse (TRUE, "arg0namespace='foo.bar'"); if (rule != NULL) { @@ -2236,19 +2211,6 @@ test_parsing (void *data) bus_match_rule_unref (rule); } - rule = check_parse (TRUE, "arg0namespace='foo.bar.'"); - if (rule != NULL) - { - _dbus_assert (rule->flags == BUS_MATCH_ARGS); - _dbus_assert (rule->args != NULL); - _dbus_assert (rule->args_len == 1); - _dbus_assert (strcmp (rule->args[0], "foo.bar.") == 0); - _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE) - == BUS_MATCH_ARG_NAMESPACE); - - bus_match_rule_unref (rule); - } - /* Only arg0namespace is supported. */ rule = check_parse (FALSE, "arg1namespace='foo'"); _dbus_assert (rule == NULL); @@ -2259,7 +2221,14 @@ test_parsing (void *data) rule = check_parse (FALSE, "arg0namespace=''"); _dbus_assert (rule == NULL); - /* Two trailing periods on otherwise-valid namespaces aren't allowed. */ + /* Trailing periods aren't allowed (earlier versions of the arg0namespace + * spec allowed a single trailing period, which altered the semantics) */ + rule = check_parse (FALSE, "arg0namespace='foo.'"); + _dbus_assert (rule == NULL); + + rule = check_parse (FALSE, "arg0namespace='foo.bar.'"); + _dbus_assert (rule == NULL); + rule = check_parse (FALSE, "arg0namespace='foo..'"); _dbus_assert (rule == NULL); @@ -2454,13 +2423,9 @@ should_not_match_message_1[] = { static const char * should_match_message_2[] = { - /* EXAMPLE_NAME is in all of these namespaces, specified with and without a - * trailing period */ - "arg0namespace='com.example.backend.'", + /* EXAMPLE_NAME is in all of these namespaces */ "arg0namespace='com.example.backend'", - "arg0namespace='com.example.'", "arg0namespace='com.example'", - "arg0namespace='com.'", "arg0namespace='com'", /* If the client specifies the name exactly, with no trailing period, then @@ -2476,12 +2441,6 @@ should_not_match_message_2[] = { /* These are not even prefixes */ "arg0namespace='com.example.backend.foo.bar'", "arg0namespace='com.example.backend.foobar'", - "arg0namespace='com.example.backend.fo.'", - - /* This should match anything within the namespace com.example.backend.foo, - * not including com.example.backend.foo itself. - */ - "arg0namespace='com.example.backend.foo.'", /* These are prefixes, but they're not parent namespaces. */ "arg0namespace='com.example.backend.fo'", diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml index bef98871..bb8ecd27 100644 --- a/doc/dbus-specification.xml +++ b/doc/dbus-specification.xml @@ -3823,10 +3823,6 @@ bus name, this can also be used for messages whose first argument is an interface name. - If the value has a trailing period, then only bus names or interface names - within that namespace are matched. If it has no trailing period, an exact - match is also allowed. - For example, the match rule member='NameOwnerChanged',arg0namespace='com.example.backend' matches name owner changes for bus names such as @@ -3834,14 +3830,6 @@ com.example.backend.foo.bar, and com.example.backend itself. - On the other hand, the match rule - member='NameOwnerChanged',arg0namespace='com.example.backend.' - (with a trailing period in the namespace) matches owner changes for - com.example.backend.foo and - com.example.backend.foo.bar, but not for - com.example.backend. - - See also . -- cgit v1.2.3 From 2dafaac83991078ed206ad359dda037e492e80df Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Thu, 7 Apr 2011 16:30:41 +0100 Subject: Check parsing (or otherwise) of path_namespace in match rules --- bus/signals.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'bus') diff --git a/bus/signals.c b/bus/signals.c index d7bddca3..4d34ca14 100644 --- a/bus/signals.c +++ b/bus/signals.c @@ -2255,6 +2255,24 @@ test_parsing (void *data) rule = check_parse (FALSE, "type='signal',type='method_call'"); _dbus_assert (rule == NULL); + rule = check_parse (TRUE, "path_namespace='/foo/bar'"); + if (rule != NULL) + { + _dbus_assert (rule->flags == BUS_MATCH_PATH_NAMESPACE); + _dbus_assert (rule->path != NULL); + _dbus_assert (strcmp (rule->path, "/foo/bar") == 0); + + bus_match_rule_unref (rule); + } + + /* Almost a duplicate */ + rule = check_parse (FALSE, "path='/foo',path_namespace='/foo'"); + _dbus_assert (rule == NULL); + + /* Trailing / was supported in the initial proposal, but now isn't */ + rule = check_parse (FALSE, "path_namespace='/foo/'"); + _dbus_assert (rule == NULL); + /* Duplicates with the argN code */ rule = check_parse (FALSE, "arg0='foo',arg0='bar'"); _dbus_assert (rule == NULL); -- cgit v1.2.3