summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/lib/ldb/Makefile.in3
-rw-r--r--source4/lib/ldb/common/ldb_explode_dn.c461
-rw-r--r--source4/lib/ldb/include/ldb_explode_dn.h38
-rw-r--r--source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c55
4 files changed, 542 insertions, 15 deletions
diff --git a/source4/lib/ldb/Makefile.in b/source4/lib/ldb/Makefile.in
index 648e3074c6..5bccf17e82 100644
--- a/source4/lib/ldb/Makefile.in
+++ b/source4/lib/ldb/Makefile.in
@@ -51,7 +51,8 @@ LDB_TDB_OBJ=ldb_tdb/ldb_match.o ldb_tdb/ldb_tdb.o \
COMMON_OBJ=common/ldb.o common/ldb_ldif.o common/util.o \
common/ldb_parse.o common/ldb_msg.o common/ldb_utf8.o \
- common/ldb_debug.o common/ldb_modules.o
+ common/ldb_debug.o common/ldb_modules.o \
+ common/ldb_explode_dn.o
MODULES_OBJ=modules/timestamps.o modules/schema.o
diff --git a/source4/lib/ldb/common/ldb_explode_dn.c b/source4/lib/ldb/common/ldb_explode_dn.c
new file mode 100644
index 0000000000..db8e8f2a85
--- /dev/null
+++ b/source4/lib/ldb/common/ldb_explode_dn.c
@@ -0,0 +1,461 @@
+/*
+ Unix SMB/CIFS implementation.
+ LDAP server
+ Copyright (C) Simo Sorce 2004
+ Copyright (C) Derrell Lipman 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "ldb/include/ldb.h"
+#include "ldb/include/ldb_explode_dn.h"
+
+#define LDB_PARSE_DN_INVALID(x) do { \
+ if (x) { \
+ goto failed; \
+ } \
+} while(0)
+
+
+
+static char
+octet_from_hex(char * p,
+ char * ret)
+{
+ unsigned char low_char;
+ unsigned char high_char;
+
+ unsigned char low_binary;
+ unsigned char high_binary;
+
+ if (p[0] == '\0' || p[1] == '\0') {
+ return -1;
+ }
+
+ high_char = p[0];
+ low_char = p[1];
+
+ if (high_char >= '0' && high_char <= '9') {
+ high_binary = high_char - '0';
+ } else if (high_char >= 'A' && high_char <= 'F') {
+ high_binary = 10 + (high_char - 'A');
+ } else if (high_char >= 'a' && high_char <= 'f') {
+ high_binary = 10 + (high_char - 'a');
+ } else {
+ return -1;
+ }
+
+ if (low_char >= '0' && low_char <= '9') {
+ low_binary = low_char - '0';
+ } else if (low_char >= 'A' && low_char <= 'F') {
+ low_binary = 10 + (low_char - 'A');
+ } else if (low_char >= 'a' && low_char <= 'f') {
+ low_binary = 10 + (low_char - 'a');
+ } else {
+ return -1;
+ }
+
+ *ret = (char) ((high_binary << 4) | low_binary);
+ return 0;
+}
+
+static char *
+parse_slash(char *p,
+ char *end)
+{
+ switch (*(p + 1)) {
+ case ',':
+ case '=':
+ case '\n':
+ case '+':
+ case '<':
+ case '>':
+ case '#':
+ case ';':
+ case '\\':
+ case '"':
+ memmove(p, p + 1, end - (p + 1));
+ return (end - 1);
+
+ default:
+ if (*(p + 1) != '\0' && *(p + 2) != '\0') {
+ if (octet_from_hex(p + 1, p) < 0) {
+ return NULL;
+ }
+ memmove(p + 1, p + 3, end - (p + 3));
+ return (end - 2);
+ } else {
+ return NULL;
+ }
+ }
+}
+
+struct ldb_dn *
+ldb_explode_dn(void *mem_ctx,
+ const char *orig_dn)
+{
+ struct ldb_dn * dn;
+ struct ldb_dn_component * component;
+ struct ldb_dn_attribute * attribute;
+ char * p;
+ char * start;
+ char * separator;
+ char * src;
+ char * dest;
+ char * dn_copy;
+ char * dn_end;
+ int i;
+ int size;
+ int orig_len;
+
+ /* Allocate a structure to hold the exploded DN */
+ if ((dn = talloc(mem_ctx, struct ldb_dn)) == NULL) {
+ return NULL;
+ }
+
+ /* Initially there are no components */
+ dn->comp_num = 0;
+
+ /* Allocate the component array, with space for one component */
+ if ((dn->components =
+ talloc_array(dn, struct ldb_dn_component *, 1)) == NULL) {
+
+ goto failed;
+ }
+
+ /* Allocate the first component */
+ if ((component = talloc(dn, struct ldb_dn_component)) == NULL) {
+ goto failed;
+ }
+
+ /* This component has no attributes yet */
+ component->attr_num = 0;
+
+ /* Get the length of the provided DN */
+ if ((orig_len = strlen(orig_dn)) == 0) {
+
+ /* We found a zero-length DN. Return it. */
+ if ((dn->dn = talloc_strdup(dn, orig_dn)) == NULL) {
+ goto failed;
+ }
+ return dn;
+ }
+
+ /* Copy the provided DN so we can manipulate it */
+ if ((dn_copy = p = talloc_strdup(mem_ctx, orig_dn)) == NULL) {
+ goto failed;
+ }
+
+ /* Our copy may end shorter than the original as we unescape chars */
+ dn_end = dn_copy + orig_len + 1;
+
+ /* For each attribute/value pair... */
+ do {
+ /* Allocate an array to hold the attributes, initially len 1 */
+ if ((component->attributes =
+ talloc_array(component,
+ struct ldb_dn_attribute *, 1)) == NULL) {
+ goto failed;
+ }
+
+ /* Allocate this attribute */
+ if ((attribute =
+ talloc(component, struct ldb_dn_attribute)) == NULL) {
+ goto failed;
+ }
+
+ /* skip white space */
+ while (*p == ' ' || *p == '\n') {
+ p++;
+ }
+
+ /* start parsing this component */
+ do {
+ /* Save pointer to beginning of attribute name */
+ start = p;
+
+ /* find our attribute/value separator '=' */
+ while (*p != '\0' && *p != '=') {
+ if (*p == '\\') {
+ if ((dn_end =
+ parse_slash(p, dn_end)) == NULL) {
+ goto failed;
+ }
+ }
+ p++;
+ }
+
+ /* Ensure we found the attribute/value separator */
+ if (*p != '=') {
+ goto failed;
+ }
+
+ /* Save pointer to separator */
+ separator = p;
+
+ /* remove trailing white space from attribute name */
+ while (p > start &&
+ (*(p - 1) == ' ' || *(p - 1) == '\n')) {
+
+ p--;
+ }
+ LDB_PARSE_DN_INVALID((p - start) < 1);
+
+ /* save attribute name */
+ if ((attribute->name =
+ talloc_strndup(attribute,
+ start,
+ p - start)) == NULL) {
+ goto failed;
+ }
+
+ ldb_debug(mem_ctx,
+ LDB_DEBUG_TRACE,
+ "attribute name: [%s]\n", attribute->name);
+
+ /* skip white space after the separator */
+ p = separator + 1;
+ p += strspn(p, " \n");
+
+ /* ensure there's a value here */
+ if (*p == '\0') {
+ goto failed;
+ }
+
+ /* check if the value is enclosed in QUOTATION */
+ if (*p == '"') {
+ /* save pointer to beginning of attr value */
+ start = p + 1;
+
+ /* find the trailing QUOTE */
+ while (*p != '\0' && *p != '"') {
+ if (*p == '\\') {
+ if ((dn_end =
+ parse_slash(p, dn_end)) == NULL) {
+ goto failed;
+ }
+ }
+
+ p++;
+ }
+
+ /* skip spaces until the separator */
+ if (*p == '\0') {
+ /* We're already at end of string */
+ separator = p;
+ } else {
+ /* Skip spaces */
+ separator = p + 1 + strspn(p+1, " \n");
+ }
+
+ /* must be end of string or a separator here */
+ if (*separator != '\0' &&
+ *separator != ',' &&
+ *separator != ';' &&
+ *separator != '+') {
+ /* Error Malformed DN */
+ goto failed;
+ }
+ } else {
+ /*
+ * Value is not quouted.
+ */
+
+ /* save pointer to beginning of value */
+ start = p;
+
+ /* find end of value */
+ while (*p != '\0' &&
+ *p != ',' &&
+ *p != ';' &&
+ *p != '+') {
+
+ if (*p == '\\') {
+ if ((dn_end =
+ parse_slash(p, dn_end)) == NULL) {
+ goto failed;
+ }
+ }
+
+ p++;
+ }
+
+ /* save pointer to the terminating separator */
+ separator = p;
+
+ /* remove trailing whitespace */
+ while (p > start &&
+ (*(p - 1) == ' ' ||
+ *(p - 1) == '\n')) {
+
+ p--;
+ }
+ }
+ LDB_PARSE_DN_INVALID((p - start) < 1);
+
+ /* save the value */
+ if ((attribute->value =
+ talloc_strndup(attribute,
+ start,
+ p - start)) == NULL) {
+ goto failed;
+ }
+
+ ldb_debug(mem_ctx,
+ LDB_DEBUG_TRACE,
+ "attribute value: [%s]\n", attribute->value);
+
+ /* save the entire RDN */
+ if ((attribute->rdn =
+ talloc_asprintf(attribute,
+ "%s=%s",
+ attribute->name,
+ attribute->value)) == NULL) {
+ goto failed;
+ }
+
+ ldb_debug(mem_ctx,
+ LDB_DEBUG_TRACE,
+ "attribute: [%s]\n", attribute->rdn);
+
+ /* add this attribute to the attribute list */
+ component->attributes[component->attr_num] = attribute;
+ component->attr_num++;
+
+ /* is this a multi-valued attribute? */
+ if (*separator == '+') {
+ /* Yup. prepare for the next value. */
+ if ((component->attributes =
+ talloc_realloc(component,
+ component->attributes,
+ struct ldb_dn_attribute *,
+ component->attr_num + 1)) == NULL) {
+ goto failed;
+ }
+
+ /* allocate new attribute structure */
+ if ((attribute =
+ talloc(component,
+ struct ldb_dn_attribute)) == NULL) {
+ goto failed;
+ }
+ }
+
+ /* if we're not at end of string, skip white space */
+ if (*separator != '\0') {
+ /* skip spaces past the separator */
+ p = separator + 1;
+ p += strspn(p, " \n");
+ }
+
+ } while (*separator == '+');
+
+ /* find total length of all attributes */
+ for (i = 0, size = 0; i < component->attr_num; i++) {
+ size += strlen(component->attributes[i]->rdn) + 1;
+ }
+
+ /*
+ * rebuild the normalized component
+ */
+
+ /* allocate space for the normalized component */
+ if ((component->component =
+ dest = talloc_size(component, size)) == NULL) {
+
+ goto failed;
+ }
+
+ /* copy each of the attributes to the normalized component */
+ for (i = 0; i < component->attr_num; i++) {
+ if (i != 0) {
+ *dest = '+';
+ dest++;
+ }
+ src = component->attributes[i]->rdn;
+ do {
+ *(dest++) = *(src++);
+ } while(*src);
+ *dest = '\0';
+ }
+
+ ldb_debug(mem_ctx,
+ LDB_DEBUG_TRACE,
+ "component: [%s]\n", component->component);
+
+ /* insert the component into the component list */
+ dn->components[dn->comp_num] = component;
+ dn->comp_num++;
+
+ /* if there are additional components... */
+ if (*separator == ',' || *separator == ';') {
+ /* ... then prepare to parse them */
+ if ((dn->components =
+ talloc_realloc(dn,
+ dn->components,
+ struct ldb_dn_component *,
+ dn->comp_num + 1)) == NULL ||
+ (component =
+ talloc(dn, struct ldb_dn_component)) == NULL) {
+
+ goto failed;
+ }
+
+ component->attr_num = 0;
+ }
+
+ /* update pointer to after the separator */
+ p = separator + 1;
+
+ } while(*separator == ',' || *separator == ';');
+
+ /* find total length of all components */
+ for (i = 0, size = 0; i < dn->comp_num; i++) {
+ size = size + strlen(dn->components[i]->component) + 1;
+ }
+
+ /* rebuild the normalized DN */
+ if ((dn->dn = dest = talloc_size(dn, size)) == NULL) {
+ goto failed;
+ }
+
+ /* copy the normalized components into the DN */
+ for (i = 0; i < dn->comp_num; i++) {
+ if (i != 0) {
+ *dest = ',';
+ dest++;
+ }
+ src = dn->components[i]->component;
+ do {
+ *(dest++) = *(src++);
+ } while(*src);
+ *dest = '\0';
+ }
+
+ ldb_debug(mem_ctx, LDB_DEBUG_TRACE, "dn: [%s]\n", dn->dn);
+
+ /* we don't need the copy of the DN any more */
+ talloc_free(dn_copy);
+
+ /* give 'em what they came for! */
+ return dn;
+
+failed:
+ /* something went wrong. free memory and tell 'em it failed */
+ talloc_free(dn);
+ ldb_debug(mem_ctx, LDB_DEBUG_TRACE, "Failed to parse %s\n", orig_dn);
+ return NULL;
+}
diff --git a/source4/lib/ldb/include/ldb_explode_dn.h b/source4/lib/ldb/include/ldb_explode_dn.h
new file mode 100644
index 0000000000..fb34be8b87
--- /dev/null
+++ b/source4/lib/ldb/include/ldb_explode_dn.h
@@ -0,0 +1,38 @@
+/*
+ Unix SMB/CIFS implementation.
+ LDAP server
+ Copyright (C) Simo Sorce 2004
+ Copyright (C) Derrell Lipman 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+struct ldb_dn_attribute {
+ char * rdn;
+ char * name;
+ char * value;
+};
+
+struct ldb_dn_component {
+ char * component;
+ int attr_num;
+ struct ldb_dn_attribute ** attributes;
+};
+
+struct ldb_dn {
+ char *dn;
+ int comp_num;
+ struct ldb_dn_component ** components;
+};
diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
index 25efc8ced2..147ee599a9 100644
--- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
+++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
@@ -569,23 +569,52 @@ lsqlite3_search(struct ldb_module * module,
"SELECT entry.entry_data\n"
" FROM ldb_entry AS entry\n"
" WHERE entry.eid IN\n"
- " (SELECT ldb_entry.eid\n"
+ " (SELECT DISTINCT ldb_entry.eid\n"
" FROM ldb_entry,\n"
" ldb_descendants,\n"
" %q\n"
" WHERE ldb_descendants.aeid = %lld\n"
" AND ldb_entry.eid = ldb_descendants.deid\n"
" AND ldap_entry.eid IN\n"
- "%s);",
+ "%s"
+ ");",
table_list,
+ eid,
sql_constraints);
break;
-#warning "scope BASE and ONLEVEL not yet implemented"
case LDB_SCOPE_BASE:
+ sql = sqlite3_mprintf(
+ "SELECT entry.entry_data\n"
+ " FROM ldb_entry AS entry\n"
+ " WHERE entry.eid IN\n"
+ " (SELECT DISTINCT ldb_entry.eid\n"
+ " FROM %q\n"
+ " WHERE ldb_entry.eid = %lld\n"
+ " AND ldb_entry.eid IN\n"
+ "%s"
+ ");",
+ table_list,
+ eid,
+ sql_constraints);
break;
case LDB_SCOPE_ONELEVEL:
+ sql = sqlite3_mprintf(
+ "SELECT entry.entry_data\n"
+ " FROM ldb_entry AS entry\n"
+ " WHERE entry.eid IN\n"
+ " (SELECT DISTINCT ldb_entry.eid\n"
+ " FROM ldb_entry AS pchild, "
+ " %q\n"
+ " WHERE ldb_entry.eid = pchild.eid "
+ " AND pchild.peid = %lld "
+ " AND ldb_entry.eid IN\n"
+ "%s"
+ ");",
+ table_list,
+ eid,
+ sql_constraints);
break;
}
@@ -599,9 +628,7 @@ lsqlite3_new_attr(struct ldb_module * module,
{
struct lsqlite3_private * lsqlite3 = module->private_data;
- /* Get a case-folded copy of the attribute name */
- pAttrName = ldb_casefold((struct ldb_context *) module, pAttrName);
-
+ /* NOTE: pAttrName is assumed to already be case-folded here! */
QUERY_NOROWS(lsqlite3,
FALSE,
"CREATE TABLE ldb_attr_%q "
@@ -639,9 +666,13 @@ lsqlite3_msg_to_sql(struct ldb_module * module,
flags = el->flags & LDB_FLAG_MOD_MASK;
}
+ /* Get a case-folded copy of the attribute name */
+ pAttrName = ldb_casefold((struct ldb_context *) module,
+ el->name);
+
if (flags == LDB_FLAG_MOD_ADD) {
/* Create the attribute table if it doesn't exist */
- if (lsqlite3_new_attr(module, el->name) != 0) {
+ if (lsqlite3_new_attr(module, pAttrName) != 0) {
return -1;
}
}
@@ -649,10 +680,6 @@ lsqlite3_msg_to_sql(struct ldb_module * module,
/* For each value of the specified attribute name... */
for (j = 0; j < el->num_values; j++) {
- /* Get a case-folded copy of the attribute name */
- pAttrName = ldb_casefold((struct ldb_context *) module,
- el->name);
-
/* ... bind the attribute value, if necessary */
switch (flags) {
case LDB_FLAG_MOD_ADD:
@@ -725,7 +752,7 @@ lsqlite3_msg_to_sql(struct ldb_module * module,
static int
-lsqlite3_new_dn(struct ldb_module *module,
+lsqlite3_new_dn(struct ldb_module * module,
char * pDN,
long long * pEID)
{
@@ -738,10 +765,10 @@ lsqlite3_new_dn(struct ldb_module *module,
/* Parse the DN into its constituent components */
#warning "this simple parse of DN ignores escaped '=' and ','. fix it."
while (pDN != NULL) {
- pName = strsep(&pDN, ",");
+ pName = strsep(&pValue, "=");
if (pDN == NULL) {
- /* Attribute name with value? Should not occur. */
+ /* Attribute name without value? Should not occur. */
return -1;
}