summaryrefslogtreecommitdiff
path: root/source4/lib/ldb/common
diff options
context:
space:
mode:
Diffstat (limited to 'source4/lib/ldb/common')
-rw-r--r--source4/lib/ldb/common/attrib_handlers.c335
-rw-r--r--source4/lib/ldb/common/ldb.c8
-rw-r--r--source4/lib/ldb/common/ldb_attributes.c281
-rw-r--r--source4/lib/ldb/common/ldb_dn.c132
-rw-r--r--source4/lib/ldb/common/ldb_ldif.c78
-rw-r--r--source4/lib/ldb/common/ldb_match.c260
-rw-r--r--source4/lib/ldb/common/ldb_utf8.c4
7 files changed, 976 insertions, 122 deletions
diff --git a/source4/lib/ldb/common/attrib_handlers.c b/source4/lib/ldb/common/attrib_handlers.c
new file mode 100644
index 0000000000..fcff4113b4
--- /dev/null
+++ b/source4/lib/ldb/common/attrib_handlers.c
@@ -0,0 +1,335 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 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
+*/
+/*
+ attribute handlers for well known attribute types, selected by syntax OID
+ see rfc2252
+*/
+
+#include "includes.h"
+#include "ldb/include/ldb.h"
+#include "ldb/include/ldb_private.h"
+#include <ctype.h>
+
+/*
+ default handler that just copies a ldb_val.
+*/
+int ldb_handler_copy(struct ldb_context *ldb,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ *out = ldb_val_dup(ldb, in);
+ if (out->data == NULL) {
+ ldb_oom(ldb);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ a case folding copy handler, removing leading and trailing spaces and
+ multiple internal spaces
+*/
+static int ldb_handler_fold(struct ldb_context *ldb,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ uint8_t *s1, *s2;
+ out->data = talloc_size(ldb, strlen(in->data)+1);
+ if (out->data == NULL) {
+ ldb_oom(ldb);
+ return -1;
+ }
+ s1 = in->data;
+ s2 = out->data;
+ while (*s1 == ' ') s1++;
+ while (*s1) {
+ *s2 = toupper(*s1);
+ if (s1[0] == ' ') {
+ while (s1[0] == s1[1]) s1++;
+ }
+ s2++; s1++;
+ }
+ *s2 = 0;
+ out->length = strlen(out->data);
+ return 0;
+}
+
+
+/*
+ a case folding copy handler, removing leading and trailing spaces and
+ multiple internal spaces, and checking for wildcard characters
+*/
+static int ldb_handler_fold_wildcard(struct ldb_context *ldb,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ if (strchr(in->data, '*')) {
+ return -1;
+ }
+ return ldb_handler_fold(ldb, in, out);
+}
+
+/*
+ canonicalise a ldap Integer
+ rfc2252 specifies it should be in decimal form
+*/
+static int ldb_canonicalise_Integer(struct ldb_context *ldb,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ char *end;
+ long long i = strtoll(in->data, &end, 0);
+ if (*end != 0) {
+ return -1;
+ }
+ out->data = talloc_asprintf(ldb, "%lld", i);
+ if (out->data == NULL) {
+ return -1;
+ }
+ out->length = strlen(out->data);
+ return 0;
+}
+
+/*
+ compare two Integers
+*/
+static int ldb_comparison_Integer(struct ldb_context *ldb,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ return strtoll(v1->data, NULL, 0) - strtoll(v2->data, NULL, 0);
+}
+
+/*
+ compare two binary blobs
+*/
+int ldb_comparison_binary(struct ldb_context *ldb,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ if (v1->length != v2->length) {
+ return v1->length - v2->length;
+ }
+ return memcmp(v1->data, v2->data, v1->length);
+}
+
+/*
+ compare two case insensitive strings, ignoring multiple whitespace
+ and leading and trailing whitespace
+ see rfc2252 section 8.1
+*/
+static int ldb_comparison_fold(struct ldb_context *ldb,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ const char *s1=v1->data, *s2=v2->data;
+ while (*s1 == ' ') s1++;
+ while (*s2 == ' ') s2++;
+ /* TODO: make utf8 safe, possibly with helper function from application */
+ while (*s1 && *s2) {
+ if (toupper(*s1) != toupper(*s2)) break;
+ if (*s1 == ' ') {
+ while (s1[0] == s1[1]) s1++;
+ while (s2[0] == s2[1]) s2++;
+ }
+ s1++; s2++;
+ }
+ while (*s1 == ' ') s1++;
+ while (*s2 == ' ') s2++;
+ return (int)(*s1) - (int)(*s2);
+}
+
+/*
+ compare two case insensitive strings, ignoring multiple whitespace
+ and leading and trailing whitespace
+ see rfc2252 section 8.1
+ handles wildcards
+*/
+static int ldb_comparison_fold_wildcard(struct ldb_context *ldb,
+ const struct ldb_val *v1,
+ const struct ldb_val *v2)
+{
+ const char *s1=v1->data, *s2=v2->data;
+ while (*s1 == ' ') s1++;
+ while (*s2 == ' ') s2++;
+ /* TODO: make utf8 safe, possibly with helper function from application */
+ while (*s1 && *s2) {
+ if (s1[0] == '*' && s1[1] == 0) {
+ return 0;
+ }
+ if (toupper(*s1) != toupper(*s2)) break;
+ if (*s1 == ' ') {
+ while (s1[0] == s1[1]) s1++;
+ while (s2[0] == s2[1]) s2++;
+ }
+ s1++; s2++;
+ }
+ while (*s1 == ' ') s1++;
+ while (*s2 == ' ') s2++;
+ return (int)(*s1) - (int)(*s2);
+}
+
+
+/*
+ canonicalise a attribute in DN format
+*/
+static int ldb_canonicalise_dn(struct ldb_context *ldb,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct ldb_dn *dn2=NULL, *dn1 = ldb_dn_explode(ldb, in->data);
+ out->data = NULL;
+ if (dn1 == NULL) {
+ goto failed;
+ }
+ dn2 = ldb_dn_casefold(ldb, dn1);
+ if (dn2 == NULL) goto failed;
+
+ out->data = ldb_dn_linearize(ldb, dn2);
+ if (out->data == NULL) goto failed;
+
+ talloc_free(dn1);
+ talloc_free(dn2);
+ return 0;
+
+failed:
+ talloc_free(dn1);
+ talloc_free(dn2);
+ return -1;
+}
+
+/*
+ compare two dns
+*/
+static int ldb_comparison_dn(struct ldb_context *ldb,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ struct ldb_val cv1, cv2;
+ int ret;
+ if (ldb_canonicalise_dn(ldb, v1, &cv1) != 0 ||
+ ldb_canonicalise_dn(ldb, v2, &cv2) != 0) {
+ goto failed;
+ }
+ ret = strcmp(cv1.data, cv2.data);
+ talloc_free(cv1.data);
+ talloc_free(cv2.data);
+ return ret;
+failed:
+ talloc_free(cv1.data);
+ talloc_free(cv2.data);
+ return -1;
+}
+
+/*
+ compare two objectclasses, looking at subclasses
+*/
+static int ldb_comparison_objectclass(struct ldb_context *ldb,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ int ret, i;
+ const char **subclasses;
+ ret = ldb_comparison_fold(ldb, v1, v2);
+ if (ret == 0) {
+ return 0;
+ }
+ fprintf(stderr, "looing for %s %s\n", v1->data, v2->data);
+ subclasses = ldb_subclass_list(ldb, v1->data);
+ if (subclasses == NULL) {
+ return ret;
+ }
+ for (i=0;subclasses[i];i++) {
+ struct ldb_val vs;
+ vs.data = discard_const(subclasses[i]);
+ vs.length = strlen(subclasses[i]);
+ if (ldb_comparison_objectclass(ldb, &vs, v2) == 0) {
+ return 0;
+ }
+ }
+ return ret;
+}
+
+/*
+ table of standard attribute handlers
+*/
+static const struct ldb_attrib_handler ldb_standard_attribs[] = {
+ {
+ .attr = LDB_SYNTAX_INTEGER,
+ .flags = 0,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_canonicalise_Integer,
+ .comparison_fn = ldb_comparison_Integer
+ },
+ {
+ .attr = LDB_SYNTAX_OCTET_STRING,
+ .flags = 0,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_handler_copy,
+ .comparison_fn = ldb_comparison_binary
+ },
+ {
+ .attr = LDB_SYNTAX_DIRECTORY_STRING,
+ .flags = 0,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_handler_fold,
+ .comparison_fn = ldb_comparison_fold
+ },
+ {
+ .attr = LDB_SYNTAX_WILDCARD,
+ .flags = LDB_ATTR_FLAG_WILDCARD,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_handler_fold_wildcard,
+ .comparison_fn = ldb_comparison_fold_wildcard
+ },
+ {
+ .attr = LDB_SYNTAX_DN,
+ .flags = 0,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_canonicalise_dn,
+ .comparison_fn = ldb_comparison_dn
+ },
+ {
+ .attr = LDB_SYNTAX_OBJECTCLASS,
+ .flags = 0,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_handler_fold,
+ .comparison_fn = ldb_comparison_objectclass
+ }
+};
+
+
+/*
+ return the attribute handlers for a given syntax name
+*/
+const struct ldb_attrib_handler *ldb_attrib_handler_syntax(struct ldb_context *ldb,
+ const char *syntax)
+{
+ int i;
+ unsigned num_handlers = sizeof(ldb_standard_attribs)/sizeof(ldb_standard_attribs[0]);
+ /* TODO: should be replaced with a binary search */
+ for (i=0;i<num_handlers;i++) {
+ if (strcmp(ldb_standard_attribs[i].attr, syntax) == 0) {
+ return &ldb_standard_attribs[i];
+ }
+ }
+ return NULL;
+}
+
diff --git a/source4/lib/ldb/common/ldb.c b/source4/lib/ldb/common/ldb.c
index 63526dfe2e..aa5b58c252 100644
--- a/source4/lib/ldb/common/ldb.c
+++ b/source4/lib/ldb/common/ldb.c
@@ -43,6 +43,14 @@
struct ldb_context *ldb_init(void *mem_ctx)
{
struct ldb_context *ldb = talloc_zero(mem_ctx, struct ldb_context);
+ int ret;
+
+ ret = ldb_setup_wellknown_attributes(ldb);
+ if (ret != 0) {
+ talloc_free(ldb);
+ return NULL;
+ }
+
return ldb;
}
diff --git a/source4/lib/ldb/common/ldb_attributes.c b/source4/lib/ldb/common/ldb_attributes.c
new file mode 100644
index 0000000000..e053ccbbf2
--- /dev/null
+++ b/source4/lib/ldb/common/ldb_attributes.c
@@ -0,0 +1,281 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 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
+*/
+/*
+ register handlers for specific attributes and objectclass relationships
+
+ this allows a backend to store its schema information in any format
+ it likes (or to not have any schema information at all) while keeping the
+ message matching logic generic
+*/
+
+#include "includes.h"
+#include "ldb/include/ldb.h"
+#include "ldb/include/ldb_private.h"
+
+/*
+ add to the list of ldif handlers for this ldb context
+*/
+int ldb_set_attrib_handlers(struct ldb_context *ldb,
+ const struct ldb_attrib_handler *handlers,
+ unsigned num_handlers)
+{
+ struct ldb_attrib_handler *h;
+ h = talloc_realloc(ldb, ldb->schema.attrib_handlers,
+ struct ldb_attrib_handler,
+ ldb->schema.num_attrib_handlers + num_handlers);
+ if (h == NULL) {
+ ldb_oom(ldb);
+ return -1;
+ }
+ ldb->schema.attrib_handlers = h;
+ memcpy(h + ldb->schema.num_attrib_handlers,
+ handlers, sizeof(*h) * num_handlers);
+ ldb->schema.num_attrib_handlers += num_handlers;
+ return 0;
+}
+
+
+/*
+ default function for read/write/canonicalise
+*/
+static int ldb_default_copy(struct ldb_context *ldb,
+ const struct ldb_val *in,
+ struct ldb_val *out)
+{
+ *out = *in;
+ return 0;
+}
+
+/*
+ default function for comparison
+*/
+static int ldb_default_cmp(struct ldb_context *ldb,
+ const struct ldb_val *v1,
+ const struct ldb_val *v2)
+{
+ if (v1->length != v2->length) {
+ return v1->length - v2->length;
+ }
+ return memcmp(v1->data, v2->data, v1->length);
+}
+
+/*
+ default handler function pointers
+*/
+static const struct ldb_attrib_handler ldb_default_attrib_handler = {
+ .attr = NULL,
+ .ldif_read_fn = ldb_default_copy,
+ .ldif_write_fn = ldb_default_copy,
+ .canonicalise_fn = ldb_default_copy,
+ .comparison_fn = ldb_default_cmp,
+};
+
+/*
+ return the attribute handlers for a given attribute
+*/
+const struct ldb_attrib_handler *ldb_attrib_handler(struct ldb_context *ldb,
+ const char *attrib)
+{
+ int i;
+ const struct ldb_attrib_handler *def = &ldb_default_attrib_handler;
+ /* TODO: should be replaced with a binary search, with a sort on add */
+ for (i=0;i<ldb->schema.num_attrib_handlers;i++) {
+ if (strcmp(ldb->schema.attrib_handlers[i].attr, "*") == 0) {
+ def = &ldb->schema.attrib_handlers[i];
+ }
+ if (ldb_attr_cmp(attrib, ldb->schema.attrib_handlers[i].attr) == 0) {
+ return &ldb->schema.attrib_handlers[i];
+ }
+ }
+ return def;
+}
+
+
+/*
+ add to the list of ldif handlers for this ldb context
+*/
+void ldb_remove_attrib_handler(struct ldb_context *ldb, const char *attrib)
+{
+ const struct ldb_attrib_handler *h;
+ int i;
+ h = ldb_attrib_handler(ldb, attrib);
+ if (h == &ldb_default_attrib_handler) {
+ return;
+ }
+ i = h - ldb->schema.attrib_handlers;
+ if (i < ldb->schema.num_attrib_handlers - 1) {
+ memmove(&ldb->schema.attrib_handlers[i],
+ h+1, sizeof(*h) * (ldb->schema.num_attrib_handlers-(i+1)));
+ }
+ ldb->schema.num_attrib_handlers--;
+}
+
+
+/*
+ setup the attribute handles for well known attributes
+*/
+int ldb_setup_wellknown_attributes(struct ldb_context *ldb)
+{
+ const struct {
+ const char *attr;
+ const char *syntax;
+ } wellknown[] = {
+ { "dn", LDB_SYNTAX_DN },
+ { "distinguishedName", LDB_SYNTAX_DN },
+ { "cn", LDB_SYNTAX_DIRECTORY_STRING },
+ { "dc", LDB_SYNTAX_DIRECTORY_STRING },
+ { "ou", LDB_SYNTAX_DIRECTORY_STRING },
+ { "objectClass", LDB_SYNTAX_OBJECTCLASS }
+ };
+ int i;
+ for (i=0;i<ARRAY_SIZE(wellknown);i++) {
+ const struct ldb_attrib_handler *h =
+ ldb_attrib_handler_syntax(ldb, wellknown[i].syntax);
+ struct ldb_attrib_handler h2;
+ if (h == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Unknown syntax '%s'\n",
+ wellknown[i].syntax);
+ return -1;
+ }
+ h2 = *h;
+ h2.attr = wellknown[i].attr;
+ if (ldb_set_attrib_handlers(ldb, &h2, 1) != 0) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+/*
+ return the list of subclasses for a class
+*/
+const char **ldb_subclass_list(struct ldb_context *ldb, const char *class)
+{
+ int i;
+ for (i=0;i<ldb->schema.num_classes;i++) {
+ if (ldb_attr_cmp(class, ldb->schema.classes[i].name) == 0) {
+ return (const char **)ldb->schema.classes[i].subclasses;
+ }
+ }
+ return NULL;
+}
+
+
+/*
+ add a new subclass
+*/
+static int ldb_subclass_new(struct ldb_context *ldb, const char *class, const char *subclass)
+{
+ struct ldb_subclass *s, *c;
+ s = talloc_realloc(ldb, ldb->schema.classes, struct ldb_subclass, ldb->schema.num_classes+1);
+ if (s == NULL) goto failed;
+
+ ldb->schema.classes = s;
+ c = &s[ldb->schema.num_classes];
+ c->name = talloc_strdup(s, class);
+ if (c->name == NULL) goto failed;
+
+ c->subclasses = talloc_array(s, char *, 2);
+ if (c->subclasses == NULL) goto failed;
+
+ c->subclasses[0] = talloc_strdup(c->subclasses, subclass);
+ if (c->subclasses[0] == NULL) goto failed;
+ c->subclasses[1] = NULL;
+
+ ldb->schema.num_classes++;
+
+ return 0;
+failed:
+ ldb_oom(ldb);
+ return -1;
+}
+
+/*
+ add a subclass
+*/
+int ldb_subclass_add(struct ldb_context *ldb, const char *class, const char *subclass)
+{
+ int i, n;
+ struct ldb_subclass *c;
+ char **s;
+
+ for (i=0;i<ldb->schema.num_classes;i++) {
+ if (ldb_attr_cmp(class, ldb->schema.classes[i].name) == 0) {
+ break;
+ }
+ }
+ if (i == ldb->schema.num_classes) {
+ return ldb_subclass_new(ldb, class, subclass);
+ }
+ c = &ldb->schema.classes[i];
+
+ for (n=0;c->subclasses[n];n++) /* noop */;
+
+ s = talloc_realloc(ldb->schema.classes, c->subclasses, char *, n+2);
+ if (s == NULL) {
+ ldb_oom(ldb);
+ return -1;
+ }
+
+ c->subclasses = s;
+ s[n] = talloc_strdup(s, subclass);
+ if (s[n] == NULL) {
+ ldb_oom(ldb);
+ return -1;
+ }
+ s[n+1] = NULL;
+
+ return 0;
+}
+
+/*
+ remove a set of subclasses for a class
+*/
+void ldb_subclass_remove(struct ldb_context *ldb, const char *class)
+{
+ int i;
+ struct ldb_subclass *c;
+
+ for (i=0;i<ldb->schema.num_classes;i++) {
+ if (ldb_attr_cmp(class, ldb->schema.classes[i].name) == 0) {
+ break;
+ }
+ }
+ if (i == ldb->schema.num_classes) {
+ return;
+ }
+
+ c = &ldb->schema.classes[i];
+ talloc_free(c->name);
+ talloc_free(c->subclasses);
+ if (ldb->schema.num_classes-(i+1) > 0) {
+ memmove(c, c+1, sizeof(*c) * ldb->schema.num_classes-(i+1));
+ }
+ ldb->schema.num_classes--;
+ if (ldb->schema.num_classes == 0) {
+ talloc_free(ldb->schema.classes);
+ ldb->schema.classes = NULL;
+ }
+}
diff --git a/source4/lib/ldb/common/ldb_dn.c b/source4/lib/ldb/common/ldb_dn.c
index 7ae314e46c..f147197499 100644
--- a/source4/lib/ldb/common/ldb_dn.c
+++ b/source4/lib/ldb/common/ldb_dn.c
@@ -1,7 +1,7 @@
/*
ldb database library
- Copyright (C) Simo Sorce 2004
+ 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
@@ -40,22 +40,22 @@
#include "ldb/include/ldb_dn.h"
-#define LDB_DN_NULL_RETURN(x) do { if (!x) return NULL; } while(0)
+#define LDB_DN_NULL_FAILED(x) if (!(x)) goto failed
static char *escape_string(void *mem_ctx, const char *src)
{
const char *p, *s;
- char *d, *dst;
+ char *d, *dst=NULL;
- LDB_DN_NULL_RETURN(src);
+ LDB_DN_NULL_FAILED(src);
/* allocate destination string, it will be at most 3 times the source */
dst = d = talloc_array(mem_ctx, char, strlen(src) * 3 + 1);
- LDB_DN_NULL_RETURN(dst);
+ LDB_DN_NULL_FAILED(dst);
p = s = src;
- while (p) {
+ while (*p) {
p += strcspn(p, ",=\n+<>#;\\\"");
if (*p == '\0') /* no special s found, all ok */
break;
@@ -73,17 +73,20 @@ static char *escape_string(void *mem_ctx, const char *src)
memcpy(d, s, &src[strlen(src)] - s + 1);
return dst;
+failed:
+ talloc_free(dst);
+ return NULL;
}
static char *unescape_string(void *mem_ctx, const char *src)
{
unsigned x;
- char *p, *dst, *end;
+ char *p, *dst=NULL, *end;
- LDB_DN_NULL_RETURN(src);
+ LDB_DN_NULL_FAILED(src);
dst = p = talloc_strdup(mem_ctx, src);
- LDB_DN_NULL_RETURN(dst);
+ LDB_DN_NULL_FAILED(dst);
end = &dst[strlen(dst)];
@@ -115,6 +118,9 @@ static char *unescape_string(void *mem_ctx, const char *src)
}
return dst;
+failed:
+ talloc_free(dst);
+ return NULL;
}
static char *seek_to_separator(char *string, const char *separator)
@@ -123,7 +129,7 @@ static char *seek_to_separator(char *string, const char *separator)
p = strchr(string, '=');
- LDB_DN_NULL_RETURN(p);
+ LDB_DN_NULL_FAILED(p);
p++;
@@ -134,7 +140,7 @@ static char *seek_to_separator(char *string, const char *separator)
p++;
while (*p != '\"') {
p = strchr(p, '\"');
- LDB_DN_NULL_RETURN(p);
+ LDB_DN_NULL_FAILED(p);
if (*(p - 1) == '\\')
p++;
@@ -144,6 +150,9 @@ static char *seek_to_separator(char *string, const char *separator)
p += strcspn(p, separator);
return p;
+
+failed:
+ return NULL;
}
static char *ldb_dn_trim_string(char *string, const char *edge)
@@ -169,16 +178,16 @@ static struct ldb_dn_attribute *ldb_dn_explode_attribute(void *mem_ctx, char *ra
char *p;
at = talloc(mem_ctx, struct ldb_dn_attribute);
- LDB_DN_NULL_RETURN(at);
+ LDB_DN_NULL_FAILED(at);
p = strchr(raw_attribute, '=');
- LDB_DN_NULL_RETURN(p);
+ LDB_DN_NULL_FAILED(p);
*p = '\0';
at->name = talloc_strdup(at, ldb_dn_trim_string(raw_attribute, " \n"));
- LDB_DN_NULL_RETURN(at->name);
+ LDB_DN_NULL_FAILED(at->name);
p++;
@@ -196,9 +205,13 @@ static struct ldb_dn_attribute *ldb_dn_explode_attribute(void *mem_ctx, char *ra
}
/* no quotes means we must unescape the string */
at->value = unescape_string(at, p);
- LDB_DN_NULL_RETURN(at->value);
+ 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)
@@ -207,7 +220,7 @@ static struct ldb_dn_component *explode_component(void *mem_ctx, char *raw_compo
char *p;
dc = talloc(mem_ctx, struct ldb_dn_component);
- LDB_DN_NULL_RETURN(dc);
+ LDB_DN_NULL_FAILED(dc);
dc->attr_num = 0;
dc->attributes = NULL;
@@ -220,7 +233,7 @@ static struct ldb_dn_component *explode_component(void *mem_ctx, char *raw_compo
/* terminate the current attribute and return pointer to the next one */
t = seek_to_separator(p, "+");
- LDB_DN_NULL_RETURN(t);
+ LDB_DN_NULL_FAILED(t);
if (*t) { /* here there is a separator */
*t = '\0'; /*terminate */
@@ -231,11 +244,11 @@ static struct ldb_dn_component *explode_component(void *mem_ctx, char *raw_compo
dc->attributes = talloc_realloc(dc, dc->attributes,
struct ldb_dn_attribute *,
dc->attr_num + 1);
- LDB_DN_NULL_RETURN(dc->attributes);
+ 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_RETURN(dc->attributes[dc->attr_num]);
+ LDB_DN_NULL_FAILED(dc->attributes[dc->attr_num]);
dc->attr_num++;
@@ -245,6 +258,9 @@ static struct ldb_dn_component *explode_component(void *mem_ctx, char *raw_compo
} while(*p);
return dc;
+failed:
+ talloc_free(dc);
+ return NULL;
}
/* FIXME: currently consider a dn composed of only case insensitive attributes
@@ -291,7 +307,7 @@ struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn)
/* Allocate a structure to hold the exploded DN */
edn = talloc(mem_ctx, struct ldb_dn);
- LDB_DN_NULL_RETURN(edn);
+ LDB_DN_NULL_FAILED(edn);
/* Initially there are no components */
edn->comp_num = 0;
@@ -299,7 +315,7 @@ struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn)
pdn = p = talloc_strdup(edn, dn);
if (!pdn)
- goto error;
+ goto failed;
/* get the components */
do {
@@ -308,7 +324,7 @@ 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 error;
+ goto failed;
if (*t) { /* here there is a separator */
*t = '\0'; /*terminate */
@@ -320,12 +336,12 @@ struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn)
struct ldb_dn_component *,
edn->comp_num + 1);
if (edn->components == NULL)
- goto error;
+ 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 error;
+ goto failed;
edn->comp_num++;
@@ -340,39 +356,39 @@ struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn)
talloc_free(pdn);
return edn;
-error:
+failed:
talloc_free(edn);
return NULL;
}
char *ldb_dn_linearize(void *mem_ctx, struct ldb_dn *edn)
{
- char *dn, *format, *ename, *evalue;
+ char *dn, *ename, *evalue;
+ const char *format;
int i, j;
dn = talloc_strdup(mem_ctx, "");
- LDB_DN_NULL_RETURN(dn);
+ LDB_DN_NULL_FAILED(dn);
for (i = 0; i < edn->comp_num; i++) {
if (i != 0) {
dn = talloc_append_string(mem_ctx, dn, ",");
}
for (j = 0; j < edn->components[i]->attr_num; j++) {
- if (i != 0 && j == 0)
- format = ",%s=%s";
- else if (i == 0 && j == 0)
+ if (j == 0) {
format = "%s=%s";
- else
+ } else {
format = "+%s=%s";
+ }
- ename = escape_string(mem_ctx, edn->components[i]->attributes[j]->name);
- LDB_DN_NULL_RETURN(ename);
+ ename = escape_string(dn, edn->components[i]->attributes[j]->name);
+ LDB_DN_NULL_FAILED(ename);
- evalue = escape_string(mem_ctx, edn->components[i]->attributes[j]->value);
- LDB_DN_NULL_RETURN(evalue);
+ evalue = escape_string(dn, edn->components[i]->attributes[j]->value);
+ LDB_DN_NULL_FAILED(evalue);
dn = talloc_asprintf_append(dn, format, ename, evalue);
- LDB_DN_NULL_RETURN(dn);
+ LDB_DN_NULL_FAILED(dn);
talloc_free(ename);
talloc_free(evalue);
@@ -380,6 +396,9 @@ char *ldb_dn_linearize(void *mem_ctx, struct ldb_dn *edn)
}
return dn;
+failed:
+ talloc_free(dn);
+ return NULL;
}
/* FIXME: currently consider a dn composed of only case insensitive attributes
@@ -414,6 +433,8 @@ int ldb_dn_compare(struct ldb_dn *edn0, struct ldb_dn *edn1)
return k;
}
}
+
+ return 0;
}
/*
@@ -421,45 +442,50 @@ int ldb_dn_compare(struct ldb_dn *edn0, struct ldb_dn *edn1)
attribute values of case insensitive attributes. We also need to remove
extraneous spaces between elements
*/
-struct ldb_dn *ldb_dn_casefold(void *mem_ctx, struct ldb_dn *edn, void *user_data,
- int (* case_fold_attr_fn)(void * user_data, char * attr))
+struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, struct ldb_dn *edn)
{
struct ldb_dn *cedn;
int i, j;
- cedn = talloc(mem_ctx, struct ldb_dn);
- LDB_DN_NULL_RETURN(cedn);
+ 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);
- LDB_DN_NULL_RETURN(cedn->components);
+ LDB_DN_NULL_FAILED(cedn->components);
for (i = 0; i < edn->comp_num; i++) {
struct ldb_dn_component *dc;
dc = talloc(cedn->components, struct ldb_dn_component);
- LDB_DN_NULL_RETURN(dc);
+ LDB_DN_NULL_FAILED(dc);
dc->attr_num = edn->components[i]->attr_num;
dc->attributes = edn->components[i]->attributes;
- LDB_DN_NULL_RETURN(dc->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_RETURN(at);
+ LDB_DN_NULL_FAILED(at);
at->name = ldb_casefold(at, edn->components[i]->attributes[j]->name);
- LDB_DN_NULL_RETURN(at->name);
-
- if (case_fold_attr_fn(user_data, at->name)) {
- at->value = ldb_casefold(at, edn->components[i]->attributes[j]->value);
- } else {
- at->value = talloc_strdup(at, edn->components[i]->attributes[j]->value);
+ 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;
}
- LDB_DN_NULL_RETURN(at->value);
+ talloc_steal(at, v.data);
+ at->value = v.data;
dc->attributes[j] = at;
}
@@ -467,5 +493,9 @@ struct ldb_dn *ldb_dn_casefold(void *mem_ctx, struct ldb_dn *edn, void *user_dat
}
return cedn;
+
+failed:
+ talloc_free(cedn);
+ return NULL;
}
diff --git a/source4/lib/ldb/common/ldb_ldif.c b/source4/lib/ldb/common/ldb_ldif.c
index f3bc5c6207..deeb84b3c0 100644
--- a/source4/lib/ldb/common/ldb_ldif.c
+++ b/source4/lib/ldb/common/ldb_ldif.c
@@ -45,68 +45,6 @@
#endif
/*
- add to the list of ldif handlers for this ldb context
-*/
-int ldb_ldif_add_handlers(struct ldb_context *ldb,
- const struct ldb_ldif_handler *handlers,
- unsigned num_handlers)
-{
- struct ldb_ldif_handler *h;
- h = talloc_realloc(ldb, ldb->ldif_handlers,
- struct ldb_ldif_handler,
- ldb->ldif_num_handlers + num_handlers);
- if (h == NULL) {
- ldb_oom(ldb);
- return -1;
- }
- ldb->ldif_handlers = h;
- memcpy(h + ldb->ldif_num_handlers,
- handlers, sizeof(*h) * num_handlers);
- ldb->ldif_num_handlers += num_handlers;
- return 0;
-}
-
-
-/*
- default function for ldif read/write
-*/
-static int ldb_ldif_default(struct ldb_context *ldb, const struct ldb_val *in,
- struct ldb_val *out)
-{
- *out = *in;
- return 0;
-}
-
-
-/*
- return a function for reading an ldif encoded attributes into a ldb_val
-*/
-static ldb_ldif_handler_t ldb_ldif_read_fn(struct ldb_context *ldb, const char *attr)
-{
- int i;
- for (i=0;i<ldb->ldif_num_handlers;i++) {
- if (ldb_attr_cmp(attr, ldb->ldif_handlers[i].attr) == 0) {
- return ldb->ldif_handlers[i].read_fn;
- }
- }
- return ldb_ldif_default;
-}
-
-/*
- return a function for writing an ldif encoded attribute from a ldb_val
-*/
-static ldb_ldif_handler_t ldb_ldif_write_fn(struct ldb_context *ldb, const char *attr)
-{
- int i;
- for (i=0;i<ldb->ldif_num_handlers;i++) {
- if (ldb_attr_cmp(attr, ldb->ldif_handlers[i].attr) == 0) {
- return ldb->ldif_handlers[i].write_fn;
- }
- }
- return ldb_ldif_default;
-}
-
-/*
*/
static int ldb_read_data_file(void *mem_ctx, struct ldb_val *value)
@@ -356,6 +294,10 @@ int ldb_ldif_write(struct ldb_context *ldb,
}
for (i=0;i<msg->num_elements;i++) {
+ const struct ldb_attrib_handler *h;
+
+ h = ldb_attrib_handler(ldb, msg->elements[i].name);
+
if (ldif->changetype == LDB_CHANGETYPE_MODIFY) {
switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
case LDB_FLAG_MOD_ADD:
@@ -374,10 +316,8 @@ int ldb_ldif_write(struct ldb_context *ldb,
}
for (j=0;j<msg->elements[i].num_values;j++) {
- ldb_ldif_handler_t write_fn = ldb_ldif_write_fn(ldb,
- msg->elements[i].name);
struct ldb_val v;
- ret = write_fn(ldb, &msg->elements[i].values[j], &v);
+ ret = h->ldif_write_fn(ldb, &msg->elements[i].values[j], &v);
CHECK_RET;
if (ldb_should_b64_encode(&v)) {
ret = fprintf_fn(private_data, "%s:: ",
@@ -650,7 +590,7 @@ struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb,
msg->dn = value.data;
while (next_attr(ldif, &s, &attr, &value) == 0) {
- ldb_ldif_handler_t read_fn;
+ const struct ldb_attrib_handler *h;
struct ldb_message_element *el;
int ret, empty = 0;
@@ -696,7 +636,7 @@ struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb,
el = &msg->elements[msg->num_elements-1];
- read_fn = ldb_ldif_read_fn(ldb, attr);
+ h = ldb_attrib_handler(ldb, attr);
if (msg->num_elements > 0 && ldb_attr_cmp(attr, el->name) == 0 &&
flags == el->flags) {
@@ -707,7 +647,7 @@ struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb,
if (!el->values) {
goto failed;
}
- ret = read_fn(ldb, &value, &el->values[el->num_values]);
+ ret = h->ldif_read_fn(ldb, &value, &el->values[el->num_values]);
if (ret != 0) {
goto failed;
}
@@ -731,7 +671,7 @@ struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb,
goto failed;
}
el->num_values = 1;
- ret = read_fn(ldb, &value, &el->values[0]);
+ ret = h->ldif_read_fn(ldb, &value, &el->values[0]);
if (ret != 0) {
goto failed;
}
diff --git a/source4/lib/ldb/common/ldb_match.c b/source4/lib/ldb/common/ldb_match.c
new file mode 100644
index 0000000000..45a482066e
--- /dev/null
+++ b/source4/lib/ldb/common/ldb_match.c
@@ -0,0 +1,260 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004-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 expression matching
+ *
+ * Description: ldb expression matching
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb/include/ldb.h"
+#include "ldb/include/ldb_private.h"
+
+
+/*
+ check if the scope matches in a search result
+*/
+static int ldb_match_scope(const char *dn, const char *base, enum ldb_scope scope)
+{
+ size_t dn_len, base_len;
+
+ if (base == NULL) {
+ return 1;
+ }
+
+ base_len = strlen(base);
+ dn_len = strlen(dn);
+
+ if (scope != LDB_SCOPE_ONELEVEL && ldb_dn_cmp(dn, base) == 0) {
+ return 1;
+ }
+
+ if (base_len+1 >= dn_len) {
+ return 0;
+ }
+
+ switch (scope) {
+ case LDB_SCOPE_BASE:
+ break;
+
+ case LDB_SCOPE_ONELEVEL:
+ if (ldb_dn_cmp(dn + (dn_len - base_len), base) == 0 &&
+ dn[dn_len - base_len - 1] == ',' &&
+ strchr(dn, ',') == &dn[dn_len - base_len - 1]) {
+ return 1;
+ }
+ break;
+
+ case LDB_SCOPE_SUBTREE:
+ default:
+ if (ldb_dn_cmp(dn + (dn_len - base_len), base) == 0 &&
+ dn[dn_len - base_len - 1] == ',') {
+ return 1;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+
+/*
+ match a leaf node
+*/
+static int ldb_match_leaf(struct ldb_context *ldb,
+ struct ldb_message *msg,
+ struct ldb_parse_tree *tree,
+ const char *base,
+ enum ldb_scope scope)
+{
+ unsigned int i;
+ struct ldb_message_element *el;
+ const struct ldb_attrib_handler *h;
+
+ if (!ldb_match_scope(msg->dn, base, scope)) {
+ return 0;
+ }
+
+ if (ldb_attr_cmp(tree->u.simple.attr, "dn") == 0) {
+ if (strcmp(tree->u.simple.value.data, "*") == 0) {
+ return 1;
+ }
+ return ldb_dn_cmp(msg->dn, tree->u.simple.value.data) == 0;
+ }
+
+ el = ldb_msg_find_element(msg, tree->u.simple.attr);
+ if (el == NULL) {
+ return 0;
+ }
+
+ if (strcmp(tree->u.simple.value.data, "*") == 0) {
+ return 1;
+ }
+
+ h = ldb_attrib_handler(ldb, el->name);
+
+ for (i=0;i<el->num_values;i++) {
+ if (h->comparison_fn(ldb, &tree->u.simple.value,
+ &el->values[i]) == 0) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ bitwise-and comparator
+*/
+static int ldb_comparator_and(struct ldb_val *v1, struct ldb_val *v2)
+{
+ uint64_t i1, i2;
+ i1 = strtoull(v1->data, NULL, 0);
+ i2 = strtoull(v2->data, NULL, 0);
+ return ((i1 & i2) == i2);
+}
+
+/*
+ bitwise-or comparator
+*/
+static int ldb_comparator_or(struct ldb_val *v1, struct ldb_val *v2)
+{
+ uint64_t i1, i2;
+ i1 = strtoull(v1->data, NULL, 0);
+ i2 = strtoull(v2->data, NULL, 0);
+ return ((i1 & i2) != 0);
+}
+
+
+/*
+ extended match, handles things like bitops
+*/
+static int ldb_match_extended(struct ldb_context *ldb,
+ struct ldb_message *msg,
+ struct ldb_parse_tree *tree,
+ const char *base,
+ enum ldb_scope scope)
+{
+ int i;
+ const struct {
+ const char *oid;
+ int (*comparator)(struct ldb_val *, struct ldb_val *);
+ } rules[] = {
+ { LDB_OID_COMPARATOR_AND, ldb_comparator_and},
+ { LDB_OID_COMPARATOR_OR, ldb_comparator_or}
+ };
+ int (*comp)(struct ldb_val *, struct ldb_val *) = NULL;
+ struct ldb_message_element *el;
+
+ if (tree->u.extended.dnAttributes) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: dnAttributes extended match not supported yet");
+ return -1;
+ }
+ if (tree->u.extended.rule_id == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet");
+ return -1;
+ }
+ if (tree->u.extended.attr == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-attribute extended matches not supported yet");
+ return -1;
+ }
+
+ for (i=0;i<ARRAY_SIZE(rules);i++) {
+ if (strcmp(rules[i].oid, tree->u.extended.rule_id) == 0) {
+ comp = rules[i].comparator;
+ break;
+ }
+ }
+ if (comp == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s\n",
+ tree->u.extended.rule_id);
+ return -1;
+ }
+
+ /* find the message element */
+ el = ldb_msg_find_element(msg, tree->u.extended.attr);
+ if (el == NULL) {
+ return 0;
+ }
+
+ for (i=0;i<el->num_values;i++) {
+ int ret = comp(&el->values[i], &tree->u.extended.value);
+ if (ret == -1 || ret == 1) return ret;
+ }
+
+ return 0;
+}
+
+/*
+ return 0 if the given parse tree matches the given message. Assumes
+ the message is in sorted order
+
+ return 1 if it matches, and 0 if it doesn't match
+
+ this is a recursive function, and does short-circuit evaluation
+ */
+int ldb_match_message(struct ldb_context *ldb,
+ struct ldb_message *msg,
+ struct ldb_parse_tree *tree,
+ const char *base,
+ enum ldb_scope scope)
+{
+ unsigned int i;
+ int v;
+
+ switch (tree->operation) {
+ case LDB_OP_SIMPLE:
+ break;
+
+ case LDB_OP_EXTENDED:
+ return ldb_match_extended(ldb, msg, tree, base, scope);
+
+ case LDB_OP_NOT:
+ return ! ldb_match_message(ldb, msg, tree->u.not.child, base, scope);
+
+ case LDB_OP_AND:
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ v = ldb_match_message(ldb, msg, tree->u.list.elements[i],
+ base, scope);
+ if (!v) return 0;
+ }
+ return 1;
+
+ case LDB_OP_OR:
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ v = ldb_match_message(ldb, msg, tree->u.list.elements[i],
+ base, scope);
+ if (v) return 1;
+ }
+ return 0;
+ }
+
+ return ldb_match_leaf(ldb, msg, tree, base, scope);
+}
diff --git a/source4/lib/ldb/common/ldb_utf8.c b/source4/lib/ldb/common/ldb_utf8.c
index 0c1ea6ca81..38c117d7e0 100644
--- a/source4/lib/ldb/common/ldb_utf8.c
+++ b/source4/lib/ldb/common/ldb_utf8.c
@@ -84,8 +84,8 @@ int ldb_dn_cmp(const char *dn1, const char *dn2)
compare two attributes
return 0 for match
*/
-int ldb_attr_cmp(const char *dn1, const char *dn2)
+int ldb_attr_cmp(const char *attr1, const char *attr2)
{
- return ldb_caseless_cmp(dn1, dn2);
+ return ldb_caseless_cmp(attr1, attr2);
}