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"
42 #define LDB_DN_NULL_FAILED(x) if (!(x)) goto failed
44 static int ldb_dn_is_valid_attribute_name(const char *name)
47 if (! isascii(*name)) {
50 if (! (isalnum((unsigned char)*name) || *name == '-')) {
59 char *ldb_dn_escape_value(void *mem_ctx, struct ldb_val value)
61 const char *p, *s, *src;
68 p = s = src = (const char *)value.data;
71 /* allocate destination string, it will be at most 3 times the source */
72 dst = d = talloc_array(mem_ctx, char, len * 3 + 1);
73 LDB_DN_NULL_FAILED(dst);
75 while (p - src < len) {
77 p += strcspn(p, ",=\n+<>#;\\\"");
79 if (p - src == len) /* found no escapable chars */
82 memcpy(d, s, p - s); /* copy the part of the string before the stop */
83 d += (p - s); /* move to current position */
85 if (*p) { /* it is a normal escapable character */
88 } else { /* we have a zero byte in the string */
89 strncpy(d, "\00", 3); /* escape the zero */
91 p++; /* skip the zero */
93 s = p; /* move forward */
96 /* copy the last part (with zero) and return */
97 memcpy(d, s, &src[len] - s + 1);
106 static struct ldb_val ldb_dn_unescape_value(void *mem_ctx, const char *src)
108 struct ldb_val value;
110 char *p, *dst = NULL, *end;
114 LDB_DN_NULL_FAILED(src);
116 dst = p = talloc_memdup(mem_ctx, src, strlen(src) + 1);
117 LDB_DN_NULL_FAILED(dst);
119 end = &dst[strlen(dst)];
122 p += strcspn(p, ",=\n+<>#;\\\"");
125 if (strchr(",=\n+<>#;\\\"", p[1])) {
126 memmove(p, p + 1, end - (p + 1) + 1);
132 if (sscanf(p + 1, "%02x", &x) == 1) {
133 *p = (unsigned char)x;
134 memmove(p + 1, p + 3, end - (p + 3) + 1);
141 /* a string with not escaped specials is invalid (tested) */
147 value.length = end - dst;
156 /* check if the string contains quotes
157 * skips leading and trailing spaces
158 * - returns 0 if no quotes found
159 * - returns 1 if quotes are found and put their position
160 * in *quote_start and *quote_end parameters
161 * - return -1 if there are open quotes
164 static int get_quotes_position(const char *source, int *quote_start, int *quote_end)
170 /* check if there are quotes surrounding the value */
171 p += strspn(p, " \n"); /* skip white spaces */
174 *quote_start = p - source;
179 LDB_DN_NULL_FAILED(p);
181 if (*(p - 1) == '\\')
185 *quote_end = p - source;
195 static char *seek_to_separator(char *string, const char *separators)
200 p = strchr(string, '=');
201 LDB_DN_NULL_FAILED(p);
205 /* check if there are quotes surrounding the value */
207 ret = get_quotes_position(p, &qs, &qe);
211 if (ret == 1) { /* quotes found */
213 p += qe; /* positioning after quotes */
214 p += strspn(p, " \n"); /* skip white spaces after the quote */
216 if (strcspn(p, separators) != 0) /* if there are characters between quotes */
217 return NULL; /* and separators, the dn is invalid */
219 return p; /* return on the separator */
222 /* no quotes found seek to separators */
223 ret = strcspn(p, separators);
224 if (ret == 0) /* no separators ?! bail out */
233 static char *ldb_dn_trim_string(char *string, const char *edge)
237 /* seek out edge from start of string */
238 s = string + strspn(string, edge);
240 /* backwards skip from end of string */
241 p = &s[strlen(s) - 1];
242 while (p > s && strchr(edge, *p)) {
250 /* we choosed to not support multpile valued components */
251 static struct ldb_dn_component ldb_dn_explode_component(void *mem_ctx, char *raw_component)
253 struct ldb_dn_component dc;
257 /* find attribute type/value separator */
258 p = strchr(raw_component, '=');
259 LDB_DN_NULL_FAILED(p);
261 *p++ = '\0'; /* terminate name and point to value */
263 /* copy and trim name in the component */
264 dc.name = talloc_strdup(mem_ctx, ldb_dn_trim_string(raw_component, " \n"));
268 if (! ldb_dn_is_valid_attribute_name(dc.name)) {
272 ret = get_quotes_position(p, &qs, &qe);
275 case 0: /* no quotes trim the string */
276 p = ldb_dn_trim_string(p, " \n");
277 dc.value = ldb_dn_unescape_value(mem_ctx, p);
280 case 1: /* quotes found get the unquoted string */
283 dc.value.length = strlen(p);
284 dc.value.data = talloc_memdup(mem_ctx, p, dc.value.length + 1);
287 default: /* mismatched quotes ot other error, bail out */
291 if (dc.value.length == 0) {
298 talloc_free(dc.name);
303 struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn)
305 struct ldb_dn *edn; /* the exploded dn */
310 /* Allocate a structure to hold the exploded DN */
311 edn = talloc(mem_ctx, struct ldb_dn);
312 LDB_DN_NULL_FAILED(edn);
314 /* Initially there are no components */
316 edn->components = NULL;
318 /* Special DNs case */
321 edn->components = talloc(edn, struct ldb_dn_component);
322 if (edn->components == NULL) goto failed;
323 edn->components[0].name = talloc_strdup(edn->components, "@SPECIAL");
324 if (edn->components[0].name == NULL) goto failed;
325 edn->components[0].value.data = talloc_strdup(edn->components, dn);
326 if (edn->components[0].value.data== NULL) goto failed;
327 edn->components[0].value.length = strlen(dn);
331 pdn = p = talloc_strdup(edn, dn);
332 LDB_DN_NULL_FAILED(pdn);
334 /* get the components */
338 /* terminate the current component and return pointer to the next one */
339 t = seek_to_separator(p, ",;");
340 LDB_DN_NULL_FAILED(t);
342 if (*t) { /* here there is a separator */
343 *t = '\0'; /*terminate */
344 t++; /* a separtor means another component follows */
347 /* allocate space to hold the dn component */
348 edn->components = talloc_realloc(edn, edn->components,
349 struct ldb_dn_component,
351 if (edn->components == NULL)
354 /* store the exploded component in the main structure */
355 edn->components[edn->comp_num] = ldb_dn_explode_component(edn, p);
356 LDB_DN_NULL_FAILED(edn->components[edn->comp_num].name);
360 /* jump to the next component if any */
374 char *ldb_dn_linearize(void *mem_ctx, const struct ldb_dn *edn)
380 if ((edn->comp_num == 1) && strcmp("@SPECIAL", edn->components[0].name) == 0) {
381 dn = talloc_strdup(mem_ctx, edn->components[0].value.data);
385 dn = talloc_strdup(mem_ctx, "");
386 LDB_DN_NULL_FAILED(dn);
388 for (i = 0; i < edn->comp_num; i++) {
389 value = ldb_dn_escape_value(dn, edn->components[i].value);
390 LDB_DN_NULL_FAILED(value);
393 dn = talloc_asprintf_append(dn, "%s=%s", edn->components[i].name, value);
395 dn = talloc_asprintf_append(dn, ",%s=%s", edn->components[i].name, value);
397 LDB_DN_NULL_FAILED(dn);
409 /* compare DNs using casefolding compare functions */
411 int ldb_dn_compare_base(struct ldb_context *ldb,
412 const struct ldb_dn *base,
413 const struct ldb_dn *dn)
418 if (base->comp_num > dn->comp_num) {
419 return (dn->comp_num - base->comp_num);
422 /* if the number of components doesn't match they differ */
423 n0 = base->comp_num - 1;
424 n1 = dn->comp_num - 1;
425 while (n0 >= 0 && n1 >= 0) {
426 const struct ldb_attrib_handler *h;
428 /* compare names (attribute names are guaranteed to be ASCII only) */
429 ret = ldb_caseless_cmp(base->components[n0].name,
430 dn->components[n1].name);
435 /* names match, compare values */
436 h = ldb_attrib_handler(ldb, base->components[n0].name);
437 ret = h->comparison_fn(ldb, ldb, &(base->components[n0].value),
438 &(dn->components[n1].value));
449 int ldb_dn_compare(struct ldb_context *ldb,
450 const struct ldb_dn *edn0,
451 const struct ldb_dn *edn1)
453 if (edn0->comp_num != edn1->comp_num)
454 return (edn1->comp_num - edn0->comp_num);
456 return ldb_dn_compare_base(ldb, edn0, edn1);
459 int ldb_dn_cmp(struct ldb_context *ldb, const char *dn0, const char *dn1)
465 edn0 = ldb_dn_explode_casefold(ldb, dn0);
466 if (edn0 == NULL) return 0;
468 edn1 = ldb_dn_explode_casefold(ldb, dn1);
474 ret = ldb_dn_compare(ldb, edn0, edn1);
483 casefold a dn. We need to casefold the attribute names, and canonicalize
484 attribute values of case insensitive attributes.
486 struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, const struct ldb_dn *edn)
491 cedn = talloc(ldb, struct ldb_dn);
492 LDB_DN_NULL_FAILED(cedn);
494 cedn->comp_num = edn->comp_num;
495 cedn->components = talloc_array(cedn, struct ldb_dn_component, edn->comp_num);
496 LDB_DN_NULL_FAILED(cedn->components);
498 for (i = 0; i < edn->comp_num; i++) {
499 struct ldb_dn_component dc;
500 const struct ldb_attrib_handler *h;
502 dc.name = ldb_casefold(cedn, edn->components[i].name);
503 LDB_DN_NULL_FAILED(dc.name);
505 h = ldb_attrib_handler(ldb, dc.name);
506 if (h->canonicalise_fn(ldb, cedn, &(edn->components[i].value), &(dc.value)) != 0) {
510 cedn->components[i] = dc;
520 struct ldb_dn *ldb_dn_explode_casefold(struct ldb_context *ldb, const char *dn)
522 struct ldb_dn *edn, *cdn;
524 edn = ldb_dn_explode(ldb, dn);
525 if (edn == NULL) return NULL;
527 cdn = ldb_dn_casefold(ldb, edn);