s4-dsdb: rework drs_ObjectIdentifier_to_dn() into drs_ObjectIdentifier_to_dn_and_nc_r...
[samba.git] / source4 / dsdb / common / dsdb_dn.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba utility functions
4
5    Copyright (C) Andrew Tridgell 2009
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 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 <ldb_module.h>
25 #include "librpc/ndr/libndr.h"
26 #include "libcli/security/dom_sid.h"
27 #include "lib/util/smb_strtox.h"
28
29 enum dsdb_dn_format dsdb_dn_oid_to_format(const char *oid) 
30 {
31         if (strcmp(oid, LDB_SYNTAX_DN) == 0) {
32                 return DSDB_NORMAL_DN;
33         } else if (strcmp(oid, DSDB_SYNTAX_BINARY_DN) == 0) {
34                 return DSDB_BINARY_DN;
35         } else if (strcmp(oid, DSDB_SYNTAX_STRING_DN) == 0) {
36                 return DSDB_STRING_DN;
37         } else if (strcmp(oid, DSDB_SYNTAX_OR_NAME) == 0) {
38                 return DSDB_NORMAL_DN;
39         } else {
40                 return DSDB_INVALID_DN;
41         }
42 }
43
44 static struct dsdb_dn *dsdb_dn_construct_internal(TALLOC_CTX *mem_ctx, 
45                                                   struct ldb_dn *dn, 
46                                                   DATA_BLOB extra_part, 
47                                                   enum dsdb_dn_format dn_format, 
48                                                   const char *oid) 
49 {
50         struct dsdb_dn *dsdb_dn = NULL;
51
52         switch (dn_format) {
53         case DSDB_BINARY_DN:
54         case DSDB_STRING_DN:
55                 break;
56         case DSDB_NORMAL_DN:
57                 if (extra_part.length != 0) {
58                         errno = EINVAL;
59                         return NULL;
60                 }
61                 break;
62         case DSDB_INVALID_DN:
63         default:
64                 errno = EINVAL;
65                 return NULL;
66         }
67
68         dsdb_dn = talloc(mem_ctx, struct dsdb_dn);
69         if (!dsdb_dn) {
70                 errno = ENOMEM;
71                 return NULL;
72         }
73         dsdb_dn->dn = talloc_steal(dsdb_dn, dn);
74         dsdb_dn->extra_part = extra_part;
75         dsdb_dn->dn_format = dn_format;
76
77         dsdb_dn->oid = oid;
78         talloc_steal(dsdb_dn, extra_part.data);
79         return dsdb_dn;
80 }
81
82 struct dsdb_dn *dsdb_dn_construct(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, DATA_BLOB extra_part, 
83                                   const char *oid) 
84 {
85         enum dsdb_dn_format dn_format = dsdb_dn_oid_to_format(oid);
86         return dsdb_dn_construct_internal(mem_ctx, dn, extra_part, dn_format, oid);
87 }
88
89 struct dsdb_dn *dsdb_dn_parse_trusted(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, 
90                                       const struct ldb_val *dn_blob, const char *dn_oid)
91 {
92         struct dsdb_dn *dsdb_dn;
93         struct ldb_dn *dn;
94         size_t len;
95         TALLOC_CTX *tmp_ctx;
96         char *p1;
97         char *p2;
98         uint32_t blen;
99         struct ldb_val bval;
100         struct ldb_val dval;
101         char *dn_str;
102         int error = 0;
103
104         enum dsdb_dn_format dn_format = dsdb_dn_oid_to_format(dn_oid);
105
106         if (dn_blob == NULL || dn_blob->data == NULL || dn_blob->length == 0) {
107                 return NULL;
108         }
109
110         switch (dn_format) {
111         case DSDB_INVALID_DN:
112                 return NULL;
113         case DSDB_NORMAL_DN:
114         {
115                 dn = ldb_dn_from_ldb_val(mem_ctx, ldb, dn_blob);
116                 if (!dn) {
117                         talloc_free(dn);
118                         return NULL;
119                 }
120                 return dsdb_dn_construct_internal(mem_ctx, dn, data_blob_null, dn_format, dn_oid);
121         }
122         case DSDB_BINARY_DN:
123                 if (dn_blob->length < 2 || dn_blob->data[0] != 'B' || dn_blob->data[1] != ':') {
124                         return NULL;
125                 }
126                 break;
127         case DSDB_STRING_DN:
128                 if (dn_blob->length < 2 || dn_blob->data[0] != 'S' || dn_blob->data[1] != ':') {
129                         return NULL;
130                 }
131                 break;
132         default:
133                 return NULL;
134         }
135
136         if (strlen((const char*)dn_blob->data) != dn_blob->length) {
137                 /* The RDN must not contain a character with value 0x0 */
138                 return NULL;
139         }
140
141         tmp_ctx = talloc_new(mem_ctx);
142         if (tmp_ctx == NULL) {
143                 return NULL;
144         }
145
146         len = dn_blob->length - 2;
147         p1 = talloc_strndup(tmp_ctx, (const char *)dn_blob->data + 2, len);
148         if (!p1) {
149                 goto failed;
150         }
151
152         errno = 0;
153         blen = smb_strtoul(p1, &p2, 10, &error, SMB_STR_STANDARD);
154         if (error != 0) {
155                 DEBUG(10, (__location__ ": failed\n"));
156                 goto failed;
157         }
158         if (p2 == NULL) {
159                 DEBUG(10, (__location__ ": failed\n"));
160                 goto failed;
161         }
162         if (p2[0] != ':') {
163                 DEBUG(10, (__location__ ": failed\n"));
164                 goto failed;
165         }
166         len -= PTR_DIFF(p2,p1);//???
167         p1 = p2+1;
168         len--;
169                 
170         if (blen >= len) {
171                 DEBUG(10, (__location__ ": blen=%u len=%u\n", (unsigned)blen, (unsigned)len));
172                 goto failed;
173         }
174                 
175         p2 = p1 + blen;
176         if (p2[0] != ':') {
177                 DEBUG(10, (__location__ ": %s", p2));
178                 goto failed;
179         }
180         dn_str = p2+1;
181                 
182                 
183         switch (dn_format) {
184         case DSDB_BINARY_DN:
185                 if ((blen % 2 != 0)) {
186                         DEBUG(10, (__location__ ": blen=%u - not an even number\n", (unsigned)blen));
187                         goto failed;
188                 }
189                 
190                 if (blen >= 2) {
191                         bval.length = (blen/2)+1;
192                         bval.data = talloc_size(tmp_ctx, bval.length);
193                         if (bval.data == NULL) {
194                                 DEBUG(10, (__location__ ": err\n"));
195                                 goto failed;
196                         }
197                         bval.data[bval.length-1] = 0;
198                 
199                         bval.length = strhex_to_str((char *)bval.data, bval.length,
200                                                     p1, blen);
201                         if (bval.length != (blen / 2)) {
202                                 DEBUG(10, (__location__ ": non hexadecimal characters found in binary prefix\n"));
203                                 goto failed;
204                         }
205                 } else {
206                         bval = data_blob_null;
207                 }
208
209                 break;
210         case DSDB_STRING_DN:
211                 bval = data_blob(p1, blen);
212                 break;
213         default:
214                 /* never reached */
215                 return NULL;
216         }
217         
218
219         dval.data = (uint8_t *)dn_str;
220         dval.length = strlen(dn_str);
221                 
222         dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &dval);
223         if (!dn) {
224                 DEBUG(10, (__location__ ": err\n"));
225                 goto failed;
226         }
227                 
228         dsdb_dn = dsdb_dn_construct(mem_ctx, dn, bval, dn_oid);
229                 
230         talloc_free(tmp_ctx);
231         return dsdb_dn;
232
233 failed:
234         talloc_free(tmp_ctx);
235         return NULL;
236 }
237
238 struct dsdb_dn *dsdb_dn_parse(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, 
239                               const struct ldb_val *dn_blob, const char *dn_oid)
240 {
241         struct dsdb_dn *dsdb_dn = dsdb_dn_parse_trusted(mem_ctx, ldb,
242                                                         dn_blob, dn_oid);
243         if (dsdb_dn == NULL) {
244                 return NULL;
245         }
246         if (ldb_dn_validate(dsdb_dn->dn) == false) {
247                 DEBUG(10, ("could not parse %.*s as a %s DN",
248                            (int)dn_blob->length, dn_blob->data,
249                            dn_oid));
250                 return NULL;
251         }
252         return dsdb_dn;
253 }
254
255 static char *dsdb_dn_get_with_postfix(TALLOC_CTX *mem_ctx, 
256                                      struct dsdb_dn *dsdb_dn,
257                                      const char *postfix)
258 {
259         if (!postfix) {
260                 return NULL;
261         }
262
263         switch (dsdb_dn->dn_format) {
264         case DSDB_NORMAL_DN:
265         {
266                 return talloc_strdup(mem_ctx, postfix);
267         }
268         case DSDB_BINARY_DN:
269         {
270                 char *hexstr = data_blob_hex_string_upper(mem_ctx, &dsdb_dn->extra_part);
271         
272                 char *p = talloc_asprintf(mem_ctx, "B:%u:%s:%s", (unsigned)(dsdb_dn->extra_part.length*2), hexstr, 
273                                           postfix);
274                 talloc_free(hexstr);
275                 return p;
276         }
277         case DSDB_STRING_DN:
278         {
279                 return talloc_asprintf(mem_ctx, "S:%u:%*.*s:%s", 
280                                     (unsigned)(dsdb_dn->extra_part.length), 
281                                     (int)(dsdb_dn->extra_part.length), 
282                                     (int)(dsdb_dn->extra_part.length), 
283                                     (const char *)dsdb_dn->extra_part.data, 
284                                     postfix);
285         }
286         default:
287                 return NULL;
288         }
289 }
290
291 char *dsdb_dn_get_linearized(TALLOC_CTX *mem_ctx, 
292                               struct dsdb_dn *dsdb_dn)
293 {
294         const char *postfix = ldb_dn_get_linearized(dsdb_dn->dn);
295         return dsdb_dn_get_with_postfix(mem_ctx, dsdb_dn, postfix);
296 }
297
298 char *dsdb_dn_get_casefold(TALLOC_CTX *mem_ctx, 
299                            struct dsdb_dn *dsdb_dn) 
300 {
301         const char *postfix = ldb_dn_get_casefold(dsdb_dn->dn);
302         return dsdb_dn_get_with_postfix(mem_ctx, dsdb_dn, postfix);
303 }
304
305 char *dsdb_dn_get_extended_linearized(TALLOC_CTX *mem_ctx, 
306                                       struct dsdb_dn *dsdb_dn,
307                                       int mode)
308 {
309         char *postfix = ldb_dn_get_extended_linearized(mem_ctx, dsdb_dn->dn, mode);
310         char *ret = dsdb_dn_get_with_postfix(mem_ctx, dsdb_dn, postfix);
311         talloc_free(postfix);
312         return ret;
313 }
314
315 int dsdb_dn_binary_canonicalise(struct ldb_context *ldb, void *mem_ctx,
316                                 const struct ldb_val *in, struct ldb_val *out)
317 {
318         struct dsdb_dn *dsdb_dn = dsdb_dn_parse(mem_ctx, ldb, in, DSDB_SYNTAX_BINARY_DN);
319         
320         if (!dsdb_dn) {
321                 return -1;
322         }
323         *out = data_blob_string_const(dsdb_dn_get_casefold(mem_ctx, dsdb_dn));
324         talloc_free(dsdb_dn);
325         if (!out->data) {
326                 return -1;
327         }
328         return 0;
329 }
330
331 int dsdb_dn_binary_comparison(struct ldb_context *ldb, void *mem_ctx,
332                                      const struct ldb_val *v1,
333                                      const struct ldb_val *v2)
334 {
335         return ldb_any_comparison(ldb, mem_ctx, dsdb_dn_binary_canonicalise, v1, v2);
336 }
337
338 int dsdb_dn_string_canonicalise(struct ldb_context *ldb, void *mem_ctx,
339                                 const struct ldb_val *in, struct ldb_val *out)
340 {
341         struct dsdb_dn *dsdb_dn = dsdb_dn_parse(mem_ctx, ldb, in, DSDB_SYNTAX_STRING_DN);
342         
343         if (!dsdb_dn) {
344                 return -1;
345         }
346         *out = data_blob_string_const(dsdb_dn_get_casefold(mem_ctx, dsdb_dn));
347         talloc_free(dsdb_dn);
348         if (!out->data) {
349                 return -1;
350         }
351         return 0;
352 }
353
354 int dsdb_dn_string_comparison(struct ldb_context *ldb, void *mem_ctx,
355                                      const struct ldb_val *v1,
356                                      const struct ldb_val *v2)
357 {
358         return ldb_any_comparison(ldb, mem_ctx, dsdb_dn_string_canonicalise, v1, v2);
359 }
360
361 /*
362   format a drsuapi_DsReplicaObjectIdentifier naming context as a string
363  */
364 char *drs_ObjectIdentifier_to_string(TALLOC_CTX *mem_ctx,
365                                      struct drsuapi_DsReplicaObjectIdentifier *nc)
366 {
367         char *ret = NULL;
368         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
369         if (!GUID_all_zero(&nc->guid)) {
370                 char *guid = GUID_string(tmp_ctx, &nc->guid);
371                 if (guid) {
372                         ret = talloc_asprintf_append(ret, "<GUID=%s>;", guid);
373                 }
374         }
375         if (nc->__ndr_size_sid != 0 && nc->sid.sid_rev_num != 0) {
376                 const char *sid = dom_sid_string(tmp_ctx, &nc->sid);
377                 if (sid) {
378                         ret = talloc_asprintf_append(ret, "<SID=%s>;", sid);
379                 }
380         }
381         if (nc->__ndr_size_dn != 0 && nc->dn) {
382                 ret = talloc_asprintf_append(ret, "%s", nc->dn);
383         }
384         talloc_free(tmp_ctx);
385         talloc_steal(mem_ctx, ret);
386         return ret;
387 }
388
389 struct ldb_dn *drs_ObjectIdentifier_to_dn(TALLOC_CTX *mem_ctx,
390                                           struct ldb_context *ldb,
391                                           struct drsuapi_DsReplicaObjectIdentifier *nc)
392 {
393         char *dn_string = drs_ObjectIdentifier_to_string(mem_ctx, nc);
394         struct ldb_dn *new_dn;
395         new_dn = ldb_dn_new(mem_ctx, ldb, dn_string);
396         talloc_free(dn_string);
397         return new_dn;
398 }
399
400 /*
401  * Safely convert a drsuapi_DsReplicaObjectIdentifier into a validated
402  * LDB DN of an existing DB entry, and/or find the NC root
403  *
404  * Finally, we must return the DN as found in the DB, as otherwise a
405  * subsequence ldb_dn_compare(dn, nc_root) will fail (as this is based
406  * on the string components).
407  */
408 int drs_ObjectIdentifier_to_dn_and_nc_root(TALLOC_CTX *mem_ctx,
409                                            struct ldb_context *ldb,
410                                            struct drsuapi_DsReplicaObjectIdentifier *nc,
411                                            struct ldb_dn **normalised_dn,
412                                            struct ldb_dn **nc_root)
413 {
414         int ret;
415         struct ldb_dn *new_dn = NULL;
416
417         new_dn = drs_ObjectIdentifier_to_dn(mem_ctx,
418                                             ldb,
419                                             nc);
420         if (new_dn == NULL) {
421                 return LDB_ERR_INVALID_DN_SYNTAX;
422         }
423
424         ret = dsdb_normalise_dn_and_find_nc_root(ldb,
425                                                  mem_ctx,
426                                                  new_dn,
427                                                  normalised_dn,
428                                                  nc_root);
429         TALLOC_FREE(new_dn);
430         return ret;
431 }