From 180304516d2a7f4cd483bad5b08f22f7323c7738 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 13 Oct 2010 20:48:27 +1100 Subject: s4-ldb: use operator_fn syntax function in ldb_match code this also fixes error handling in case of bad syntax, memory error etc, which was previously conidered as a mismatch, but should return an error Pair-Programmed-With: Andrew Bartlett --- source4/lib/ldb/common/ldb_match.c | 304 ++++++++++++++++++++++++++----------- 1 file changed, 212 insertions(+), 92 deletions(-) diff --git a/source4/lib/ldb/common/ldb_match.c b/source4/lib/ldb/common/ldb_match.c index 869b3bd1c8..bf4c786932 100644 --- a/source4/lib/ldb/common/ldb_match.c +++ b/source4/lib/ldb/common/ldb_match.c @@ -81,55 +81,94 @@ static int ldb_match_scope(struct ldb_context *ldb, static int ldb_match_present(struct ldb_context *ldb, const struct ldb_message *msg, const struct ldb_parse_tree *tree, - enum ldb_scope scope) + enum ldb_scope scope, bool *matched) { + const struct ldb_schema_attribute *a; + struct ldb_message_element *el; + if (ldb_attr_dn(tree->u.present.attr) == 0) { - return 1; + *matched = true; + return LDB_SUCCESS; } - if (ldb_msg_find_element(msg, tree->u.present.attr)) { - return 1; + el = ldb_msg_find_element(msg, tree->u.present.attr); + if (el == NULL) { + *matched = false; + return LDB_SUCCESS; } - return 0; + a = ldb_schema_attribute_by_name(ldb, el->name); + if (!a) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + + if (a->syntax->operator_fn) { + int i; + for (i = 0; i < el->num_values; i++) { + int ret = a->syntax->operator_fn(ldb, LDB_OP_PRESENT, a, &el->values[i], NULL, matched); + if (ret != LDB_SUCCESS) return ret; + if (*matched) return LDB_SUCCESS; + } + *matched = false; + return LDB_SUCCESS; + } + + *matched = true; + return LDB_SUCCESS; } static int ldb_match_comparison(struct ldb_context *ldb, const struct ldb_message *msg, const struct ldb_parse_tree *tree, enum ldb_scope scope, - enum ldb_parse_op comp_op) + enum ldb_parse_op comp_op, bool *matched) { unsigned int i; struct ldb_message_element *el; const struct ldb_schema_attribute *a; - int ret; /* FIXME: APPROX comparison not handled yet */ - if (comp_op == LDB_OP_APPROX) return 0; + if (comp_op == LDB_OP_APPROX) { + return LDB_ERR_INAPPROPRIATE_MATCHING; + } el = ldb_msg_find_element(msg, tree->u.comparison.attr); if (el == NULL) { - return 0; + *matched = false; + return LDB_SUCCESS; } a = ldb_schema_attribute_by_name(ldb, el->name); + if (!a) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } for (i = 0; i < el->num_values; i++) { - ret = a->syntax->comparison_fn(ldb, ldb, &el->values[i], &tree->u.comparison.value); - - if (ret == 0) { - return 1; - } - if (ret > 0 && comp_op == LDB_OP_GREATER) { - return 1; - } - if (ret < 0 && comp_op == LDB_OP_LESS) { - return 1; + if (a->syntax->operator_fn) { + int ret; + ret = a->syntax->operator_fn(ldb, comp_op, a, &el->values[i], &tree->u.comparison.value, matched); + if (ret != LDB_SUCCESS) return ret; + if (*matched) return LDB_SUCCESS; + } else { + int ret = a->syntax->comparison_fn(ldb, ldb, &el->values[i], &tree->u.comparison.value); + + if (ret == 0) { + *matched = true; + return LDB_SUCCESS; + } + if (ret > 0 && comp_op == LDB_OP_GREATER) { + *matched = true; + return LDB_SUCCESS; + } + if (ret < 0 && comp_op == LDB_OP_LESS) { + *matched = true; + return LDB_SUCCESS; + } } } - return 0; + *matched = false; + return LDB_SUCCESS; } /* @@ -138,7 +177,8 @@ static int ldb_match_comparison(struct ldb_context *ldb, static int ldb_match_equality(struct ldb_context *ldb, const struct ldb_message *msg, const struct ldb_parse_tree *tree, - enum ldb_scope scope) + enum ldb_scope scope, + bool *matched) { unsigned int i; struct ldb_message_element *el; @@ -149,39 +189,52 @@ static int ldb_match_equality(struct ldb_context *ldb, if (ldb_attr_dn(tree->u.equality.attr) == 0) { valuedn = ldb_dn_from_ldb_val(ldb, ldb, &tree->u.equality.value); if (valuedn == NULL) { - return 0; + return LDB_ERR_INVALID_DN_SYNTAX; } ret = ldb_dn_compare(msg->dn, valuedn); talloc_free(valuedn); - if (ret == 0) return 1; - return 0; + *matched = (ret == 0); + return LDB_SUCCESS; } /* TODO: handle the "*" case derived from an extended search operation without the attibute type defined */ el = ldb_msg_find_element(msg, tree->u.equality.attr); if (el == NULL) { - return 0; + *matched = false; + return LDB_SUCCESS; } a = ldb_schema_attribute_by_name(ldb, el->name); + if (a == NULL) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } for (i=0;inum_values;i++) { - if (a->syntax->comparison_fn(ldb, ldb, &tree->u.equality.value, - &el->values[i]) == 0) { - return 1; + if (a->syntax->operator_fn) { + ret = a->syntax->operator_fn(ldb, LDB_OP_EQUALITY, a, + &tree->u.equality.value, &el->values[i], matched); + if (ret != LDB_SUCCESS) return ret; + if (*matched) return LDB_SUCCESS; + } else { + if (a->syntax->comparison_fn(ldb, ldb, &tree->u.equality.value, + &el->values[i]) == 0) { + *matched = true; + return LDB_SUCCESS; + } } } - return 0; + *matched = false; + return LDB_SUCCESS; } static int ldb_wildcard_compare(struct ldb_context *ldb, const struct ldb_parse_tree *tree, - const struct ldb_val value) + const struct ldb_val value, bool *matched) { const struct ldb_schema_attribute *a; struct ldb_val val; @@ -192,9 +245,13 @@ static int ldb_wildcard_compare(struct ldb_context *ldb, unsigned int c = 0; a = ldb_schema_attribute_by_name(ldb, tree->u.substring.attr); + if (!a) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } - if(a->syntax->canonicalise_fn(ldb, ldb, &value, &val) != 0) - return -1; + if (a->syntax->canonicalise_fn(ldb, ldb, &value, &val) != 0) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } save_p = val.data; cnk.data = NULL; @@ -202,13 +259,13 @@ static int ldb_wildcard_compare(struct ldb_context *ldb, if ( ! tree->u.substring.start_with_wildcard ) { chunk = tree->u.substring.chunks[c]; - if(a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed; + if (a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto mismatch; /* This deals with wildcard prefix searches on binary attributes (eg objectGUID) */ if (cnk.length > val.length) { - goto failed; + goto mismatch; } - if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) goto failed; + if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) goto mismatch; val.length -= cnk.length; val.data += cnk.length; c++; @@ -219,11 +276,11 @@ static int ldb_wildcard_compare(struct ldb_context *ldb, while (tree->u.substring.chunks[c]) { chunk = tree->u.substring.chunks[c]; - if(a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed; + if(a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto mismatch; /* FIXME: case of embedded nulls */ p = strstr((char *)val.data, (char *)cnk.data); - if (p == NULL) goto failed; + if (p == NULL) goto mismatch; if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) { do { /* greedy */ g = strstr((char *)p + cnk.length, (char *)cnk.data); @@ -237,14 +294,17 @@ static int ldb_wildcard_compare(struct ldb_context *ldb, cnk.data = NULL; } - if ( (! tree->u.substring.end_with_wildcard) && (*(val.data) != 0) ) goto failed; /* last chunk have not reached end of string */ + /* last chunk may not have reached end of string */ + if ( (! tree->u.substring.end_with_wildcard) && (*(val.data) != 0) ) goto mismatch; talloc_free(save_p); - return 1; + *matched = true; + return LDB_SUCCESS; -failed: +mismatch: + *matched = false; talloc_free(save_p); talloc_free(cnk.data); - return 0; + return LDB_SUCCESS; } /* @@ -253,46 +313,71 @@ failed: static int ldb_match_substring(struct ldb_context *ldb, const struct ldb_message *msg, const struct ldb_parse_tree *tree, - enum ldb_scope scope) + enum ldb_scope scope, bool *matched) { unsigned int i; struct ldb_message_element *el; el = ldb_msg_find_element(msg, tree->u.substring.attr); if (el == NULL) { - return 0; + *matched = false; + return LDB_SUCCESS; } for (i = 0; i < el->num_values; i++) { - if (ldb_wildcard_compare(ldb, tree, el->values[i]) == 1) { - return 1; - } + int ret; + ret = ldb_wildcard_compare(ldb, tree, el->values[i], matched); + if (ret != LDB_SUCCESS) return ret; + if (*matched) return LDB_SUCCESS; } - return 0; + *matched = false; + return LDB_SUCCESS; } /* bitwise-and comparator */ -static int ldb_comparator_and(const struct ldb_val *v1, const struct ldb_val *v2) +static int ldb_comparator_bitmask(const char *oid, const struct ldb_val *v1, const struct ldb_val *v2, + bool *matched) { uint64_t i1, i2; - i1 = strtoull((char *)v1->data, NULL, 0); - i2 = strtoull((char *)v2->data, NULL, 0); - return ((i1 & i2) == i2); -} + char ibuf[100]; + char *endptr = NULL; -/* - bitwise-or comparator -*/ -static int ldb_comparator_or(const struct ldb_val *v1, const struct ldb_val *v2) -{ - uint64_t i1, i2; - i1 = strtoull((char *)v1->data, NULL, 0); - i2 = strtoull((char *)v2->data, NULL, 0); - return ((i1 & i2) != 0); + if (v1->length >= sizeof(ibuf)-1) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + memcpy(ibuf, (char *)v1->data, v1->length); + ibuf[v1->length] = 0; + i1 = strtoull(ibuf, &endptr, 0); + if (endptr != NULL) { + if (endptr == ibuf || *endptr != 0) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + } + + if (v2->length >= sizeof(ibuf)-1) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + endptr = NULL; + memcpy(ibuf, (char *)v2->data, v2->length); + ibuf[v2->length] = 0; + i2 = strtoull(ibuf, &endptr, 0); + if (endptr != NULL) { + if (endptr == ibuf || *endptr != 0) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + } + if (strcmp(LDB_OID_COMPARATOR_AND, oid) == 0) { + *matched = ((i1 & i2) == i2); + } else if (strcmp(LDB_OID_COMPARATOR_OR, oid) == 0) { + *matched = ((i1 & i2) != 0); + } else { + return LDB_ERR_INAPPROPRIATE_MATCHING; + } + return LDB_SUCCESS; } @@ -302,17 +387,17 @@ static int ldb_comparator_or(const struct ldb_val *v1, const struct ldb_val *v2) static int ldb_match_extended(struct ldb_context *ldb, const struct ldb_message *msg, const struct ldb_parse_tree *tree, - enum ldb_scope scope) + enum ldb_scope scope, bool *matched) { unsigned int i; const struct { const char *oid; - int (*comparator)(const struct ldb_val *, const struct ldb_val *); + int (*comparator)(const char *, const struct ldb_val *, const struct ldb_val *, bool *); } rules[] = { - { LDB_OID_COMPARATOR_AND, ldb_comparator_and}, - { LDB_OID_COMPARATOR_OR, ldb_comparator_or} + { LDB_OID_COMPARATOR_AND, ldb_comparator_bitmask}, + { LDB_OID_COMPARATOR_OR, ldb_comparator_bitmask} }; - int (*comp)(const struct ldb_val *, const struct ldb_val *) = NULL; + int (*comp)(const char *,const struct ldb_val *, const struct ldb_val *, bool *) = NULL; struct ldb_message_element *el; if (tree->u.extended.dnAttributes) { @@ -324,11 +409,11 @@ static int ldb_match_extended(struct ldb_context *ldb, } if (tree->u.extended.rule_id == NULL) { ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet"); - return -1; + return LDB_ERR_INAPPROPRIATE_MATCHING; } if (tree->u.extended.attr == NULL) { ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-attribute extended matches not supported yet"); - return -1; + return LDB_ERR_INAPPROPRIATE_MATCHING; } for (i=0;iu.extended.rule_id); - return -1; + return LDB_ERR_INAPPROPRIATE_MATCHING; } /* find the message element */ el = ldb_msg_find_element(msg, tree->u.extended.attr); if (el == NULL) { - return 0; + *matched = false; + return LDB_SUCCESS; } for (i=0;inum_values;i++) { - int ret = comp(&el->values[i], &tree->u.extended.value); - if (ret == -1 || ret == 1) return ret; + int ret = comp(tree->u.extended.rule_id, &el->values[i], &tree->u.extended.value, matched); + if (ret != LDB_SUCCESS) return ret; + if (*matched) return LDB_SUCCESS; } - return 0; + *matched = false; + return LDB_SUCCESS; } /* @@ -368,53 +456,61 @@ static int ldb_match_extended(struct ldb_context *ldb, static int ldb_match_message(struct ldb_context *ldb, const struct ldb_message *msg, const struct ldb_parse_tree *tree, - enum ldb_scope scope) + enum ldb_scope scope, bool *matched) { unsigned int i; - int v; + int ret; + + *matched = false; switch (tree->operation) { case LDB_OP_AND: for (i=0;iu.list.num_elements;i++) { - v = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope); - if (!v) return 0; + ret = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope, matched); + if (ret != LDB_SUCCESS) return ret; + if (!*matched) return LDB_SUCCESS; } - return 1; + *matched = true; + return LDB_SUCCESS; case LDB_OP_OR: for (i=0;iu.list.num_elements;i++) { - v = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope); - if (v) return 1; + ret = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope, matched); + if (ret != LDB_SUCCESS) return ret; + if (*matched) return LDB_SUCCESS; } - return 0; + *matched = false; + return LDB_SUCCESS; case LDB_OP_NOT: - return ! ldb_match_message(ldb, msg, tree->u.isnot.child, scope); + ret = ldb_match_message(ldb, msg, tree->u.isnot.child, scope, matched); + if (ret != LDB_SUCCESS) return ret; + *matched = ! *matched; + return LDB_SUCCESS; case LDB_OP_EQUALITY: - return ldb_match_equality(ldb, msg, tree, scope); + return ldb_match_equality(ldb, msg, tree, scope, matched); case LDB_OP_SUBSTRING: - return ldb_match_substring(ldb, msg, tree, scope); + return ldb_match_substring(ldb, msg, tree, scope, matched); case LDB_OP_GREATER: - return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_GREATER); + return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_GREATER, matched); case LDB_OP_LESS: - return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_LESS); + return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_LESS, matched); case LDB_OP_PRESENT: - return ldb_match_present(ldb, msg, tree, scope); + return ldb_match_present(ldb, msg, tree, scope, matched); case LDB_OP_APPROX: - return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_APPROX); + return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_APPROX, matched); case LDB_OP_EXTENDED: - return ldb_match_extended(ldb, msg, tree, scope); - + return ldb_match_extended(ldb, msg, tree, scope, matched); } - return 0; + return LDB_ERR_INAPPROPRIATE_MATCHING; } int ldb_match_msg(struct ldb_context *ldb, @@ -423,11 +519,35 @@ int ldb_match_msg(struct ldb_context *ldb, struct ldb_dn *base, enum ldb_scope scope) { + bool matched; + int ret; + if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) { return 0; } - return ldb_match_message(ldb, msg, tree, scope); + ret = ldb_match_message(ldb, msg, tree, scope, &matched); + if (ret != LDB_SUCCESS) { + /* to match the old API, we need to consider this a + failure to match */ + return 0; + } + return matched?1:0; +} + +int ldb_match_msg_error(struct ldb_context *ldb, + const struct ldb_message *msg, + const struct ldb_parse_tree *tree, + struct ldb_dn *base, + enum ldb_scope scope, + bool *matched) +{ + if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) { + *matched = false; + return LDB_SUCCESS; + } + + return ldb_match_message(ldb, msg, tree, scope, matched); } int ldb_match_msg_objectclass(const struct ldb_message *msg, -- cgit