libcli/auth: let netlogon_creds_copy() make use of ndr_deepcopy_struct()
[samba4-gss.git] / source4 / dsdb / schema / schema_prefixmap.c
blob3a6a13059fd76db4915541efcbefa7f5a4560028
1 /*
2 Unix SMB/CIFS implementation.
4 DRS::prefixMap implementation
6 Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2009
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "dsdb/samdb/samdb.h"
24 #include "librpc/gen_ndr/ndr_drsuapi.h"
25 #include "librpc/gen_ndr/ndr_drsblobs.h"
26 #include "../lib/util/asn1.h"
27 #include "lib/util/smb_strtox.h"
30 /**
31 * Determine range type for supplied ATTID
33 enum dsdb_attid_type dsdb_pfm_get_attid_type(uint32_t attid)
35 if (attid <= 0x7FFFFFFF) {
36 return DSDB_ATTID_TYPE_PFM;
38 else if (attid <= 0xBFFFFFFF) {
39 return DSDB_ATTID_TYPE_INTID;
41 else if (attid <= 0xFFFEFFFF) {
42 return DSDB_ATTID_TYPE_RESERVED;
44 else {
45 return DSDB_ATTID_TYPE_INTERNAL;
49 /**
50 * Allocates schema_prefixMap object in supplied memory context
52 static struct dsdb_schema_prefixmap *_dsdb_schema_prefixmap_talloc(TALLOC_CTX *mem_ctx,
53 uint32_t length)
55 struct dsdb_schema_prefixmap *pfm;
57 pfm = talloc_zero(mem_ctx, struct dsdb_schema_prefixmap);
58 if (!pfm) {
59 return NULL;
62 pfm->length = length;
63 pfm->prefixes = talloc_zero_array(pfm, struct dsdb_schema_prefixmap_oid,
64 pfm->length);
65 if (!pfm->prefixes) {
66 talloc_free(pfm);
67 return NULL;
70 return pfm;
73 /**
74 * Initial prefixMap creation according to:
75 * [MS-DRSR] section 5.12.2
77 WERROR dsdb_schema_pfm_new(TALLOC_CTX *mem_ctx, struct dsdb_schema_prefixmap **_pfm)
79 uint32_t i;
80 struct dsdb_schema_prefixmap *pfm;
81 const struct {
82 uint32_t id;
83 const char *oid_prefix;
84 } pfm_init_data[] = {
85 {.id=0x00000000, .oid_prefix="2.5.4"},
86 {.id=0x00000001, .oid_prefix="2.5.6"},
87 {.id=0x00000002, .oid_prefix="1.2.840.113556.1.2"},
88 {.id=0x00000003, .oid_prefix="1.2.840.113556.1.3"},
89 {.id=0x00000004, .oid_prefix="2.16.840.1.101.2.2.1"},
90 {.id=0x00000005, .oid_prefix="2.16.840.1.101.2.2.3"},
91 {.id=0x00000006, .oid_prefix="2.16.840.1.101.2.1.5"},
92 {.id=0x00000007, .oid_prefix="2.16.840.1.101.2.1.4"},
93 {.id=0x00000008, .oid_prefix="2.5.5"},
94 {.id=0x00000009, .oid_prefix="1.2.840.113556.1.4"},
95 {.id=0x0000000A, .oid_prefix="1.2.840.113556.1.5"},
96 {.id=0x00000013, .oid_prefix="0.9.2342.19200300.100"},
97 {.id=0x00000014, .oid_prefix="2.16.840.1.113730.3"},
98 {.id=0x00000015, .oid_prefix="0.9.2342.19200300.100.1"},
99 {.id=0x00000016, .oid_prefix="2.16.840.1.113730.3.1"},
100 {.id=0x00000017, .oid_prefix="1.2.840.113556.1.5.7000"},
101 {.id=0x00000018, .oid_prefix="2.5.21"},
102 {.id=0x00000019, .oid_prefix="2.5.18"},
103 {.id=0x0000001A, .oid_prefix="2.5.20"},
106 /* allocate mem for prefix map */
107 pfm = _dsdb_schema_prefixmap_talloc(mem_ctx, ARRAY_SIZE(pfm_init_data));
108 W_ERROR_HAVE_NO_MEMORY(pfm);
110 /* build prefixes */
111 for (i = 0; i < pfm->length; i++) {
112 if (!ber_write_partial_OID_String(pfm, &pfm->prefixes[i].bin_oid, pfm_init_data[i].oid_prefix)) {
113 talloc_free(pfm);
114 return WERR_INTERNAL_ERROR;
116 pfm->prefixes[i].id = pfm_init_data[i].id;
119 *_pfm = pfm;
121 return WERR_OK;
125 struct dsdb_schema_prefixmap *dsdb_schema_pfm_copy_shallow(TALLOC_CTX *mem_ctx,
126 const struct dsdb_schema_prefixmap *pfm)
128 uint32_t i;
129 struct dsdb_schema_prefixmap *pfm_copy;
131 pfm_copy = _dsdb_schema_prefixmap_talloc(mem_ctx, pfm->length);
132 if (!pfm_copy) {
133 return NULL;
135 for (i = 0; i < pfm_copy->length; i++) {
136 pfm_copy->prefixes[i] = pfm->prefixes[i];
139 return pfm_copy;
143 * Adds oid to prefix map.
144 * On success returns ID for newly added index
145 * or ID of existing entry that matches oid
146 * Reference: [MS-DRSR] section 5.12.2
148 * \param pfm prefixMap
149 * \param bin_oid OID prefix to be added to prefixMap
150 * \param pfm_id Location where to store prefixMap entry ID
152 WERROR dsdb_schema_pfm_add_entry(struct dsdb_schema_prefixmap *pfm,
153 DATA_BLOB bin_oid,
154 const uint32_t *remote_id,
155 uint32_t *_idx)
157 uint32_t i;
158 struct dsdb_schema_prefixmap_oid * pfm_entry;
159 struct dsdb_schema_prefixmap_oid * prefixes_new;
161 /* dup memory for bin-oid prefix to be added */
162 bin_oid = data_blob_dup_talloc(pfm, bin_oid);
163 W_ERROR_HAVE_NO_MEMORY(bin_oid.data);
165 /* make room for new entry */
166 prefixes_new = talloc_realloc(pfm, pfm->prefixes, struct dsdb_schema_prefixmap_oid, pfm->length + 1);
167 if (!prefixes_new) {
168 talloc_free(bin_oid.data);
169 return WERR_NOT_ENOUGH_MEMORY;
171 pfm->prefixes = prefixes_new;
173 /* make new unique ID in prefixMap */
174 pfm_entry = &pfm->prefixes[pfm->length];
175 pfm_entry->id = 0;
176 for (i = 0; i < pfm->length; i++) {
177 if (pfm_entry->id < pfm->prefixes[i].id) {
178 pfm_entry->id = pfm->prefixes[i].id;
181 if (remote_id == NULL) {
182 continue;
185 if (pfm->prefixes[i].id == *remote_id) {
187 * We can't use the remote id.
188 * it's already in use.
190 remote_id = NULL;
194 /* add new bin-oid prefix */
195 if (remote_id != NULL) {
196 pfm_entry->id = *remote_id;
197 } else {
198 pfm_entry->id++;
200 pfm_entry->bin_oid = bin_oid;
202 if (_idx != NULL) {
203 *_idx = pfm->length;
205 pfm->length++;
207 return WERR_OK;
212 * Make partial binary OID for supplied OID.
213 * Reference: [MS-DRSR] section 5.12.2
215 static WERROR _dsdb_pfm_make_binary_oid(const char *full_oid, TALLOC_CTX *mem_ctx,
216 DATA_BLOB *_bin_oid, uint32_t *_last_subid)
218 uint32_t last_subid;
219 const char *oid_subid;
220 int error = 0;
222 /* make last sub-identifier value */
223 oid_subid = strrchr(full_oid, '.');
224 if (!oid_subid) {
225 return WERR_INVALID_PARAMETER;
227 oid_subid++;
228 last_subid = smb_strtoul(oid_subid, NULL, 10, &error, SMB_STR_STANDARD);
229 if (error != 0) {
230 return WERR_INVALID_PARAMETER;
233 /* encode oid in BER format */
234 if (!ber_write_OID_String(mem_ctx, _bin_oid, full_oid)) {
235 DEBUG(0,("ber_write_OID_String() failed for %s\n", full_oid));
236 return WERR_INTERNAL_ERROR;
239 /* get the prefix of the OID */
240 if (last_subid < 128) {
241 _bin_oid->length -= 1;
242 } else {
243 _bin_oid->length -= 2;
246 /* return last_value if requested */
247 if (_last_subid) {
248 *_last_subid = last_subid;
251 return WERR_OK;
255 * Lookup partial-binary-oid in prefixMap
257 WERROR dsdb_schema_pfm_find_binary_oid(const struct dsdb_schema_prefixmap *pfm,
258 DATA_BLOB bin_oid,
259 uint32_t *_idx)
261 uint32_t i;
263 for (i = 0; i < pfm->length; i++) {
264 if (pfm->prefixes[i].bin_oid.length != bin_oid.length) {
265 continue;
268 if (memcmp(pfm->prefixes[i].bin_oid.data, bin_oid.data, bin_oid.length) == 0) {
269 if (_idx) {
270 *_idx = i;
272 return WERR_OK;
276 return WERR_NOT_FOUND;
280 * Lookup full-oid in prefixMap
281 * Note: this may be slow.
283 WERROR dsdb_schema_pfm_find_oid(const struct dsdb_schema_prefixmap *pfm,
284 const char *full_oid,
285 uint32_t *_idx)
287 WERROR werr;
288 DATA_BLOB bin_oid;
290 ZERO_STRUCT(bin_oid);
292 /* make partial-binary-oid to look for */
293 werr = _dsdb_pfm_make_binary_oid(full_oid, NULL, &bin_oid, NULL);
294 W_ERROR_NOT_OK_RETURN(werr);
296 /* lookup the partial-oid */
297 werr = dsdb_schema_pfm_find_binary_oid(pfm, bin_oid, _idx);
299 data_blob_free(&bin_oid);
301 return werr;
305 * Make ATTID for given OID
306 * If OID is not in prefixMap, new prefix
307 * may be added depending on 'can_change_pfm' flag
308 * Reference: [MS-DRSR] section 5.12.2
310 static WERROR dsdb_schema_pfm_make_attid_impl(struct dsdb_schema_prefixmap *pfm,
311 const char *oid,
312 bool can_change_pfm,
313 uint32_t *attid)
315 WERROR werr;
316 uint32_t idx;
317 uint32_t lo_word, hi_word;
318 uint32_t last_subid;
319 DATA_BLOB bin_oid;
321 if (!pfm) {
322 return WERR_INVALID_PARAMETER;
324 if (!oid) {
325 return WERR_INVALID_PARAMETER;
328 werr = _dsdb_pfm_make_binary_oid(oid, pfm, &bin_oid, &last_subid);
329 W_ERROR_NOT_OK_RETURN(werr);
331 /* search the prefix in the prefix table, if none found, add
332 * one entry for new prefix.
334 werr = dsdb_schema_pfm_find_binary_oid(pfm, bin_oid, &idx);
335 if (W_ERROR_IS_OK(werr)) {
336 /* free memory allocated for bin_oid */
337 data_blob_free(&bin_oid);
338 } else {
339 /* return error in read-only mode */
340 if (!can_change_pfm) {
341 DEBUG(0, ("Unable to convert %s to an attid, and can_change_pfm=false!\n", oid));
342 return werr;
345 /* entry does not exists, add it */
346 werr = dsdb_schema_pfm_add_entry(pfm, bin_oid, NULL, &idx);
347 W_ERROR_NOT_OK_RETURN(werr);
350 /* compose the attid */
351 lo_word = last_subid % 16384; /* actually get lower 14 bits: lo_word & 0x3FFF */
352 if (last_subid >= 16384) {
353 /* mark it so that it is known to not be the whole lastValue
354 * This will raise 16-th bit*/
355 lo_word += 32768;
357 hi_word = pfm->prefixes[idx].id;
359 /* make ATTID:
360 * HIWORD is prefixMap id
361 * LOWORD is truncated binary-oid */
362 *attid = (hi_word * 65536) + lo_word;
364 return WERR_OK;
368 * Make ATTID for given OID
369 * Reference: [MS-DRSR] section 5.12.2
371 * Note: This function may change prefixMap if prefix
372 * for supplied 'oid' doesn't exists yet.
373 * It is recommended to be used mostly when caller
374 * want to add new prefixes.
375 * Otherwise dsdb_schema_pfm_attid_from_oid() should be used.
377 WERROR dsdb_schema_pfm_make_attid(struct dsdb_schema_prefixmap *pfm,
378 const char *oid,
379 uint32_t *attid)
381 return dsdb_schema_pfm_make_attid_impl(pfm, oid, true, attid);
385 * Make ATTID for given OID
386 * Reference: [MS-DRSR] section 5.12.2
388 WERROR dsdb_schema_pfm_attid_from_oid(struct dsdb_schema_prefixmap *pfm,
389 const char *oid,
390 uint32_t *attid)
392 return dsdb_schema_pfm_make_attid_impl(pfm, oid, false, attid);
396 * Make OID for given ATTID.
397 * Reference: [MS-DRSR] section 5.12.2
399 WERROR dsdb_schema_pfm_oid_from_attid(const struct dsdb_schema_prefixmap *pfm,
400 uint32_t attid,
401 TALLOC_CTX *mem_ctx, const char **_oid)
403 uint32_t i;
404 uint32_t hi_word, lo_word;
405 DATA_BLOB bin_oid = {NULL, 0};
406 char *oid;
407 struct dsdb_schema_prefixmap_oid *pfm_entry;
408 WERROR werr = WERR_OK;
410 /* sanity check for attid requested */
411 if (dsdb_pfm_get_attid_type(attid) != DSDB_ATTID_TYPE_PFM) {
412 return WERR_INVALID_PARAMETER;
415 /* crack attid value */
416 hi_word = attid >> 16;
417 lo_word = attid & 0xFFFF;
419 /* locate corRespoNding prefixMap entry */
420 pfm_entry = NULL;
421 for (i = 0; i < pfm->length; i++) {
422 if (hi_word == pfm->prefixes[i].id) {
423 pfm_entry = &pfm->prefixes[i];
424 break;
428 if (!pfm_entry) {
429 DEBUG(1,("Failed to find prefixMap entry for ATTID = 0x%08X (%d)\n",
430 attid, attid));
431 return WERR_DS_NO_ATTRIBUTE_OR_VALUE;
434 /* copy oid prefix making enough room */
435 bin_oid.length = pfm_entry->bin_oid.length + 2;
436 bin_oid.data = talloc_array(mem_ctx, uint8_t, bin_oid.length);
437 W_ERROR_HAVE_NO_MEMORY(bin_oid.data);
438 memcpy(bin_oid.data, pfm_entry->bin_oid.data, pfm_entry->bin_oid.length);
440 if (lo_word < 128) {
441 bin_oid.length = bin_oid.length - 1;
442 bin_oid.data[bin_oid.length-1] = lo_word;
444 else {
445 if (lo_word >= 32768) {
446 lo_word -= 32768;
448 bin_oid.data[bin_oid.length-2] = (0x80 | ((lo_word>>7) & 0x7f));
449 bin_oid.data[bin_oid.length-1] = lo_word & 0x7f;
452 if (!ber_read_OID_String(mem_ctx, bin_oid, &oid)) {
453 DEBUG(0,("ber_read_OID_String() failed for %s\n",
454 hex_encode_talloc(bin_oid.data, bin_oid.data, bin_oid.length)));
455 werr = WERR_INTERNAL_ERROR;
458 /* free locally allocated memory */
459 talloc_free(bin_oid.data);
461 *_oid = oid;
463 return werr;
468 * Verifies drsuapi mappings.
470 static WERROR _dsdb_drsuapi_pfm_verify(const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr,
471 bool have_schema_info)
473 uint32_t i;
474 uint32_t num_mappings;
475 struct drsuapi_DsReplicaOIDMapping *mapping;
477 /* check input params */
478 if (!ctr) {
479 return WERR_INVALID_PARAMETER;
481 if (!ctr->mappings) {
482 return WERR_INVALID_PARAMETER;
484 num_mappings = ctr->num_mappings;
486 if (have_schema_info) {
487 DATA_BLOB blob;
489 if (ctr->num_mappings < 2) {
490 return WERR_INVALID_PARAMETER;
493 /* check last entry for being special */
494 mapping = &ctr->mappings[ctr->num_mappings - 1];
495 if (mapping->id_prefix != 0) {
496 return WERR_INVALID_PARAMETER;
499 /* verify schemaInfo blob is valid one */
500 blob = data_blob_const(mapping->oid.binary_oid, mapping->oid.length);
501 if (!dsdb_schema_info_blob_is_valid(&blob)) {
502 return WERR_INVALID_PARAMETER;
505 /* get number of read mappings in the map */
506 num_mappings--;
509 /* now, verify rest of entries for being at least not null */
510 for (i = 0; i < num_mappings; i++) {
511 mapping = &ctr->mappings[i];
512 if (!mapping->oid.length) {
513 return WERR_INVALID_PARAMETER;
515 if (!mapping->oid.binary_oid) {
516 return WERR_INVALID_PARAMETER;
518 /* check it is not the special entry */
519 if (*mapping->oid.binary_oid == 0xFF) {
520 return WERR_INVALID_PARAMETER;
524 return WERR_OK;
528 * Convert drsuapi_ prefix map to prefixMap internal presentation.
530 * \param ctr Pointer to drsuapi_DsReplicaOIDMapping_Ctr which represents drsuapi_ prefixMap
531 * \param have_schema_info if drsuapi_prefixMap have schem_info in it or not
532 * \param mem_ctx TALLOC_CTX to make allocations in
533 * \param _pfm Out pointer to hold newly created prefixMap
534 * \param _schema_info Out param to store schema_info to. If NULL, schema_info is not decoded
536 WERROR dsdb_schema_pfm_from_drsuapi_pfm(const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr,
537 bool have_schema_info,
538 TALLOC_CTX *mem_ctx,
539 struct dsdb_schema_prefixmap **_pfm,
540 struct dsdb_schema_info **_schema_info)
542 WERROR werr;
543 uint32_t i;
544 DATA_BLOB blob;
545 uint32_t num_mappings;
546 struct dsdb_schema_prefixmap *pfm;
548 if (!_pfm) {
549 return WERR_INVALID_PARAMETER;
553 * error out if schema_info is requested
554 * but it is not in the drsuapi_prefixMap
556 if (_schema_info && !have_schema_info) {
557 return WERR_INVALID_PARAMETER;
560 /* verify drsuapi_pefixMap */
561 werr =_dsdb_drsuapi_pfm_verify(ctr, have_schema_info);
562 W_ERROR_NOT_OK_RETURN(werr);
564 /* allocate mem for prefix map */
565 num_mappings = ctr->num_mappings;
566 if (have_schema_info) {
567 num_mappings--;
569 pfm = _dsdb_schema_prefixmap_talloc(mem_ctx, num_mappings);
570 W_ERROR_HAVE_NO_MEMORY(pfm);
572 /* copy entries from drsuapi_prefixMap */
573 for (i = 0; i < pfm->length; i++) {
574 blob = data_blob_talloc(pfm,
575 ctr->mappings[i].oid.binary_oid,
576 ctr->mappings[i].oid.length);
577 if (!blob.data) {
578 talloc_free(pfm);
579 return WERR_NOT_ENOUGH_MEMORY;
581 pfm->prefixes[i].id = ctr->mappings[i].id_prefix;
582 pfm->prefixes[i].bin_oid = blob;
585 /* fetch schema_info if requested */
586 if (_schema_info) {
587 /* by this time, i should have this value,
588 * but set it here for clarity */
589 i = ctr->num_mappings - 1;
591 blob = data_blob_const(ctr->mappings[i].oid.binary_oid,
592 ctr->mappings[i].oid.length);
593 werr = dsdb_schema_info_from_blob(&blob, mem_ctx, _schema_info);
594 if (!W_ERROR_IS_OK(werr)) {
595 talloc_free(pfm);
596 return werr;
600 /* schema_prefixMap created successfully */
601 *_pfm = pfm;
603 return WERR_OK;
607 * Convert drsuapi_ prefix map to prefixMap internal presentation.
609 * \param pfm Schema prefixMap to be converted
610 * \param schema_info schema_info string - if NULL, we don't need it
611 * \param mem_ctx TALLOC_CTX to make allocations in
612 * \param _ctr Out pointer to drsuapi_DsReplicaOIDMapping_Ctr prefix map structure
614 WERROR dsdb_drsuapi_pfm_from_schema_pfm(const struct dsdb_schema_prefixmap *pfm,
615 const struct dsdb_schema_info *schema_info,
616 TALLOC_CTX *mem_ctx,
617 struct drsuapi_DsReplicaOIDMapping_Ctr **_ctr)
619 uint32_t i;
620 DATA_BLOB blob;
621 struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
623 if (!_ctr) {
624 return WERR_INVALID_PARAMETER;
626 if (!pfm) {
627 return WERR_INVALID_PARAMETER;
629 if (pfm->length == 0) {
630 return WERR_INVALID_PARAMETER;
633 /* allocate memory for the structure */
634 ctr = talloc_zero(mem_ctx, struct drsuapi_DsReplicaOIDMapping_Ctr);
635 W_ERROR_HAVE_NO_MEMORY(ctr);
637 ctr->num_mappings = (schema_info ? pfm->length + 1 : pfm->length);
638 ctr->mappings = talloc_array(ctr, struct drsuapi_DsReplicaOIDMapping, ctr->num_mappings);
639 if (!ctr->mappings) {
640 talloc_free(ctr);
641 return WERR_NOT_ENOUGH_MEMORY;
644 /* copy entries from schema_prefixMap */
645 for (i = 0; i < pfm->length; i++) {
646 blob = data_blob_dup_talloc(ctr, pfm->prefixes[i].bin_oid);
647 if (!blob.data) {
648 talloc_free(ctr);
649 return WERR_NOT_ENOUGH_MEMORY;
651 ctr->mappings[i].id_prefix = pfm->prefixes[i].id;
652 ctr->mappings[i].oid.length = blob.length;
653 ctr->mappings[i].oid.binary_oid = blob.data;
656 /* make schema_info entry if needed */
657 if (schema_info) {
658 WERROR werr;
660 /* by this time, i should have this value,
661 * but set it here for clarity */
662 i = ctr->num_mappings - 1;
664 werr = dsdb_blob_from_schema_info(schema_info, ctr, &blob);
665 if (!W_ERROR_IS_OK(werr)) {
666 talloc_free(ctr);
667 return werr;
670 ctr->mappings[i].id_prefix = 0;
671 ctr->mappings[i].oid.length = blob.length;
672 ctr->mappings[i].oid.binary_oid = blob.data;
675 /* drsuapi_prefixMap constructed successfully */
676 *_ctr = ctr;
678 return WERR_OK;
682 * Verifies schema prefixMap and drsuapi prefixMap are same.
683 * Note that we just need to verify pfm contains prefixes
684 * from ctr, not that those prefixes has same id_prefix.
686 WERROR dsdb_schema_pfm_contains_drsuapi_pfm(const struct dsdb_schema_prefixmap *pfm,
687 const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
689 WERROR werr;
690 uint32_t i;
691 uint32_t idx;
692 DATA_BLOB bin_oid;
694 /* verify drsuapi_pefixMap */
695 werr = _dsdb_drsuapi_pfm_verify(ctr, true);
696 W_ERROR_NOT_OK_RETURN(werr);
698 /* check pfm contains every entry from ctr, except the last one */
699 for (i = 0; i < ctr->num_mappings - 1; i++) {
700 bin_oid.length = ctr->mappings[i].oid.length;
701 bin_oid.data = ctr->mappings[i].oid.binary_oid;
703 werr = dsdb_schema_pfm_find_binary_oid(pfm, bin_oid, &idx);
704 if (!W_ERROR_IS_OK(werr)) {
705 return WERR_DS_DRA_SCHEMA_MISMATCH;
709 return WERR_OK;