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 return WERR_INTERNAL_ERROR
;
194 /* get the prefix of the OID */
195 if (last_subid
< 128) {
196 _bin_oid
->length
-= 1;
198 _bin_oid
->length
-= 2;
201 /* return last_value if requested */
203 *_last_subid
= last_subid
;
210 * Lookup partial-binary-oid in prefixMap
212 WERROR
dsdb_schema_pfm_find_binary_oid(const struct dsdb_schema_prefixmap
*pfm
,
218 for (i
= 0; i
< pfm
->length
; i
++) {
219 if (pfm
->prefixes
[i
].bin_oid
.length
!= bin_oid
.length
) {
223 if (memcmp(pfm
->prefixes
[i
].bin_oid
.data
, bin_oid
.data
, bin_oid
.length
) == 0) {
231 return WERR_DS_NO_MSDS_INTID
;
235 * Lookup full-oid in prefixMap
236 * Note: this may be slow.
238 WERROR
dsdb_schema_pfm_find_oid(const struct dsdb_schema_prefixmap
*pfm
,
239 const char *full_oid
,
245 ZERO_STRUCT(bin_oid
);
247 /* make partial-binary-oid to look for */
248 werr
= _dsdb_pfm_make_binary_oid(full_oid
, NULL
, &bin_oid
, NULL
);
249 W_ERROR_NOT_OK_RETURN(werr
);
251 /* lookup the partial-oid */
252 werr
= dsdb_schema_pfm_find_binary_oid(pfm
, bin_oid
, _idx
);
254 data_blob_free(&bin_oid
);
260 * Make ATTID for given OID
261 * Reference: [MS-DRSR] section 5.12.2
263 WERROR
dsdb_schema_pfm_make_attid(struct dsdb_schema_prefixmap
*pfm
, const char *oid
, uint32_t *attid
)
267 uint32_t lo_word
, hi_word
;
272 return WERR_INVALID_PARAMETER
;
275 return WERR_INVALID_PARAMETER
;
278 werr
= _dsdb_pfm_make_binary_oid(oid
, pfm
, &bin_oid
, &last_subid
);
279 W_ERROR_NOT_OK_RETURN(werr
);
281 /* search the prefix in the prefix table, if none found, add
282 * one entry for new prefix.
284 werr
= dsdb_schema_pfm_find_binary_oid(pfm
, bin_oid
, &idx
);
285 if (W_ERROR_IS_OK(werr
)) {
286 /* free memory allocated for bin_oid */
287 data_blob_free(&bin_oid
);
289 /* entry does not exists, add it */
290 werr
= _dsdb_schema_pfm_add_entry(pfm
, bin_oid
, &idx
);
291 W_ERROR_NOT_OK_RETURN(werr
);
294 /* compose the attid */
295 lo_word
= last_subid
% 16384; /* actually get lower 14 bits: lo_word & 0x3FFF */
296 if (last_subid
>= 16384) {
297 /* mark it so that it is known to not be the whole lastValue
298 * This will raise 16-th bit*/
301 hi_word
= pfm
->prefixes
[idx
].id
;
304 * HIWORD is prefixMap id
305 * LOWORD is truncated binary-oid */
306 *attid
= (hi_word
* 65536) + lo_word
;
313 * Make OID for given ATTID.
314 * Reference: [MS-DRSR] section 5.12.2
316 WERROR
dsdb_schema_pfm_oid_from_attid(struct dsdb_schema_prefixmap
*pfm
, uint32_t attid
,
317 TALLOC_CTX
*mem_ctx
, const char **_oid
)
320 uint32_t hi_word
, lo_word
;
321 DATA_BLOB bin_oid
= {NULL
, 0};
322 struct dsdb_schema_prefixmap_oid
*pfm_entry
;
323 WERROR werr
= WERR_OK
;
325 /* sanity check for attid requested */
326 if (dsdb_pfm_get_attid_type(attid
) != dsdb_attid_type_pfm
) {
327 return WERR_INVALID_PARAMETER
;
330 /* crack attid value */
331 hi_word
= attid
>> 16;
332 lo_word
= attid
& 0xFFFF;
334 /* locate corRespoNding prefixMap entry */
336 for (i
= 0; i
< pfm
->length
; i
++) {
337 if (hi_word
== pfm
->prefixes
[i
].id
) {
338 pfm_entry
= &pfm
->prefixes
[i
];
344 return WERR_INTERNAL_ERROR
;
347 /* copy oid prefix making enough room */
348 bin_oid
.length
= pfm_entry
->bin_oid
.length
+ 2;
349 bin_oid
.data
= talloc_array(mem_ctx
, uint8_t, bin_oid
.length
);
350 W_ERROR_HAVE_NO_MEMORY(bin_oid
.data
);
351 memcpy(bin_oid
.data
, pfm_entry
->bin_oid
.data
, pfm_entry
->bin_oid
.length
);
354 bin_oid
.length
= bin_oid
.length
- 1;
355 bin_oid
.data
[bin_oid
.length
-1] = lo_word
;
358 if (lo_word
>= 32768) {
361 bin_oid
.data
[bin_oid
.length
-2] = (0x80 | ((lo_word
>>7) & 0x7f));
362 bin_oid
.data
[bin_oid
.length
-1] = lo_word
& 0x7f;
365 if (!ber_read_OID_String(mem_ctx
, bin_oid
, _oid
)) {
366 werr
= WERR_INTERNAL_ERROR
;
369 /* free locally allocated memory */
370 talloc_free(bin_oid
.data
);
377 * Verifies drsuapi mappings.
379 static WERROR
_dsdb_drsuapi_pfm_verify(const struct drsuapi_DsReplicaOIDMapping_Ctr
*ctr
,
380 bool have_schema_info
)
383 uint32_t num_mappings
;
384 struct drsuapi_DsReplicaOIDMapping
*mapping
;
386 /* check input params */
388 return WERR_INVALID_PARAMETER
;
390 if (!ctr
->mappings
) {
391 return WERR_INVALID_PARAMETER
;
393 num_mappings
= ctr
->num_mappings
;
395 if (have_schema_info
) {
397 struct dsdb_schema_info
*schi
= NULL
;
399 if (ctr
->num_mappings
< 2) {
400 return WERR_INVALID_PARAMETER
;
403 /* check last entry for being special */
404 mapping
= &ctr
->mappings
[ctr
->num_mappings
- 1];
405 if (mapping
->id_prefix
!= 0) {
406 return WERR_INVALID_PARAMETER
;
409 /* parse schemaInfo blob to verify it is valid */
410 blob
= data_blob_const(mapping
->oid
.binary_oid
, mapping
->oid
.length
);
411 if (!W_ERROR_IS_OK(dsdb_schema_info_from_blob(&blob
, talloc_autofree_context(), &schi
))) {
413 return WERR_INVALID_PARAMETER
;
416 /* get number of read mappings in the map */
420 /* now, verify rest of entries for being at least not null */
421 for (i
= 0; i
< num_mappings
; i
++) {
422 mapping
= &ctr
->mappings
[i
];
423 if (!mapping
->oid
.length
) {
424 return WERR_INVALID_PARAMETER
;
426 if (!mapping
->oid
.binary_oid
) {
427 return WERR_INVALID_PARAMETER
;
429 /* check it is not the special entry */
430 if (*mapping
->oid
.binary_oid
== 0xFF) {
431 return WERR_INVALID_PARAMETER
;
439 * Convert drsuapi_ prefix map to prefixMap internal presentation.
441 * \param ctr Pointer to drsuapi_DsReplicaOIDMapping_Ctr which represents drsuapi_ prefixMap
442 * \param have_schema_info if drsuapi_prefixMap have schem_info in it or not
443 * \param mem_ctx TALLOC_CTX to make allocations in
444 * \param _pfm Out pointer to hold newly created prefixMap
445 * \param _schema_info Out param to store schema_info to. If NULL, schema_info is not decoded
447 WERROR
dsdb_schema_pfm_from_drsuapi_pfm(const struct drsuapi_DsReplicaOIDMapping_Ctr
*ctr
,
448 bool have_schema_info
,
450 struct dsdb_schema_prefixmap
**_pfm
,
451 const char **_schema_info
)
456 uint32_t num_mappings
;
457 struct dsdb_schema_prefixmap
*pfm
;
460 return WERR_INVALID_PARAMETER
;
464 * error out if schema_info is requested
465 * but it is not in the drsuapi_prefixMap
467 if (_schema_info
&& !have_schema_info
) {
468 return WERR_INVALID_PARAMETER
;
471 /* verify drsuapi_pefixMap */
472 werr
=_dsdb_drsuapi_pfm_verify(ctr
, have_schema_info
);
473 W_ERROR_NOT_OK_RETURN(werr
);
475 /* allocate mem for prefix map */
476 num_mappings
= ctr
->num_mappings
;
477 if (have_schema_info
) {
480 pfm
= _dsdb_schema_prefixmap_talloc(mem_ctx
, num_mappings
);
481 W_ERROR_HAVE_NO_MEMORY(pfm
);
483 /* copy entries from drsuapi_prefixMap */
484 for (i
= 0; i
< pfm
->length
; i
++) {
485 blob
= data_blob_talloc(pfm
,
486 ctr
->mappings
[i
].oid
.binary_oid
,
487 ctr
->mappings
[i
].oid
.length
);
492 pfm
->prefixes
[i
].id
= ctr
->mappings
[i
].id_prefix
;
493 pfm
->prefixes
[i
].bin_oid
= blob
;
496 /* fetch schema_info if requested */
498 /* by this time, i should have this value,
499 * but set it here for clarity */
500 i
= ctr
->num_mappings
- 1;
502 *_schema_info
= hex_encode_talloc(mem_ctx
,
503 ctr
->mappings
[i
].oid
.binary_oid
,
504 ctr
->mappings
[i
].oid
.length
);
505 if (!*_schema_info
) {
511 /* schema_prefixMap created successfully */
518 * Convert drsuapi_ prefix map to prefixMap internal presentation.
520 * \param pfm Schema prefixMap to be converted
521 * \param schema_info schema_info string - if NULL, we don't need it
522 * \param mem_ctx TALLOC_CTX to make allocations in
523 * \param _ctr Out pointer to drsuapi_DsReplicaOIDMapping_Ctr prefix map structure
525 WERROR
dsdb_drsuapi_pfm_from_schema_pfm(const struct dsdb_schema_prefixmap
*pfm
,
526 const char *schema_info
,
528 struct drsuapi_DsReplicaOIDMapping_Ctr
**_ctr
)
532 struct drsuapi_DsReplicaOIDMapping_Ctr
*ctr
;
535 return WERR_INVALID_PARAMETER
;
538 return WERR_INVALID_PARAMETER
;
540 if (pfm
->length
== 0) {
541 return WERR_INVALID_PARAMETER
;
544 /* allocate memory for the structure */
545 ctr
= talloc_zero(mem_ctx
, struct drsuapi_DsReplicaOIDMapping_Ctr
);
546 W_ERROR_HAVE_NO_MEMORY(ctr
);
548 ctr
->num_mappings
= (schema_info
? pfm
->length
+ 1 : pfm
->length
);
549 ctr
->mappings
= talloc_array(ctr
, struct drsuapi_DsReplicaOIDMapping
, ctr
->num_mappings
);
550 if (!ctr
->mappings
) {
555 /* copy entries from schema_prefixMap */
556 for (i
= 0; i
< pfm
->length
; i
++) {
557 blob
= data_blob_dup_talloc(ctr
, &pfm
->prefixes
[i
].bin_oid
);
562 ctr
->mappings
[i
].id_prefix
= pfm
->prefixes
[i
].id
;
563 ctr
->mappings
[i
].oid
.length
= blob
.length
;
564 ctr
->mappings
[i
].oid
.binary_oid
= blob
.data
;
567 /* make schema_info entry if needed */
569 /* by this time, i should have this value,
570 * but set it here for clarity */
571 i
= ctr
->num_mappings
- 1;
573 blob
= strhex_to_data_blob(ctr
, schema_info
);
579 ctr
->mappings
[i
].id_prefix
= 0;
580 ctr
->mappings
[i
].oid
.length
= blob
.length
;
581 ctr
->mappings
[i
].oid
.binary_oid
= blob
.data
;
584 /* drsuapi_prefixMap constructed successfully */
591 * Verifies schema prefixMap and drsuapi prefixMap are same.
592 * Note that we just need to verify pfm contains prefixes
593 * from ctr, not that those prefixes has same id_prefix.
595 WERROR
dsdb_schema_pfm_contains_drsuapi_pfm(const struct dsdb_schema_prefixmap
*pfm
,
596 const struct drsuapi_DsReplicaOIDMapping_Ctr
*ctr
)
603 /* verify drsuapi_pefixMap */
604 werr
= _dsdb_drsuapi_pfm_verify(ctr
, true);
605 W_ERROR_NOT_OK_RETURN(werr
);
607 /* check pfm contains every entry from ctr, except the last one */
608 for (i
= 0; i
< ctr
->num_mappings
- 1; i
++) {
609 bin_oid
.length
= ctr
->mappings
[i
].oid
.length
;
610 bin_oid
.data
= ctr
->mappings
[i
].oid
.binary_oid
;
612 werr
= dsdb_schema_pfm_find_binary_oid(pfm
, bin_oid
, &idx
);
613 if (!W_ERROR_IS_OK(werr
)) {
614 return WERR_DS_DRA_SCHEMA_MISMATCH
;