chiark / gitweb /
bus: fix pattern matching
authorDavid Herrmann <dh.herrmann@gmail.com>
Wed, 10 Jun 2015 17:34:05 +0000 (19:34 +0200)
committerSven Eden <yamakuzure@gmx.net>
Tue, 14 Mar 2017 09:01:50 +0000 (10:01 +0100)
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..

src/libelogind/sd-bus/bus-internal.c
src/libelogind/sd-bus/test-bus-kernel-bloom.c
src/libelogind/sd-bus/test-bus-signature.c

index 91b288cd255011dc3398679abb4afbdeaba622f7..37793e48edb03a5dbdad94028a2d45343700f25b 100644 (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++;
         }
 }
index 8ebbbfaaac3e161af5cf43edfa43f3bd1508e2be..01f784f8c232b4d6fbb624538ed79d6bb46089d2 100644 (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;
 }
index 4165c9273a1fe0a042ac58e477effa915e2a2b46..17c6188ca01cee5e565ed22ac3f09fca379f3774 100644 (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"), ""));