4 Copyright (C) Simo Sorce 2005
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
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 2 of the License, or (at your option) any later version.
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.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 * Component: ldb dn explode and utility functions
30 * Description: - explode a dn into it's own basic elements
31 * and put them in a structure
32 * - manipulate ldb_dn structures
38 #include "ldb/include/ldb.h"
39 #include "ldb/include/ldb_private.h"
40 #include "ldb/include/ldb_dn.h"
43 #define LDB_DN_NULL_FAILED(x) if (!(x)) goto failed
45 static char *escape_string(void *mem_ctx, const char *src)
50 LDB_DN_NULL_FAILED(src);
52 /* allocate destination string, it will be at most 3 times the source */
53 dst = d = talloc_array(mem_ctx, char, strlen(src) * 3 + 1);
54 LDB_DN_NULL_FAILED(dst);
59 p += strcspn(p, ",=\n+<>#;\\\"");
60 if (*p == '\0') /* no special s found, all ok */
63 if (*p) { /* copy part of the string and escape */
72 /* copy the last part (with zero) and return */
73 memcpy(d, s, &src[strlen(src)] - s + 1);
81 static char *unescape_string(void *mem_ctx, const char *src)
84 char *p, *dst=NULL, *end;
86 LDB_DN_NULL_FAILED(src);
88 dst = p = talloc_strdup(mem_ctx, src);
89 LDB_DN_NULL_FAILED(dst);
91 end = &dst[strlen(dst)];
94 p += strcspn(p, ",=\n+<>#;\\\"");
95 if (*p == '\0') /* no escapes or specials found, all ok */
99 if (strchr(",=\n+<>#;\\\"", p[1])) {
100 memmove(p, p + 1, end - (p + 1) + 1);
106 if (sscanf(p + 1, "%02x", &x) == 1) {
107 *p = (unsigned char)x;
108 memmove(p + 1, p + 3, end - (p + 3) + 1);
115 /* a string with not escaped specials is invalid */
126 static char *seek_to_separator(char *string, const char *separator)
130 p = strchr(string, '=');
132 LDB_DN_NULL_FAILED(p);
136 /* check if there are quotes surrounding the value */
137 p += strspn(p, " \n"); /* skip white spaces after '=' */
143 LDB_DN_NULL_FAILED(p);
145 if (*(p - 1) == '\\')
150 p += strcspn(p, separator);
158 static char *ldb_dn_trim_string(char *string, const char *edge)
162 /* seek out edge from start of string */
163 s = string + strspn(string, edge);
165 /* backwards skip from end of string */
166 p = &s[strlen(s) - 1];
167 while (p > s && strchr(edge, *p)) {
175 static struct ldb_dn_attribute *ldb_dn_explode_attribute(void *mem_ctx, char *raw_attribute)
177 struct ldb_dn_attribute *at;
180 at = talloc(mem_ctx, struct ldb_dn_attribute);
181 LDB_DN_NULL_FAILED(at);
183 p = strchr(raw_attribute, '=');
185 LDB_DN_NULL_FAILED(p);
189 at->name = talloc_strdup(at, ldb_dn_trim_string(raw_attribute, " \n"));
190 LDB_DN_NULL_FAILED(at->name);
194 p = ldb_dn_trim_string(p, " \n");
196 if (*p == '\"') { /* quotes at start means there must be quotes at the end */
197 if (p[strlen(p) - 1] != '\"') /* malformed value */
201 p[strlen(p) - 1] = '\0';
202 at->value = talloc_strdup(at, p);
206 /* no quotes means we must unescape the string */
207 at->value = unescape_string(at, p);
208 LDB_DN_NULL_FAILED(at->value);
217 static struct ldb_dn_component *explode_component(void *mem_ctx, char *raw_component)
219 struct ldb_dn_component *dc;
222 dc = talloc(mem_ctx, struct ldb_dn_component);
223 LDB_DN_NULL_FAILED(dc);
226 dc->attributes = NULL;
230 /* get the components */
234 /* terminate the current attribute and return pointer to the next one */
235 t = seek_to_separator(p, "+");
236 LDB_DN_NULL_FAILED(t);
238 if (*t) { /* here there is a separator */
239 *t = '\0'; /*terminate */
240 t++; /* a separtor means there's another attribute that follows */
243 /* allocate attributes pointer */
244 dc->attributes = talloc_realloc(dc, dc->attributes,
245 struct ldb_dn_attribute *,
247 LDB_DN_NULL_FAILED(dc->attributes);
249 /* store the exploded attirbute in the main structure */
250 dc->attributes[dc->attr_num] = ldb_dn_explode_attribute(dc->attributes, p);
251 LDB_DN_NULL_FAILED(dc->attributes[dc->attr_num]);
255 /* jump to the next attribute if any */
266 /* FIXME: currently consider a dn composed of only case insensitive attributes
267 this is not correct and need to be fixed soon */
268 static void ldb_dn_sort_attributes(struct ldb_dn *edn)
270 struct ldb_dn_attribute *at0, *at1;
273 for (i = 0; i < edn->comp_num; i++) {
274 if (edn->components[i]->attr_num > 1) {
276 /* it is very unlikely that there is a multivalued RDN. In that
277 unlikely case it is very unlikely you will find more than 2
278 values. So the use of bubble sort here seem to be acceptable */
279 for (j = 0; (j + 1) < edn->components[i]->attr_num; j++) {
280 for (k = j; k >= 0; k--) {
281 at0 = edn->components[i]->attributes[k];
282 at1 = edn->components[i]->attributes[k + 1];
283 l = ldb_caseless_cmp(at0->name, at1->name);
285 /* already sorted, so no bubbles to move exit inner loop */
289 if (ldb_caseless_cmp(at0->value, at1->value) >= 0) {
290 /* already sorted, so no bubbles to move exit inner loop */
295 edn->components[i]->attributes[k] = at1;
296 edn->components[i]->attributes[k + 1] = at0;
303 struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn)
305 struct ldb_dn *edn; /* the exploded dn */
308 /* Allocate a structure to hold the exploded DN */
309 edn = talloc(mem_ctx, struct ldb_dn);
310 LDB_DN_NULL_FAILED(edn);
312 /* Initially there are no components */
314 edn->components = NULL;
316 pdn = p = talloc_strdup(edn, dn);
320 /* get the components */
324 /* terminate the current component and return pointer to the next one */
325 t = seek_to_separator(p, ",;");
329 if (*t) { /* here there is a separator */
330 *t = '\0'; /*terminate */
331 t++; /* a separtor means there's another component that follows */
334 /* allocate space to hold the dn component */
335 edn->components = talloc_realloc(edn, edn->components,
336 struct ldb_dn_component *,
338 if (edn->components == NULL)
341 /* store the exploded component in the main structure */
342 edn->components[edn->comp_num] = explode_component(edn->components, p);
343 if (edn->components[edn->comp_num] == NULL)
348 /* jump to the next component if any */
353 /* sort attributes if there's any multivalued component */
354 ldb_dn_sort_attributes(edn);
364 char *ldb_dn_linearize(void *mem_ctx, struct ldb_dn *edn)
366 char *dn, *ename, *evalue;
370 dn = talloc_strdup(mem_ctx, "");
371 LDB_DN_NULL_FAILED(dn);
373 for (i = 0; i < edn->comp_num; i++) {
375 dn = talloc_append_string(mem_ctx, dn, ",");
377 for (j = 0; j < edn->components[i]->attr_num; j++) {
384 ename = escape_string(dn, edn->components[i]->attributes[j]->name);
385 LDB_DN_NULL_FAILED(ename);
387 evalue = escape_string(dn, edn->components[i]->attributes[j]->value);
388 LDB_DN_NULL_FAILED(evalue);
390 dn = talloc_asprintf_append(dn, format, ename, evalue);
391 LDB_DN_NULL_FAILED(dn);
404 /* FIXME: currently consider a dn composed of only case insensitive attributes
405 this is not correct and need to be fixed soon */
406 int ldb_dn_compare(struct ldb_dn *edn0, struct ldb_dn *edn1)
408 struct ldb_dn_attribute *at0, *at1;
411 /* if the number of components doesn't match they differ */
412 if (edn0->comp_num != edn1->comp_num)
413 return (edn1->comp_num - edn0->comp_num);
415 for (i = 0; i < edn0->comp_num; i++) {
417 /* if the number of attributes per component doesn't match they differ */
418 if (edn0->components[i]->attr_num != edn1->components[i]->attr_num)
419 return (edn1->components[i]->attr_num - edn0->components[i]->attr_num);
421 for (j = 0; j < edn0->components[i]->attr_num; j++) {
422 at0 = edn0->components[i]->attributes[j];
423 at1 = edn1->components[i]->attributes[j];
426 k = ldb_caseless_cmp(at0->name, at1->name);
430 /* names match, compare values */
431 k = ldb_caseless_cmp(at0->value, at1->value);
441 casefold a dn. We need to uppercase the attribute names, and the
442 attribute values of case insensitive attributes. We also need to remove
443 extraneous spaces between elements
445 struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, struct ldb_dn *edn)
450 cedn = talloc(ldb, struct ldb_dn);
451 LDB_DN_NULL_FAILED(cedn);
453 cedn->comp_num = edn->comp_num;
454 cedn->components = talloc_array(cedn, struct ldb_dn_component *, edn->comp_num);
455 LDB_DN_NULL_FAILED(cedn->components);
457 for (i = 0; i < edn->comp_num; i++) {
458 struct ldb_dn_component *dc;
460 dc = talloc(cedn->components, struct ldb_dn_component);
461 LDB_DN_NULL_FAILED(dc);
463 dc->attr_num = edn->components[i]->attr_num;
464 dc->attributes = edn->components[i]->attributes;
465 LDB_DN_NULL_FAILED(dc->attributes);
467 for (j = 0; j < edn->components[i]->attr_num; j++) {
468 struct ldb_dn_attribute *at;
469 struct ldb_val v0, v;
470 const struct ldb_attrib_handler *h;
472 at = talloc(dc->attributes, struct ldb_dn_attribute);
473 LDB_DN_NULL_FAILED(at);
475 at->name = ldb_casefold(at, edn->components[i]->attributes[j]->name);
476 LDB_DN_NULL_FAILED(at->name);
478 h = ldb_attrib_handler(ldb, at->name);
479 /* at->value should be a ldb_val, work around
481 v0.data = edn->components[i]->attributes[j]->value;
482 v0.length = strlen(v0.data);
483 if (h->canonicalise_fn(ldb, &v0, &v) != 0) {
487 talloc_steal(at, v.data);
489 dc->attributes[j] = at;
492 cedn->components[i] = dc;