bus: fix pattern matching

DBus-spec defines two different pattern matchings:

  1) Path and namespace prefix matching. In this case, A matches B either
     if both are equal, or if B is fully included in the namespace of A.
     In other words, A has to be a prefix of B, but end with a separator
     character (or the following character in B must be one).

     This is used for path_namespace= and arg0namespace=

  2) The other pattern matching is used for arg0path= which does a two-way
     matching. That is, A must be a prefix of B, or B a prefix of A.
     Furthermore, the prefix must end with a separator.

Fix the sd-bus helpers to reflect that. The 'simple_' and 'complex_'
prefixes don't make any sense now, but.. eh..
This commit is contained in:
David Herrmann 2015-06-10 19:34:05 +02:00
parent 2e90f867f9
commit 744dccdd36
3 changed files with 45 additions and 8 deletions

View File

@ -211,6 +211,17 @@ bool member_name_is_valid(const char *p) {
return true;
}
/*
* Complex pattern match
* This checks whether @a is a 'complex-prefix' of @b, or @b is a
* 'complex-prefix' of @a, based on strings that consist of labels with @c as
* spearator. This function returns true if:
* - both strings are equal
* - either is a prefix of the other and ends with @c
* The second rule makes sure that either string needs to be fully included in
* the other, and the string which is considered the prefix needs to end with a
* separator.
*/
static bool complex_pattern_check(char c, const char *a, const char *b) {
bool separator = false;
@ -222,9 +233,7 @@ static bool complex_pattern_check(char c, const char *a, const char *b) {
for (;;) {
if (*a != *b)
return (separator && (*a == 0 || *b == 0)) ||
(*a == 0 && *b == c && b[1] == 0) ||
(*b == 0 && *a == c && a[1] == 0);
return (separator && (*a == 0 || *b == 0));
if (*a == 0)
return true;
@ -243,7 +252,18 @@ bool path_complex_pattern(const char *pattern, const char *value) {
return complex_pattern_check('/', pattern, value);
}
/*
* Simple pattern match
* This checks whether @a is a 'simple-prefix' of @b, based on strings that
* consist of labels with @c as separator. This function returns true, if:
* - if @a and @b are equal
* - if @a is a prefix of @b, and the first following character in @b (or the
* last character in @a) is @c
* The second rule basically makes sure that if @a is a prefix of @b, then @b
* must follow with a new label separated by @c. It cannot extend the label.
*/
static bool simple_pattern_check(char c, const char *a, const char *b) {
bool separator = false;
if (!a && !b)
return true;
@ -253,11 +273,13 @@ static bool simple_pattern_check(char c, const char *a, const char *b) {
for (;;) {
if (*a != *b)
return *a == 0 && *b == c;
return *a == 0 && (*b == c || separator);
if (*a == 0)
return true;
separator = *a == c;
a++, b++;
}
}

View File

@ -124,5 +124,15 @@ int main(int argc, char *argv[]) {
test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/'", true);
test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/quux'", false);
test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo/'", false);
test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/'", false);
test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/foo/bar/waldo/'", false);
test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/foo/'", true);
test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "/foo/bar/waldo", "arg0path='/foo/'", true);
test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "/foo", "arg0path='/foo'", true);
test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "/foo", "arg0path='/foo/bar/waldo'", false);
test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "/foo/", "arg0path='/foo/bar/waldo'", true);
return 0;
}

View File

@ -95,23 +95,28 @@ int main(int argc, char *argv[]) {
assert_se(!namespace_complex_pattern("foo.", ""));
assert_se(path_complex_pattern("", ""));
assert_se(path_complex_pattern("", "/"));
assert_se(path_complex_pattern("/", ""));
assert_se(!path_complex_pattern("", "/"));
assert_se(!path_complex_pattern("/", ""));
assert_se(path_complex_pattern("/", "/"));
assert_se(path_complex_pattern("/foobar/", "/"));
assert_se(path_complex_pattern("/foobar/", "/foobar"));
assert_se(!path_complex_pattern("/foobar/", "/foobar"));
assert_se(path_complex_pattern("/foobar", "/foobar"));
assert_se(path_complex_pattern("/foobar", "/foobar/"));
assert_se(!path_complex_pattern("/foobar", "/foobar/"));
assert_se(!path_complex_pattern("/foobar", "/foobar/waldo"));
assert_se(path_complex_pattern("/foobar/", "/foobar/waldo"));
assert_se(path_complex_pattern("/foobar/waldo", "/foobar/"));
assert_se(path_simple_pattern("/foo/", "/foo/bar/waldo"));
assert_se(namespace_simple_pattern("", ""));
assert_se(namespace_simple_pattern("", ".foobar"));
assert_se(namespace_simple_pattern("foobar", "foobar"));
assert_se(namespace_simple_pattern("foobar.waldo", "foobar.waldo"));
assert_se(namespace_simple_pattern("foobar", "foobar.waldo"));
assert_se(!namespace_simple_pattern("foobar.waldo", "foobar"));
assert_se(!namespace_simple_pattern("", "foo"));
assert_se(!namespace_simple_pattern("foo", ""));
assert_se(namespace_simple_pattern("foo.", "foo.bar.waldo"));
assert_se(streq(object_path_startswith("/foo/bar", "/foo"), "bar"));
assert_se(streq(object_path_startswith("/foo", "/foo"), ""));