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/>.
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"
30 * Determine range type for supplied ATTID
32 enum dsdb_attid_type dsdb_pfm_get_attid_type(uint32_t attid)
34 if (attid <= 0x7FFFFFFF) {
35 return dsdb_attid_type_pfm;
37 else if (attid <= 0xBFFFFFFF) {
38 return dsdb_attid_type_intid;
40 else if (attid <= 0xFFFEFFFF) {
41 return dsdb_attid_type_reserved;
44 return dsdb_attid_type_internal;
49 * Allocates schema_prefixMap object in supplied memory context
51 static struct dsdb_schema_prefixmap *_dsdb_schema_prefixmap_talloc(TALLOC_CTX *mem_ctx,
54 struct dsdb_schema_prefixmap *pfm;
56 pfm = talloc_zero(mem_ctx, struct dsdb_schema_prefixmap);
62 pfm->prefixes = talloc_zero_array(pfm, struct dsdb_schema_prefixmap_oid,
73 * Initial prefixMap creation according to:
74 * [MS-DRSR] section 5.12.2
76 WERROR dsdb_schema_pfm_new(TALLOC_CTX *mem_ctx, struct dsdb_schema_prefixmap **_pfm)
79 struct dsdb_schema_prefixmap *pfm;
82 const char *oid_prefix;
84 {.id=0x00000000, .oid_prefix="2.5.4"},
85 {.id=0x00000001, .oid_prefix="2.5.6"},
86 {.id=0x00000002, .oid_prefix="1.2.840.113556.1.2"},
87 {.id=0x00000003, .oid_prefix="1.2.840.113556.1.3"},
88 {.id=0x00000004, .oid_prefix="2.16.840.1.101.2.2.1"},
89 {.id=0x00000005, .oid_prefix="2.16.840.1.101.2.2.3"},
90 {.id=0x00000006, .oid_prefix="2.16.840.1.101.2.1.5"},
91 {.id=0x00000007, .oid_prefix="2.16.840.1.101.2.1.4"},
92 {.id=0x00000008, .oid_prefix="2.5.5"},
93 {.id=0x00000009, .oid_prefix="1.2.840.113556.1.4"},
94 {.id=0x0000000A, .oid_prefix="1.2.840.113556.1.5"},
95 {.id=0x00000013, .oid_prefix="0.9.2342.19200300.100"},
96 {.id=0x00000014, .oid_prefix="2.16.840.1.113730.3"},
97 {.id=0x00000015, .oid_prefix="0.9.2342.19200300.100.1"},
98 {.id=0x00000016, .oid_prefix="2.16.840.1.113730.3.1"},
99 {.id=0x00000017, .oid_prefix="1.2.840.113556.1.5.7000"},
100 {.id=0x00000018, .oid_prefix="2.5.21"},
101 {.id=0x00000019, .oid_prefix="2.5.18"},
102 {.id=0x0000001A, .oid_prefix="2.5.20"},
105 /* allocate mem for prefix map */
106 pfm = _dsdb_schema_prefixmap_talloc(mem_ctx, ARRAY_SIZE(pfm_init_data));
107 W_ERROR_HAVE_NO_MEMORY(pfm);
110 for (i = 0; i < pfm->length; i++) {
111 if (!ber_write_partial_OID_String(pfm, &pfm->prefixes[i].bin_oid, pfm_init_data[i].oid_prefix)) {
113 return WERR_INTERNAL_ERROR;
115 pfm->prefixes[i].id = pfm_init_data[i].id;
125 * Adds oid to prefix map.
126 * On success returns ID for newly added index
127 * or ID of existing entry that matches oid
128 * Reference: [MS-DRSR] section 5.12.2
130 * \param pfm prefixMap
131 * \param bin_oid OID prefix to be added to prefixMap
132 * \param pfm_id Location where to store prefixMap entry ID
134 static WERROR _dsdb_schema_pfm_add_entry(struct dsdb_schema_prefixmap *pfm, DATA_BLOB bin_oid, uint32_t *_idx)
137 struct dsdb_schema_prefixmap_oid * pfm_entry;
138 struct dsdb_schema_prefixmap_oid * prefixes_new;
140 /* dup memory for bin-oid prefix to be added */
141 bin_oid = data_blob_dup_talloc(pfm, &bin_oid);
142 W_ERROR_HAVE_NO_MEMORY(bin_oid.data);
144 /* make room for new entry */
145 prefixes_new = talloc_realloc(pfm, pfm->prefixes, struct dsdb_schema_prefixmap_oid, pfm->length + 1);
147 talloc_free(bin_oid.data);
150 pfm->prefixes = prefixes_new;
152 /* make new unique ID in prefixMap */
153 pfm_entry = &pfm->prefixes[pfm->length];
155 for (i = 0; i < pfm->length; i++) {
156 if (pfm_entry->id < pfm->prefixes[i].id)
157 pfm_entry->id = pfm->prefixes[i].id;
160 /* add new bin-oid prefix */
162 pfm_entry->bin_oid = bin_oid;
172 * Make partial binary OID for supplied OID.
173 * Reference: [MS-DRSR] section 5.12.2
175 static WERROR _dsdb_pfm_make_binary_oid(const char *full_oid, TALLOC_CTX *mem_ctx,
176 DATA_BLOB *_bin_oid, uint32_t *_last_subid)
179 const char *oid_subid;
181 /* make last sub-identifier value */
182 oid_subid = strrchr(full_oid, '.');
184 return WERR_INVALID_PARAMETER;
187 last_subid = strtoul(oid_subid, NULL, 10);
189 /* encode oid in BER format */
190 if (!ber_write_OID_String(mem_ctx, _bin_oid, full_oid)) {
191 DEBUG(0,("ber_write_OID_String() failed for %s\n", full_oid));
192 return WERR_INTERNAL_ERROR;
195 /* get the prefix of the OID */
196 if (last_subid < 128) {
197 _bin_oid->length -= 1;
199 _bin_oid->length -= 2;
202 /* return last_value if requested */
204 *_last_subid = last_subid;
211 * Lookup partial-binary-oid in prefixMap
213 WERROR dsdb_schema_pfm_find_binary_oid(const struct dsdb_schema_prefixmap *pfm,
219 for (i = 0; i < pfm->length; i++) {
220 if (pfm->prefixes[i].bin_oid.length != bin_oid.length) {
224 if (memcmp(pfm->prefixes[i].bin_oid.data, bin_oid.data, bin_oid.length) == 0) {
232 return WERR_NOT_FOUND;
236 * Lookup full-oid in prefixMap
237 * Note: this may be slow.
239 WERROR dsdb_schema_pfm_find_oid(const struct dsdb_schema_prefixmap *pfm,
240 const char *full_oid,
246 ZERO_STRUCT(bin_oid);
248 /* make partial-binary-oid to look for */
249 werr = _dsdb_pfm_make_binary_oid(full_oid, NULL, &bin_oid, NULL);
250 W_ERROR_NOT_OK_RETURN(werr);
252 /* lookup the partial-oid */
253 werr = dsdb_schema_pfm_find_binary_oid(pfm, bin_oid, _idx);
255 data_blob_free(&bin_oid);
261 * Make ATTID for given OID
262 * Reference: [MS-DRSR] section 5.12.2
264 WERROR dsdb_schema_pfm_make_attid(struct dsdb_schema_prefixmap *pfm, const char *oid, uint32_t *attid)
268 uint32_t lo_word, hi_word;
273 return WERR_INVALID_PARAMETER;
276 return WERR_INVALID_PARAMETER;
279 werr = _dsdb_pfm_make_binary_oid(oid, pfm, &bin_oid, &last_subid);
280 W_ERROR_NOT_OK_RETURN(werr);
282 /* search the prefix in the prefix table, if none found, add
283 * one entry for new prefix.
285 werr = dsdb_schema_pfm_find_binary_oid(pfm, bin_oid, &idx);
286 if (W_ERROR_IS_OK(werr)) {
287 /* free memory allocated for bin_oid */
288 data_blob_free(&bin_oid);
290 /* entry does not exists, add it */
291 werr = _dsdb_schema_pfm_add_entry(pfm, bin_oid, &idx);
292 W_ERROR_NOT_OK_RETURN(werr);
295 /* compose the attid */
296 lo_word = last_subid % 16384; /* actually get lower 14 bits: lo_word & 0x3FFF */
297 if (last_subid >= 16384) {
298 /* mark it so that it is known to not be the whole lastValue
299 * This will raise 16-th bit*/
302 hi_word = pfm->prefixes[idx].id;
305 * HIWORD is prefixMap id
306 * LOWORD is truncated binary-oid */
307 *attid = (hi_word * 65536) + lo_word;
314 * Make OID for given ATTID.
315 * Reference: [MS-DRSR] section 5.12.2
317 WERROR dsdb_schema_pfm_oid_from_attid(struct dsdb_schema_prefixmap *pfm, uint32_t attid,
318 TALLOC_CTX *mem_ctx, const char **_oid)
321 uint32_t hi_word, lo_word;
322 DATA_BLOB bin_oid = {NULL, 0};
323 struct dsdb_schema_prefixmap_oid *pfm_entry;
324 WERROR werr = WERR_OK;
326 /* sanity check for attid requested */
327 if (dsdb_pfm_get_attid_type(attid) != dsdb_attid_type_pfm) {
328 return WERR_INVALID_PARAMETER;
331 /* crack attid value */
332 hi_word = attid >> 16;
333 lo_word = attid & 0xFFFF;
335 /* locate corRespoNding prefixMap entry */
337 for (i = 0; i < pfm->length; i++) {
338 if (hi_word == pfm->prefixes[i].id) {
339 pfm_entry = &pfm->prefixes[i];
345 DEBUG(1,("Failed to find prefixMap entry for ATTID = 0x%08X (%d)\n",
347 return WERR_DS_NO_ATTRIBUTE_OR_VALUE;
350 /* copy oid prefix making enough room */
351 bin_oid.length = pfm_entry->bin_oid.length + 2;
352 bin_oid.data = talloc_array(mem_ctx, uint8_t, bin_oid.length);
353 W_ERROR_HAVE_NO_MEMORY(bin_oid.data);
354 memcpy(bin_oid.data, pfm_entry->bin_oid.data, pfm_entry->bin_oid.length);
357 bin_oid.length = bin_oid.length - 1;
358 bin_oid.data[bin_oid.length-1] = lo_word;
361 if (lo_word >= 32768) {
364 bin_oid.data[bin_oid.length-2] = (0x80 | ((lo_word>>7) & 0x7f));
365 bin_oid.data[bin_oid.length-1] = lo_word & 0x7f;
368 if (!ber_read_OID_String(mem_ctx, bin_oid, _oid)) {
369 DEBUG(0,("ber_read_OID_String() failed for %s\n",
370 hex_encode_talloc(bin_oid.data, bin_oid.data, bin_oid.length)));
371 werr = WERR_INTERNAL_ERROR;
374 /* free locally allocated memory */
375 talloc_free(bin_oid.data);
382 * Verifies drsuapi mappings.
384 static WERROR _dsdb_drsuapi_pfm_verify(const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr,
385 bool have_schema_info)
388 uint32_t num_mappings;
389 struct drsuapi_DsReplicaOIDMapping *mapping;
391 /* check input params */
393 return WERR_INVALID_PARAMETER;
395 if (!ctr->mappings) {
396 return WERR_INVALID_PARAMETER;
398 num_mappings = ctr->num_mappings;
400 if (have_schema_info) {
403 if (ctr->num_mappings < 2) {
404 return WERR_INVALID_PARAMETER;
407 /* check last entry for being special */
408 mapping = &ctr->mappings[ctr->num_mappings - 1];
409 if (mapping->id_prefix != 0) {
410 return WERR_INVALID_PARAMETER;
413 /* verify schemaInfo blob is valid one */
414 blob = data_blob_const(mapping->oid.binary_oid, mapping->oid.length);
415 if (!dsdb_schema_info_blob_is_valid(&blob)) {
416 return WERR_INVALID_PARAMETER;
419 /* get number of read mappings in the map */
423 /* now, verify rest of entries for being at least not null */
424 for (i = 0; i < num_mappings; i++) {
425 mapping = &ctr->mappings[i];
426 if (!mapping->oid.length) {
427 return WERR_INVALID_PARAMETER;
429 if (!mapping->oid.binary_oid) {
430 return WERR_INVALID_PARAMETER;
432 /* check it is not the special entry */
433 if (*mapping->oid.binary_oid == 0xFF) {
434 return WERR_INVALID_PARAMETER;
442 * Convert drsuapi_ prefix map to prefixMap internal presentation.
444 * \param ctr Pointer to drsuapi_DsReplicaOIDMapping_Ctr which represents drsuapi_ prefixMap
445 * \param have_schema_info if drsuapi_prefixMap have schem_info in it or not
446 * \param mem_ctx TALLOC_CTX to make allocations in
447 * \param _pfm Out pointer to hold newly created prefixMap
448 * \param _schema_info Out param to store schema_info to. If NULL, schema_info is not decoded
450 WERROR dsdb_schema_pfm_from_drsuapi_pfm(const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr,
451 bool have_schema_info,
453 struct dsdb_schema_prefixmap **_pfm,
454 const char **_schema_info)
459 uint32_t num_mappings;
460 struct dsdb_schema_prefixmap *pfm;
463 return WERR_INVALID_PARAMETER;
467 * error out if schema_info is requested
468 * but it is not in the drsuapi_prefixMap
470 if (_schema_info && !have_schema_info) {
471 return WERR_INVALID_PARAMETER;
474 /* verify drsuapi_pefixMap */
475 werr =_dsdb_drsuapi_pfm_verify(ctr, have_schema_info);
476 W_ERROR_NOT_OK_RETURN(werr);
478 /* allocate mem for prefix map */
479 num_mappings = ctr->num_mappings;
480 if (have_schema_info) {
483 pfm = _dsdb_schema_prefixmap_talloc(mem_ctx, num_mappings);
484 W_ERROR_HAVE_NO_MEMORY(pfm);
486 /* copy entries from drsuapi_prefixMap */
487 for (i = 0; i < pfm->length; i++) {
488 blob = data_blob_talloc(pfm,
489 ctr->mappings[i].oid.binary_oid,
490 ctr->mappings[i].oid.length);
495 pfm->prefixes[i].id = ctr->mappings[i].id_prefix;
496 pfm->prefixes[i].bin_oid = blob;
499 /* fetch schema_info if requested */
501 /* by this time, i should have this value,
502 * but set it here for clarity */
503 i = ctr->num_mappings - 1;
505 *_schema_info = hex_encode_talloc(mem_ctx,
506 ctr->mappings[i].oid.binary_oid,
507 ctr->mappings[i].oid.length);
508 if (!*_schema_info) {
514 /* schema_prefixMap created successfully */
521 * Convert drsuapi_ prefix map to prefixMap internal presentation.
523 * \param pfm Schema prefixMap to be converted
524 * \param schema_info schema_info string - if NULL, we don't need it
525 * \param mem_ctx TALLOC_CTX to make allocations in
526 * \param _ctr Out pointer to drsuapi_DsReplicaOIDMapping_Ctr prefix map structure
528 WERROR dsdb_drsuapi_pfm_from_schema_pfm(const struct dsdb_schema_prefixmap *pfm,
529 const char *schema_info,
531 struct drsuapi_DsReplicaOIDMapping_Ctr **_ctr)
535 struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
538 return WERR_INVALID_PARAMETER;
541 return WERR_INVALID_PARAMETER;
543 if (pfm->length == 0) {
544 return WERR_INVALID_PARAMETER;
547 /* allocate memory for the structure */
548 ctr = talloc_zero(mem_ctx, struct drsuapi_DsReplicaOIDMapping_Ctr);
549 W_ERROR_HAVE_NO_MEMORY(ctr);
551 ctr->num_mappings = (schema_info ? pfm->length + 1 : pfm->length);
552 ctr->mappings = talloc_array(ctr, struct drsuapi_DsReplicaOIDMapping, ctr->num_mappings);
553 if (!ctr->mappings) {
558 /* copy entries from schema_prefixMap */
559 for (i = 0; i < pfm->length; i++) {
560 blob = data_blob_dup_talloc(ctr, &pfm->prefixes[i].bin_oid);
565 ctr->mappings[i].id_prefix = pfm->prefixes[i].id;
566 ctr->mappings[i].oid.length = blob.length;
567 ctr->mappings[i].oid.binary_oid = blob.data;
570 /* make schema_info entry if needed */
572 /* by this time, i should have this value,
573 * but set it here for clarity */
574 i = ctr->num_mappings - 1;
576 blob = strhex_to_data_blob(ctr, schema_info);
582 ctr->mappings[i].id_prefix = 0;
583 ctr->mappings[i].oid.length = blob.length;
584 ctr->mappings[i].oid.binary_oid = blob.data;
587 /* drsuapi_prefixMap constructed successfully */
594 * Verifies schema prefixMap and drsuapi prefixMap are same.
595 * Note that we just need to verify pfm contains prefixes
596 * from ctr, not that those prefixes has same id_prefix.
598 WERROR dsdb_schema_pfm_contains_drsuapi_pfm(const struct dsdb_schema_prefixmap *pfm,
599 const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
606 /* verify drsuapi_pefixMap */
607 werr = _dsdb_drsuapi_pfm_verify(ctr, true);
608 W_ERROR_NOT_OK_RETURN(werr);
610 /* check pfm contains every entry from ctr, except the last one */
611 for (i = 0; i < ctr->num_mappings - 1; i++) {
612 bin_oid.length = ctr->mappings[i].oid.length;
613 bin_oid.data = ctr->mappings[i].oid.binary_oid;
615 werr = dsdb_schema_pfm_find_binary_oid(pfm, bin_oid, &idx);
616 if (!W_ERROR_IS_OK(werr)) {
617 return WERR_DS_DRA_SCHEMA_MISMATCH;