4 Copyright (C) Simo Sorce 2004
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_RETURN(x) do { if (!x) return NULL; } while(0)
45 static char *escape_string(void *mem_ctx, const char *src)
50 LDB_DN_NULL_RETURN(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_RETURN(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);
78 static char *unescape_string(void *mem_ctx, const char *src)
83 LDB_DN_NULL_RETURN(src);
85 dst = p = talloc_strdup(mem_ctx, src);
86 LDB_DN_NULL_RETURN(dst);
88 end = &dst[strlen(dst)];
91 p += strcspn(p, ",=\n+<>#;\\\"");
92 if (*p == '\0') /* no escapes or specials found, all ok */
96 if (strchr(",=\n+<>#;\\\"", p[1])) {
97 memmove(p, p + 1, end - (p + 1) + 1);
103 if (sscanf(p + 1, "%02x", &x) == 1) {
104 *p = (unsigned char)x;
105 memmove(p + 1, p + 3, end - (p + 3) + 1);
112 /* a string with not escaped specials is invalid */
120 static char *seek_to_separator(char *string, const char *separator)
124 p = strchr(string, '=');
126 LDB_DN_NULL_RETURN(p);
130 /* check if there are quotes surrounding the value */
131 p += strspn(p, " \n"); /* skip white spaces after '=' */
137 LDB_DN_NULL_RETURN(p);
139 if (*(p - 1) == '\\')
144 p += strcspn(p, separator);
149 static char *ldb_dn_trim_string(char *string, const char *edge)
153 /* seek out edge from start of string */
154 s = string + strspn(string, edge);
156 /* backwards skip from end of string */
157 p = &s[strlen(s) - 1];
158 while (p > s && strchr(edge, *p)) {
166 static struct ldb_dn_attribute *ldb_dn_explode_attribute(void *mem_ctx, char *raw_attribute)
168 struct ldb_dn_attribute *at;
171 at = talloc(mem_ctx, struct ldb_dn_attribute);
172 LDB_DN_NULL_RETURN(at);
174 p = strchr(raw_attribute, '=');
176 LDB_DN_NULL_RETURN(p);
180 at->name = talloc_strdup(at, ldb_dn_trim_string(raw_attribute, " \n"));
181 LDB_DN_NULL_RETURN(at->name);
185 p = ldb_dn_trim_string(p, " \n");
187 if (*p == '\"') { /* quotes at start means there must be quotes at the end */
188 if (p[strlen(p) - 1] != '\"') /* malformed value */
192 p[strlen(p) - 1] = '\0';
193 at->value = talloc_strdup(at, p);
197 /* no quotes means we must unescape the string */
198 at->value = unescape_string(at, p);
199 LDB_DN_NULL_RETURN(at->value);
204 static struct ldb_dn_component *explode_component(void *mem_ctx, char *raw_component)
206 struct ldb_dn_component *dc;
209 dc = talloc(mem_ctx, struct ldb_dn_component);
210 LDB_DN_NULL_RETURN(dc);
213 dc->attributes = NULL;
217 /* get the components */
221 /* terminate the current attribute and return pointer to the next one */
222 t = seek_to_separator(p, "+");
223 LDB_DN_NULL_RETURN(t);
225 if (*t) { /* here there is a separator */
226 *t = '\0'; /*terminate */
227 t++; /* a separtor means there's another attribute that follows */
230 /* allocate attributes pointer */
231 dc->attributes = talloc_realloc(dc, dc->attributes,
232 struct ldb_dn_attribute *,
234 LDB_DN_NULL_RETURN(dc->attributes);
236 /* store the exploded attirbute in the main structure */
237 dc->attributes[dc->attr_num] = ldb_dn_explode_attribute(dc->attributes, p);
238 LDB_DN_NULL_RETURN(dc->attributes[dc->attr_num]);
242 /* jump to the next attribute if any */
250 /* FIXME: currently consider a dn composed of only case insensitive attributes
251 this is not correct and need to be fixed soon */
252 static void ldb_dn_sort_attributes(struct ldb_dn *edn)
254 struct ldb_dn_attribute *at0, *at1;
257 for (i = 0; i < edn->comp_num; i++) {
258 if (edn->components[i]->attr_num > 1) {
260 /* it is very unlikely that there is a multivalued RDN. In that
261 unlikely case it is very unlikely you will find more than 2
262 values. So the use of bubble sort here seem to be acceptable */
263 for (j = 0; (j + 1) < edn->components[i]->attr_num; j++) {
264 for (k = j; k >= 0; k--) {
265 at0 = edn->components[i]->attributes[k];
266 at1 = edn->components[i]->attributes[k + 1];
267 l = ldb_caseless_cmp(at0->name, at1->name);
269 /* already sorted, so no bubbles to move exit inner loop */
273 if (ldb_caseless_cmp(at0->value, at1->value) >= 0) {
274 /* already sorted, so no bubbles to move exit inner loop */
279 edn->components[i]->attributes[k] = at1;
280 edn->components[i]->attributes[k + 1] = at0;
287 struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn)
289 struct ldb_dn *edn; /* the exploded dn */
292 /* Allocate a structure to hold the exploded DN */
293 edn = talloc(mem_ctx, struct ldb_dn);
294 LDB_DN_NULL_RETURN(edn);
296 /* Initially there are no components */
298 edn->components = NULL;
300 pdn = p = talloc_strdup(edn, dn);
304 /* get the components */
308 /* terminate the current component and return pointer to the next one */
309 t = seek_to_separator(p, ",;");
313 if (*t) { /* here there is a separator */
314 *t = '\0'; /*terminate */
315 t++; /* a separtor means there's another component that follows */
318 /* allocate space to hold the dn component */
319 edn->components = talloc_realloc(edn, edn->components,
320 struct ldb_dn_component *,
322 if (edn->components == NULL)
325 /* store the exploded component in the main structure */
326 edn->components[edn->comp_num] = explode_component(edn->components, p);
327 if (edn->components[edn->comp_num] == NULL)
332 /* jump to the next component if any */
337 /* sort attributes if there's any multivalued component */
338 ldb_dn_sort_attributes(edn);
348 char *ldb_dn_linearize(void *mem_ctx, struct ldb_dn *edn)
350 char *dn, *format, *ename, *evalue;
353 dn = talloc_strdup(mem_ctx, "");
354 LDB_DN_NULL_RETURN(dn);
356 for (i = 0; i < edn->comp_num; i++) {
358 dn = talloc_append_string(mem_ctx, dn, ",");
360 for (j = 0; j < edn->components[i]->attr_num; j++) {
361 if (i != 0 && j == 0)
363 else if (i == 0 && j == 0)
368 ename = escape_string(mem_ctx, edn->components[i]->attributes[j]->name);
369 LDB_DN_NULL_RETURN(ename);
371 evalue = escape_string(mem_ctx, edn->components[i]->attributes[j]->value);
372 LDB_DN_NULL_RETURN(evalue);
374 dn = talloc_asprintf_append(dn, format, ename, evalue);
375 LDB_DN_NULL_RETURN(dn);
385 /* FIXME: currently consider a dn composed of only case insensitive attributes
386 this is not correct and need to be fixed soon */
387 int ldb_dn_compare(struct ldb_dn *edn0, struct ldb_dn *edn1)
389 struct ldb_dn_attribute *at0, *at1;
392 /* if the number of components doesn't match they differ */
393 if (edn0->comp_num != edn1->comp_num)
394 return (edn1->comp_num - edn0->comp_num);
396 for (i = 0; i < edn0->comp_num; i++) {
398 /* if the number of attributes per component doesn't match they differ */
399 if (edn0->components[i]->attr_num != edn1->components[i]->attr_num)
400 return (edn1->components[i]->attr_num - edn0->components[i]->attr_num);
402 for (j = 0; j < edn0->components[i]->attr_num; j++) {
403 at0 = edn0->components[i]->attributes[j];
404 at1 = edn1->components[i]->attributes[j];
407 k = ldb_caseless_cmp(at0->name, at1->name);
411 /* names match, compare values */
412 k = ldb_caseless_cmp(at0->value, at1->value);
420 casefold a dn. We need to uppercase the attribute names, and the
421 attribute values of case insensitive attributes. We also need to remove
422 extraneous spaces between elements
424 struct ldb_dn *ldb_dn_casefold(void *mem_ctx, struct ldb_dn *edn, void *user_data,
425 int (* case_fold_attr_fn)(void * user_data, char * attr))
430 cedn = talloc(mem_ctx, struct ldb_dn);
431 LDB_DN_NULL_RETURN(cedn);
433 cedn->comp_num = edn->comp_num;
434 cedn->components = talloc_array(cedn, struct ldb_dn_component *, edn->comp_num);
435 LDB_DN_NULL_RETURN(cedn->components);
437 for (i = 0; i < edn->comp_num; i++) {
438 struct ldb_dn_component *dc;
440 dc = talloc(cedn->components, struct ldb_dn_component);
441 LDB_DN_NULL_RETURN(dc);
443 dc->attr_num = edn->components[i]->attr_num;
444 dc->attributes = edn->components[i]->attributes;
445 LDB_DN_NULL_RETURN(dc->attributes);
447 for (j = 0; j < edn->components[i]->attr_num; j++) {
448 struct ldb_dn_attribute *at;
450 at = talloc(dc->attributes, struct ldb_dn_attribute);
451 LDB_DN_NULL_RETURN(at);
453 at->name = ldb_casefold(at, edn->components[i]->attributes[j]->name);
454 LDB_DN_NULL_RETURN(at->name);
456 if (case_fold_attr_fn(user_data, at->name)) {
457 at->value = ldb_casefold(at, edn->components[i]->attributes[j]->value);
459 at->value = talloc_strdup(at, edn->components[i]->attributes[j]->value);
461 LDB_DN_NULL_RETURN(at->value);
463 dc->attributes[j] = at;
466 cedn->components[i] = dc;