r26697: Leak less memory into the ldb context.
[samba.git] / source4 / dsdb / schema / schema_init.c
index b609478f94afa70e0bd15b61cc0bef069666c37c..6a7463951e57a03ff658e73f0950693d14bfbca1 100644 (file)
@@ -3,10 +3,11 @@
    DSDB schema header
    
    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,
@@ -15,8 +16,7 @@
    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/>.
    
 */
 
@@ -27,6 +27,7 @@
 #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_drsuapi(struct dsdb_schema *schema, const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
 {
@@ -80,27 +81,34 @@ WERROR dsdb_load_oid_mappings_ldb(struct dsdb_schema *schema,
                                  const struct ldb_val *schemaInfo)
 {
        WERROR status;
-       NTSTATUS nt_status;
+       enum ndr_err_code ndr_err;
        struct prefixMapBlob pfm;
        char *schema_info;
 
-       nt_status = ndr_pull_struct_blob(prefixMap, schema, &pfm,
-                                        (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
-       if (!NT_STATUS_IS_OK(nt_status)) {
+       TALLOC_CTX *mem_ctx = talloc_new(schema);
+       W_ERROR_HAVE_NO_MEMORY(mem_ctx);
+       
+       ndr_err = ndr_pull_struct_blob(prefixMap, mem_ctx, lp_iconv_convenience(global_loadparm), &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(schema, pfm.ctr.dsdb.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);
@@ -114,7 +122,8 @@ WERROR dsdb_load_oid_mappings_ldb(struct dsdb_schema *schema,
 
        /* call the drsuapi version */
        status = dsdb_load_oid_mappings_drsuapi(schema, &pfm.ctr.dsdb);
-       talloc_free(pfm.ctr.dsdb.mappings);
+       talloc_free(mem_ctx);
+
        W_ERROR_NOT_OK_RETURN(status);
 
        return WERR_OK;
@@ -161,7 +170,7 @@ WERROR dsdb_get_oid_mappings_ldb(const struct dsdb_schema *schema,
                                 struct ldb_val *schemaInfo)
 {
        WERROR status;
-       NTSTATUS nt_status;
+       enum ndr_err_code ndr_err;
        struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
        struct prefixMapBlob pfm;
 
@@ -172,10 +181,11 @@ WERROR dsdb_get_oid_mappings_ldb(const struct dsdb_schema *schema,
        pfm.reserved    = 0;
        pfm.ctr.dsdb    = *ctr;
 
-       nt_status = ndr_push_struct_blob(prefixMap, mem_ctx, &pfm,
-                                        (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
+       ndr_err = ndr_push_struct_blob(prefixMap, mem_ctx, lp_iconv_convenience(global_loadparm), &pfm,
+                                      (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
        talloc_free(ctr);
-       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);
        }
 
@@ -323,6 +333,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);\
@@ -331,12 +369,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; \
@@ -369,9 +407,9 @@ WERROR dsdb_attribute_from_ldb(const struct dsdb_schema *schema,
 {
        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);
+       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;
@@ -391,10 +429,10 @@ WERROR dsdb_attribute_from_ldb(const struct dsdb_schema *schema,
 
        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);
+       GET_STRING_LDB(msg, "attributeSyntax", mem_ctx, attr, attributeSyntax_oid, true);
        if (schema->num_prefixes == 0) {
                /* set an invalid value */
                attr->attributeSyntax_id = 0xFFFFFFFF;
@@ -410,21 +448,21 @@ WERROR dsdb_attribute_from_ldb(const struct dsdb_schema *schema,
        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) {
@@ -441,9 +479,9 @@ WERROR dsdb_class_from_ldb(const struct dsdb_schema *schema,
 {
        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);
+       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;
@@ -459,33 +497,36 @@ WERROR dsdb_class_from_ldb(const struct dsdb_schema *schema,
        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;
 }
@@ -587,7 +628,7 @@ static struct drsuapi_DsReplicaAttribute *dsdb_find_object_attr_name(struct dsdb
        } \
        if (_a && _a->value_ctr.num_values >= 1) { \
                ssize_t _ret; \
-               _ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, \
+               _ret = convert_string_talloc(mem_ctx, lp_iconv_convenience(global_loadparm), CH_UTF16, CH_UNIX, \
                                             _a->value_ctr.values[0].blob->data, \
                                             _a->value_ctr.values[0].blob->length, \
                                             (void **)discard_const(&(p)->elem)); \
@@ -622,11 +663,12 @@ static struct drsuapi_DsReplicaAttribute *dsdb_find_object_attr_name(struct dsdb
        if (_a && _a->value_ctr.num_values >= 1 \
            && _a->value_ctr.values[0].blob) { \
                struct drsuapi_DsReplicaObjectIdentifier3 _id3; \
-               NTSTATUS _nt_status; \
-               _nt_status = ndr_pull_struct_blob_all(_a->value_ctr.values[0].blob, \
-                                                     mem_ctx, &_id3,\
+               enum ndr_err_code _ndr_err; \
+               _ndr_err = ndr_pull_struct_blob_all(_a->value_ctr.values[0].blob, \
+                                                     mem_ctx, lp_iconv_convenience(global_loadparm), &_id3,\
                                                      (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);\
-               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); \
                } \
                (p)->elem = _id3.dn; \
@@ -644,7 +686,7 @@ static struct drsuapi_DsReplicaAttribute *dsdb_find_object_attr_name(struct dsdb
        } \
        if (strict && _a->value_ctr.num_values != 1) { \
                d_printf("%s: %s num_values == %u\n", __location__, attr, \
-                       _a->value_ctr.num_values); \
+                        (unsigned int)_a->value_ctr.num_values);       \
                return WERR_INVALID_PARAM; \
        } \
        if (strict && !_a->value_ctr.values[0].blob) { \
@@ -653,15 +695,15 @@ static struct drsuapi_DsReplicaAttribute *dsdb_find_object_attr_name(struct dsdb
        } \
        if (strict && _a->value_ctr.values[0].blob->length != 4) { \
                d_printf("%s: %s length == %u\n", __location__, attr, \
-                       _a->value_ctr.values[0].blob->length); \
+                        (unsigned int)_a->value_ctr.values[0].blob->length); \
                return WERR_INVALID_PARAM; \
        } \
        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);\
+               (p)->elem = (IVAL(_a->value_ctr.values[0].blob->data,0)?true:false);\
        } else { \
-               (p)->elem = False; \
+               (p)->elem = false; \
        } \
 } while (0)
 
@@ -683,11 +725,12 @@ static struct drsuapi_DsReplicaAttribute *dsdb_find_object_attr_name(struct dsdb
        if (_a && _a->value_ctr.num_values >= 1 \
            && _a->value_ctr.values[0].blob \
            && _a->value_ctr.values[0].blob->length == 16) { \
-               NTSTATUS _nt_status; \
-               _nt_status = ndr_pull_struct_blob_all(_a->value_ctr.values[0].blob, \
-                                                     mem_ctx, &(p)->elem, \
+               enum ndr_err_code _ndr_err; \
+               _ndr_err = ndr_pull_struct_blob_all(_a->value_ctr.values[0].blob, \
+                                                     mem_ctx, lp_iconv_convenience(global_loadparm), &(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 { \
@@ -714,8 +757,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)) {
@@ -731,7 +774,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);
@@ -745,21 +788,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) {
@@ -776,8 +819,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)) {
@@ -789,10 +832,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_DN_DS(schema, r, "defaultObjectCategory", mem_ctx, obj, defaultObjectCategory, 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);
+       GET_STRING_DS(schema, r, "subClassOf", mem_ctx, obj, subClassOf, true);
 
        obj->systemAuxiliaryClass       = NULL;
        obj->systemPossSuperiors        = NULL;
@@ -804,18 +847,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;
 }
@@ -875,6 +920,21 @@ const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName(const struct dsdb
        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;
+       }
+
+       return NULL;
+}
+
 const struct dsdb_class *dsdb_class_by_governsID_id(const struct dsdb_schema *schema,
                                                    uint32_t id)
 {
@@ -930,6 +990,23 @@ const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema
        return NULL;
 }
 
+const struct dsdb_class *dsdb_class_by_cn(const struct dsdb_schema *schema,
+                                         const char *cn)
+{
+       struct dsdb_class *cur;
+
+       if (!cn) return NULL;
+
+       /* TODO: add binary search */
+       for (cur = schema->classes; cur; cur = cur->next) {
+               if (strcasecmp(cur->cn, cn) != 0) continue;
+
+               return cur;
+       }
+
+       return NULL;
+}
+
 const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
                                       uint32_t id)
 {
@@ -950,6 +1027,31 @@ 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;
@@ -964,10 +1066,36 @@ int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
        return LDB_SUCCESS;
 }
 
-const struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb)
+/**
+ * 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;
-       const struct dsdb_schema *schema;
+       struct dsdb_schema *schema;
 
        /* see if we have a cached copy */
        p = ldb_get_opaque(ldb, "dsdb_schema");
@@ -983,6 +1111,30 @@ const struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb)
        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;
@@ -1019,6 +1171,8 @@ WERROR dsdb_attach_schema_from_ldif_file(struct ldb_context *ldb, const char *pf
        if (!msg) {
                goto nomem;
        }
+       talloc_steal(mem_ctx, msg);
+       talloc_free(ldif);
 
        prefix_val = ldb_msg_find_ldb_val(msg, "prefixMap");
        if (!prefix_val) {
@@ -1055,6 +1209,9 @@ WERROR dsdb_attach_schema_from_ldif_file(struct ldb_context *ldb, const char *pf
                        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");