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 "librpc/gen_ndr/ndr_misc.h"
#include "librpc/gen_ndr/ndr_drsuapi.h"
#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "param/param.h"
+
+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)
{
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, 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(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);
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.oid = 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(pfm.ctr.dsdb.mappings);
+ talloc_free(mem_ctx);
+
W_ERROR_NOT_OK_RETURN(status);
return WERR_OK;
struct drsuapi_DsReplicaOIDMapping_Ctr **_ctr)
{
struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
- uint32_t i,j;
+ uint32_t i;
ctr = talloc(mem_ctx, struct drsuapi_DsReplicaOIDMapping_Ctr);
W_ERROR_HAVE_NO_MEMORY(ctr);
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[j].oid,
+ schema->prefixes[i].oid,
schema->prefixes[i].oid_len - 1);
W_ERROR_HAVE_NO_MEMORY(ctr->mappings[i].oid.oid);
}
struct ldb_val *schemaInfo)
{
WERROR status;
- NTSTATUS nt_status;
+ enum ndr_err_code ndr_err;
struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
struct prefixMapBlob pfm;
W_ERROR_NOT_OK_RETURN(status);
pfm.version = PREFIX_MAP_VERSION_DSDB;
+ 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, schema->iconv_convenience, &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);
}
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)
+{
+ /*
+ * TODO:
+ * - (maybe) read the old prefixMap attribute and parse it
+ *
+ * - recheck the prefix doesn't exist (because the ldb
+ * has maybe a more uptodate value than schem->prefixes
+ *
+ * - calculate a new mapping for the oid prefix of full_oid
+ * - store the new prefixMap attribute
+ *
+ * - (maybe) update schema->prefixes
+ * or
+ * - better find a way to indicate a schema reload,
+ * so that other processes also notice the schema change
+ */
+ return WERR_NOT_SUPPORTED;
+}
+
#define GET_STRING_LDB(msg, attr, mem_ctx, p, elem, strict) do { \
(p)->elem = samdb_result_string(msg, attr, NULL);\
if (strict && (p)->elem == NULL) { \
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);\
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; \
}\
} 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);
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) {
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_LDB(msg, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, 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;
}
+#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");
+ talloc_free(mem_ctx);
+ 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));
+ talloc_free(mem_ctx);
+ 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));
+ talloc_free(mem_ctx);
+ 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));
+ talloc_free(mem_ctx);
+ 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) {
+ printf("Search failed: %s\n", ldb_errstring(ldb));
+ 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)
+{
+ 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;
+ }
+
+ /* Downlaod 'top' */
+ ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE,
+ "(&(objectClass=classSchema)(lDAPDisplayName=top))",
+ NULL, &top_res);
+ if (ret != LDB_SUCCESS) {
+ printf("Search failed: %s\n", ldb_errstring(ldb));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ talloc_steal(local_ctx, top_res);
+
+ if (top_res->count != 1) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ 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) {
+ printf("Search failed: %s\n", ldb_errstring(ldb));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ *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);
+ if (ret != LDB_SUCCESS) {
+ *error_string_out = talloc_asprintf(mem_ctx,
+ "Failed to fetch objectClass schema elements: %s\n", ldb_errstring(ldb));
+ 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;
} \
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, 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 (_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, s->iconv_convenience, &_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; \
} \
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) { \
} \
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)
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, 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 { \
{
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)) {
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);
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) {
{
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)) {
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;
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;
}
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)
{
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)
{
return NULL;
}
+/**
+ Return a list of linked attributes, in lDAPDisplayName format.
+
+ This may be used to determine if a modification would require
+ backlinks to be updated, for example
+*/
+
+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;
+}
+
+static char **merge_attr_list(TALLOC_CTX *mem_ctx,
+ char **attrs, const char **new_attrs)
+{
+ char **ret_attrs;
+ int i;
+ size_t new_len, orig_len = str_list_length((const char **)attrs);
+ if (!new_attrs) {
+ return attrs;
+ }
+
+ ret_attrs = talloc_realloc(mem_ctx,
+ attrs, char *, orig_len + str_list_length(new_attrs) + 1);
+ if (ret_attrs) {
+ for (i=0; i < str_list_length(new_attrs); i++) {
+ ret_attrs[orig_len + i] = new_attrs[i];
+ }
+ new_len = orig_len + str_list_length(new_attrs);
+
+ ret_attrs[new_len] = NULL;
+
+ }
+
+ return ret_attrs;
+}
+
+char **dsdb_full_attribute_list_internal(TALLOC_CTX *mem_ctx,
+ const struct dsdb_schema *schema,
+ const char **class_list,
+ enum dsdb_attr_list_query query)
+{
+ int i;
+ const struct dsdb_class *class;
+
+ char **attr_list = NULL;
+ char **recursive_list;
+
+ for (i=0; class_list && class_list[i]; i++) {
+ class = dsdb_class_by_lDAPDisplayName(schema, class_list[i]);
+
+ switch (query) {
+ case DSDB_SCHEMA_ALL_MAY:
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->mayContain);
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMayContain);
+ break;
+
+ case DSDB_SCHEMA_ALL_MUST:
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->mustContain);
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMustContain);
+ break;
+
+ case DSDB_SCHEMA_SYS_MAY:
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMayContain);
+ break;
+
+ case DSDB_SCHEMA_SYS_MUST:
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMustContain);
+ break;
+
+ case DSDB_SCHEMA_MAY:
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->mayContain);
+ break;
+
+ case DSDB_SCHEMA_MUST:
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->mustContain);
+ break;
+
+ case DSDB_SCHEMA_ALL:
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->mayContain);
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMayContain);
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->mustContain);
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMustContain);
+ break;
+ }
+
+ recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema,
+ class->systemAuxiliaryClass,
+ query);
+
+ attr_list = merge_attr_list(mem_ctx, attr_list, (const char **)recursive_list);
+
+ recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema,
+ class->auxiliaryClass,
+ query);
+
+ attr_list = merge_attr_list(mem_ctx, attr_list, (const char **)recursive_list);
+
+ }
+ return attr_list;
+}
+
+char **dsdb_full_attribute_list(TALLOC_CTX *mem_ctx,
+ const struct dsdb_schema *schema,
+ const char **class_list,
+ enum dsdb_attr_list_query query)
+{
+ char **attr_list = dsdb_full_attribute_list_internal(mem_ctx, schema, class_list, query);
+ size_t new_len = str_list_length((const char **)attr_list);
+
+ /* Remove duplicates */
+ if (new_len > 1) {
+ int i;
+ qsort(attr_list, new_len,
+ sizeof(*attr_list),
+ (comparison_fn_t)strcasecmp);
+
+ for (i=1 ; i < new_len; i++) {
+ char **val1 = &attr_list[i-1];
+ char **val2 = &attr_list[i];
+ if (ldb_attr_cmp(*val1, *val2) == 0) {
+ memmove(val1, val2, (new_len - i) * sizeof( *attr_list));
+ new_len--;
+ i--;
+ }
+ }
+ }
+ return attr_list;
+}
+/**
+ * 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;
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");
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;
+}