X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd-bus%2Fbus-match.c;h=ffc97562fd8e286d12db6f6deeabf82f3c440f57;hp=750acfe6d5386dcfad5ff31a6c9ce494baf5964d;hb=bc6422cbd1dfc258fb2b4909a2a25ad356e63400;hpb=fd59d9f29838c3888168554c774003e7ad6d33b0 diff --git a/src/libsystemd-bus/bus-match.c b/src/libsystemd-bus/bus-match.c index 750acfe6d..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: @@ -256,7 +287,10 @@ int bus_match_run( /* Run the callback. And then invoke siblings. */ if (node->leaf.callback) { - r = node->leaf.callback(bus, m, node->leaf.userdata); + _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + + 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; } @@ -328,7 +362,7 @@ 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, m); @@ -555,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 && hasprefix(k, "type")) + if (n == 4 && startswith(k, "type")) return BUS_MATCH_MESSAGE_TYPE; - if (n == 6 && hasprefix(k, "sender")) + if (n == 6 && startswith(k, "sender")) return BUS_MATCH_SENDER; - if (n == 11 && hasprefix(k, "destination")) + if (n == 11 && startswith(k, "destination")) return BUS_MATCH_DESTINATION; - if (n == 9 && hasprefix(k, "interface")) + if (n == 9 && startswith(k, "interface")) return BUS_MATCH_INTERFACE; - if (n == 6 && hasprefix(k, "member")) + if (n == 6 && startswith(k, "member")) return BUS_MATCH_MEMBER; - if (n == 4 && hasprefix(k, "path")) + if (n == 4 && startswith(k, "path")) return BUS_MATCH_PATH; - if (n == 14 && hasprefix(k, "path_namespace")) + if (n == 14 && startswith(k, "path_namespace")) return BUS_MATCH_PATH_NAMESPACE; - if (n == 4 && hasprefix(k, "arg")) { + if (n == 4 && startswith(k, "arg")) { int j; j = undecchar(k[3]); @@ -580,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 && hasprefix(k, "arg")) { + if (n == 5 && startswith(k, "arg")) { int a, b; enum bus_match_node_type t; @@ -596,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 && hasprefix(k, "arg") && hasprefix(k + 4, "path")) { + if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) { int j; j = undecchar(k[3]); @@ -606,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 && hasprefix(k, "arg") && hasprefix(k + 5, "path")) { + if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) { enum bus_match_node_type t; int a, b; @@ -622,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 && hasprefix(k, "arg") && hasprefix(k + 4, "namespace")) { + if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) { int j; j = undecchar(k[3]); @@ -632,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 && hasprefix(k, "arg") && hasprefix(k + 5, "namespace")) { + if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) { enum bus_match_node_type t; int a, b; @@ -692,25 +726,31 @@ int bus_match_parse( 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) { @@ -718,10 +758,20 @@ int bus_match_parse( 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; + } } } @@ -734,6 +784,14 @@ int bus_match_parse( 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) @@ -759,16 +817,16 @@ int bus_match_parse( 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 bus_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,6 +845,46 @@ fail: 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, struct bus_match_component *components,