b20aecef686d61f4be15f8bd7b6b353d31383633
[abartlet/samba.git/.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  * Lookup partial-binary-oid in prefixMap
173  */
174 WERROR dsdb_schema_pfm_find_binary_oid(struct dsdb_schema_prefixmap *pfm,
175                                        DATA_BLOB bin_oid,
176                                        uint32_t *_idx)
177 {
178         uint32_t i;
179
180         for (i = 0; i < pfm->length; i++) {
181                 if (pfm->prefixes[i].bin_oid.length != bin_oid.length) {
182                         continue;
183                 }
184
185                 if (memcmp(pfm->prefixes[i].bin_oid.data, bin_oid.data, bin_oid.length) == 0) {
186                         if (_idx) {
187                                 *_idx = i;
188                         }
189                         return WERR_OK;
190                 }
191         }
192
193         return WERR_DS_NO_MSDS_INTID;
194 }
195
196 /**
197  * Make ATTID for given OID
198  * Reference: [MS-DRSR] section 5.12.2
199  */
200 WERROR dsdb_schema_pfm_make_attid(struct dsdb_schema_prefixmap *pfm, const char *oid, uint32_t *attid)
201 {
202         WERROR werr;
203         uint32_t idx;
204         uint32_t lo_word, hi_word;
205         uint32_t last_subid;
206         DATA_BLOB bin_oid;
207
208         if (!pfm) {
209                 return WERR_INVALID_PARAMETER;
210         }
211         if (!oid) {
212                 return WERR_INVALID_PARAMETER;
213         }
214
215         werr = _dsdb_pfm_make_binary_oid(oid, pfm, &bin_oid, &last_subid);
216         W_ERROR_NOT_OK_RETURN(werr);
217
218         /* search the prefix in the prefix table, if none found, add
219          * one entry for new prefix.
220          */
221         werr = dsdb_schema_pfm_find_binary_oid(pfm, bin_oid, &idx);
222         if (W_ERROR_IS_OK(werr)) {
223                 /* free memory allocated for bin_oid */
224                 data_blob_free(&bin_oid);
225         } else {
226                 /* entry does not exists, add it */
227                 werr = _dsdb_schema_pfm_add_entry(pfm, bin_oid, &idx);
228                 W_ERROR_NOT_OK_RETURN(werr);
229         }
230
231         /* compose the attid */
232         lo_word = last_subid % 16384;   /* actually get lower 14 bits: lo_word & 0x3FFF */
233         if (last_subid >= 16384) {
234                 /* mark it so that it is known to not be the whole lastValue
235                  * This will raise 16-th bit*/
236                 lo_word += 32768;
237         }
238         hi_word = pfm->prefixes[idx].id;
239
240         /* make ATTID:
241          * HIWORD is prefixMap id
242          * LOWORD is truncated binary-oid */
243         *attid = (hi_word * 65536) + lo_word;
244
245         return WERR_OK;
246 }
247
248
249 /**
250  * Make OID for given ATTID.
251  * Reference: [MS-DRSR] section 5.12.2
252  */
253 WERROR dsdb_schema_pfm_oid_from_attid(struct dsdb_schema_prefixmap *pfm, uint32_t attid,
254                                       TALLOC_CTX *mem_ctx, const char **_oid)
255 {
256         int i;
257         uint32_t hi_word, lo_word;
258         DATA_BLOB bin_oid = {NULL, 0};
259         struct dsdb_schema_prefixmap_oid *pfm_entry;
260         WERROR werr = WERR_OK;
261
262         /* crack attid value */
263         hi_word = attid >> 16;
264         lo_word = attid & 0xFFFF;
265
266         /* locate corRespoNding prefixMap entry */
267         pfm_entry = NULL;
268         for (i = 0; i < pfm->length; i++) {
269                 if (hi_word == pfm->prefixes[i].id) {
270                         pfm_entry = &pfm->prefixes[i];
271                         break;
272                 }
273         }
274
275         if (!pfm_entry) {
276                 return WERR_INTERNAL_ERROR;
277         }
278
279         /* copy oid prefix making enough room */
280         bin_oid.length = pfm_entry->bin_oid.length + 2;
281         bin_oid.data = talloc_array(mem_ctx, uint8_t, bin_oid.length);
282         W_ERROR_HAVE_NO_MEMORY(bin_oid.data);
283         memcpy(bin_oid.data, pfm_entry->bin_oid.data, pfm_entry->bin_oid.length);
284
285         if (lo_word < 128) {
286                 bin_oid.length = bin_oid.length - 1;
287                 bin_oid.data[bin_oid.length-1] = lo_word;
288         }
289         else {
290                 if (lo_word >= 32768) {
291                         lo_word -= 32768;
292                 }
293                 bin_oid.data[bin_oid.length-2] = (0x80 | ((lo_word>>7) & 0x7f));
294                 bin_oid.data[bin_oid.length-1] = lo_word & 0x7f;
295         }
296
297         if (!ber_read_OID_String(mem_ctx, bin_oid, _oid)) {
298                 werr = WERR_INTERNAL_ERROR;
299         }
300
301         /* free locally allocated memory */
302         talloc_free(bin_oid.data);
303
304         return werr;
305 }
306