r23560: - Activate metze's schema modules (from metze's schema-loading-13 patch).
authorAndrew Bartlett <abartlet@samba.org>
Thu, 21 Jun 2007 10:18:20 +0000 (10:18 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 19:53:27 +0000 (14:53 -0500)
- samba3sam.js: rework the samba3sam test to not use objectCategory,
  as it's has special rules (dnsName a simple match)
- ldap.js: Test the ordering of the objectClass attributes for the baseDN
- schema_init.c: Load the mayContain and mustContain (and system...) attributes when
  reading the schema from ldb
- To make the schema load not suck in terms of performance, write the
  schema into a static global variable
- ldif_handlers.c: Match objectCategory for equality and canonicolisation
  based on the loaded schema, not simple tring manipuation
- ldb_msg.c: don't duplicate attributes when adding attributes to a list
- kludge_acl.c: return allowedAttributesEffective based on schema results
  and privilages

Andrew Bartlett
(This used to be commit dcff83ebe463bc7391841f55856d7915c204d000)

13 files changed:
source4/dsdb/samdb/ldb_modules/kludge_acl.c
source4/dsdb/samdb/ldb_modules/schema_fsmo.c
source4/dsdb/samdb/samdb.c
source4/dsdb/schema/schema_init.c
source4/lib/db_wrap.c
source4/lib/ldb/common/ldb_msg.c
source4/lib/ldb/samba/ldif_handlers.c
source4/scripting/libjs/provision.js
source4/setup/provision
source4/setup/provision_partitions.ldif
source4/setup/provision_schema_basedn_modify.ldif
testprogs/ejs/ldap.js
testprogs/ejs/samba3sam.js

index ff0dd062fbc271bef54bc174199481dcb7c947f3..6b043aeb406642137ca15edb2c522845c0f2531c 100644 (file)
@@ -37,6 +37,7 @@
 #include "ldb/include/ldb_private.h"
 #include "auth/auth.h"
 #include "libcli/security/security.h"
+#include "dsdb/samdb/samdb.h"
 
 /* Kludge ACL rules:
  *
@@ -105,13 +106,74 @@ struct kludge_acl_context {
        int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
 
        enum user_is user_type;
+       bool allowedAttributes;
+       bool allowedAttributesEffective;
+       const char **attrs;
 };
 
+/* read all objectClasses */
+
+static int kludge_acl_allowedAttributes(struct ldb_context *ldb, struct ldb_message *msg,
+                                                        const char *attrName) 
+{
+       struct ldb_message_element *oc_el = ldb_msg_find_element(msg, "objectClass");
+       struct ldb_message_element *allowedAttributes;
+       const struct dsdb_schema *schema = dsdb_get_schema(ldb);
+       const struct dsdb_class *class;
+       int i, j, ret;
+       ret = ldb_msg_add_empty(msg, attrName, 0, &allowedAttributes);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+       
+       for (i=0; i < oc_el->num_values; i++) {
+               class = dsdb_class_by_lDAPDisplayName(schema, (const char *)oc_el->values[i].data);
+               if (!class) {
+                       /* We don't know this class?  what is going on? */
+                       continue;
+               }
+               for (j=0; class->mayContain && class->mayContain[j]; j++) {
+                       ldb_msg_add_string(msg, attrName, class->mayContain[j]);
+               }
+               for (j=0; class->mustContain && class->mustContain[j]; j++) {
+                       ldb_msg_add_string(msg, attrName, class->mustContain[j]);
+               }
+               for (j=0; class->systemMayContain && class->systemMayContain[j]; j++) {
+                       ldb_msg_add_string(msg, attrName, class->systemMayContain[j]);
+               }
+               for (j=0; class->systemMustContain && class->systemMustContain[j]; j++) {
+                       ldb_msg_add_string(msg, attrName, class->systemMustContain[j]);
+               }
+       }
+               
+       if (allowedAttributes->num_values > 1) {
+               qsort(allowedAttributes->values, 
+                     allowedAttributes->num_values, 
+                     sizeof(*allowedAttributes->values),
+                     data_blob_cmp);
+       
+               for (i=1 ; i < allowedAttributes->num_values; i++) {
+                       struct ldb_val *val1 = &allowedAttributes->values[i-1];
+                       struct ldb_val *val2 = &allowedAttributes->values[i];
+                       if (data_blob_cmp(val1, val2) == 0) {
+                               memmove(val1, val2, (allowedAttributes->num_values - i) * sizeof( struct ldb_val)); 
+                               allowedAttributes->num_values--;
+                               i--;
+                       }
+               }
+       }
+
+       return 0;
+
+}
+
+/* find all attributes allowed by all these objectClasses */
+
 static int kludge_acl_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
 {
        struct kludge_acl_context *ac;
        struct kludge_private_data *data;
-       int i;
+       int i, ret;
 
        if (!context || !ares) {
                ldb_set_errstring(ldb, "NULL Context or Result in callback");
@@ -121,12 +183,28 @@ static int kludge_acl_callback(struct ldb_context *ldb, void *context, struct ld
        ac = talloc_get_type(context, struct kludge_acl_context);
        data = talloc_get_type(ac->module->private_data, struct kludge_private_data);
 
-       if (ares->type == LDB_REPLY_ENTRY
-           && data && data->password_attrs) /* if we are not initialized just get through */
+       if (ares->type != LDB_REPLY_ENTRY) {
+               return ac->up_callback(ldb, ac->up_context, ares);
+       }
+
+       if (ac->allowedAttributes) {
+               ret = kludge_acl_allowedAttributes(ldb, ares->message, "allowedAttributes");
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+       }
+
+       if (data && data->password_attrs) /* if we are not initialized just get through */
        {
                switch (ac->user_type) {
                case SYSTEM:
                case ADMINISTRATOR:
+                       if (ac->allowedAttributesEffective) {
+                               ret = kludge_acl_allowedAttributes(ldb, ares->message, "allowedAttributesEffective");
+                               if (ret != LDB_SUCCESS) {
+                                       return ret;
+                               }
+                       }
                        break;
                default:
                        /* remove password attributes */
@@ -136,6 +214,12 @@ static int kludge_acl_callback(struct ldb_context *ldb, void *context, struct ld
                }
        }
 
+       if ((ac->allowedAttributes || ac->allowedAttributesEffective) && 
+           (!ldb_attr_in_list(ac->attrs, "objectClass") && 
+            !ldb_attr_in_list(ac->attrs, "*"))) {
+               ldb_msg_remove_attr(ares->message, "objectClass");
+       }
+
        return ac->up_callback(ldb, ac->up_context, ares);
 
 error:
@@ -163,6 +247,7 @@ static int kludge_acl_search(struct ldb_module *module, struct ldb_request *req)
        ac->up_context = req->context;
        ac->up_callback = req->callback;
        ac->user_type = what_is_user(module);
+       ac->attrs = req->op.search.attrs;
 
        down_req = talloc_zero(req, struct ldb_request);
        if (down_req == NULL) {
@@ -174,7 +259,15 @@ static int kludge_acl_search(struct ldb_module *module, struct ldb_request *req)
        down_req->op.search.scope = req->op.search.scope;
        down_req->op.search.tree = req->op.search.tree;
        down_req->op.search.attrs = req->op.search.attrs;
-       
+
+       ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes");
+
+       ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective");
+
+       if (ac->allowedAttributes || ac->allowedAttributesEffective) {
+               down_req->op.search.attrs
+                       = ldb_attr_list_copy_add(down_req, down_req->op.search.attrs, "objectClass");
+       }
 
        /*  FIXME: I hink we should copy the tree and keep the original
         *  unmodified. SSS */
index eb5d7e8e8e552ae65a2fc03464a8ab5d88bdf3c5..3df887acb6337b651a4deb2240ba7ff8f2b560de 100644 (file)
@@ -54,6 +54,10 @@ static int schema_fsmo_init(struct ldb_module *module)
                NULL
        };
 
+       if (dsdb_get_schema(module->ldb)) {
+         return ldb_next_init(module);
+       }
+
        schema_dn = samdb_schema_dn(module->ldb);
        if (!schema_dn) {
                ldb_debug(module->ldb, LDB_DEBUG_WARNING,
index 2208bb933395c510d222162a95a5b90703346d15..2ae0fe25acd1e019fa56b345557b7605d2be8f88 100644 (file)
@@ -50,6 +50,7 @@ struct ldb_context *samdb_connect(TALLOC_CTX *mem_ctx,
        if (!ldb) {
                return NULL;
        }
+       dsdb_make_schema_global(ldb);
        return ldb;
 }
 
index b609478f94afa70e0bd15b61cc0bef069666c37c..c7a7b59754e3426c7f762440ee10870080a61976 100644 (file)
@@ -323,6 +323,34 @@ WERROR dsdb_map_int2oid(const struct dsdb_schema *schema, uint32_t in, TALLOC_CT
        talloc_steal(mem_ctx, (p)->elem); \
 } while (0)
 
+#define GET_STRING_LIST_LDB(msg, attr, mem_ctx, p, elem, strict) do {  \
+       int get_string_list_counter;                                    \
+       struct ldb_message_element *get_string_list_el = ldb_msg_find_element(msg, attr); \
+       if (get_string_list_el == NULL) {                               \
+               if (strict) {                                           \
+                       d_printf("%s: %s == NULL\n", __location__, attr); \
+                       return WERR_INVALID_PARAM;                      \
+               } else {                                                \
+                       (p)->elem = NULL;                               \
+                       break;                                          \
+               }                                                       \
+       }                                                               \
+       (p)->elem = talloc_array(mem_ctx, const char *, get_string_list_el->num_values + 1); \
+        for (get_string_list_counter=0;                                        \
+            get_string_list_counter < get_string_list_el->num_values;  \
+            get_string_list_counter++) {                               \
+               (p)->elem[get_string_list_counter] = talloc_strndup((p)->elem, \
+                                                                   (const char *)get_string_list_el->values[get_string_list_counter].data, \
+                                                                   get_string_list_el->values[get_string_list_counter].length); \
+               if (!(p)->elem[get_string_list_counter]) {              \
+                       d_printf("%s: talloc_strndup failed for %s\n", __location__, attr); \
+                       return WERR_NOMEM;                              \
+               }                                                       \
+               (p)->elem[get_string_list_counter+1] = NULL;            \
+       }                                                               \
+       talloc_steal(mem_ctx, (p)->elem);                               \
+} while (0)
+
 #define GET_BOOL_LDB(msg, attr, p, elem, strict) do { \
        const char *str; \
        str = samdb_result_string(msg, attr, NULL);\
@@ -466,13 +494,14 @@ WERROR dsdb_class_from_ldb(const struct dsdb_schema *schema,
 
        obj->systemAuxiliaryClass       = NULL;
        obj->systemPossSuperiors        = NULL;
-       obj->systemMustContain          = NULL;
-       obj->systemMayContain           = NULL;
 
        obj->auxiliaryClass             = NULL;
        obj->possSuperiors              = NULL;
-       obj->mustContain                = NULL;
-       obj->mayContain                 = NULL;
+
+       GET_STRING_LIST_LDB(msg, "systemMustContain", mem_ctx, obj, systemMustContain, False);
+       GET_STRING_LIST_LDB(msg, "systemMayContain", mem_ctx, obj, systemMayContain, False);
+       GET_STRING_LIST_LDB(msg, "mustContain", mem_ctx, obj, mustContain, False);
+       GET_STRING_LIST_LDB(msg, "mayContain", mem_ctx, obj, mayContain, False);
 
        GET_STRING_LDB(msg, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, False);
 
@@ -930,6 +959,23 @@ const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema
        return NULL;
 }
 
+const struct dsdb_class *dsdb_class_by_cn(const struct dsdb_schema *schema,
+                                         const char *cn)
+{
+       struct dsdb_class *cur;
+
+       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;
+}
+
 const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
                                       uint32_t id)
 {
@@ -964,6 +1010,22 @@ int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
        return LDB_SUCCESS;
 }
 
+static struct dsdb_schema *global_schema;
+
+int dsdb_set_global_schema(struct ldb_context *ldb)
+{
+       int ret;
+       if (!global_schema) {
+         return LDB_SUCCESS;
+       }
+       ret = ldb_set_opaque(ldb, "dsdb_schema", global_schema);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       return LDB_SUCCESS;
+}
+
 const struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb)
 {
        const void *p;
@@ -983,6 +1045,26 @@ const struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb)
        return schema;
 }
 
+void dsdb_make_schema_global(struct ldb_context *ldb)
+{
+       const void *p;
+       const struct dsdb_schema *schema;
+
+       /* see if we have a cached copy */
+       p = ldb_get_opaque(ldb, "dsdb_schema");
+       if (!p) {
+               return;
+       }
+
+       schema = talloc_get_type(p, struct dsdb_schema);
+       if (!schema) {
+               return;
+       }
+
+       talloc_steal(NULL, schema);
+       global_schema = schema;
+}
+
 WERROR dsdb_attach_schema_from_ldif_file(struct ldb_context *ldb, const char *pf, const char *df)
 {
        struct ldb_ldif *ldif;
index f884140d1ccf39d7b0420094067445c43c4e06b7..e7d3388f7224505281633a957e2acb9fc2852826 100644 (file)
@@ -35,6 +35,7 @@
 #include "lib/ldb/include/ldb_errors.h"
 #include "lib/ldb/samba/ldif_handlers.h"
 #include "db_wrap.h"
+#include "dsdb/samdb/samdb.h"
 
 static struct tdb_wrap *tdb_list;
 
@@ -126,6 +127,10 @@ struct ldb_context *ldb_wrap_connect(TALLOC_CTX *mem_ctx,
                talloc_free(ldb);
                return NULL;
        }
+       
+       if (strcmp(lp_sam_url(), url) == 0) {
+               dsdb_set_global_schema(ldb);
+       }
 
        ret = ldb_register_samba_handlers(ldb);
        if (ret == -1) {
index 1d02fb0f3ea55c95dda53b19805d2e28e6b0cf31..d0dd252e47cdac478ece7246f006e77b51105c1c 100644 (file)
@@ -666,7 +666,15 @@ const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *att
 {
        const char **ret;
        int i;
-       for (i=0;attrs[i];i++) /* noop */ ;
+       bool found = false;
+       for (i=0;attrs[i];i++) {
+               if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
+                       found = true;
+               }
+       }
+       if (found) {
+               return ldb_attr_list_copy(mem_ctx, attrs);
+       }
        ret = talloc_array(mem_ctx, const char *, i+2);
        if (ret == NULL) {
                return NULL;
@@ -686,7 +694,7 @@ const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *att
 int ldb_attr_in_list(const char * const *attrs, const char *attr)
 {
        int i;
-       for (i=0;attrs[i];i++) {
+       for (i=0;attrs && attrs[i];i++) {
                if (ldb_attr_cmp(attrs[i], attr) == 0) {
                        return 1;
                }
index 44b956a8b627d2c93d222e7bc430550d5c78ed56..e1691d0cb3bf7d2710c93d401eaaba23e6fdfc52 100644 (file)
@@ -299,66 +299,53 @@ static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_c
                                            const struct ldb_val *in, struct ldb_val *out)
 {
        struct ldb_dn *dn1 = NULL;
-       char *oc1, *oc2;
+       const struct dsdb_schema *schema = dsdb_get_schema(ldb);
+       const struct dsdb_class *class;
 
+       if (!schema) {
+               *out = data_blob_talloc(mem_ctx, in->data, in->length);
+               return LDB_SUCCESS;
+       }
        dn1 = ldb_dn_new(mem_ctx, ldb, (char *)in->data);
        if ( ! ldb_dn_validate(dn1)) {
-               oc1 = talloc_strndup(mem_ctx, (char *)in->data, in->length);
-       } else if (ldb_dn_get_comp_num(dn1) >= 1 && strcasecmp(ldb_dn_get_rdn_name(dn1), "cn") == 0) {
+               const char *lDAPDisplayName = talloc_strndup(mem_ctx, (char *)in->data, in->length);
+               class = dsdb_class_by_lDAPDisplayName(schema, lDAPDisplayName);
+               talloc_free(lDAPDisplayName);
+       } else if (ldb_dn_get_comp_num(dn1) >= 1 && ldb_attr_cmp(ldb_dn_get_rdn_name(dn1), "cn") == 0) {
                const struct ldb_val *val = ldb_dn_get_rdn_val(dn1);
-               oc1 = talloc_strndup(mem_ctx, (char *)val->data, val->length);
+               const char *cn = talloc_strndup(mem_ctx, (char *)val->data, val->length);
+               class = dsdb_class_by_cn(schema, cn);
+               talloc_free(cn);
        } else {
+               talloc_free(dn1);
                return -1;
        }
-
-       oc2 = ldb_casefold(ldb, mem_ctx, oc1);
-       out->data = (void *)oc2;
-       out->length = strlen(oc2);
-       talloc_free(oc1);
        talloc_free(dn1);
-       return 0;
+
+       if (!class) {
+               return -1;
+       }
+       
+       *out = data_blob_string_const(talloc_strdup(mem_ctx, class->lDAPDisplayName));
+
+       return LDB_SUCCESS;
 }
 
 static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
                                          const struct ldb_val *v1,
                                          const struct ldb_val *v2)
 {
-       struct ldb_dn *dn1 = NULL, *dn2 = NULL;
-       const char *oc1, *oc2;
 
-       dn1 = ldb_dn_new(mem_ctx, ldb, (char *)v1->data);
-       if ( ! ldb_dn_validate(dn1)) {
-               oc1 = talloc_strndup(mem_ctx, (char *)v1->data, v1->length);
-       } else if (ldb_dn_get_comp_num(dn1) >= 1 && strcasecmp(ldb_dn_get_rdn_name(dn1), "cn") == 0) {
-               const struct ldb_val *val = ldb_dn_get_rdn_val(dn1);
-               oc1 = talloc_strndup(mem_ctx, (char *)val->data, val->length);
-       } else {
-               oc1 = NULL;
-       }
+       int ret1, ret2;
+       struct ldb_val v1_canon, v2_canon;
+       ret1 = ldif_canonicalise_objectCategory(ldb, mem_ctx, v1, &v1_canon);
+       ret2 = ldif_canonicalise_objectCategory(ldb, mem_ctx, v2, &v2_canon);
 
-       dn2 = ldb_dn_new(mem_ctx, ldb, (char *)v2->data);
-       if ( ! ldb_dn_validate(dn2)) {
-               oc2 = talloc_strndup(mem_ctx, (char *)v2->data, v2->length);
-       } else if (ldb_dn_get_comp_num(dn2) >= 2 && strcasecmp(ldb_dn_get_rdn_name(dn2), "cn") == 0) {
-               const struct ldb_val *val = ldb_dn_get_rdn_val(dn2);
-               oc2 = talloc_strndup(mem_ctx, (char *)val->data, val->length);
+       if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
+               return ldb_attr_cmp(v1_canon.data, v2_canon.data);
        } else {
-               oc2 = NULL;
+               return strcasecmp(v1->data, v2->data);
        }
-
-       oc1 = ldb_casefold(ldb, mem_ctx, oc1);
-       oc2 = ldb_casefold(ldb, mem_ctx, oc2);
-       if (!oc1 && oc2) {
-               return -1;
-       } 
-       if (oc1 && !oc2) {
-               return 1;
-       }       
-       if (!oc1 && !oc2) {
-               return -1;
-       }
-
-       return strcmp(oc1, oc2);
 }
 
 #define LDB_SYNTAX_SAMBA_SID                   "LDB_SYNTAX_SAMBA_SID"
index 9adcab267957b4fb1c238f79b0b0f4961f46d383..f94c34e932696c6903f015f2cebdee74ea000638 100644 (file)
@@ -611,7 +611,7 @@ function provision(subobj, message, blank, paths, session_info, credentials, lda
        var modify_ok = setup_ldb_modify("provision_schema_basedn_modify.ldif", info, samdb);
        if (!modify_ok) {
                if (!add_ok) {
-                       message("Failed to both add and modify schema dn: + samdb.errstring() + "\n");
+                       message("Failed to both add and modify schema dn:" + samdb.errstring() + "\n");
                        message("Perhaps you need to run the provision script with the --ldap-base-dn option, and add this record to the backend manually\n"); 
                        assert(modify_ok);
                }
@@ -744,7 +744,7 @@ function provision_schema(subobj, message, tmp_schema_path, paths)
        var modify_ok = setup_ldb_modify("provision_schema_basedn_modify.ldif", info, samdb);
        if (!modify_ok) {
                if (!add_ok) {
-                       message("Failed to both add and modify schema dn: + samdb.errstring() + "\n");
+                       message("Failed to both add and modify schema dn: + samdb.errstring() + "\n");
                        message("Perhaps you need to run the provision script with the --ldap-base-dn option, and add this record to the backend manually\n"); 
                        assert(modify_ok);
                }
@@ -882,16 +882,18 @@ function provision_guess()
                                        "extended_dn",
                                        "asq",
                                        "samldb",
-                                       "password_hash",
                                        "operational",
                                        "objectclass",
                                        "rdn_name",
                                        "show_deleted",
                                        "partition");
        subobj.MODULES_LIST = join(",", modules_list);
-       subobj.DOMAINDN_MOD = "objectguid";
-       subobj.CONFIGDN_MOD = "objectguid";
-       subobj.SCHEMADN_MOD = "objectguid";
+       subobj.DOMAINDN_MOD = "pdc_fsmo,password_hash";
+       subobj.CONFIGDN_MOD = "naming_fsmo";
+       subobj.SCHEMADN_MOD = "schema_fsmo";
+       subobj.DOMAINDN_MOD2 = ",objectguid";
+       subobj.CONFIGDN_MOD2 = ",objectguid";
+       subobj.SCHEMADN_MOD2 = ",objectguid";
 
        subobj.EXTENSIBLEOBJECT = "# no objectClass: extensibleObject for local ldb";
        subobj.ACI              = "# no aci for local ldb";
index 3c5d31dc0fcaadf0c751b44b938881285d5ed713..9a67d06963e16fced1a79da6d1b1d52bf73615b8 100755 (executable)
@@ -132,11 +132,11 @@ if (ldapbackend) {
                subobj["LDAPMODULE"] = "entryUUID";
        }
        subobj["DOMAINDN_LDB"] = subobj["LDAPBACKEND"];
-       subobj["DOMAINDN_MOD"] = subobj["LDAPMODULE"] + ",paged_searches";
+       subobj["DOMAINDN_MOD2"] = subobj["LDAPMODULE"] + ",paged_searches";
        subobj["CONFIGDN_LDB"] = subobj["LDAPBACKEND"];
-       subobj["CONFIGDN_MOD"] = subobj["LDAPMODULE"] + ",paged_searches";
+       subobj["CONFIGDN_MOD2"] = subobj["LDAPMODULE"] + ",paged_searches";
        subobj["SCHEMADN_LDB"] = subobj["LDAPBACKEND"];
-       subobj["SCHEMADN_MOD"] = subobj["LDAPMODULE"] + ",paged_searches";
+       subobj["SCHEMADN_MOD2"] = subobj["LDAPMODULE"] + ",paged_searches";
 }
 
 if (!provision_validate(subobj, message)) {
index 3800918bc129f0a989c2abe371ad9210852404b8..c6107c6502e2e45436d2360bbd4bf1ebdcb4a81e 100644 (file)
@@ -5,9 +5,9 @@ partition: ${DOMAINDN}:${DOMAINDN_LDB}
 replicateEntries: @SUBCLASSES
 replicateEntries: @ATTRIBUTES
 replicateEntries: @INDEXLIST
-modules:${SCHEMADN}:${SCHEMADN_MOD}
-modules:${CONFIGDN}:${CONFIGDN_MOD}
-modules:${DOMAINDN}:${DOMAINDN_MOD}
+modules:${SCHEMADN}:${SCHEMADN_MOD}${SCHEMADN_MOD2}
+modules:${CONFIGDN}:${CONFIGDN_MOD}${CONFIGDN_MOD2}
+modules:${DOMAINDN}:${DOMAINDN_MOD}${DOMAINDN_MOD2}
 
 dn: @MODULES
 @LIST: ${MODULES_LIST}
index 1f188d06796f63051759f02471e0b01c96d51c06..a222a654f728caf07d5cc50c63bd782aa4769547 100644 (file)
@@ -23,3 +23,21 @@ fSMORoleOwner: CN=NTDS Settings,CN=${NETBIOSNAME},CN=Servers,CN=${DEFAULTSITE},C
 -
 replace: objectVersion
 objectVersion: 30
+-
+replace: prefixMap
+prefixMap:: QkRTRAAAAAAiAAAAAAACACIAAAAAAAAAAgAAAAQAAgABAAAAAgAAAAgAAgACAAAACA
+ AAAAwAAgADAAAACAAAABAAAgAEAAAACAAAABQAAgAFAAAACAAAABgAAgAGAAAACAAAABwAAgAHAAA
+ ACAAAACAAAgAIAAAAAgAAACQAAgAJAAAACAAAACgAAgAKAAAACAAAACwAAgATAAAACAAAADAAAgAU
+ AAAACAAAADQAAgAVAAAACQAAADgAAgAWAAAACQAAADwAAgAXAAAACgAAAEAAAgAYAAAAAgAAAEQAA
+ gAZAAAAAgAAAEgAAgAaAAAAAgAAAEwAAgALAAAACgAAAFAAAgAMAAAACQAAAFQAAgANAAAACgAAAF
+ gAAgAOAAAACQAAAFwAAgAPAAAACgAAAGAAAgAQAAAACQAAAGQAAgARAAAACQAAAGgAAgASAAAACgA
+ AAGwAAgAbAAAACQAAAHAAAgAcAAAACQAAAHQAAgAdAAAACAAAAHgAAgAeAAAACAAAAHwAAgAfAAAA
+ CQAAAIAAAgAgAAAACQAAAIQAAgAhAAAACQAAAIgAAgACAAAAVQQAAAIAAABVBgAACAAAACqGSIb3F
+ AECCAAAACqGSIb3FAEDCAAAAGCGSAFlAgIBCAAAAGCGSAFlAgIDCAAAAGCGSAFlAgEFCAAAAGCGSA
+ FlAgEEAgAAAFUFAAAIAAAAKoZIhvcUAQQIAAAAKoZIhvcUAQUIAAAACZImiZPyLGQIAAAAYIZIAYb
+ 4QgMJAAAACZImiZPyLGQBAAAACQAAAGCGSAGG+EIDAQAAAAoAAAAqhkiG9xQBBbZYAAACAAAAVRUA
+ AAIAAABVEgAAAgAAAFUUAAAKAAAAKoZIhvcUAQSCBAAACQAAACqGSIb3FAEFOAAAAAoAAAAqhkiG9
+ xQBBIIGAAAJAAAAKoZIhvcUAQU5AAAACgAAACqGSIb3FAEEggcAAAkAAAAqhkiG9xQBBToAAAAJAA
+ AAKoZIhvcUAQVJAAAACgAAACqGSIb3FAEEgjEAAAkAAAArBgEEAYs6ZXcAAAAJAAAAYIZIAYb4QgM
+ CAAAACAAAACsGAQQBgXoBCAAAACqGSIb3DQEJCQAAAAmSJomT8ixkBAAAAAkAAAArBgEEAbd9BAEA
+ AAAJAAAAKwYBBAG3fQQC
index ecd50c3097b95f03eff561b8df20c486002cb886..7ea66a7998f3f40c024e415223094326905df094 100755 (executable)
@@ -25,7 +25,7 @@ if (options.ARGV.length != 1) {
 
 var host = options.ARGV[0];
 
-function basic_tests(ldb, gc_ldb, base_dn, configuration_dn)
+function basic_tests(ldb, gc_ldb, base_dn, configuration_dn, schema_dn)
 {
        println("Running basic tests");
 
@@ -473,6 +473,33 @@ objectClass: user
        assert(res.error == 0);
        assert (res.msgs.length > 0);
 
+       println("Testing objectCategory canonacolisation");
+       var attrs = new Array("cn");
+       var res = ldb.search("objectCategory=ntDsDSA", configuration_dn, ldb.SCOPE_SUBTREE, attrs);
+       assert(res.error == 0);
+       if (res.msgs.length == 0) {
+               println("Didn't find any records with objectCategory=ntDsDSA");
+       }
+       assert(res.msgs.length != 0);
+       
+       var attrs = new Array("cn");
+       var res = ldb.search("objectCategory=CN=ntDs-DSA," + schema_dn, configuration_dn, ldb.SCOPE_SUBTREE, attrs);
+       assert(res.error == 0);
+       if (res.msgs.length == 0) {
+               println("Didn't find any records with objectCategory=CN=ntDs-DSA," + schema_dn);
+       }
+       assert(res.msgs.length != 0);
+       
+       println("Testing objectClass attribute order on "+ base_dn);
+       var attrs = new Array("objectclass");
+       var res = ldb.search("objectClass=domain", base_dn, ldb.SCOPE_BASE, attrs);
+       assert(res.error == 0);
+       assert(res.msgs.length == 1);
+
+       assert(res.msgs[0].objectClass[0] == "top");
+       assert(res.msgs[0].objectClass[1] == "domain");
+       assert(res.msgs[0].objectClass[2] == "domainDNS");
+       
 }
 
 function basedn_tests(ldb, gc_ldb)
@@ -522,6 +549,15 @@ function find_configurationdn(ldb)
     return res.msgs[0].configurationNamingContext;
 }
 
+function find_schemadn(ldb)
+{
+    var attrs = new Array("schemaNamingContext");
+    var res = ldb.search("", "", ldb.SCOPE_BASE, attrs);
+    assert(res.error == 0);
+    assert(res.msgs.length == 1);
+    return res.msgs[0].schemaNamingContext;
+}
+
 /* use command line creds if available */
 ldb.credentials = options.get_credentials();
 gc_ldb.credentials = options.get_credentials();
@@ -529,6 +565,7 @@ gc_ldb.credentials = options.get_credentials();
 var ok = ldb.connect("ldap://" + host);
 var base_dn = find_basedn(ldb);
 var configuration_dn = find_configurationdn(ldb);
+var schema_dn = find_schemadn(ldb);
 
 printf("baseDN: %s\n", base_dn);
 
@@ -537,7 +574,7 @@ if (!ok) {
        gc_ldb = undefined;
 }
 
-basic_tests(ldb, gc_ldb, base_dn, configuration_dn)
+basic_tests(ldb, gc_ldb, base_dn, configuration_dn, schema_dn)
 
 basedn_tests(ldb, gc_ldb)
 
index e0fab647b585f2bbd150950aac6ce5acfe1320b1..5fa527a69444b1073b6222986ca6e930a6db4d35 100755 (executable)
@@ -270,7 +270,7 @@ objectClass: user
 cn: X
 codePage: x
 revision: x
-objectCategory: x
+dnsHostName: x
 nextRid: y
 lastLogon: x
 description: x
@@ -282,7 +282,7 @@ objectClass: top
 cn: Y
 codePage: x
 revision: x
-objectCategory: y
+dnsHostName: y
 nextRid: y
 lastLogon: y
 description: x
@@ -292,7 +292,7 @@ objectClass: top
 cn: Z
 codePage: x
 revision: y
-objectCategory: z
+dnsHostName: z
 nextRid: y
 lastLogon: z
 description: y
@@ -342,86 +342,86 @@ description: y
 
        /* Search remote record by local DN */
        dn = s4.dn("cn=A");
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("", dn, ldb.SCOPE_BASE, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 1);
        assert(res.msgs[0].dn == dn);
-       assert(res.msgs[0].objectCategory == undefined);
+       assert(res.msgs[0].dnsHostName == undefined);
        assert(res.msgs[0].lastLogon == "x");
 
        /* Search remote record by remote DN */
        dn = s3.dn("cn=A");
-       attrs = new Array("objectCategory", "lastLogon", "sambaLogonTime");
+       attrs = new Array("dnsHostName", "lastLogon", "sambaLogonTime");
        res = s3.db.search("", dn, ldb.SCOPE_BASE, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 1);
        assert(res.msgs[0].dn == dn);
-       assert(res.msgs[0].objectCategory == undefined);
+       assert(res.msgs[0].dnsHostName == undefined);
        assert(res.msgs[0].lastLogon == undefined);
        assert(res.msgs[0].sambaLogonTime == "x");
 
        /* Search split record by local DN */
        dn = s4.dn("cn=X");
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("", dn, ldb.SCOPE_BASE, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 1);
        assert(res.msgs[0].dn == dn);
-       assert(res.msgs[0].objectCategory == "x");
+       assert(res.msgs[0].dnsHostName == "x");
        assert(res.msgs[0].lastLogon == "x");
 
        /* Search split record by remote DN */
        dn = s3.dn("cn=X");
-       attrs = new Array("objectCategory", "lastLogon", "sambaLogonTime");
+       attrs = new Array("dnsHostName", "lastLogon", "sambaLogonTime");
        res = s3.db.search("", dn, ldb.SCOPE_BASE, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 1);
        assert(res.msgs[0].dn == dn);
-       assert(res.msgs[0].objectCategory == undefined);
+       assert(res.msgs[0].dnsHostName == undefined);
        assert(res.msgs[0].lastLogon == undefined);
        assert(res.msgs[0].sambaLogonTime == "x");
 
        println("Testing search by attribute");
 
        /* Search by ignored attribute */
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("(revision=x)", NULL, ldb. SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 2);
        assert(res.msgs[0].dn == s4.dn("cn=Y"));
-       assert(res.msgs[0].objectCategory == "y");
+       assert(res.msgs[0].dnsHostName == "y");
        assert(res.msgs[0].lastLogon == "y");
        assert(res.msgs[1].dn == s4.dn("cn=X"));
-       assert(res.msgs[1].objectCategory == "x");
+       assert(res.msgs[1].dnsHostName == "x");
        assert(res.msgs[1].lastLogon == "x");
 
        /* Search by kept attribute */
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("(description=y)", NULL, ldb. SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 2);
        assert(res.msgs[0].dn == s4.dn("cn=Z"));
-       assert(res.msgs[0].objectCategory == "z");
+       assert(res.msgs[0].dnsHostName == "z");
        assert(res.msgs[0].lastLogon == "z");
        assert(res.msgs[1].dn == s4.dn("cn=C"));
-       assert(res.msgs[1].objectCategory == undefined);
+       assert(res.msgs[1].dnsHostName == undefined);
        assert(res.msgs[1].lastLogon == "z");
 
        /* Search by renamed attribute */
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("(badPwdCount=x)", NULL, ldb. SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 2);
        assert(res.msgs[0].dn == s4.dn("cn=B"));
-       assert(res.msgs[0].objectCategory == undefined);
+       assert(res.msgs[0].dnsHostName == undefined);
        assert(res.msgs[0].lastLogon == "y");
        assert(res.msgs[1].dn == s4.dn("cn=A"));
-       assert(res.msgs[1].objectCategory == undefined);
+       assert(res.msgs[1].dnsHostName == undefined);
        assert(res.msgs[1].lastLogon == "x");
 
        /* Search by converted attribute */
-       attrs = new Array("objectCategory", "lastLogon", "objectSid");
+       attrs = new Array("dnsHostName", "lastLogon", "objectSid");
        /* TODO:
           Using the SID directly in the parse tree leads to conversion
           errors, letting the search fail with no results.
@@ -431,23 +431,23 @@ description: y
        assert(res.error == 0);
        assert(res.msgs.length == 2);
        assert(res.msgs[0].dn == s4.dn("cn=X"));
-       assert(res.msgs[0].objectCategory == "x");
+       assert(res.msgs[0].dnsHostName == "x");
        assert(res.msgs[0].lastLogon == "x");
        assert(res.msgs[0].objectSid == "S-1-5-21-4231626423-2410014848-2360679739-552");
        assert(res.msgs[1].dn == s4.dn("cn=A"));
-       assert(res.msgs[1].objectCategory == undefined);
+       assert(res.msgs[1].dnsHostName == undefined);
        assert(res.msgs[1].lastLogon == "x");
        assert(res.msgs[1].objectSid == "S-1-5-21-4231626423-2410014848-2360679739-552");
 
        /* Search by generated attribute */
        /* In most cases, this even works when the mapping is missing
         * a `convert_operator' by enumerating the remote db. */
-       attrs = new Array("objectCategory", "lastLogon", "primaryGroupID");
+       attrs = new Array("dnsHostName", "lastLogon", "primaryGroupID");
        res = ldb.search("(primaryGroupID=512)", NULL, ldb. SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 1);
        assert(res.msgs[0].dn == s4.dn("cn=A"));
-       assert(res.msgs[0].objectCategory == undefined);
+       assert(res.msgs[0].dnsHostName == undefined);
        assert(res.msgs[0].lastLogon == "x");
        assert(res.msgs[0].primaryGroupID == "512");
 
@@ -468,23 +468,23 @@ description: y
        */
 
        /* Search by remote name of renamed attribute */
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("(sambaBadPasswordCount=*)", "", ldb. SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 0);
 
        /* Search by objectClass */
-       attrs = new Array("objectCategory", "lastLogon", "objectClass");
+       attrs = new Array("dnsHostName", "lastLogon", "objectClass");
        res = ldb.search("(objectClass=user)", NULL, ldb. SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 2);
        assert(res.msgs[0].dn == s4.dn("cn=X"));
-       assert(res.msgs[0].objectCategory == "x");
+       assert(res.msgs[0].dnsHostName == "x");
        assert(res.msgs[0].lastLogon == "x");
        assert(res.msgs[0].objectClass != undefined);
        assert(res.msgs[0].objectClass[3] == "user");
        assert(res.msgs[1].dn == s4.dn("cn=A"));
-       assert(res.msgs[1].objectCategory == undefined);
+       assert(res.msgs[1].dnsHostName == undefined);
        assert(res.msgs[1].lastLogon == "x");
        assert(res.msgs[1].objectClass != undefined);
        assert(res.msgs[1].objectClass[0] == "user");
@@ -494,19 +494,19 @@ description: y
        assert(res.error == 0);
        assert(res.msgs.length == 3);
        assert(res.msgs[0].dn == s4.dn("cn=B"));
-       assert(res.msgs[0].objectCategory == undefined);
+       assert(res.msgs[0].dnsHostName == undefined);
        assert(res.msgs[0].lastLogon == "y");
        assert(res.msgs[0].objectClass != undefined);
        for (i=0;i<res.msgs[0].objectClass.length;i++) {
                assert(res.msgs[0].objectClass[i] != "user");
        }
        assert(res.msgs[1].dn == s4.dn("cn=X"));
-       assert(res.msgs[1].objectCategory == "x");
+       assert(res.msgs[1].dnsHostName == "x");
        assert(res.msgs[1].lastLogon == "x");
        assert(res.msgs[1].objectClass != undefined);
        assert(res.msgs[1].objectClass[3] == "user");
        assert(res.msgs[2].dn == s4.dn("cn=A"));
-       assert(res.msgs[2].objectCategory == undefined);
+       assert(res.msgs[2].dnsHostName == undefined);
        assert(res.msgs[2].lastLogon == "x");
        assert(res.msgs[2].objectClass != undefined);
        assert(res.msgs[2].objectClass[0] == "user");
@@ -514,43 +514,43 @@ description: y
        println("Testing search by parse tree");
 
        /* Search by conjunction of local attributes */
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("(&(codePage=x)(revision=x))", NULL, ldb.SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 2);
        assert(res.msgs[0].dn == s4.dn("cn=Y"));
-       assert(res.msgs[0].objectCategory == "y");
+       assert(res.msgs[0].dnsHostName == "y");
        assert(res.msgs[0].lastLogon == "y");
        assert(res.msgs[1].dn == s4.dn("cn=X"));
-       assert(res.msgs[1].objectCategory == "x");
+       assert(res.msgs[1].dnsHostName == "x");
        assert(res.msgs[1].lastLogon == "x");
 
        /* Search by conjunction of remote attributes */
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("(&(lastLogon=x)(description=x))", NULL, ldb.SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 2);
        assert(res.msgs[0].dn == s4.dn("cn=X"));
-       assert(res.msgs[0].objectCategory == "x");
+       assert(res.msgs[0].dnsHostName == "x");
        assert(res.msgs[0].lastLogon == "x");
        assert(res.msgs[1].dn == s4.dn("cn=A"));
-       assert(res.msgs[1].objectCategory == undefined);
+       assert(res.msgs[1].dnsHostName == undefined);
        assert(res.msgs[1].lastLogon == "x");
        
        /* Search by conjunction of local and remote attribute */
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("(&(codePage=x)(description=x))", NULL, ldb.SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 2);
        assert(res.msgs[0].dn == s4.dn("cn=Y"));
-       assert(res.msgs[0].objectCategory == "y");
+       assert(res.msgs[0].dnsHostName == "y");
        assert(res.msgs[0].lastLogon == "y");
        assert(res.msgs[1].dn == s4.dn("cn=X"));
-       assert(res.msgs[1].objectCategory == "x");
+       assert(res.msgs[1].dnsHostName == "x");
        assert(res.msgs[1].lastLogon == "x");
 
        /* Search by conjunction of local and remote attribute w/o match */
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("(&(codePage=x)(nextRid=x))", NULL, ldb.SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 0);
@@ -559,203 +559,203 @@ description: y
        assert(res.msgs.length == 0);
 
        /* Search by disjunction of local attributes */
-       attrs = new Array("objectCategory", "lastLogon");
-       res = ldb.search("(|(revision=x)(objectCategory=x))", NULL, ldb.SCOPE_DEFAULT, attrs);
+       attrs = new Array("dnsHostName", "lastLogon");
+       res = ldb.search("(|(revision=x)(dnsHostName=x))", NULL, ldb.SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 2);
        assert(res.msgs[0].dn == s4.dn("cn=Y"));
-       assert(res.msgs[0].objectCategory == "y");
+       assert(res.msgs[0].dnsHostName == "y");
        assert(res.msgs[0].lastLogon == "y");
        assert(res.msgs[1].dn == s4.dn("cn=X"));
-       assert(res.msgs[1].objectCategory == "x");
+       assert(res.msgs[1].dnsHostName == "x");
        assert(res.msgs[1].lastLogon == "x");
 
        /* Search by disjunction of remote attributes */
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("(|(badPwdCount=x)(lastLogon=x))", NULL, ldb.SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 3);
        assert(res.msgs[0].dn == s4.dn("cn=B"));
-       assert(res.msgs[0].objectCategory == undefined);
+       assert(res.msgs[0].dnsHostName == undefined);
        assert(res.msgs[0].lastLogon == "y");
        assert(res.msgs[1].dn == s4.dn("cn=X"));
-       assert(res.msgs[1].objectCategory == "x");
+       assert(res.msgs[1].dnsHostName == "x");
        assert(res.msgs[1].lastLogon == "x");
        assert(res.msgs[2].dn == s4.dn("cn=A"));
-       assert(res.msgs[2].objectCategory == undefined);
+       assert(res.msgs[2].dnsHostName == undefined);
        assert(res.msgs[2].lastLogon == "x");
 
        /* Search by disjunction of local and remote attribute */
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("(|(revision=x)(lastLogon=y))", NULL, ldb.SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 3);
        assert(res.msgs[0].dn == s4.dn("cn=Y"));
-       assert(res.msgs[0].objectCategory == "y");
+       assert(res.msgs[0].dnsHostName == "y");
        assert(res.msgs[0].lastLogon == "y");
        assert(res.msgs[1].dn == s4.dn("cn=B"));
-       assert(res.msgs[1].objectCategory == undefined);
+       assert(res.msgs[1].dnsHostName == undefined);
        assert(res.msgs[1].lastLogon == "y");
        assert(res.msgs[2].dn == s4.dn("cn=X"));
-       assert(res.msgs[2].objectCategory == "x");
+       assert(res.msgs[2].dnsHostName == "x");
        assert(res.msgs[2].lastLogon == "x");
 
        /* Search by disjunction of local and remote attribute w/o match */
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("(|(codePage=y)(nextRid=z))", NULL, ldb.SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 0);
 
        /* Search by negated local attribute */
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("(!(revision=x))", NULL, ldb.SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 4);
        assert(res.msgs[0].dn == s4.dn("cn=B"));
-       assert(res.msgs[0].objectCategory == undefined);
+       assert(res.msgs[0].dnsHostName == undefined);
        assert(res.msgs[0].lastLogon == "y");
        assert(res.msgs[1].dn == s4.dn("cn=A"));
-       assert(res.msgs[1].objectCategory == undefined);
+       assert(res.msgs[1].dnsHostName == undefined);
        assert(res.msgs[1].lastLogon == "x");
        assert(res.msgs[2].dn == s4.dn("cn=Z"));
-       assert(res.msgs[2].objectCategory == "z");
+       assert(res.msgs[2].dnsHostName == "z");
        assert(res.msgs[2].lastLogon == "z");
        assert(res.msgs[3].dn == s4.dn("cn=C"));
-       assert(res.msgs[3].objectCategory == undefined);
+       assert(res.msgs[3].dnsHostName == undefined);
        assert(res.msgs[3].lastLogon == "z");
 
        /* Search by negated remote attribute */
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("(!(description=x))", NULL, ldb.SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 2);
        assert(res.msgs[0].dn == s4.dn("cn=Z"));
-       assert(res.msgs[0].objectCategory == "z");
+       assert(res.msgs[0].dnsHostName == "z");
        assert(res.msgs[0].lastLogon == "z");
        assert(res.msgs[1].dn == s4.dn("cn=C"));
-       assert(res.msgs[1].objectCategory == undefined);
+       assert(res.msgs[1].dnsHostName == undefined);
        assert(res.msgs[1].lastLogon == "z");
 
        /* Search by negated conjunction of local attributes */
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("(!(&(codePage=x)(revision=x)))", NULL, ldb.SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 4);
        assert(res.msgs[0].dn == s4.dn("cn=B"));
-       assert(res.msgs[0].objectCategory == undefined);
+       assert(res.msgs[0].dnsHostName == undefined);
        assert(res.msgs[0].lastLogon == "y");
        assert(res.msgs[1].dn == s4.dn("cn=A"));
-       assert(res.msgs[1].objectCategory == undefined);
+       assert(res.msgs[1].dnsHostName == undefined);
        assert(res.msgs[1].lastLogon == "x");
        assert(res.msgs[2].dn == s4.dn("cn=Z"));
-       assert(res.msgs[2].objectCategory == "z");
+       assert(res.msgs[2].dnsHostName == "z");
        assert(res.msgs[2].lastLogon == "z");
        assert(res.msgs[3].dn == s4.dn("cn=C"));
-       assert(res.msgs[3].objectCategory == undefined);
+       assert(res.msgs[3].dnsHostName == undefined);
        assert(res.msgs[3].lastLogon == "z");
 
        /* Search by negated conjunction of remote attributes */
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("(!(&(lastLogon=x)(description=x)))", NULL, ldb.SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 4);
        assert(res.msgs[0].dn == s4.dn("cn=Y"));
-       assert(res.msgs[0].objectCategory == "y");
+       assert(res.msgs[0].dnsHostName == "y");
        assert(res.msgs[0].lastLogon == "y");
        assert(res.msgs[1].dn == s4.dn("cn=B"));
-       assert(res.msgs[1].objectCategory == undefined);
+       assert(res.msgs[1].dnsHostName == undefined);
        assert(res.msgs[1].lastLogon == "y");
        assert(res.msgs[2].dn == s4.dn("cn=Z"));
-       assert(res.msgs[2].objectCategory == "z");
+       assert(res.msgs[2].dnsHostName == "z");
        assert(res.msgs[2].lastLogon == "z");
        assert(res.msgs[3].dn == s4.dn("cn=C"));
-       assert(res.msgs[3].objectCategory == undefined);
+       assert(res.msgs[3].dnsHostName == undefined);
        assert(res.msgs[3].lastLogon == "z");
 
        /* Search by negated conjunction of local and remote attribute */
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("(!(&(codePage=x)(description=x)))", NULL, ldb.SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 4);
        assert(res.msgs[0].dn == s4.dn("cn=B"));
-       assert(res.msgs[0].objectCategory == undefined);
+       assert(res.msgs[0].dnsHostName == undefined);
        assert(res.msgs[0].lastLogon == "y");
        assert(res.msgs[1].dn == s4.dn("cn=A"));
-       assert(res.msgs[1].objectCategory == undefined);
+       assert(res.msgs[1].dnsHostName == undefined);
        assert(res.msgs[1].lastLogon == "x");
        assert(res.msgs[2].dn == s4.dn("cn=Z"));
-       assert(res.msgs[2].objectCategory == "z");
+       assert(res.msgs[2].dnsHostName == "z");
        assert(res.msgs[2].lastLogon == "z");
        assert(res.msgs[3].dn == s4.dn("cn=C"));
-       assert(res.msgs[3].objectCategory == undefined);
+       assert(res.msgs[3].dnsHostName == undefined);
        assert(res.msgs[3].lastLogon == "z");
 
        /* Search by negated disjunction of local attributes */
-       attrs = new Array("objectCategory", "lastLogon");
-       res = ldb.search("(!(|(revision=x)(objectCategory=x)))", NULL, ldb.SCOPE_DEFAULT, attrs);
+       attrs = new Array("dnsHostName", "lastLogon");
+       res = ldb.search("(!(|(revision=x)(dnsHostName=x)))", NULL, ldb.SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs[0].dn == s4.dn("cn=B"));
-       assert(res.msgs[0].objectCategory == undefined);
+       assert(res.msgs[0].dnsHostName == undefined);
        assert(res.msgs[0].lastLogon == "y");
        assert(res.msgs[1].dn == s4.dn("cn=A"));
-       assert(res.msgs[1].objectCategory == undefined);
+       assert(res.msgs[1].dnsHostName == undefined);
        assert(res.msgs[1].lastLogon == "x");
        assert(res.msgs[2].dn == s4.dn("cn=Z"));
-       assert(res.msgs[2].objectCategory == "z");
+       assert(res.msgs[2].dnsHostName == "z");
        assert(res.msgs[2].lastLogon == "z");
        assert(res.msgs[3].dn == s4.dn("cn=C"));
-       assert(res.msgs[3].objectCategory == undefined);
+       assert(res.msgs[3].dnsHostName == undefined);
        assert(res.msgs[3].lastLogon == "z");
 
        /* Search by negated disjunction of remote attributes */
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("(!(|(badPwdCount=x)(lastLogon=x)))", NULL, ldb.SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 3);
        assert(res.msgs[0].dn == s4.dn("cn=Y"));
-       assert(res.msgs[0].objectCategory == "y");
+       assert(res.msgs[0].dnsHostName == "y");
        assert(res.msgs[0].lastLogon == "y");
        assert(res.msgs[1].dn == s4.dn("cn=Z"));
-       assert(res.msgs[1].objectCategory == "z");
+       assert(res.msgs[1].dnsHostName == "z");
        assert(res.msgs[1].lastLogon == "z");
        assert(res.msgs[2].dn == s4.dn("cn=C"));
-       assert(res.msgs[2].objectCategory == undefined);
+       assert(res.msgs[2].dnsHostName == undefined);
        assert(res.msgs[2].lastLogon == "z");
 
        /* Search by negated disjunction of local and remote attribute */
-       attrs = new Array("objectCategory", "lastLogon");
+       attrs = new Array("dnsHostName", "lastLogon");
        res = ldb.search("(!(|(revision=x)(lastLogon=y)))", NULL, ldb.SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 3);
        assert(res.msgs[0].dn == s4.dn("cn=A"));
-       assert(res.msgs[0].objectCategory == undefined);
+       assert(res.msgs[0].dnsHostName == undefined);
        assert(res.msgs[0].lastLogon == "x");
        assert(res.msgs[1].dn == s4.dn("cn=Z"));
-       assert(res.msgs[1].objectCategory == "z");
+       assert(res.msgs[1].dnsHostName == "z");
        assert(res.msgs[1].lastLogon == "z");
        assert(res.msgs[2].dn == s4.dn("cn=C"));
-       assert(res.msgs[2].objectCategory == undefined);
+       assert(res.msgs[2].dnsHostName == undefined);
        assert(res.msgs[2].lastLogon == "z");
 
        /* Search by complex parse tree */
-       attrs = new Array("objectCategory", "lastLogon");
-       res = ldb.search("(|(&(revision=x)(objectCategory=x))(!(&(description=x)(nextRid=y)))(badPwdCount=y))", NULL, ldb.SCOPE_DEFAULT, attrs);
+       attrs = new Array("dnsHostName", "lastLogon");
+       res = ldb.search("(|(&(revision=x)(dnsHostName=x))(!(&(description=x)(nextRid=y)))(badPwdCount=y))", NULL, ldb.SCOPE_DEFAULT, attrs);
        assert(res.error == 0);
        assert(res.msgs.length == 5);
        assert(res.msgs[0].dn == s4.dn("cn=B"));
-       assert(res.msgs[0].objectCategory == undefined);
+       assert(res.msgs[0].dnsHostName == undefined);
        assert(res.msgs[0].lastLogon == "y");
        assert(res.msgs[1].dn == s4.dn("cn=X"));
-       assert(res.msgs[1].objectCategory == "x");
+       assert(res.msgs[1].dnsHostName == "x");
        assert(res.msgs[1].lastLogon == "x");
        assert(res.msgs[2].dn == s4.dn("cn=A"));
-       assert(res.msgs[2].objectCategory == undefined);
+       assert(res.msgs[2].dnsHostName == undefined);
        assert(res.msgs[2].lastLogon == "x");
        assert(res.msgs[3].dn == s4.dn("cn=Z"));
-       assert(res.msgs[3].objectCategory == "z");
+       assert(res.msgs[3].dnsHostName == "z");
        assert(res.msgs[3].lastLogon == "z");
        assert(res.msgs[4].dn == s4.dn("cn=C"));
-       assert(res.msgs[4].objectCategory == undefined);
+       assert(res.msgs[4].dnsHostName == undefined);
        assert(res.msgs[4].lastLogon == "z");
 
        /* Clean up */