Split schema_init.c into smaller bits.
[kai/samba.git] / source4 / dsdb / schema / schema_init.c
index 41998a16db42c1b135182b855b1a820e6dcf16f1..3ed7daee5953aa8a778436a01baf08ea286708dc 100644 (file)
@@ -2,11 +2,12 @@
    Unix SMB/CIFS mplementation.
    DSDB schema header
    
-   Copyright (C) Stefan Metzmacher 2006
-    
+   Copyright (C) Stefan Metzmacher <metze@samba.org> 2006-2007
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2008
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
 */
 
 #include "includes.h"
 #include "dsdb/samdb/samdb.h"
+#include "lib/ldb/include/ldb_errors.h"
 #include "lib/util/dlinklist.h"
 #include "librpc/gen_ndr/ndr_misc.h"
 #include "librpc/gen_ndr/ndr_drsuapi.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "param/param.h"
 
-WERROR dsdb_load_oid_mappings(struct dsdb_schema *schema, const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
+struct dsdb_schema *dsdb_new_schema(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience)
+{
+       struct dsdb_schema *schema = talloc_zero(mem_ctx, struct dsdb_schema);
+       if (!schema) {
+               return NULL;
+       }
+
+       schema->iconv_convenience = iconv_convenience;
+       return schema;
+}
+
+
+WERROR dsdb_load_oid_mappings_drsuapi(struct dsdb_schema *schema, const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
 {
        uint32_t i,j;
 
@@ -73,7 +88,125 @@ WERROR dsdb_load_oid_mappings(struct dsdb_schema *schema, const struct drsuapi_D
        return WERR_OK;
 }
 
-WERROR dsdb_verify_oid_mappings(const struct dsdb_schema *schema, const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
+WERROR dsdb_load_oid_mappings_ldb(struct dsdb_schema *schema,
+                                 const struct ldb_val *prefixMap,
+                                 const struct ldb_val *schemaInfo)
+{
+       WERROR status;
+       enum ndr_err_code ndr_err;
+       struct prefixMapBlob pfm;
+       char *schema_info;
+
+       TALLOC_CTX *mem_ctx = talloc_new(schema);
+       W_ERROR_HAVE_NO_MEMORY(mem_ctx);
+       
+       ndr_err = ndr_pull_struct_blob(prefixMap, mem_ctx, schema->iconv_convenience, &pfm, (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
+               talloc_free(mem_ctx);
+               return ntstatus_to_werror(nt_status);
+       }
+
+       if (pfm.version != PREFIX_MAP_VERSION_DSDB) {
+               talloc_free(mem_ctx);
+               return WERR_FOOBAR;
+       }
+
+       if (schemaInfo->length != 21 && schemaInfo->data[0] == 0xFF) {
+               talloc_free(mem_ctx);
+               return WERR_FOOBAR;
+       }
+
+       /* append the schema info as last element */
+       pfm.ctr.dsdb.num_mappings++;
+       pfm.ctr.dsdb.mappings = talloc_realloc(mem_ctx, pfm.ctr.dsdb.mappings,
+                                              struct drsuapi_DsReplicaOIDMapping,
+                                              pfm.ctr.dsdb.num_mappings);
+       W_ERROR_HAVE_NO_MEMORY(pfm.ctr.dsdb.mappings);
+
+       schema_info = data_blob_hex_string(pfm.ctr.dsdb.mappings, schemaInfo);
+       W_ERROR_HAVE_NO_MEMORY(schema_info);
+
+       pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].id_prefix          = 0;    
+       pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].oid.__ndr_size     = schemaInfo->length;
+       pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].oid.oid            = schema_info;
+
+       /* call the drsuapi version */
+       status = dsdb_load_oid_mappings_drsuapi(schema, &pfm.ctr.dsdb);
+       talloc_free(mem_ctx);
+
+       W_ERROR_NOT_OK_RETURN(status);
+
+       return WERR_OK;
+}
+
+WERROR dsdb_get_oid_mappings_drsuapi(const struct dsdb_schema *schema,
+                                    bool include_schema_info,
+                                    TALLOC_CTX *mem_ctx,
+                                    struct drsuapi_DsReplicaOIDMapping_Ctr **_ctr)
+{
+       struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
+       uint32_t i;
+
+       ctr = talloc(mem_ctx, struct drsuapi_DsReplicaOIDMapping_Ctr);
+       W_ERROR_HAVE_NO_MEMORY(ctr);
+
+       ctr->num_mappings       = schema->num_prefixes;
+       if (include_schema_info) ctr->num_mappings++;
+       ctr->mappings = talloc_array(schema, struct drsuapi_DsReplicaOIDMapping, ctr->num_mappings);
+       W_ERROR_HAVE_NO_MEMORY(ctr->mappings);
+
+       for (i=0; i < schema->num_prefixes; i++) {
+               ctr->mappings[i].id_prefix      = schema->prefixes[i].id>>16;
+               ctr->mappings[i].oid.oid        = talloc_strndup(ctr->mappings,
+                                                                schema->prefixes[i].oid,
+                                                                schema->prefixes[i].oid_len - 1);
+               W_ERROR_HAVE_NO_MEMORY(ctr->mappings[i].oid.oid);
+       }
+
+       if (include_schema_info) {
+               ctr->mappings[i].id_prefix      = 0;
+               ctr->mappings[i].oid.oid        = talloc_strdup(ctr->mappings,
+                                                               schema->schema_info);
+               W_ERROR_HAVE_NO_MEMORY(ctr->mappings[i].oid.oid);
+       }
+
+       *_ctr = ctr;
+       return WERR_OK;
+}
+
+WERROR dsdb_get_oid_mappings_ldb(const struct dsdb_schema *schema,
+                                TALLOC_CTX *mem_ctx,
+                                struct ldb_val *prefixMap,
+                                struct ldb_val *schemaInfo)
+{
+       WERROR status;
+       enum ndr_err_code ndr_err;
+       struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
+       struct prefixMapBlob pfm;
+
+       status = dsdb_get_oid_mappings_drsuapi(schema, false, mem_ctx, &ctr);
+       W_ERROR_NOT_OK_RETURN(status);
+
+       pfm.version     = PREFIX_MAP_VERSION_DSDB;
+       pfm.reserved    = 0;
+       pfm.ctr.dsdb    = *ctr;
+
+       ndr_err = ndr_push_struct_blob(prefixMap, mem_ctx, schema->iconv_convenience, &pfm, (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
+       talloc_free(ctr);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
+               return ntstatus_to_werror(nt_status);
+       }
+
+       *schemaInfo = strhex_to_data_blob(schema->schema_info);
+       W_ERROR_HAVE_NO_MEMORY(schemaInfo->data);
+       talloc_steal(mem_ctx, schemaInfo->data);
+
+       return WERR_OK;
+}
+
+WERROR dsdb_verify_oid_mappings_drsuapi(const struct dsdb_schema *schema, const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
 {
        uint32_t i,j;
 
@@ -134,19 +267,153 @@ WERROR dsdb_verify_oid_mappings(const struct dsdb_schema *schema, const struct d
 }
 
 WERROR dsdb_map_oid2int(const struct dsdb_schema *schema, const char *in, uint32_t *out)
+{
+       return dsdb_find_prefix_for_oid(schema->num_prefixes, schema->prefixes, in, out);
+}
+
+
+WERROR dsdb_map_int2oid(const struct dsdb_schema *schema, uint32_t in, TALLOC_CTX *mem_ctx, const char **out)
 {
        uint32_t i;
 
        for (i=0; i < schema->num_prefixes; i++) {
+               const char *val;
+               if (schema->prefixes[i].id != (in & 0xFFFF0000)) {
+                       continue;
+               }
+
+               val = talloc_asprintf(mem_ctx, "%s%u",
+                                     schema->prefixes[i].oid,
+                                     in & 0xFFFF);
+               W_ERROR_HAVE_NO_MEMORY(val);
+
+               *out = val;
+               return WERR_OK;
+       }
+
+       return WERR_DS_NO_MSDS_INTID;
+}
+
+/*
+ * this function is called from within a ldb transaction from the schema_fsmo module
+ */
+WERROR dsdb_create_prefix_mapping(struct ldb_context *ldb, struct dsdb_schema *schema, const char *full_oid)
+{
+       WERROR status;
+       uint32_t num_prefixes;
+       struct dsdb_schema_oid_prefix *prefixes;
+       TALLOC_CTX *mem_ctx;
+       uint32_t out;
+
+       mem_ctx = talloc_new(ldb);
+       W_ERROR_HAVE_NO_MEMORY(mem_ctx);
+
+       /* Read prefixes from disk*/
+       status = dsdb_read_prefixes_from_ldb( mem_ctx, ldb, &num_prefixes, &prefixes ); 
+       if (!W_ERROR_IS_OK(status)) {
+               DEBUG(0,("dsdb_create_prefix_mapping: dsdb_read_prefixes_from_ldb: %s\n",
+                       win_errstr(status)));
+               talloc_free(mem_ctx);
+               return status;
+       }
+
+       /* Check if there is a prefix for the oid in the prefixes array*/
+       status = dsdb_find_prefix_for_oid( num_prefixes, prefixes, full_oid, &out ); 
+       if (W_ERROR_IS_OK(status)) {
+               /* prefix found*/
+               talloc_free(mem_ctx);
+               return status;
+       } else if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) {
+               /* error */
+               DEBUG(0,("dsdb_create_prefix_mapping: dsdb_find_prefix_for_oid: %s\n",
+                       win_errstr(status)));
+               talloc_free(mem_ctx);
+               return status;
+       }
+
+       /* Create the new mapping for the prefix of full_oid */
+       status = dsdb_prefix_map_update(mem_ctx, &num_prefixes, &prefixes, full_oid);
+       if (!W_ERROR_IS_OK(status)) {
+               DEBUG(0,("dsdb_create_prefix_mapping: dsdb_prefix_map_update: %s\n",
+                       win_errstr(status)));
+               talloc_free(mem_ctx);
+               return status;
+       }
+
+       /* Update prefixMap in ldb*/
+       status = dsdb_write_prefixes_to_ldb(mem_ctx, ldb, num_prefixes, prefixes);
+       if (!W_ERROR_IS_OK(status)) {
+               DEBUG(0,("dsdb_create_prefix_mapping: dsdb_write_prefixes_to_ldb: %s\n",
+                       win_errstr(status)));
+               talloc_free(mem_ctx);
+               return status;
+       }
+
+       talloc_free(mem_ctx);
+       return status;
+}
+
+WERROR dsdb_prefix_map_update(TALLOC_CTX *mem_ctx, uint32_t *num_prefixes, struct dsdb_schema_oid_prefix **prefixes, const char *oid)
+{
+       uint32_t new_num_prefixes, index_new_prefix, new_entry_id;
+       const char* lastDotOffset;
+       size_t size;
+       
+       new_num_prefixes = *num_prefixes + 1;
+       index_new_prefix = *num_prefixes;
+
+       /*
+        * this is the algorithm we use to create new mappings for now
+        *
+        * TODO: find what algorithm windows use
+        */
+       new_entry_id = (*num_prefixes)<<16;
+
+       /* Extract the prefix from the oid*/
+       lastDotOffset = strrchr(oid, '.');
+       if (lastDotOffset == NULL) {
+               DEBUG(0,("dsdb_prefix_map_update: failed to find the last dot\n"));
+               return WERR_NOT_FOUND;
+       }
+
+       /* Calculate the size of the remainig string that should be the prefix of it */
+       size = strlen(oid) - strlen(lastDotOffset);
+       if (size <= 0) {
+               DEBUG(0,("dsdb_prefix_map_update: size of the remaining string invalid\n"));
+               return WERR_FOOBAR;
+       }
+       /* Add one because we need to copy the dot */
+       size += 1;
+
+       /* Create a spot in the prefixMap for one more prefix*/
+       (*prefixes) = talloc_realloc(mem_ctx, *prefixes, struct dsdb_schema_oid_prefix, new_num_prefixes);
+       W_ERROR_HAVE_NO_MEMORY(*prefixes);
+
+       /* Add the new prefix entry*/
+       (*prefixes)[index_new_prefix].id = new_entry_id;
+       (*prefixes)[index_new_prefix].oid = talloc_strndup(mem_ctx, oid, size);
+       (*prefixes)[index_new_prefix].oid_len = strlen((*prefixes)[index_new_prefix].oid);
+
+       /* Increase num_prefixes because new prefix has been added */
+       ++(*num_prefixes);
+
+       return WERR_OK;
+}
+
+WERROR dsdb_find_prefix_for_oid(uint32_t num_prefixes, const struct dsdb_schema_oid_prefix *prefixes, const char *in, uint32_t *out)
+{
+       uint32_t i;
+
+       for (i=0; i < num_prefixes; i++) {
                const char *val_str;
                char *end_str;
                unsigned val;
 
-               if (strncmp(schema->prefixes[i].oid, in, schema->prefixes[i].oid_len) != 0) {
+               if (strncmp(prefixes[i].oid, in, prefixes[i].oid_len) != 0) {
                        continue;
                }
 
-               val_str = in + schema->prefixes[i].oid_len;
+               val_str = in + prefixes[i].oid_len;
                end_str = NULL;
                errno = 0;
 
@@ -172,33 +439,142 @@ WERROR dsdb_map_oid2int(const struct dsdb_schema *schema, const char *in, uint32
                        return WERR_INVALID_PARAM;
                }
 
-               *out = schema->prefixes[i].id | val;
+               *out = prefixes[i].id | val;
                return WERR_OK;
        }
 
        return WERR_DS_NO_MSDS_INTID;
 }
 
-WERROR dsdb_map_int2oid(const struct dsdb_schema *schema, uint32_t in, TALLOC_CTX *mem_ctx, const char **out)
+WERROR dsdb_write_prefixes_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
+                                 uint32_t num_prefixes,
+                                 const struct dsdb_schema_oid_prefix *prefixes)
 {
+       struct ldb_message msg;
+       struct ldb_dn *schema_dn;
+       struct ldb_message_element el;
+       struct prefixMapBlob pm;
+       struct ldb_val ndr_blob;
+       enum ndr_err_code ndr_err;
        uint32_t i;
+       int ret;
+       
+       schema_dn = samdb_schema_dn(ldb);
+       if (!schema_dn) {
+               DEBUG(0,("dsdb_write_prefixes_to_ldb: no schema dn present\n"));        
+               return WERR_FOOBAR;
+       }
 
-       for (i=0; i < schema->num_prefixes; i++) {
-               const char *val;
-               if (schema->prefixes[i].id != (in & 0xFFFF0000)) {
-                       continue;
-               }
+       pm.version                      = PREFIX_MAP_VERSION_DSDB;
+       pm.ctr.dsdb.num_mappings        = num_prefixes;
+       pm.ctr.dsdb.mappings            = talloc_array(mem_ctx,
+                                               struct drsuapi_DsReplicaOIDMapping,
+                                               pm.ctr.dsdb.num_mappings);
+       if (!pm.ctr.dsdb.mappings) {
+               return WERR_NOMEM;
+       }
 
-               val = talloc_asprintf(mem_ctx, "%s%u",
-                                     schema->prefixes[i].oid,
-                                     in & 0xFFFF);
-               W_ERROR_HAVE_NO_MEMORY(val);
+       for (i=0; i < num_prefixes; i++) {
+               pm.ctr.dsdb.mappings[i].id_prefix = prefixes[i].id>>16;
+               pm.ctr.dsdb.mappings[i].oid.oid = talloc_strdup(pm.ctr.dsdb.mappings, prefixes[i].oid);
+       }
 
-               *out = val;
-               return WERR_OK;
+       ndr_err = ndr_push_struct_blob(&ndr_blob, ldb,
+                                      lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
+                                      &pm,
+                                      (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               return WERR_FOOBAR;
        }
+       el.num_values = 1;
+       el.values = &ndr_blob;
+       el.flags = LDB_FLAG_MOD_REPLACE;
+       el.name = talloc_strdup(mem_ctx, "prefixMap");
+       msg.dn = ldb_dn_copy(mem_ctx, schema_dn);
+       msg.num_elements = 1;
+       msg.elements = &el;
+       ret = ldb_modify( ldb, &msg );
+       if (ret != 0) {
+               DEBUG(0,("dsdb_write_prefixes_to_ldb: ldb_modify failed\n"));   
+               return WERR_FOOBAR;
+       }
+       return WERR_OK;
+}
 
-       return WERR_DS_NO_MSDS_INTID;
+WERROR dsdb_read_prefixes_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, uint32_t* num_prefixes, struct dsdb_schema_oid_prefix **prefixes)
+{
+       struct prefixMapBlob *blob;
+       enum ndr_err_code ndr_err;
+       uint32_t i;
+       const struct ldb_val *prefix_val;
+       struct ldb_dn *schema_dn;
+       struct ldb_result *schema_res;
+       int ret;    
+       static const char *schema_attrs[] = {
+               "prefixMap",
+               NULL
+       };
+
+       schema_dn = samdb_schema_dn(ldb);
+       if (!schema_dn) {
+               DEBUG(0,("dsdb_read_prefixes_from_ldb: no schema dn present\n"));
+               return WERR_FOOBAR;
+       }
+
+       ret = ldb_search(ldb, schema_dn, LDB_SCOPE_BASE,NULL, schema_attrs,&schema_res);
+       if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+               DEBUG(0,("dsdb_read_prefixes_from_ldb: no prefix map present\n"));
+               return WERR_FOOBAR;
+       } else if (ret != LDB_SUCCESS) {
+               DEBUG(0,("dsdb_read_prefixes_from_ldb: failed to search the schema head\n"));
+               return WERR_FOOBAR;
+       }
+
+       prefix_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "prefixMap");
+       if (!prefix_val) {
+               DEBUG(0,("dsdb_read_prefixes_from_ldb: no prefixMap attribute found\n"));
+               return WERR_FOOBAR;
+       }
+
+       blob = talloc(mem_ctx, struct prefixMapBlob);
+       W_ERROR_HAVE_NO_MEMORY(blob);
+
+       ndr_err = ndr_pull_struct_blob(prefix_val, blob, 
+                                          lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
+                                          blob,
+                                          (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               DEBUG(0,("dsdb_read_prefixes_from_ldb: ndr_pull_struct_blob failed\n"));
+               talloc_free(blob);
+               return WERR_FOOBAR;
+       }
+
+       if (blob->version != PREFIX_MAP_VERSION_DSDB) {
+               DEBUG(0,("dsdb_read_prefixes_from_ldb: blob->version incorect\n"));
+               talloc_free(blob);
+               return WERR_FOOBAR;
+       }
+       
+       *num_prefixes = blob->ctr.dsdb.num_mappings;
+       *prefixes = talloc_array(mem_ctx, struct dsdb_schema_oid_prefix, *num_prefixes);
+       if(!(*prefixes)) {
+               talloc_free(blob);
+               return WERR_NOMEM;
+       }
+       for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
+               char *oid;
+               (*prefixes)[i].id = blob->ctr.dsdb.mappings[i].id_prefix<<16;
+               oid = talloc_strdup(mem_ctx, blob->ctr.dsdb.mappings[i].oid.oid);
+               (*prefixes)[i].oid = talloc_asprintf_append(oid, "."); 
+               (*prefixes)[i].oid_len = strlen(blob->ctr.dsdb.mappings[i].oid.oid);
+       }
+
+       talloc_free(blob);
+       return WERR_OK;
 }
 
 #define GET_STRING_LDB(msg, attr, mem_ctx, p, elem, strict) do { \
@@ -210,6 +586,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);\
@@ -218,12 +622,12 @@ WERROR dsdb_map_int2oid(const struct dsdb_schema *schema, uint32_t in, TALLOC_CT
                        d_printf("%s: %s == NULL\n", __location__, attr); \
                        return WERR_INVALID_PARAM; \
                } else { \
-                       (p)->elem = False; \
+                       (p)->elem = false; \
                } \
        } else if (strcasecmp("TRUE", str) == 0) { \
-               (p)->elem = True; \
+               (p)->elem = true; \
        } else if (strcasecmp("FALSE", str) == 0) { \
-               (p)->elem = False; \
+               (p)->elem = false; \
        } else { \
                d_printf("%s: %s == %s\n", __location__, attr, str); \
                return WERR_INVALID_PARAM; \
@@ -249,13 +653,28 @@ WERROR dsdb_map_int2oid(const struct dsdb_schema *schema, uint32_t in, TALLOC_CT
        }\
 } while (0)
 
-WERROR dsdb_attribute_from_ldb(struct ldb_message *msg, TALLOC_CTX *mem_ctx, struct dsdb_attribute *attr)
+WERROR dsdb_attribute_from_ldb(const struct dsdb_schema *schema,
+                              struct ldb_message *msg,
+                              TALLOC_CTX *mem_ctx,
+                              struct dsdb_attribute *attr)
 {
-       GET_STRING_LDB(msg, "cn", mem_ctx, attr, cn, True);
-       GET_STRING_LDB(msg, "lDAPDisplayName", mem_ctx, attr, lDAPDisplayName, True);
-       GET_STRING_LDB(msg, "attributeID", mem_ctx, attr, attributeID_oid, True);
-       /* set an invalid value */
-       attr->attributeID_id = 0xFFFFFFFF;
+       WERROR status;
+
+       GET_STRING_LDB(msg, "cn", mem_ctx, attr, cn, false);
+       GET_STRING_LDB(msg, "lDAPDisplayName", mem_ctx, attr, lDAPDisplayName, true);
+       GET_STRING_LDB(msg, "attributeID", mem_ctx, attr, attributeID_oid, true);
+       if (schema->num_prefixes == 0) {
+               /* set an invalid value */
+               attr->attributeID_id = 0xFFFFFFFF;
+       } else {
+               status = dsdb_map_oid2int(schema, attr->attributeID_oid, &attr->attributeID_id);
+               if (!W_ERROR_IS_OK(status)) {
+                       DEBUG(0,("%s: '%s': unable to map attributeID %s: %s\n",
+                               __location__, attr->lDAPDisplayName, attr->attributeID_oid,
+                               win_errstr(status)));
+                       return status;
+               }
+       }
        GET_GUID_LDB(msg, "schemaIDGUID", attr, schemaIDGUID);
        GET_UINT32_LDB(msg, "mAPIID", attr, mAPIID);
 
@@ -263,30 +682,40 @@ WERROR dsdb_attribute_from_ldb(struct ldb_message *msg, TALLOC_CTX *mem_ctx, str
 
        GET_UINT32_LDB(msg, "searchFlags", attr, searchFlags);
        GET_UINT32_LDB(msg, "systemFlags", attr, systemFlags);
-       GET_BOOL_LDB(msg, "isMemberOfPartialAttributeSet", attr, isMemberOfPartialAttributeSet, False);
+       GET_BOOL_LDB(msg, "isMemberOfPartialAttributeSet", attr, isMemberOfPartialAttributeSet, false);
        GET_UINT32_LDB(msg, "linkID", attr, linkID);
 
-       GET_STRING_LDB(msg, "attributeSyntax", mem_ctx, attr, attributeSyntax_oid, True);
-       /* set an invalid value */
-       attr->attributeSyntax_id = 0xFFFFFFFF;
+       GET_STRING_LDB(msg, "attributeSyntax", mem_ctx, attr, attributeSyntax_oid, true);
+       if (schema->num_prefixes == 0) {
+               /* set an invalid value */
+               attr->attributeSyntax_id = 0xFFFFFFFF;
+       } else {
+               status = dsdb_map_oid2int(schema, attr->attributeSyntax_oid, &attr->attributeSyntax_id);
+               if (!W_ERROR_IS_OK(status)) {
+                       DEBUG(0,("%s: '%s': unable to map attributeSyntax_ %s: %s\n",
+                               __location__, attr->lDAPDisplayName, attr->attributeSyntax_oid,
+                               win_errstr(status)));
+                       return status;
+               }
+       }
        GET_UINT32_LDB(msg, "oMSyntax", attr, oMSyntax);
        GET_BLOB_LDB(msg, "oMObjectClass", mem_ctx, attr, oMObjectClass);
 
-       GET_BOOL_LDB(msg, "isSingleValued", attr, isSingleValued, True);
+       GET_BOOL_LDB(msg, "isSingleValued", attr, isSingleValued, true);
        GET_UINT32_LDB(msg, "rangeLower", attr, rangeLower);
        GET_UINT32_LDB(msg, "rangeUpper", attr, rangeUpper);
-       GET_BOOL_LDB(msg, "extendedCharsAllowed", attr, extendedCharsAllowed, False);
+       GET_BOOL_LDB(msg, "extendedCharsAllowed", attr, extendedCharsAllowed, false);
 
        GET_UINT32_LDB(msg, "schemaFlagsEx", attr, schemaFlagsEx);
        GET_BLOB_LDB(msg, "msDs-Schema-Extensions", mem_ctx, attr, msDs_Schema_Extensions);
 
-       GET_BOOL_LDB(msg, "showInAdvancedViewOnly", attr, showInAdvancedViewOnly, False);
-       GET_STRING_LDB(msg, "adminDisplayName", mem_ctx, attr, adminDisplayName, False);
-       GET_STRING_LDB(msg, "adminDescription", mem_ctx, attr, adminDescription, False);
-       GET_STRING_LDB(msg, "classDisplayName", mem_ctx, attr, classDisplayName, False);
-       GET_BOOL_LDB(msg, "isEphemeral", attr, isEphemeral, False);
-       GET_BOOL_LDB(msg, "isDefunct", attr, isDefunct, False);
-       GET_BOOL_LDB(msg, "systemOnly", attr, systemOnly, False);
+       GET_BOOL_LDB(msg, "showInAdvancedViewOnly", attr, showInAdvancedViewOnly, false);
+       GET_STRING_LDB(msg, "adminDisplayName", mem_ctx, attr, adminDisplayName, false);
+       GET_STRING_LDB(msg, "adminDescription", mem_ctx, attr, adminDescription, false);
+       GET_STRING_LDB(msg, "classDisplayName", mem_ctx, attr, classDisplayName, false);
+       GET_BOOL_LDB(msg, "isEphemeral", attr, isEphemeral, false);
+       GET_BOOL_LDB(msg, "isDefunct", attr, isDefunct, false);
+       GET_BOOL_LDB(msg, "systemOnly", attr, systemOnly, false);
 
        attr->syntax = dsdb_syntax_for_attribute(attr);
        if (!attr->syntax) {
@@ -296,47 +725,356 @@ WERROR dsdb_attribute_from_ldb(struct ldb_message *msg, TALLOC_CTX *mem_ctx, str
        return WERR_OK;
 }
 
-WERROR dsdb_class_from_ldb(struct ldb_message *msg, TALLOC_CTX *mem_ctx, struct dsdb_class *obj)
+WERROR dsdb_class_from_ldb(const struct dsdb_schema *schema,
+                          struct ldb_message *msg,
+                          TALLOC_CTX *mem_ctx,
+                          struct dsdb_class *obj)
 {
-       GET_STRING_LDB(msg, "cn", mem_ctx, obj, cn, True);
-       GET_STRING_LDB(msg, "lDAPDisplayName", mem_ctx, obj, lDAPDisplayName, True);
-       GET_STRING_LDB(msg, "governsID", mem_ctx, obj, governsID_oid, True);
-       /* set an invalid value */
-       obj->governsID_id = 0xFFFFFFFF;
+       WERROR status;
+
+       GET_STRING_LDB(msg, "cn", mem_ctx, obj, cn, false);
+       GET_STRING_LDB(msg, "lDAPDisplayName", mem_ctx, obj, lDAPDisplayName, true);
+       GET_STRING_LDB(msg, "governsID", mem_ctx, obj, governsID_oid, true);
+       if (schema->num_prefixes == 0) {
+               /* set an invalid value */
+               obj->governsID_id = 0xFFFFFFFF;
+       } else {
+               status = dsdb_map_oid2int(schema, obj->governsID_oid, &obj->governsID_id);
+               if (!W_ERROR_IS_OK(status)) {
+                       DEBUG(0,("%s: '%s': unable to map governsID %s: %s\n",
+                               __location__, obj->lDAPDisplayName, obj->governsID_oid,
+                               win_errstr(status)));
+                       return status;
+               }
+       }
        GET_GUID_LDB(msg, "schemaIDGUID", obj, schemaIDGUID);
 
        GET_UINT32_LDB(msg, "objectClassCategory", obj, objectClassCategory);
-       GET_STRING_LDB(msg, "rDNAttID", mem_ctx, obj, rDNAttID, False);
-       GET_STRING_LDB(msg, "defaultObjectCategory", mem_ctx, obj, defaultObjectCategory, True);
+       GET_STRING_LDB(msg, "rDNAttID", mem_ctx, obj, rDNAttID, false);
+       GET_STRING_LDB(msg, "defaultObjectCategory", mem_ctx, obj, defaultObjectCategory, true);
  
-       GET_STRING_LDB(msg, "subClassOf", mem_ctx, obj, subClassOf, True);
+       GET_STRING_LDB(msg, "subClassOf", mem_ctx, obj, subClassOf, true);
 
-       obj->systemAuxiliaryClass       = NULL;
-       obj->systemPossSuperiors        = NULL;
-       obj->systemMustContain          = NULL;
-       obj->systemMayContain           = NULL;
+       GET_STRING_LIST_LDB(msg, "systemAuxiliaryClass", mem_ctx, obj, systemAuxiliaryClass, false);
+       GET_STRING_LIST_LDB(msg, "auxiliaryClass", mem_ctx, obj, auxiliaryClass, false);
 
-       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_LIST_LDB(msg, "systemPossSuperiors", mem_ctx, obj, systemPossSuperiors, false);
+       GET_STRING_LIST_LDB(msg, "possSuperiors", mem_ctx, obj, possSuperiors, false);
+       GET_STRING_LIST_LDB(msg, "possibleInferiors", mem_ctx, obj, possibleInferiors, false);
 
-       GET_STRING_LDB(msg, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, False);
+       GET_STRING_LDB(msg, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, false);
 
        GET_UINT32_LDB(msg, "schemaFlagsEx", obj, schemaFlagsEx);
        GET_BLOB_LDB(msg, "msDs-Schema-Extensions", mem_ctx, obj, msDs_Schema_Extensions);
 
-       GET_BOOL_LDB(msg, "showInAdvancedViewOnly", obj, showInAdvancedViewOnly, False);
-       GET_STRING_LDB(msg, "adminDisplayName", mem_ctx, obj, adminDisplayName, False);
-       GET_STRING_LDB(msg, "adminDescription", mem_ctx, obj, adminDescription, False);
-       GET_STRING_LDB(msg, "classDisplayName", mem_ctx, obj, classDisplayName, False);
-       GET_BOOL_LDB(msg, "defaultHidingValue", obj, defaultHidingValue, False);
-       GET_BOOL_LDB(msg, "isDefunct", obj, isDefunct, False);
-       GET_BOOL_LDB(msg, "systemOnly", obj, systemOnly, False);
+       GET_BOOL_LDB(msg, "showInAdvancedViewOnly", obj, showInAdvancedViewOnly, false);
+       GET_STRING_LDB(msg, "adminDisplayName", mem_ctx, obj, adminDisplayName, false);
+       GET_STRING_LDB(msg, "adminDescription", mem_ctx, obj, adminDescription, false);
+       GET_STRING_LDB(msg, "classDisplayName", mem_ctx, obj, classDisplayName, false);
+       GET_BOOL_LDB(msg, "defaultHidingValue", obj, defaultHidingValue, false);
+       GET_BOOL_LDB(msg, "isDefunct", obj, isDefunct, false);
+       GET_BOOL_LDB(msg, "systemOnly", obj, systemOnly, false);
 
        return WERR_OK;
 }
 
+#define dsdb_oom(error_string, mem_ctx) *error_string = talloc_asprintf(mem_ctx, "dsdb out of memory at %s:%d\n", __FILE__, __LINE__)
+
+int dsdb_schema_from_ldb_results(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
+                                struct smb_iconv_convenience *iconv_convenience, 
+                                struct ldb_result *schema_res,
+                                struct ldb_result *attrs_res, struct ldb_result *objectclass_res, 
+                                struct dsdb_schema **schema_out,
+                                char **error_string)
+{
+       WERROR status;
+       uint32_t i;
+       const struct ldb_val *prefix_val;
+       const struct ldb_val *info_val;
+       struct ldb_val info_val_default;
+       struct dsdb_schema *schema;
+
+       schema = dsdb_new_schema(mem_ctx, iconv_convenience);
+       if (!schema) {
+               dsdb_oom(error_string, mem_ctx);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       prefix_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "prefixMap");
+       if (!prefix_val) {
+               *error_string = talloc_asprintf(mem_ctx, 
+                                               "schema_fsmo_init: no prefixMap attribute found");
+               return LDB_ERR_CONSTRAINT_VIOLATION;
+       }
+       info_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "schemaInfo");
+       if (!info_val) {
+               info_val_default = strhex_to_data_blob("FF0000000000000000000000000000000000000000");
+               if (!info_val_default.data) {
+                       dsdb_oom(error_string, mem_ctx);
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+               talloc_steal(mem_ctx, info_val_default.data);
+               info_val = &info_val_default;
+       }
+
+       status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val);
+       if (!W_ERROR_IS_OK(status)) {
+               *error_string = talloc_asprintf(mem_ctx, 
+                             "schema_fsmo_init: failed to load oid mappings: %s",
+                             win_errstr(status));
+               return LDB_ERR_CONSTRAINT_VIOLATION;
+       }
+
+       for (i=0; i < attrs_res->count; i++) {
+               struct dsdb_attribute *sa;
+
+               sa = talloc_zero(schema, struct dsdb_attribute);
+               if (!sa) {
+                       dsdb_oom(error_string, mem_ctx);
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+
+               status = dsdb_attribute_from_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",
+                                     ldb_dn_get_linearized(attrs_res->msgs[i]->dn),
+                                     win_errstr(status));
+                       return LDB_ERR_CONSTRAINT_VIOLATION;
+               }
+
+               DLIST_ADD_END(schema->attributes, sa, struct dsdb_attribute *);
+       }
+
+       for (i=0; i < objectclass_res->count; i++) {
+               struct dsdb_class *sc;
+
+               sc = talloc_zero(schema, struct dsdb_class);
+               if (!sc) {
+                       dsdb_oom(error_string, mem_ctx);
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+
+               status = dsdb_class_from_ldb(schema, objectclass_res->msgs[i], sc, sc);
+               if (!W_ERROR_IS_OK(status)) {
+                       *error_string = talloc_asprintf(mem_ctx, 
+                                     "schema_fsmo_init: failed to load class definition: %s:%s",
+                                     ldb_dn_get_linearized(objectclass_res->msgs[i]->dn),
+                                     win_errstr(status));
+                       return LDB_ERR_CONSTRAINT_VIOLATION;
+               }
+
+               DLIST_ADD_END(schema->classes, sc, struct dsdb_class *);
+       }
+
+       schema->fsmo.master_dn = ldb_msg_find_attr_as_dn(ldb, schema, schema_res->msgs[0], "fSMORoleOwner");
+       if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), schema->fsmo.master_dn) == 0) {
+               schema->fsmo.we_are_master = true;
+       } else {
+               schema->fsmo.we_are_master = false;
+       }
+
+       DEBUG(5, ("schema_fsmo_init: we are master: %s\n",
+                 (schema->fsmo.we_are_master?"yes":"no")));
+
+       *schema_out = schema;
+       return LDB_SUCCESS;
+}
+
+/* This recursive load of the objectClasses presumes that they
+ * everything is in a strict subClassOf hirarchy.  
+ *
+ * We load this in order so we produce certain outputs (such as the
+ * exported schema for openldap, and sorted objectClass attribute) 'in
+ * order' */
+
+static int fetch_oc_recursive(struct ldb_context *ldb, struct ldb_dn *schemadn, 
+                             TALLOC_CTX *mem_ctx, 
+                             struct ldb_result *search_from,
+                             struct ldb_result *res_list)
+{
+       int i;
+       int ret = 0;
+       for (i=0; i < search_from->count; i++) {
+               struct ldb_result *res;
+               const char *name = ldb_msg_find_attr_as_string(search_from->msgs[i], 
+                                                              "lDAPDisplayname", NULL);
+
+               ret = ldb_search_exp_fmt(ldb, mem_ctx, &res,
+                                       schemadn, LDB_SCOPE_SUBTREE, NULL,
+                                       "(&(&(objectClass=classSchema)(subClassOf=%s))(!(lDAPDisplayName=%s)))",
+                                       name, name);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+               
+               res_list->msgs = talloc_realloc(res_list, res_list->msgs, 
+                                               struct ldb_message *, res_list->count + 2);
+               if (!res_list->msgs) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+               res_list->msgs[res_list->count] = talloc_move(res_list, 
+                                                             &search_from->msgs[i]);
+               res_list->count++;
+               res_list->msgs[res_list->count] = NULL;
+
+               if (res->count > 0) {
+                       ret = fetch_oc_recursive(ldb, schemadn, mem_ctx, res, res_list); 
+               }
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+       }
+       return ret;
+}
+
+static int fetch_objectclass_schema(struct ldb_context *ldb, struct ldb_dn *schemadn, 
+                                   TALLOC_CTX *mem_ctx, 
+                                   struct ldb_result **objectclasses_res,
+                                   char **error_string)
+{
+       TALLOC_CTX *local_ctx = talloc_new(mem_ctx);
+       struct ldb_result *top_res, *ret_res;
+       int ret;
+       if (!local_ctx) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       
+       /* Download 'top' */
+       ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE, 
+                        "(&(objectClass=classSchema)(lDAPDisplayName=top))", 
+                        NULL, &top_res);
+       if (ret != LDB_SUCCESS) {
+               *error_string = talloc_asprintf(mem_ctx, 
+                                               "dsdb_schema: failed to search for top classSchema object: %s",
+                                               ldb_errstring(ldb));
+               return ret;
+       }
+
+       talloc_steal(local_ctx, top_res);
+
+       if (top_res->count != 1) {
+               *error_string = talloc_asprintf(mem_ctx, 
+                                               "dsdb_schema: failed to find top classSchema object");
+               return LDB_ERR_NO_SUCH_OBJECT;
+       }
+
+       ret_res = talloc_zero(local_ctx, struct ldb_result);
+       if (!ret_res) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       ret = fetch_oc_recursive(ldb, schemadn, local_ctx, top_res, ret_res); 
+
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       *objectclasses_res = talloc_move(mem_ctx, &ret_res);
+       return ret;
+}
+
+int dsdb_schema_from_schema_dn(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
+                              struct smb_iconv_convenience *iconv_convenience, 
+                              struct ldb_dn *schema_dn,
+                              struct dsdb_schema **schema,
+                              char **error_string_out) 
+{
+       TALLOC_CTX *tmp_ctx;
+       char *error_string;
+       int ret;
+
+       struct ldb_result *schema_res;
+       struct ldb_result *a_res;
+       struct ldb_result *c_res;
+       static const char *schema_attrs[] = {
+               "prefixMap",
+               "schemaInfo",
+               "fSMORoleOwner",
+               NULL
+       };
+
+       tmp_ctx = talloc_new(mem_ctx);
+       if (!tmp_ctx) {
+               dsdb_oom(error_string_out, mem_ctx);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       /*
+        * setup the prefix mappings and schema info
+        */
+       ret = ldb_search(ldb, schema_dn,
+                        LDB_SCOPE_BASE,
+                        NULL, schema_attrs,
+                        &schema_res);
+       if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+               talloc_free(tmp_ctx);
+               return ret;
+       } else if (ret != LDB_SUCCESS) {
+               *error_string_out = talloc_asprintf(mem_ctx, 
+                                      "dsdb_schema: failed to search the schema head: %s",
+                                      ldb_errstring(ldb));
+               talloc_free(tmp_ctx);
+               return ret;
+       }
+       talloc_steal(tmp_ctx, schema_res);
+       if (schema_res->count != 1) {
+               *error_string_out = talloc_asprintf(mem_ctx, 
+                             "dsdb_schema: [%u] schema heads found on a base search",
+                             schema_res->count);
+               talloc_free(tmp_ctx);
+               return LDB_ERR_CONSTRAINT_VIOLATION;
+       }
+
+       /*
+        * load the attribute definitions
+        */
+       ret = ldb_search(ldb, schema_dn,
+                        LDB_SCOPE_ONELEVEL,
+                        "(objectClass=attributeSchema)", NULL,
+                        &a_res);
+       if (ret != LDB_SUCCESS) {
+               *error_string_out = talloc_asprintf(mem_ctx, 
+                                      "dsdb_schema: failed to search attributeSchema objects: %s",
+                                      ldb_errstring(ldb));
+               talloc_free(tmp_ctx);
+               return ret;
+       }
+       talloc_steal(tmp_ctx, a_res);
+
+       /*
+        * load the objectClass definitions
+        */
+       ret = fetch_objectclass_schema(ldb, schema_dn, tmp_ctx, &c_res, &error_string);
+       if (ret != LDB_SUCCESS) {
+               *error_string_out = talloc_asprintf(mem_ctx, 
+                                      "Failed to fetch objectClass schema elements: %s", error_string);
+               talloc_free(tmp_ctx);
+               return ret;
+       }
+
+       ret = dsdb_schema_from_ldb_results(tmp_ctx, ldb,
+                                          lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
+                                          schema_res, a_res, c_res, schema, &error_string);
+       if (ret != LDB_SUCCESS) {
+               *error_string_out = talloc_asprintf(mem_ctx, 
+                                                   "dsdb_schema load failed: %s",
+                                                   error_string);
+               talloc_free(tmp_ctx);
+               return ret;
+       }
+       talloc_steal(mem_ctx, *schema);
+       talloc_free(tmp_ctx);
+
+       return LDB_SUCCESS;
+}      
+
+
 static const struct {
        const char *name;
        const char *oid;
@@ -427,13 +1165,57 @@ static struct drsuapi_DsReplicaAttribute *dsdb_find_object_attr_name(struct dsdb
                d_printf("%s: %s == NULL\n", __location__, attr); \
                return WERR_INVALID_PARAM; \
        } \
-       if (strict && _a->value_ctr.unicode_string.num_values != 1) { \
+       if (strict && _a->value_ctr.num_values != 1) { \
                d_printf("%s: %s num_values == %u\n", __location__, attr, \
-                       _a->value_ctr.unicode_string.num_values); \
+                       _a->value_ctr.num_values); \
                return WERR_INVALID_PARAM; \
        } \
-       if (_a && _a->value_ctr.unicode_string.num_values >= 1) { \
-               (p)->elem = talloc_steal(mem_ctx, _a->value_ctr.unicode_string.values[0].string);\
+       if (_a && _a->value_ctr.num_values >= 1) { \
+               ssize_t _ret; \
+               _ret = convert_string_talloc(mem_ctx, s->iconv_convenience, CH_UTF16, CH_UNIX, \
+                                            _a->value_ctr.values[0].blob->data, \
+                                            _a->value_ctr.values[0].blob->length, \
+                                            (void **)discard_const(&(p)->elem)); \
+               if (_ret == -1) { \
+                       DEBUG(0,("%s: invalid data!\n", attr)); \
+                       dump_data(0, \
+                                    _a->value_ctr.values[0].blob->data, \
+                                    _a->value_ctr.values[0].blob->length); \
+                       return WERR_FOOBAR; \
+               } \
+       } else { \
+               (p)->elem = NULL; \
+       } \
+} while (0)
+
+#define GET_DN_DS(s, r, attr, mem_ctx, p, elem, strict) do { \
+       struct drsuapi_DsReplicaAttribute *_a; \
+       _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
+       if (strict && !_a) { \
+               d_printf("%s: %s == NULL\n", __location__, attr); \
+               return WERR_INVALID_PARAM; \
+       } \
+       if (strict && _a->value_ctr.num_values != 1) { \
+               d_printf("%s: %s num_values == %u\n", __location__, attr, \
+                       _a->value_ctr.num_values); \
+               return WERR_INVALID_PARAM; \
+       } \
+       if (strict && !_a->value_ctr.values[0].blob) { \
+               d_printf("%s: %s data == NULL\n", __location__, attr); \
+               return WERR_INVALID_PARAM; \
+       } \
+       if (_a && _a->value_ctr.num_values >= 1 \
+           && _a->value_ctr.values[0].blob) { \
+               struct drsuapi_DsReplicaObjectIdentifier3 _id3; \
+               enum ndr_err_code _ndr_err; \
+               _ndr_err = ndr_pull_struct_blob_all(_a->value_ctr.values[0].blob, \
+                                                     mem_ctx, s->iconv_convenience, &_id3,\
+                                                     (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);\
+               if (!NDR_ERR_CODE_IS_SUCCESS(_ndr_err)) { \
+                       NTSTATUS _nt_status = ndr_map_error2ntstatus(_ndr_err); \
+                       return ntstatus_to_werror(_nt_status); \
+               } \
+               (p)->elem = _id3.dn; \
        } else { \
                (p)->elem = NULL; \
        } \
@@ -446,36 +1228,36 @@ static struct drsuapi_DsReplicaAttribute *dsdb_find_object_attr_name(struct dsdb
                d_printf("%s: %s == NULL\n", __location__, attr); \
                return WERR_INVALID_PARAM; \
        } \
-       if (strict && _a->value_ctr.data_blob.num_values != 1) { \
+       if (strict && _a->value_ctr.num_values != 1) { \
                d_printf("%s: %s num_values == %u\n", __location__, attr, \
-                       _a->value_ctr.data_blob.num_values); \
+                        (unsigned int)_a->value_ctr.num_values);       \
                return WERR_INVALID_PARAM; \
        } \
-       if (strict && !_a->value_ctr.data_blob.values[0].data) { \
+       if (strict && !_a->value_ctr.values[0].blob) { \
                d_printf("%s: %s data == NULL\n", __location__, attr); \
                return WERR_INVALID_PARAM; \
        } \
-       if (strict && _a->value_ctr.data_blob.values[0].data->length != 4) { \
+       if (strict && _a->value_ctr.values[0].blob->length != 4) { \
                d_printf("%s: %s length == %u\n", __location__, attr, \
-                       _a->value_ctr.data_blob.values[0].data->length); \
+                        (unsigned int)_a->value_ctr.values[0].blob->length); \
                return WERR_INVALID_PARAM; \
        } \
-       if (_a && _a->value_ctr.data_blob.num_values >= 1 \
-           && _a->value_ctr.data_blob.values[0].data \
-           && _a->value_ctr.data_blob.values[0].data->length == 4) { \
-               (p)->elem = (IVAL(_a->value_ctr.data_blob.values[0].data->data,0)?True:False);\
+       if (_a && _a->value_ctr.num_values >= 1 \
+           && _a->value_ctr.values[0].blob \
+           && _a->value_ctr.values[0].blob->length == 4) { \
+               (p)->elem = (IVAL(_a->value_ctr.values[0].blob->data,0)?true:false);\
        } else { \
-               (p)->elem = False; \
+               (p)->elem = false; \
        } \
 } while (0)
 
 #define GET_UINT32_DS(s, r, attr, p, elem) do { \
        struct drsuapi_DsReplicaAttribute *_a; \
        _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
-       if (_a && _a->value_ctr.data_blob.num_values >= 1 \
-           && _a->value_ctr.data_blob.values[0].data \
-           && _a->value_ctr.data_blob.values[0].data->length == 4) { \
-               (p)->elem = IVAL(_a->value_ctr.data_blob.values[0].data->data,0);\
+       if (_a && _a->value_ctr.num_values >= 1 \
+           && _a->value_ctr.values[0].blob \
+           && _a->value_ctr.values[0].blob->length == 4) { \
+               (p)->elem = IVAL(_a->value_ctr.values[0].blob->data,0);\
        } else { \
                (p)->elem = 0; \
        } \
@@ -484,14 +1266,15 @@ static struct drsuapi_DsReplicaAttribute *dsdb_find_object_attr_name(struct dsdb
 #define GET_GUID_DS(s, r, attr, mem_ctx, p, elem) do { \
        struct drsuapi_DsReplicaAttribute *_a; \
        _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
-       if (_a && _a->value_ctr.data_blob.num_values >= 1 \
-           && _a->value_ctr.data_blob.values[0].data \
-           && _a->value_ctr.data_blob.values[0].data->length == 16) { \
-               NTSTATUS _nt_status; \
-               _nt_status = ndr_pull_struct_blob_all(_a->value_ctr.data_blob.values[0].data, \
-                                                     mem_ctx, &(p)->elem, \
+       if (_a && _a->value_ctr.num_values >= 1 \
+           && _a->value_ctr.values[0].blob \
+           && _a->value_ctr.values[0].blob->length == 16) { \
+               enum ndr_err_code _ndr_err; \
+               _ndr_err = ndr_pull_struct_blob_all(_a->value_ctr.values[0].blob, \
+                                                     mem_ctx, s->iconv_convenience, &(p)->elem, \
                                                      (ndr_pull_flags_fn_t)ndr_pull_GUID); \
-               if (!NT_STATUS_IS_OK(_nt_status)) { \
+               if (!NDR_ERR_CODE_IS_SUCCESS(_ndr_err)) { \
+                       NTSTATUS _nt_status = ndr_map_error2ntstatus(_ndr_err); \
                        return ntstatus_to_werror(_nt_status); \
                } \
        } else { \
@@ -502,9 +1285,9 @@ static struct drsuapi_DsReplicaAttribute *dsdb_find_object_attr_name(struct dsdb
 #define GET_BLOB_DS(s, r, attr, mem_ctx, p, elem) do { \
        struct drsuapi_DsReplicaAttribute *_a; \
        _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
-       if (_a && _a->value_ctr.data_blob.num_values >= 1 \
-           && _a->value_ctr.data_blob.values[0].data) { \
-               (p)->elem = *_a->value_ctr.data_blob.values[0].data;\
+       if (_a && _a->value_ctr.num_values >= 1 \
+           && _a->value_ctr.values[0].blob) { \
+               (p)->elem = *_a->value_ctr.values[0].blob;\
                talloc_steal(mem_ctx, (p)->elem.data); \
        } else { \
                ZERO_STRUCT((p)->elem);\
@@ -518,8 +1301,8 @@ WERROR dsdb_attribute_from_drsuapi(struct dsdb_schema *schema,
 {
        WERROR status;
 
-       GET_STRING_DS(schema, r, "name", mem_ctx, attr, cn, True);
-       GET_STRING_DS(schema, r, "lDAPDisplayName", mem_ctx, attr, lDAPDisplayName, True);
+       GET_STRING_DS(schema, r, "name", mem_ctx, attr, cn, true);
+       GET_STRING_DS(schema, r, "lDAPDisplayName", mem_ctx, attr, lDAPDisplayName, true);
        GET_UINT32_DS(schema, r, "attributeID", attr, attributeID_id);
        status = dsdb_map_int2oid(schema, attr->attributeID_id, mem_ctx, &attr->attributeID_oid);
        if (!W_ERROR_IS_OK(status)) {
@@ -535,7 +1318,7 @@ WERROR dsdb_attribute_from_drsuapi(struct dsdb_schema *schema,
 
        GET_UINT32_DS(schema, r, "searchFlags", attr, searchFlags);
        GET_UINT32_DS(schema, r, "systemFlags", attr, systemFlags);
-       GET_BOOL_DS(schema, r, "isMemberOfPartialAttributeSet", attr, isMemberOfPartialAttributeSet, False);
+       GET_BOOL_DS(schema, r, "isMemberOfPartialAttributeSet", attr, isMemberOfPartialAttributeSet, false);
        GET_UINT32_DS(schema, r, "linkID", attr, linkID);
 
        GET_UINT32_DS(schema, r, "attributeSyntax", attr, attributeSyntax_id);
@@ -549,21 +1332,21 @@ WERROR dsdb_attribute_from_drsuapi(struct dsdb_schema *schema,
        GET_UINT32_DS(schema, r, "oMSyntax", attr, oMSyntax);
        GET_BLOB_DS(schema, r, "oMObjectClass", mem_ctx, attr, oMObjectClass);
 
-       GET_BOOL_DS(schema, r, "isSingleValued", attr, isSingleValued, True);
+       GET_BOOL_DS(schema, r, "isSingleValued", attr, isSingleValued, true);
        GET_UINT32_DS(schema, r, "rangeLower", attr, rangeLower);
        GET_UINT32_DS(schema, r, "rangeUpper", attr, rangeUpper);
-       GET_BOOL_DS(schema, r, "extendedCharsAllowed", attr, extendedCharsAllowed, False);
+       GET_BOOL_DS(schema, r, "extendedCharsAllowed", attr, extendedCharsAllowed, false);
 
        GET_UINT32_DS(schema, r, "schemaFlagsEx", attr, schemaFlagsEx);
        GET_BLOB_DS(schema, r, "msDs-Schema-Extensions", mem_ctx, attr, msDs_Schema_Extensions);
 
-       GET_BOOL_DS(schema, r, "showInAdvancedViewOnly", attr, showInAdvancedViewOnly, False);
-       GET_STRING_DS(schema, r, "adminDisplayName", mem_ctx, attr, adminDisplayName, False);
-       GET_STRING_DS(schema, r, "adminDescription", mem_ctx, attr, adminDescription, False);
-       GET_STRING_DS(schema, r, "classDisplayName", mem_ctx, attr, classDisplayName, False);
-       GET_BOOL_DS(schema, r, "isEphemeral", attr, isEphemeral, False);
-       GET_BOOL_DS(schema, r, "isDefunct", attr, isDefunct, False);
-       GET_BOOL_DS(schema, r, "systemOnly", attr, systemOnly, False);
+       GET_BOOL_DS(schema, r, "showInAdvancedViewOnly", attr, showInAdvancedViewOnly, false);
+       GET_STRING_DS(schema, r, "adminDisplayName", mem_ctx, attr, adminDisplayName, false);
+       GET_STRING_DS(schema, r, "adminDescription", mem_ctx, attr, adminDescription, false);
+       GET_STRING_DS(schema, r, "classDisplayName", mem_ctx, attr, classDisplayName, false);
+       GET_BOOL_DS(schema, r, "isEphemeral", attr, isEphemeral, false);
+       GET_BOOL_DS(schema, r, "isDefunct", attr, isDefunct, false);
+       GET_BOOL_DS(schema, r, "systemOnly", attr, systemOnly, false);
 
        attr->syntax = dsdb_syntax_for_attribute(attr);
        if (!attr->syntax) {
@@ -580,8 +1363,8 @@ WERROR dsdb_class_from_drsuapi(struct dsdb_schema *schema,
 {
        WERROR status;
 
-       GET_STRING_DS(schema, r, "name", mem_ctx, obj, cn, True);
-       GET_STRING_DS(schema, r, "lDAPDisplayName", mem_ctx, obj, lDAPDisplayName, True);
+       GET_STRING_DS(schema, r, "name", mem_ctx, obj, cn, true);
+       GET_STRING_DS(schema, r, "lDAPDisplayName", mem_ctx, obj, lDAPDisplayName, true);
        GET_UINT32_DS(schema, r, "governsID", obj, governsID_id);
        status = dsdb_map_int2oid(schema, obj->governsID_id, mem_ctx, &obj->governsID_oid);
        if (!W_ERROR_IS_OK(status)) {
@@ -593,10 +1376,10 @@ WERROR dsdb_class_from_drsuapi(struct dsdb_schema *schema,
        GET_GUID_DS(schema, r, "schemaIDGUID", mem_ctx, obj, schemaIDGUID);
 
        GET_UINT32_DS(schema, r, "objectClassCategory", obj, objectClassCategory);
-       GET_STRING_DS(schema, r, "rDNAttID", mem_ctx, obj, rDNAttID, False);
-       GET_STRING_DS(schema, r, "defaultObjectCategory", mem_ctx, obj, defaultObjectCategory, True);
-       GET_STRING_DS(schema, r, "subClassOf", mem_ctx, obj, subClassOf, True);
+       GET_STRING_DS(schema, r, "rDNAttID", mem_ctx, obj, rDNAttID, false);
+       GET_DN_DS(schema, r, "defaultObjectCategory", mem_ctx, obj, defaultObjectCategory, true);
+
+       GET_STRING_DS(schema, r, "subClassOf", mem_ctx, obj, subClassOf, true);
 
        obj->systemAuxiliaryClass       = NULL;
        obj->systemPossSuperiors        = NULL;
@@ -608,148 +1391,21 @@ WERROR dsdb_class_from_drsuapi(struct dsdb_schema *schema,
        obj->mustContain                = NULL;
        obj->mayContain                 = NULL;
 
-       GET_STRING_DS(schema, r, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, False);
+       obj->possibleInferiors          = NULL;
+
+       GET_STRING_DS(schema, r, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, false);
 
        GET_UINT32_DS(schema, r, "schemaFlagsEx", obj, schemaFlagsEx);
        GET_BLOB_DS(schema, r, "msDs-Schema-Extensions", mem_ctx, obj, msDs_Schema_Extensions);
 
-       GET_BOOL_DS(schema, r, "showInAdvancedViewOnly", obj, showInAdvancedViewOnly, False);
-       GET_STRING_DS(schema, r, "adminDisplayName", mem_ctx, obj, adminDisplayName, False);
-       GET_STRING_DS(schema, r, "adminDescription", mem_ctx, obj, adminDescription, False);
-       GET_STRING_DS(schema, r, "classDisplayName", mem_ctx, obj, classDisplayName, False);
-       GET_BOOL_DS(schema, r, "defaultHidingValue", obj, defaultHidingValue, False);
-       GET_BOOL_DS(schema, r, "isDefunct", obj, isDefunct, False);
-       GET_BOOL_DS(schema, r, "systemOnly", obj, systemOnly, False);
+       GET_BOOL_DS(schema, r, "showInAdvancedViewOnly", obj, showInAdvancedViewOnly, false);
+       GET_STRING_DS(schema, r, "adminDisplayName", mem_ctx, obj, adminDisplayName, false);
+       GET_STRING_DS(schema, r, "adminDescription", mem_ctx, obj, adminDescription, false);
+       GET_STRING_DS(schema, r, "classDisplayName", mem_ctx, obj, classDisplayName, false);
+       GET_BOOL_DS(schema, r, "defaultHidingValue", obj, defaultHidingValue, false);
+       GET_BOOL_DS(schema, r, "isDefunct", obj, isDefunct, false);
+       GET_BOOL_DS(schema, r, "systemOnly", obj, systemOnly, false);
 
        return WERR_OK;
 }
 
-const struct dsdb_attribute *dsdb_attribute_by_attributeID_id(const struct dsdb_schema *schema,
-                                                             uint32_t id)
-{
-       struct dsdb_attribute *cur;
-
-       /*
-        * 0xFFFFFFFF is used as value when no mapping table is available,
-        * so don't try to match with it
-        */
-       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;
-}
-
-const struct dsdb_attribute *dsdb_attribute_by_attributeID_oid(const struct dsdb_schema *schema,
-                                                              const char *oid)
-{
-       struct dsdb_attribute *cur;
-
-       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;
-}
-
-const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName(const struct dsdb_schema *schema,
-                                                              const char *name)
-{
-       struct dsdb_attribute *cur;
-
-       if (!name) return NULL;
-
-       /* TODO: add binary search */
-       for (cur = schema->attributes; cur; cur = cur->next) {
-               if (strcmp(cur->lDAPDisplayName, name) != 0) continue;
-
-               return cur;
-       }
-
-       return NULL;
-}
-
-const struct dsdb_class *dsdb_class_by_governsID_id(const struct dsdb_schema *schema,
-                                                   uint32_t id)
-{
-       struct dsdb_class *cur;
-
-       /*
-        * 0xFFFFFFFF is used as value when no mapping table is available,
-        * so don't try to match with it
-        */
-       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;
-}
-
-const struct dsdb_class *dsdb_class_by_governsID_oid(const struct dsdb_schema *schema,
-                                                    const char *oid)
-{
-       struct dsdb_class *cur;
-
-       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;
-}
-
-const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema *schema,
-                                                      const char *name)
-{
-       struct dsdb_class *cur;
-
-       if (!name) return NULL;
-
-       /* TODO: add binary search */
-       for (cur = schema->classes; cur; cur = cur->next) {
-               if (strcmp(cur->lDAPDisplayName, name) != 0) continue;
-
-               return cur;
-       }
-
-       return NULL;
-}
-
-const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
-                                      uint32_t id)
-{
-       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;
-       }
-
-       c = dsdb_class_by_governsID_id(schema, id);
-       if (c) {
-               return c->lDAPDisplayName;
-       }
-
-       return NULL;
-}