diff options
author | Andrew Tridgell <tridge@samba.org> | 2006-09-24 02:49:04 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:14:36 -0500 |
commit | 3e2c696e45b24b0192ab7b1ddaf1dd4d79571609 (patch) | |
tree | 9c4423bdb006f7c183fea0c87331d23e7043d0b1 /source3/lib/ldb/common/ldb_dn.c | |
parent | 0c3194816b513e3743ddcacd1eca2b683ca39b88 (diff) | |
download | samba-3e2c696e45b24b0192ab7b1ddaf1dd4d79571609.tar.gz samba-3e2c696e45b24b0192ab7b1ddaf1dd4d79571609.tar.bz2 samba-3e2c696e45b24b0192ab7b1ddaf1dd4d79571609.zip |
r18866: Jeremy and Volker have given the go-ahead on the group mapping ldb
code. Yay!
This first commit copies lib/ldb/ from Samba4. A huge congratulations
should go to Simo on this - he has put an enormous amount of work into
ldb, and it's great to see it go into the Samba3 tree.
(This used to be commit bbedf2e34315f5c420a3a05dfe22b1d5cf79f042)
Diffstat (limited to 'source3/lib/ldb/common/ldb_dn.c')
-rw-r--r-- | source3/lib/ldb/common/ldb_dn.c | 944 |
1 files changed, 944 insertions, 0 deletions
diff --git a/source3/lib/ldb/common/ldb_dn.c b/source3/lib/ldb/common/ldb_dn.c new file mode 100644 index 0000000000..a0f48723ab --- /dev/null +++ b/source3/lib/ldb/common/ldb_dn.c @@ -0,0 +1,944 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 2005 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * Name: ldb + * + * Component: ldb dn explode and utility functions + * + * Description: - explode a dn into it's own basic elements + * and put them in a structure + * - manipulate ldb_dn structures + * + * Author: Simo Sorce + */ + +#include "includes.h" +#include "ldb/include/includes.h" + +#define LDB_DN_NULL_FAILED(x) if (!(x)) goto failed + +#define LDB_SPECIAL "@SPECIAL" + +int ldb_dn_is_special(const struct ldb_dn *dn) +{ + if (dn == NULL || dn->comp_num != 1) return 0; + + return ! strcmp(dn->components[0].name, LDB_SPECIAL); +} + +int ldb_dn_check_special(const struct ldb_dn *dn, const char *check) +{ + if (dn == NULL || dn->comp_num != 1) return 0; + + return ! strcmp((char *)dn->components[0].value.data, check); +} + +char *ldb_dn_escape_value(void *mem_ctx, struct ldb_val value) +{ + const char *p, *s, *src; + char *d, *dst; + int len; + + if (!value.length) + return NULL; + + p = s = src = (const char *)value.data; + len = value.length; + + /* allocate destination string, it will be at most 3 times the source */ + dst = d = talloc_array(mem_ctx, char, len * 3 + 1); + LDB_DN_NULL_FAILED(dst); + + while (p - src < len) { + + p += strcspn(p, ",=\n+<>#;\\\""); + + if (p - src == len) /* found no escapable chars */ + break; + + memcpy(d, s, p - s); /* copy the part of the string before the stop */ + d += (p - s); /* move to current position */ + + if (*p) { /* it is a normal escapable character */ + *d++ = '\\'; + *d++ = *p++; + } else { /* we have a zero byte in the string */ + strncpy(d, "\00", 3); /* escape the zero */ + d = d + 3; + p++; /* skip the zero */ + } + s = p; /* move forward */ + } + + /* copy the last part (with zero) and return */ + memcpy(d, s, &src[len] - s + 1); + + return dst; + +failed: + talloc_free(dst); + return NULL; +} + +static struct ldb_val ldb_dn_unescape_value(void *mem_ctx, const char *src) +{ + struct ldb_val value; + unsigned x; + char *p, *dst = NULL, *end; + + memset(&value, 0, sizeof(value)); + + LDB_DN_NULL_FAILED(src); + + dst = p = talloc_memdup(mem_ctx, src, strlen(src) + 1); + LDB_DN_NULL_FAILED(dst); + + end = &dst[strlen(dst)]; + + while (*p) { + p += strcspn(p, ",=\n+<>#;\\\""); + + if (*p == '\\') { + if (strchr(",=\n+<>#;\\\"", p[1])) { + memmove(p, p + 1, end - (p + 1) + 1); + end--; + p++; + continue; + } + + if (sscanf(p + 1, "%02x", &x) == 1) { + *p = (unsigned char)x; + memmove(p + 1, p + 3, end - (p + 3) + 1); + end -= 2; + p++; + continue; + } + } + + /* a string with not escaped specials is invalid (tested) */ + if (*p != '\0') { + goto failed; + } + } + + value.length = end - dst; + value.data = (uint8_t *)dst; + return value; + +failed: + talloc_free(dst); + return value; +} + +/* check if the string contains quotes + * skips leading and trailing spaces + * - returns 0 if no quotes found + * - returns 1 if quotes are found and put their position + * in *quote_start and *quote_end parameters + * - return -1 if there are open quotes + */ + +static int get_quotes_position(const char *source, int *quote_start, int *quote_end) +{ + const char *p; + + if (source == NULL || quote_start == NULL || quote_end == NULL) return -1; + + p = source; + + /* check if there are quotes surrounding the value */ + p += strspn(p, " \n"); /* skip white spaces */ + + if (*p == '\"') { + *quote_start = p - source; + + p++; + while (*p != '\"') { + p = strchr(p, '\"'); + LDB_DN_NULL_FAILED(p); + + if (*(p - 1) == '\\') + p++; + } + + *quote_end = p - source; + return 1; + } + + return 0; + +failed: + return -1; +} + +static char *seek_to_separator(char *string, const char *separators) +{ + char *p, *q; + int ret, qs, qe, escaped; + + if (string == NULL || separators == NULL) return NULL; + + p = strchr(string, '='); + LDB_DN_NULL_FAILED(p); + + p++; + + /* check if there are quotes surrounding the value */ + + ret = get_quotes_position(p, &qs, &qe); + if (ret == -1) + return NULL; + + if (ret == 1) { /* quotes found */ + + p += qe; /* positioning after quotes */ + p += strspn(p, " \n"); /* skip white spaces after the quote */ + + if (strcspn(p, separators) != 0) /* if there are characters between quotes */ + return NULL; /* and separators, the dn is invalid */ + + return p; /* return on the separator */ + } + + /* no quotes found seek to separators */ + q = p; + do { + escaped = 0; + ret = strcspn(q, separators); + + if (q[ret - 1] == '\\') { + escaped = 1; + q = q + ret + 1; + } + } while (escaped); + + if (ret == 0 && p == q) /* no separators ?! bail out */ + return NULL; + + return q + ret; + +failed: + return NULL; +} + +static char *ldb_dn_trim_string(char *string, const char *edge) +{ + char *s, *p; + + /* seek out edge from start of string */ + s = string + strspn(string, edge); + + /* backwards skip from end of string */ + p = &s[strlen(s) - 1]; + while (p > s && strchr(edge, *p)) { + *p = '\0'; + p--; + } + + return s; +} + +/* we choosed to not support multpile valued components */ +static struct ldb_dn_component ldb_dn_explode_component(void *mem_ctx, char *raw_component) +{ + struct ldb_dn_component dc; + char *p; + int ret, qs, qe; + + memset(&dc, 0, sizeof(dc)); + + if (raw_component == NULL) { + return dc; + } + + /* find attribute type/value separator */ + p = strchr(raw_component, '='); + LDB_DN_NULL_FAILED(p); + + *p++ = '\0'; /* terminate name and point to value */ + + /* copy and trim name in the component */ + dc.name = talloc_strdup(mem_ctx, ldb_dn_trim_string(raw_component, " \n")); + if (!dc.name) + return dc; + + if (! ldb_valid_attr_name(dc.name)) { + goto failed; + } + + ret = get_quotes_position(p, &qs, &qe); + + switch (ret) { + case 0: /* no quotes trim the string */ + p = ldb_dn_trim_string(p, " \n"); + dc.value = ldb_dn_unescape_value(mem_ctx, p); + break; + + case 1: /* quotes found get the unquoted string */ + p[qe] = '\0'; + p = p + qs + 1; + dc.value.length = strlen(p); + dc.value.data = talloc_memdup(mem_ctx, p, dc.value.length + 1); + break; + + default: /* mismatched quotes ot other error, bail out */ + goto failed; + } + + if (dc.value.length == 0) { + goto failed; + } + + return dc; + +failed: + talloc_free(dc.name); + dc.name = NULL; + return dc; +} + +struct ldb_dn *ldb_dn_new(void *mem_ctx) +{ + struct ldb_dn *edn; + + edn = talloc(mem_ctx, struct ldb_dn); + LDB_DN_NULL_FAILED(edn); + + /* Initially there are no components */ + edn->comp_num = 0; + edn->components = NULL; + + return edn; + +failed: + return NULL; +} + +struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn) +{ + struct ldb_dn *edn; /* the exploded dn */ + char *pdn, *p; + + if (dn == NULL) return NULL; + + /* Allocate a structure to hold the exploded DN */ + edn = ldb_dn_new(mem_ctx); + pdn = NULL; + + /* Empty DNs */ + if (dn[0] == '\0') { + return edn; + } + + /* Special DNs case */ + if (dn[0] == '@') { + edn->comp_num = 1; + edn->components = talloc(edn, struct ldb_dn_component); + if (edn->components == NULL) goto failed; + edn->components[0].name = talloc_strdup(edn->components, LDB_SPECIAL); + if (edn->components[0].name == NULL) goto failed; + edn->components[0].value.data = (uint8_t *)talloc_strdup(edn->components, dn); + if (edn->components[0].value.data== NULL) goto failed; + edn->components[0].value.length = strlen(dn); + return edn; + } + + pdn = p = talloc_strdup(edn, dn); + LDB_DN_NULL_FAILED(pdn); + + /* get the components */ + do { + char *t; + + /* terminate the current component and return pointer to the next one */ + t = seek_to_separator(p, ",;"); + LDB_DN_NULL_FAILED(t); + + if (*t) { /* here there is a separator */ + *t = '\0'; /*terminate */ + t++; /* a separtor means another component follows */ + } + + /* allocate space to hold the dn component */ + edn->components = talloc_realloc(edn, edn->components, + struct ldb_dn_component, + edn->comp_num + 1); + if (edn->components == NULL) + goto failed; + + /* store the exploded component in the main structure */ + edn->components[edn->comp_num] = ldb_dn_explode_component(edn, p); + LDB_DN_NULL_FAILED(edn->components[edn->comp_num].name); + + edn->comp_num++; + + /* jump to the next component if any */ + p = t; + + } while(*p); + + talloc_free(pdn); + return edn; + +failed: + talloc_free(pdn); + talloc_free(edn); + return NULL; +} + +struct ldb_dn *ldb_dn_explode_or_special(void *mem_ctx, const char *dn) +{ + struct ldb_dn *edn; /* the exploded dn */ + + if (dn == NULL) return NULL; + + if (strncasecmp(dn, "<GUID=", 6) == 0) { + /* this is special DN returned when the + * exploded_dn control is used + */ + + /* Allocate a structure to hold the exploded DN */ + edn = ldb_dn_new(mem_ctx); + + edn->comp_num = 1; + edn->components = talloc(edn, struct ldb_dn_component); + if (edn->components == NULL) goto failed; + edn->components[0].name = talloc_strdup(edn->components, LDB_SPECIAL); + if (edn->components[0].name == NULL) goto failed; + edn->components[0].value.data = (uint8_t *)talloc_strdup(edn->components, dn); + if (edn->components[0].value.data== NULL) goto failed; + edn->components[0].value.length = strlen(dn); + return edn; + + } + + return ldb_dn_explode(mem_ctx, dn); + +failed: + talloc_free(edn); + return NULL; +} + +char *ldb_dn_linearize(void *mem_ctx, const struct ldb_dn *edn) +{ + char *dn, *value; + int i; + + if (edn == NULL) return NULL; + + /* Special DNs */ + if (ldb_dn_is_special(edn)) { + dn = talloc_strdup(mem_ctx, (char *)edn->components[0].value.data); + return dn; + } + + dn = talloc_strdup(mem_ctx, ""); + LDB_DN_NULL_FAILED(dn); + + for (i = 0; i < edn->comp_num; i++) { + value = ldb_dn_escape_value(dn, edn->components[i].value); + LDB_DN_NULL_FAILED(value); + + if (i == 0) { + dn = talloc_asprintf_append(dn, "%s=%s", edn->components[i].name, value); + } else { + dn = talloc_asprintf_append(dn, ",%s=%s", edn->components[i].name, value); + } + LDB_DN_NULL_FAILED(dn); + + talloc_free(value); + } + + return dn; + +failed: + talloc_free(dn); + return NULL; +} + +/* Determine if dn is below base, in the ldap tree. Used for + * evaluating a subtree search. + * 0 if they match, otherwise non-zero + */ + +int ldb_dn_compare_base(struct ldb_context *ldb, + const struct ldb_dn *base, + const struct ldb_dn *dn) +{ + int ret; + int n0, n1; + + if (base == NULL || base->comp_num == 0) return 0; + if (dn == NULL || dn->comp_num == 0) return -1; + + /* if the base has more componts than the dn, then they differ */ + if (base->comp_num > dn->comp_num) { + return (dn->comp_num - base->comp_num); + } + + n0 = base->comp_num - 1; + n1 = dn->comp_num - 1; + while (n0 >= 0 && n1 >= 0) { + const struct ldb_attrib_handler *h; + + /* compare names (attribute names are guaranteed to be ASCII only) */ + ret = ldb_attr_cmp(base->components[n0].name, + dn->components[n1].name); + if (ret) { + return ret; + } + + /* names match, compare values */ + h = ldb_attrib_handler(ldb, base->components[n0].name); + ret = h->comparison_fn(ldb, ldb, &(base->components[n0].value), + &(dn->components[n1].value)); + if (ret) { + return ret; + } + n1--; + n0--; + } + + return 0; +} + +/* compare DNs using casefolding compare functions. + + If they match, then return 0 + */ + +int ldb_dn_compare(struct ldb_context *ldb, + const struct ldb_dn *edn0, + const struct ldb_dn *edn1) +{ + if (edn0 == NULL || edn1 == NULL) return edn1 - edn0; + + if (edn0->comp_num != edn1->comp_num) + return (edn1->comp_num - edn0->comp_num); + + return ldb_dn_compare_base(ldb, edn0, edn1); +} + +int ldb_dn_cmp(struct ldb_context *ldb, const char *dn0, const char *dn1) +{ + struct ldb_dn *edn0; + struct ldb_dn *edn1; + int ret; + + if (dn0 == NULL || dn1 == NULL) return dn1 - dn0; + + edn0 = ldb_dn_explode_casefold(ldb, dn0); + if (edn0 == NULL) return 1; + + edn1 = ldb_dn_explode_casefold(ldb, dn1); + if (edn1 == NULL) { + talloc_free(edn0); + return -1; + } + + ret = ldb_dn_compare(ldb, edn0, edn1); + + talloc_free(edn0); + talloc_free(edn1); + + return ret; +} + +/* + casefold a dn. We need to casefold the attribute names, and canonicalize + attribute values of case insensitive attributes. +*/ +struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, const struct ldb_dn *edn) +{ + struct ldb_dn *cedn; + int i; + + if (edn == NULL) return NULL; + + cedn = ldb_dn_new(ldb); + if (!cedn) { + return NULL; + } + + cedn->comp_num = edn->comp_num; + cedn->components = talloc_array(cedn, struct ldb_dn_component, edn->comp_num); + if (!cedn->components) { + talloc_free(cedn); + return NULL; + } + + for (i = 0; i < edn->comp_num; i++) { + struct ldb_dn_component dc; + const struct ldb_attrib_handler *h; + + dc.name = ldb_attr_casefold(cedn, edn->components[i].name); + if (!dc.name) { + talloc_free(cedn); + return NULL; + } + + h = ldb_attrib_handler(ldb, dc.name); + if (h->canonicalise_fn(ldb, cedn, &(edn->components[i].value), &(dc.value)) != 0) { + talloc_free(cedn); + return NULL; + } + + cedn->components[i] = dc; + } + + return cedn; +} + +struct ldb_dn *ldb_dn_explode_casefold(struct ldb_context *ldb, const char *dn) +{ + struct ldb_dn *edn, *cdn; + + if (dn == NULL) return NULL; + + edn = ldb_dn_explode(ldb, dn); + if (edn == NULL) return NULL; + + cdn = ldb_dn_casefold(ldb, edn); + + talloc_free(edn); + return cdn; +} + +char *ldb_dn_linearize_casefold(struct ldb_context *ldb, const struct ldb_dn *edn) +{ + struct ldb_dn *cdn; + char *dn; + + if (edn == NULL) return NULL; + + /* Special DNs */ + if (ldb_dn_is_special(edn)) { + dn = talloc_strdup(ldb, (char *)edn->components[0].value.data); + return dn; + } + + cdn = ldb_dn_casefold(ldb, edn); + if (cdn == NULL) return NULL; + + dn = ldb_dn_linearize(ldb, cdn); + if (dn == NULL) { + talloc_free(cdn); + return NULL; + } + + talloc_free(cdn); + return dn; +} + +static struct ldb_dn_component ldb_dn_copy_component(void *mem_ctx, struct ldb_dn_component *src) +{ + struct ldb_dn_component dst; + + memset(&dst, 0, sizeof(dst)); + + if (src == NULL) { + return dst; + } + + dst.value = ldb_val_dup(mem_ctx, &(src->value)); + if (dst.value.data == NULL) { + return dst; + } + + dst.name = talloc_strdup(mem_ctx, src->name); + if (dst.name == NULL) { + talloc_free(dst.value.data); + } + + return dst; +} + +/* copy specified number of elements of a dn into a new one + element are copied from top level up to the unique rdn + num_el may be greater than dn->comp_num (see ldb_dn_make_child) +*/ +struct ldb_dn *ldb_dn_copy_partial(void *mem_ctx, const struct ldb_dn *dn, int num_el) +{ + struct ldb_dn *newdn; + int i, n, e; + + if (dn == NULL) return NULL; + if (num_el <= 0) return NULL; + + newdn = ldb_dn_new(mem_ctx); + LDB_DN_NULL_FAILED(newdn); + + newdn->comp_num = num_el; + n = newdn->comp_num - 1; + newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num); + + if (dn->comp_num == 0) return newdn; + e = dn->comp_num - 1; + + for (i = 0; i < newdn->comp_num; i++) { + newdn->components[n - i] = ldb_dn_copy_component(newdn->components, + &(dn->components[e - i])); + if ((e - i) == 0) { + return newdn; + } + } + + return newdn; + +failed: + talloc_free(newdn); + return NULL; +} + +struct ldb_dn *ldb_dn_copy(void *mem_ctx, const struct ldb_dn *dn) +{ + if (dn == NULL) return NULL; + return ldb_dn_copy_partial(mem_ctx, dn, dn->comp_num); +} + +struct ldb_dn *ldb_dn_get_parent(void *mem_ctx, const struct ldb_dn *dn) +{ + if (dn == NULL) return NULL; + return ldb_dn_copy_partial(mem_ctx, dn, dn->comp_num - 1); +} + +struct ldb_dn_component *ldb_dn_build_component(void *mem_ctx, const char *attr, + const char *val) +{ + struct ldb_dn_component *dc; + + if (attr == NULL || val == NULL) return NULL; + + dc = talloc(mem_ctx, struct ldb_dn_component); + if (dc == NULL) return NULL; + + dc->name = talloc_strdup(dc, attr); + if (dc->name == NULL) { + talloc_free(dc); + return NULL; + } + + dc->value.data = (uint8_t *)talloc_strdup(dc, val); + if (dc->value.data == NULL) { + talloc_free(dc); + return NULL; + } + + dc->value.length = strlen(val); + + return dc; +} + +struct ldb_dn *ldb_dn_build_child(void *mem_ctx, const char *attr, + const char * value, + const struct ldb_dn *base) +{ + struct ldb_dn *newdn; + if (! ldb_valid_attr_name(attr)) return NULL; + if (value == NULL || value == '\0') return NULL; + + if (base != NULL) { + newdn = ldb_dn_copy_partial(mem_ctx, base, base->comp_num + 1); + LDB_DN_NULL_FAILED(newdn); + } else { + newdn = ldb_dn_new(mem_ctx); + LDB_DN_NULL_FAILED(newdn); + + newdn->comp_num = 1; + newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num); + } + + newdn->components[0].name = talloc_strdup(newdn->components, attr); + LDB_DN_NULL_FAILED(newdn->components[0].name); + + newdn->components[0].value.data = (uint8_t *)talloc_strdup(newdn->components, value); + LDB_DN_NULL_FAILED(newdn->components[0].value.data); + newdn->components[0].value.length = strlen((char *)newdn->components[0].value.data); + + return newdn; + +failed: + talloc_free(newdn); + return NULL; + +} + +struct ldb_dn *ldb_dn_make_child(void *mem_ctx, const struct ldb_dn_component *component, + const struct ldb_dn *base) +{ + if (component == NULL) return NULL; + + return ldb_dn_build_child(mem_ctx, component->name, + (char *)component->value.data, base); +} + +struct ldb_dn *ldb_dn_compose(void *mem_ctx, const struct ldb_dn *dn1, const struct ldb_dn *dn2) +{ + int i; + struct ldb_dn *newdn; + + if (dn2 == NULL && dn1 == NULL) { + return NULL; + } + + if (dn2 == NULL) { + newdn = ldb_dn_new(mem_ctx); + LDB_DN_NULL_FAILED(newdn); + + newdn->comp_num = dn1->comp_num; + newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num); + } else { + int comp_num = dn2->comp_num; + if (dn1 != NULL) comp_num += dn1->comp_num; + newdn = ldb_dn_copy_partial(mem_ctx, dn2, comp_num); + } + + if (dn1 == NULL) { + return newdn; + } + + for (i = 0; i < dn1->comp_num; i++) { + newdn->components[i] = ldb_dn_copy_component(newdn->components, + &(dn1->components[i])); + } + + return newdn; + +failed: + talloc_free(newdn); + return NULL; +} + +struct ldb_dn *ldb_dn_string_compose(void *mem_ctx, const struct ldb_dn *base, const char *child_fmt, ...) +{ + struct ldb_dn *dn; + char *child_str; + va_list ap; + + if (child_fmt == NULL) return NULL; + + va_start(ap, child_fmt); + child_str = talloc_vasprintf(mem_ctx, child_fmt, ap); + va_end(ap); + + if (child_str == NULL) return NULL; + + dn = ldb_dn_compose(mem_ctx, ldb_dn_explode(mem_ctx, child_str), base); + + talloc_free(child_str); + + return dn; +} + +struct ldb_dn_component *ldb_dn_get_rdn(void *mem_ctx, const struct ldb_dn *dn) +{ + struct ldb_dn_component *rdn; + + if (dn == NULL) return NULL; + + if (dn->comp_num < 1) { + return NULL; + } + + rdn = talloc(mem_ctx, struct ldb_dn_component); + if (rdn == NULL) return NULL; + + *rdn = ldb_dn_copy_component(mem_ctx, &dn->components[0]); + if (rdn->name == NULL) { + talloc_free(rdn); + return NULL; + } + + return rdn; +} + +/* Create a 'canonical name' string from a DN: + + ie dc=samba,dc=org -> samba.org/ + uid=administrator,ou=users,dc=samba,dc=org = samba.org/users/administrator + + There are two formats, the EX format has the last / replaced with a newline (\n). + +*/ +static char *ldb_dn_canonical(void *mem_ctx, const struct ldb_dn *dn, int ex_format) { + int i; + char *cracked = NULL; + + /* Walk backwards down the DN, grabbing 'dc' components at first */ + for (i = dn->comp_num - 1 ; i >= 0; i--) { + if (ldb_attr_cmp(dn->components[i].name, "dc") != 0) { + break; + } + if (cracked) { + cracked = talloc_asprintf(mem_ctx, "%s.%s", + ldb_dn_escape_value(mem_ctx, dn->components[i].value), + cracked); + } else { + cracked = ldb_dn_escape_value(mem_ctx, dn->components[i].value); + } + if (!cracked) { + return NULL; + } + } + + /* Only domain components? Finish here */ + if (i < 0) { + if (ex_format) { + cracked = talloc_asprintf(mem_ctx, "%s\n", cracked); + } else { + cracked = talloc_asprintf(mem_ctx, "%s/", cracked); + } + return cracked; + } + + /* Now walk backwards appending remaining components */ + for (; i > 0; i--) { + cracked = talloc_asprintf(mem_ctx, "%s/%s", cracked, + ldb_dn_escape_value(mem_ctx, dn->components[i].value)); + if (!cracked) { + return NULL; + } + } + + /* Last one, possibly a newline for the 'ex' format */ + if (ex_format) { + cracked = talloc_asprintf(mem_ctx, "%s\n%s", cracked, + ldb_dn_escape_value(mem_ctx, dn->components[i].value)); + } else { + cracked = talloc_asprintf(mem_ctx, "%s/%s", cracked, + ldb_dn_escape_value(mem_ctx, dn->components[i].value)); + } + return cracked; +} + +/* Wrapper functions for the above, for the two different string formats */ +char *ldb_dn_canonical_string(void *mem_ctx, const struct ldb_dn *dn) { + return ldb_dn_canonical(mem_ctx, dn, 0); + +} + +char *ldb_dn_canonical_ex_string(void *mem_ctx, const struct ldb_dn *dn) { + return ldb_dn_canonical(mem_ctx, dn, 1); +} |