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);
123 W_ERROR_HAVE_NO_MEMORY(bin_oid.data);
125 /* make room for new entry */
126 prefixes_new = talloc_realloc(pfm, pfm->prefixes, struct dsdb_schema_prefixmap_oid, pfm->length + 1);
128 talloc_free(bin_oid.data);
131 pfm->prefixes = prefixes_new;
133 /* make new unique ID in prefixMap */
134 pfm_entry = &pfm->prefixes[pfm->length];
136 for (i = 0; i < pfm->length; i++) {
137 if (pfm_entry->id < pfm->prefixes[i].id)
138 pfm_entry->id = pfm->prefixes[i].id;
141 /* add new bin-oid prefix */
143 pfm_entry->bin_oid = bin_oid;
153 * Make partial binary OID for supplied OID.
154 * Reference: [MS-DRSR] section 5.12.2
156 static WERROR _dsdb_pfm_make_binary_oid(const char *full_oid, TALLOC_CTX *mem_ctx,
157 DATA_BLOB *_bin_oid, uint32_t *_last_subid)
160 const char *oid_subid;
162 /* make last sub-identifier value */
163 oid_subid = strrchr(full_oid, '.');
165 return WERR_INVALID_PARAMETER;
168 last_subid = strtoul(oid_subid, NULL, 10);
170 /* encode oid in BER format */
171 if (!ber_write_OID_String(mem_ctx, _bin_oid, full_oid)) {
172 return WERR_INTERNAL_ERROR;
175 /* get the prefix of the OID */
176 if (last_subid < 128) {
177 _bin_oid->length -= 1;
179 _bin_oid->length -= 2;
182 /* return last_value if requested */
184 *_last_subid = last_subid;
191 * Lookup partial-binary-oid in prefixMap
193 WERROR dsdb_schema_pfm_find_binary_oid(const struct dsdb_schema_prefixmap *pfm,
199 for (i = 0; i < pfm->length; i++) {
200 if (pfm->prefixes[i].bin_oid.length != bin_oid.length) {
204 if (memcmp(pfm->prefixes[i].bin_oid.data, bin_oid.data, bin_oid.length) == 0) {
212 return WERR_DS_NO_MSDS_INTID;
216 * Lookup full-oid in prefixMap
217 * Note: this may be slow.
219 WERROR dsdb_schema_pfm_find_oid(const struct dsdb_schema_prefixmap *pfm,
220 const char *full_oid,
226 ZERO_STRUCT(bin_oid);
228 /* make partial-binary-oid to look for */
229 werr = _dsdb_pfm_make_binary_oid(full_oid, NULL, &bin_oid, NULL);
230 W_ERROR_NOT_OK_RETURN(werr);
232 /* lookup the partial-oid */
233 werr = dsdb_schema_pfm_find_binary_oid(pfm, bin_oid, _idx);
235 data_blob_free(&bin_oid);
241 * Make ATTID for given OID
242 * Reference: [MS-DRSR] section 5.12.2
244 WERROR dsdb_schema_pfm_make_attid(struct dsdb_schema_prefixmap *pfm, const char *oid, uint32_t *attid)
248 uint32_t lo_word, hi_word;
253 return WERR_INVALID_PARAMETER;
256 return WERR_INVALID_PARAMETER;
259 werr = _dsdb_pfm_make_binary_oid(oid, pfm, &bin_oid, &last_subid);
260 W_ERROR_NOT_OK_RETURN(werr);
262 /* search the prefix in the prefix table, if none found, add
263 * one entry for new prefix.
265 werr = dsdb_schema_pfm_find_binary_oid(pfm, bin_oid, &idx);
266 if (W_ERROR_IS_OK(werr)) {
267 /* free memory allocated for bin_oid */
268 data_blob_free(&bin_oid);
270 /* entry does not exists, add it */
271 werr = _dsdb_schema_pfm_add_entry(pfm, bin_oid, &idx);
272 W_ERROR_NOT_OK_RETURN(werr);
275 /* compose the attid */
276 lo_word = last_subid % 16384; /* actually get lower 14 bits: lo_word & 0x3FFF */
277 if (last_subid >= 16384) {
278 /* mark it so that it is known to not be the whole lastValue
279 * This will raise 16-th bit*/
282 hi_word = pfm->prefixes[idx].id;
285 * HIWORD is prefixMap id
286 * LOWORD is truncated binary-oid */
287 *attid = (hi_word * 65536) + lo_word;
294 * Make OID for given ATTID.
295 * Reference: [MS-DRSR] section 5.12.2
297 WERROR dsdb_schema_pfm_oid_from_attid(struct dsdb_schema_prefixmap *pfm, uint32_t attid,
298 TALLOC_CTX *mem_ctx, const char **_oid)
301 uint32_t hi_word, lo_word;
302 DATA_BLOB bin_oid = {NULL, 0};
303 struct dsdb_schema_prefixmap_oid *pfm_entry;
304 WERROR werr = WERR_OK;
306 /* crack attid value */
307 hi_word = attid >> 16;
308 lo_word = attid & 0xFFFF;
310 /* locate corRespoNding prefixMap entry */
312 for (i = 0; i < pfm->length; i++) {
313 if (hi_word == pfm->prefixes[i].id) {
314 pfm_entry = &pfm->prefixes[i];
320 return WERR_INTERNAL_ERROR;
323 /* copy oid prefix making enough room */
324 bin_oid.length = pfm_entry->bin_oid.length + 2;
325 bin_oid.data = talloc_array(mem_ctx, uint8_t, bin_oid.length);
326 W_ERROR_HAVE_NO_MEMORY(bin_oid.data);
327 memcpy(bin_oid.data, pfm_entry->bin_oid.data, pfm_entry->bin_oid.length);
330 bin_oid.length = bin_oid.length - 1;
331 bin_oid.data[bin_oid.length-1] = lo_word;
334 if (lo_word >= 32768) {
337 bin_oid.data[bin_oid.length-2] = (0x80 | ((lo_word>>7) & 0x7f));
338 bin_oid.data[bin_oid.length-1] = lo_word & 0x7f;
341 if (!ber_read_OID_String(mem_ctx, bin_oid, _oid)) {
342 werr = WERR_INTERNAL_ERROR;
345 /* free locally allocated memory */
346 talloc_free(bin_oid.data);
353 * Verifies drsuapi mappings.
355 static WERROR _dsdb_drsuapi_pfm_verify(const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr,
356 bool have_schema_info)
359 uint32_t num_mappings;
360 struct drsuapi_DsReplicaOIDMapping *mapping;
362 /* check input params */
364 return WERR_INVALID_PARAMETER;
366 if (!ctr->mappings) {
367 return WERR_INVALID_PARAMETER;
369 num_mappings = ctr->num_mappings;
371 if (have_schema_info) {
372 if (ctr->num_mappings < 2) {
373 return WERR_INVALID_PARAMETER;
376 /* check last entry for being special */
377 mapping = &ctr->mappings[ctr->num_mappings - 1];
378 if (!mapping->oid.binary_oid) {
379 return WERR_INVALID_PARAMETER;
381 if (mapping->id_prefix != 0) {
382 return WERR_INVALID_PARAMETER;
384 if (mapping->oid.length != 21) {
385 return WERR_INVALID_PARAMETER;
387 if (*mapping->oid.binary_oid != 0xFF) {
388 return WERR_INVALID_PARAMETER;
391 /* get number of read mappings in the map */
395 /* now, verify rest of entries for being at least not null */
396 for (i = 0; i < num_mappings; i++) {
397 mapping = &ctr->mappings[i];
398 if (!mapping->oid.length) {
399 return WERR_INVALID_PARAMETER;
401 if (!mapping->oid.binary_oid) {
402 return WERR_INVALID_PARAMETER;
404 /* check it is not the special entry */
405 if (*mapping->oid.binary_oid == 0xFF) {
406 return WERR_INVALID_PARAMETER;
414 * Convert drsuapi_ prefix map to prefixMap internal presentation.
416 * \param ctr Pointer to drsuapi_DsReplicaOIDMapping_Ctr which represents drsuapi_ prefixMap
417 * \param have_schema_info if drsuapi_prefixMap have schem_info in it or not
418 * \param mem_ctx TALLOC_CTX to make allocations in
419 * \param _pfm Out pointer to hold newly created prefixMap
420 * \param _schema_info Out param to store schema_info to. If NULL, schema_info is not decoded
422 WERROR dsdb_schema_pfm_from_drsuapi_pfm(const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr,
423 bool have_schema_info,
425 struct dsdb_schema_prefixmap **_pfm,
426 const char **_schema_info)
431 uint32_t num_mappings;
432 struct dsdb_schema_prefixmap *pfm;
435 return WERR_INVALID_PARAMETER;
439 * error out if schema_info is requested
440 * but it is not in the drsuapi_prefixMap
442 if (_schema_info && !have_schema_info) {
443 return WERR_INVALID_PARAMETER;
446 /* verify drsuapi_pefixMap */
447 werr =_dsdb_drsuapi_pfm_verify(ctr, have_schema_info);
448 W_ERROR_NOT_OK_RETURN(werr);
450 /* allocate mem for prefix map */
451 num_mappings = ctr->num_mappings;
452 if (have_schema_info) {
455 pfm = _dsdb_schema_prefixmap_talloc(mem_ctx, num_mappings);
456 W_ERROR_HAVE_NO_MEMORY(pfm);
458 /* copy entries from drsuapi_prefixMap */
459 for (i = 0; i < pfm->length; i++) {
460 blob = data_blob_talloc(pfm,
461 ctr->mappings[i].oid.binary_oid,
462 ctr->mappings[i].oid.length);
467 pfm->prefixes[i].id = ctr->mappings[i].id_prefix;
468 pfm->prefixes[i].bin_oid = blob;
471 /* fetch schema_info if requested */
473 /* by this time, i should have this value,
474 * but set it here for clarity */
475 i = ctr->num_mappings - 1;
477 *_schema_info = hex_encode_talloc(mem_ctx,
478 ctr->mappings[i].oid.binary_oid,
479 ctr->mappings[i].oid.length);
480 if (!*_schema_info) {
486 /* schema_prefixMap created successfully */
493 * Convert drsuapi_ prefix map to prefixMap internal presentation.
495 * \param pfm Schema prefixMap to be converted
496 * \param schema_info schema_info string - if NULL, we don't need it
497 * \param mem_ctx TALLOC_CTX to make allocations in
498 * \param _ctr Out pointer to drsuapi_DsReplicaOIDMapping_Ctr prefix map structure
500 WERROR dsdb_drsuapi_pfm_from_schema_pfm(const struct dsdb_schema_prefixmap *pfm,
501 const char *schema_info,
503 struct drsuapi_DsReplicaOIDMapping_Ctr **_ctr)
507 struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
510 return WERR_INVALID_PARAMETER;
513 return WERR_INVALID_PARAMETER;
515 if (pfm->length == 0) {
516 return WERR_INVALID_PARAMETER;
519 /* allocate memory for the structure */
520 ctr = talloc_zero(mem_ctx, struct drsuapi_DsReplicaOIDMapping_Ctr);
521 W_ERROR_HAVE_NO_MEMORY(ctr);
523 ctr->num_mappings = (schema_info ? pfm->length + 1 : pfm->length);
524 ctr->mappings = talloc_array(ctr, struct drsuapi_DsReplicaOIDMapping, ctr->num_mappings);
525 if (!ctr->mappings) {
530 /* copy entries from schema_prefixMap */
531 for (i = 0; i < pfm->length; i++) {
532 blob = data_blob_dup_talloc(ctr, &pfm->prefixes[i].bin_oid);
537 ctr->mappings[i].id_prefix = pfm->prefixes[i].id;
538 ctr->mappings[i].oid.length = blob.length;
539 ctr->mappings[i].oid.binary_oid = blob.data;
542 /* make schema_info entry if needed */
544 /* by this time, i should have this value,
545 * but set it here for clarity */
546 i = ctr->num_mappings - 1;
548 blob = strhex_to_data_blob(ctr, schema_info);
554 ctr->mappings[i].id_prefix = 0;
555 ctr->mappings[i].oid.length = blob.length;
556 ctr->mappings[i].oid.binary_oid = blob.data;
559 /* drsuapi_prefixMap constructed successfully */
566 * Verifies schema prefixMap and drsuapi prefixMap are same.
567 * Note that we just need to verify pfm contains prefixes
568 * from ctr, not that those prefixes has same id_prefix.
570 WERROR dsdb_schema_pfm_contains_drsuapi_pfm(const struct dsdb_schema_prefixmap *pfm,
571 const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
578 /* verify drsuapi_pefixMap */
579 werr = _dsdb_drsuapi_pfm_verify(ctr, true);
580 W_ERROR_NOT_OK_RETURN(werr);
582 /* check pfm contains every entry from ctr, except the last one */
583 for (i = 0; i < ctr->num_mappings - 1; i++) {
584 bin_oid.length = ctr->mappings[i].oid.length;
585 bin_oid.data = ctr->mappings[i].oid.binary_oid;
587 werr = dsdb_schema_pfm_find_binary_oid(pfm, bin_oid, &idx);
588 if (!W_ERROR_IS_OK(werr)) {
589 return WERR_DS_DRA_SCHEMA_MISMATCH;