X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd-bus%2Fbus-match.c;h=ffc97562fd8e286d12db6f6deeabf82f3c440f57;hb=bc6422cbd1dfc258fb2b4909a2a25ad356e63400;hp=501a38df70b8aad2905d687fffc5bf070e348624;hpb=88fe224c8c3cf80ad48bb2b5ddd6e455b0a112d4;p=elogind.git diff --git a/src/libsystemd-bus/bus-match.c b/src/libsystemd-bus/bus-match.c index 501a38df7..ffc97562f 100644 --- a/src/libsystemd-bus/bus-match.c +++ b/src/libsystemd-bus/bus-match.c @@ -22,6 +22,9 @@ #include "bus-internal.h" #include "bus-message.h" #include "bus-match.h" +#include "bus-error.h" +#include "bus-util.h" +#include "strv.h" /* Example: * @@ -60,7 +63,7 @@ */ static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) { - return t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_ARG_NAMESPACE_LAST; + return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_NAMESPACE_LAST; } static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) { @@ -127,7 +130,8 @@ static bool value_node_test( struct bus_match_node *node, enum bus_match_node_type parent_type, uint8_t value_u8, - const char *value_str) { + const char *value_str, + sd_bus_message *m) { assert(node); assert(node->type == BUS_MATCH_VALUE); @@ -141,6 +145,33 @@ static bool value_node_test( return node->value.u8 == value_u8; case BUS_MATCH_SENDER: + if (streq_ptr(node->value.str, value_str)) + return true; + + if (m->creds.mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) { + char **i; + + /* on kdbus we have the well known names list + * in the credentials, let's make use of that + * for an accurate match */ + + STRV_FOREACH(i, m->creds.well_known_names) + if (streq_ptr(node->value.str, *i)) + return true; + + } else { + + /* If we don't have kdbus, we don't know the + * well-known names of the senders. In that, + * let's just hope that dbus-daemon doesn't + * send us stuff we didn't want. */ + + if (node->value.str[0] != ':' && value_str && value_str[0] == ':') + return true; + } + + return false; + case BUS_MATCH_DESTINATION: case BUS_MATCH_INTERFACE: case BUS_MATCH_MEMBER: @@ -199,7 +230,6 @@ static bool value_node_same( int bus_match_run( sd_bus *bus, struct bus_match_node *node, - int ret, sd_bus_message *m) { @@ -230,7 +260,7 @@ int bus_match_run( * we won't call any. The children of the root node * are compares or leaves, they will automatically * call their siblings. */ - return bus_match_run(bus, node->child, ret, m); + return bus_match_run(bus, node->child, m); case BUS_MATCH_VALUE: @@ -240,7 +270,7 @@ int bus_match_run( * automatically call their siblings */ assert(node->child); - return bus_match_run(bus, node->child, ret, m); + return bus_match_run(bus, node->child, m); case BUS_MATCH_LEAF: @@ -256,12 +286,16 @@ int bus_match_run( return r; /* Run the callback. And then invoke siblings. */ - assert(node->leaf.callback); - r = node->leaf.callback(bus, ret, m, node->leaf.userdata); - if (r != 0) - return r; + if (node->leaf.callback) { + _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; - return bus_match_run(bus, node->next, ret, m); + r = node->leaf.callback(bus, m, node->leaf.userdata, &error_buffer); + r = bus_maybe_reply_error(m, r, &error_buffer); + if (r != 0) + return r; + } + + return bus_match_run(bus, node->next, m); case BUS_MATCH_MESSAGE_TYPE: test_u8 = m->header->type; @@ -318,7 +352,7 @@ int bus_match_run( found = NULL; if (found) { - r = bus_match_run(bus, found, ret, m); + r = bus_match_run(bus, found, m); if (r != 0) return r; } @@ -328,10 +362,10 @@ int bus_match_run( /* No hash table, so let's iterate manually... */ for (c = node->child; c; c = c->next) { - if (!value_node_test(c, node->type, test_u8, test_str)) + if (!value_node_test(c, node->type, test_u8, test_str, m)) continue; - r = bus_match_run(bus, c, ret, m); + r = bus_match_run(bus, c, m); if (r != 0) return r; } @@ -341,7 +375,7 @@ int bus_match_run( return 0; /* And now, let's invoke our siblings */ - return bus_match_run(bus, node->next, ret, m); + return bus_match_run(bus, node->next, m); } static int bus_match_add_compare_value( @@ -500,6 +534,7 @@ static int bus_match_add_leaf( struct bus_match_node *where, sd_bus_message_handler_t callback, void *userdata, + uint64_t cookie, struct bus_match_node **ret) { struct bus_match_node *n; @@ -519,6 +554,7 @@ static int bus_match_add_leaf( n->next->prev = n; n->leaf.callback = callback; n->leaf.userdata = userdata; + n->leaf.cookie = cookie; where->child = n; @@ -553,22 +589,22 @@ static int bus_match_find_leaf( enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) { assert(k); - if (n == 4 && memcmp(k, "type", 4) == 0) + if (n == 4 && startswith(k, "type")) return BUS_MATCH_MESSAGE_TYPE; - if (n == 6 && memcmp(k, "sender", 6) == 0) + if (n == 6 && startswith(k, "sender")) return BUS_MATCH_SENDER; - if (n == 11 && memcmp(k, "destination", 11) == 0) + if (n == 11 && startswith(k, "destination")) return BUS_MATCH_DESTINATION; - if (n == 9 && memcmp(k, "interface", 9) == 0) + if (n == 9 && startswith(k, "interface")) return BUS_MATCH_INTERFACE; - if (n == 6 && memcmp(k, "member", 6) == 0) + if (n == 6 && startswith(k, "member")) return BUS_MATCH_MEMBER; - if (n == 4 && memcmp(k, "path", 4) == 0) + if (n == 4 && startswith(k, "path")) return BUS_MATCH_PATH; - if (n == 14 && memcmp(k, "path_namespace", 14) == 0) + if (n == 14 && startswith(k, "path_namespace")) return BUS_MATCH_PATH_NAMESPACE; - if (n == 4 && memcmp(k, "arg", 3) == 0) { + if (n == 4 && startswith(k, "arg")) { int j; j = undecchar(k[3]); @@ -578,7 +614,7 @@ enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n return BUS_MATCH_ARG + j; } - if (n == 5 && memcmp(k, "arg", 3) == 0) { + if (n == 5 && startswith(k, "arg")) { int a, b; enum bus_match_node_type t; @@ -594,7 +630,7 @@ enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n return t; } - if (n == 8 && memcmp(k, "arg", 3) == 0 && memcmp(k + 4, "path", 4) == 0) { + if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) { int j; j = undecchar(k[3]); @@ -604,7 +640,7 @@ enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n return BUS_MATCH_ARG_PATH + j; } - if (n == 9 && memcmp(k, "arg", 3) == 0 && memcmp(k + 5, "path", 4) == 0) { + if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) { enum bus_match_node_type t; int a, b; @@ -620,7 +656,7 @@ enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n return t; } - if (n == 13 && memcmp(k, "arg", 3) == 0 && memcmp(k + 4, "namespace", 9) == 0) { + if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) { int j; j = undecchar(k[3]); @@ -630,7 +666,7 @@ enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n return BUS_MATCH_ARG_NAMESPACE + j; } - if (n == 14 && memcmp(k, "arg", 3) == 0 && memcmp(k + 5, "namespace", 9) == 0) { + if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) { enum bus_match_node_type t; int a, b; @@ -649,14 +685,8 @@ enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n return -EINVAL; } -struct match_component { - enum bus_match_node_type type; - uint8_t value_u8; - char *value_str; -}; - static int match_component_compare(const void *a, const void *b) { - const struct match_component *x = a, *y = b; + const struct bus_match_component *x = a, *y = b; if (x->type < y->type) return -1; @@ -666,7 +696,7 @@ static int match_component_compare(const void *a, const void *b) { return 0; } -static void free_components(struct match_component *components, unsigned n_components) { +void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) { unsigned i; for (i = 0; i < n_components; i++) @@ -675,13 +705,13 @@ static void free_components(struct match_component *components, unsigned n_compo free(components); } -static int parse_match( +int bus_match_parse( const char *match, - struct match_component **_components, + struct bus_match_component **_components, unsigned *_n_components) { const char *p = match; - struct match_component *components = NULL; + struct bus_match_component *components = NULL; size_t components_allocated = 0; unsigned n_components = 0, i; _cleanup_free_ char *value = NULL; @@ -696,25 +726,31 @@ static int parse_match( enum bus_match_node_type t; unsigned j = 0; size_t value_allocated = 0; - bool escaped = false; + bool escaped = false, quoted; uint8_t u; eq = strchr(p, '='); if (!eq) return -EINVAL; - if (eq[1] != '\'') - return -EINVAL; - t = bus_match_node_type_from_string(p, eq - p); if (t < 0) return -EINVAL; - for (q = eq + 2;; q++) { + quoted = eq[1] == '\''; + + for (q = eq + 1 + quoted;; q++) { if (*q == 0) { - r = -EINVAL; - goto fail; + + if (quoted) { + r = -EINVAL; + goto fail; + } else { + if (value) + value[j] = 0; + break; + } } if (!escaped) { @@ -722,10 +758,20 @@ static int parse_match( escaped = true; continue; } - if (*q == '\'') { - if (value) - value[j] = 0; - break; + + if (quoted) { + if (*q == '\'') { + if (value) + value[j] = 0; + break; + } + } else { + if (*q == ',') { + if (value) + value[j] = 0; + + break; + } } } @@ -738,6 +784,14 @@ static int parse_match( escaped = false; } + if (!value) { + value = strdup(""); + if (!value) { + r = -ENOMEM; + goto fail; + } + } + if (t == BUS_MATCH_MESSAGE_TYPE) { r = bus_message_type_from_string(value, &u); if (r < 0) @@ -763,16 +817,16 @@ static int parse_match( if (q[1] == 0) break; - if (q[1] != ',') { + if (q[quoted] != ',') { r = -EINVAL; goto fail; } - p = q + 2; + p = q + 1 + quoted; } /* Order the whole thing, so that we always generate the same tree */ - qsort(components, n_components, sizeof(struct match_component), match_component_compare); + qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare); /* Check for duplicates */ for (i = 0; i+1 < n_components; i++) @@ -787,29 +841,64 @@ static int parse_match( return 0; fail: - free_components(components, n_components); + bus_match_parse_free(components, n_components); return r; } +char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) { + _cleanup_free_ FILE *f = NULL; + char *buffer = NULL; + size_t size = 0; + unsigned i; + + if (n_components <= 0) + return strdup(""); + + assert(components); + + f = open_memstream(&buffer, &size); + if (!f) + return NULL; + + for (i = 0; i < n_components; i++) { + char buf[32]; + + if (i != 0) + fputc(',', f); + + fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f); + fputc('=', f); + fputc('\'', f); + + if (components[i].type == BUS_MATCH_MESSAGE_TYPE) + fputs(bus_message_type_to_string(components[i].value_u8), f); + else + fputs(components[i].value_str, f); + + fputc('\'', f); + } + + fflush(f); + if (ferror(f)) + return NULL; + + return buffer; +} + int bus_match_add( struct bus_match_node *root, - const char *match, + struct bus_match_component *components, + unsigned n_components, sd_bus_message_handler_t callback, void *userdata, + uint64_t cookie, struct bus_match_node **ret) { - struct match_component *components = NULL; - unsigned n_components = 0, i; + unsigned i; struct bus_match_node *n; int r; assert(root); - assert(match); - assert(callback); - - r = parse_match(match, &components, &n_components); - if (r < 0) - return r; n = root; for (i = 0; i < n_components; i++) { @@ -817,38 +906,32 @@ int bus_match_add( n, components[i].type, components[i].value_u8, components[i].value_str, &n); if (r < 0) - goto finish; + return r; } - r = bus_match_add_leaf(n, callback, userdata, &n); + r = bus_match_add_leaf(n, callback, userdata, cookie, &n); if (r < 0) - goto finish; + return r; if (ret) *ret = n; -finish: - free_components(components, n_components); - return r; + return 0; } int bus_match_remove( struct bus_match_node *root, - const char *match, + struct bus_match_component *components, + unsigned n_components, sd_bus_message_handler_t callback, - void *userdata) { + void *userdata, + uint64_t *cookie) { - struct match_component *components = NULL; - unsigned n_components = 0, i; + unsigned i; struct bus_match_node *n, **gc; int r; assert(root); - assert(match); - - r = parse_match(match, &components, &n_components); - if (r < 0) - return r; gc = newa(struct bus_match_node*, n_components); @@ -859,14 +942,17 @@ int bus_match_remove( components[i].value_u8, components[i].value_str, &n); if (r <= 0) - goto finish; + return r; gc[i] = n; } r = bus_match_find_leaf(n, callback, userdata, &n); if (r <= 0) - goto finish; + return r; + + if (cookie) + *cookie = n->leaf.cookie; /* Free the leaf */ bus_match_node_free(n); @@ -882,8 +968,6 @@ int bus_match_remove( break; } -finish: - free_components(components, n_components); return r; }