From faa4be0535fd41bf282b1afc749a05412f4ee96c Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Wed, 5 Nov 2014 11:02:25 +0100 Subject: [PATCH] ldb: Allow to register extended match rules This allows to extend LDB by registering extended match rules from outside the library itself. This is necessary when the implementation requires knowledge about syntaxes implemented in samba extensions, like the LDAP_MATCHING_RULE_TRANSITIVE_EVAL match. Signed-off-by: Samuel Cabrero Singed-off-by: Andrew Bartlett Reviewed-by: Andrew Bartlett Reviewed-by: Garming Sam --- lib/ldb/common/ldb.c | 5 + lib/ldb/common/ldb_match.c | 177 +++++++++++++++++++++++++++------- lib/ldb/include/ldb_module.h | 13 +++ lib/ldb/include/ldb_private.h | 6 ++ 4 files changed, 165 insertions(+), 36 deletions(-) diff --git a/lib/ldb/common/ldb.c b/lib/ldb/common/ldb.c index c49513cfaa7..0f0f5ab99b6 100644 --- a/lib/ldb/common/ldb.c +++ b/lib/ldb/common/ldb.c @@ -130,6 +130,11 @@ struct ldb_context *ldb_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx) ldb_set_create_perms(ldb, 0666); ldb_set_modules_dir(ldb, LDB_MODULESDIR); ldb_set_event_context(ldb, ev_ctx); + ret = ldb_register_extended_match_rules(ldb); + if (ret != LDB_SUCCESS) { + talloc_free(ldb); + return NULL; + } /* TODO: get timeout from options if available there */ ldb->default_timeout = 300; /* set default to 5 minutes */ diff --git a/lib/ldb/common/ldb_match.c b/lib/ldb/common/ldb_match.c index 7918aec65f1..a493daec49f 100644 --- a/lib/ldb/common/ldb_match.c +++ b/lib/ldb/common/ldb_match.c @@ -33,6 +33,7 @@ */ #include "ldb_private.h" +#include "dlinklist.h" /* check if the scope matches in a search result @@ -342,7 +343,7 @@ static int ldb_match_substring(struct ldb_context *ldb, /* - bitwise-and comparator + bitwise and/or comparator depending on oid */ static int ldb_comparator_bitmask(const char *oid, const struct ldb_val *v1, const struct ldb_val *v2, bool *matched) @@ -385,10 +386,48 @@ static int ldb_comparator_bitmask(const char *oid, const struct ldb_val *v1, con return LDB_SUCCESS; } +static int ldb_match_bitmask(struct ldb_context *ldb, + const char *oid, + const struct ldb_message *msg, + const char *attribute_to_match, + const struct ldb_val *value_to_match, + bool *matched) +{ + unsigned int i; + struct ldb_message_element *el; + + /* find the message element */ + el = ldb_msg_find_element(msg, attribute_to_match); + if (el == NULL) { + *matched = false; + return LDB_SUCCESS; + } + + for (i=0;inum_values;i++) { + int ret; + struct ldb_val *v = &el->values[i]; + + ret = ldb_comparator_bitmask(oid, v, value_to_match, matched); + if (ret != LDB_SUCCESS) { + return ret; + } + if (*matched) { + return LDB_SUCCESS; + } + } + + *matched = false; + return LDB_SUCCESS; +} + /* always return false */ -static int ldb_comparator_false(const char *oid, const struct ldb_val *v1, const struct ldb_val *v2, +static int ldb_comparator_false(struct ldb_context *ldb, + const char *oid, + const struct ldb_message *msg, + const char *attribute_to_match, + const struct ldb_val *value_to_match, bool *matched) { *matched = false; @@ -396,6 +435,23 @@ static int ldb_comparator_false(const char *oid, const struct ldb_val *v1, const } +static const struct ldb_extended_match_rule *ldb_find_extended_match_rule(struct ldb_context *ldb, + const char *oid) +{ + struct ldb_extended_match_entry *extended_match_rule; + + for (extended_match_rule = ldb->extended_match_rules; + extended_match_rule; + extended_match_rule = extended_match_rule->next) { + if (strcmp(extended_match_rule->rule->oid, oid) == 0) { + return extended_match_rule->rule; + } + } + + return NULL; +} + + /* extended match, handles things like bitops */ @@ -404,17 +460,7 @@ static int ldb_match_extended(struct ldb_context *ldb, const struct ldb_parse_tree *tree, enum ldb_scope scope, bool *matched) { - unsigned int i; - const struct { - const char *oid; - int (*comparator)(const char *, const struct ldb_val *, const struct ldb_val *, bool *); - } rules[] = { - { LDB_OID_COMPARATOR_AND, ldb_comparator_bitmask}, - { LDB_OID_COMPARATOR_OR, ldb_comparator_bitmask}, - { SAMBA_LDAP_MATCH_ALWAYS_FALSE, ldb_comparator_false} - }; - int (*comp)(const char *,const struct ldb_val *, const struct ldb_val *, bool *) = NULL; - struct ldb_message_element *el; + const struct ldb_extended_match_rule *rule; if (tree->u.extended.dnAttributes) { /* FIXME: We really need to find out what this ":dn" part in @@ -432,33 +478,16 @@ static int ldb_match_extended(struct ldb_context *ldb, return LDB_ERR_INAPPROPRIATE_MATCHING; } - for (i=0;iu.extended.rule_id) == 0) { - comp = rules[i].comparator; - break; - } - } - if (comp == NULL) { + rule = ldb_find_extended_match_rule(ldb, tree->u.extended.rule_id); + if (rule == NULL) { ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s", tree->u.extended.rule_id); return LDB_ERR_INAPPROPRIATE_MATCHING; } - /* find the message element */ - el = ldb_msg_find_element(msg, tree->u.extended.attr); - if (el == NULL) { - *matched = false; - return LDB_SUCCESS; - } - - for (i=0;inum_values;i++) { - 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; - } - - *matched = false; - return LDB_SUCCESS; + return rule->callback(ldb, rule->oid, msg, + tree->u.extended.attr, + &tree->u.extended.value, matched); } /* @@ -587,5 +616,81 @@ int ldb_match_msg_objectclass(const struct ldb_message *msg, return 0; } +_PRIVATE_ int ldb_register_extended_match_rules(struct ldb_context *ldb) +{ + struct ldb_extended_match_rule *bitmask_and; + struct ldb_extended_match_rule *bitmask_or; + struct ldb_extended_match_rule *always_false; + int ret; + + /* Register bitmask-and match */ + bitmask_and = talloc_zero(ldb, struct ldb_extended_match_rule); + if (bitmask_and == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + bitmask_and->oid = LDB_OID_COMPARATOR_AND; + bitmask_and->callback = ldb_match_bitmask; + + ret = ldb_register_extended_match_rule(ldb, bitmask_and); + if (ret != LDB_SUCCESS) { + return ret; + } + + /* Register bitmask-or match */ + bitmask_or = talloc_zero(ldb, struct ldb_extended_match_rule); + if (bitmask_or == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + bitmask_or->oid = LDB_OID_COMPARATOR_OR; + bitmask_or->callback = ldb_match_bitmask; + + ret = ldb_register_extended_match_rule(ldb, bitmask_or); + if (ret != LDB_SUCCESS) { + return ret; + } + + /* Register always-false match */ + always_false = talloc_zero(ldb, struct ldb_extended_match_rule); + if (always_false == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + always_false->oid = SAMBA_LDAP_MATCH_ALWAYS_FALSE; + always_false->callback = ldb_comparator_false; + + ret = ldb_register_extended_match_rule(ldb, always_false); + if (ret != LDB_SUCCESS) { + return ret; + } + + return LDB_SUCCESS; +} + +/* + register a new ldb backend + + if override is true, then override any existing backend for this prefix +*/ +int ldb_register_extended_match_rule(struct ldb_context *ldb, + const struct ldb_extended_match_rule *rule) +{ + const struct ldb_extended_match_rule *lookup_rule; + struct ldb_extended_match_entry *entry; + + lookup_rule = ldb_find_extended_match_rule(ldb, rule->oid); + if (lookup_rule) { + return LDB_ERR_ENTRY_ALREADY_EXISTS; + } + + entry = talloc_zero(ldb, struct ldb_extended_match_entry); + if (!entry) { + return LDB_ERR_OPERATIONS_ERROR; + } + entry->rule = rule; + DLIST_ADD_END(ldb->extended_match_rules, entry, struct ldb_extended_match_entry); + + return LDB_SUCCESS; +} - diff --git a/lib/ldb/include/ldb_module.h b/lib/ldb/include/ldb_module.h index be50c092101..34e33c0ec55 100644 --- a/lib/ldb/include/ldb_module.h +++ b/lib/ldb/include/ldb_module.h @@ -162,6 +162,8 @@ int ldb_match_msg_error(struct ldb_context *ldb, int ldb_match_msg_objectclass(const struct ldb_message *msg, const char *objectclass); +int ldb_register_extended_match_rules(struct ldb_context *ldb); + /* The following definitions come from lib/ldb/common/ldb_modules.c */ struct ldb_module *ldb_module_new(TALLOC_CTX *memctx, @@ -369,4 +371,15 @@ bool ldb_msg_element_equal_ordered(const struct ldb_message_element *el1, const struct ldb_message_element *el2); +struct ldb_extended_match_rule +{ + const char *oid; + int (*callback)(struct ldb_context *, const char *oid, + const struct ldb_message *, const char *, + const struct ldb_val *, bool *); +}; + +int ldb_register_extended_match_rule(struct ldb_context *ldb, + const struct ldb_extended_match_rule *rule); + #endif diff --git a/lib/ldb/include/ldb_private.h b/lib/ldb/include/ldb_private.h index 526bf5e4910..797744875a3 100644 --- a/lib/ldb/include/ldb_private.h +++ b/lib/ldb/include/ldb_private.h @@ -100,6 +100,12 @@ struct ldb_context { /* debugging operations */ struct ldb_debug_ops debug_ops; + /* extended matching rules */ + struct ldb_extended_match_entry { + const struct ldb_extended_match_rule *rule; + struct ldb_extended_match_entry *prev, *next; + } *extended_match_rules; + /* custom utf8 functions */ struct ldb_utf8_fns utf8_fns; -- 2.34.1