s4/drs: Remove unused structures and functions
[ira/wip.git] / source4 / dsdb / schema / schema_prefixmap.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    DRS::prefixMap implementation
5
6    Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2009
7
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.
12
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.
17
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/>.
20 */
21
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
28
29 /**
30  * Allocates schema_prefixMap object in supplied memory context
31  */
32 static struct dsdb_schema_prefixmap *_dsdb_schema_prefixmap_talloc(TALLOC_CTX *mem_ctx,
33                                                                    uint32_t length)
34 {
35         struct dsdb_schema_prefixmap *pfm;
36
37         pfm = talloc_zero(mem_ctx, struct dsdb_schema_prefixmap);
38         if (!pfm) {
39                 return NULL;
40         }
41
42         pfm->length = length;
43         pfm->prefixes = talloc_zero_array(pfm, struct dsdb_schema_prefixmap_oid,
44                                           pfm->length);
45         if (!pfm->prefixes) {
46                 talloc_free(pfm);
47                 return NULL;
48         }
49
50         return pfm;
51 }
52
53 /**
54  * Initial prefixMap creation according to:
55  * [MS-DRSR] section 5.12.2
56  */
57 WERROR dsdb_schema_pfm_new(TALLOC_CTX *mem_ctx, struct dsdb_schema_prefixmap **_pfm)
58 {
59         uint32_t i;
60         struct dsdb_schema_prefixmap *pfm;
61         const struct {
62                 uint32_t        id;
63                 const char      *oid_prefix;
64         } pfm_init_data[] = {
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"},
84         };
85
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);
89
90         /* build prefixes */
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)) {
93                         talloc_free(pfm);
94                         return WERR_INTERNAL_ERROR;
95                 }
96                 pfm->prefixes[i].id = pfm_init_data[i].id;
97         }
98
99         *_pfm = pfm;
100
101         return WERR_OK;
102 }
103
104
105 /**
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
110  *
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
114  */
115 static WERROR _dsdb_schema_pfm_add_entry(struct dsdb_schema_prefixmap *pfm, DATA_BLOB bin_oid, uint32_t *_idx)
116 {
117         uint32_t i;
118         struct dsdb_schema_prefixmap_oid * pfm_entry;
119         struct dsdb_schema_prefixmap_oid * prefixes_new;
120
121         /* dup memory for bin-oid prefix to be added */
122         bin_oid = data_blob_dup_talloc(pfm, &bin_oid);
123         if (!bin_oid.data) {
124                 return WERR_NOMEM;
125         }
126
127         /* make room for new entry */
128         prefixes_new = talloc_realloc(pfm, pfm->prefixes, struct dsdb_schema_prefixmap_oid, pfm->length + 1);
129         if (!prefixes_new) {
130                 talloc_free(bin_oid.data);
131                 return WERR_NOMEM;
132         }
133         pfm->prefixes = prefixes_new;
134
135         /* make new unique ID in prefixMap */
136         pfm_entry = &pfm->prefixes[pfm->length];
137         pfm_entry->id = 0;
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;
141         }
142
143         /* add new bin-oid prefix */
144         pfm_entry->id++;
145         pfm_entry->bin_oid = bin_oid;
146
147         *_idx = pfm->length;
148         pfm->length++;
149
150         return WERR_OK;
151 }
152
153
154 /**
155  * Make partial binary OID for supplied OID.
156  * Reference: [MS-DRSR] section 5.12.2
157  */
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)
160 {
161         uint32_t last_subid;
162         const char *oid_subid;
163
164         /* make last sub-identifier value */
165         oid_subid = strrchr(full_oid, '.');
166         if (!oid_subid) {
167                 return WERR_INVALID_PARAMETER;
168         }
169         oid_subid++;
170         last_subid = strtoul(oid_subid, NULL, 10);
171
172         /* encode oid in BER format */
173         if (!ber_write_OID_String(mem_ctx, _bin_oid, full_oid)) {
174                 return WERR_INTERNAL_ERROR;
175         }
176
177         /* get the prefix of the OID */
178         if (last_subid < 128) {
179                 _bin_oid->length -= 1;
180         } else {
181                 _bin_oid->length -= 2;
182         }
183
184         /* return last_value if requested */
185         if (_last_subid) {
186                 *_last_subid = last_subid;
187         }
188
189         return WERR_OK;
190 }
191
192 /**
193  * Lookup partial-binary-oid in prefixMap
194  */
195 WERROR dsdb_schema_pfm_find_binary_oid(const struct dsdb_schema_prefixmap *pfm,
196                                        DATA_BLOB bin_oid,
197                                        uint32_t *_idx)
198 {
199         uint32_t i;
200
201         for (i = 0; i < pfm->length; i++) {
202                 if (pfm->prefixes[i].bin_oid.length != bin_oid.length) {
203                         continue;
204                 }
205
206                 if (memcmp(pfm->prefixes[i].bin_oid.data, bin_oid.data, bin_oid.length) == 0) {
207                         if (_idx) {
208                                 *_idx = i;
209                         }
210                         return WERR_OK;
211                 }
212         }
213
214         return WERR_DS_NO_MSDS_INTID;
215 }
216
217 /**
218  * Lookup full-oid in prefixMap
219  * Note: this may be slow.
220  */
221 WERROR dsdb_schema_pfm_find_oid(const struct dsdb_schema_prefixmap *pfm,
222                                 const char *full_oid,
223                                 uint32_t *_idx)
224 {
225         WERROR werr;
226         DATA_BLOB bin_oid;
227
228         ZERO_STRUCT(bin_oid);
229
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);
233
234         /* lookup the partial-oid */
235         werr = dsdb_schema_pfm_find_binary_oid(pfm, bin_oid, _idx);
236
237         data_blob_free(&bin_oid);
238
239         return werr;
240 }
241
242 /**
243  * Make ATTID for given OID
244  * Reference: [MS-DRSR] section 5.12.2
245  */
246 WERROR dsdb_schema_pfm_make_attid(struct dsdb_schema_prefixmap *pfm, const char *oid, uint32_t *attid)
247 {
248         WERROR werr;
249         uint32_t idx;
250         uint32_t lo_word, hi_word;
251         uint32_t last_subid;
252         DATA_BLOB bin_oid;
253
254         if (!pfm) {
255                 return WERR_INVALID_PARAMETER;
256         }
257         if (!oid) {
258                 return WERR_INVALID_PARAMETER;
259         }
260
261         werr = _dsdb_pfm_make_binary_oid(oid, pfm, &bin_oid, &last_subid);
262         W_ERROR_NOT_OK_RETURN(werr);
263
264         /* search the prefix in the prefix table, if none found, add
265          * one entry for new prefix.
266          */
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);
271         } else {
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);
275         }
276
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*/
282                 lo_word += 32768;
283         }
284         hi_word = pfm->prefixes[idx].id;
285
286         /* make ATTID:
287          * HIWORD is prefixMap id
288          * LOWORD is truncated binary-oid */
289         *attid = (hi_word * 65536) + lo_word;
290
291         return WERR_OK;
292 }
293
294
295 /**
296  * Make OID for given ATTID.
297  * Reference: [MS-DRSR] section 5.12.2
298  */
299 WERROR dsdb_schema_pfm_oid_from_attid(struct dsdb_schema_prefixmap *pfm, uint32_t attid,
300                                       TALLOC_CTX *mem_ctx, const char **_oid)
301 {
302         int i;
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;
307
308         /* crack attid value */
309         hi_word = attid >> 16;
310         lo_word = attid & 0xFFFF;
311
312         /* locate corRespoNding prefixMap entry */
313         pfm_entry = NULL;
314         for (i = 0; i < pfm->length; i++) {
315                 if (hi_word == pfm->prefixes[i].id) {
316                         pfm_entry = &pfm->prefixes[i];
317                         break;
318                 }
319         }
320
321         if (!pfm_entry) {
322                 return WERR_INTERNAL_ERROR;
323         }
324
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);
330
331         if (lo_word < 128) {
332                 bin_oid.length = bin_oid.length - 1;
333                 bin_oid.data[bin_oid.length-1] = lo_word;
334         }
335         else {
336                 if (lo_word >= 32768) {
337                         lo_word -= 32768;
338                 }
339                 bin_oid.data[bin_oid.length-2] = (0x80 | ((lo_word>>7) & 0x7f));
340                 bin_oid.data[bin_oid.length-1] = lo_word & 0x7f;
341         }
342
343         if (!ber_read_OID_String(mem_ctx, bin_oid, _oid)) {
344                 werr = WERR_INTERNAL_ERROR;
345         }
346
347         /* free locally allocated memory */
348         talloc_free(bin_oid.data);
349
350         return werr;
351 }
352
353
354 /**
355  * Verifies drsuapi mappings.
356  */
357 static WERROR _dsdb_drsuapi_pfm_verify(const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr,
358                                        bool have_schema_info)
359 {
360         uint32_t i;
361         uint32_t num_mappings;
362         struct drsuapi_DsReplicaOIDMapping *mapping;
363
364         /* check input params */
365         if (!ctr) {
366                 return WERR_INVALID_PARAMETER;
367         }
368         if (!ctr->mappings) {
369                 return WERR_INVALID_PARAMETER;
370         }
371         num_mappings = ctr->num_mappings;
372
373         if (have_schema_info) {
374                 if (ctr->num_mappings < 2) {
375                         return WERR_INVALID_PARAMETER;
376                 }
377
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;
382                 }
383                 if (mapping->id_prefix != 0) {
384                         return WERR_INVALID_PARAMETER;
385                 }
386                 if (mapping->oid.length != 21) {
387                         return WERR_INVALID_PARAMETER;
388                 }
389                 if (*mapping->oid.binary_oid != 0xFF) {
390                         return WERR_INVALID_PARAMETER;
391                 }
392
393                 /* get number of read mappings in the map */
394                 num_mappings--;
395         }
396
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;
402                 }
403                 if (!mapping->oid.binary_oid) {
404                         return WERR_INVALID_PARAMETER;
405                 }
406                 /* check it is not the special entry */
407                 if (*mapping->oid.binary_oid == 0xFF) {
408                         return WERR_INVALID_PARAMETER;
409                 }
410         }
411
412         return WERR_OK;
413 }
414
415 /**
416  * Convert drsuapi_ prefix map to prefixMap internal presentation.
417  *
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
423  */
424 WERROR dsdb_schema_pfm_from_drsuapi_pfm(const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr,
425                                         bool have_schema_info,
426                                         TALLOC_CTX *mem_ctx,
427                                         struct dsdb_schema_prefixmap **_pfm,
428                                         const char **_schema_info)
429 {
430         WERROR werr;
431         uint32_t i;
432         DATA_BLOB blob;
433         uint32_t num_mappings;
434         struct dsdb_schema_prefixmap *pfm;
435
436         if (!_pfm) {
437                 return WERR_INVALID_PARAMETER;
438         }
439
440         /*
441          * error out if schema_info is requested
442          * but it is not in the drsuapi_prefixMap
443          */
444         if (_schema_info && !have_schema_info) {
445                 return WERR_INVALID_PARAMETER;
446         }
447
448         /* verify drsuapi_pefixMap */
449         werr =_dsdb_drsuapi_pfm_verify(ctr, have_schema_info);
450         W_ERROR_NOT_OK_RETURN(werr);
451
452         /* allocate mem for prefix map */
453         num_mappings = ctr->num_mappings;
454         if (have_schema_info) {
455                 num_mappings--;
456         }
457         pfm = _dsdb_schema_prefixmap_talloc(mem_ctx, num_mappings);
458         W_ERROR_HAVE_NO_MEMORY(pfm);
459
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);
465                 if (!blob.data) {
466                         talloc_free(pfm);
467                         return WERR_NOMEM;
468                 }
469                 pfm->prefixes[i].id = ctr->mappings[i].id_prefix;
470                 pfm->prefixes[i].bin_oid = blob;
471         }
472
473         /* fetch schema_info if requested */
474         if (_schema_info) {
475                 /* by this time, i should have this value,
476                  *  but set it here for clarity */
477                 i = ctr->num_mappings - 1;
478
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) {
483                         talloc_free(pfm);
484                         return WERR_NOMEM;
485                 }
486         }
487
488         /* schema_prefixMap created successfully */
489         *_pfm = pfm;
490
491         return WERR_OK;
492 }
493
494 /**
495  * Convert drsuapi_ prefix map to prefixMap internal presentation.
496  *
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
501  */
502 WERROR dsdb_drsuapi_pfm_from_schema_pfm(const struct dsdb_schema_prefixmap *pfm,
503                                         const char *schema_info,
504                                         TALLOC_CTX *mem_ctx,
505                                         struct drsuapi_DsReplicaOIDMapping_Ctr **_ctr)
506 {
507         uint32_t i;
508         DATA_BLOB blob;
509         struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
510
511         if (!_ctr) {
512                 return WERR_INVALID_PARAMETER;
513         }
514         if (!pfm) {
515                 return WERR_INVALID_PARAMETER;
516         }
517         if (pfm->length == 0) {
518                 return WERR_INVALID_PARAMETER;
519         }
520
521         /* allocate memory for the structure */
522         ctr = talloc_zero(mem_ctx, struct drsuapi_DsReplicaOIDMapping_Ctr);
523         W_ERROR_HAVE_NO_MEMORY(ctr);
524
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) {
528                 talloc_free(ctr);
529                 return WERR_NOMEM;
530         }
531
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);
535                 if (!blob.data) {
536                         talloc_free(ctr);
537                         return WERR_NOMEM;
538                 }
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;
542         }
543
544         /* make schema_info entry if needed */
545         if (schema_info) {
546                 /* by this time, i should have this value,
547                  *  but set it here for clarity */
548                 i = ctr->num_mappings - 1;
549
550                 blob = strhex_to_data_blob(ctr, schema_info);
551                 if (!blob.data) {
552                         talloc_free(ctr);
553                         return WERR_NOMEM;
554                 }
555
556                 ctr->mappings[i].id_prefix = 0;
557                 ctr->mappings[i].oid.length = blob.length;
558                 ctr->mappings[i].oid.binary_oid = blob.data;
559         }
560
561         /* drsuapi_prefixMap constructed successfully */
562         *_ctr = ctr;
563
564         return WERR_OK;
565 }
566
567 /**
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.
571  */
572 WERROR dsdb_schema_pfm_contains_drsuapi_pfm(const struct dsdb_schema_prefixmap *pfm,
573                                             const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
574 {
575         WERROR werr;
576         uint32_t i;
577         uint32_t idx;
578         DATA_BLOB bin_oid;
579
580         /* verify drsuapi_pefixMap */
581         werr = _dsdb_drsuapi_pfm_verify(ctr, true);
582         W_ERROR_NOT_OK_RETURN(werr);
583
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;
588
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;
592                 }
593         }
594
595         return WERR_OK;
596 }