s4-dsdb: Improve logging for drs_ObjectIdentifier_to_dn_and_nc_root()
[metze/samba-autobuild/.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\n",
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 for debugging
363  *
364  * When forming a DN for DB access you must use drs_ObjectIdentifier_to_dn()
365  */
366 char *drs_ObjectIdentifier_to_debug_string(TALLOC_CTX *mem_ctx,
367                                            struct drsuapi_DsReplicaObjectIdentifier *nc)
368 {
369         char *ret = NULL;
370         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
371         if (!GUID_all_zero(&nc->guid)) {
372                 char *guid = GUID_string(tmp_ctx, &nc->guid);
373                 if (guid) {
374                         ret = talloc_asprintf_append(ret, "<GUID=%s>;", guid);
375                 }
376         }
377         if (nc->__ndr_size_sid != 0 && nc->sid.sid_rev_num != 0) {
378                 const char *sid = dom_sid_string(tmp_ctx, &nc->sid);
379                 if (sid) {
380                         ret = talloc_asprintf_append(ret, "<SID=%s>;", sid);
381                 }
382         }
383         if (nc->__ndr_size_dn != 0 && nc->dn) {
384                 ret = talloc_asprintf_append(ret, "%s", nc->dn);
385         }
386         talloc_free(tmp_ctx);
387         talloc_steal(mem_ctx, ret);
388         return ret;
389 }
390
391 /*
392  * Safely convert a drsuapi_DsReplicaObjectIdentifier into an LDB DN
393  *
394  * We need to have GUID and SID priority and not allow extended
395  * components in the DN.
396  *
397  * We must also totally honour the priority even if the string DN is not valid or able to parse as a DN.
398  */
399 static struct ldb_dn *drs_ObjectIdentifier_to_dn(TALLOC_CTX *mem_ctx,
400                                                  struct ldb_context *ldb,
401                                                  struct drsuapi_DsReplicaObjectIdentifier *nc)
402 {
403         struct ldb_dn *new_dn = NULL;
404
405         if (!GUID_all_zero(&nc->guid)) {
406                 struct GUID_txt_buf buf;
407                 char *guid = GUID_buf_string(&nc->guid, &buf);
408
409                 new_dn = ldb_dn_new_fmt(mem_ctx,
410                                         ldb,
411                                         "<GUID=%s>",
412                                         guid);
413                 if (new_dn == NULL) {
414                         DBG_ERR("Failed to prepare drs_ObjectIdentifier "
415                                 "GUID %s into a DN\n",
416                                 guid);
417                         return NULL;
418                 }
419
420                 return new_dn;
421         }
422
423         if (nc->__ndr_size_sid != 0 && nc->sid.sid_rev_num != 0) {
424                 struct dom_sid_buf buf;
425                 char *sid = dom_sid_str_buf(&nc->sid, &buf);
426
427                 new_dn = ldb_dn_new_fmt(mem_ctx,
428                                         ldb,
429                                         "<SID=%s>",
430                                         sid);
431                 if (new_dn == NULL) {
432                         DBG_ERR("Failed to prepare drs_ObjectIdentifier "
433                                 "SID %s into a DN\n",
434                                 sid);
435                         return NULL;
436                 }
437                 return new_dn;
438         }
439
440         if (nc->__ndr_size_dn != 0 && nc->dn) {
441                 int dn_comp_num = 0;
442                 bool new_dn_valid = false;
443
444                 new_dn = ldb_dn_new(mem_ctx, ldb, nc->dn);
445                 if (new_dn == NULL) {
446                         /* Set to WARNING as this is user-controlled, don't print the value into the logs */
447                         DBG_WARNING("Failed to parse string DN in "
448                                     "drs_ObjectIdentifier into an LDB DN\n");
449                         return NULL;
450                 }
451
452                 new_dn_valid = ldb_dn_validate(new_dn);
453                 if (!new_dn_valid) {
454                         /*
455                          * Set to WARNING as this is user-controlled,
456                          * but can print the value into the logs as it
457                          * parsed a bit
458                          */
459                         DBG_WARNING("Failed to validate string DN [%s] in "
460                                     "drs_ObjectIdentifier as an LDB DN\n",
461                                     ldb_dn_get_linearized(new_dn));
462                         return NULL;
463                 }
464
465                 dn_comp_num = ldb_dn_get_comp_num(new_dn);
466                 if (dn_comp_num <= 0) {
467                         /*
468                          * Set to WARNING as this is user-controlled,
469                          * but can print the value into the logs as it
470                          * parsed a bit
471                          */
472                         DBG_WARNING("DN [%s] in drs_ObjectIdentifier "
473                                     "must have 1 or more components\n",
474                                     ldb_dn_get_linearized(new_dn));
475                         return NULL;
476                 }
477
478                 if (ldb_dn_is_special(new_dn)) {
479                         /*
480                          * Set to WARNING as this is user-controlled,
481                          * but can print the value into the logs as it
482                          * parsed a bit
483                          */
484                         DBG_WARNING("New string DN [%s] in "
485                                     "drs_ObjectIdentifier is a "
486                                     "special LDB DN\n",
487                                     ldb_dn_get_linearized(new_dn));
488                         return NULL;
489                 }
490
491                 /*
492                  * We want this just to be a string DN, extended
493                  * components are manually handled above
494                  */
495                 if (ldb_dn_has_extended(new_dn)) {
496                         /*
497                          * Set to WARNING as this is user-controlled,
498                          * but can print the value into the logs as it
499                          * parsed a bit
500                          */
501                         DBG_WARNING("Refusing to parse New string DN [%s] in "
502                                     "drs_ObjectIdentifier as an "
503                                     "extended LDB DN "
504                                     "(GUIDs and SIDs should be in the "
505                                     ".guid and .sid IDL elements, "
506                                     "not in the string\n",
507                                     ldb_dn_get_extended_linearized(mem_ctx,
508                                                                    new_dn,
509                                                                    1));
510                         return NULL;
511                 }
512                 return new_dn;
513         }
514
515         DBG_WARNING("Refusing to parse empty string DN "
516                     "(and no GUID or SID) "
517                     "drs_ObjectIdentifier into a empty "
518                     "(eg RootDSE) LDB DN\n");
519         return NULL;
520 }
521
522 /*
523  * Safely convert a drsuapi_DsReplicaObjectIdentifier into a validated
524  * LDB DN of an existing DB entry, and/or find the NC root
525  *
526  * We need to have GUID and SID priority and not allow extended
527  * components in the DN.
528  *
529  * We must also totally honour the priority even if the string DN is
530  * not valid or able to parse as a DN.
531  *
532  * Finally, we must return the DN as found in the DB, as otherwise a
533  * subsequence ldb_dn_compare(dn, nc_root) will fail (as this is based
534  * on the string components).
535  */
536 int drs_ObjectIdentifier_to_dn_and_nc_root(TALLOC_CTX *mem_ctx,
537                                            struct ldb_context *ldb,
538                                            struct drsuapi_DsReplicaObjectIdentifier *nc,
539                                            struct ldb_dn **normalised_dn,
540                                            struct ldb_dn **nc_root)
541 {
542         int ret;
543         struct ldb_dn *new_dn = NULL;
544
545         new_dn = drs_ObjectIdentifier_to_dn(mem_ctx,
546                                             ldb,
547                                             nc);
548         if (new_dn == NULL) {
549                 return LDB_ERR_INVALID_DN_SYNTAX;
550         }
551
552         ret = dsdb_normalise_dn_and_find_nc_root(ldb,
553                                                  mem_ctx,
554                                                  new_dn,
555                                                  normalised_dn,
556                                                  nc_root);
557         if (ret != LDB_SUCCESS) {
558                 /*
559                  * dsdb_normalise_dn_and_find_nc_root() sets LDB error
560                  * strings, and the functions it calls do also
561                  */
562                 DBG_NOTICE("Failed to find DN \"%s\" -> \"%s\" for normalisation: %s (%s)\n",
563                            drs_ObjectIdentifier_to_debug_string(mem_ctx, nc),
564                            ldb_dn_get_extended_linearized(mem_ctx, new_dn, 1),
565                            ldb_errstring(ldb),
566                            ldb_strerror(ret));
567         }
568
569         TALLOC_FREE(new_dn);
570         return ret;
571 }