summaryrefslogtreecommitdiffstats
path: root/source4/dsdb/schema/schema_prefixmap.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
commit8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch)
tree4099e8021376c7d8c05bdf8503093d80e9c7bad0 /source4/dsdb/schema/schema_prefixmap.c
parentInitial commit. (diff)
downloadsamba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz
samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source4/dsdb/schema/schema_prefixmap.c')
-rw-r--r--source4/dsdb/schema/schema_prefixmap.c710
1 files changed, 710 insertions, 0 deletions
diff --git a/source4/dsdb/schema/schema_prefixmap.c b/source4/dsdb/schema/schema_prefixmap.c
new file mode 100644
index 0000000..3a6a130
--- /dev/null
+++ b/source4/dsdb/schema/schema_prefixmap.c
@@ -0,0 +1,710 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ DRS::prefixMap implementation
+
+ Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2009
+
+ 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 "librpc/gen_ndr/ndr_drsblobs.h"
+#include "../lib/util/asn1.h"
+#include "lib/util/smb_strtox.h"
+
+
+/**
+ * Determine range type for supplied ATTID
+ */
+enum dsdb_attid_type dsdb_pfm_get_attid_type(uint32_t attid)
+{
+ if (attid <= 0x7FFFFFFF) {
+ return DSDB_ATTID_TYPE_PFM;
+ }
+ else if (attid <= 0xBFFFFFFF) {
+ return DSDB_ATTID_TYPE_INTID;
+ }
+ else if (attid <= 0xFFFEFFFF) {
+ return DSDB_ATTID_TYPE_RESERVED;
+ }
+ else {
+ return DSDB_ATTID_TYPE_INTERNAL;
+ }
+}
+
+/**
+ * Allocates schema_prefixMap object in supplied memory context
+ */
+static struct dsdb_schema_prefixmap *_dsdb_schema_prefixmap_talloc(TALLOC_CTX *mem_ctx,
+ uint32_t length)
+{
+ struct dsdb_schema_prefixmap *pfm;
+
+ pfm = talloc_zero(mem_ctx, struct dsdb_schema_prefixmap);
+ if (!pfm) {
+ return NULL;
+ }
+
+ pfm->length = length;
+ pfm->prefixes = talloc_zero_array(pfm, struct dsdb_schema_prefixmap_oid,
+ pfm->length);
+ if (!pfm->prefixes) {
+ talloc_free(pfm);
+ return NULL;
+ }
+
+ return pfm;
+}
+
+/**
+ * Initial prefixMap creation according to:
+ * [MS-DRSR] section 5.12.2
+ */
+WERROR dsdb_schema_pfm_new(TALLOC_CTX *mem_ctx, struct dsdb_schema_prefixmap **_pfm)
+{
+ uint32_t i;
+ struct dsdb_schema_prefixmap *pfm;
+ const struct {
+ uint32_t id;
+ const char *oid_prefix;
+ } pfm_init_data[] = {
+ {.id=0x00000000, .oid_prefix="2.5.4"},
+ {.id=0x00000001, .oid_prefix="2.5.6"},
+ {.id=0x00000002, .oid_prefix="1.2.840.113556.1.2"},
+ {.id=0x00000003, .oid_prefix="1.2.840.113556.1.3"},
+ {.id=0x00000004, .oid_prefix="2.16.840.1.101.2.2.1"},
+ {.id=0x00000005, .oid_prefix="2.16.840.1.101.2.2.3"},
+ {.id=0x00000006, .oid_prefix="2.16.840.1.101.2.1.5"},
+ {.id=0x00000007, .oid_prefix="2.16.840.1.101.2.1.4"},
+ {.id=0x00000008, .oid_prefix="2.5.5"},
+ {.id=0x00000009, .oid_prefix="1.2.840.113556.1.4"},
+ {.id=0x0000000A, .oid_prefix="1.2.840.113556.1.5"},
+ {.id=0x00000013, .oid_prefix="0.9.2342.19200300.100"},
+ {.id=0x00000014, .oid_prefix="2.16.840.1.113730.3"},
+ {.id=0x00000015, .oid_prefix="0.9.2342.19200300.100.1"},
+ {.id=0x00000016, .oid_prefix="2.16.840.1.113730.3.1"},
+ {.id=0x00000017, .oid_prefix="1.2.840.113556.1.5.7000"},
+ {.id=0x00000018, .oid_prefix="2.5.21"},
+ {.id=0x00000019, .oid_prefix="2.5.18"},
+ {.id=0x0000001A, .oid_prefix="2.5.20"},
+ };
+
+ /* allocate mem for prefix map */
+ pfm = _dsdb_schema_prefixmap_talloc(mem_ctx, ARRAY_SIZE(pfm_init_data));
+ W_ERROR_HAVE_NO_MEMORY(pfm);
+
+ /* build prefixes */
+ for (i = 0; i < pfm->length; i++) {
+ if (!ber_write_partial_OID_String(pfm, &pfm->prefixes[i].bin_oid, pfm_init_data[i].oid_prefix)) {
+ talloc_free(pfm);
+ return WERR_INTERNAL_ERROR;
+ }
+ pfm->prefixes[i].id = pfm_init_data[i].id;
+ }
+
+ *_pfm = pfm;
+
+ return WERR_OK;
+}
+
+
+struct dsdb_schema_prefixmap *dsdb_schema_pfm_copy_shallow(TALLOC_CTX *mem_ctx,
+ const struct dsdb_schema_prefixmap *pfm)
+{
+ uint32_t i;
+ struct dsdb_schema_prefixmap *pfm_copy;
+
+ pfm_copy = _dsdb_schema_prefixmap_talloc(mem_ctx, pfm->length);
+ if (!pfm_copy) {
+ return NULL;
+ }
+ for (i = 0; i < pfm_copy->length; i++) {
+ pfm_copy->prefixes[i] = pfm->prefixes[i];
+ }
+
+ return pfm_copy;
+}
+
+/**
+ * Adds oid to prefix map.
+ * On success returns ID for newly added index
+ * or ID of existing entry that matches oid
+ * Reference: [MS-DRSR] section 5.12.2
+ *
+ * \param pfm prefixMap
+ * \param bin_oid OID prefix to be added to prefixMap
+ * \param pfm_id Location where to store prefixMap entry ID
+ */
+WERROR dsdb_schema_pfm_add_entry(struct dsdb_schema_prefixmap *pfm,
+ DATA_BLOB bin_oid,
+ const uint32_t *remote_id,
+ uint32_t *_idx)
+{
+ uint32_t i;
+ struct dsdb_schema_prefixmap_oid * pfm_entry;
+ struct dsdb_schema_prefixmap_oid * prefixes_new;
+
+ /* dup memory for bin-oid prefix to be added */
+ bin_oid = data_blob_dup_talloc(pfm, bin_oid);
+ W_ERROR_HAVE_NO_MEMORY(bin_oid.data);
+
+ /* make room for new entry */
+ prefixes_new = talloc_realloc(pfm, pfm->prefixes, struct dsdb_schema_prefixmap_oid, pfm->length + 1);
+ if (!prefixes_new) {
+ talloc_free(bin_oid.data);
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+ pfm->prefixes = prefixes_new;
+
+ /* make new unique ID in prefixMap */
+ pfm_entry = &pfm->prefixes[pfm->length];
+ pfm_entry->id = 0;
+ for (i = 0; i < pfm->length; i++) {
+ if (pfm_entry->id < pfm->prefixes[i].id) {
+ pfm_entry->id = pfm->prefixes[i].id;
+ }
+
+ if (remote_id == NULL) {
+ continue;
+ }
+
+ if (pfm->prefixes[i].id == *remote_id) {
+ /*
+ * We can't use the remote id.
+ * it's already in use.
+ */
+ remote_id = NULL;
+ }
+ }
+
+ /* add new bin-oid prefix */
+ if (remote_id != NULL) {
+ pfm_entry->id = *remote_id;
+ } else {
+ pfm_entry->id++;
+ }
+ pfm_entry->bin_oid = bin_oid;
+
+ if (_idx != NULL) {
+ *_idx = pfm->length;
+ }
+ pfm->length++;
+
+ return WERR_OK;
+}
+
+
+/**
+ * Make partial binary OID for supplied OID.
+ * Reference: [MS-DRSR] section 5.12.2
+ */
+static WERROR _dsdb_pfm_make_binary_oid(const char *full_oid, TALLOC_CTX *mem_ctx,
+ DATA_BLOB *_bin_oid, uint32_t *_last_subid)
+{
+ uint32_t last_subid;
+ const char *oid_subid;
+ int error = 0;
+
+ /* make last sub-identifier value */
+ oid_subid = strrchr(full_oid, '.');
+ if (!oid_subid) {
+ return WERR_INVALID_PARAMETER;
+ }
+ oid_subid++;
+ last_subid = smb_strtoul(oid_subid, NULL, 10, &error, SMB_STR_STANDARD);
+ if (error != 0) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ /* encode oid in BER format */
+ if (!ber_write_OID_String(mem_ctx, _bin_oid, full_oid)) {
+ DEBUG(0,("ber_write_OID_String() failed for %s\n", full_oid));
+ return WERR_INTERNAL_ERROR;
+ }
+
+ /* get the prefix of the OID */
+ if (last_subid < 128) {
+ _bin_oid->length -= 1;
+ } else {
+ _bin_oid->length -= 2;
+ }
+
+ /* return last_value if requested */
+ if (_last_subid) {
+ *_last_subid = last_subid;
+ }
+
+ return WERR_OK;
+}
+
+/**
+ * Lookup partial-binary-oid in prefixMap
+ */
+WERROR dsdb_schema_pfm_find_binary_oid(const struct dsdb_schema_prefixmap *pfm,
+ DATA_BLOB bin_oid,
+ uint32_t *_idx)
+{
+ uint32_t i;
+
+ for (i = 0; i < pfm->length; i++) {
+ if (pfm->prefixes[i].bin_oid.length != bin_oid.length) {
+ continue;
+ }
+
+ if (memcmp(pfm->prefixes[i].bin_oid.data, bin_oid.data, bin_oid.length) == 0) {
+ if (_idx) {
+ *_idx = i;
+ }
+ return WERR_OK;
+ }
+ }
+
+ return WERR_NOT_FOUND;
+}
+
+/**
+ * Lookup full-oid in prefixMap
+ * Note: this may be slow.
+ */
+WERROR dsdb_schema_pfm_find_oid(const struct dsdb_schema_prefixmap *pfm,
+ const char *full_oid,
+ uint32_t *_idx)
+{
+ WERROR werr;
+ DATA_BLOB bin_oid;
+
+ ZERO_STRUCT(bin_oid);
+
+ /* make partial-binary-oid to look for */
+ werr = _dsdb_pfm_make_binary_oid(full_oid, NULL, &bin_oid, NULL);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ /* lookup the partial-oid */
+ werr = dsdb_schema_pfm_find_binary_oid(pfm, bin_oid, _idx);
+
+ data_blob_free(&bin_oid);
+
+ return werr;
+}
+
+/**
+ * Make ATTID for given OID
+ * If OID is not in prefixMap, new prefix
+ * may be added depending on 'can_change_pfm' flag
+ * Reference: [MS-DRSR] section 5.12.2
+ */
+static WERROR dsdb_schema_pfm_make_attid_impl(struct dsdb_schema_prefixmap *pfm,
+ const char *oid,
+ bool can_change_pfm,
+ uint32_t *attid)
+{
+ WERROR werr;
+ uint32_t idx;
+ uint32_t lo_word, hi_word;
+ uint32_t last_subid;
+ DATA_BLOB bin_oid;
+
+ if (!pfm) {
+ return WERR_INVALID_PARAMETER;
+ }
+ if (!oid) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ werr = _dsdb_pfm_make_binary_oid(oid, pfm, &bin_oid, &last_subid);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ /* search the prefix in the prefix table, if none found, add
+ * one entry for new prefix.
+ */
+ werr = dsdb_schema_pfm_find_binary_oid(pfm, bin_oid, &idx);
+ if (W_ERROR_IS_OK(werr)) {
+ /* free memory allocated for bin_oid */
+ data_blob_free(&bin_oid);
+ } else {
+ /* return error in read-only mode */
+ if (!can_change_pfm) {
+ DEBUG(0, ("Unable to convert %s to an attid, and can_change_pfm=false!\n", oid));
+ return werr;
+ }
+
+ /* entry does not exists, add it */
+ werr = dsdb_schema_pfm_add_entry(pfm, bin_oid, NULL, &idx);
+ W_ERROR_NOT_OK_RETURN(werr);
+ }
+
+ /* compose the attid */
+ lo_word = last_subid % 16384; /* actually get lower 14 bits: lo_word & 0x3FFF */
+ if (last_subid >= 16384) {
+ /* mark it so that it is known to not be the whole lastValue
+ * This will raise 16-th bit*/
+ lo_word += 32768;
+ }
+ hi_word = pfm->prefixes[idx].id;
+
+ /* make ATTID:
+ * HIWORD is prefixMap id
+ * LOWORD is truncated binary-oid */
+ *attid = (hi_word * 65536) + lo_word;
+
+ return WERR_OK;
+}
+
+/**
+ * Make ATTID for given OID
+ * Reference: [MS-DRSR] section 5.12.2
+ *
+ * Note: This function may change prefixMap if prefix
+ * for supplied 'oid' doesn't exists yet.
+ * It is recommended to be used mostly when caller
+ * want to add new prefixes.
+ * Otherwise dsdb_schema_pfm_attid_from_oid() should be used.
+ */
+WERROR dsdb_schema_pfm_make_attid(struct dsdb_schema_prefixmap *pfm,
+ const char *oid,
+ uint32_t *attid)
+{
+ return dsdb_schema_pfm_make_attid_impl(pfm, oid, true, attid);
+}
+
+/**
+ * Make ATTID for given OID
+ * Reference: [MS-DRSR] section 5.12.2
+ */
+WERROR dsdb_schema_pfm_attid_from_oid(struct dsdb_schema_prefixmap *pfm,
+ const char *oid,
+ uint32_t *attid)
+{
+ return dsdb_schema_pfm_make_attid_impl(pfm, oid, false, attid);
+}
+
+/**
+ * Make OID for given ATTID.
+ * Reference: [MS-DRSR] section 5.12.2
+ */
+WERROR dsdb_schema_pfm_oid_from_attid(const struct dsdb_schema_prefixmap *pfm,
+ uint32_t attid,
+ TALLOC_CTX *mem_ctx, const char **_oid)
+{
+ uint32_t i;
+ uint32_t hi_word, lo_word;
+ DATA_BLOB bin_oid = {NULL, 0};
+ char *oid;
+ struct dsdb_schema_prefixmap_oid *pfm_entry;
+ WERROR werr = WERR_OK;
+
+ /* sanity check for attid requested */
+ if (dsdb_pfm_get_attid_type(attid) != DSDB_ATTID_TYPE_PFM) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ /* crack attid value */
+ hi_word = attid >> 16;
+ lo_word = attid & 0xFFFF;
+
+ /* locate corRespoNding prefixMap entry */
+ pfm_entry = NULL;
+ for (i = 0; i < pfm->length; i++) {
+ if (hi_word == pfm->prefixes[i].id) {
+ pfm_entry = &pfm->prefixes[i];
+ break;
+ }
+ }
+
+ if (!pfm_entry) {
+ DEBUG(1,("Failed to find prefixMap entry for ATTID = 0x%08X (%d)\n",
+ attid, attid));
+ return WERR_DS_NO_ATTRIBUTE_OR_VALUE;
+ }
+
+ /* copy oid prefix making enough room */
+ bin_oid.length = pfm_entry->bin_oid.length + 2;
+ bin_oid.data = talloc_array(mem_ctx, uint8_t, bin_oid.length);
+ W_ERROR_HAVE_NO_MEMORY(bin_oid.data);
+ memcpy(bin_oid.data, pfm_entry->bin_oid.data, pfm_entry->bin_oid.length);
+
+ if (lo_word < 128) {
+ bin_oid.length = bin_oid.length - 1;
+ bin_oid.data[bin_oid.length-1] = lo_word;
+ }
+ else {
+ if (lo_word >= 32768) {
+ lo_word -= 32768;
+ }
+ bin_oid.data[bin_oid.length-2] = (0x80 | ((lo_word>>7) & 0x7f));
+ bin_oid.data[bin_oid.length-1] = lo_word & 0x7f;
+ }
+
+ if (!ber_read_OID_String(mem_ctx, bin_oid, &oid)) {
+ DEBUG(0,("ber_read_OID_String() failed for %s\n",
+ hex_encode_talloc(bin_oid.data, bin_oid.data, bin_oid.length)));
+ werr = WERR_INTERNAL_ERROR;
+ }
+
+ /* free locally allocated memory */
+ talloc_free(bin_oid.data);
+
+ *_oid = oid;
+
+ return werr;
+}
+
+
+/**
+ * Verifies drsuapi mappings.
+ */
+static WERROR _dsdb_drsuapi_pfm_verify(const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr,
+ bool have_schema_info)
+{
+ uint32_t i;
+ uint32_t num_mappings;
+ struct drsuapi_DsReplicaOIDMapping *mapping;
+
+ /* check input params */
+ if (!ctr) {
+ return WERR_INVALID_PARAMETER;
+ }
+ if (!ctr->mappings) {
+ return WERR_INVALID_PARAMETER;
+ }
+ num_mappings = ctr->num_mappings;
+
+ if (have_schema_info) {
+ DATA_BLOB blob;
+
+ if (ctr->num_mappings < 2) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ /* check last entry for being special */
+ mapping = &ctr->mappings[ctr->num_mappings - 1];
+ if (mapping->id_prefix != 0) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ /* verify schemaInfo blob is valid one */
+ blob = data_blob_const(mapping->oid.binary_oid, mapping->oid.length);
+ if (!dsdb_schema_info_blob_is_valid(&blob)) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ /* get number of read mappings in the map */
+ num_mappings--;
+ }
+
+ /* now, verify rest of entries for being at least not null */
+ for (i = 0; i < num_mappings; i++) {
+ mapping = &ctr->mappings[i];
+ if (!mapping->oid.length) {
+ return WERR_INVALID_PARAMETER;
+ }
+ if (!mapping->oid.binary_oid) {
+ return WERR_INVALID_PARAMETER;
+ }
+ /* check it is not the special entry */
+ if (*mapping->oid.binary_oid == 0xFF) {
+ return WERR_INVALID_PARAMETER;
+ }
+ }
+
+ return WERR_OK;
+}
+
+/**
+ * Convert drsuapi_ prefix map to prefixMap internal presentation.
+ *
+ * \param ctr Pointer to drsuapi_DsReplicaOIDMapping_Ctr which represents drsuapi_ prefixMap
+ * \param have_schema_info if drsuapi_prefixMap have schem_info in it or not
+ * \param mem_ctx TALLOC_CTX to make allocations in
+ * \param _pfm Out pointer to hold newly created prefixMap
+ * \param _schema_info Out param to store schema_info to. If NULL, schema_info is not decoded
+ */
+WERROR dsdb_schema_pfm_from_drsuapi_pfm(const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr,
+ bool have_schema_info,
+ TALLOC_CTX *mem_ctx,
+ struct dsdb_schema_prefixmap **_pfm,
+ struct dsdb_schema_info **_schema_info)
+{
+ WERROR werr;
+ uint32_t i;
+ DATA_BLOB blob;
+ uint32_t num_mappings;
+ struct dsdb_schema_prefixmap *pfm;
+
+ if (!_pfm) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ /*
+ * error out if schema_info is requested
+ * but it is not in the drsuapi_prefixMap
+ */
+ if (_schema_info && !have_schema_info) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ /* verify drsuapi_pefixMap */
+ werr =_dsdb_drsuapi_pfm_verify(ctr, have_schema_info);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ /* allocate mem for prefix map */
+ num_mappings = ctr->num_mappings;
+ if (have_schema_info) {
+ num_mappings--;
+ }
+ pfm = _dsdb_schema_prefixmap_talloc(mem_ctx, num_mappings);
+ W_ERROR_HAVE_NO_MEMORY(pfm);
+
+ /* copy entries from drsuapi_prefixMap */
+ for (i = 0; i < pfm->length; i++) {
+ blob = data_blob_talloc(pfm,
+ ctr->mappings[i].oid.binary_oid,
+ ctr->mappings[i].oid.length);
+ if (!blob.data) {
+ talloc_free(pfm);
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+ pfm->prefixes[i].id = ctr->mappings[i].id_prefix;
+ pfm->prefixes[i].bin_oid = blob;
+ }
+
+ /* fetch schema_info if requested */
+ if (_schema_info) {
+ /* by this time, i should have this value,
+ * but set it here for clarity */
+ i = ctr->num_mappings - 1;
+
+ blob = data_blob_const(ctr->mappings[i].oid.binary_oid,
+ ctr->mappings[i].oid.length);
+ werr = dsdb_schema_info_from_blob(&blob, mem_ctx, _schema_info);
+ if (!W_ERROR_IS_OK(werr)) {
+ talloc_free(pfm);
+ return werr;
+ }
+ }
+
+ /* schema_prefixMap created successfully */
+ *_pfm = pfm;
+
+ return WERR_OK;
+}
+
+/**
+ * Convert drsuapi_ prefix map to prefixMap internal presentation.
+ *
+ * \param pfm Schema prefixMap to be converted
+ * \param schema_info schema_info string - if NULL, we don't need it
+ * \param mem_ctx TALLOC_CTX to make allocations in
+ * \param _ctr Out pointer to drsuapi_DsReplicaOIDMapping_Ctr prefix map structure
+ */
+WERROR dsdb_drsuapi_pfm_from_schema_pfm(const struct dsdb_schema_prefixmap *pfm,
+ const struct dsdb_schema_info *schema_info,
+ TALLOC_CTX *mem_ctx,
+ struct drsuapi_DsReplicaOIDMapping_Ctr **_ctr)
+{
+ uint32_t i;
+ DATA_BLOB blob;
+ struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
+
+ if (!_ctr) {
+ return WERR_INVALID_PARAMETER;
+ }
+ if (!pfm) {
+ return WERR_INVALID_PARAMETER;
+ }
+ if (pfm->length == 0) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ /* allocate memory for the structure */
+ ctr = talloc_zero(mem_ctx, struct drsuapi_DsReplicaOIDMapping_Ctr);
+ W_ERROR_HAVE_NO_MEMORY(ctr);
+
+ ctr->num_mappings = (schema_info ? pfm->length + 1 : pfm->length);
+ ctr->mappings = talloc_array(ctr, struct drsuapi_DsReplicaOIDMapping, ctr->num_mappings);
+ if (!ctr->mappings) {
+ talloc_free(ctr);
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* copy entries from schema_prefixMap */
+ for (i = 0; i < pfm->length; i++) {
+ blob = data_blob_dup_talloc(ctr, pfm->prefixes[i].bin_oid);
+ if (!blob.data) {
+ talloc_free(ctr);
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+ ctr->mappings[i].id_prefix = pfm->prefixes[i].id;
+ ctr->mappings[i].oid.length = blob.length;
+ ctr->mappings[i].oid.binary_oid = blob.data;
+ }
+
+ /* make schema_info entry if needed */
+ if (schema_info) {
+ WERROR werr;
+
+ /* by this time, i should have this value,
+ * but set it here for clarity */
+ i = ctr->num_mappings - 1;
+
+ werr = dsdb_blob_from_schema_info(schema_info, ctr, &blob);
+ if (!W_ERROR_IS_OK(werr)) {
+ talloc_free(ctr);
+ return werr;
+ }
+
+ ctr->mappings[i].id_prefix = 0;
+ ctr->mappings[i].oid.length = blob.length;
+ ctr->mappings[i].oid.binary_oid = blob.data;
+ }
+
+ /* drsuapi_prefixMap constructed successfully */
+ *_ctr = ctr;
+
+ return WERR_OK;
+}
+
+/**
+ * Verifies schema prefixMap and drsuapi prefixMap are same.
+ * Note that we just need to verify pfm contains prefixes
+ * from ctr, not that those prefixes has same id_prefix.
+ */
+WERROR dsdb_schema_pfm_contains_drsuapi_pfm(const struct dsdb_schema_prefixmap *pfm,
+ const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
+{
+ WERROR werr;
+ uint32_t i;
+ uint32_t idx;
+ DATA_BLOB bin_oid;
+
+ /* verify drsuapi_pefixMap */
+ werr = _dsdb_drsuapi_pfm_verify(ctr, true);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ /* check pfm contains every entry from ctr, except the last one */
+ for (i = 0; i < ctr->num_mappings - 1; i++) {
+ bin_oid.length = ctr->mappings[i].oid.length;
+ bin_oid.data = ctr->mappings[i].oid.binary_oid;
+
+ werr = dsdb_schema_pfm_find_binary_oid(pfm, bin_oid, &idx);
+ if (!W_ERROR_IS_OK(werr)) {
+ return WERR_DS_DRA_SCHEMA_MISMATCH;
+ }
+ }
+
+ return WERR_OK;
+}