ldb: Allow to register extended match rules
authorSamuel Cabrero <samuelcabrero@kernevil.me>
Wed, 5 Nov 2014 10:02:25 +0000 (11:02 +0100)
committerGarming Sam <garming@samba.org>
Sun, 21 Dec 2014 23:18:09 +0000 (00:18 +0100)
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 <samuelcabrero@kernevil.me>
Singed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
lib/ldb/common/ldb.c
lib/ldb/common/ldb_match.c
lib/ldb/include/ldb_module.h
lib/ldb/include/ldb_private.h

index c49513cfaa7584174bf3a8a40cef6c8c5b3c1769..0f0f5ab99b69b805cd0535399ca9d7c4c34abc11 100644 (file)
@@ -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 */
index 7918aec65f166378a232e9da4513f1dd19928ff5..a493daec49f866edfa4f7896ac5797e0e9efb715 100644 (file)
@@ -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;i<el->num_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;i<ARRAY_SIZE(rules);i++) {
-               if (strcmp(rules[i].oid, tree->u.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;i<el->num_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;
+}
 
-                             
index be50c092101b016bb8a9d6e6856b10e492387f8b..34e33c0ec559d98e2524e0ea421e7b316b9fdf37 100644 (file)
@@ -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
index 526bf5e49104115afa4f56c6e435018d5440c187..797744875a3999934b04058df23afcb1e1a25902 100644 (file)
@@ -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;