schema_fsmo: move fsmo info into struct dsdb_schema
[samba.git] / source4 / dsdb / schema / schema_init.c
index 23b5fd9dcc130efb6e0fc71ff2117cf723d4793c..6f8958dab8f29b2486c53d24758eb5237aa78d8c 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
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
+
    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;
 
@@ -210,6 +343,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 +379,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 +410,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 +439,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,43 +482,61 @@ 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;
 
        obj->auxiliaryClass             = NULL;
-       obj->possSuperiors              = NULL;
-       obj->mustContain                = NULL;
-       obj->mayContain                 = NULL;
 
-       GET_STRING_LDB(msg, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, False);
+       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_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;
 }
@@ -427,13 +631,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,35 +694,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.uint32.num_values >= 1 \
-           && _a->value_ctr.uint32.values[0].value) { \
-               (p)->elem = *_a->value_ctr.uint32.values[0].value;\
+       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; \
        } \
@@ -483,14 +732,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 { \
@@ -501,9 +751,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);\
@@ -517,8 +767,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)) {
@@ -534,7 +784,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);
@@ -548,21 +798,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) {
@@ -579,8 +829,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)) {
@@ -592,10 +842,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;
@@ -607,18 +857,20 @@ 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;
 }
@@ -670,7 +922,22 @@ const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName(const struct dsdb
 
        /* TODO: add binary search */
        for (cur = schema->attributes; cur; cur = cur->next) {
-               if (strcmp(cur->lDAPDisplayName, name) != 0) continue;
+               if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue;
+
+               return cur;
+       }
+
+       return NULL;
+}
+
+const struct dsdb_attribute *dsdb_attribute_by_linkID(const struct dsdb_schema *schema,
+                                                     int linkID)
+{
+       struct dsdb_attribute *cur;
+
+       /* TODO: add binary search */
+       for (cur = schema->attributes; cur; cur = cur->next) {
+               if (cur->linkID != linkID) continue;
 
                return cur;
        }
@@ -725,7 +992,24 @@ const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema
 
        /* TODO: add binary search */
        for (cur = schema->classes; cur; cur = cur->next) {
-               if (strcmp(cur->lDAPDisplayName, name) != 0) continue;
+               if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue;
+
+               return cur;
+       }
+
+       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;
        }
@@ -752,3 +1036,241 @@ const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
 
        return NULL;
 }
+
+WERROR dsdb_linked_attribute_lDAPDisplayName_list(const struct dsdb_schema *schema, TALLOC_CTX *mem_ctx, const char ***attr_list_ret)
+{
+       const char **attr_list = NULL;
+       struct dsdb_attribute *cur;
+       int i = 0;
+       for (cur = schema->attributes; cur; cur = cur->next) {
+               if (cur->linkID == 0) continue;
+               
+               attr_list = talloc_realloc(mem_ctx, attr_list, const char *, i+2);
+               if (!attr_list) {
+                       return WERR_NOMEM;
+               }
+               attr_list[i] = cur->lDAPDisplayName;
+               i++;
+       }
+       attr_list[i] = NULL;
+       *attr_list_ret = attr_list;
+       return WERR_OK;
+}
+
+/**
+ * Attach the schema to an opaque pointer on the ldb, so ldb modules
+ * can find it 
+ */
+
+int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
+{
+       int ret;
+
+       ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       talloc_steal(ldb, schema);
+
+       return LDB_SUCCESS;
+}
+
+/**
+ * Global variable to hold one copy of the schema, used to avoid memory bloat
+ */
+static struct dsdb_schema *global_schema;
+
+/**
+ * Make this ldb use the 'global' schema, setup to avoid having multiple copies in this process
+ */
+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;
+}
+
+/**
+ * Find the schema object for this ldb
+ */
+
+struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb)
+{
+       const void *p;
+       struct dsdb_schema *schema;
+
+       /* see if we have a cached copy */
+       p = ldb_get_opaque(ldb, "dsdb_schema");
+       if (!p) {
+               return NULL;
+       }
+
+       schema = talloc_get_type(p, struct dsdb_schema);
+       if (!schema) {
+               return NULL;
+       }
+
+       return schema;
+}
+
+/**
+ * Make the schema found on this ldb the 'global' schema
+ */
+
+void dsdb_make_schema_global(struct ldb_context *ldb)
+{
+       struct dsdb_schema *schema = dsdb_get_schema(ldb);
+       if (!schema) {
+               return;
+       }
+
+       talloc_steal(talloc_autofree_context(), schema);
+       global_schema = schema;
+
+       dsdb_set_global_schema(ldb);
+}
+
+
+/**
+ * Rather than read a schema from the LDB itself, read it from an ldif
+ * file.  This allows schema to be loaded and used while adding the
+ * schema itself to the directory.
+ */
+
+WERROR dsdb_attach_schema_from_ldif_file(struct ldb_context *ldb, const char *pf, const char *df)
+{
+       struct ldb_ldif *ldif;
+       struct ldb_message *msg;
+       TALLOC_CTX *mem_ctx;
+       WERROR status;
+       int ret;
+       struct dsdb_schema *schema;
+       const struct ldb_val *prefix_val;
+       const struct ldb_val *info_val;
+       struct ldb_val info_val_default;
+
+       mem_ctx = talloc_new(ldb);
+       if (!mem_ctx) {
+               goto nomem;
+       }
+
+       schema = dsdb_new_schema(mem_ctx, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")));
+
+       schema->fsmo.we_are_master = true;
+       schema->fsmo.master_dn = ldb_dn_new_fmt(schema, ldb, "@PROVISION_SCHEMA_MASTER");
+       if (!schema->fsmo.master_dn) {
+               goto nomem;
+       }
+
+       /*
+        * load the prefixMap attribute from pf
+        */
+       ldif = ldb_ldif_read_string(ldb, &pf);
+       if (!ldif) {
+               status = WERR_INVALID_PARAM;
+               goto failed;
+       }
+       talloc_steal(mem_ctx, ldif);
+
+       msg = ldb_msg_canonicalize(ldb, ldif->msg);
+       if (!msg) {
+               goto nomem;
+       }
+       talloc_steal(mem_ctx, msg);
+       talloc_free(ldif);
+
+       prefix_val = ldb_msg_find_ldb_val(msg, "prefixMap");
+       if (!prefix_val) {
+               status = WERR_INVALID_PARAM;
+               goto failed;
+       }
+
+       info_val = ldb_msg_find_ldb_val(msg, "schemaInfo");
+       if (!info_val) {
+               info_val_default = strhex_to_data_blob("FF0000000000000000000000000000000000000000");
+               if (!info_val_default.data) {
+                       goto nomem;
+               }
+               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)) {
+               goto failed;
+       }
+
+       /*
+        * load the attribute and class definitions outof df
+        */
+       while ((ldif = ldb_ldif_read_string(ldb, &df))) {
+               bool is_sa;
+               bool is_sc;
+
+               talloc_steal(mem_ctx, ldif);
+
+               msg = ldb_msg_canonicalize(ldb, ldif->msg);
+               if (!msg) {
+                       goto nomem;
+               }
+
+               talloc_steal(mem_ctx, msg);
+               talloc_free(ldif);
+
+               is_sa = ldb_msg_check_string_attribute(msg, "objectClass", "attributeSchema");
+               is_sc = ldb_msg_check_string_attribute(msg, "objectClass", "classSchema");
+
+               if (is_sa) {
+                       struct dsdb_attribute *sa;
+
+                       sa = talloc_zero(schema, struct dsdb_attribute);
+                       if (!sa) {
+                               goto nomem;
+                       }
+
+                       status = dsdb_attribute_from_ldb(schema, msg, sa, sa);
+                       if (!W_ERROR_IS_OK(status)) {
+                               goto failed;
+                       }
+
+                       DLIST_ADD_END(schema->attributes, sa, struct dsdb_attribute *);
+               } else if (is_sc) {
+                       struct dsdb_class *sc;
+
+                       sc = talloc_zero(schema, struct dsdb_class);
+                       if (!sc) {
+                               goto nomem;
+                       }
+
+                       status = dsdb_class_from_ldb(schema, msg, sc, sc);
+                       if (!W_ERROR_IS_OK(status)) {
+                               goto failed;
+                       }
+
+                       DLIST_ADD_END(schema->classes, sc, struct dsdb_class *);
+               }
+       }
+
+       ret = dsdb_set_schema(ldb, schema);
+       if (ret != LDB_SUCCESS) {
+               status = WERR_FOOBAR;
+               goto failed;
+       }
+
+       goto done;
+
+nomem:
+       status = WERR_NOMEM;
+failed:
+done:
+       talloc_free(mem_ctx);
+       return status;
+}