summaryrefslogtreecommitdiff
path: root/source4/lib/ldb/common/ldb_dn.c
diff options
context:
space:
mode:
authorSimo Sorce <idra@samba.org>2005-07-02 17:30:03 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:19:06 -0500
commit1c5105065a44173667de2a022dd2417e56b527d6 (patch)
tree165be48497b07108926b29cc9b9e94f79ab9632d /source4/lib/ldb/common/ldb_dn.c
parent2e419725b0e7b4dcb43340ae93ae7bb60b4a5597 (diff)
downloadsamba-1c5105065a44173667de2a022dd2417e56b527d6.tar.gz
samba-1c5105065a44173667de2a022dd2417e56b527d6.tar.bz2
samba-1c5105065a44173667de2a022dd2417e56b527d6.zip
r8082: large rewite of ldb_dn.c
- we do not support multpiple attribute components anymore, makes code a lot easier they will be readded later if we found out they are really used, so far my tests show w2k3 do not handle them as well - fix escaping issues, move component value to be in an ldb_val structure still need to handle binary values case - make cononicalize functions leak less memory by giving a specific memory context - fix tests scripts so that test-ldap can start - make test not delete databases on completion so that I can inspect them (This used to be commit 624a73148d125690ce18515f19231d26df207738)
Diffstat (limited to 'source4/lib/ldb/common/ldb_dn.c')
-rw-r--r--source4/lib/ldb/common/ldb_dn.c410
1 files changed, 175 insertions, 235 deletions
diff --git a/source4/lib/ldb/common/ldb_dn.c b/source4/lib/ldb/common/ldb_dn.c
index f147197499..18b620b506 100644
--- a/source4/lib/ldb/common/ldb_dn.c
+++ b/source4/lib/ldb/common/ldb_dn.c
@@ -37,63 +37,74 @@
#include "includes.h"
#include "ldb/include/ldb.h"
#include "ldb/include/ldb_private.h"
-#include "ldb/include/ldb_dn.h"
#define LDB_DN_NULL_FAILED(x) if (!(x)) goto failed
-static char *escape_string(void *mem_ctx, const char *src)
+static char *ldb_dn_escape_value(void *mem_ctx, struct ldb_val value)
{
- const char *p, *s;
- char *d, *dst=NULL;
+ const char *p, *s, *src;
+ char *d, *dst;
+ int len;
- LDB_DN_NULL_FAILED(src);
+ 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, strlen(src) * 3 + 1);
+ dst = d = talloc_array(mem_ctx, char, len * 3 + 1);
LDB_DN_NULL_FAILED(dst);
- p = s = src;
+ while (p - src < len) {
- while (*p) {
p += strcspn(p, ",=\n+<>#;\\\"");
- if (*p == '\0') /* no special s found, all ok */
+
+ if (p - src == len) /* found no escapable chars */
break;
- if (*p) { /* copy part of the string and escape */
- memcpy(d, s, p - s);
- d += (p - s);
+ 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++;
- s = 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[strlen(src)] - s + 1);
+ memcpy(d, s, &src[len] - s + 1);
return dst;
+
failed:
talloc_free(dst);
return NULL;
}
-static char *unescape_string(void *mem_ctx, const char *src)
+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;
+ char *p, *dst = NULL, *end;
+
+ value.length = 0;
LDB_DN_NULL_FAILED(src);
- dst = p = talloc_strdup(mem_ctx, 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 == '\0') /* no escapes or specials found, all ok */
- return dst;
if (*p == '\\') {
if (strchr(",=\n+<>#;\\\"", p[1])) {
@@ -112,31 +123,41 @@ static char *unescape_string(void *mem_ctx, const char *src)
}
}
- /* a string with not escaped specials is invalid */
-
- return NULL;
+ /* a string with not escaped specials is invalid (tested) */
+ if (*p != '\0') {
+ goto failed;
+ }
}
- return dst;
+ value.length = end - dst;
+ value.data = dst;
+ return value;
+
failed:
talloc_free(dst);
- return NULL;
+ return value;
}
-static char *seek_to_separator(char *string, const char *separator)
-{
- char *p;
-
- p = strchr(string, '=');
+/* 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
+ */
- LDB_DN_NULL_FAILED(p);
+static int get_quotes_position(const char *source, int *quote_start, int *quote_end)
+{
+ const char *p;
- p++;
+ p = source;
/* check if there are quotes surrounding the value */
- p += strspn(p, " \n"); /* skip white spaces after '=' */
+ p += strspn(p, " \n"); /* skip white spaces */
if (*p == '\"') {
+ *quote_start = p - source;
+
p++;
while (*p != '\"') {
p = strchr(p, '\"');
@@ -145,11 +166,50 @@ static char *seek_to_separator(char *string, const char *separator)
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;
+ int ret, qs, qe;
+
+ 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 */
}
- p += strcspn(p, separator);
+ /* no quotes found seek to separators */
+ ret = strcspn(p, separators);
+ if (ret == 0) /* no separators ?! bail out */
+ return NULL;
- return p;
+ return p + ret;
failed:
return NULL;
@@ -172,132 +232,53 @@ static char *ldb_dn_trim_string(char *string, const char *edge)
return s;
}
-static struct ldb_dn_attribute *ldb_dn_explode_attribute(void *mem_ctx, char *raw_attribute)
+/* 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_attribute *at;
+ struct ldb_dn_component dc;
char *p;
+ int ret, qs, qe;
- at = talloc(mem_ctx, struct ldb_dn_attribute);
- LDB_DN_NULL_FAILED(at);
-
- p = strchr(raw_attribute, '=');
-
+ /* find attribute type/value separator */
+ p = strchr(raw_component, '=');
LDB_DN_NULL_FAILED(p);
- *p = '\0';
+ *p++ = '\0'; /* terminate name and point to value */
- at->name = talloc_strdup(at, ldb_dn_trim_string(raw_attribute, " \n"));
- LDB_DN_NULL_FAILED(at->name);
+ /* 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;
- p++;
+ ret = get_quotes_position(p, &qs, &qe);
- p = ldb_dn_trim_string(p, " \n");
+ 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;
- if (*p == '\"') { /* quotes at start means there must be quotes at the end */
- if (p[strlen(p) - 1] != '\"') /* malformed value */
- return NULL;
-
- p++;
- p[strlen(p) - 1] = '\0';
- at->value = talloc_strdup(at, p);
+ 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;
- return at;
+ default: /* mismatched quotes ot other error, bail out */
+ goto failed;
}
- /* no quotes means we must unescape the string */
- at->value = unescape_string(at, p);
- LDB_DN_NULL_FAILED(at->value);
-
- return at;
-
-failed:
- talloc_free(at);
- return NULL;
-}
-static struct ldb_dn_component *explode_component(void *mem_ctx, char *raw_component)
-{
- struct ldb_dn_component *dc;
- char *p;
-
- dc = talloc(mem_ctx, struct ldb_dn_component);
- LDB_DN_NULL_FAILED(dc);
-
- dc->attr_num = 0;
- dc->attributes = NULL;
-
- p = raw_component;
-
- /* get the components */
- do {
- char *t;
-
- /* terminate the current attribute 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 there's another attribute that follows */
- }
-
- /* allocate attributes pointer */
- dc->attributes = talloc_realloc(dc, dc->attributes,
- struct ldb_dn_attribute *,
- dc->attr_num + 1);
- LDB_DN_NULL_FAILED(dc->attributes);
-
- /* store the exploded attirbute in the main structure */
- dc->attributes[dc->attr_num] = ldb_dn_explode_attribute(dc->attributes, p);
- LDB_DN_NULL_FAILED(dc->attributes[dc->attr_num]);
-
- dc->attr_num++;
-
- /* jump to the next attribute if any */
- p = t;
-
- } while(*p);
+ if (dc.value.length == 0) {
+ goto failed;
+ }
return dc;
-failed:
- talloc_free(dc);
- return NULL;
-}
-
-/* FIXME: currently consider a dn composed of only case insensitive attributes
- this is not correct and need to be fixed soon */
-static void ldb_dn_sort_attributes(struct ldb_dn *edn)
-{
- struct ldb_dn_attribute *at0, *at1;
- int i, j, k, l;
- for (i = 0; i < edn->comp_num; i++) {
- if (edn->components[i]->attr_num > 1) {
-
- /* it is very unlikely that there is a multivalued RDN. In that
- unlikely case it is very unlikely you will find more than 2
- values. So the use of bubble sort here seem to be acceptable */
- for (j = 0; (j + 1) < edn->components[i]->attr_num; j++) {
- for (k = j; k >= 0; k--) {
- at0 = edn->components[i]->attributes[k];
- at1 = edn->components[i]->attributes[k + 1];
- l = ldb_caseless_cmp(at0->name, at1->name);
- if (l > 0) {
- /* already sorted, so no bubbles to move exit inner loop */
- break;
- }
- if (l == 0) {
- if (ldb_caseless_cmp(at0->value, at1->value) >= 0) {
- /* already sorted, so no bubbles to move exit inner loop */
- break;
- }
- }
-
- edn->components[i]->attributes[k] = at1;
- edn->components[i]->attributes[k + 1] = at0;
- }
- }
- }
- }
+failed:
+ talloc_free(dc.name);
+ dc.name = NULL;
+ return dc;
}
struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn)
@@ -305,6 +286,8 @@ struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn)
struct ldb_dn *edn; /* the exploded dn */
char *pdn, *p;
+ pdn = NULL;
+
/* Allocate a structure to hold the exploded DN */
edn = talloc(mem_ctx, struct ldb_dn);
LDB_DN_NULL_FAILED(edn);
@@ -314,8 +297,7 @@ struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn)
edn->components = NULL;
pdn = p = talloc_strdup(edn, dn);
- if (!pdn)
- goto failed;
+ LDB_DN_NULL_FAILED(pdn);
/* get the components */
do {
@@ -323,25 +305,23 @@ struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn)
/* terminate the current component and return pointer to the next one */
t = seek_to_separator(p, ",;");
- if (t == NULL)
- goto failed;
+ LDB_DN_NULL_FAILED(t);
if (*t) { /* here there is a separator */
*t = '\0'; /*terminate */
- t++; /* a separtor means there's another component that follows */
+ 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 *,
+ 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] = explode_component(edn->components, p);
- if (edn->components[edn->comp_num] == NULL)
- goto failed;
+ edn->components[edn->comp_num] = ldb_dn_explode_component(edn, p);
+ LDB_DN_NULL_FAILED(edn->components[edn->comp_num].name);
edn->comp_num++;
@@ -350,87 +330,71 @@ struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn)
} while(*p);
- /* sort attributes if there's any multivalued component */
- ldb_dn_sort_attributes(edn);
-
talloc_free(pdn);
return edn;
failed:
+ talloc_free(pdn);
talloc_free(edn);
return NULL;
}
-char *ldb_dn_linearize(void *mem_ctx, struct ldb_dn *edn)
+char *ldb_dn_linearize(void *mem_ctx, const struct ldb_dn *edn)
{
- char *dn, *ename, *evalue;
- const char *format;
- int i, j;
+ char *dn, *value;
+ const char *format = "%s=%s";
+ int i;
dn = talloc_strdup(mem_ctx, "");
LDB_DN_NULL_FAILED(dn);
for (i = 0; i < edn->comp_num; i++) {
+
if (i != 0) {
- dn = talloc_append_string(mem_ctx, dn, ",");
+ format = ",%s=%s";
}
- for (j = 0; j < edn->components[i]->attr_num; j++) {
- if (j == 0) {
- format = "%s=%s";
- } else {
- format = "+%s=%s";
- }
-
- ename = escape_string(dn, edn->components[i]->attributes[j]->name);
- LDB_DN_NULL_FAILED(ename);
- evalue = escape_string(dn, edn->components[i]->attributes[j]->value);
- LDB_DN_NULL_FAILED(evalue);
+ value = ldb_dn_escape_value(dn, edn->components[i].value);
+ LDB_DN_NULL_FAILED(value);
- dn = talloc_asprintf_append(dn, format, ename, evalue);
- LDB_DN_NULL_FAILED(dn);
+ dn = talloc_asprintf_append(dn, format, edn->components[i].name, value);
+ LDB_DN_NULL_FAILED(dn);
- talloc_free(ename);
- talloc_free(evalue);
- }
+ talloc_free(value);
}
return dn;
+
failed:
talloc_free(dn);
return NULL;
}
-/* FIXME: currently consider a dn composed of only case insensitive attributes
- this is not correct and need to be fixed soon */
-int ldb_dn_compare(struct ldb_dn *edn0, struct ldb_dn *edn1)
+/* compare DNs using casefolding compare functions */
+int ldb_dn_compare(struct ldb_context *ldb, const struct ldb_dn *edn0, const struct ldb_dn *edn1)
{
- struct ldb_dn_attribute *at0, *at1;
- int i, j, k;
+ int i, ret;
/* if the number of components doesn't match they differ */
if (edn0->comp_num != edn1->comp_num)
return (edn1->comp_num - edn0->comp_num);
for (i = 0; i < edn0->comp_num; i++) {
+ const struct ldb_attrib_handler *h;
- /* if the number of attributes per component doesn't match they differ */
- if (edn0->components[i]->attr_num != edn1->components[i]->attr_num)
- return (edn1->components[i]->attr_num - edn0->components[i]->attr_num);
-
- for (j = 0; j < edn0->components[i]->attr_num; j++) {
- at0 = edn0->components[i]->attributes[j];
- at1 = edn1->components[i]->attributes[j];
-
- /* compare names */
- k = ldb_caseless_cmp(at0->name, at1->name);
- if (k)
- return k;
+ /* compare names (attribute names are guaranteed to be ASCII only) */
+ ret = ldb_caseless_cmp(edn0->components[i].name,
+ edn1->components[i].name);
+ if (ret) {
+ return ret;
+ }
- /* names match, compare values */
- k = ldb_caseless_cmp(at0->value, at1->value);
- if (k)
- return k;
+ /* names match, compare values */
+ h = ldb_attrib_handler(ldb, edn0->components[i].name);
+ ret = h->comparison_fn(ldb, ldb, &(edn0->components[i].value),
+ &(edn1->components[i].value));
+ if (ret) {
+ return ret;
}
}
@@ -438,55 +402,31 @@ int ldb_dn_compare(struct ldb_dn *edn0, struct ldb_dn *edn1)
}
/*
- casefold a dn. We need to uppercase the attribute names, and the
- attribute values of case insensitive attributes. We also need to remove
- extraneous spaces between elements
+ 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, struct ldb_dn *edn)
+struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, const struct ldb_dn *edn)
{
struct ldb_dn *cedn;
- int i, j;
+ int i;
cedn = talloc(ldb, struct ldb_dn);
LDB_DN_NULL_FAILED(cedn);
cedn->comp_num = edn->comp_num;
- cedn->components = talloc_array(cedn, struct ldb_dn_component *, edn->comp_num);
+ cedn->components = talloc_array(cedn, struct ldb_dn_component, edn->comp_num);
LDB_DN_NULL_FAILED(cedn->components);
for (i = 0; i < edn->comp_num; i++) {
- struct ldb_dn_component *dc;
+ struct ldb_dn_component dc;
+ const struct ldb_attrib_handler *h;
- dc = talloc(cedn->components, struct ldb_dn_component);
- LDB_DN_NULL_FAILED(dc);
+ dc.name = ldb_casefold(cedn, edn->components[i].name);
+ LDB_DN_NULL_FAILED(dc.name);
- dc->attr_num = edn->components[i]->attr_num;
- dc->attributes = edn->components[i]->attributes;
- LDB_DN_NULL_FAILED(dc->attributes);
-
- for (j = 0; j < edn->components[i]->attr_num; j++) {
- struct ldb_dn_attribute *at;
- struct ldb_val v0, v;
- const struct ldb_attrib_handler *h;
-
- at = talloc(dc->attributes, struct ldb_dn_attribute);
- LDB_DN_NULL_FAILED(at);
-
- at->name = ldb_casefold(at, edn->components[i]->attributes[j]->name);
- LDB_DN_NULL_FAILED(at->name);
-
- h = ldb_attrib_handler(ldb, at->name);
- /* at->value should be a ldb_val, work around
- this for now .... */
- v0.data = edn->components[i]->attributes[j]->value;
- v0.length = strlen(v0.data);
- if (h->canonicalise_fn(ldb, &v0, &v) != 0) {
- return NULL;
- }
-
- talloc_steal(at, v.data);
- at->value = v.data;
- dc->attributes[j] = at;
+ h = ldb_attrib_handler(ldb, dc.name);
+ if (h->canonicalise_fn(ldb, cedn, &(edn->components[i].value), &(dc.value)) != 0) {
+ goto failed;
}
cedn->components[i] = dc;