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 * Allocates schema_prefixMap object in supplied memory context
32 static struct dsdb_schema_prefixmap *_dsdb_schema_prefixmap_talloc(TALLOC_CTX *mem_ctx,
35 struct dsdb_schema_prefixmap *pfm;
37 pfm = talloc_zero(mem_ctx, struct dsdb_schema_prefixmap);
43 pfm->prefixes = talloc_zero_array(pfm, struct dsdb_schema_prefixmap_oid,
54 * Initial prefixMap creation according to:
55 * [MS-DRSR] section 5.12.2
57 WERROR dsdb_schema_pfm_new(TALLOC_CTX *mem_ctx, struct dsdb_schema_prefixmap **_pfm)
60 struct dsdb_schema_prefixmap *pfm;
63 const char *oid_prefix;
65 {.id=0x00000000, .oid_prefix="2.5.4"},
66 {.id=0x00000001, .oid_prefix="2.5.6"},
67 {.id=0x00000002, .oid_prefix="1.2.840.113556.1.2"},
68 {.id=0x00000003, .oid_prefix="1.2.840.113556.1.3"},
69 {.id=0x00000004, .oid_prefix="2.16.840.1.101.2.2.1"},
70 {.id=0x00000005, .oid_prefix="2.16.840.1.101.2.2.3"},
71 {.id=0x00000006, .oid_prefix="2.16.840.1.101.2.1.5"},
72 {.id=0x00000007, .oid_prefix="2.16.840.1.101.2.1.4"},
73 {.id=0x00000008, .oid_prefix="2.5.5"},
74 {.id=0x00000009, .oid_prefix="1.2.840.113556.1.4"},
75 {.id=0x0000000A, .oid_prefix="1.2.840.113556.1.5"},
76 {.id=0x00000013, .oid_prefix="0.9.2342.19200300.100"},
77 {.id=0x00000014, .oid_prefix="2.16.840.1.113730.3"},
78 {.id=0x00000015, .oid_prefix="0.9.2342.19200300.100.1"},
79 {.id=0x00000016, .oid_prefix="2.16.840.1.113730.3.1"},
80 {.id=0x00000017, .oid_prefix="1.2.840.113556.1.5.7000"},
81 {.id=0x00000018, .oid_prefix="2.5.21"},
82 {.id=0x00000019, .oid_prefix="2.5.18"},
83 {.id=0x0000001A, .oid_prefix="2.5.20"},
86 /* allocate mem for prefix map */
87 pfm = _dsdb_schema_prefixmap_talloc(mem_ctx, ARRAY_SIZE(pfm_init_data));
88 W_ERROR_HAVE_NO_MEMORY(pfm);
91 for (i = 0; i < pfm->length; i++) {
92 if (!ber_write_partial_OID_String(pfm, &pfm->prefixes[i].bin_oid, pfm_init_data[i].oid_prefix)) {
94 return WERR_INTERNAL_ERROR;
96 pfm->prefixes[i].id = pfm_init_data[i].id;
106 * Adds oid to prefix map.
107 * On success returns ID for newly added index
108 * or ID of existing entry that matches oid
109 * Reference: [MS-DRSR] section 5.12.2
111 * \param pfm prefixMap
112 * \param bin_oid OID prefix to be added to prefixMap
113 * \param pfm_id Location where to store prefixMap entry ID
115 static WERROR _dsdb_schema_pfm_add_entry(struct dsdb_schema_prefixmap *pfm, DATA_BLOB bin_oid, uint32_t *_idx)
118 struct dsdb_schema_prefixmap_oid * pfm_entry;
119 struct dsdb_schema_prefixmap_oid * prefixes_new;
121 /* dup memory for bin-oid prefix to be added */
122 bin_oid = data_blob_dup_talloc(pfm, &bin_oid);
127 /* make room for new entry */
128 prefixes_new = talloc_realloc(pfm, pfm->prefixes, struct dsdb_schema_prefixmap_oid, pfm->length + 1);
130 talloc_free(bin_oid.data);
133 pfm->prefixes = prefixes_new;
135 /* make new unique ID in prefixMap */
136 pfm_entry = &pfm->prefixes[pfm->length];
138 for (i = 0; i < pfm->length; i++) {
139 if (pfm_entry->id < pfm->prefixes[i].id)
140 pfm_entry->id = pfm->prefixes[i].id;
143 /* add new bin-oid prefix */
145 pfm_entry->bin_oid = bin_oid;
155 * Make partial binary OID for supplied OID.
156 * Reference: [MS-DRSR] section 5.12.2
158 static WERROR _dsdb_pfm_make_binary_oid(const char *full_oid, TALLOC_CTX *mem_ctx,
159 DATA_BLOB *_bin_oid, uint32_t *_last_subid)
162 const char *oid_subid;
164 /* make last sub-identifier value */
165 oid_subid = strrchr(full_oid, '.');
167 return WERR_INVALID_PARAMETER;
170 last_subid = strtoul(oid_subid, NULL, 10);
172 /* encode oid in BER format */
173 if (!ber_write_OID_String(mem_ctx, _bin_oid, full_oid)) {
174 return WERR_INTERNAL_ERROR;
177 /* get the prefix of the OID */
178 if (last_subid < 128) {
179 _bin_oid->length -= 1;
181 _bin_oid->length -= 2;
184 /* return last_value if requested */
186 *_last_subid = last_subid;
193 * Lookup partial-binary-oid in prefixMap
195 WERROR dsdb_schema_pfm_find_binary_oid(const struct dsdb_schema_prefixmap *pfm,
201 for (i = 0; i < pfm->length; i++) {
202 if (pfm->prefixes[i].bin_oid.length != bin_oid.length) {
206 if (memcmp(pfm->prefixes[i].bin_oid.data, bin_oid.data, bin_oid.length) == 0) {
214 return WERR_DS_NO_MSDS_INTID;
218 * Lookup full-oid in prefixMap
219 * Note: this may be slow.
221 WERROR dsdb_schema_pfm_find_oid(const struct dsdb_schema_prefixmap *pfm,
222 const char *full_oid,
228 ZERO_STRUCT(bin_oid);
230 /* make partial-binary-oid to look for */
231 werr = _dsdb_pfm_make_binary_oid(full_oid, NULL, &bin_oid, NULL);
232 W_ERROR_NOT_OK_RETURN(werr);
234 /* lookup the partial-oid */
235 werr = dsdb_schema_pfm_find_binary_oid(pfm, bin_oid, _idx);
237 data_blob_free(&bin_oid);
243 * Make ATTID for given OID
244 * Reference: [MS-DRSR] section 5.12.2
246 WERROR dsdb_schema_pfm_make_attid(struct dsdb_schema_prefixmap *pfm, const char *oid, uint32_t *attid)
250 uint32_t lo_word, hi_word;
255 return WERR_INVALID_PARAMETER;
258 return WERR_INVALID_PARAMETER;
261 werr = _dsdb_pfm_make_binary_oid(oid, pfm, &bin_oid, &last_subid);
262 W_ERROR_NOT_OK_RETURN(werr);
264 /* search the prefix in the prefix table, if none found, add
265 * one entry for new prefix.
267 werr = dsdb_schema_pfm_find_binary_oid(pfm, bin_oid, &idx);
268 if (W_ERROR_IS_OK(werr)) {
269 /* free memory allocated for bin_oid */
270 data_blob_free(&bin_oid);
272 /* entry does not exists, add it */
273 werr = _dsdb_schema_pfm_add_entry(pfm, bin_oid, &idx);
274 W_ERROR_NOT_OK_RETURN(werr);
277 /* compose the attid */
278 lo_word = last_subid % 16384; /* actually get lower 14 bits: lo_word & 0x3FFF */
279 if (last_subid >= 16384) {
280 /* mark it so that it is known to not be the whole lastValue
281 * This will raise 16-th bit*/
284 hi_word = pfm->prefixes[idx].id;
287 * HIWORD is prefixMap id
288 * LOWORD is truncated binary-oid */
289 *attid = (hi_word * 65536) + lo_word;
296 * Make OID for given ATTID.
297 * Reference: [MS-DRSR] section 5.12.2
299 WERROR dsdb_schema_pfm_oid_from_attid(struct dsdb_schema_prefixmap *pfm, uint32_t attid,
300 TALLOC_CTX *mem_ctx, const char **_oid)
303 uint32_t hi_word, lo_word;
304 DATA_BLOB bin_oid = {NULL, 0};
305 struct dsdb_schema_prefixmap_oid *pfm_entry;
306 WERROR werr = WERR_OK;
308 /* crack attid value */
309 hi_word = attid >> 16;
310 lo_word = attid & 0xFFFF;
312 /* locate corRespoNding prefixMap entry */
314 for (i = 0; i < pfm->length; i++) {
315 if (hi_word == pfm->prefixes[i].id) {
316 pfm_entry = &pfm->prefixes[i];
322 return WERR_INTERNAL_ERROR;
325 /* copy oid prefix making enough room */
326 bin_oid.length = pfm_entry->bin_oid.length + 2;
327 bin_oid.data = talloc_array(mem_ctx, uint8_t, bin_oid.length);
328 W_ERROR_HAVE_NO_MEMORY(bin_oid.data);
329 memcpy(bin_oid.data, pfm_entry->bin_oid.data, pfm_entry->bin_oid.length);
332 bin_oid.length = bin_oid.length - 1;
333 bin_oid.data[bin_oid.length-1] = lo_word;
336 if (lo_word >= 32768) {
339 bin_oid.data[bin_oid.length-2] = (0x80 | ((lo_word>>7) & 0x7f));
340 bin_oid.data[bin_oid.length-1] = lo_word & 0x7f;
343 if (!ber_read_OID_String(mem_ctx, bin_oid, _oid)) {
344 werr = WERR_INTERNAL_ERROR;
347 /* free locally allocated memory */
348 talloc_free(bin_oid.data);
355 * Verifies drsuapi mappings.
357 static WERROR _dsdb_drsuapi_pfm_verify(const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr,
358 bool have_schema_info)
361 uint32_t num_mappings;
362 struct drsuapi_DsReplicaOIDMapping *mapping;
364 /* check input params */
366 return WERR_INVALID_PARAMETER;
368 if (!ctr->mappings) {
369 return WERR_INVALID_PARAMETER;
371 num_mappings = ctr->num_mappings;
373 if (have_schema_info) {
374 if (ctr->num_mappings < 2) {
375 return WERR_INVALID_PARAMETER;
378 /* check last entry for being special */
379 mapping = &ctr->mappings[ctr->num_mappings - 1];
380 if (!mapping->oid.binary_oid) {
381 return WERR_INVALID_PARAMETER;
383 if (mapping->id_prefix != 0) {
384 return WERR_INVALID_PARAMETER;
386 if (mapping->oid.length != 21) {
387 return WERR_INVALID_PARAMETER;
389 if (*mapping->oid.binary_oid != 0xFF) {
390 return WERR_INVALID_PARAMETER;
393 /* get number of read mappings in the map */
397 /* now, verify rest of entries for being at least not null */
398 for (i = 0; i < num_mappings; i++) {
399 mapping = &ctr->mappings[i];
400 if (!mapping->oid.length) {
401 return WERR_INVALID_PARAMETER;
403 if (!mapping->oid.binary_oid) {
404 return WERR_INVALID_PARAMETER;
406 /* check it is not the special entry */
407 if (*mapping->oid.binary_oid == 0xFF) {
408 return WERR_INVALID_PARAMETER;
416 * Convert drsuapi_ prefix map to prefixMap internal presentation.
418 * \param ctr Pointer to drsuapi_DsReplicaOIDMapping_Ctr which represents drsuapi_ prefixMap
419 * \param have_schema_info if drsuapi_prefixMap have schem_info in it or not
420 * \param mem_ctx TALLOC_CTX to make allocations in
421 * \param _pfm Out pointer to hold newly created prefixMap
422 * \param _schema_info Out param to store schema_info to. If NULL, schema_info is not decoded
424 WERROR dsdb_schema_pfm_from_drsuapi_pfm(const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr,
425 bool have_schema_info,
427 struct dsdb_schema_prefixmap **_pfm,
428 const char **_schema_info)
433 uint32_t num_mappings;
434 struct dsdb_schema_prefixmap *pfm;
437 return WERR_INVALID_PARAMETER;
441 * error out if schema_info is requested
442 * but it is not in the drsuapi_prefixMap
444 if (_schema_info && !have_schema_info) {
445 return WERR_INVALID_PARAMETER;
448 /* verify drsuapi_pefixMap */
449 werr =_dsdb_drsuapi_pfm_verify(ctr, have_schema_info);
450 W_ERROR_NOT_OK_RETURN(werr);
452 /* allocate mem for prefix map */
453 num_mappings = ctr->num_mappings;
454 if (have_schema_info) {
457 pfm = _dsdb_schema_prefixmap_talloc(mem_ctx, num_mappings);
458 W_ERROR_HAVE_NO_MEMORY(pfm);
460 /* copy entries from drsuapi_prefixMap */
461 for (i = 0; i < pfm->length; i++) {
462 blob = data_blob_talloc(pfm,
463 ctr->mappings[i].oid.binary_oid,
464 ctr->mappings[i].oid.length);
469 pfm->prefixes[i].id = ctr->mappings[i].id_prefix;
470 pfm->prefixes[i].bin_oid = blob;
473 /* fetch schema_info if requested */
475 /* by this time, i should have this value,
476 * but set it here for clarity */
477 i = ctr->num_mappings - 1;
479 *_schema_info = hex_encode_talloc(mem_ctx,
480 ctr->mappings[i].oid.binary_oid,
481 ctr->mappings[i].oid.length);
482 if (!*_schema_info) {
488 /* schema_prefixMap created successfully */
495 * Convert drsuapi_ prefix map to prefixMap internal presentation.
497 * \param pfm Schema prefixMap to be converted
498 * \param schema_info schema_info string - if NULL, we don't need it
499 * \param mem_ctx TALLOC_CTX to make allocations in
500 * \param _ctr Out pointer to drsuapi_DsReplicaOIDMapping_Ctr prefix map structure
502 WERROR dsdb_drsuapi_pfm_from_schema_pfm(const struct dsdb_schema_prefixmap *pfm,
503 const char *schema_info,
505 struct drsuapi_DsReplicaOIDMapping_Ctr **_ctr)
509 struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
512 return WERR_INVALID_PARAMETER;
515 return WERR_INVALID_PARAMETER;
517 if (pfm->length == 0) {
518 return WERR_INVALID_PARAMETER;
521 /* allocate memory for the structure */
522 ctr = talloc_zero(mem_ctx, struct drsuapi_DsReplicaOIDMapping_Ctr);
523 W_ERROR_HAVE_NO_MEMORY(ctr);
525 ctr->num_mappings = (schema_info ? pfm->length + 1 : pfm->length);
526 ctr->mappings = talloc_array(ctr, struct drsuapi_DsReplicaOIDMapping, ctr->num_mappings);
527 if (!ctr->mappings) {
532 /* copy entries from schema_prefixMap */
533 for (i = 0; i < pfm->length; i++) {
534 blob = data_blob_dup_talloc(ctr, &pfm->prefixes[i].bin_oid);
539 ctr->mappings[i].id_prefix = pfm->prefixes[i].id;
540 ctr->mappings[i].oid.length = blob.length;
541 ctr->mappings[i].oid.binary_oid = blob.data;
544 /* make schema_info entry if needed */
546 /* by this time, i should have this value,
547 * but set it here for clarity */
548 i = ctr->num_mappings - 1;
550 blob = strhex_to_data_blob(ctr, schema_info);
556 ctr->mappings[i].id_prefix = 0;
557 ctr->mappings[i].oid.length = blob.length;
558 ctr->mappings[i].oid.binary_oid = blob.data;
561 /* drsuapi_prefixMap constructed successfully */
568 * Verifies schema prefixMap and drsuapi prefixMap are same.
569 * Note that we just need to verify pfm contains prefixes
570 * from ctr, not that those prefixes has same id_prefix.
572 WERROR dsdb_schema_pfm_contains_drsuapi_pfm(const struct dsdb_schema_prefixmap *pfm,
573 const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
580 /* verify drsuapi_pefixMap */
581 werr = _dsdb_drsuapi_pfm_verify(ctr, true);
582 W_ERROR_NOT_OK_RETURN(werr);
584 /* check pfm contains every entry from ctr, except the last one */
585 for (i = 0; i < ctr->num_mappings - 1; i++) {
586 bin_oid.length = ctr->mappings[i].oid.length;
587 bin_oid.data = ctr->mappings[i].oid.binary_oid;
589 werr = dsdb_schema_pfm_find_binary_oid(pfm, bin_oid, &idx);
590 if (!W_ERROR_IS_OK(werr)) {
591 return WERR_DS_DRA_SCHEMA_MISMATCH;