summaryrefslogtreecommitdiff
path: root/source4/dsdb/schema
diff options
context:
space:
mode:
Diffstat (limited to 'source4/dsdb/schema')
-rw-r--r--source4/dsdb/schema/schema.h183
-rw-r--r--source4/dsdb/schema/schema_description.c316
-rw-r--r--source4/dsdb/schema/schema_init.c1411
-rw-r--r--source4/dsdb/schema/schema_query.c344
-rw-r--r--source4/dsdb/schema/schema_set.c409
-rw-r--r--source4/dsdb/schema/schema_syntax.c1426
6 files changed, 4089 insertions, 0 deletions
diff --git a/source4/dsdb/schema/schema.h b/source4/dsdb/schema/schema.h
new file mode 100644
index 0000000000..68dc8197cb
--- /dev/null
+++ b/source4/dsdb/schema/schema.h
@@ -0,0 +1,183 @@
+/*
+ Unix SMB/CIFS mplementation.
+ DSDB schema header
+
+ Copyright (C) Stefan Metzmacher <metze@samba.org> 2006
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _DSDB_SCHEMA_H
+#define _DSDB_SCHEMA_H
+
+struct dsdb_attribute;
+struct dsdb_class;
+struct dsdb_schema;
+
+struct dsdb_syntax {
+ const char *name;
+ const char *ldap_oid;
+ uint32_t oMSyntax;
+ struct ldb_val oMObjectClass;
+ const char *attributeSyntax_oid;
+ const char *equality;
+ const char *substring;
+ const char *comment;
+ const char *ldb_syntax;
+
+ WERROR (*drsuapi_to_ldb)(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct drsuapi_DsReplicaAttribute *in,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *out);
+ WERROR (*ldb_to_drsuapi)(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct ldb_message_element *in,
+ TALLOC_CTX *mem_ctx,
+ struct drsuapi_DsReplicaAttribute *out);
+};
+
+struct dsdb_attribute {
+ struct dsdb_attribute *prev, *next;
+
+ const char *cn;
+ const char *lDAPDisplayName;
+ const char *attributeID_oid;
+ uint32_t attributeID_id;
+ struct GUID schemaIDGUID;
+ uint32_t mAPIID;
+
+ struct GUID attributeSecurityGUID;
+
+ uint32_t searchFlags;
+ uint32_t systemFlags;
+ bool isMemberOfPartialAttributeSet;
+ uint32_t linkID;
+
+ const char *attributeSyntax_oid;
+ uint32_t attributeSyntax_id;
+ uint32_t oMSyntax;
+ struct ldb_val oMObjectClass;
+
+ bool isSingleValued;
+ uint32_t rangeLower;
+ uint32_t rangeUpper;
+ bool extendedCharsAllowed;
+
+ uint32_t schemaFlagsEx;
+ struct ldb_val msDs_Schema_Extensions;
+
+ bool showInAdvancedViewOnly;
+ const char *adminDisplayName;
+ const char *adminDescription;
+ const char *classDisplayName;
+ bool isEphemeral;
+ bool isDefunct;
+ bool systemOnly;
+
+ /* internal stuff */
+ const struct dsdb_syntax *syntax;
+};
+
+struct dsdb_class {
+ struct dsdb_class *prev, *next;
+
+ const char *cn;
+ const char *lDAPDisplayName;
+ const char *governsID_oid;
+ uint32_t governsID_id;
+ struct GUID schemaIDGUID;
+
+ uint32_t objectClassCategory;
+ const char *rDNAttID;
+ const char *defaultObjectCategory;
+
+ const char *subClassOf;
+
+ const char **systemAuxiliaryClass;
+ const char **systemPossSuperiors;
+ const char **systemMustContain;
+ const char **systemMayContain;
+
+ const char **auxiliaryClass;
+ const char **possSuperiors;
+ const char **mustContain;
+ const char **mayContain;
+ const char **possibleInferiors;
+
+ const char *defaultSecurityDescriptor;
+
+ uint32_t schemaFlagsEx;
+ struct ldb_val msDs_Schema_Extensions;
+
+ bool showInAdvancedViewOnly;
+ const char *adminDisplayName;
+ const char *adminDescription;
+ const char *classDisplayName;
+ bool defaultHidingValue;
+ bool isDefunct;
+ bool systemOnly;
+};
+
+struct dsdb_schema_oid_prefix {
+ uint32_t id;
+ const char *oid;
+ size_t oid_len;
+};
+
+struct dsdb_schema {
+ uint32_t num_prefixes;
+ struct dsdb_schema_oid_prefix *prefixes;
+
+ /*
+ * the last element of the prefix mapping table isn't a oid,
+ * it starts with 0xFF and has 21 bytes and is maybe a schema
+ * version number
+ *
+ * this is the content of the schemaInfo attribute of the
+ * Schema-Partition head object.
+ */
+ const char *schema_info;
+
+ struct dsdb_attribute *attributes;
+ struct dsdb_class *classes;
+
+ struct {
+ bool we_are_master;
+ struct ldb_dn *master_dn;
+ } fsmo;
+
+ struct smb_iconv_convenience *iconv_convenience;
+};
+
+enum dsdb_attr_list_query {
+ DSDB_SCHEMA_ALL_MAY,
+ DSDB_SCHEMA_ALL_MUST,
+ DSDB_SCHEMA_SYS_MAY,
+ DSDB_SCHEMA_SYS_MUST,
+ DSDB_SCHEMA_MAY,
+ DSDB_SCHEMA_MUST,
+ DSDB_SCHEMA_ALL
+};
+
+enum dsdb_schema_convert_target {
+ TARGET_OPENLDAP,
+ TARGET_FEDORA_DS,
+ TARGET_AD_SCHEMA_SUBENTRY
+};
+
+#include "dsdb/schema/proto.h"
+
+#endif /* _DSDB_SCHEMA_H */
diff --git a/source4/dsdb/schema/schema_description.c b/source4/dsdb/schema/schema_description.c
new file mode 100644
index 0000000000..6884c5284e
--- /dev/null
+++ b/source4/dsdb/schema/schema_description.c
@@ -0,0 +1,316 @@
+/*
+ Unix SMB/CIFS mplementation.
+ Print schema info into string format
+
+ Copyright (C) Andrew Bartlett 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+
+*/
+#include "includes.h"
+#include "dsdb/samdb/samdb.h"
+
+#define IF_NULL_FAIL_RET(x) do { \
+ if (!x) { \
+ return NULL; \
+ } \
+ } while (0)
+
+
+char *schema_attribute_description(TALLOC_CTX *mem_ctx,
+ enum dsdb_schema_convert_target target,
+ const char *seperator,
+ const char *oid,
+ const char *name,
+ const char *description,
+ const char *equality,
+ const char *substring,
+ const char *syntax,
+ bool single_value, bool operational)
+{
+ char *schema_entry = talloc_asprintf(mem_ctx,
+ "(%s%s%s", seperator, oid, seperator);
+
+ schema_entry = talloc_asprintf_append(schema_entry,
+ "NAME '%s'%s", name, seperator);
+ IF_NULL_FAIL_RET(schema_entry);
+
+ if (description) {
+#if 0
+ /* Need a way to escape ' characters from the description */
+ schema_entry = talloc_asprintf_append(schema_entry,
+ "DESC '%s'%s", description, seperator);
+ IF_NULL_FAIL_RET(schema_entry);
+#endif
+ }
+
+ if (equality) {
+ schema_entry = talloc_asprintf_append(schema_entry,
+ "EQUALITY %s%s", equality, seperator);
+ IF_NULL_FAIL_RET(schema_entry);
+ }
+ if (substring) {
+ schema_entry = talloc_asprintf_append(schema_entry,
+ "SUBSTR %s%s", substring, seperator);
+ IF_NULL_FAIL_RET(schema_entry);
+ }
+
+ schema_entry = talloc_asprintf_append(schema_entry,
+ "SYNTAX %s%s", syntax, seperator);
+ IF_NULL_FAIL_RET(schema_entry);
+
+ if (single_value) {
+ schema_entry = talloc_asprintf_append(schema_entry,
+ "SINGLE-VALUE%s", seperator);
+ IF_NULL_FAIL_RET(schema_entry);
+ }
+
+ if (operational) {
+ schema_entry = talloc_asprintf_append(schema_entry,
+ "NO-USER-MODIFICATION%s", seperator);
+ IF_NULL_FAIL_RET(schema_entry);
+ }
+
+ schema_entry = talloc_asprintf_append(schema_entry,
+ ")");
+ return schema_entry;
+}
+
+char *schema_attribute_to_description(TALLOC_CTX *mem_ctx, const struct dsdb_attribute *attribute)
+{
+ char *schema_description;
+ const struct dsdb_syntax *map = find_syntax_map_by_ad_oid(attribute->attributeSyntax_oid);
+ const char *syntax = map ? map->ldap_oid : attribute->attributeSyntax_oid;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ if (!tmp_ctx) {
+ return NULL;
+ }
+
+
+ schema_description
+ = schema_attribute_description(mem_ctx,
+ TARGET_AD_SCHEMA_SUBENTRY,
+ " ",
+ attribute->attributeID_oid,
+ attribute->lDAPDisplayName,
+ NULL, NULL, NULL, talloc_asprintf(tmp_ctx, "'%s'", syntax),
+ attribute->isSingleValued,
+ attribute->systemOnly);
+ talloc_free(tmp_ctx);
+ return schema_description;
+}
+
+#define APPEND_ATTRS(attributes) \
+ do { \
+ int k; \
+ for (k=0; attributes && attributes[k]; k++) { \
+ const char *attr_name = attributes[k]; \
+ \
+ schema_entry = talloc_asprintf_append(schema_entry, \
+ "%s ", \
+ attr_name); \
+ IF_NULL_FAIL_RET(schema_entry); \
+ if (attributes[k+1]) { \
+ IF_NULL_FAIL_RET(schema_entry); \
+ if (target == TARGET_OPENLDAP && ((k+1)%5 == 0)) { \
+ schema_entry = talloc_asprintf_append(schema_entry, \
+ "$%s ", seperator); \
+ IF_NULL_FAIL_RET(schema_entry); \
+ } else { \
+ schema_entry = talloc_asprintf_append(schema_entry, \
+ "$ "); \
+ } \
+ } \
+ } \
+ } while (0)
+
+
+/* Print a schema class or dITContentRule as a string.
+ *
+ * To print a scheam class, specify objectClassCategory but not auxillary_classes
+ * To print a dITContentRule, specify auxillary_classes but set objectClassCategory == -1
+ *
+ */
+
+char *schema_class_description(TALLOC_CTX *mem_ctx,
+ enum dsdb_schema_convert_target target,
+ const char *seperator,
+ const char *oid,
+ const char *name,
+ const char **auxillary_classes,
+ const char *description,
+ const char *subClassOf,
+ int objectClassCategory,
+ char **must,
+ char **may)
+{
+ char *schema_entry = talloc_asprintf(mem_ctx,
+ "(%s%s%s", seperator, oid, seperator);
+
+ IF_NULL_FAIL_RET(schema_entry);
+
+ schema_entry = talloc_asprintf_append(schema_entry,
+ "NAME '%s'%s", name, seperator);
+ IF_NULL_FAIL_RET(schema_entry);
+
+ if (description) {
+ schema_entry = talloc_asprintf_append(schema_entry,
+ "DESC '%s'%s", description, seperator);
+ IF_NULL_FAIL_RET(schema_entry);
+ }
+
+ if (auxillary_classes) {
+ schema_entry = talloc_asprintf_append(schema_entry,
+ "AUX ( ");
+ IF_NULL_FAIL_RET(schema_entry);
+
+ APPEND_ATTRS(auxillary_classes);
+
+ schema_entry = talloc_asprintf_append(schema_entry,
+ ")%s", seperator);
+ IF_NULL_FAIL_RET(schema_entry);
+ }
+
+ if (subClassOf && strcasecmp(subClassOf, name) != 0) {
+ schema_entry = talloc_asprintf_append(schema_entry,
+ "SUP %s%s", subClassOf, seperator);
+ IF_NULL_FAIL_RET(schema_entry);
+ }
+
+ switch (objectClassCategory) {
+ case -1:
+ break;
+ /* Dummy case for when used for printing ditContentRules */
+ case 0:
+ /*
+ * NOTE: this is an type 88 class
+ * e.g. 2.5.6.6 NAME 'person'
+ * but w2k3 gives STRUCTURAL here!
+ */
+ schema_entry = talloc_asprintf_append(schema_entry,
+ "STRUCTURAL%s", seperator);
+ IF_NULL_FAIL_RET(schema_entry);
+ break;
+ case 1:
+ schema_entry = talloc_asprintf_append(schema_entry,
+ "STRUCTURAL%s", seperator);
+ IF_NULL_FAIL_RET(schema_entry);
+ break;
+ case 2:
+ schema_entry = talloc_asprintf_append(schema_entry,
+ "ABSTRACT%s", seperator);
+ IF_NULL_FAIL_RET(schema_entry);
+ break;
+ case 3:
+ schema_entry = talloc_asprintf_append(schema_entry,
+ "AUXILIARY%s", seperator);
+ IF_NULL_FAIL_RET(schema_entry);
+ break;
+ }
+
+ if (must) {
+ schema_entry = talloc_asprintf_append(schema_entry,
+ "MUST (%s", target == TARGET_AD_SCHEMA_SUBENTRY ? "" : " ");
+ IF_NULL_FAIL_RET(schema_entry);
+
+ APPEND_ATTRS(must);
+
+ schema_entry = talloc_asprintf_append(schema_entry,
+ ")%s", seperator);
+ IF_NULL_FAIL_RET(schema_entry);
+ }
+
+ if (may) {
+ schema_entry = talloc_asprintf_append(schema_entry,
+ "MAY (%s", target == TARGET_AD_SCHEMA_SUBENTRY ? "" : " ");
+ IF_NULL_FAIL_RET(schema_entry);
+
+ APPEND_ATTRS(may);
+
+ schema_entry = talloc_asprintf_append(schema_entry,
+ ")%s", seperator);
+ IF_NULL_FAIL_RET(schema_entry);
+ }
+
+ schema_entry = talloc_asprintf_append(schema_entry,
+ ")");
+ return schema_entry;
+}
+
+char *schema_class_to_description(TALLOC_CTX *mem_ctx, const struct dsdb_class *class)
+{
+ char *schema_description;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ if (!tmp_ctx) {
+ return NULL;
+ }
+
+ schema_description
+ = schema_class_description(mem_ctx,
+ TARGET_AD_SCHEMA_SUBENTRY,
+ " ",
+ class->governsID_oid,
+ class->lDAPDisplayName,
+ NULL,
+ NULL,
+ class->subClassOf,
+ class->objectClassCategory,
+ dsdb_attribute_list(tmp_ctx,
+ class, DSDB_SCHEMA_ALL_MUST),
+ dsdb_attribute_list(tmp_ctx,
+ class, DSDB_SCHEMA_ALL_MAY));
+ talloc_free(tmp_ctx);
+ return schema_description;
+}
+char *schema_class_to_dITContentRule(TALLOC_CTX *mem_ctx, const struct dsdb_class *class,
+ const struct dsdb_schema *schema)
+{
+ int i;
+ char *schema_description;
+ char **aux_class_list = NULL;
+ char **attrs;
+ char **must_attr_list = NULL;
+ char **may_attr_list = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ const struct dsdb_class *aux_class;
+ if (!tmp_ctx) {
+ return NULL;
+ }
+
+ aux_class_list = merge_attr_list(tmp_ctx, aux_class_list, class->systemAuxiliaryClass);
+ aux_class_list = merge_attr_list(tmp_ctx, aux_class_list, class->auxiliaryClass);
+
+ for (i=0; aux_class_list && aux_class_list[i]; i++) {
+ aux_class = dsdb_class_by_lDAPDisplayName(schema, aux_class_list[i]);
+
+ attrs = dsdb_attribute_list(mem_ctx, aux_class, DSDB_SCHEMA_ALL_MUST);
+ must_attr_list = merge_attr_list(mem_ctx, must_attr_list, attrs);
+
+ attrs = dsdb_attribute_list(mem_ctx, aux_class, DSDB_SCHEMA_ALL_MAY);
+ may_attr_list = merge_attr_list(mem_ctx, may_attr_list, attrs);
+ }
+
+ schema_description
+ = schema_class_description(mem_ctx,
+ TARGET_AD_SCHEMA_SUBENTRY,
+ " ",
+ class->governsID_oid,
+ class->lDAPDisplayName,
+ (const char **)aux_class_list,
+ NULL,
+ class->subClassOf,
+ -1, must_attr_list, may_attr_list);
+ talloc_free(tmp_ctx);
+ return schema_description;
+}
diff --git a/source4/dsdb/schema/schema_init.c b/source4/dsdb/schema/schema_init.c
new file mode 100644
index 0000000000..3ed7daee59
--- /dev/null
+++ b/source4/dsdb/schema/schema_init.c
@@ -0,0 +1,1411 @@
+/*
+ Unix SMB/CIFS mplementation.
+ DSDB schema header
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, 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"
+
+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;
+
+ schema->prefixes = talloc_array(schema, struct dsdb_schema_oid_prefix, ctr->num_mappings);
+ W_ERROR_HAVE_NO_MEMORY(schema->prefixes);
+
+ for (i=0, j=0; i < ctr->num_mappings; i++) {
+ if (ctr->mappings[i].oid.oid == NULL) {
+ return WERR_INVALID_PARAM;
+ }
+
+ if (strncasecmp(ctr->mappings[i].oid.oid, "ff", 2) == 0) {
+ if (ctr->mappings[i].id_prefix != 0) {
+ return WERR_INVALID_PARAM;
+ }
+
+ /* the magic value should be in the last array member */
+ if (i != (ctr->num_mappings - 1)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ if (ctr->mappings[i].oid.__ndr_size != 21) {
+ return WERR_INVALID_PARAM;
+ }
+
+ schema->schema_info = talloc_strdup(schema, ctr->mappings[i].oid.oid);
+ W_ERROR_HAVE_NO_MEMORY(schema->schema_info);
+ } else {
+ /* the last array member should contain the magic value not a oid */
+ if (i == (ctr->num_mappings - 1)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ schema->prefixes[j].id = ctr->mappings[i].id_prefix<<16;
+ schema->prefixes[j].oid = talloc_asprintf(schema->prefixes, "%s.",
+ ctr->mappings[i].oid.oid);
+ W_ERROR_HAVE_NO_MEMORY(schema->prefixes[j].oid);
+ schema->prefixes[j].oid_len = strlen(schema->prefixes[j].oid);
+ j++;
+ }
+ }
+
+ schema->num_prefixes = j;
+ return WERR_OK;
+}
+
+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;
+
+ for (i=0; i < ctr->num_mappings; i++) {
+ if (ctr->mappings[i].oid.oid == NULL) {
+ return WERR_INVALID_PARAM;
+ }
+
+ if (strncasecmp(ctr->mappings[i].oid.oid, "ff", 2) == 0) {
+ if (ctr->mappings[i].id_prefix != 0) {
+ return WERR_INVALID_PARAM;
+ }
+
+ /* the magic value should be in the last array member */
+ if (i != (ctr->num_mappings - 1)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ if (ctr->mappings[i].oid.__ndr_size != 21) {
+ return WERR_INVALID_PARAM;
+ }
+
+ if (strcasecmp(schema->schema_info, ctr->mappings[i].oid.oid) != 0) {
+ return WERR_DS_DRA_SCHEMA_MISMATCH;
+ }
+ } else {
+ /* the last array member should contain the magic value not a oid */
+ if (i == (ctr->num_mappings - 1)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ for (j=0; j < schema->num_prefixes; j++) {
+ size_t oid_len;
+ if (schema->prefixes[j].id != (ctr->mappings[i].id_prefix<<16)) {
+ continue;
+ }
+
+ oid_len = strlen(ctr->mappings[i].oid.oid);
+
+ if (oid_len != (schema->prefixes[j].oid_len - 1)) {
+ return WERR_DS_DRA_SCHEMA_MISMATCH;
+ }
+
+ if (strncmp(ctr->mappings[i].oid.oid, schema->prefixes[j].oid, oid_len) != 0) {
+ return WERR_DS_DRA_SCHEMA_MISMATCH;
+ }
+
+ break;
+ }
+
+ if (j == schema->num_prefixes) {
+ return WERR_DS_DRA_SCHEMA_MISMATCH;
+ }
+ }
+ }
+
+ return WERR_OK;
+}
+
+WERROR dsdb_map_oid2int(const struct dsdb_schema *schema, const char *in, uint32_t *out)
+{
+ return dsdb_find_prefix_for_oid(schema->num_prefixes, schema->prefixes, in, out);
+}
+
+
+WERROR dsdb_map_int2oid(const struct dsdb_schema *schema, uint32_t in, TALLOC_CTX *mem_ctx, const char **out)
+{
+ uint32_t i;
+
+ for (i=0; i < schema->num_prefixes; i++) {
+ const char *val;
+ if (schema->prefixes[i].id != (in & 0xFFFF0000)) {
+ continue;
+ }
+
+ val = talloc_asprintf(mem_ctx, "%s%u",
+ schema->prefixes[i].oid,
+ in & 0xFFFF);
+ W_ERROR_HAVE_NO_MEMORY(val);
+
+ *out = val;
+ return WERR_OK;
+ }
+
+ return WERR_DS_NO_MSDS_INTID;
+}
+
+/*
+ * this function is called from within a ldb transaction from the schema_fsmo module
+ */
+WERROR dsdb_create_prefix_mapping(struct ldb_context *ldb, struct dsdb_schema *schema, const char *full_oid)
+{
+ WERROR status;
+ uint32_t num_prefixes;
+ struct dsdb_schema_oid_prefix *prefixes;
+ TALLOC_CTX *mem_ctx;
+ uint32_t out;
+
+ mem_ctx = talloc_new(ldb);
+ W_ERROR_HAVE_NO_MEMORY(mem_ctx);
+
+ /* Read prefixes from disk*/
+ status = dsdb_read_prefixes_from_ldb( mem_ctx, ldb, &num_prefixes, &prefixes );
+ if (!W_ERROR_IS_OK(status)) {
+ DEBUG(0,("dsdb_create_prefix_mapping: dsdb_read_prefixes_from_ldb: %s\n",
+ win_errstr(status)));
+ talloc_free(mem_ctx);
+ return status;
+ }
+
+ /* Check if there is a prefix for the oid in the prefixes array*/
+ status = dsdb_find_prefix_for_oid( num_prefixes, prefixes, full_oid, &out );
+ if (W_ERROR_IS_OK(status)) {
+ /* prefix found*/
+ talloc_free(mem_ctx);
+ return status;
+ } else if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) {
+ /* error */
+ DEBUG(0,("dsdb_create_prefix_mapping: dsdb_find_prefix_for_oid: %s\n",
+ win_errstr(status)));
+ talloc_free(mem_ctx);
+ return status;
+ }
+
+ /* Create the new mapping for the prefix of full_oid */
+ status = dsdb_prefix_map_update(mem_ctx, &num_prefixes, &prefixes, full_oid);
+ if (!W_ERROR_IS_OK(status)) {
+ DEBUG(0,("dsdb_create_prefix_mapping: dsdb_prefix_map_update: %s\n",
+ win_errstr(status)));
+ talloc_free(mem_ctx);
+ return status;
+ }
+
+ /* Update prefixMap in ldb*/
+ status = dsdb_write_prefixes_to_ldb(mem_ctx, ldb, num_prefixes, prefixes);
+ if (!W_ERROR_IS_OK(status)) {
+ DEBUG(0,("dsdb_create_prefix_mapping: dsdb_write_prefixes_to_ldb: %s\n",
+ win_errstr(status)));
+ talloc_free(mem_ctx);
+ return status;
+ }
+
+ talloc_free(mem_ctx);
+ return status;
+}
+
+WERROR dsdb_prefix_map_update(TALLOC_CTX *mem_ctx, uint32_t *num_prefixes, struct dsdb_schema_oid_prefix **prefixes, const char *oid)
+{
+ uint32_t new_num_prefixes, index_new_prefix, new_entry_id;
+ const char* lastDotOffset;
+ size_t size;
+
+ new_num_prefixes = *num_prefixes + 1;
+ index_new_prefix = *num_prefixes;
+
+ /*
+ * this is the algorithm we use to create new mappings for now
+ *
+ * TODO: find what algorithm windows use
+ */
+ new_entry_id = (*num_prefixes)<<16;
+
+ /* Extract the prefix from the oid*/
+ lastDotOffset = strrchr(oid, '.');
+ if (lastDotOffset == NULL) {
+ DEBUG(0,("dsdb_prefix_map_update: failed to find the last dot\n"));
+ return WERR_NOT_FOUND;
+ }
+
+ /* Calculate the size of the remainig string that should be the prefix of it */
+ size = strlen(oid) - strlen(lastDotOffset);
+ if (size <= 0) {
+ DEBUG(0,("dsdb_prefix_map_update: size of the remaining string invalid\n"));
+ return WERR_FOOBAR;
+ }
+ /* Add one because we need to copy the dot */
+ size += 1;
+
+ /* Create a spot in the prefixMap for one more prefix*/
+ (*prefixes) = talloc_realloc(mem_ctx, *prefixes, struct dsdb_schema_oid_prefix, new_num_prefixes);
+ W_ERROR_HAVE_NO_MEMORY(*prefixes);
+
+ /* Add the new prefix entry*/
+ (*prefixes)[index_new_prefix].id = new_entry_id;
+ (*prefixes)[index_new_prefix].oid = talloc_strndup(mem_ctx, oid, size);
+ (*prefixes)[index_new_prefix].oid_len = strlen((*prefixes)[index_new_prefix].oid);
+
+ /* Increase num_prefixes because new prefix has been added */
+ ++(*num_prefixes);
+
+ return WERR_OK;
+}
+
+WERROR dsdb_find_prefix_for_oid(uint32_t num_prefixes, const struct dsdb_schema_oid_prefix *prefixes, const char *in, uint32_t *out)
+{
+ uint32_t i;
+
+ for (i=0; i < num_prefixes; i++) {
+ const char *val_str;
+ char *end_str;
+ unsigned val;
+
+ if (strncmp(prefixes[i].oid, in, prefixes[i].oid_len) != 0) {
+ continue;
+ }
+
+ val_str = in + prefixes[i].oid_len;
+ end_str = NULL;
+ errno = 0;
+
+ if (val_str[0] == '\0') {
+ return WERR_INVALID_PARAM;
+ }
+
+ /* two '.' chars are invalid */
+ if (val_str[0] == '.') {
+ return WERR_INVALID_PARAM;
+ }
+
+ val = strtoul(val_str, &end_str, 10);
+ if (end_str[0] == '.' && end_str[1] != '\0') {
+ /*
+ * if it's a '.' and not the last char
+ * then maybe an other mapping apply
+ */
+ continue;
+ } else if (end_str[0] != '\0') {
+ return WERR_INVALID_PARAM;
+ } else if (val > 0xFFFF) {
+ return WERR_INVALID_PARAM;
+ }
+
+ *out = prefixes[i].id | val;
+ return WERR_OK;
+ }
+
+ return WERR_DS_NO_MSDS_INTID;
+}
+
+WERROR dsdb_write_prefixes_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
+ uint32_t num_prefixes,
+ const struct dsdb_schema_oid_prefix *prefixes)
+{
+ struct ldb_message msg;
+ struct ldb_dn *schema_dn;
+ struct ldb_message_element el;
+ struct prefixMapBlob pm;
+ struct ldb_val ndr_blob;
+ enum ndr_err_code ndr_err;
+ uint32_t i;
+ int ret;
+
+ schema_dn = samdb_schema_dn(ldb);
+ if (!schema_dn) {
+ DEBUG(0,("dsdb_write_prefixes_to_ldb: no schema dn present\n"));
+ return WERR_FOOBAR;
+ }
+
+ pm.version = PREFIX_MAP_VERSION_DSDB;
+ pm.ctr.dsdb.num_mappings = num_prefixes;
+ pm.ctr.dsdb.mappings = talloc_array(mem_ctx,
+ struct drsuapi_DsReplicaOIDMapping,
+ pm.ctr.dsdb.num_mappings);
+ if (!pm.ctr.dsdb.mappings) {
+ return WERR_NOMEM;
+ }
+
+ for (i=0; i < num_prefixes; i++) {
+ pm.ctr.dsdb.mappings[i].id_prefix = prefixes[i].id>>16;
+ pm.ctr.dsdb.mappings[i].oid.oid = talloc_strdup(pm.ctr.dsdb.mappings, prefixes[i].oid);
+ }
+
+ ndr_err = ndr_push_struct_blob(&ndr_blob, ldb,
+ lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
+ &pm,
+ (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return WERR_FOOBAR;
+ }
+
+ el.num_values = 1;
+ el.values = &ndr_blob;
+ el.flags = LDB_FLAG_MOD_REPLACE;
+ el.name = talloc_strdup(mem_ctx, "prefixMap");
+
+ msg.dn = ldb_dn_copy(mem_ctx, schema_dn);
+ msg.num_elements = 1;
+ msg.elements = &el;
+
+ ret = ldb_modify( ldb, &msg );
+ if (ret != 0) {
+ DEBUG(0,("dsdb_write_prefixes_to_ldb: ldb_modify failed\n"));
+ return WERR_FOOBAR;
+ }
+
+ return WERR_OK;
+}
+
+WERROR dsdb_read_prefixes_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, uint32_t* num_prefixes, struct dsdb_schema_oid_prefix **prefixes)
+{
+ struct prefixMapBlob *blob;
+ enum ndr_err_code ndr_err;
+ uint32_t i;
+ const struct ldb_val *prefix_val;
+ struct ldb_dn *schema_dn;
+ struct ldb_result *schema_res;
+ int ret;
+ static const char *schema_attrs[] = {
+ "prefixMap",
+ NULL
+ };
+
+ schema_dn = samdb_schema_dn(ldb);
+ if (!schema_dn) {
+ DEBUG(0,("dsdb_read_prefixes_from_ldb: no schema dn present\n"));
+ return WERR_FOOBAR;
+ }
+
+ ret = ldb_search(ldb, schema_dn, LDB_SCOPE_BASE,NULL, schema_attrs,&schema_res);
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ DEBUG(0,("dsdb_read_prefixes_from_ldb: no prefix map present\n"));
+ return WERR_FOOBAR;
+ } else if (ret != LDB_SUCCESS) {
+ DEBUG(0,("dsdb_read_prefixes_from_ldb: failed to search the schema head\n"));
+ return WERR_FOOBAR;
+ }
+
+ prefix_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "prefixMap");
+ if (!prefix_val) {
+ DEBUG(0,("dsdb_read_prefixes_from_ldb: no prefixMap attribute found\n"));
+ return WERR_FOOBAR;
+ }
+
+ blob = talloc(mem_ctx, struct prefixMapBlob);
+ W_ERROR_HAVE_NO_MEMORY(blob);
+
+ ndr_err = ndr_pull_struct_blob(prefix_val, blob,
+ lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
+ blob,
+ (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0,("dsdb_read_prefixes_from_ldb: ndr_pull_struct_blob failed\n"));
+ talloc_free(blob);
+ return WERR_FOOBAR;
+ }
+
+ if (blob->version != PREFIX_MAP_VERSION_DSDB) {
+ DEBUG(0,("dsdb_read_prefixes_from_ldb: blob->version incorect\n"));
+ talloc_free(blob);
+ return WERR_FOOBAR;
+ }
+
+ *num_prefixes = blob->ctr.dsdb.num_mappings;
+ *prefixes = talloc_array(mem_ctx, struct dsdb_schema_oid_prefix, *num_prefixes);
+ if(!(*prefixes)) {
+ talloc_free(blob);
+ return WERR_NOMEM;
+ }
+ for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
+ char *oid;
+ (*prefixes)[i].id = blob->ctr.dsdb.mappings[i].id_prefix<<16;
+ oid = talloc_strdup(mem_ctx, blob->ctr.dsdb.mappings[i].oid.oid);
+ (*prefixes)[i].oid = talloc_asprintf_append(oid, ".");
+ (*prefixes)[i].oid_len = strlen(blob->ctr.dsdb.mappings[i].oid.oid);
+ }
+
+ talloc_free(blob);
+ return WERR_OK;
+}
+
+#define GET_STRING_LDB(msg, attr, mem_ctx, p, elem, strict) do { \
+ (p)->elem = samdb_result_string(msg, attr, NULL);\
+ if (strict && (p)->elem == NULL) { \
+ d_printf("%s: %s == NULL\n", __location__, attr); \
+ return WERR_INVALID_PARAM; \
+ } \
+ 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);\
+ if (str == NULL) { \
+ if (strict) { \
+ d_printf("%s: %s == NULL\n", __location__, attr); \
+ return WERR_INVALID_PARAM; \
+ } else { \
+ (p)->elem = false; \
+ } \
+ } else if (strcasecmp("TRUE", str) == 0) { \
+ (p)->elem = true; \
+ } else if (strcasecmp("FALSE", str) == 0) { \
+ (p)->elem = false; \
+ } else { \
+ d_printf("%s: %s == %s\n", __location__, attr, str); \
+ return WERR_INVALID_PARAM; \
+ } \
+} while (0)
+
+#define GET_UINT32_LDB(msg, attr, p, elem) do { \
+ (p)->elem = samdb_result_uint(msg, attr, 0);\
+} while (0)
+
+#define GET_GUID_LDB(msg, attr, p, elem) do { \
+ (p)->elem = samdb_result_guid(msg, attr);\
+} while (0)
+
+#define GET_BLOB_LDB(msg, attr, mem_ctx, p, elem) do { \
+ const struct ldb_val *_val;\
+ _val = ldb_msg_find_ldb_val(msg, attr);\
+ if (_val) {\
+ (p)->elem = *_val;\
+ talloc_steal(mem_ctx, (p)->elem.data);\
+ } else {\
+ ZERO_STRUCT((p)->elem);\
+ }\
+} while (0)
+
+WERROR dsdb_attribute_from_ldb(const struct dsdb_schema *schema,
+ struct ldb_message *msg,
+ TALLOC_CTX *mem_ctx,
+ struct dsdb_attribute *attr)
+{
+ 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_GUID_LDB(msg, "attributeSecurityGUID", attr, attributeSecurityGUID);
+
+ GET_UINT32_LDB(msg, "searchFlags", attr, searchFlags);
+ GET_UINT32_LDB(msg, "systemFlags", attr, systemFlags);
+ 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);
+ 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_UINT32_LDB(msg, "rangeLower", attr, rangeLower);
+ GET_UINT32_LDB(msg, "rangeUpper", attr, rangeUpper);
+ 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);
+
+ attr->syntax = dsdb_syntax_for_attribute(attr);
+ if (!attr->syntax) {
+ return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
+ }
+
+ return WERR_OK;
+}
+
+WERROR dsdb_class_from_ldb(const struct dsdb_schema *schema,
+ struct ldb_message *msg,
+ TALLOC_CTX *mem_ctx,
+ struct dsdb_class *obj)
+{
+ 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, "subClassOf", mem_ctx, obj, subClassOf, true);
+
+ GET_STRING_LIST_LDB(msg, "systemAuxiliaryClass", mem_ctx, obj, systemAuxiliaryClass, false);
+ GET_STRING_LIST_LDB(msg, "auxiliaryClass", mem_ctx, obj, auxiliaryClass, 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);
+
+ return WERR_OK;
+}
+
+#define dsdb_oom(error_string, mem_ctx) *error_string = talloc_asprintf(mem_ctx, "dsdb out of memory at %s:%d\n", __FILE__, __LINE__)
+
+int dsdb_schema_from_ldb_results(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
+ struct smb_iconv_convenience *iconv_convenience,
+ struct ldb_result *schema_res,
+ struct ldb_result *attrs_res, struct ldb_result *objectclass_res,
+ struct dsdb_schema **schema_out,
+ char **error_string)
+{
+ WERROR status;
+ uint32_t i;
+ const struct ldb_val *prefix_val;
+ const struct ldb_val *info_val;
+ struct ldb_val info_val_default;
+ struct dsdb_schema *schema;
+
+ schema = dsdb_new_schema(mem_ctx, iconv_convenience);
+ if (!schema) {
+ dsdb_oom(error_string, mem_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ prefix_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "prefixMap");
+ if (!prefix_val) {
+ *error_string = talloc_asprintf(mem_ctx,
+ "schema_fsmo_init: no prefixMap attribute found");
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+ info_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "schemaInfo");
+ if (!info_val) {
+ info_val_default = strhex_to_data_blob("FF0000000000000000000000000000000000000000");
+ if (!info_val_default.data) {
+ dsdb_oom(error_string, mem_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ talloc_steal(mem_ctx, info_val_default.data);
+ info_val = &info_val_default;
+ }
+
+ status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val);
+ if (!W_ERROR_IS_OK(status)) {
+ *error_string = talloc_asprintf(mem_ctx,
+ "schema_fsmo_init: failed to load oid mappings: %s",
+ win_errstr(status));
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ for (i=0; i < attrs_res->count; i++) {
+ struct dsdb_attribute *sa;
+
+ sa = talloc_zero(schema, struct dsdb_attribute);
+ if (!sa) {
+ dsdb_oom(error_string, mem_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ status = dsdb_attribute_from_ldb(schema, attrs_res->msgs[i], sa, sa);
+ if (!W_ERROR_IS_OK(status)) {
+ *error_string = talloc_asprintf(mem_ctx,
+ "schema_fsmo_init: failed to load attribute definition: %s:%s",
+ ldb_dn_get_linearized(attrs_res->msgs[i]->dn),
+ win_errstr(status));
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ DLIST_ADD_END(schema->attributes, sa, struct dsdb_attribute *);
+ }
+
+ for (i=0; i < objectclass_res->count; i++) {
+ struct dsdb_class *sc;
+
+ sc = talloc_zero(schema, struct dsdb_class);
+ if (!sc) {
+ dsdb_oom(error_string, mem_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ status = dsdb_class_from_ldb(schema, objectclass_res->msgs[i], sc, sc);
+ if (!W_ERROR_IS_OK(status)) {
+ *error_string = talloc_asprintf(mem_ctx,
+ "schema_fsmo_init: failed to load class definition: %s:%s",
+ ldb_dn_get_linearized(objectclass_res->msgs[i]->dn),
+ win_errstr(status));
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ DLIST_ADD_END(schema->classes, sc, struct dsdb_class *);
+ }
+
+ schema->fsmo.master_dn = ldb_msg_find_attr_as_dn(ldb, schema, schema_res->msgs[0], "fSMORoleOwner");
+ if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), schema->fsmo.master_dn) == 0) {
+ schema->fsmo.we_are_master = true;
+ } else {
+ schema->fsmo.we_are_master = false;
+ }
+
+ DEBUG(5, ("schema_fsmo_init: we are master: %s\n",
+ (schema->fsmo.we_are_master?"yes":"no")));
+
+ *schema_out = schema;
+ return LDB_SUCCESS;
+}
+
+/* This recursive load of the objectClasses presumes that they
+ * everything is in a strict subClassOf hirarchy.
+ *
+ * We load this in order so we produce certain outputs (such as the
+ * exported schema for openldap, and sorted objectClass attribute) 'in
+ * order' */
+
+static int fetch_oc_recursive(struct ldb_context *ldb, struct ldb_dn *schemadn,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_result *search_from,
+ struct ldb_result *res_list)
+{
+ int i;
+ int ret = 0;
+ for (i=0; i < search_from->count; i++) {
+ struct ldb_result *res;
+ const char *name = ldb_msg_find_attr_as_string(search_from->msgs[i],
+ "lDAPDisplayname", NULL);
+
+ ret = ldb_search_exp_fmt(ldb, mem_ctx, &res,
+ schemadn, LDB_SCOPE_SUBTREE, NULL,
+ "(&(&(objectClass=classSchema)(subClassOf=%s))(!(lDAPDisplayName=%s)))",
+ name, name);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ res_list->msgs = talloc_realloc(res_list, res_list->msgs,
+ struct ldb_message *, res_list->count + 2);
+ if (!res_list->msgs) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ res_list->msgs[res_list->count] = talloc_move(res_list,
+ &search_from->msgs[i]);
+ res_list->count++;
+ res_list->msgs[res_list->count] = NULL;
+
+ if (res->count > 0) {
+ ret = fetch_oc_recursive(ldb, schemadn, mem_ctx, res, res_list);
+ }
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static int fetch_objectclass_schema(struct ldb_context *ldb, struct ldb_dn *schemadn,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_result **objectclasses_res,
+ char **error_string)
+{
+ TALLOC_CTX *local_ctx = talloc_new(mem_ctx);
+ struct ldb_result *top_res, *ret_res;
+ int ret;
+ if (!local_ctx) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Download 'top' */
+ ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE,
+ "(&(objectClass=classSchema)(lDAPDisplayName=top))",
+ NULL, &top_res);
+ if (ret != LDB_SUCCESS) {
+ *error_string = talloc_asprintf(mem_ctx,
+ "dsdb_schema: failed to search for top classSchema object: %s",
+ ldb_errstring(ldb));
+ return ret;
+ }
+
+ talloc_steal(local_ctx, top_res);
+
+ if (top_res->count != 1) {
+ *error_string = talloc_asprintf(mem_ctx,
+ "dsdb_schema: failed to find top classSchema object");
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+
+ ret_res = talloc_zero(local_ctx, struct ldb_result);
+ if (!ret_res) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = fetch_oc_recursive(ldb, schemadn, local_ctx, top_res, ret_res);
+
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ *objectclasses_res = talloc_move(mem_ctx, &ret_res);
+ return ret;
+}
+
+int dsdb_schema_from_schema_dn(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
+ struct smb_iconv_convenience *iconv_convenience,
+ struct ldb_dn *schema_dn,
+ struct dsdb_schema **schema,
+ char **error_string_out)
+{
+ TALLOC_CTX *tmp_ctx;
+ char *error_string;
+ int ret;
+
+ struct ldb_result *schema_res;
+ struct ldb_result *a_res;
+ struct ldb_result *c_res;
+ static const char *schema_attrs[] = {
+ "prefixMap",
+ "schemaInfo",
+ "fSMORoleOwner",
+ NULL
+ };
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (!tmp_ctx) {
+ dsdb_oom(error_string_out, mem_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /*
+ * setup the prefix mappings and schema info
+ */
+ ret = ldb_search(ldb, schema_dn,
+ LDB_SCOPE_BASE,
+ NULL, schema_attrs,
+ &schema_res);
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ talloc_free(tmp_ctx);
+ return ret;
+ } else if (ret != LDB_SUCCESS) {
+ *error_string_out = talloc_asprintf(mem_ctx,
+ "dsdb_schema: failed to search the schema head: %s",
+ ldb_errstring(ldb));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ talloc_steal(tmp_ctx, schema_res);
+ if (schema_res->count != 1) {
+ *error_string_out = talloc_asprintf(mem_ctx,
+ "dsdb_schema: [%u] schema heads found on a base search",
+ schema_res->count);
+ talloc_free(tmp_ctx);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ /*
+ * load the attribute definitions
+ */
+ ret = ldb_search(ldb, schema_dn,
+ LDB_SCOPE_ONELEVEL,
+ "(objectClass=attributeSchema)", NULL,
+ &a_res);
+ if (ret != LDB_SUCCESS) {
+ *error_string_out = talloc_asprintf(mem_ctx,
+ "dsdb_schema: failed to search attributeSchema objects: %s",
+ ldb_errstring(ldb));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ talloc_steal(tmp_ctx, a_res);
+
+ /*
+ * load the objectClass definitions
+ */
+ ret = fetch_objectclass_schema(ldb, schema_dn, tmp_ctx, &c_res, &error_string);
+ if (ret != LDB_SUCCESS) {
+ *error_string_out = talloc_asprintf(mem_ctx,
+ "Failed to fetch objectClass schema elements: %s", error_string);
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ ret = dsdb_schema_from_ldb_results(tmp_ctx, ldb,
+ lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
+ schema_res, a_res, c_res, schema, &error_string);
+ if (ret != LDB_SUCCESS) {
+ *error_string_out = talloc_asprintf(mem_ctx,
+ "dsdb_schema load failed: %s",
+ error_string);
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ talloc_steal(mem_ctx, *schema);
+ talloc_free(tmp_ctx);
+
+ return LDB_SUCCESS;
+}
+
+
+static const struct {
+ const char *name;
+ const char *oid;
+} name_mappings[] = {
+ { "cn", "2.5.4.3" },
+ { "name", "1.2.840.113556.1.4.1" },
+ { "lDAPDisplayName", "1.2.840.113556.1.2.460" },
+ { "attributeID", "1.2.840.113556.1.2.30" },
+ { "schemaIDGUID", "1.2.840.113556.1.4.148" },
+ { "mAPIID", "1.2.840.113556.1.2.49" },
+ { "attributeSecurityGUID", "1.2.840.113556.1.4.149" },
+ { "searchFlags", "1.2.840.113556.1.2.334" },
+ { "systemFlags", "1.2.840.113556.1.4.375" },
+ { "isMemberOfPartialAttributeSet", "1.2.840.113556.1.4.639" },
+ { "linkID", "1.2.840.113556.1.2.50" },
+ { "attributeSyntax", "1.2.840.113556.1.2.32" },
+ { "oMSyntax", "1.2.840.113556.1.2.231" },
+ { "oMObjectClass", "1.2.840.113556.1.2.218" },
+ { "isSingleValued", "1.2.840.113556.1.2.33" },
+ { "rangeLower", "1.2.840.113556.1.2.34" },
+ { "rangeUpper", "1.2.840.113556.1.2.35" },
+ { "extendedCharsAllowed", "1.2.840.113556.1.2.380" },
+ { "schemaFlagsEx", "1.2.840.113556.1.4.120" },
+ { "msDs-Schema-Extensions", "1.2.840.113556.1.4.1440" },
+ { "showInAdvancedViewOnly", "1.2.840.113556.1.2.169" },
+ { "adminDisplayName", "1.2.840.113556.1.2.194" },
+ { "adminDescription", "1.2.840.113556.1.2.226" },
+ { "classDisplayName", "1.2.840.113556.1.4.610" },
+ { "isEphemeral", "1.2.840.113556.1.4.1212" },
+ { "isDefunct", "1.2.840.113556.1.4.661" },
+ { "systemOnly", "1.2.840.113556.1.4.170" },
+ { "governsID", "1.2.840.113556.1.2.22" },
+ { "objectClassCategory", "1.2.840.113556.1.2.370" },
+ { "rDNAttID", "1.2.840.113556.1.2.26" },
+ { "defaultObjectCategory", "1.2.840.113556.1.4.783" },
+ { "subClassOf", "1.2.840.113556.1.2.21" },
+ { "systemAuxiliaryClass", "1.2.840.113556.1.4.198" },
+ { "systemPossSuperiors", "1.2.840.113556.1.4.195" },
+ { "systemMustContain", "1.2.840.113556.1.4.197" },
+ { "systemMayContain", "1.2.840.113556.1.4.196" },
+ { "auxiliaryClass", "1.2.840.113556.1.2.351" },
+ { "possSuperiors", "1.2.840.113556.1.2.8" },
+ { "mustContain", "1.2.840.113556.1.2.24" },
+ { "mayContain", "1.2.840.113556.1.2.25" },
+ { "defaultSecurityDescriptor", "1.2.840.113556.1.4.224" },
+ { "defaultHidingValue", "1.2.840.113556.1.4.518" },
+};
+
+static struct drsuapi_DsReplicaAttribute *dsdb_find_object_attr_name(struct dsdb_schema *schema,
+ struct drsuapi_DsReplicaObject *obj,
+ const char *name,
+ uint32_t *idx)
+{
+ WERROR status;
+ uint32_t i, id;
+ const char *oid = NULL;
+
+ for(i=0; i < ARRAY_SIZE(name_mappings); i++) {
+ if (strcmp(name_mappings[i].name, name) != 0) continue;
+
+ oid = name_mappings[i].oid;
+ break;
+ }
+
+ if (!oid) {
+ return NULL;
+ }
+
+ status = dsdb_map_oid2int(schema, oid, &id);
+ if (!W_ERROR_IS_OK(status)) {
+ return NULL;
+ }
+
+ for (i=0; i < obj->attribute_ctr.num_attributes; i++) {
+ if (obj->attribute_ctr.attributes[i].attid != id) continue;
+
+ if (idx) *idx = i;
+ return &obj->attribute_ctr.attributes[i];
+ }
+
+ return NULL;
+}
+
+#define GET_STRING_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 (_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; \
+ } \
+} while (0)
+
+#define GET_BOOL_DS(s, r, attr, 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, \
+ (unsigned int)_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 (strict && _a->value_ctr.values[0].blob->length != 4) { \
+ d_printf("%s: %s length == %u\n", __location__, attr, \
+ (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);\
+ } else { \
+ (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.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; \
+ } \
+} while (0)
+
+#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.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 (!NDR_ERR_CODE_IS_SUCCESS(_ndr_err)) { \
+ NTSTATUS _nt_status = ndr_map_error2ntstatus(_ndr_err); \
+ return ntstatus_to_werror(_nt_status); \
+ } \
+ } else { \
+ ZERO_STRUCT((p)->elem);\
+ } \
+} while (0)
+
+#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.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);\
+ }\
+} while (0)
+
+WERROR dsdb_attribute_from_drsuapi(struct dsdb_schema *schema,
+ struct drsuapi_DsReplicaObject *r,
+ TALLOC_CTX *mem_ctx,
+ struct dsdb_attribute *attr)
+{
+ 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_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)) {
+ DEBUG(0,("%s: '%s': unable to map attributeID 0x%08X: %s\n",
+ __location__, attr->lDAPDisplayName, attr->attributeID_id,
+ win_errstr(status)));
+ return status;
+ }
+ GET_GUID_DS(schema, r, "schemaIDGUID", mem_ctx, attr, schemaIDGUID);
+ GET_UINT32_DS(schema, r, "mAPIID", attr, mAPIID);
+
+ GET_GUID_DS(schema, r, "attributeSecurityGUID", mem_ctx, attr, attributeSecurityGUID);
+
+ 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_UINT32_DS(schema, r, "linkID", attr, linkID);
+
+ GET_UINT32_DS(schema, r, "attributeSyntax", attr, attributeSyntax_id);
+ status = dsdb_map_int2oid(schema, attr->attributeSyntax_id, mem_ctx, &attr->attributeSyntax_oid);
+ if (!W_ERROR_IS_OK(status)) {
+ DEBUG(0,("%s: '%s': unable to map attributeSyntax 0x%08X: %s\n",
+ __location__, attr->lDAPDisplayName, attr->attributeSyntax_id,
+ win_errstr(status)));
+ return status;
+ }
+ 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_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_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);
+
+ attr->syntax = dsdb_syntax_for_attribute(attr);
+ if (!attr->syntax) {
+ return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
+ }
+
+ return WERR_OK;
+}
+
+WERROR dsdb_class_from_drsuapi(struct dsdb_schema *schema,
+ struct drsuapi_DsReplicaObject *r,
+ TALLOC_CTX *mem_ctx,
+ struct dsdb_class *obj)
+{
+ 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_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)) {
+ DEBUG(0,("%s: '%s': unable to map governsID 0x%08X: %s\n",
+ __location__, obj->lDAPDisplayName, obj->governsID_id,
+ win_errstr(status)));
+ return 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, "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;
+
+ 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);
+
+ return WERR_OK;
+}
+
diff --git a/source4/dsdb/schema/schema_query.c b/source4/dsdb/schema/schema_query.c
new file mode 100644
index 0000000000..ca26ffd206
--- /dev/null
+++ b/source4/dsdb/schema/schema_query.c
@@ -0,0 +1,344 @@
+/*
+ Unix SMB/CIFS mplementation.
+ DSDB schema header
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+#include "dsdb/samdb/samdb.h"
+
+const struct dsdb_attribute *dsdb_attribute_by_attributeID_id(const struct dsdb_schema *schema,
+ uint32_t id)
+{
+ struct dsdb_attribute *cur;
+
+ /*
+ * 0xFFFFFFFF is used as value when no mapping table is available,
+ * so don't try to match with it
+ */
+ if (id == 0xFFFFFFFF) return NULL;
+
+ /* TODO: add binary search */
+ for (cur = schema->attributes; cur; cur = cur->next) {
+ if (cur->attributeID_id != id) continue;
+
+ return cur;
+ }
+
+ return NULL;
+}
+
+const struct dsdb_attribute *dsdb_attribute_by_attributeID_oid(const struct dsdb_schema *schema,
+ const char *oid)
+{
+ struct dsdb_attribute *cur;
+
+ if (!oid) return NULL;
+
+ /* TODO: add binary search */
+ for (cur = schema->attributes; cur; cur = cur->next) {
+ if (strcmp(cur->attributeID_oid, oid) != 0) continue;
+
+ return cur;
+ }
+
+ return NULL;
+}
+
+const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName(const struct dsdb_schema *schema,
+ const char *name)
+{
+ struct dsdb_attribute *cur;
+
+ if (!name) return NULL;
+
+ /* TODO: add binary search */
+ for (cur = schema->attributes; cur; cur = cur->next) {
+ if (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;
+ }
+
+ return NULL;
+}
+
+const struct dsdb_class *dsdb_class_by_governsID_id(const struct dsdb_schema *schema,
+ uint32_t id)
+{
+ struct dsdb_class *cur;
+
+ /*
+ * 0xFFFFFFFF is used as value when no mapping table is available,
+ * so don't try to match with it
+ */
+ if (id == 0xFFFFFFFF) return NULL;
+
+ /* TODO: add binary search */
+ for (cur = schema->classes; cur; cur = cur->next) {
+ if (cur->governsID_id != id) continue;
+
+ return cur;
+ }
+
+ return NULL;
+}
+
+const struct dsdb_class *dsdb_class_by_governsID_oid(const struct dsdb_schema *schema,
+ const char *oid)
+{
+ struct dsdb_class *cur;
+
+ if (!oid) return NULL;
+
+ /* TODO: add binary search */
+ for (cur = schema->classes; cur; cur = cur->next) {
+ if (strcmp(cur->governsID_oid, oid) != 0) continue;
+
+ return cur;
+ }
+
+ return NULL;
+}
+
+const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema *schema,
+ const char *name)
+{
+ struct dsdb_class *cur;
+
+ if (!name) return NULL;
+
+ /* TODO: add binary search */
+ for (cur = schema->classes; cur; cur = cur->next) {
+ if (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;
+ }
+
+ return NULL;
+}
+
+const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
+ uint32_t id)
+{
+ const struct dsdb_attribute *a;
+ const struct dsdb_class *c;
+
+ /* TODO: add binary search */
+ a = dsdb_attribute_by_attributeID_id(schema, id);
+ if (a) {
+ return a->lDAPDisplayName;
+ }
+
+ c = dsdb_class_by_governsID_id(schema, id);
+ if (c) {
+ return c->lDAPDisplayName;
+ }
+
+ return NULL;
+}
+
+/**
+ 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;
+}
+
+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;
+}
+
+/*
+ Return a merged list of the attributes of exactly one class (not
+ considering subclasses, auxillary classes etc)
+*/
+
+char **dsdb_attribute_list(TALLOC_CTX *mem_ctx, const struct dsdb_class *class, enum dsdb_attr_list_query query)
+{
+ char **attr_list = NULL;
+ 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;
+ }
+ return attr_list;
+}
+
+static 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 **this_class_list;
+ char **recursive_list;
+
+ for (i=0; class_list && class_list[i]; i++) {
+ class = dsdb_class_by_lDAPDisplayName(schema, class_list[i]);
+
+ this_class_list = dsdb_attribute_list(mem_ctx, class, query);
+ attr_list = merge_attr_list(mem_ctx, attr_list, (const char **)this_class_list);
+
+ 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;
+}
diff --git a/source4/dsdb/schema/schema_set.c b/source4/dsdb/schema/schema_set.c
new file mode 100644
index 0000000000..2303b88a05
--- /dev/null
+++ b/source4/dsdb/schema/schema_set.c
@@ -0,0 +1,409 @@
+/*
+ Unix SMB/CIFS mplementation.
+ DSDB schema header
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+#include "dsdb/samdb/samdb.h"
+#include "lib/ldb/include/ldb_errors.h"
+#include "lib/ldb/include/ldb_private.h"
+#include "lib/util/dlinklist.h"
+#include "param/param.h"
+
+
+static int dsdb_schema_set_attributes(struct ldb_context *ldb, struct dsdb_schema *schema, bool write_attributes)
+{
+ int ret = LDB_SUCCESS;
+ struct ldb_result *res;
+ struct ldb_result *res_idx;
+ struct dsdb_attribute *attr;
+ struct ldb_message *mod_msg;
+ TALLOC_CTX *mem_ctx = talloc_new(ldb);
+
+ struct ldb_message *msg;
+ struct ldb_message *msg_idx;
+
+ if (!mem_ctx) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg = ldb_msg_new(mem_ctx);
+ if (!msg) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ msg_idx = ldb_msg_new(mem_ctx);
+ if (!msg_idx) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ msg->dn = ldb_dn_new(msg, ldb, "@ATTRIBUTES");
+ if (!msg->dn) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ msg_idx->dn = ldb_dn_new(msg, ldb, "@INDEXLIST");
+ if (!msg_idx->dn) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ for (attr = schema->attributes; attr; attr = attr->next) {
+ const struct ldb_schema_syntax *s;
+ const char *syntax = attr->syntax->ldb_syntax;
+ if (!syntax) {
+ syntax = attr->syntax->ldap_oid;
+ }
+
+ /* Write out a rough approximation of the schema as an @ATTRIBUTES value, for bootstrapping */
+ if (strcmp(syntax, LDB_SYNTAX_INTEGER) == 0) {
+ ret = ldb_msg_add_string(msg, attr->lDAPDisplayName, "INTEGER");
+ } else if (strcmp(syntax, LDB_SYNTAX_DIRECTORY_STRING) == 0) {
+ ret = ldb_msg_add_string(msg, attr->lDAPDisplayName, "CASE_INSENSITIVE");
+ }
+ if (ret != LDB_SUCCESS) {
+ break;
+ }
+
+ if (attr->searchFlags & SEARCH_FLAG_ATTINDEX) {
+ ret = ldb_msg_add_string(msg_idx, "@IDXATTR", attr->lDAPDisplayName);
+ if (ret != LDB_SUCCESS) {
+ break;
+ }
+ }
+
+ if (!attr->syntax) {
+ continue;
+ }
+
+ ret = ldb_schema_attribute_add(ldb, attr->lDAPDisplayName, LDB_ATTR_FLAG_FIXED,
+ syntax);
+ if (ret != LDB_SUCCESS) {
+ s = ldb_samba_syntax_by_name(ldb, attr->syntax->ldap_oid);
+ if (s) {
+ ret = ldb_schema_attribute_add_with_syntax(ldb, attr->lDAPDisplayName, LDB_ATTR_FLAG_FIXED, s);
+ } else {
+ ret = LDB_SUCCESS; /* Nothing to do here */
+ }
+ }
+
+ if (ret != LDB_SUCCESS) {
+ break;
+ }
+ }
+
+ if (!write_attributes || ret != LDB_SUCCESS) {
+ talloc_free(mem_ctx);
+ return ret;
+ }
+
+
+ /* Try to avoid churning the attributes too much - we only want to do this if they have changed */
+ ret = ldb_search_exp_fmt(ldb, mem_ctx, &res, msg->dn, LDB_SCOPE_BASE, NULL, "dn=%s", ldb_dn_get_linearized(msg->dn));
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ ret = ldb_add(ldb, msg);
+ } else if (ret != LDB_SUCCESS) {
+ } else if (res->count != 1) {
+ ret = ldb_add(ldb, msg);
+ } else {
+ ret = LDB_SUCCESS;
+ /* Annoyingly added to our search results */
+ ldb_msg_remove_attr(res->msgs[0], "distinguishedName");
+
+ mod_msg = ldb_msg_diff(ldb, res->msgs[0], msg);
+ if (mod_msg->num_elements > 0) {
+ ret = ldb_modify(ldb, mod_msg);
+ }
+ }
+
+ if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
+ /* We might be on a read-only DB */
+ ret = LDB_SUCCESS;
+ }
+ if (ret != LDB_SUCCESS) {
+ talloc_free(mem_ctx);
+ return ret;
+ }
+
+ /* Now write out the indexs, as found in the schema (if they have changed) */
+
+ ret = ldb_search_exp_fmt(ldb, mem_ctx, &res_idx, msg_idx->dn, LDB_SCOPE_BASE, NULL, "dn=%s", ldb_dn_get_linearized(msg_idx->dn));
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ ret = ldb_add(ldb, msg_idx);
+ } else if (ret != LDB_SUCCESS) {
+ } else if (res->count != 1) {
+ ret = ldb_add(ldb, msg_idx);
+ } else {
+ ret = LDB_SUCCESS;
+ /* Annoyingly added to our search results */
+ ldb_msg_remove_attr(res_idx->msgs[0], "distinguishedName");
+
+ mod_msg = ldb_msg_diff(ldb, res_idx->msgs[0], msg_idx);
+ if (mod_msg->num_elements > 0) {
+ ret = ldb_modify(ldb, mod_msg);
+ }
+ }
+ if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
+ /* We might be on a read-only DB */
+ ret = LDB_SUCCESS;
+ }
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+/**
+ * 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;
+ }
+
+ /* Set the new attributes based on the new schema */
+ ret = dsdb_schema_set_attributes(ldb, schema, true);
+ 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;
+ }
+
+ /* Set the new attributes based on the new schema */
+ ret = dsdb_schema_set_attributes(ldb, global_schema, false);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* Keep a reference to this schema, just incase the global copy is replaced */
+ if (talloc_reference(ldb, global_schema) == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ 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;
+ }
+
+ if (global_schema) {
+ talloc_unlink(talloc_autofree_context(), schema);
+ }
+
+ 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;
+}
diff --git a/source4/dsdb/schema/schema_syntax.c b/source4/dsdb/schema/schema_syntax.c
new file mode 100644
index 0000000000..97cd0020a9
--- /dev/null
+++ b/source4/dsdb/schema/schema_syntax.c
@@ -0,0 +1,1426 @@
+/*
+ Unix SMB/CIFS mplementation.
+ DSDB schema syntaxes
+
+ Copyright (C) Stefan Metzmacher <metze@samba.org> 2006
+ Copyright (C) Simo Sorce 2005
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+
+*/
+#include "includes.h"
+#include "dsdb/samdb/samdb.h"
+#include "librpc/gen_ndr/ndr_drsuapi.h"
+#include "lib/ldb/include/ldb.h"
+#include "system/time.h"
+#include "lib/charset/charset.h"
+#include "librpc/ndr/libndr.h"
+#include "param/param.h"
+
+static WERROR dsdb_syntax_FOOBAR_drsuapi_to_ldb(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct drsuapi_DsReplicaAttribute *in,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *out)
+{
+ uint32_t i;
+
+ out->flags = 0;
+ out->name = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
+ W_ERROR_HAVE_NO_MEMORY(out->name);
+
+ out->num_values = in->value_ctr.num_values;
+ out->values = talloc_array(mem_ctx, struct ldb_val, out->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->values);
+
+ for (i=0; i < out->num_values; i++) {
+ char *str;
+
+ if (in->value_ctr.values[i].blob == NULL) {
+ return WERR_FOOBAR;
+ }
+
+ str = talloc_asprintf(out->values, "%s: not implemented",
+ attr->syntax->name);
+ W_ERROR_HAVE_NO_MEMORY(str);
+
+ out->values[i] = data_blob_string_const(str);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_FOOBAR_ldb_to_drsuapi(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct ldb_message_element *in,
+ TALLOC_CTX *mem_ctx,
+ struct drsuapi_DsReplicaAttribute *out)
+{
+ return WERR_FOOBAR;
+}
+
+static WERROR dsdb_syntax_BOOL_drsuapi_to_ldb(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct drsuapi_DsReplicaAttribute *in,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *out)
+{
+ uint32_t i;
+
+ out->flags = 0;
+ out->name = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
+ W_ERROR_HAVE_NO_MEMORY(out->name);
+
+ out->num_values = in->value_ctr.num_values;
+ out->values = talloc_array(mem_ctx, struct ldb_val, out->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->values);
+
+ for (i=0; i < out->num_values; i++) {
+ uint32_t v;
+ char *str;
+
+ if (in->value_ctr.values[i].blob == NULL) {
+ return WERR_FOOBAR;
+ }
+
+ if (in->value_ctr.values[i].blob->length != 4) {
+ return WERR_FOOBAR;
+ }
+
+ v = IVAL(in->value_ctr.values[i].blob->data, 0);
+
+ if (v != 0) {
+ str = talloc_strdup(out->values, "TRUE");
+ W_ERROR_HAVE_NO_MEMORY(str);
+ } else {
+ str = talloc_strdup(out->values, "FALSE");
+ W_ERROR_HAVE_NO_MEMORY(str);
+ }
+
+ out->values[i] = data_blob_string_const(str);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_BOOL_ldb_to_drsuapi(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct ldb_message_element *in,
+ TALLOC_CTX *mem_ctx,
+ struct drsuapi_DsReplicaAttribute *out)
+{
+ uint32_t i;
+ DATA_BLOB *blobs;
+
+ if (attr->attributeID_id == 0xFFFFFFFF) {
+ return WERR_FOOBAR;
+ }
+
+ out->attid = attr->attributeID_id;
+ out->value_ctr.num_values = in->num_values;
+ out->value_ctr.values = talloc_array(mem_ctx,
+ struct drsuapi_DsAttributeValue,
+ in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
+
+ blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(blobs);
+
+ for (i=0; i < in->num_values; i++) {
+ out->value_ctr.values[i].blob = &blobs[i];
+
+ blobs[i] = data_blob_talloc(blobs, NULL, 4);
+ W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
+
+ if (strcmp("TRUE", (const char *)in->values[i].data) == 0) {
+ SIVAL(blobs[i].data, 0, 0x00000001);
+ } else if (strcmp("FALSE", (const char *)in->values[i].data) == 0) {
+ SIVAL(blobs[i].data, 0, 0x00000000);
+ } else {
+ return WERR_FOOBAR;
+ }
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_INT32_drsuapi_to_ldb(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct drsuapi_DsReplicaAttribute *in,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *out)
+{
+ uint32_t i;
+
+ out->flags = 0;
+ out->name = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
+ W_ERROR_HAVE_NO_MEMORY(out->name);
+
+ out->num_values = in->value_ctr.num_values;
+ out->values = talloc_array(mem_ctx, struct ldb_val, out->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->values);
+
+ for (i=0; i < out->num_values; i++) {
+ int32_t v;
+ char *str;
+
+ if (in->value_ctr.values[i].blob == NULL) {
+ return WERR_FOOBAR;
+ }
+
+ if (in->value_ctr.values[i].blob->length != 4) {
+ return WERR_FOOBAR;
+ }
+
+ v = IVALS(in->value_ctr.values[i].blob->data, 0);
+
+ str = talloc_asprintf(out->values, "%d", v);
+ W_ERROR_HAVE_NO_MEMORY(str);
+
+ out->values[i] = data_blob_string_const(str);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_INT32_ldb_to_drsuapi(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct ldb_message_element *in,
+ TALLOC_CTX *mem_ctx,
+ struct drsuapi_DsReplicaAttribute *out)
+{
+ uint32_t i;
+ DATA_BLOB *blobs;
+
+ if (attr->attributeID_id == 0xFFFFFFFF) {
+ return WERR_FOOBAR;
+ }
+
+ out->attid = attr->attributeID_id;
+ out->value_ctr.num_values = in->num_values;
+ out->value_ctr.values = talloc_array(mem_ctx,
+ struct drsuapi_DsAttributeValue,
+ in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
+
+ blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(blobs);
+
+ for (i=0; i < in->num_values; i++) {
+ int32_t v;
+
+ out->value_ctr.values[i].blob = &blobs[i];
+
+ blobs[i] = data_blob_talloc(blobs, NULL, 4);
+ W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
+
+ v = strtol((const char *)in->values[i].data, NULL, 10);
+
+ SIVALS(blobs[i].data, 0, v);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_INT64_drsuapi_to_ldb(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct drsuapi_DsReplicaAttribute *in,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *out)
+{
+ uint32_t i;
+
+ out->flags = 0;
+ out->name = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
+ W_ERROR_HAVE_NO_MEMORY(out->name);
+
+ out->num_values = in->value_ctr.num_values;
+ out->values = talloc_array(mem_ctx, struct ldb_val, out->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->values);
+
+ for (i=0; i < out->num_values; i++) {
+ int64_t v;
+ char *str;
+
+ if (in->value_ctr.values[i].blob == NULL) {
+ return WERR_FOOBAR;
+ }
+
+ if (in->value_ctr.values[i].blob->length != 8) {
+ return WERR_FOOBAR;
+ }
+
+ v = BVALS(in->value_ctr.values[i].blob->data, 0);
+
+ str = talloc_asprintf(out->values, "%lld", (long long int)v);
+ W_ERROR_HAVE_NO_MEMORY(str);
+
+ out->values[i] = data_blob_string_const(str);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_INT64_ldb_to_drsuapi(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct ldb_message_element *in,
+ TALLOC_CTX *mem_ctx,
+ struct drsuapi_DsReplicaAttribute *out)
+{
+ uint32_t i;
+ DATA_BLOB *blobs;
+
+ if (attr->attributeID_id == 0xFFFFFFFF) {
+ return WERR_FOOBAR;
+ }
+
+ out->attid = attr->attributeID_id;
+ out->value_ctr.num_values = in->num_values;
+ out->value_ctr.values = talloc_array(mem_ctx,
+ struct drsuapi_DsAttributeValue,
+ in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
+
+ blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(blobs);
+
+ for (i=0; i < in->num_values; i++) {
+ int64_t v;
+
+ out->value_ctr.values[i].blob = &blobs[i];
+
+ blobs[i] = data_blob_talloc(blobs, NULL, 8);
+ W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
+
+ v = strtoll((const char *)in->values[i].data, NULL, 10);
+
+ SBVALS(blobs[i].data, 0, v);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_NTTIME_UTC_drsuapi_to_ldb(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct drsuapi_DsReplicaAttribute *in,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *out)
+{
+ uint32_t i;
+
+ out->flags = 0;
+ out->name = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
+ W_ERROR_HAVE_NO_MEMORY(out->name);
+
+ out->num_values = in->value_ctr.num_values;
+ out->values = talloc_array(mem_ctx, struct ldb_val, out->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->values);
+
+ for (i=0; i < out->num_values; i++) {
+ NTTIME v;
+ time_t t;
+ char *str;
+
+ if (in->value_ctr.values[i].blob == NULL) {
+ return WERR_FOOBAR;
+ }
+
+ if (in->value_ctr.values[i].blob->length != 8) {
+ return WERR_FOOBAR;
+ }
+
+ v = BVAL(in->value_ctr.values[i].blob->data, 0);
+ v *= 10000000;
+ t = nt_time_to_unix(v);
+
+ /*
+ * NOTE: On a w2k3 server you can set a GeneralizedTime string
+ * via LDAP, but you get back an UTCTime string,
+ * but via DRSUAPI you get back the NTTIME_1sec value
+ * that represents the GeneralizedTime value!
+ *
+ * So if we store the UTCTime string in our ldb
+ * we'll loose information!
+ */
+ str = ldb_timestring_utc(out->values, t);
+ W_ERROR_HAVE_NO_MEMORY(str);
+ out->values[i] = data_blob_string_const(str);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_NTTIME_UTC_ldb_to_drsuapi(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct ldb_message_element *in,
+ TALLOC_CTX *mem_ctx,
+ struct drsuapi_DsReplicaAttribute *out)
+{
+ uint32_t i;
+ DATA_BLOB *blobs;
+
+ if (attr->attributeID_id == 0xFFFFFFFF) {
+ return WERR_FOOBAR;
+ }
+
+ out->attid = attr->attributeID_id;
+ out->value_ctr.num_values = in->num_values;
+ out->value_ctr.values = talloc_array(mem_ctx,
+ struct drsuapi_DsAttributeValue,
+ in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
+
+ blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(blobs);
+
+ for (i=0; i < in->num_values; i++) {
+ NTTIME v;
+ time_t t;
+
+ out->value_ctr.values[i].blob = &blobs[i];
+
+ blobs[i] = data_blob_talloc(blobs, NULL, 8);
+ W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
+
+ t = ldb_string_utc_to_time((const char *)in->values[i].data);
+ unix_to_nt_time(&v, t);
+ v /= 10000000;
+
+ SBVAL(blobs[i].data, 0, v);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_NTTIME_drsuapi_to_ldb(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct drsuapi_DsReplicaAttribute *in,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *out)
+{
+ uint32_t i;
+
+ out->flags = 0;
+ out->name = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
+ W_ERROR_HAVE_NO_MEMORY(out->name);
+
+ out->num_values = in->value_ctr.num_values;
+ out->values = talloc_array(mem_ctx, struct ldb_val, out->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->values);
+
+ for (i=0; i < out->num_values; i++) {
+ NTTIME v;
+ time_t t;
+ char *str;
+
+ if (in->value_ctr.values[i].blob == NULL) {
+ return WERR_FOOBAR;
+ }
+
+ if (in->value_ctr.values[i].blob->length != 8) {
+ return WERR_FOOBAR;
+ }
+
+ v = BVAL(in->value_ctr.values[i].blob->data, 0);
+ v *= 10000000;
+ t = nt_time_to_unix(v);
+
+ str = ldb_timestring(out->values, t);
+ W_ERROR_HAVE_NO_MEMORY(str);
+
+ out->values[i] = data_blob_string_const(str);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_NTTIME_ldb_to_drsuapi(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct ldb_message_element *in,
+ TALLOC_CTX *mem_ctx,
+ struct drsuapi_DsReplicaAttribute *out)
+{
+ uint32_t i;
+ DATA_BLOB *blobs;
+
+ if (attr->attributeID_id == 0xFFFFFFFF) {
+ return WERR_FOOBAR;
+ }
+
+ out->attid = attr->attributeID_id;
+ out->value_ctr.num_values = in->num_values;
+ out->value_ctr.values = talloc_array(mem_ctx,
+ struct drsuapi_DsAttributeValue,
+ in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
+
+ blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(blobs);
+
+ for (i=0; i < in->num_values; i++) {
+ NTTIME v;
+ time_t t;
+
+ out->value_ctr.values[i].blob = &blobs[i];
+
+ blobs[i] = data_blob_talloc(blobs, NULL, 8);
+ W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
+
+ t = ldb_string_to_time((const char *)in->values[i].data);
+ unix_to_nt_time(&v, t);
+ v /= 10000000;
+
+ SBVAL(blobs[i].data, 0, v);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_DATA_BLOB_drsuapi_to_ldb(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct drsuapi_DsReplicaAttribute *in,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *out)
+{
+ uint32_t i;
+
+ out->flags = 0;
+ out->name = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
+ W_ERROR_HAVE_NO_MEMORY(out->name);
+
+ out->num_values = in->value_ctr.num_values;
+ out->values = talloc_array(mem_ctx, struct ldb_val, out->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->values);
+
+ for (i=0; i < out->num_values; i++) {
+ if (in->value_ctr.values[i].blob == NULL) {
+ return WERR_FOOBAR;
+ }
+
+ if (in->value_ctr.values[i].blob->length == 0) {
+ return WERR_FOOBAR;
+ }
+
+ out->values[i] = data_blob_dup_talloc(out->values,
+ in->value_ctr.values[i].blob);
+ W_ERROR_HAVE_NO_MEMORY(out->values[i].data);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_DATA_BLOB_ldb_to_drsuapi(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct ldb_message_element *in,
+ TALLOC_CTX *mem_ctx,
+ struct drsuapi_DsReplicaAttribute *out)
+{
+ uint32_t i;
+ DATA_BLOB *blobs;
+
+ if (attr->attributeID_id == 0xFFFFFFFF) {
+ return WERR_FOOBAR;
+ }
+
+ out->attid = attr->attributeID_id;
+ out->value_ctr.num_values = in->num_values;
+ out->value_ctr.values = talloc_array(mem_ctx,
+ struct drsuapi_DsAttributeValue,
+ in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
+
+ blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(blobs);
+
+ for (i=0; i < in->num_values; i++) {
+ out->value_ctr.values[i].blob = &blobs[i];
+
+ blobs[i] = data_blob_dup_talloc(blobs, &in->values[i]);
+ W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR _dsdb_syntax_OID_obj_drsuapi_to_ldb(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct drsuapi_DsReplicaAttribute *in,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *out)
+{
+ uint32_t i;
+
+ out->flags = 0;
+ out->name = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
+ W_ERROR_HAVE_NO_MEMORY(out->name);
+
+ out->num_values = in->value_ctr.num_values;
+ out->values = talloc_array(mem_ctx, struct ldb_val, out->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->values);
+
+ for (i=0; i < out->num_values; i++) {
+ uint32_t v;
+ const struct dsdb_class *c;
+ const char *str;
+
+ if (in->value_ctr.values[i].blob == NULL) {
+ return WERR_FOOBAR;
+ }
+
+ if (in->value_ctr.values[i].blob->length != 4) {
+ return WERR_FOOBAR;
+ }
+
+ v = IVAL(in->value_ctr.values[i].blob->data, 0);
+
+ c = dsdb_class_by_governsID_id(schema, v);
+ if (!c) {
+ return WERR_FOOBAR;
+ }
+
+ str = talloc_strdup(out->values, c->lDAPDisplayName);
+ W_ERROR_HAVE_NO_MEMORY(str);
+
+ /* the values need to be reversed */
+ out->values[out->num_values - (i + 1)] = data_blob_string_const(str);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR _dsdb_syntax_OID_oid_drsuapi_to_ldb(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct drsuapi_DsReplicaAttribute *in,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *out)
+{
+ uint32_t i;
+
+ out->flags = 0;
+ out->name = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
+ W_ERROR_HAVE_NO_MEMORY(out->name);
+
+ out->num_values = in->value_ctr.num_values;
+ out->values = talloc_array(mem_ctx, struct ldb_val, out->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->values);
+
+ for (i=0; i < out->num_values; i++) {
+ uint32_t v;
+ WERROR status;
+ const char *str;
+
+ if (in->value_ctr.values[i].blob == NULL) {
+ return WERR_FOOBAR;
+ }
+
+ if (in->value_ctr.values[i].blob->length != 4) {
+ return WERR_FOOBAR;
+ }
+
+ v = IVAL(in->value_ctr.values[i].blob->data, 0);
+
+ status = dsdb_map_int2oid(schema, v, out->values, &str);
+ W_ERROR_NOT_OK_RETURN(status);
+
+ out->values[i] = data_blob_string_const(str);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_OID_drsuapi_to_ldb(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct drsuapi_DsReplicaAttribute *in,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *out)
+{
+ uint32_t i;
+
+ switch (attr->attributeID_id) {
+ case DRSUAPI_ATTRIBUTE_objectClass:
+ return _dsdb_syntax_OID_obj_drsuapi_to_ldb(schema, attr, in, mem_ctx, out);
+ case DRSUAPI_ATTRIBUTE_governsID:
+ case DRSUAPI_ATTRIBUTE_attributeID:
+ case DRSUAPI_ATTRIBUTE_attributeSyntax:
+ return _dsdb_syntax_OID_oid_drsuapi_to_ldb(schema, attr, in, mem_ctx, out);
+ }
+
+ out->flags = 0;
+ out->name = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
+ W_ERROR_HAVE_NO_MEMORY(out->name);
+
+ out->num_values = in->value_ctr.num_values;
+ out->values = talloc_array(mem_ctx, struct ldb_val, out->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->values);
+
+ for (i=0; i < out->num_values; i++) {
+ uint32_t v;
+ const char *name;
+ char *str;
+
+ if (in->value_ctr.values[i].blob == NULL) {
+ return WERR_FOOBAR;
+ }
+
+ if (in->value_ctr.values[i].blob->length != 4) {
+ return WERR_FOOBAR;
+ }
+
+ v = IVAL(in->value_ctr.values[i].blob->data, 0);
+
+ name = dsdb_lDAPDisplayName_by_id(schema, v);
+ if (!name) {
+ return WERR_FOOBAR;
+ }
+
+ str = talloc_strdup(out->values, name);
+ W_ERROR_HAVE_NO_MEMORY(str);
+
+ out->values[i] = data_blob_string_const(str);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_OID_ldb_to_drsuapi(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct ldb_message_element *in,
+ TALLOC_CTX *mem_ctx,
+ struct drsuapi_DsReplicaAttribute *out)
+{
+ uint32_t i;
+ DATA_BLOB *blobs;
+
+ if (attr->attributeID_id == 0xFFFFFFFF) {
+ return WERR_FOOBAR;
+ }
+
+ switch (attr->attributeID_id) {
+ case DRSUAPI_ATTRIBUTE_objectClass:
+ case DRSUAPI_ATTRIBUTE_governsID:
+ case DRSUAPI_ATTRIBUTE_attributeID:
+ case DRSUAPI_ATTRIBUTE_attributeSyntax:
+ return dsdb_syntax_FOOBAR_ldb_to_drsuapi(schema, attr, in, mem_ctx, out);
+ }
+
+ out->attid = attr->attributeID_id;
+ out->value_ctr.num_values = in->num_values;
+ out->value_ctr.values = talloc_array(mem_ctx,
+ struct drsuapi_DsAttributeValue,
+ in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
+
+ blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(blobs);
+
+ for (i=0; i < in->num_values; i++) {
+ uint32_t v;
+
+ out->value_ctr.values[i].blob = &blobs[i];
+
+ blobs[i] = data_blob_talloc(blobs, NULL, 4);
+ W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
+
+ v = strtol((const char *)in->values[i].data, NULL, 10);
+
+ SIVAL(blobs[i].data, 0, v);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_UNICODE_drsuapi_to_ldb(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct drsuapi_DsReplicaAttribute *in,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *out)
+{
+ uint32_t i;
+
+ out->flags = 0;
+ out->name = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
+ W_ERROR_HAVE_NO_MEMORY(out->name);
+
+ out->num_values = in->value_ctr.num_values;
+ out->values = talloc_array(mem_ctx, struct ldb_val, out->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->values);
+
+ for (i=0; i < out->num_values; i++) {
+ ssize_t ret;
+ char *str;
+
+ if (in->value_ctr.values[i].blob == NULL) {
+ return WERR_FOOBAR;
+ }
+
+ if (in->value_ctr.values[i].blob->length == 0) {
+ return WERR_FOOBAR;
+ }
+
+ ret = convert_string_talloc(out->values, schema->iconv_convenience,
+ CH_UTF16, CH_UNIX,
+ in->value_ctr.values[i].blob->data,
+ in->value_ctr.values[i].blob->length,
+ (void **)&str);
+ if (ret == -1) {
+ return WERR_FOOBAR;
+ }
+
+ out->values[i] = data_blob_string_const(str);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_UNICODE_ldb_to_drsuapi(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct ldb_message_element *in,
+ TALLOC_CTX *mem_ctx,
+ struct drsuapi_DsReplicaAttribute *out)
+{
+ uint32_t i;
+ DATA_BLOB *blobs;
+
+ if (attr->attributeID_id == 0xFFFFFFFF) {
+ return WERR_FOOBAR;
+ }
+
+ out->attid = attr->attributeID_id;
+ out->value_ctr.num_values = in->num_values;
+ out->value_ctr.values = talloc_array(mem_ctx,
+ struct drsuapi_DsAttributeValue,
+ in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
+
+ blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(blobs);
+
+ for (i=0; i < in->num_values; i++) {
+ ssize_t ret;
+
+ out->value_ctr.values[i].blob = &blobs[i];
+
+ ret = convert_string_talloc(blobs, schema->iconv_convenience, CH_UNIX, CH_UTF16,
+ in->values[i].data,
+ in->values[i].length,
+ (void **)&blobs[i].data);
+ if (ret == -1) {
+ return WERR_FOOBAR;
+ }
+ blobs[i].length = ret;
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_DN_drsuapi_to_ldb(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct drsuapi_DsReplicaAttribute *in,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *out)
+{
+ uint32_t i;
+
+ out->flags = 0;
+ out->name = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
+ W_ERROR_HAVE_NO_MEMORY(out->name);
+
+ out->num_values = in->value_ctr.num_values;
+ out->values = talloc_array(mem_ctx, struct ldb_val, out->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->values);
+
+ for (i=0; i < out->num_values; i++) {
+ struct drsuapi_DsReplicaObjectIdentifier3 id3;
+ enum ndr_err_code ndr_err;
+
+ if (in->value_ctr.values[i].blob == NULL) {
+ return WERR_FOOBAR;
+ }
+
+ if (in->value_ctr.values[i].blob->length == 0) {
+ return WERR_FOOBAR;
+ }
+
+ ndr_err = ndr_pull_struct_blob_all(in->value_ctr.values[i].blob,
+ out->values, schema->iconv_convenience, &id3,
+ (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
+ return ntstatus_to_werror(status);
+ }
+
+ /* TODO: handle id3.guid and id3.sid */
+ out->values[i] = data_blob_string_const(id3.dn);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_DN_ldb_to_drsuapi(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct ldb_message_element *in,
+ TALLOC_CTX *mem_ctx,
+ struct drsuapi_DsReplicaAttribute *out)
+{
+ uint32_t i;
+ DATA_BLOB *blobs;
+
+ if (attr->attributeID_id == 0xFFFFFFFF) {
+ return WERR_FOOBAR;
+ }
+
+ out->attid = attr->attributeID_id;
+ out->value_ctr.num_values = in->num_values;
+ out->value_ctr.values = talloc_array(mem_ctx,
+ struct drsuapi_DsAttributeValue,
+ in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
+
+ blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(blobs);
+
+ for (i=0; i < in->num_values; i++) {
+ struct drsuapi_DsReplicaObjectIdentifier3 id3;
+ enum ndr_err_code ndr_err;
+
+ out->value_ctr.values[i].blob = &blobs[i];
+
+ /* TODO: handle id3.guid and id3.sid */
+ ZERO_STRUCT(id3);
+ id3.dn = (const char *)in->values[i].data;
+
+ ndr_err = ndr_push_struct_blob(&blobs[i], blobs, schema->iconv_convenience, &id3, (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
+ return ntstatus_to_werror(status);
+ }
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_DN_BINARY_drsuapi_to_ldb(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct drsuapi_DsReplicaAttribute *in,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *out)
+{
+ uint32_t i;
+
+ out->flags = 0;
+ out->name = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
+ W_ERROR_HAVE_NO_MEMORY(out->name);
+
+ out->num_values = in->value_ctr.num_values;
+ out->values = talloc_array(mem_ctx, struct ldb_val, out->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->values);
+
+ for (i=0; i < out->num_values; i++) {
+ struct drsuapi_DsReplicaObjectIdentifier3Binary id3b;
+ char *binary;
+ char *str;
+ enum ndr_err_code ndr_err;
+
+ if (in->value_ctr.values[i].blob == NULL) {
+ return WERR_FOOBAR;
+ }
+
+ if (in->value_ctr.values[i].blob->length == 0) {
+ return WERR_FOOBAR;
+ }
+
+ ndr_err = ndr_pull_struct_blob_all(in->value_ctr.values[i].blob,
+ out->values, schema->iconv_convenience, &id3b,
+ (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3Binary);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
+ return ntstatus_to_werror(status);
+ }
+
+ /* TODO: handle id3.guid and id3.sid */
+ binary = data_blob_hex_string(out->values, &id3b.binary);
+ W_ERROR_HAVE_NO_MEMORY(binary);
+
+ str = talloc_asprintf(out->values, "B:%u:%s:%s",
+ (unsigned int)(id3b.binary.length * 2), /* because of 2 hex chars per byte */
+ binary,
+ id3b.dn);
+ W_ERROR_HAVE_NO_MEMORY(str);
+
+ /* TODO: handle id3.guid and id3.sid */
+ out->values[i] = data_blob_string_const(str);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_DN_BINARY_ldb_to_drsuapi(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct ldb_message_element *in,
+ TALLOC_CTX *mem_ctx,
+ struct drsuapi_DsReplicaAttribute *out)
+{
+ uint32_t i;
+ DATA_BLOB *blobs;
+
+ if (attr->attributeID_id == 0xFFFFFFFF) {
+ return WERR_FOOBAR;
+ }
+
+ out->attid = attr->attributeID_id;
+ out->value_ctr.num_values = in->num_values;
+ out->value_ctr.values = talloc_array(mem_ctx,
+ struct drsuapi_DsAttributeValue,
+ in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
+
+ blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(blobs);
+
+ for (i=0; i < in->num_values; i++) {
+ struct drsuapi_DsReplicaObjectIdentifier3Binary id3b;
+ enum ndr_err_code ndr_err;
+
+ out->value_ctr.values[i].blob = &blobs[i];
+
+ /* TODO: handle id3b.guid and id3b.sid, id3.binary */
+ ZERO_STRUCT(id3b);
+ id3b.dn = (const char *)in->values[i].data;
+ id3b.binary = data_blob(NULL, 0);
+
+ ndr_err = ndr_push_struct_blob(&blobs[i], blobs, schema->iconv_convenience, &id3b,
+ (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3Binary);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
+ return ntstatus_to_werror(status);
+ }
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_PRESENTATION_ADDRESS_drsuapi_to_ldb(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct drsuapi_DsReplicaAttribute *in,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *out)
+{
+ uint32_t i;
+
+ out->flags = 0;
+ out->name = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
+ W_ERROR_HAVE_NO_MEMORY(out->name);
+
+ out->num_values = in->value_ctr.num_values;
+ out->values = talloc_array(mem_ctx, struct ldb_val, out->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->values);
+
+ for (i=0; i < out->num_values; i++) {
+ uint32_t len;
+ ssize_t ret;
+ char *str;
+
+ if (in->value_ctr.values[i].blob == NULL) {
+ return WERR_FOOBAR;
+ }
+
+ if (in->value_ctr.values[i].blob->length < 4) {
+ return WERR_FOOBAR;
+ }
+
+ len = IVAL(in->value_ctr.values[i].blob->data, 0);
+
+ if (len != in->value_ctr.values[i].blob->length) {
+ return WERR_FOOBAR;
+ }
+
+ ret = convert_string_talloc(out->values, schema->iconv_convenience, CH_UTF16, CH_UNIX,
+ in->value_ctr.values[i].blob->data+4,
+ in->value_ctr.values[i].blob->length-4,
+ (void **)&str);
+ if (ret == -1) {
+ return WERR_FOOBAR;
+ }
+
+ out->values[i] = data_blob_string_const(str);
+ }
+
+ return WERR_OK;
+}
+
+static WERROR dsdb_syntax_PRESENTATION_ADDRESS_ldb_to_drsuapi(const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ const struct ldb_message_element *in,
+ TALLOC_CTX *mem_ctx,
+ struct drsuapi_DsReplicaAttribute *out)
+{
+ uint32_t i;
+ DATA_BLOB *blobs;
+
+ if (attr->attributeID_id == 0xFFFFFFFF) {
+ return WERR_FOOBAR;
+ }
+
+ out->attid = attr->attributeID_id;
+ out->value_ctr.num_values = in->num_values;
+ out->value_ctr.values = talloc_array(mem_ctx,
+ struct drsuapi_DsAttributeValue,
+ in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
+
+ blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
+ W_ERROR_HAVE_NO_MEMORY(blobs);
+
+ for (i=0; i < in->num_values; i++) {
+ uint8_t *data;
+ ssize_t ret;
+
+ out->value_ctr.values[i].blob = &blobs[i];
+
+ ret = convert_string_talloc(blobs, schema->iconv_convenience, CH_UNIX, CH_UTF16,
+ in->values[i].data,
+ in->values[i].length,
+ (void **)&data);
+ if (ret == -1) {
+ return WERR_FOOBAR;
+ }
+
+ blobs[i] = data_blob_talloc(blobs, NULL, 4 + ret);
+ W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
+
+ SIVAL(blobs[i].data, 0, 4 + ret);
+
+ if (ret > 0) {
+ memcpy(blobs[i].data + 4, data, ret);
+ talloc_free(data);
+ }
+ }
+
+ return WERR_OK;
+}
+
+#define OMOBJECTCLASS(val) { .length = sizeof(val) - 1, .data = discard_const_p(uint8_t, val) }
+
+static const struct dsdb_syntax dsdb_syntaxes[] = {
+ {
+ .name = "Boolean",
+ .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.7",
+ .oMSyntax = 1,
+ .attributeSyntax_oid = "2.5.5.8",
+ .drsuapi_to_ldb = dsdb_syntax_BOOL_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_BOOL_ldb_to_drsuapi,
+ .equality = "booleanMatch",
+ .comment = "Boolean"
+ },{
+ .name = "Integer",
+ .ldap_oid = LDB_SYNTAX_INTEGER,
+ .oMSyntax = 2,
+ .attributeSyntax_oid = "2.5.5.9",
+ .drsuapi_to_ldb = dsdb_syntax_INT32_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_INT32_ldb_to_drsuapi,
+ .equality = "integerMatch",
+ .comment = "Integer",
+ },{
+ .name = "String(Octet)",
+ .ldap_oid = LDB_SYNTAX_OCTET_STRING,
+ .oMSyntax = 4,
+ .attributeSyntax_oid = "2.5.5.10",
+ .drsuapi_to_ldb = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
+ .equality = "octetStringMatch",
+ .comment = "Octet String",
+ },{
+ .name = "String(Sid)",
+ .ldap_oid = LDB_SYNTAX_OCTET_STRING,
+ .oMSyntax = 4,
+ .attributeSyntax_oid = "2.5.5.17",
+ .drsuapi_to_ldb = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
+ .equality = "octetStringMatch",
+ .comment = "Octet String - Security Identifier (SID)",
+ .ldb_syntax = LDB_SYNTAX_SAMBA_SID
+ },{
+ .name = "String(Object-Identifier)",
+ .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.38",
+ .oMSyntax = 6,
+ .attributeSyntax_oid = "2.5.5.2",
+ .drsuapi_to_ldb = dsdb_syntax_OID_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_OID_ldb_to_drsuapi,
+ .equality = "caseIgnoreMatch", /* Would use "objectIdentifierMatch" but most are ldap attribute/class names */
+ .comment = "OID String",
+ .ldb_syntax = LDB_SYNTAX_DIRECTORY_STRING
+ },{
+ .name = "Enumeration",
+ .ldap_oid = LDB_SYNTAX_INTEGER,
+ .oMSyntax = 10,
+ .attributeSyntax_oid = "2.5.5.9",
+ .drsuapi_to_ldb = dsdb_syntax_INT32_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_INT32_ldb_to_drsuapi,
+ },{
+ /* not used in w2k3 forest */
+ .name = "String(Numeric)",
+ .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.36",
+ .oMSyntax = 18,
+ .attributeSyntax_oid = "2.5.5.6",
+ .drsuapi_to_ldb = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
+ .equality = "numericStringMatch",
+ .substring = "numericStringSubstringsMatch",
+ .comment = "Numeric String"
+ },{
+ .name = "String(Printable)",
+ .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.44",
+ .oMSyntax = 19,
+ .attributeSyntax_oid = "2.5.5.5",
+ .drsuapi_to_ldb = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
+ },{
+ .name = "String(Teletex)",
+ .ldap_oid = "1.2.840.113556.1.4.905",
+ .oMSyntax = 20,
+ .attributeSyntax_oid = "2.5.5.4",
+ .drsuapi_to_ldb = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
+ .equality = "caseIgnoreMatch",
+ .substring = "caseIgnoreSubstringsMatch",
+ .comment = "Case Insensitive String",
+ .ldb_syntax = LDB_SYNTAX_DIRECTORY_STRING,
+ },{
+ .name = "String(IA5)",
+ .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.26",
+ .oMSyntax = 22,
+ .attributeSyntax_oid = "2.5.5.5",
+ .drsuapi_to_ldb = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
+ .equality = "caseExactIA5Match",
+ .comment = "Printable String"
+ },{
+ .name = "String(UTC-Time)",
+ .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.53",
+ .oMSyntax = 23,
+ .attributeSyntax_oid = "2.5.5.11",
+ .drsuapi_to_ldb = dsdb_syntax_NTTIME_UTC_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_NTTIME_UTC_ldb_to_drsuapi,
+ .equality = "generalizedTimeMatch",
+ .comment = "UTC Time",
+ },{
+ .name = "String(Generalized-Time)",
+ .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.24",
+ .oMSyntax = 24,
+ .attributeSyntax_oid = "2.5.5.11",
+ .drsuapi_to_ldb = dsdb_syntax_NTTIME_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_NTTIME_ldb_to_drsuapi,
+ .equality = "generalizedTimeMatch",
+ .comment = "Generalized Time",
+ .ldb_syntax = LDB_SYNTAX_UTC_TIME,
+ },{
+ /* not used in w2k3 schema */
+ .name = "String(Case Sensitive)",
+ .ldap_oid = "1.2.840.113556.1.4.1362",
+ .oMSyntax = 27,
+ .attributeSyntax_oid = "2.5.5.3",
+ .drsuapi_to_ldb = dsdb_syntax_FOOBAR_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_FOOBAR_ldb_to_drsuapi,
+ },{
+ .name = "String(Unicode)",
+ .ldap_oid = LDB_SYNTAX_DIRECTORY_STRING,
+ .oMSyntax = 64,
+ .attributeSyntax_oid = "2.5.5.12",
+ .drsuapi_to_ldb = dsdb_syntax_UNICODE_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_UNICODE_ldb_to_drsuapi,
+ .equality = "caseIgnoreMatch",
+ .substring = "caseIgnoreSubstringsMatch",
+ .comment = "Directory String",
+ },{
+ .name = "Interval/LargeInteger",
+ .ldap_oid = "1.2.840.113556.1.4.906",
+ .oMSyntax = 65,
+ .attributeSyntax_oid = "2.5.5.16",
+ .drsuapi_to_ldb = dsdb_syntax_INT64_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_INT64_ldb_to_drsuapi,
+ .equality = "integerMatch",
+ .comment = "Large Integer",
+ .ldb_syntax = LDB_SYNTAX_INTEGER,
+ },{
+ .name = "String(NT-Sec-Desc)",
+ .ldap_oid = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
+ .oMSyntax = 66,
+ .attributeSyntax_oid = "2.5.5.15",
+ .drsuapi_to_ldb = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
+ },{
+ .name = "Object(DS-DN)",
+ .ldap_oid = LDB_SYNTAX_DN,
+ .oMSyntax = 127,
+ .oMObjectClass = OMOBJECTCLASS("\x2b\x0c\x02\x87\x73\x1c\x00\x85\x4a"),
+ .attributeSyntax_oid = "2.5.5.1",
+ .drsuapi_to_ldb = dsdb_syntax_DN_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_DN_ldb_to_drsuapi,
+ .equality = "distinguishedNameMatch",
+ .comment = "Object(DS-DN) == a DN",
+ },{
+ .name = "Object(DN-Binary)",
+ .ldap_oid = "1.2.840.113556.1.4.903",
+ .oMSyntax = 127,
+ .oMObjectClass = OMOBJECTCLASS("\x2a\x86\x48\x86\xf7\x14\x01\x01\x01\x0b"),
+ .attributeSyntax_oid = "2.5.5.7",
+ .drsuapi_to_ldb = dsdb_syntax_DN_BINARY_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_DN_BINARY_ldb_to_drsuapi,
+ .equality = "distinguishedNameMatch",
+ .comment = "OctetString: Binary+DN",
+ .ldb_syntax = LDB_SYNTAX_DN,
+ },{
+ /* not used in w2k3 schema */
+ .name = "Object(OR-Name)",
+ .ldap_oid = "1.2.840.113556.1.4.1221",
+ .oMSyntax = 127,
+ .oMObjectClass = OMOBJECTCLASS("\x56\x06\x01\x02\x05\x0b\x1D"),
+ .attributeSyntax_oid = "2.5.5.7",
+ .drsuapi_to_ldb = dsdb_syntax_FOOBAR_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_FOOBAR_ldb_to_drsuapi,
+ },{
+ /*
+ * TODO: verify if DATA_BLOB is correct here...!
+ *
+ * repsFrom and repsTo are the only attributes using
+ * this attribute syntax, but they're not replicated...
+ */
+ .name = "Object(Replica-Link)",
+ .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.40",
+ .oMSyntax = 127,
+ .oMObjectClass = OMOBJECTCLASS("\x2a\x86\x48\x86\xf7\x14\x01\x01\x01\x06"),
+ .attributeSyntax_oid = "2.5.5.10",
+ .drsuapi_to_ldb = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
+ },{
+ .name = "Object(Presentation-Address)",
+ .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.43",
+ .oMSyntax = 127,
+ .oMObjectClass = OMOBJECTCLASS("\x2b\x0c\x02\x87\x73\x1c\x00\x85\x5c"),
+ .attributeSyntax_oid = "2.5.5.13",
+ .drsuapi_to_ldb = dsdb_syntax_PRESENTATION_ADDRESS_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_PRESENTATION_ADDRESS_ldb_to_drsuapi,
+ .comment = "Presentation Address"
+ },{
+ /* not used in w2k3 schema */
+ .name = "Object(Access-Point)",
+ .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.2",
+ .oMSyntax = 127,
+ .oMObjectClass = OMOBJECTCLASS("\x2b\x0c\x02\x87\x73\x1c\x00\x85\x3e"),
+ .attributeSyntax_oid = "2.5.5.14",
+ .drsuapi_to_ldb = dsdb_syntax_FOOBAR_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_FOOBAR_ldb_to_drsuapi,
+ .equality = "distinguishedNameMatch",
+ .comment = "OctetString: String+DN",
+ .ldb_syntax = LDB_SYNTAX_DN,
+ },{
+ /* not used in w2k3 schema */
+ .name = "Object(DN-String)",
+ .ldap_oid = "1.2.840.113556.1.4.904",
+ .oMSyntax = 127,
+ .oMObjectClass = OMOBJECTCLASS("\x2a\x86\x48\x86\xf7\x14\x01\x01\x01\x0c"),
+ .attributeSyntax_oid = "2.5.5.14",
+ .drsuapi_to_ldb = dsdb_syntax_FOOBAR_drsuapi_to_ldb,
+ .ldb_to_drsuapi = dsdb_syntax_FOOBAR_ldb_to_drsuapi,
+ .ldb_syntax = LDB_SYNTAX_DN,
+ }
+};
+
+const struct dsdb_syntax *find_syntax_map_by_ad_oid(const char *ad_oid)
+{
+ int i;
+ for (i=0; dsdb_syntaxes[i].ldap_oid; i++) {
+ if (strcasecmp(ad_oid, dsdb_syntaxes[i].attributeSyntax_oid) == 0) {
+ return &dsdb_syntaxes[i];
+ }
+ }
+ return NULL;
+}
+
+const struct dsdb_syntax *find_syntax_map_by_ad_syntax(int oMSyntax)
+{
+ int i;
+ for (i=0; dsdb_syntaxes[i].ldap_oid; i++) {
+ if (oMSyntax == dsdb_syntaxes[i].oMSyntax) {
+ return &dsdb_syntaxes[i];
+ }
+ }
+ return NULL;
+}
+
+const struct dsdb_syntax *find_syntax_map_by_standard_oid(const char *standard_oid)
+{
+ int i;
+ for (i=0; dsdb_syntaxes[i].ldap_oid; i++) {
+ if (strcasecmp(standard_oid, dsdb_syntaxes[i].ldap_oid) == 0) {
+ return &dsdb_syntaxes[i];
+ }
+ }
+ return NULL;
+}
+const struct dsdb_syntax *dsdb_syntax_for_attribute(const struct dsdb_attribute *attr)
+{
+ uint32_t i;
+
+ for (i=0; i < ARRAY_SIZE(dsdb_syntaxes); i++) {
+ if (attr->oMSyntax != dsdb_syntaxes[i].oMSyntax) continue;
+
+ if (attr->oMObjectClass.length != dsdb_syntaxes[i].oMObjectClass.length) continue;
+
+ if (attr->oMObjectClass.length) {
+ int ret;
+ ret = memcmp(attr->oMObjectClass.data,
+ dsdb_syntaxes[i].oMObjectClass.data,
+ attr->oMObjectClass.length);
+ if (ret != 0) continue;
+ }
+
+ if (strcmp(attr->attributeSyntax_oid, dsdb_syntaxes[i].attributeSyntax_oid) != 0) continue;
+
+ return &dsdb_syntaxes[i];
+ }
+
+ return NULL;
+}
+
+WERROR dsdb_attribute_drsuapi_to_ldb(const struct dsdb_schema *schema,
+ const struct drsuapi_DsReplicaAttribute *in,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *out)
+{
+ const struct dsdb_attribute *sa;
+
+ sa = dsdb_attribute_by_attributeID_id(schema, in->attid);
+ if (!sa) {
+ return WERR_FOOBAR;
+ }
+
+ return sa->syntax->drsuapi_to_ldb(schema, sa, in, mem_ctx, out);
+}
+
+WERROR dsdb_attribute_ldb_to_drsuapi(const struct dsdb_schema *schema,
+ const struct ldb_message_element *in,
+ TALLOC_CTX *mem_ctx,
+ struct drsuapi_DsReplicaAttribute *out)
+{
+ const struct dsdb_attribute *sa;
+
+ sa = dsdb_attribute_by_lDAPDisplayName(schema, in->name);
+ if (!sa) {
+ return WERR_FOOBAR;
+ }
+
+ return sa->syntax->ldb_to_drsuapi(schema, sa, in, mem_ctx, out);
+}