Initial Implementation of the DS objects access checks.
[sfrench/samba-autobuild/.git] / source4 / lib / ldb / common / ldb_dn.c
1 /*
2    ldb database library
3
4    Copyright (C) Simo Sorce 2005
5
6      ** NOTE! The following LGPL license applies to the ldb
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Lesser General Public
12    License as published by the Free Software Foundation; either
13    version 3 of the License, or (at your option) any later version.
14
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Lesser General Public License for more details.
19
20    You should have received a copy of the GNU Lesser General Public
21    License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 */
23
24 /*
25  *  Name: ldb
26  *
27  *  Component: ldb dn creation and manipulation utility functions
28  *
29  *  Description: - explode a dn into it's own basic elements
30  *                 and put them in a structure (only if necessary)
31  *               - manipulate ldb_dn structures
32  *
33  *  Author: Simo Sorce
34  */
35
36 #include "ldb_private.h"
37 #include <ctype.h>
38
39 #define LDB_DN_NULL_FAILED(x) if (!(x)) goto failed
40
41 #define LDB_FREE(x) do { talloc_free(x); x = NULL; } while(0)
42
43 /**
44    internal ldb exploded dn structures
45 */
46 struct ldb_dn_component {
47
48         char *name;
49         struct ldb_val value;
50
51         char *cf_name;
52         struct ldb_val cf_value;
53 };
54
55 struct ldb_dn_ext_component {
56
57         char *name;
58         struct ldb_val value;
59 };
60
61 struct ldb_dn {
62
63         struct ldb_context *ldb;
64
65         /* Special DNs are always linearized */
66         bool special;
67         bool invalid;
68
69         bool valid_case;
70
71         char *linearized;
72         char *ext_linearized;
73         char *casefold;
74
75         unsigned int comp_num;
76         struct ldb_dn_component *components;
77
78         unsigned int ext_comp_num;
79         struct ldb_dn_ext_component *ext_components;
80 };
81
82 /* strdn may be NULL */
83 struct ldb_dn *ldb_dn_from_ldb_val(void *mem_ctx,
84                                    struct ldb_context *ldb,
85                                    const struct ldb_val *strdn)
86 {
87         struct ldb_dn *dn;
88
89         if (! ldb) return NULL;
90
91         dn = talloc_zero(mem_ctx, struct ldb_dn);
92         LDB_DN_NULL_FAILED(dn);
93
94         dn->ldb = ldb;
95
96         if (strdn->data && strdn->length) {
97                 const char *data = (const char *)strdn->data;
98                 size_t length = strdn->length;
99
100                 if (data[0] == '@') {
101                         dn->special = true;
102                 }
103                 dn->ext_linearized = talloc_strndup(dn, data, length);
104                 LDB_DN_NULL_FAILED(dn->ext_linearized);
105
106                 if (data[0] == '<') {
107                         const char *p_save, *p = dn->ext_linearized;
108                         do {
109                                 p_save = p;
110                                 p = strstr(p, ">;");
111                                 if (p) {
112                                         p = p + 2;
113                                 }
114                         } while (p);
115
116                         if (p_save == dn->ext_linearized) {
117                                 dn->linearized = talloc_strdup(dn, "");
118                         } else {
119                                 dn->linearized = talloc_strdup(dn, p_save);
120                         }
121                         LDB_DN_NULL_FAILED(dn->linearized);
122                 } else {
123                         dn->linearized = dn->ext_linearized;
124                         dn->ext_linearized = NULL;
125                 }
126         } else {
127                 dn->linearized = talloc_strdup(dn, "");
128                 LDB_DN_NULL_FAILED(dn->linearized);
129         }
130
131         return dn;
132
133 failed:
134         talloc_free(dn);
135         return NULL;
136 }
137
138 /* strdn may be NULL */
139 struct ldb_dn *ldb_dn_new(void *mem_ctx,
140                           struct ldb_context *ldb,
141                           const char *strdn)
142 {
143         struct ldb_val blob;
144         blob.data = strdn;
145         blob.length = strdn ? strlen(strdn) : 0;
146         return ldb_dn_from_ldb_val(mem_ctx, ldb, &blob);
147 }
148
149 struct ldb_dn *ldb_dn_new_fmt(void *mem_ctx,
150                               struct ldb_context *ldb,
151                               const char *new_fmt, ...)
152 {
153         char *strdn;
154         va_list ap;
155
156         if ( (! mem_ctx) || (! ldb)) return NULL;
157
158         va_start(ap, new_fmt);
159         strdn = talloc_vasprintf(mem_ctx, new_fmt, ap);
160         va_end(ap);
161
162         if (strdn) {
163                 struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb, strdn);
164                 talloc_free(strdn);
165                 return dn;
166         }
167
168         return NULL;
169 }
170
171 static int ldb_dn_escape_internal(char *dst, const char *src, int len)
172 {
173         const char *p, *s;
174         char *d;
175         int l;
176
177         p = s = src;
178         d = dst;
179
180         while (p - src < len) {
181
182                 p += strcspn(p, ",=\n+<>#;\\\"");
183
184                 if (p - src == len) /* found no escapable chars */
185                         break;
186
187                 /* copy the part of the string before the stop */
188                 memcpy(d, s, p - s);
189                 d += (p - s); /* move to current position */
190
191                 if (*p) { /* it is a normal escapable character */
192                         *d++ = '\\';
193                         *d++ = *p++;
194                 } else { /* we have a zero byte in the string */
195                         strncpy(d, "\00", 3); /* escape the zero */
196                         d += 3;
197                         p++; /* skip the zero */
198                 }
199                 s = p; /* move forward */
200         }
201
202         /* copy the last part (with zero) and return */
203         l = len - (s - src);
204         memcpy(d, s, l + 1);
205
206         /* return the length of the resulting string */
207         return (l + (d - dst));
208 }
209
210 char *ldb_dn_escape_value(void *mem_ctx, struct ldb_val value)
211 {
212         char *dst;
213
214         if (!value.length)
215                 return NULL;
216
217         /* allocate destination string, it will be at most 3 times the source */
218         dst = talloc_array(mem_ctx, char, value.length * 3 + 1);
219         if ( ! dst) {
220                 talloc_free(dst);
221                 return NULL;
222         }
223
224         ldb_dn_escape_internal(dst, (const char *)value.data, value.length);
225
226         dst = talloc_realloc(mem_ctx, dst, char, strlen(dst) + 1);
227
228         return dst;
229 }
230
231 /*
232   explode a DN string into a ldb_dn structure
233   based on RFC4514 except that we don't support multiple valued RDNs
234 */
235 static bool ldb_dn_explode(struct ldb_dn *dn)
236 {
237         char *p, *ex_name, *ex_value, *data, *d, *dt, *t;
238         bool trim = false;
239         bool in_extended = false;
240         bool in_ex_name = false;
241         bool in_ex_value = false;
242         bool in_attr = false;
243         bool in_value = false;
244         bool in_quote = false;
245         bool is_oid = false;
246         bool escape = false;
247         unsigned x;
248         int l, ret;
249         char *parse_dn;
250
251         if ( ! dn || dn->invalid) return false;
252
253         if (dn->components) {
254                 return true;
255         }
256
257         if (dn->ext_linearized) {
258                 parse_dn = dn->ext_linearized;
259         } else {
260                 parse_dn = dn->linearized;
261         }
262
263         if ( ! parse_dn ) {
264                 return false;
265         }
266
267         /* Empty DNs */
268         if (parse_dn[0] == '\0') {
269                 return true;
270         }
271
272         /* Special DNs case */
273         if (dn->special) {
274                 return true;
275         }
276
277         /* make sure we free this if alloced previously before replacing */
278         talloc_free(dn->components);
279
280         talloc_free(dn->ext_components);
281         dn->ext_components = NULL;
282
283         /* in the common case we have 3 or more components */
284         /* make sure all components are zeroed, other functions depend on it */
285         dn->components = talloc_zero_array(dn, struct ldb_dn_component, 3);
286         if ( ! dn->components) {
287                 return false;
288         }
289         dn->comp_num = 0;
290
291         /* Components data space is allocated here once */
292         data = talloc_array(dn->components, char, strlen(parse_dn) + 1);
293         if (!data) {
294                 return false;
295         }
296
297         p = parse_dn;
298         in_extended = true;
299         in_ex_name = false;
300         in_ex_value = false;
301         trim = true;
302         t = NULL;
303         d = dt = data;
304
305         while (*p) {
306                 if (in_extended) {
307
308                         if (!in_ex_name && !in_ex_value) {
309
310                                 if (p[0] == '<') {
311                                         p++;
312                                         ex_name = d;
313                                         in_ex_name = true;
314                                         continue;
315                                 } else if (p[0] == '\0') {
316                                         p++;
317                                         continue;
318                                 } else {
319                                         in_extended = false;
320                                         in_attr = true;
321                                         dt = d;
322
323                                         continue;
324                                 }
325                         }
326
327                         if (in_ex_name && *p == '=') {
328                                 *d++ = '\0';
329                                 p++;
330                                 ex_value = d;
331                                 in_ex_name = false;
332                                 in_ex_value = true;
333                                 continue;
334                         }
335
336                         if (in_ex_value && *p == '>') {
337                                 const struct ldb_dn_extended_syntax *ext_syntax;
338                                 struct ldb_val ex_val = {
339                                         .data = (uint8_t *)ex_value,
340                                         .length = d - ex_value
341                                 };
342
343                                 *d++ = '\0';
344                                 p++;
345                                 in_ex_value = false;
346
347                                 /* Process name and ex_value */
348
349                                 dn->ext_components = talloc_realloc(dn,
350                                                                     dn->ext_components,
351                                                                     struct ldb_dn_ext_component,
352                                                                     dn->ext_comp_num + 1);
353                                 if ( ! dn->ext_components) {
354                                         /* ouch ! */
355                                         goto failed;
356                                 }
357
358                                 ext_syntax = ldb_dn_extended_syntax_by_name(dn->ldb, ex_name);
359                                 if (!ext_syntax) {
360                                         /* We don't know about this type of extended DN */
361                                         goto failed;
362                                 }
363
364                                 dn->ext_components[dn->ext_comp_num].name = talloc_strdup(dn->ext_components, ex_name);
365                                 if (!dn->ext_components[dn->ext_comp_num].name) {
366                                         /* ouch */
367                                         goto failed;
368                                 }
369                                 ret = ext_syntax->read_fn(dn->ldb, dn->ext_components,
370                                                           &ex_val, &dn->ext_components[dn->ext_comp_num].value);
371                                 if (ret != LDB_SUCCESS) {
372                                         dn->invalid = true;
373                                         goto failed;
374                                 }
375
376                                 dn->ext_comp_num++;
377
378                                 if (*p == '\0') {
379                                         /* We have reached the end (extended component only)! */
380                                         talloc_free(data);
381                                         return true;
382
383                                 } else if (*p == ';') {
384                                         p++;
385                                         continue;
386                                 } else {
387                                         dn->invalid = true;
388                                         goto failed;
389                                 }
390                         }
391
392                         *d++ = *p++;
393                         continue;
394                 }
395                 if (in_attr) {
396                         if (trim) {
397                                 if (*p == ' ') {
398                                         p++;
399                                         continue;
400                                 }
401
402                                 /* first char */
403                                 trim = false;
404
405                                 if (!isascii(*p)) {
406                                         /* attr names must be ascii only */
407                                         dn->invalid = true;
408                                         goto failed;
409                                 }
410
411                                 if (isdigit(*p)) {
412                                         is_oid = true;
413                                 } else
414                                 if ( ! isalpha(*p)) {
415                                         /* not a digit nor an alpha,
416                                          * invalid attribute name */
417                                         dn->invalid = true;
418                                         goto failed;
419                                 }
420
421                                 /* Copy this character across from parse_dn,
422                                  * now we have trimmed out spaces */
423                                 *d++ = *p++;
424                                 continue;
425                         }
426
427                         if (*p == ' ') {
428                                 p++;
429                                 /* valid only if we are at the end */
430                                 trim = true;
431                                 continue;
432                         }
433
434                         if (trim && (*p != '=')) {
435                                 /* spaces/tabs are not allowed */
436                                 dn->invalid = true;
437                                 goto failed;
438                         }
439
440                         if (*p == '=') {
441                                 /* attribute terminated */
442                                 in_attr = false;
443                                 in_value = true;
444                                 trim = true;
445                                 l = 0;
446
447                                 /* Terminate this string in d
448                                  * (which is a copy of parse_dn
449                                  *  with spaces trimmed) */
450                                 *d++ = '\0';
451                                 dn->components[dn->comp_num].name = talloc_strdup(dn->components, dt);
452                                 if ( ! dn->components[dn->comp_num].name) {
453                                         /* ouch */
454                                         goto failed;
455                                 }
456
457                                 dt = d;
458
459                                 p++;
460                                 continue;
461                         }
462
463                         if (!isascii(*p)) {
464                                 /* attr names must be ascii only */
465                                 dn->invalid = true;
466                                 goto failed;
467                         }
468
469                         if (is_oid && ( ! (isdigit(*p) || (*p == '.')))) {
470                                 /* not a digit nor a dot,
471                                  * invalid attribute oid */
472                                 dn->invalid = true;
473                                 goto failed;
474                         } else
475                         if ( ! (isalpha(*p) || isdigit(*p) || (*p == '-'))) {
476                                 /* not ALPHA, DIGIT or HYPHEN */
477                                 dn->invalid = true;
478                                 goto failed;
479                         }
480
481                         *d++ = *p++;
482                         continue;
483                 }
484
485                 if (in_value) {
486                         if (in_quote) {
487                                 if (*p == '\"') {
488                                         if (p[-1] != '\\') {
489                                                 p++;
490                                                 in_quote = false;
491                                                 continue;
492                                         }
493                                 }
494                                 *d++ = *p++;
495                                 l++;
496                                 continue;
497                         }
498
499                         if (trim) {
500                                 if (*p == ' ') {
501                                         p++;
502                                         continue;
503                                 }
504
505                                 /* first char */
506                                 trim = false;
507
508                                 if (*p == '\"') {
509                                         in_quote = true;
510                                         p++;
511                                         continue;
512                                 }
513                         }
514
515                         switch (*p) {
516
517                         /* TODO: support ber encoded values
518                         case '#':
519                         */
520
521                         case ',':
522                                 if (escape) {
523                                         *d++ = *p++;
524                                         l++;
525                                         escape = false;
526                                         continue;
527                                 }
528                                 /* ok found value terminator */
529
530                                 if ( t ) {
531                                         /* trim back */
532                                         d -= (p - t);
533                                         l -= (p - t);
534                                 }
535
536                                 in_attr = true;
537                                 in_value = false;
538                                 trim = true;
539
540                                 p++;
541                                 *d++ = '\0';
542                                 dn->components[dn->comp_num].value.data = (uint8_t *)talloc_strdup(dn->components, dt);
543                                 dn->components[dn->comp_num].value.length = l;
544                                 if ( ! dn->components[dn->comp_num].value.data) {
545                                         /* ouch ! */
546                                         goto failed;
547                                 }
548
549                                 dt = d;
550
551                                 dn->comp_num++;
552                                 if (dn->comp_num > 2) {
553                                         dn->components = talloc_realloc(dn,
554                                                                         dn->components,
555                                                                         struct ldb_dn_component,
556                                                                         dn->comp_num + 1);
557                                         if ( ! dn->components) {
558                                                 /* ouch ! */
559                                                 goto failed;
560                                         }
561                                         /* make sure all components are zeroed, other functions depend on this */
562                                         memset(&dn->components[dn->comp_num], '\0', sizeof(struct ldb_dn_component));
563                                 }
564
565                                 continue;
566
567                         case '=':
568                         case '\n':
569                         case '+':
570                         case '<':
571                         case '>':
572                         case '#':
573                         case ';':
574                         case '\"':
575                                 /* a string with not escaped specials is invalid (tested) */
576                                 if ( ! escape) {
577                                         dn->invalid = true;
578                                         goto failed;
579                                 }
580                                 escape = false;
581
582                                 *d++ = *p++;
583                                 l++;
584
585                                 if ( t ) t = NULL;
586                                 break;
587
588                         case '\\':
589                                 if ( ! escape) {
590                                         escape = true;
591                                         p++;
592                                         continue;
593                                 }
594                                 escape = false;
595
596                                 *d++ = *p++;
597                                 l++;
598
599                                 if ( t ) t = NULL;
600                                 break;
601
602                         default:
603                                 if (escape) {
604                                         if (sscanf(p, "%02x", &x) != 1) {
605                                                 /* invalid escaping sequence */
606                                                 dn->invalid = true;
607                                                 goto failed;
608                                         }
609                                         escape = false;
610
611                                         p += 2;
612                                         *d++ = (unsigned char)x;
613                                         l++;
614
615                                         if ( t ) t = NULL;
616                                         break;
617                                 }
618
619                                 if (*p == ' ') {
620                                         if ( ! t) t = p;
621                                 } else {
622                                         if ( t ) t = NULL;
623                                 }
624
625                                 *d++ = *p++;
626                                 l++;
627
628                                 break;
629                         }
630
631                 }
632         }
633
634         if (in_attr || in_quote) {
635                 /* invalid dn */
636                 dn->invalid = true;
637                 goto failed;
638         }
639
640         /* save last element */
641         if ( t ) {
642                 /* trim back */
643                 d -= (p - t);
644                 l -= (p - t);
645         }
646
647         *d++ = '\0';
648         dn->components[dn->comp_num].value.length = l;
649         dn->components[dn->comp_num].value.data =
650                                 (uint8_t *)talloc_strdup(dn->components, dt);
651         if ( ! dn->components[dn->comp_num].value.data) {
652                 /* ouch */
653                 goto failed;
654         }
655
656         dn->comp_num++;
657
658         talloc_free(data);
659         return true;
660
661 failed:
662         dn->comp_num = 0;
663         talloc_free(dn->components);
664         return false;
665 }
666
667 bool ldb_dn_validate(struct ldb_dn *dn)
668 {
669         return ldb_dn_explode(dn);
670 }
671
672 const char *ldb_dn_get_linearized(struct ldb_dn *dn)
673 {
674         int i, len;
675         char *d, *n;
676
677         if ( ! dn || ( dn->invalid)) return NULL;
678
679         if (dn->linearized) return dn->linearized;
680
681         if ( ! dn->components) {
682                 dn->invalid = true;
683                 return NULL;
684         }
685
686         if (dn->comp_num == 0) {
687                 dn->linearized = talloc_strdup(dn, "");
688                 if ( ! dn->linearized) return NULL;
689                 return dn->linearized;
690         }
691
692         /* calculate maximum possible length of DN */
693         for (len = 0, i = 0; i < dn->comp_num; i++) {
694                 /* name len */
695                 len += strlen(dn->components[i].name);
696                 /* max escaped data len */
697                 len += (dn->components[i].value.length * 3);
698                 len += 2; /* '=' and ',' */
699         }
700         dn->linearized = talloc_array(dn, char, len);
701         if ( ! dn->linearized) return NULL;
702
703         d = dn->linearized;
704
705         for (i = 0; i < dn->comp_num; i++) {
706
707                 /* copy the name */
708                 n = dn->components[i].name;
709                 while (*n) *d++ = *n++;
710
711                 *d++ = '=';
712
713                 /* and the value */
714                 d += ldb_dn_escape_internal( d,
715                                 (char *)dn->components[i].value.data,
716                                 dn->components[i].value.length);
717                 *d++ = ',';
718         }
719
720         *(--d) = '\0';
721
722         /* don't waste more memory than necessary */
723         dn->linearized = talloc_realloc(dn, dn->linearized,
724                                         char, (d - dn->linearized + 1));
725
726         return dn->linearized;
727 }
728
729 char *ldb_dn_get_extended_linearized(void *mem_ctx, struct ldb_dn *dn, int mode)
730 {
731         const char *linearized = ldb_dn_get_linearized(dn);
732         char *p;
733         int i;
734
735         if (!linearized) {
736                 return NULL;
737         }
738
739         if (!ldb_dn_has_extended(dn)) {
740                 return talloc_strdup(mem_ctx, linearized);
741         }
742
743         if (!ldb_dn_validate(dn)) {
744                 return NULL;
745         }
746
747         for (i = 0; i < dn->ext_comp_num; i++) {
748                 const struct ldb_dn_extended_syntax *ext_syntax;
749                 const char *name = dn->ext_components[i].name;
750                 struct ldb_val ec_val = dn->ext_components[i].value;
751                 struct ldb_val val;
752                 int ret;
753
754                 ext_syntax = ldb_dn_extended_syntax_by_name(dn->ldb, name);
755
756                 if (mode == 1) {
757                         ret = ext_syntax->write_clear_fn(dn->ldb, mem_ctx,
758                                                         &ec_val, &val);
759                 } else if (mode == 0) {
760                         ret = ext_syntax->write_hex_fn(dn->ldb, mem_ctx,
761                                                         &ec_val, &val);
762                 } else {
763                         ret = -1;
764                 }
765
766                 if (ret != LDB_SUCCESS) {
767                         return NULL;
768                 }
769
770                 if (i == 0) {
771                         p = talloc_asprintf(mem_ctx, "<%s=%s>",
772                                                         name, val.data);
773                 } else {
774                         p = talloc_asprintf_append(p, ";<%s=%s>",
775                                                         name, val.data);
776                 }
777
778                 talloc_free(val.data);
779
780                 if (!p) {
781                         return NULL;
782                 }
783         }
784
785         if (dn->ext_comp_num && *linearized) {
786                 p = talloc_asprintf_append(p, ";%s", linearized);
787         }
788
789         if (!p) {
790                 return NULL;
791         }
792
793         return p;
794 }
795
796
797
798 char *ldb_dn_alloc_linearized(void *mem_ctx, struct ldb_dn *dn)
799 {
800         return talloc_strdup(mem_ctx, ldb_dn_get_linearized(dn));
801 }
802
803 /*
804   casefold a dn. We need to casefold the attribute names, and canonicalize
805   attribute values of case insensitive attributes.
806 */
807
808 static bool ldb_dn_casefold_internal(struct ldb_dn *dn)
809 {
810         int i, ret;
811
812         if ( ! dn || dn->invalid) return false;
813
814         if (dn->valid_case) return true;
815
816         if (( ! dn->components) && ( ! ldb_dn_explode(dn))) {
817                 return false;
818         }
819
820         for (i = 0; i < dn->comp_num; i++) {
821                 const struct ldb_schema_attribute *a;
822
823                 dn->components[i].cf_name =
824                         ldb_attr_casefold(dn->components,
825                                           dn->components[i].name);
826                 if (!dn->components[i].cf_name) {
827                         goto failed;
828                 }
829
830                 a = ldb_schema_attribute_by_name(dn->ldb,
831                                                  dn->components[i].cf_name);
832
833                 ret = a->syntax->canonicalise_fn(dn->ldb, dn->components,
834                                                  &(dn->components[i].value),
835                                                  &(dn->components[i].cf_value));
836                 if (ret != 0) {
837                         goto failed;
838                 }
839         }
840
841         dn->valid_case = true;
842
843         return true;
844
845 failed:
846         for (i = 0; i < dn->comp_num; i++) {
847                 LDB_FREE(dn->components[i].cf_name);
848                 LDB_FREE(dn->components[i].cf_value.data);
849         }
850         return false;
851 }
852
853 const char *ldb_dn_get_casefold(struct ldb_dn *dn)
854 {
855         int i, len;
856         char *d, *n;
857
858         if (dn->casefold) return dn->casefold;
859
860         if (dn->special) {
861                 dn->casefold = talloc_strdup(dn, dn->linearized);
862                 if (!dn->casefold) return NULL;
863                 dn->valid_case = true;
864                 return dn->casefold;
865         }
866
867         if ( ! ldb_dn_casefold_internal(dn)) {
868                 return NULL;
869         }
870
871         if (dn->comp_num == 0) {
872                 dn->casefold = talloc_strdup(dn, "");
873                 return dn->casefold;
874         }
875
876         /* calculate maximum possible length of DN */
877         for (len = 0, i = 0; i < dn->comp_num; i++) {
878                 /* name len */
879                 len += strlen(dn->components[i].cf_name);
880                 /* max escaped data len */
881                 len += (dn->components[i].cf_value.length * 3);
882                 len += 2; /* '=' and ',' */
883         }
884         dn->casefold = talloc_array(dn, char, len);
885         if ( ! dn->casefold) return NULL;
886
887         d = dn->casefold;
888
889         for (i = 0; i < dn->comp_num; i++) {
890
891                 /* copy the name */
892                 n = dn->components[i].cf_name;
893                 while (*n) *d++ = *n++;
894
895                 *d++ = '=';
896
897                 /* and the value */
898                 d += ldb_dn_escape_internal( d,
899                                 (char *)dn->components[i].cf_value.data,
900                                 dn->components[i].cf_value.length);
901                 *d++ = ',';
902         }
903         *(--d) = '\0';
904
905         /* don't waste more memory than necessary */
906         dn->casefold = talloc_realloc(dn, dn->casefold,
907                                       char, strlen(dn->casefold) + 1);
908
909         return dn->casefold;
910 }
911
912 char *ldb_dn_alloc_casefold(void *mem_ctx, struct ldb_dn *dn)
913 {
914         return talloc_strdup(mem_ctx, ldb_dn_get_casefold(dn));
915 }
916
917 /* Determine if dn is below base, in the ldap tree.  Used for
918  * evaluating a subtree search.
919  * 0 if they match, otherwise non-zero
920  */
921
922 int ldb_dn_compare_base(struct ldb_dn *base, struct ldb_dn *dn)
923 {
924         int ret;
925         int n_base, n_dn;
926
927         if ( ! base || base->invalid) return 1;
928         if ( ! dn || dn->invalid) return -1;
929
930         if (( ! base->valid_case) || ( ! dn->valid_case)) {
931                 if (base->linearized && dn->linearized) {
932                         /* try with a normal compare first, if we are lucky
933                          * we will avoid exploding and casfolding */
934                         int dif;
935                         dif = strlen(dn->linearized) - strlen(base->linearized);
936                         if (dif < 0) {
937                                 return dif;
938                         }
939                         if (strcmp(base->linearized,
940                                    &dn->linearized[dif]) == 0) {
941                                 return 0;
942                         }
943                 }
944
945                 if ( ! ldb_dn_casefold_internal(base)) {
946                         return 1;
947                 }
948
949                 if ( ! ldb_dn_casefold_internal(dn)) {
950                         return -1;
951                 }
952
953         }
954
955         /* if base has more components,
956          * they don't have the same base */
957         if (base->comp_num > dn->comp_num) {
958                 return (dn->comp_num - base->comp_num);
959         }
960
961         if (dn->comp_num == 0) {
962                 if (dn->special && base->special) {
963                         return strcmp(base->linearized, dn->linearized);
964                 } else if (dn->special) {
965                         return -1;
966                 } else if (base->special) {
967                         return 1;
968                 } else {
969                         return 0;
970                 }
971         }
972
973         n_base = base->comp_num - 1;
974         n_dn = dn->comp_num - 1;
975
976         while (n_base >= 0) {
977                 char *b_name = base->components[n_base].cf_name;
978                 char *dn_name = dn->components[n_dn].cf_name;
979
980                 char *b_vdata = (char *)base->components[n_base].cf_value.data;
981                 char *dn_vdata = (char *)dn->components[n_dn].cf_value.data;
982
983                 size_t b_vlen = base->components[n_base].cf_value.length;
984                 size_t dn_vlen = dn->components[n_dn].cf_value.length;
985
986                 /* compare attr names */
987                 ret = strcmp(b_name, dn_name);
988                 if (ret != 0) return ret;
989
990                 /* compare attr.cf_value. */
991                 if (b_vlen != dn_vlen) {
992                         return b_vlen - dn_vlen;
993                 }
994                 ret = strcmp(b_vdata, dn_vdata);
995                 if (ret != 0) return ret;
996
997                 n_base--;
998                 n_dn--;
999         }
1000
1001         return 0;
1002 }
1003
1004 /* compare DNs using casefolding compare functions.
1005
1006    If they match, then return 0
1007  */
1008
1009 int ldb_dn_compare(struct ldb_dn *dn0, struct ldb_dn *dn1)
1010 {
1011         int i, ret;
1012
1013         if (( ! dn0) || dn0->invalid || ! dn1 || dn1->invalid) {
1014                 return -1;
1015         }
1016
1017         if (( ! dn0->valid_case) || ( ! dn1->valid_case)) {
1018                 if (dn0->linearized && dn1->linearized) {
1019                         /* try with a normal compare first, if we are lucky
1020                          * we will avoid exploding and casfolding */
1021                         if (strcmp(dn0->linearized, dn1->linearized) == 0) {
1022                                 return 0;
1023                         }
1024                 }
1025
1026                 if ( ! ldb_dn_casefold_internal(dn0)) {
1027                         return 1;
1028                 }
1029
1030                 if ( ! ldb_dn_casefold_internal(dn1)) {
1031                         return -1;
1032                 }
1033
1034         }
1035
1036         if (dn0->comp_num != dn1->comp_num) {
1037                 return (dn1->comp_num - dn0->comp_num);
1038         }
1039
1040         if (dn0->comp_num == 0) {
1041                 if (dn0->special && dn1->special) {
1042                         return strcmp(dn0->linearized, dn1->linearized);
1043                 } else if (dn0->special) {
1044                         return 1;
1045                 } else if (dn1->special) {
1046                         return -1;
1047                 } else {
1048                         return 0;
1049                 }
1050         }
1051
1052         for (i = 0; i < dn0->comp_num; i++) {
1053                 char *dn0_name = dn0->components[i].cf_name;
1054                 char *dn1_name = dn1->components[i].cf_name;
1055
1056                 char *dn0_vdata = (char *)dn0->components[i].cf_value.data;
1057                 char *dn1_vdata = (char *)dn1->components[i].cf_value.data;
1058
1059                 size_t dn0_vlen = dn0->components[i].cf_value.length;
1060                 size_t dn1_vlen = dn1->components[i].cf_value.length;
1061
1062                 /* compare attr names */
1063                 ret = strcmp(dn0_name, dn1_name);
1064                 if (ret != 0) {
1065                         return ret;
1066                 }
1067
1068                 /* compare attr.cf_value. */
1069                 if (dn0_vlen != dn1_vlen) {
1070                         return dn0_vlen - dn1_vlen;
1071                 }
1072                 ret = strcmp(dn0_vdata, dn1_vdata);
1073                 if (ret != 0) {
1074                         return ret;
1075                 }
1076         }
1077
1078         return 0;
1079 }
1080
1081 static struct ldb_dn_component ldb_dn_copy_component(
1082                                                 void *mem_ctx,
1083                                                 struct ldb_dn_component *src)
1084 {
1085         struct ldb_dn_component dst;
1086
1087         memset(&dst, 0, sizeof(dst));
1088
1089         if (src == NULL) {
1090                 return dst;
1091         }
1092
1093         dst.value = ldb_val_dup(mem_ctx, &(src->value));
1094         if (dst.value.data == NULL) {
1095                 return dst;
1096         }
1097
1098         dst.name = talloc_strdup(mem_ctx, src->name);
1099         if (dst.name == NULL) {
1100                 LDB_FREE(dst.value.data);
1101                 return dst;
1102         }
1103
1104         if (src->cf_value.data) {
1105                 dst.cf_value = ldb_val_dup(mem_ctx, &(src->cf_value));
1106                 if (dst.cf_value.data == NULL) {
1107                         LDB_FREE(dst.value.data);
1108                         LDB_FREE(dst.name);
1109                         return dst;
1110                 }
1111
1112                 dst.cf_name = talloc_strdup(mem_ctx, src->cf_name);
1113                 if (dst.cf_name == NULL) {
1114                         LDB_FREE(dst.cf_name);
1115                         LDB_FREE(dst.value.data);
1116                         LDB_FREE(dst.name);
1117                         return dst;
1118                 }
1119         } else {
1120                 dst.cf_value.data = NULL;
1121                 dst.cf_name = NULL;
1122         }
1123
1124         return dst;
1125 }
1126
1127 static struct ldb_dn_ext_component ldb_dn_ext_copy_component(
1128                                                 void *mem_ctx,
1129                                                 struct ldb_dn_ext_component *src)
1130 {
1131         struct ldb_dn_ext_component dst;
1132
1133         memset(&dst, 0, sizeof(dst));
1134
1135         if (src == NULL) {
1136                 return dst;
1137         }
1138
1139         dst.value = ldb_val_dup(mem_ctx, &(src->value));
1140         if (dst.value.data == NULL) {
1141                 return dst;
1142         }
1143
1144         dst.name = talloc_strdup(mem_ctx, src->name);
1145         if (dst.name == NULL) {
1146                 LDB_FREE(dst.value.data);
1147                 return dst;
1148         }
1149
1150         return dst;
1151 }
1152
1153 struct ldb_dn *ldb_dn_copy(void *mem_ctx, struct ldb_dn *dn)
1154 {
1155         struct ldb_dn *new_dn;
1156
1157         if (!dn || dn->invalid) {
1158                 return NULL;
1159         }
1160
1161         new_dn = talloc_zero(mem_ctx, struct ldb_dn);
1162         if ( !new_dn) {
1163                 return NULL;
1164         }
1165
1166         *new_dn = *dn;
1167
1168         if (dn->components) {
1169                 int i;
1170
1171                 new_dn->components =
1172                         talloc_zero_array(new_dn,
1173                                           struct ldb_dn_component,
1174                                           dn->comp_num);
1175                 if ( ! new_dn->components) {
1176                         talloc_free(new_dn);
1177                         return NULL;
1178                 }
1179
1180                 for (i = 0; i < dn->comp_num; i++) {
1181                         new_dn->components[i] =
1182                                 ldb_dn_copy_component(new_dn->components,
1183                                                       &dn->components[i]);
1184                         if ( ! new_dn->components[i].value.data) {
1185                                 talloc_free(new_dn);
1186                                 return NULL;
1187                         }
1188                 }
1189         }
1190
1191         if (dn->ext_components) {
1192                 int i;
1193
1194                 new_dn->ext_components =
1195                         talloc_zero_array(new_dn,
1196                                           struct ldb_dn_ext_component,
1197                                           dn->ext_comp_num);
1198                 if ( ! new_dn->ext_components) {
1199                         talloc_free(new_dn);
1200                         return NULL;
1201                 }
1202
1203                 for (i = 0; i < dn->ext_comp_num; i++) {
1204                         new_dn->ext_components[i] =
1205                                  ldb_dn_ext_copy_component(
1206                                                 new_dn->ext_components,
1207                                                 &dn->ext_components[i]);
1208                         if ( ! new_dn->ext_components[i].value.data) {
1209                                 talloc_free(new_dn);
1210                                 return NULL;
1211                         }
1212                 }
1213         }
1214
1215         if (dn->casefold) {
1216                 new_dn->casefold = talloc_strdup(new_dn, dn->casefold);
1217                 if ( ! new_dn->casefold) {
1218                         talloc_free(new_dn);
1219                         return NULL;
1220                 }
1221         }
1222
1223         if (dn->linearized) {
1224                 new_dn->linearized = talloc_strdup(new_dn, dn->linearized);
1225                 if ( ! new_dn->linearized) {
1226                         talloc_free(new_dn);
1227                         return NULL;
1228                 }
1229         }
1230
1231         if (dn->ext_linearized) {
1232                 new_dn->ext_linearized = talloc_strdup(new_dn,
1233                                                         dn->ext_linearized);
1234                 if ( ! new_dn->ext_linearized) {
1235                         talloc_free(new_dn);
1236                         return NULL;
1237                 }
1238         }
1239
1240         return new_dn;
1241 }
1242
1243 /* modify the given dn by adding a base.
1244  *
1245  * return true if successful and false if not
1246  * if false is returned the dn may be marked invalid
1247  */
1248 bool ldb_dn_add_base(struct ldb_dn *dn, struct ldb_dn *base)
1249 {
1250         const char *s;
1251         char *t;
1252
1253         if ( !base || base->invalid || !dn || dn->invalid) {
1254                 return false;
1255         }
1256
1257         if (dn->components) {
1258                 int i;
1259
1260                 if ( ! ldb_dn_validate(base)) {
1261                         return false;
1262                 }
1263
1264                 s = NULL;
1265                 if (dn->valid_case) {
1266                         if ( ! (s = ldb_dn_get_casefold(base))) {
1267                                 return false;
1268                         }
1269                 }
1270
1271                 dn->components = talloc_realloc(dn,
1272                                                 dn->components,
1273                                                 struct ldb_dn_component,
1274                                                 dn->comp_num + base->comp_num);
1275                 if ( ! dn->components) {
1276                         dn->invalid = true;
1277                         return false;
1278                 }
1279
1280                 for (i = 0; i < base->comp_num; dn->comp_num++, i++) {
1281                         dn->components[dn->comp_num] =
1282                                 ldb_dn_copy_component(dn->components,
1283                                                         &base->components[i]);
1284                         if (dn->components[dn->comp_num].value.data == NULL) {
1285                                 dn->invalid = true;
1286                                 return false;
1287                         }
1288                 }
1289
1290                 if (dn->casefold && s) {
1291                         if (*dn->casefold) {
1292                                 t = talloc_asprintf(dn, "%s,%s",
1293                                                     dn->casefold, s);
1294                         } else {
1295                                 t = talloc_strdup(dn, s);
1296                         }
1297                         LDB_FREE(dn->casefold);
1298                         dn->casefold = t;
1299                 }
1300         }
1301
1302         if (dn->linearized) {
1303
1304                 s = ldb_dn_get_linearized(base);
1305                 if ( ! s) {
1306                         return false;
1307                 }
1308
1309                 if (*dn->linearized) {
1310                         t = talloc_asprintf(dn, "%s,%s",
1311                                             dn->linearized, s);
1312                 } else {
1313                         t = talloc_strdup(dn, s);
1314                 }
1315                 if ( ! t) {
1316                         dn->invalid = true;
1317                         return false;
1318                 }
1319                 LDB_FREE(dn->linearized);
1320                 dn->linearized = t;
1321         }
1322
1323         /* Wipe the ext_linearized DN,
1324          * the GUID and SID are almost certainly no longer valid */
1325         if (dn->ext_linearized) {
1326                 LDB_FREE(dn->ext_linearized);
1327         }
1328
1329         LDB_FREE(dn->ext_components);
1330         dn->ext_comp_num = 0;
1331         return true;
1332 }
1333
1334 /* modify the given dn by adding a base.
1335  *
1336  * return true if successful and false if not
1337  * if false is returned the dn may be marked invalid
1338  */
1339 bool ldb_dn_add_base_fmt(struct ldb_dn *dn, const char *base_fmt, ...)
1340 {
1341         struct ldb_dn *base;
1342         char *base_str;
1343         va_list ap;
1344         bool ret;
1345
1346         if ( !dn || dn->invalid) {
1347                 return false;
1348         }
1349
1350         va_start(ap, base_fmt);
1351         base_str = talloc_vasprintf(dn, base_fmt, ap);
1352         va_end(ap);
1353
1354         if (base_str == NULL) {
1355                 return false;
1356         }
1357
1358         base = ldb_dn_new(base_str, dn->ldb, base_str);
1359
1360         ret = ldb_dn_add_base(dn, base);
1361
1362         talloc_free(base_str);
1363
1364         return ret;
1365 }
1366
1367 /* modify the given dn by adding children elements.
1368  *
1369  * return true if successful and false if not
1370  * if false is returned the dn may be marked invalid
1371  */
1372 bool ldb_dn_add_child(struct ldb_dn *dn, struct ldb_dn *child)
1373 {
1374         const char *s;
1375         char *t;
1376
1377         if ( !child || child->invalid || !dn || dn->invalid) {
1378                 return false;
1379         }
1380
1381         if (dn->components) {
1382                 int n, i, j;
1383
1384                 if ( ! ldb_dn_validate(child)) {
1385                         return false;
1386                 }
1387
1388                 s = NULL;
1389                 if (dn->valid_case) {
1390                         if ( ! (s = ldb_dn_get_casefold(child))) {
1391                                 return false;
1392                         }
1393                 }
1394
1395                 n = dn->comp_num + child->comp_num;
1396
1397                 dn->components = talloc_realloc(dn,
1398                                                 dn->components,
1399                                                 struct ldb_dn_component,
1400                                                 n);
1401                 if ( ! dn->components) {
1402                         dn->invalid = true;
1403                         return false;
1404                 }
1405
1406                 for (i = dn->comp_num - 1, j = n - 1; i >= 0; i--, j--) {
1407                         dn->components[j] = dn->components[i];
1408                 }
1409
1410                 for (i = 0; i < child->comp_num; i++) {
1411                         dn->components[i] =
1412                                 ldb_dn_copy_component(dn->components,
1413                                                         &child->components[i]);
1414                         if (dn->components[i].value.data == NULL) {
1415                                 dn->invalid = true;
1416                                 return false;
1417                         }
1418                 }
1419
1420                 dn->comp_num = n;
1421
1422                 if (dn->casefold && s) {
1423                         t = talloc_asprintf(dn, "%s,%s", s, dn->casefold);
1424                         LDB_FREE(dn->casefold);
1425                         dn->casefold = t;
1426                 }
1427         }
1428
1429         if (dn->linearized) {
1430
1431                 s = ldb_dn_get_linearized(child);
1432                 if ( ! s) {
1433                         return false;
1434                 }
1435
1436                 t = talloc_asprintf(dn, "%s,%s", s, dn->linearized);
1437                 if ( ! t) {
1438                         dn->invalid = true;
1439                         return false;
1440                 }
1441                 LDB_FREE(dn->linearized);
1442                 dn->linearized = t;
1443         }
1444
1445         /* Wipe the ext_linearized DN,
1446          * the GUID and SID are almost certainly no longer valid */
1447         LDB_FREE(dn->ext_linearized);
1448
1449         LDB_FREE(dn->ext_components);
1450         dn->ext_comp_num = 0;
1451
1452         return true;
1453 }
1454
1455 /* modify the given dn by adding children elements.
1456  *
1457  * return true if successful and false if not
1458  * if false is returned the dn may be marked invalid
1459  */
1460 bool ldb_dn_add_child_fmt(struct ldb_dn *dn, const char *child_fmt, ...)
1461 {
1462         struct ldb_dn *child;
1463         char *child_str;
1464         va_list ap;
1465         bool ret;
1466
1467         if ( !dn || dn->invalid) {
1468                 return false;
1469         }
1470
1471         va_start(ap, child_fmt);
1472         child_str = talloc_vasprintf(dn, child_fmt, ap);
1473         va_end(ap);
1474
1475         if (child_str == NULL) {
1476                 return false;
1477         }
1478
1479         child = ldb_dn_new(child_str, dn->ldb, child_str);
1480
1481         ret = ldb_dn_add_child(dn, child);
1482
1483         talloc_free(child_str);
1484
1485         return ret;
1486 }
1487
1488 bool ldb_dn_remove_base_components(struct ldb_dn *dn, unsigned int num)
1489 {
1490         int i;
1491
1492         if ( ! ldb_dn_validate(dn)) {
1493                 return false;
1494         }
1495
1496         if (dn->comp_num < num) {
1497                 return false;
1498         }
1499
1500         /* free components */
1501         for (i = num; i > 0; i--) {
1502                 LDB_FREE(dn->components[dn->comp_num - i].name);
1503                 LDB_FREE(dn->components[dn->comp_num - i].value.data);
1504                 LDB_FREE(dn->components[dn->comp_num - i].cf_name);
1505                 LDB_FREE(dn->components[dn->comp_num - i].cf_value.data);
1506         }
1507
1508         dn->comp_num -= num;
1509
1510         if (dn->valid_case) {
1511                 for (i = 0; i < dn->comp_num; i++) {
1512                         LDB_FREE(dn->components[i].cf_name);
1513                         LDB_FREE(dn->components[i].cf_value.data);
1514                 }
1515                 dn->valid_case = false;
1516         }
1517
1518         LDB_FREE(dn->casefold);
1519         LDB_FREE(dn->linearized);
1520
1521         /* Wipe the ext_linearized DN,
1522          * the GUID and SID are almost certainly no longer valid */
1523         LDB_FREE(dn->ext_linearized);
1524
1525         LDB_FREE(dn->ext_components);
1526         dn->ext_comp_num = 0;
1527
1528         return true;
1529 }
1530
1531 bool ldb_dn_remove_child_components(struct ldb_dn *dn, unsigned int num)
1532 {
1533         int i, j;
1534
1535         if ( ! ldb_dn_validate(dn)) {
1536                 return false;
1537         }
1538
1539         if (dn->comp_num < num) {
1540                 return false;
1541         }
1542
1543         for (i = 0, j = num; j < dn->comp_num; i++, j++) {
1544                 if (i < num) {
1545                         LDB_FREE(dn->components[i].name);
1546                         LDB_FREE(dn->components[i].value.data);
1547                         LDB_FREE(dn->components[i].cf_name);
1548                         LDB_FREE(dn->components[i].cf_value.data);
1549                 }
1550                 dn->components[i] = dn->components[j];
1551         }
1552
1553         dn->comp_num -= num;
1554
1555         if (dn->valid_case) {
1556                 for (i = 0; i < dn->comp_num; i++) {
1557                         LDB_FREE(dn->components[i].cf_name);
1558                         LDB_FREE(dn->components[i].cf_value.data);
1559                 }
1560                 dn->valid_case = false;
1561         }
1562
1563         LDB_FREE(dn->casefold);
1564         LDB_FREE(dn->linearized);
1565
1566         /* Wipe the ext_linearized DN,
1567          * the GUID and SID are almost certainly no longer valid */
1568         LDB_FREE(dn->ext_linearized);
1569
1570         LDB_FREE(dn->ext_components);
1571         dn->ext_comp_num = 0;
1572         return true;
1573 }
1574
1575 struct ldb_dn *ldb_dn_get_parent(void *mem_ctx, struct ldb_dn *dn)
1576 {
1577         struct ldb_dn *new_dn;
1578
1579         new_dn = ldb_dn_copy(mem_ctx, dn);
1580         if ( !new_dn ) {
1581                 return NULL;
1582         }
1583
1584         if ( ! ldb_dn_remove_child_components(new_dn, 1)) {
1585                 talloc_free(new_dn);
1586                 return NULL;
1587         }
1588
1589         /* Wipe the ext_linearized DN,
1590          * the GUID and SID are almost certainly no longer valid */
1591         LDB_FREE(dn->ext_linearized);
1592
1593         LDB_FREE(dn->ext_components);
1594         dn->ext_comp_num = 0;
1595         return new_dn;
1596 }
1597
1598 /* Create a 'canonical name' string from a DN:
1599
1600    ie dc=samba,dc=org -> samba.org/
1601       uid=administrator,ou=users,dc=samba,dc=org = samba.org/users/administrator
1602
1603    There are two formats,
1604    the EX format has the last '/' replaced with a newline (\n).
1605
1606 */
1607 static char *ldb_dn_canonical(void *mem_ctx, struct ldb_dn *dn, int ex_format) {
1608         int i;
1609         TALLOC_CTX *tmpctx;
1610         char *cracked = NULL;
1611         const char *format = (ex_format ? "\n" : "/" );
1612
1613         if ( ! ldb_dn_validate(dn)) {
1614                 return NULL;
1615         }
1616
1617         tmpctx = talloc_new(mem_ctx);
1618
1619         /* Walk backwards down the DN, grabbing 'dc' components at first */
1620         for (i = dn->comp_num - 1 ; i >= 0; i--) {
1621                 if (ldb_attr_cmp(dn->components[i].name, "dc") != 0) {
1622                         break;
1623                 }
1624                 if (cracked) {
1625                         cracked = talloc_asprintf(tmpctx, "%s.%s",
1626                                                   ldb_dn_escape_value(tmpctx,
1627                                                         dn->components[i].value),
1628                                                   cracked);
1629                 } else {
1630                         cracked = ldb_dn_escape_value(tmpctx,
1631                                                         dn->components[i].value);
1632                 }
1633                 if (!cracked) {
1634                         goto done;
1635                 }
1636         }
1637
1638         /* Only domain components?  Finish here */
1639         if (i < 0) {
1640                 cracked = talloc_strdup_append_buffer(cracked, format);
1641                 talloc_steal(mem_ctx, cracked);
1642                 goto done;
1643         }
1644
1645         /* Now walk backwards appending remaining components */
1646         for (; i > 0; i--) {
1647                 cracked = talloc_asprintf_append_buffer(cracked, "/%s",
1648                                                         ldb_dn_escape_value(tmpctx,
1649                                                         dn->components[i].value));
1650                 if (!cracked) {
1651                         goto done;
1652                 }
1653         }
1654
1655         /* Last one, possibly a newline for the 'ex' format */
1656         cracked = talloc_asprintf_append_buffer(cracked, "%s%s", format,
1657                                                 ldb_dn_escape_value(tmpctx,
1658                                                         dn->components[i].value));
1659
1660         talloc_steal(mem_ctx, cracked);
1661 done:
1662         talloc_free(tmpctx);
1663         return cracked;
1664 }
1665
1666 /* Wrapper functions for the above, for the two different string formats */
1667 char *ldb_dn_canonical_string(void *mem_ctx, struct ldb_dn *dn) {
1668         return ldb_dn_canonical(mem_ctx, dn, 0);
1669
1670 }
1671
1672 char *ldb_dn_canonical_ex_string(void *mem_ctx, struct ldb_dn *dn) {
1673         return ldb_dn_canonical(mem_ctx, dn, 1);
1674 }
1675
1676 int ldb_dn_get_comp_num(struct ldb_dn *dn)
1677 {
1678         if ( ! ldb_dn_validate(dn)) {
1679                 return -1;
1680         }
1681         return dn->comp_num;
1682 }
1683
1684 const char *ldb_dn_get_component_name(struct ldb_dn *dn, unsigned int num)
1685 {
1686         if ( ! ldb_dn_validate(dn)) {
1687                 return NULL;
1688         }
1689         if (num >= dn->comp_num) return NULL;
1690         return dn->components[num].name;
1691 }
1692
1693 const struct ldb_val *ldb_dn_get_component_val(struct ldb_dn *dn,
1694                                                 unsigned int num)
1695 {
1696         if ( ! ldb_dn_validate(dn)) {
1697                 return NULL;
1698         }
1699         if (num >= dn->comp_num) return NULL;
1700         return &dn->components[num].value;
1701 }
1702
1703 const char *ldb_dn_get_rdn_name(struct ldb_dn *dn)
1704 {
1705         if ( ! ldb_dn_validate(dn)) {
1706                 return NULL;
1707         }
1708         if (dn->comp_num == 0) return NULL;
1709         return dn->components[0].name;
1710 }
1711
1712 const struct ldb_val *ldb_dn_get_rdn_val(struct ldb_dn *dn)
1713 {
1714         if ( ! ldb_dn_validate(dn)) {
1715                 return NULL;
1716         }
1717         if (dn->comp_num == 0) return NULL;
1718         return &dn->components[0].value;
1719 }
1720
1721 int ldb_dn_set_component(struct ldb_dn *dn, int num,
1722                          const char *name, const struct ldb_val val)
1723 {
1724         char *n;
1725         struct ldb_val v;
1726
1727         if ( ! ldb_dn_validate(dn)) {
1728                 return LDB_ERR_OTHER;
1729         }
1730
1731         if (num >= dn->comp_num) {
1732                 return LDB_ERR_OTHER;
1733         }
1734
1735         n = talloc_strdup(dn, name);
1736         if ( ! n) {
1737                 return LDB_ERR_OTHER;
1738         }
1739
1740         v.length = val.length;
1741         v.data = (uint8_t *)talloc_memdup(dn, val.data, v.length+1);
1742         if ( ! v.data) {
1743                 talloc_free(n);
1744                 return LDB_ERR_OTHER;
1745         }
1746
1747         talloc_free(dn->components[num].name);
1748         talloc_free(dn->components[num].value.data);
1749         dn->components[num].name = n;
1750         dn->components[num].value = v;
1751
1752         if (dn->valid_case) {
1753                 int i;
1754                 for (i = 0; i < dn->comp_num; i++) {
1755                         LDB_FREE(dn->components[i].cf_name);
1756                         LDB_FREE(dn->components[i].cf_value.data);
1757                 }
1758                 dn->valid_case = false;
1759         }
1760         LDB_FREE(dn->casefold);
1761         LDB_FREE(dn->linearized);
1762
1763         /* Wipe the ext_linearized DN,
1764          * the GUID and SID are almost certainly no longer valid */
1765         LDB_FREE(dn->ext_linearized);
1766
1767         dn->ext_comp_num = 0;
1768         LDB_FREE(dn->ext_components);
1769         return LDB_SUCCESS;
1770 }
1771
1772 const struct ldb_val *ldb_dn_get_extended_component(struct ldb_dn *dn,
1773                                                     const char *name)
1774 {
1775         int i;
1776         if ( ! ldb_dn_validate(dn)) {
1777                 return NULL;
1778         }
1779         for (i=0; i < dn->ext_comp_num; i++) {
1780                 if (ldb_attr_cmp(dn->ext_components[i].name, name) == 0) {
1781                         return &dn->ext_components[i].value;
1782                 }
1783         }
1784         return NULL;
1785 }
1786
1787 int ldb_dn_set_extended_component(struct ldb_dn *dn,
1788                                   const char *name, const struct ldb_val *val)
1789 {
1790         struct ldb_dn_ext_component *p;
1791         int i;
1792
1793         if ( ! ldb_dn_validate(dn)) {
1794                 return LDB_ERR_OTHER;
1795         }
1796
1797         for (i=0; i < dn->ext_comp_num; i++) {
1798                 if (ldb_attr_cmp(dn->ext_components[i].name, name) == 0) {
1799                         if (val) {
1800                                 dn->ext_components[i].value =
1801                                         ldb_val_dup(dn->ext_components, val);
1802
1803                                 dn->ext_components[i].name =
1804                                         talloc_strdup(dn->ext_components, name);
1805                                 if (!dn->ext_components[i].name ||
1806                                     !dn->ext_components[i].value.data) {
1807                                         dn->invalid = true;
1808                                         return LDB_ERR_OPERATIONS_ERROR;
1809                                 }
1810
1811                         } else {
1812                                 if (i != (dn->ext_comp_num - 1)) {
1813                                         memmove(&dn->ext_components[i],
1814                                                 &dn->ext_components[i+1],
1815                                                 ((dn->ext_comp_num-1) - i) *
1816                                                   sizeof(*dn->ext_components));
1817                                 }
1818                                 dn->ext_comp_num--;
1819
1820                                 dn->ext_components = talloc_realloc(dn,
1821                                                    dn->ext_components,
1822                                                    struct ldb_dn_ext_component,
1823                                                    dn->ext_comp_num);
1824                                 if (!dn->ext_components) {
1825                                         dn->invalid = true;
1826                                         return LDB_ERR_OPERATIONS_ERROR;
1827                                 }
1828                                 return LDB_SUCCESS;
1829                         }
1830                 }
1831         }
1832
1833         p = dn->ext_components
1834                 = talloc_realloc(dn,
1835                                  dn->ext_components,
1836                                  struct ldb_dn_ext_component,
1837                                  dn->ext_comp_num + 1);
1838         if (!dn->ext_components) {
1839                 dn->invalid = true;
1840                 return LDB_ERR_OPERATIONS_ERROR;
1841         }
1842
1843         p[dn->ext_comp_num].value = ldb_val_dup(dn->ext_components, val);
1844         p[dn->ext_comp_num].name = talloc_strdup(p, name);
1845
1846         if (!dn->ext_components[i].name || !dn->ext_components[i].value.data) {
1847                 dn->invalid = true;
1848                 return LDB_ERR_OPERATIONS_ERROR;
1849         }
1850         dn->ext_components = p;
1851         dn->ext_comp_num++;
1852
1853         return LDB_SUCCESS;
1854 }
1855
1856 void ldb_dn_remove_extended_components(struct ldb_dn *dn)
1857 {
1858         dn->ext_comp_num = 0;
1859         LDB_FREE(dn->ext_components);
1860 }
1861
1862 bool ldb_dn_is_valid(struct ldb_dn *dn)
1863 {
1864         if ( ! dn) return false;
1865         return ! dn->invalid;
1866 }
1867
1868 bool ldb_dn_is_special(struct ldb_dn *dn)
1869 {
1870         if ( ! dn || dn->invalid) return false;
1871         return dn->special;
1872 }
1873
1874 bool ldb_dn_has_extended(struct ldb_dn *dn)
1875 {
1876         if ( ! dn || dn->invalid) return false;
1877         if (dn->ext_linearized && (dn->ext_linearized[0] == '<')) return true;
1878         return dn->ext_comp_num != 0;
1879 }
1880
1881 bool ldb_dn_check_special(struct ldb_dn *dn, const char *check)
1882 {
1883         if ( ! dn || dn->invalid) return false;
1884         return ! strcmp(dn->linearized, check);
1885 }
1886
1887 bool ldb_dn_is_null(struct ldb_dn *dn)
1888 {
1889         if ( ! dn || dn->invalid) return false;
1890         if (ldb_dn_has_extended(dn)) return false;
1891         if (dn->linearized && (dn->linearized[0] == '\0')) return true;
1892         return false;
1893 }