major upgrade to the ldb attribute handling
authorAndrew Tridgell <tridge@samba.org>
Thu, 2 Apr 2009 05:42:21 +0000 (16:42 +1100)
committerAndrew Tridgell <tridge@samba.org>
Thu, 2 Apr 2009 05:42:21 +0000 (16:42 +1100)
This is all working towards supporting the full WSPP schema without a
major performance penalty.

We now use binary searches when looking up classes and attributes. We
also avoid the loop loading the attributes into ldb, by adding a hook
to override the ldb attribute search function in a module. The
attributes can thus be loaded once, and then saved as part of the
global schema.

Also added support for a few more key attribute syntaxes, as needed
for the full schema.

17 files changed:
source4/dsdb/schema/schema.h
source4/dsdb/schema/schema_init.c
source4/dsdb/schema/schema_query.c
source4/dsdb/schema/schema_set.c
source4/dsdb/schema/schema_syntax.c
source4/lib/ldb-samba/ldif_handlers.c
source4/lib/ldb/common/attrib_handlers.c
source4/lib/ldb/common/ldb_attributes.c
source4/lib/ldb/configure.ac
source4/lib/ldb/include/ldb.h
source4/lib/ldb/include/ldb_handlers.h
source4/lib/ldb/include/ldb_module.h
source4/lib/ldb/include/ldb_private.h
source4/libnet/libnet_vampire.c
source4/min_versions.m4
source4/torture/ldap/schema.c
source4/torture/libnet/libnet_BecomeDC.c

index f7d59a7c393c3144671c9813e0f95b8bf48b0d77..98ccf5ed9e1f1c38b0951cff2dd0bfebc85a369e 100644 (file)
@@ -91,6 +91,7 @@ struct dsdb_attribute {
 
        /* internal stuff */
        const struct dsdb_syntax *syntax;
+       const struct ldb_schema_attribute *ldb_schema_attribute;
 };
 
 struct dsdb_class {
@@ -156,6 +157,21 @@ struct dsdb_schema {
        struct dsdb_attribute *attributes;
        struct dsdb_class *classes;
 
+       /* lists of classes sorted by various attributes, for faster
+          access */
+       uint32_t num_classes;
+       struct dsdb_class **classes_by_lDAPDisplayName;
+       struct dsdb_class **classes_by_governsID_id;
+       struct dsdb_class **classes_by_governsID_oid;
+       struct dsdb_class **classes_by_cn;
+
+       /* lists of attributes sorted by various fields */
+       uint32_t num_attributes;
+       struct dsdb_attribute **attributes_by_lDAPDisplayName;
+       struct dsdb_attribute **attributes_by_attributeID_id;
+       struct dsdb_attribute **attributes_by_attributeID_oid;
+       struct dsdb_attribute **attributes_by_linkID;
+
        struct {
                bool we_are_master;
                struct ldb_dn *master_dn;
index e619e1ffacee5a3b14a1cb4669b8afcd8db563ed..3a65c474fb7813615cae59e9ae428d4cccd2941a 100644 (file)
@@ -28,6 +28,7 @@
 #include "librpc/gen_ndr/ndr_drsuapi.h"
 #include "librpc/gen_ndr/ndr_drsblobs.h"
 #include "param/param.h"
+#include "lib/ldb/include/ldb_module.h"
 
 struct dsdb_schema *dsdb_new_schema(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience)
 {
@@ -582,6 +583,48 @@ WERROR dsdb_read_prefixes_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
        return WERR_OK;
 }
 
+
+/*
+  setup the ldb_schema_attribute field for a dsdb_attribute
+ */
+static int dsdb_schema_setup_ldb_schema_attribute(struct ldb_context *ldb, 
+                                                 struct dsdb_attribute *attr)
+{
+       const char *syntax = attr->syntax->ldb_syntax;
+       const struct ldb_schema_syntax *s;
+       struct ldb_schema_attribute *a;
+
+       if (!syntax) {
+               syntax = attr->syntax->ldap_oid;
+       }
+
+       s = ldb_samba_syntax_by_lDAPDisplayName(ldb, attr->lDAPDisplayName);
+       if (s == NULL) {
+               s = ldb_samba_syntax_by_name(ldb, syntax);
+       }
+       if (s == NULL) {
+               s = ldb_standard_syntax_by_name(ldb, syntax);
+       }
+
+       if (s == NULL) {
+               return LDB_ERR_OPERATIONS_ERROR;                
+       }
+
+       attr->ldb_schema_attribute = a = talloc(attr, struct ldb_schema_attribute);
+       if (attr->ldb_schema_attribute == NULL) {
+               ldb_oom(ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       a->name = attr->lDAPDisplayName;
+       a->flags = 0;
+       a->syntax = s;
+       
+       return LDB_SUCCESS;
+}
+
+
+
 #define GET_STRING_LDB(msg, attr, mem_ctx, p, elem, strict) do { \
        (p)->elem = samdb_result_string(msg, attr, NULL);\
        if (strict && (p)->elem == NULL) { \
@@ -676,7 +719,8 @@ WERROR dsdb_read_prefixes_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
        }\
 } while (0)
 
-WERROR dsdb_attribute_from_ldb(const struct dsdb_schema *schema,
+WERROR dsdb_attribute_from_ldb(struct ldb_context *ldb,
+                              const struct dsdb_schema *schema,
                               struct ldb_message *msg,
                               TALLOC_CTX *mem_ctx,
                               struct dsdb_attribute *attr)
@@ -745,6 +789,10 @@ WERROR dsdb_attribute_from_ldb(const struct dsdb_schema *schema,
                return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
        }
 
+       if (dsdb_schema_setup_ldb_schema_attribute(ldb, attr) != LDB_SUCCESS) {
+               return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
+       }
+
        return WERR_OK;
 }
 
@@ -866,7 +914,7 @@ int dsdb_schema_from_ldb_results(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
                        return LDB_ERR_OPERATIONS_ERROR;
                }
 
-               status = dsdb_attribute_from_ldb(schema, attrs_res->msgs[i], sa, sa);
+               status = dsdb_attribute_from_ldb(ldb, schema, attrs_res->msgs[i], sa, sa);
                if (!W_ERROR_IS_OK(status)) {
                        *error_string = talloc_asprintf(mem_ctx, 
                                      "schema_fsmo_init: failed to load attribute definition: %s:%s",
@@ -1274,7 +1322,8 @@ static struct drsuapi_DsReplicaAttribute *dsdb_find_object_attr_name(struct dsdb
        }\
 } while (0)
 
-WERROR dsdb_attribute_from_drsuapi(struct dsdb_schema *schema,
+WERROR dsdb_attribute_from_drsuapi(struct ldb_context *ldb,
+                                  struct dsdb_schema *schema,
                                   struct drsuapi_DsReplicaObject *r,
                                   TALLOC_CTX *mem_ctx,
                                   struct dsdb_attribute *attr)
@@ -1333,6 +1382,10 @@ WERROR dsdb_attribute_from_drsuapi(struct dsdb_schema *schema,
                return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
        }
 
+       if (dsdb_schema_setup_ldb_schema_attribute(ldb, attr) != LDB_SUCCESS) {
+               return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
+       }
+
        return WERR_OK;
 }
 
index 00de0f89834e50c1bbb084f93ff35711f3011d98..f894ef5b1e55464a63a7c9e55d3beb2603ee0e26 100644 (file)
 #include "includes.h"
 #include "dsdb/samdb/samdb.h"
 
+/* a binary array search, where the array is an array of pointers to structures,
+   and we want to find a match for 'target' on 'field' in those structures.
+
+   Inputs:
+      array:          base pointer to an array of structures
+      arrray_size:    number of elements in the array
+      field:          the name of the field in the structure we are keying off
+      target:         the field value we are looking for
+      comparison_fn:  the comparison function
+      result:         where the result of the search is put
+
+   if the element is found, then 'result' is set to point to the found array element. If not,
+   then 'result' is set to NULL.
+
+   The array is assumed to be sorted by the same comparison_fn as the
+   search (with, for example, qsort)
+ */
+#define BINARY_ARRAY_SEARCH(array, array_size, field, target, comparison_fn, result) do { \
+       int32_t _b, _e; \
+       (result) = NULL; \
+       for (_b = 0, _e = (array_size)-1; _b <= _e; ) { \
+               int32_t _i = (_b+_e)/2; \
+               int _r = comparison_fn(target, array[_i]->field); \
+               if (_r == 0) { (result) = array[_i]; break; } \
+               if (_r < 0) _e = _i - 1; else _b = _i + 1; \
+       } } while (0)
+
+
+static int uint32_cmp(uint32_t c1, uint32_t c2) 
+{
+       return c1 - c2;
+}
+
+
 const struct dsdb_attribute *dsdb_attribute_by_attributeID_id(const struct dsdb_schema *schema,
                                                              uint32_t id)
 {
-       struct dsdb_attribute *cur;
+       struct dsdb_attribute *c;
 
        /*
         * 0xFFFFFFFF is used as value when no mapping table is available,
@@ -34,69 +68,49 @@ const struct dsdb_attribute *dsdb_attribute_by_attributeID_id(const struct dsdb_
         */
        if (id == 0xFFFFFFFF) return NULL;
 
-       /* TODO: add binary search */
-       for (cur = schema->attributes; cur; cur = cur->next) {
-               if (cur->attributeID_id != id) continue;
-
-               return cur;
-       }
-
-       return NULL;
+       BINARY_ARRAY_SEARCH(schema->attributes_by_attributeID_id, 
+                           schema->num_attributes, attributeID_id, id, uint32_cmp, c);
+       return c;
 }
 
 const struct dsdb_attribute *dsdb_attribute_by_attributeID_oid(const struct dsdb_schema *schema,
                                                               const char *oid)
 {
-       struct dsdb_attribute *cur;
+       struct dsdb_attribute *c;
 
        if (!oid) return NULL;
 
-       /* TODO: add binary search */
-       for (cur = schema->attributes; cur; cur = cur->next) {
-               if (strcmp(cur->attributeID_oid, oid) != 0) continue;
-
-               return cur;
-       }
-
-       return NULL;
+       BINARY_ARRAY_SEARCH(schema->attributes_by_attributeID_oid, 
+                           schema->num_attributes, attributeID_oid, oid, strcasecmp, c);
+       return c;
 }
 
 const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName(const struct dsdb_schema *schema,
                                                               const char *name)
 {
-       struct dsdb_attribute *cur;
+       struct dsdb_attribute *c;
 
        if (!name) return NULL;
 
-       /* TODO: add binary search */
-       for (cur = schema->attributes; cur; cur = cur->next) {
-               if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue;
-
-               return cur;
-       }
-
-       return NULL;
+       BINARY_ARRAY_SEARCH(schema->attributes_by_lDAPDisplayName, 
+                           schema->num_attributes, lDAPDisplayName, name, strcasecmp, c);
+       return c;
 }
 
 const struct dsdb_attribute *dsdb_attribute_by_linkID(const struct dsdb_schema *schema,
                                                      int linkID)
 {
-       struct dsdb_attribute *cur;
-
-       /* TODO: add binary search */
-       for (cur = schema->attributes; cur; cur = cur->next) {
-               if (cur->linkID != linkID) continue;
+       struct dsdb_attribute *c;
 
-               return cur;
-       }
-
-       return NULL;
+       BINARY_ARRAY_SEARCH(schema->attributes_by_linkID, 
+                           schema->num_attributes, linkID, linkID, uint32_cmp, c);
+       return c;
 }
 
 const struct dsdb_class *dsdb_class_by_governsID_id(const struct dsdb_schema *schema,
                                                    uint32_t id)
 {
-       struct dsdb_class *cur;
+       struct dsdb_class *c;
 
        /*
         * 0xFFFFFFFF is used as value when no mapping table is available,
@@ -104,65 +118,39 @@ const struct dsdb_class *dsdb_class_by_governsID_id(const struct dsdb_schema *sc
         */
        if (id == 0xFFFFFFFF) return NULL;
 
-       /* TODO: add binary search */
-       for (cur = schema->classes; cur; cur = cur->next) {
-               if (cur->governsID_id != id) continue;
-
-               return cur;
-       }
-
-       return NULL;
+       BINARY_ARRAY_SEARCH(schema->classes_by_governsID_id, 
+                           schema->num_classes, governsID_id, id, uint32_cmp, c);
+       return c;
 }
 
 const struct dsdb_class *dsdb_class_by_governsID_oid(const struct dsdb_schema *schema,
                                                     const char *oid)
 {
-       struct dsdb_class *cur;
-
+       struct dsdb_class *c;
        if (!oid) return NULL;
-
-       /* TODO: add binary search */
-       for (cur = schema->classes; cur; cur = cur->next) {
-               if (strcmp(cur->governsID_oid, oid) != 0) continue;
-
-               return cur;
-       }
-
-       return NULL;
+       BINARY_ARRAY_SEARCH(schema->classes_by_governsID_oid, 
+                           schema->num_classes, governsID_oid, oid, strcasecmp, c);
+       return c;
 }
 
 const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema *schema,
                                                       const char *name)
 {
-       struct dsdb_class *cur;
-
+       struct dsdb_class *c;
        if (!name) return NULL;
-
-       /* TODO: add binary search */
-       for (cur = schema->classes; cur; cur = cur->next) {
-               if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue;
-
-               return cur;
-       }
-
-       return NULL;
+       BINARY_ARRAY_SEARCH(schema->classes_by_lDAPDisplayName, 
+                           schema->num_classes, lDAPDisplayName, name, strcasecmp, c);
+       return c;
 }
 
 const struct dsdb_class *dsdb_class_by_cn(const struct dsdb_schema *schema,
                                          const char *cn)
 {
-       struct dsdb_class *cur;
-
+       struct dsdb_class *c;
        if (!cn) return NULL;
-
-       /* TODO: add binary search */
-       for (cur = schema->classes; cur; cur = cur->next) {
-               if (strcasecmp(cur->cn, cn) != 0) continue;
-
-               return cur;
-       }
-
-       return NULL;
+       BINARY_ARRAY_SEARCH(schema->classes_by_cn, 
+                           schema->num_classes, cn, cn, strcasecmp, c);
+       return c;
 }
 
 const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
@@ -171,7 +159,6 @@ const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
        const struct dsdb_attribute *a;
        const struct dsdb_class *c;
 
-       /* TODO: add binary search */
        a = dsdb_attribute_by_attributeID_id(schema, id);
        if (a) {
                return a->lDAPDisplayName;
index d52976958d2c89c4dcfae1a4b6467457ad2c4ae7..9f23088c977819c80585e66ad7a41dba6faed72b 100644 (file)
 #include "lib/ldb/include/ldb_module.h"
 #include "param/param.h"
 
+/*
+  override the name to attribute handler function
+ */
+const struct ldb_schema_attribute *dsdb_attribute_handler_override(struct ldb_context *ldb, 
+                                                                  void *private_data,
+                                                                  const char *name)
+{
+       struct dsdb_schema *schema = talloc_get_type_abort(private_data, struct dsdb_schema);
+       const struct dsdb_attribute *a = dsdb_attribute_by_lDAPDisplayName(schema, name);
+       if (a == NULL) {
+               /* this will fall back to ldb internal handling */
+               return NULL;
+       }
+       return a->ldb_schema_attribute;
+}
 
 static int dsdb_schema_set_attributes(struct ldb_context *ldb, struct dsdb_schema *schema, bool write_attributes)
 {
@@ -34,11 +49,19 @@ static int dsdb_schema_set_attributes(struct ldb_context *ldb, struct dsdb_schem
        struct ldb_result *res_idx;
        struct dsdb_attribute *attr;
        struct ldb_message *mod_msg;
-       TALLOC_CTX *mem_ctx = talloc_new(ldb);
-       
+       TALLOC_CTX *mem_ctx;
        struct ldb_message *msg;
        struct ldb_message *msg_idx;
 
+       /* setup our own attribute name to schema handler */
+       ldb_schema_attribute_set_override_handler(ldb, dsdb_attribute_handler_override, schema);
+
+       if (!write_attributes) {
+               talloc_free(mem_ctx);
+               return ret;
+       }
+
+       mem_ctx = talloc_new(ldb);
        if (!mem_ctx) {
                return LDB_ERR_OPERATIONS_ERROR;
        }
@@ -46,27 +69,27 @@ static int dsdb_schema_set_attributes(struct ldb_context *ldb, struct dsdb_schem
        msg = ldb_msg_new(mem_ctx);
        if (!msg) {
                ldb_oom(ldb);
-               return LDB_ERR_OPERATIONS_ERROR;
+               goto op_error;
        }
        msg_idx = ldb_msg_new(mem_ctx);
        if (!msg_idx) {
                ldb_oom(ldb);
-               return LDB_ERR_OPERATIONS_ERROR;
+               goto op_error;
        }
        msg->dn = ldb_dn_new(msg, ldb, "@ATTRIBUTES");
        if (!msg->dn) {
                ldb_oom(ldb);
-               return LDB_ERR_OPERATIONS_ERROR;
+               goto op_error;
        }
        msg_idx->dn = ldb_dn_new(msg, ldb, "@INDEXLIST");
        if (!msg_idx->dn) {
                ldb_oom(ldb);
-               return LDB_ERR_OPERATIONS_ERROR;
+               goto op_error;
        }
 
        for (attr = schema->attributes; attr; attr = attr->next) {
-               const struct ldb_schema_syntax *s;
                const char *syntax = attr->syntax->ldb_syntax;
+               
                if (!syntax) {
                        syntax = attr->syntax->ldap_oid;
                }
@@ -87,33 +110,13 @@ static int dsdb_schema_set_attributes(struct ldb_context *ldb, struct dsdb_schem
                                break;
                        }
                }
-
-               if (!attr->syntax) {
-                       continue;
-               }
-
-               ret = ldb_schema_attribute_add(ldb, attr->lDAPDisplayName, LDB_ATTR_FLAG_FIXED,
-                                              syntax);
-               if (ret != LDB_SUCCESS) {
-                       s = ldb_samba_syntax_by_name(ldb, attr->syntax->ldap_oid);
-                       if (s) {
-                               ret = ldb_schema_attribute_add_with_syntax(ldb, attr->lDAPDisplayName, LDB_ATTR_FLAG_FIXED, s);
-                       } else {
-                               ret = LDB_SUCCESS; /* Nothing to do here */
-                       }
-               }
-               
-               if (ret != LDB_SUCCESS) {
-                       break;
-               }
        }
 
-       if (!write_attributes || ret != LDB_SUCCESS) {
+       if (ret != LDB_SUCCESS) {
                talloc_free(mem_ctx);
                return ret;
        }
 
-
        /* Try to avoid churning the attributes too much - we only want to do this if they have changed */
        ret = ldb_search(ldb, mem_ctx, &res, msg->dn, LDB_SCOPE_BASE, NULL, "dn=%s", ldb_dn_get_linearized(msg->dn));
        if (ret == LDB_ERR_NO_SUCH_OBJECT) {
@@ -165,6 +168,146 @@ static int dsdb_schema_set_attributes(struct ldb_context *ldb, struct dsdb_schem
        }
        talloc_free(mem_ctx);
        return ret;
+
+op_error:
+       talloc_free(mem_ctx);
+       return LDB_ERR_OPERATIONS_ERROR;
+}
+
+static int dsdb_compare_class_by_lDAPDisplayName(struct dsdb_class **c1, struct dsdb_class **c2)
+{
+       return strcasecmp((*c1)->lDAPDisplayName, (*c2)->lDAPDisplayName);
+}
+static int dsdb_compare_class_by_governsID_id(struct dsdb_class **c1, struct dsdb_class **c2)
+{
+       return (*c1)->governsID_id - (*c2)->governsID_id;
+}
+static int dsdb_compare_class_by_governsID_oid(struct dsdb_class **c1, struct dsdb_class **c2)
+{
+       return strcasecmp((*c1)->governsID_oid, (*c2)->governsID_oid);
+}
+static int dsdb_compare_class_by_cn(struct dsdb_class **c1, struct dsdb_class **c2)
+{
+       return strcasecmp((*c1)->cn, (*c2)->cn);
+}
+
+static int dsdb_compare_attribute_by_lDAPDisplayName(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
+{
+       return strcasecmp((*a1)->lDAPDisplayName, (*a2)->lDAPDisplayName);
+}
+static int dsdb_compare_attribute_by_attributeID_id(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
+{
+       return (*a1)->attributeID_id - (*a2)->attributeID_id;
+}
+static int dsdb_compare_attribute_by_attributeID_oid(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
+{
+       return strcasecmp((*a1)->attributeID_oid, (*a2)->attributeID_oid);
+}
+static int dsdb_compare_attribute_by_linkID(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
+{
+       return (*a1)->linkID - (*a2)->linkID;
+}
+
+/*
+  create the sorted accessor arrays for the schema
+ */
+static int dsdb_setup_sorted_accessors(struct ldb_context *ldb,
+                                      struct dsdb_schema *schema)
+{
+       struct dsdb_class *cur;
+       struct dsdb_attribute *a;
+       uint32_t i;
+
+       talloc_free(schema->classes_by_lDAPDisplayName);
+       talloc_free(schema->classes_by_governsID_id);
+       talloc_free(schema->classes_by_governsID_oid);
+       talloc_free(schema->classes_by_cn);
+
+       /* count the classes */
+       for (i=0, cur=schema->classes; cur; i++, cur=cur->next) /* noop */ ;
+       schema->num_classes = i;
+
+       /* setup classes_by_* */
+       schema->classes_by_lDAPDisplayName = talloc_array(schema, struct dsdb_class *, i);
+       schema->classes_by_governsID_id    = talloc_array(schema, struct dsdb_class *, i);
+       schema->classes_by_governsID_oid   = talloc_array(schema, struct dsdb_class *, i);
+       schema->classes_by_cn              = talloc_array(schema, struct dsdb_class *, i);
+       if (schema->classes_by_lDAPDisplayName == NULL ||
+           schema->classes_by_governsID_id == NULL ||
+           schema->classes_by_governsID_oid == NULL ||
+           schema->classes_by_cn == NULL) {
+               goto failed;
+       }
+
+       for (i=0, cur=schema->classes; cur; i++, cur=cur->next) {
+               schema->classes_by_lDAPDisplayName[i] = cur;
+               schema->classes_by_governsID_id[i]    = cur;
+               schema->classes_by_governsID_oid[i]   = cur;
+               schema->classes_by_cn[i]              = cur;
+       }
+
+       /* sort the arrays */
+       qsort(schema->classes_by_lDAPDisplayName, schema->num_classes, 
+             sizeof(struct dsdb_class *), QSORT_CAST dsdb_compare_class_by_lDAPDisplayName);
+       qsort(schema->classes_by_governsID_id, schema->num_classes, 
+             sizeof(struct dsdb_class *), QSORT_CAST dsdb_compare_class_by_governsID_id);
+       qsort(schema->classes_by_governsID_oid, schema->num_classes, 
+             sizeof(struct dsdb_class *), QSORT_CAST dsdb_compare_class_by_governsID_oid);
+       qsort(schema->classes_by_cn, schema->num_classes, 
+             sizeof(struct dsdb_class *), QSORT_CAST dsdb_compare_class_by_cn);
+
+       /* now build the attribute accessor arrays */
+       talloc_free(schema->attributes_by_lDAPDisplayName);
+       talloc_free(schema->attributes_by_attributeID_id);
+       talloc_free(schema->attributes_by_attributeID_oid);
+       talloc_free(schema->attributes_by_linkID);
+
+       /* count the attributes */
+       for (i=0, a=schema->attributes; a; i++, a=a->next) /* noop */ ;
+       schema->num_attributes = i;
+
+       /* setup attributes_by_* */
+       schema->attributes_by_lDAPDisplayName = talloc_array(schema, struct dsdb_attribute *, i);
+       schema->attributes_by_attributeID_id    = talloc_array(schema, struct dsdb_attribute *, i);
+       schema->attributes_by_attributeID_oid   = talloc_array(schema, struct dsdb_attribute *, i);
+       schema->attributes_by_linkID              = talloc_array(schema, struct dsdb_attribute *, i);
+       if (schema->attributes_by_lDAPDisplayName == NULL ||
+           schema->attributes_by_attributeID_id == NULL ||
+           schema->attributes_by_attributeID_oid == NULL ||
+           schema->attributes_by_linkID == NULL) {
+               goto failed;
+       }
+
+       for (i=0, a=schema->attributes; a; i++, a=a->next) {
+               schema->attributes_by_lDAPDisplayName[i] = a;
+               schema->attributes_by_attributeID_id[i]    = a;
+               schema->attributes_by_attributeID_oid[i]   = a;
+               schema->attributes_by_linkID[i]          = a;
+       }
+
+       /* sort the arrays */
+       qsort(schema->attributes_by_lDAPDisplayName, schema->num_attributes, 
+             sizeof(struct dsdb_attribute *), QSORT_CAST dsdb_compare_attribute_by_lDAPDisplayName);
+       qsort(schema->attributes_by_attributeID_id, schema->num_attributes, 
+             sizeof(struct dsdb_attribute *), QSORT_CAST dsdb_compare_attribute_by_attributeID_id);
+       qsort(schema->attributes_by_attributeID_oid, schema->num_attributes, 
+             sizeof(struct dsdb_attribute *), QSORT_CAST dsdb_compare_attribute_by_attributeID_oid);
+       qsort(schema->attributes_by_linkID, schema->num_attributes, 
+             sizeof(struct dsdb_attribute *), QSORT_CAST dsdb_compare_attribute_by_linkID);
+
+       return LDB_SUCCESS;
+
+failed:
+       schema->classes_by_lDAPDisplayName = NULL;
+       schema->classes_by_governsID_id = NULL;
+       schema->classes_by_governsID_oid = NULL;
+       schema->classes_by_cn = NULL;
+       schema->attributes_by_lDAPDisplayName = NULL;
+       schema->attributes_by_attributeID_id = NULL;
+       schema->attributes_by_attributeID_oid = NULL;
+       schema->attributes_by_linkID = NULL;
+       ldb_oom(ldb);
+       return LDB_ERR_OPERATIONS_ERROR;
 }
 
 
@@ -177,6 +320,11 @@ int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
 {
        int ret;
 
+       ret = dsdb_setup_sorted_accessors(ldb, schema);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
        ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
        if (ret != LDB_SUCCESS) {
                return ret;
@@ -207,6 +355,7 @@ int dsdb_set_global_schema(struct ldb_context *ldb)
        if (!global_schema) {
                return LDB_SUCCESS;
        }
+
        ret = ldb_set_opaque(ldb, "dsdb_schema", global_schema);
        if (ret != LDB_SUCCESS) {
                return ret;
@@ -367,7 +516,7 @@ WERROR dsdb_attach_schema_from_ldif(struct ldb_context *ldb, const char *pf, con
                                goto nomem;
                        }
 
-                       status = dsdb_attribute_from_ldb(schema, msg, sa, sa);
+                       status = dsdb_attribute_from_ldb(ldb, schema, msg, sa, sa);
                        if (!W_ERROR_IS_OK(status)) {
                                goto failed;
                        }
index 27c9a6c4a4c06aa6462b92b471e400eed5acc7db..4fd6501cc8bc238461bbfab844f32660f931aec4 100644 (file)
@@ -1227,7 +1227,7 @@ static WERROR dsdb_syntax_PRESENTATION_ADDRESS_ldb_to_drsuapi(struct ldb_context
 static const struct dsdb_syntax dsdb_syntaxes[] = {
        {
                .name                   = "Boolean",
-               .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.7",
+               .ldap_oid               = LDB_SYNTAX_BOOLEAN,
                .oMSyntax               = 1,
                .attributeSyntax_oid    = "2.5.5.8",
                .drsuapi_to_ldb         = dsdb_syntax_BOOL_drsuapi_to_ldb,
@@ -1289,7 +1289,8 @@ static const struct dsdb_syntax dsdb_syntaxes[] = {
                .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
                .equality               = "numericStringMatch",
                .substring              = "numericStringSubstringsMatch",
-               .comment                = "Numeric String" 
+               .comment                = "Numeric String",
+               .ldb_syntax             = LDB_SYNTAX_DIRECTORY_STRING,
        },{
                .name                   = "String(Printable)",
                .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.44",
@@ -1297,6 +1298,7 @@ static const struct dsdb_syntax dsdb_syntaxes[] = {
                .attributeSyntax_oid    = "2.5.5.5",
                .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
                .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
+               .ldb_syntax             = LDB_SYNTAX_OCTET_STRING,
        },{
                .name                   = "String(Teletex)",
                .ldap_oid               = "1.2.840.113556.1.4.905",
@@ -1316,7 +1318,8 @@ static const struct dsdb_syntax dsdb_syntaxes[] = {
                .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
                .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
                .equality               = "caseExactIA5Match",
-               .comment                = "Printable String"
+               .comment                = "Printable String",
+               .ldb_syntax             = LDB_SYNTAX_OCTET_STRING,
        },{
                .name                   = "String(UTC-Time)",
                .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.53",
@@ -1423,7 +1426,8 @@ static const struct dsdb_syntax dsdb_syntaxes[] = {
                .attributeSyntax_oid    = "2.5.5.13",
                .drsuapi_to_ldb         = dsdb_syntax_PRESENTATION_ADDRESS_drsuapi_to_ldb,
                .ldb_to_drsuapi         = dsdb_syntax_PRESENTATION_ADDRESS_ldb_to_drsuapi,
-               .comment                = "Presentation Address" 
+               .comment                = "Presentation Address",
+               .ldb_syntax             = LDB_SYNTAX_DIRECTORY_STRING,
        },{
        /* not used in w2k3 schema */
                .name                   = "Object(Access-Point)",
@@ -1433,6 +1437,7 @@ static const struct dsdb_syntax dsdb_syntaxes[] = {
                .attributeSyntax_oid    = "2.5.5.14",
                .drsuapi_to_ldb         = dsdb_syntax_FOOBAR_drsuapi_to_ldb,
                .ldb_to_drsuapi         = dsdb_syntax_FOOBAR_ldb_to_drsuapi,
+               .ldb_syntax             = LDB_SYNTAX_DIRECTORY_STRING,
        },{
        /* not used in w2k3 schema */
                .name                   = "Object(DN-String)",
index fc87e6ca7a82daa7a5dac319cc7a7fb5e4481c67..d895f097576066bd55fef41cd6c4c1f543ceae1f 100644 (file)
@@ -729,6 +729,20 @@ const struct ldb_schema_syntax *ldb_samba_syntax_by_name(struct ldb_context *ldb
        return s;
 }
 
+const struct ldb_schema_syntax *ldb_samba_syntax_by_lDAPDisplayName(struct ldb_context *ldb, const char *name)
+{
+       uint32_t j;
+       const struct ldb_schema_syntax *s = NULL;
+
+       for (j=0; j < ARRAY_SIZE(samba_attributes); j++) {
+               if (strcmp(samba_attributes[j].name, name) == 0) {
+                       s = ldb_samba_syntax_by_name(ldb, samba_attributes[j].syntax);
+                       break;
+               }
+       }
+       
+       return s;
+}
 
 /*
   register the samba ldif handlers
index 80725ec04f9c5966a08964ac5e641b403c4ba2c9..4869e3289c88e6f082d057565454ef0d0be192ad 100644 (file)
@@ -105,7 +105,7 @@ int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
   canonicalise a ldap Integer
   rfc2252 specifies it should be in decimal form
 */
-int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
+static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
                                    const struct ldb_val *in, struct ldb_val *out)
 {
        char *end;
@@ -124,12 +124,44 @@ int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
 /*
   compare two Integers
 */
-int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
+static int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
                                  const struct ldb_val *v1, const struct ldb_val *v2)
 {
        return strtoll((char *)v1->data, NULL, 0) - strtoll((char *)v2->data, NULL, 0);
 }
 
+/*
+  canonicalise a ldap Boolean
+  rfc2252 specifies it should be either "TRUE" or "FALSE"
+*/
+static int ldb_canonicalise_Boolean(struct ldb_context *ldb, void *mem_ctx,
+                            const struct ldb_val *in, struct ldb_val *out)
+{
+       if (strncasecmp((char *)in->data, "TRUE", in->length) == 0) {
+               out->data = (uint8_t *)talloc_strdup(mem_ctx, "TRUE");
+               out->length = 4;
+       } else if (strncasecmp((char *)in->data, "FALSE", in->length) == 0) {
+               out->data = (uint8_t *)talloc_strdup(mem_ctx, "FALSE");
+               out->length = 4;
+       } else {
+               return -1;
+       }
+       return 0;
+}
+
+/*
+  compare two Booleans
+*/
+static int ldb_comparison_Boolean(struct ldb_context *ldb, void *mem_ctx,
+                          const struct ldb_val *v1, const struct ldb_val *v2)
+{
+       if (v1->length != v2->length) {
+               return v1->length - v2->length;
+       }
+       return strncasecmp((char *)v1->data, (char *)v2->data, v1->length);
+}
+
+
 /*
   compare two binary blobs
 */
@@ -231,7 +263,7 @@ utf8str:
 /*
   canonicalise a attribute in DN format
 */
-int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
+static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
                               const struct ldb_val *in, struct ldb_val *out)
 {
        struct ldb_dn *dn;
@@ -262,7 +294,7 @@ done:
 /*
   compare two dns
 */
-int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
+static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
                             const struct ldb_val *v1, const struct ldb_val *v2)
 {
        struct ldb_dn *dn1 = NULL, *dn2 = NULL;
@@ -287,7 +319,7 @@ int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
 /*
   compare two utc time values. 1 second resolution
 */
-int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
+static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
                                  const struct ldb_val *v1, const struct ldb_val *v2)
 {
        time_t t1, t2;
@@ -299,7 +331,7 @@ int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
 /*
   canonicalise a utc time
 */
-int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
+static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
                                    const struct ldb_val *in, struct ldb_val *out)
 {
        time_t t = ldb_string_to_time((char *)in->data);
@@ -356,7 +388,14 @@ static const struct ldb_schema_syntax ldb_standard_syntaxes[] = {
                .ldif_write_fn   = ldb_handler_copy,
                .canonicalise_fn = ldb_canonicalise_utctime,
                .comparison_fn   = ldb_comparison_utctime
-       }
+       },
+       { 
+               .name            = LDB_SYNTAX_BOOLEAN,
+               .ldif_read_fn    = ldb_handler_copy,
+               .ldif_write_fn   = ldb_handler_copy,
+               .canonicalise_fn = ldb_canonicalise_Boolean,
+               .comparison_fn   = ldb_comparison_Boolean
+       },
 };
 
 
index 9fa0fb2ccd3f2ee68cd27954fa66b062788b7201..cf45e8ef28a5af152730fc08930713d2157a7668 100644 (file)
@@ -124,6 +124,16 @@ const struct ldb_schema_attribute *ldb_schema_attribute_by_name(struct ldb_conte
        int i, e, b = 0, r;
        const struct ldb_schema_attribute *def = &ldb_attribute_default;
 
+       if (ldb->schema.attribute_handler_override) {
+               const struct ldb_schema_attribute *ret = 
+                       ldb->schema.attribute_handler_override(ldb, 
+                                                              ldb->schema.attribute_handler_override_private,
+                                                              name);
+               if (ret) {
+                       return ret;
+               }
+       }
+
        /* as handlers are sorted, '*' must be the first if present */
        if (strcmp(ldb->schema.attributes[0].name, "*") == 0) {
                def = &ldb->schema.attributes[0];
@@ -273,3 +283,14 @@ const struct ldb_dn_extended_syntax *ldb_dn_extended_syntax_by_name(struct ldb_c
        return NULL;
 }
 
+/*
+  set an attribute handler override function - used to delegate schema handling
+  to external code
+ */
+void ldb_schema_attribute_set_override_handler(struct ldb_context *ldb,
+                                              ldb_attribute_handler_override_fn_t override,
+                                              void *private_data)
+{
+       ldb->schema.attribute_handler_override_private = private_data;
+       ldb->schema.attribute_handler_override = override;
+}
index b98cc885371cdd33d638c13c11ddceb18e0a9a78..3e1a96018bab051c847aad8cb8c8ee8525df4e7e 100644 (file)
@@ -11,7 +11,7 @@ AC_DEFUN([SMB_MODULE_DEFAULT], [echo -n ""])
 AC_DEFUN([SMB_LIBRARY_ENABLE], [echo -n ""])
 AC_DEFUN([SMB_EXT_LIB], [echo -n ""])
 AC_DEFUN([SMB_ENABLE], [echo -n ""])
-AC_INIT(ldb, 0.9.4)
+AC_INIT(ldb, 0.9.5)
 AC_CONFIG_SRCDIR([common/ldb.c])
 
 AC_LIBREPLACE_ALL_CHECKS
index be41151409a73813e3635f186c9bb6cdfc1d0eb2..1b6b41aa434551f9d068972e704aa1807525d4fc 100644 (file)
@@ -402,6 +402,15 @@ const struct ldb_dn_extended_syntax *ldb_dn_extended_syntax_by_name(struct ldb_c
 */
 #define LDB_SYNTAX_INTEGER              "1.3.6.1.4.1.1466.115.121.1.27"
 
+/**
+  LDAP attribute syntax for a boolean
+
+  This is the well-known LDAP attribute syntax for a boolean.
+
+  See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2 
+*/
+#define LDB_SYNTAX_BOOLEAN              "1.3.6.1.4.1.1466.115.121.1.7"
+
 /**
   LDAP attribute syntax for an octet string
 
index e1c14e679b9c073f94680f5e6b90a5542d2c4cbf..21fbcc33f880bcd38d76c592a5065220d28ee805 100644 (file)
  *  Author: Simo Sorce
  */
 
-
 int ldb_handler_copy(          struct ldb_context *ldb, void *mem_ctx,
                                const struct ldb_val *in, struct ldb_val *out);
-
-int ldb_handler_fold(          struct ldb_context *ldb, void *mem_ctx,
-                               const struct ldb_val *in, struct ldb_val *out);
-
-int ldb_canonicalise_Integer(  struct ldb_context *ldb, void *mem_ctx,
-                               const struct ldb_val *in, struct ldb_val *out);
-
-int ldb_comparison_Integer(    struct ldb_context *ldb, void *mem_ctx,
-                               const struct ldb_val *v1, const struct ldb_val *v2);
-
 int ldb_comparison_binary(     struct ldb_context *ldb, void *mem_ctx,
                                const struct ldb_val *v1, const struct ldb_val *v2);
-
-int ldb_comparison_fold(       struct ldb_context *ldb, void *mem_ctx,
-                               const struct ldb_val *v1, const struct ldb_val *v2);
-
-int ldb_canonicalise_dn(       struct ldb_context *ldb, void *mem_ctx,
+int db_handler_fold(           struct ldb_context *ldb, void *mem_ctx,
                                const struct ldb_val *in, struct ldb_val *out);
-
-int ldb_comparison_dn(         struct ldb_context *ldb, void *mem_ctx,
-                               const struct ldb_val *v1, const struct ldb_val *v2);
-
-int ldb_comparison_objectclass(        struct ldb_context *ldb, void *mem_ctx,
-                               const struct ldb_val *v1, const struct ldb_val *v2);
-
-int ldb_comparison_utctime(    struct ldb_context *ldb, void *mem_ctx,
+int ldb_comparison_fold(       struct ldb_context *ldb, void *mem_ctx,
                                const struct ldb_val *v1, const struct ldb_val *v2);
 
-int ldb_canonicalise_utctime(  struct ldb_context *ldb, void *mem_ctx,
-                               const struct ldb_val *in, struct ldb_val *out);
-
index e07fd43e27199ec89db2485190f4b3213ecda751..d9950d664984ffb1cc61507b045f44fd30e8965c 100644 (file)
@@ -89,6 +89,13 @@ int ldb_schema_attribute_add(struct ldb_context *ldb,
                             const char *syntax);
 void ldb_schema_attribute_remove(struct ldb_context *ldb, const char *name);
 
+/* we allow external code to override the name -> schema_attribute function */
+typedef const struct ldb_schema_attribute *(*ldb_attribute_handler_override_fn_t)(struct ldb_context *, void *, const char *);
+
+void ldb_schema_attribute_set_override_handler(struct ldb_context *ldb,
+                                              ldb_attribute_handler_override_fn_t override,
+                                              void *private_data);
+
 /* The following definitions come from lib/ldb/common/ldb_controls.c  */
 struct ldb_control *get_control_from_list(struct ldb_control **controls, const char *oid);
 int save_controls(struct ldb_control *exclude, struct ldb_request *req, struct ldb_control ***saver);
index 2e8da9941ca8e38a713969216f9b81bc5d51f6c9..6946ca21820f92715d1a08e1e484503dabc30aa9 100644 (file)
@@ -65,6 +65,9 @@ struct ldb_module {
   schema related information needed for matching rules
 */
 struct ldb_schema {
+       void *attribute_handler_override_private;
+       ldb_attribute_handler_override_fn_t attribute_handler_override;
+       
        /* attribute handling table */
        unsigned num_attributes;
        struct ldb_schema_attribute *attributes;
index 4140de068601322fbfdb13c462f08aae787880ae..bd88b8ec81a313d5bfb280a6198358161b4c6855 100644 (file)
@@ -243,7 +243,7 @@ static NTSTATUS vampire_apply_schema(struct vampire_state *s,
                        sa = talloc_zero(s->self_made_schema, struct dsdb_attribute);
                        NT_STATUS_HAVE_NO_MEMORY(sa);
 
-                       status = dsdb_attribute_from_drsuapi(s->self_made_schema, &cur->object, s, sa);
+                       status = dsdb_attribute_from_drsuapi(s->ldb, s->self_made_schema, &cur->object, s, sa);
                        if (!W_ERROR_IS_OK(status)) {
                                return werror_to_ntstatus(status);
                        }
index 0469fb827a5561f08054655afe8aeb4d1d5d857a..76bc1fe8671cedd40615c235a9ea4661a3ee6af8 100644 (file)
@@ -2,5 +2,5 @@
 # if we use the ones installed in the system.
 define(TDB_MIN_VERSION,1.1.4)
 define(TALLOC_MIN_VERSION,1.3.0)
-define(LDB_REQUIRED_VERSION,0.9.4)
+define(LDB_REQUIRED_VERSION,0.9.5)
 define(TEVENT_REQUIRED_VERSION,0.9.5)
index 6184ad266d61596ad70ff2217f20f5908081c59b..7ea7b39d5cdeafd0edafbdf7a409c75d057cbf5d 100644 (file)
@@ -223,7 +223,7 @@ static int test_add_attribute(void *ptr, struct ldb_context *ldb, struct ldb_mes
                goto failed;
        }
 
-       status = dsdb_attribute_from_ldb(schema, msg, attr, attr);
+       status = dsdb_attribute_from_ldb(ldb, schema, msg, attr, attr);
        if (!W_ERROR_IS_OK(status)) {
                goto failed;
        }
index 2b1bff40ee64efedeb50882676f82a613f8ed8c4..7d1c025f18833aeff72e18954d91d4ffd2e99399 100644 (file)
@@ -231,7 +231,7 @@ static NTSTATUS test_apply_schema(struct test_become_dc_state *s,
                        sa = talloc_zero(s->self_made_schema, struct dsdb_attribute);
                        NT_STATUS_HAVE_NO_MEMORY(sa);
 
-                       status = dsdb_attribute_from_drsuapi(s->self_made_schema, &cur->object, s, sa);
+                       status = dsdb_attribute_from_drsuapi(s->ldb, s->self_made_schema, &cur->object, s, sa);
                        if (!W_ERROR_IS_OK(status)) {
                                return werror_to_ntstatus(status);
                        }