From: Andrew Tridgell Date: Thu, 2 Apr 2009 05:42:21 +0000 (+1100) Subject: major upgrade to the ldb attribute handling X-Git-Tag: tdb-1.1.5~1031^2~18^2~20 X-Git-Url: http://git.samba.org/samba.git/?a=commitdiff_plain;h=9539e2b508b3340b49575e5022c365ec382b2097;p=samba.git major upgrade to the ldb attribute handling 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. --- diff --git a/source4/dsdb/schema/schema.h b/source4/dsdb/schema/schema.h index f7d59a7c393..98ccf5ed9e1 100644 --- a/source4/dsdb/schema/schema.h +++ b/source4/dsdb/schema/schema.h @@ -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; diff --git a/source4/dsdb/schema/schema_init.c b/source4/dsdb/schema/schema_init.c index e619e1fface..3a65c474fb7 100644 --- a/source4/dsdb/schema/schema_init.c +++ b/source4/dsdb/schema/schema_init.c @@ -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; } diff --git a/source4/dsdb/schema/schema_query.c b/source4/dsdb/schema/schema_query.c index 00de0f89834..f894ef5b1e5 100644 --- a/source4/dsdb/schema/schema_query.c +++ b/source4/dsdb/schema/schema_query.c @@ -23,10 +23,44 @@ #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; diff --git a/source4/dsdb/schema/schema_set.c b/source4/dsdb/schema/schema_set.c index d52976958d2..9f23088c977 100644 --- a/source4/dsdb/schema/schema_set.c +++ b/source4/dsdb/schema/schema_set.c @@ -26,6 +26,21 @@ #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; } diff --git a/source4/dsdb/schema/schema_syntax.c b/source4/dsdb/schema/schema_syntax.c index 27c9a6c4a4c..4fd6501cc8b 100644 --- a/source4/dsdb/schema/schema_syntax.c +++ b/source4/dsdb/schema/schema_syntax.c @@ -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)", diff --git a/source4/lib/ldb-samba/ldif_handlers.c b/source4/lib/ldb-samba/ldif_handlers.c index fc87e6ca7a8..d895f097576 100644 --- a/source4/lib/ldb-samba/ldif_handlers.c +++ b/source4/lib/ldb-samba/ldif_handlers.c @@ -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 diff --git a/source4/lib/ldb/common/attrib_handlers.c b/source4/lib/ldb/common/attrib_handlers.c index 80725ec04f9..4869e3289c8 100644 --- a/source4/lib/ldb/common/attrib_handlers.c +++ b/source4/lib/ldb/common/attrib_handlers.c @@ -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 + }, }; diff --git a/source4/lib/ldb/common/ldb_attributes.c b/source4/lib/ldb/common/ldb_attributes.c index 9fa0fb2ccd3..cf45e8ef28a 100644 --- a/source4/lib/ldb/common/ldb_attributes.c +++ b/source4/lib/ldb/common/ldb_attributes.c @@ -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; +} diff --git a/source4/lib/ldb/configure.ac b/source4/lib/ldb/configure.ac index b98cc885371..3e1a96018ba 100644 --- a/source4/lib/ldb/configure.ac +++ b/source4/lib/ldb/configure.ac @@ -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 diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h index be41151409a..1b6b41aa434 100644 --- a/source4/lib/ldb/include/ldb.h +++ b/source4/lib/ldb/include/ldb.h @@ -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 RFC 2252, 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 diff --git a/source4/lib/ldb/include/ldb_handlers.h b/source4/lib/ldb/include/ldb_handlers.h index e1c14e679b9..21fbcc33f88 100644 --- a/source4/lib/ldb/include/ldb_handlers.h +++ b/source4/lib/ldb/include/ldb_handlers.h @@ -31,37 +31,12 @@ * 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); - diff --git a/source4/lib/ldb/include/ldb_module.h b/source4/lib/ldb/include/ldb_module.h index e07fd43e271..d9950d66498 100644 --- a/source4/lib/ldb/include/ldb_module.h +++ b/source4/lib/ldb/include/ldb_module.h @@ -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); diff --git a/source4/lib/ldb/include/ldb_private.h b/source4/lib/ldb/include/ldb_private.h index 2e8da9941ca..6946ca21820 100644 --- a/source4/lib/ldb/include/ldb_private.h +++ b/source4/lib/ldb/include/ldb_private.h @@ -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; diff --git a/source4/libnet/libnet_vampire.c b/source4/libnet/libnet_vampire.c index 4140de06860..bd88b8ec81a 100644 --- a/source4/libnet/libnet_vampire.c +++ b/source4/libnet/libnet_vampire.c @@ -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); } diff --git a/source4/min_versions.m4 b/source4/min_versions.m4 index 0469fb827a5..76bc1fe8671 100644 --- a/source4/min_versions.m4 +++ b/source4/min_versions.m4 @@ -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) diff --git a/source4/torture/ldap/schema.c b/source4/torture/ldap/schema.c index 6184ad266d6..7ea7b39d5cd 100644 --- a/source4/torture/ldap/schema.c +++ b/source4/torture/ldap/schema.c @@ -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; } diff --git a/source4/torture/libnet/libnet_BecomeDC.c b/source4/torture/libnet/libnet_BecomeDC.c index 2b1bff40ee6..7d1c025f188 100644 --- a/source4/torture/libnet/libnet_BecomeDC.c +++ b/source4/torture/libnet/libnet_BecomeDC.c @@ -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); }