s4/drs: Move making of partial-binary-oid to a separate function
[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  * Initial prefixMap creation according to:
30  * [MS-DRSR] section 5.12.2
31  */
32 WERROR dsdb_schema_pfm_new(TALLOC_CTX *mem_ctx, struct dsdb_schema_prefixmap **ppfm)
33 {
34         uint32_t i;
35         struct dsdb_schema_prefixmap *pfm;
36         const struct {
37                 uint32_t        id;
38                 const char      *oid_prefix;
39         } pfm_init_data[] = {
40                 {.id=0x00000000, .oid_prefix="2.5.4"},
41                 {.id=0x00000001, .oid_prefix="2.5.6"},
42                 {.id=0x00000002, .oid_prefix="1.2.840.113556.1.2"},
43                 {.id=0x00000003, .oid_prefix="1.2.840.113556.1.3"},
44                 {.id=0x00000004, .oid_prefix="2.16.840.1.101.2.2.1"},
45                 {.id=0x00000005, .oid_prefix="2.16.840.1.101.2.2.3"},
46                 {.id=0x00000006, .oid_prefix="2.16.840.1.101.2.1.5"},
47                 {.id=0x00000007, .oid_prefix="2.16.840.1.101.2.1.4"},
48                 {.id=0x00000008, .oid_prefix="2.5.5"},
49                 {.id=0x00000009, .oid_prefix="1.2.840.113556.1.4"},
50                 {.id=0x0000000A, .oid_prefix="1.2.840.113556.1.5"},
51                 {.id=0x00000013, .oid_prefix="0.9.2342.19200300.100"},
52                 {.id=0x00000014, .oid_prefix="2.16.840.1.113730.3"},
53                 {.id=0x00000015, .oid_prefix="0.9.2342.19200300.100.1"},
54                 {.id=0x00000016, .oid_prefix="2.16.840.1.113730.3.1"},
55                 {.id=0x00000017, .oid_prefix="1.2.840.113556.1.5.7000"},
56                 {.id=0x00000018, .oid_prefix="2.5.21"},
57                 {.id=0x00000019, .oid_prefix="2.5.18"},
58                 {.id=0x0000001A, .oid_prefix="2.5.20"},
59         };
60
61         /* allocate mem for prefix map */
62         pfm = talloc_zero(mem_ctx, struct dsdb_schema_prefixmap);
63         W_ERROR_HAVE_NO_MEMORY(pfm);
64
65         pfm->length = ARRAY_SIZE(pfm_init_data);
66         pfm->prefixes = talloc_array(pfm, struct dsdb_schema_prefixmap_oid, pfm->length);
67         W_ERROR_HAVE_NO_MEMORY(pfm->prefixes);
68
69         /* build prefixes */
70         for (i = 0; i < pfm->length; i++) {
71                 if (!ber_write_partial_OID_String(pfm, &pfm->prefixes[i].bin_oid, pfm_init_data[i].oid_prefix)) {
72                         talloc_free(pfm);
73                         return WERR_INTERNAL_ERROR;
74                 }
75                 pfm->prefixes[i].id = pfm_init_data[i].id;
76         }
77
78         *ppfm = pfm;
79
80         return WERR_OK;
81 }
82
83
84 /**
85  * Adds oid to prefix map.
86  * On success returns ID for newly added index
87  * or ID of existing entry that matches oid
88  * Reference: [MS-DRSR] section 5.12.2
89  *
90  * \param pfm prefixMap
91  * \param bin_oid OID prefix to be added to prefixMap
92  * \param pfm_id Location where to store prefixMap entry ID
93  */
94 static WERROR _dsdb_schema_pfm_add_entry(struct dsdb_schema_prefixmap *pfm, DATA_BLOB bin_oid, uint32_t *_idx)
95 {
96         uint32_t i;
97         struct dsdb_schema_prefixmap_oid * pfm_entry;
98         struct dsdb_schema_prefixmap_oid * prefixes_new;
99
100         /* dup memory for bin-oid prefix to be added */
101         bin_oid = data_blob_dup_talloc(pfm, &bin_oid);
102         if (!bin_oid.data) {
103                 return WERR_NOMEM;
104         }
105
106         /* make room for new entry */
107         prefixes_new = talloc_realloc(pfm, pfm->prefixes, struct dsdb_schema_prefixmap_oid, pfm->length + 1);
108         if (!prefixes_new) {
109                 talloc_free(bin_oid.data);
110                 return WERR_NOMEM;
111         }
112         pfm->prefixes = prefixes_new;
113
114         /* make new unique ID in prefixMap */
115         pfm_entry = &pfm->prefixes[pfm->length];
116         pfm_entry->id = 0;
117         for (i = 0; i < pfm->length; i++) {
118                 if (pfm_entry->id < pfm->prefixes[i].id)
119                         pfm_entry->id = pfm->prefixes[i].id;
120         }
121
122         /* add new bin-oid prefix */
123         pfm_entry->id++;
124         pfm_entry->bin_oid = bin_oid;
125
126         *_idx = pfm->length;
127         pfm->length++;
128
129         return WERR_OK;
130 }
131
132
133 /**
134  * Make partial binary OID for supplied OID.
135  * Reference: [MS-DRSR] section 5.12.2
136  */
137 static WERROR _dsdb_pfm_make_binary_oid(const char *full_oid, TALLOC_CTX *mem_ctx,
138                                         DATA_BLOB *_bin_oid, uint32_t *_last_subid)
139 {
140         uint32_t last_subid;
141         const char *oid_subid;
142
143         /* make last sub-identifier value */
144         oid_subid = strrchr(full_oid, '.');
145         if (!oid_subid) {
146                 return WERR_INVALID_PARAMETER;
147         }
148         oid_subid++;
149         last_subid = strtoul(oid_subid, NULL, 10);
150
151         /* encode oid in BER format */
152         if (!ber_write_OID_String(mem_ctx, _bin_oid, full_oid)) {
153                 return WERR_INTERNAL_ERROR;
154         }
155
156         /* get the prefix of the OID */
157         if (last_subid < 128) {
158                 _bin_oid->length -= 1;
159         } else {
160                 _bin_oid->length -= 2;
161         }
162
163         /* return last_value if requested */
164         if (_last_subid) {
165                 *_last_subid = last_subid;
166         }
167
168         return WERR_OK;
169 }
170
171 /**
172  * Make ATTID for given OID
173  * Reference: [MS-DRSR] section 5.12.2
174  */
175 WERROR dsdb_schema_pfm_make_attid(struct dsdb_schema_prefixmap *pfm, const char *oid, uint32_t *attid)
176 {
177         WERROR werr;
178         uint32_t i;
179         uint32_t lo_word, hi_word;
180         uint32_t last_value;
181         DATA_BLOB bin_oid;
182         struct dsdb_schema_prefixmap_oid *pfm_entry;
183
184         if (!pfm) {
185                 return WERR_INVALID_PARAMETER;
186         }
187         if (!oid) {
188                 return WERR_INVALID_PARAMETER;
189         }
190
191         werr = _dsdb_pfm_make_binary_oid(oid, pfm, &bin_oid, &last_value);
192         W_ERROR_NOT_OK_RETURN(werr);
193
194         /* search the prefix in the prefix table, if none found, add
195          * one entry for new prefix.
196          */
197         pfm_entry = NULL;
198         for (i = 0; i < pfm->length; i++) {
199                 if (pfm->prefixes[i].bin_oid.length != bin_oid.length)
200                         continue;
201
202                 if (memcmp(pfm->prefixes[i].bin_oid.data, bin_oid.data, bin_oid.length) == 0) {
203                         pfm_entry = &pfm->prefixes[i];
204                         break;
205                 }
206         }
207         /* add entry in no entry exists */
208         if (!pfm_entry) {
209                 uint32_t idx;
210                 werr = _dsdb_schema_pfm_add_entry(pfm, bin_oid, &idx);
211                 W_ERROR_NOT_OK_RETURN(werr);
212
213                 pfm_entry = &pfm->prefixes[idx];
214         } else {
215                 /* free memory allocated for bin_oid */
216                 data_blob_free(&bin_oid);
217         }
218
219         /* compose the attid */
220         lo_word = last_value % 16384;   /* actually get lower 14 bits: lo_word & 0x3FFF */
221         if (last_value >= 16384) {
222                 /* mark it so that it is known to not be the whole lastValue
223                  * This will raise 16-th bit*/
224                 lo_word += 32768;
225         }
226         hi_word = pfm_entry->id;
227
228         /* make ATTID:
229          * HIWORD is prefixMap id
230          * LOWORD is truncated binary-oid */
231         *attid = (hi_word * 65536) + lo_word;
232
233         return WERR_OK;
234 }
235
236
237 /**
238  * Make OID for given ATTID.
239  * Reference: [MS-DRSR] section 5.12.2
240  */
241 WERROR dsdb_schema_pfm_oid_from_attid(struct dsdb_schema_prefixmap *pfm, uint32_t attid,
242                                       TALLOC_CTX *mem_ctx, const char **_oid)
243 {
244         int i;
245         uint32_t hi_word, lo_word;
246         DATA_BLOB bin_oid = {NULL, 0};
247         struct dsdb_schema_prefixmap_oid *pfm_entry;
248         WERROR werr = WERR_OK;
249
250         /* crack attid value */
251         hi_word = attid >> 16;
252         lo_word = attid & 0xFFFF;
253
254         /* locate corRespoNding prefixMap entry */
255         pfm_entry = NULL;
256         for (i = 0; i < pfm->length; i++) {
257                 if (hi_word == pfm->prefixes[i].id) {
258                         pfm_entry = &pfm->prefixes[i];
259                         break;
260                 }
261         }
262
263         if (!pfm_entry) {
264                 return WERR_INTERNAL_ERROR;
265         }
266
267         /* copy oid prefix making enough room */
268         bin_oid.length = pfm_entry->bin_oid.length + 2;
269         bin_oid.data = talloc_array(mem_ctx, uint8_t, bin_oid.length);
270         W_ERROR_HAVE_NO_MEMORY(bin_oid.data);
271         memcpy(bin_oid.data, pfm_entry->bin_oid.data, pfm_entry->bin_oid.length);
272
273         if (lo_word < 128) {
274                 bin_oid.length = bin_oid.length - 1;
275                 bin_oid.data[bin_oid.length-1] = lo_word;
276         }
277         else {
278                 if (lo_word >= 32768) {
279                         lo_word -= 32768;
280                 }
281                 bin_oid.data[bin_oid.length-2] = (0x80 | ((lo_word>>7) & 0x7f));
282                 bin_oid.data[bin_oid.length-1] = lo_word & 0x7f;
283         }
284
285         if (!ber_read_OID_String(mem_ctx, bin_oid, _oid)) {
286                 werr = WERR_INTERNAL_ERROR;
287         }
288
289         /* free locally allocated memory */
290         talloc_free(bin_oid.data);
291
292         return werr;
293 }
294