summaryrefslogtreecommitdiff
path: root/source4/lib/ldb
diff options
context:
space:
mode:
Diffstat (limited to 'source4/lib/ldb')
-rw-r--r--source4/lib/ldb/Makefile.in5
-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
-rw-r--r--source4/lib/ldb/config.mk4
-rw-r--r--source4/lib/ldb/include/ldb.h40
-rw-r--r--source4/lib/ldb/include/ldb_dn.h3
-rw-r--r--source4/lib/ldb/include/ldb_private.h51
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_cache.c188
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_index.c112
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_match.c426
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_search.c15
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_tdb.c65
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_tdb.h19
-rw-r--r--source4/lib/ldb/samba/ldif_handlers.c26
19 files changed, 1368 insertions, 684 deletions
diff --git a/source4/lib/ldb/Makefile.in b/source4/lib/ldb/Makefile.in
index 4a065ba83f..2f82f63714 100644
--- a/source4/lib/ldb/Makefile.in
+++ b/source4/lib/ldb/Makefile.in
@@ -44,7 +44,7 @@ LIB_FLAGS=-Llib -lldb $(LDAP_LIBS) $(SQLITE3_LIBS) $(GCOV_LIBS) @LIBS@
TDB_OBJ=$(TDBDIR)/common/tdb.o $(TDBDIR)/common/spinlock.o
TALLOC_OBJ=$(TALLOCDIR)/talloc.o
-LDB_TDB_OBJ=ldb_tdb/ldb_match.o ldb_tdb/ldb_tdb.o \
+LDB_TDB_OBJ=ldb_tdb/ldb_tdb.o \
ldb_tdb/ldb_pack.o ldb_tdb/ldb_search.o ldb_tdb/ldb_index.o \
ldb_tdb/ldb_cache.o
@@ -52,7 +52,8 @@ LDB_TDB_OBJ=ldb_tdb/ldb_match.o ldb_tdb/ldb_tdb.o \
COMMON_OBJ=common/ldb.o common/ldb_ldif.o \
common/ldb_parse.o common/ldb_msg.o common/ldb_utf8.o \
common/ldb_debug.o common/ldb_modules.o \
- common/ldb_dn.o
+ common/ldb_dn.o common/ldb_match.o common/ldb_attributes.o \
+ common/attrib_handlers.o
MODULES_OBJ=modules/timestamps.o modules/schema.o
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);
}
diff --git a/source4/lib/ldb/config.mk b/source4/lib/ldb/config.mk
index 691af8bcfa..83de5730d4 100644
--- a/source4/lib/ldb/config.mk
+++ b/source4/lib/ldb/config.mk
@@ -50,7 +50,6 @@ ADD_OBJ_FILES = \
lib/ldb/ldb_tdb/ldb_search.o \
lib/ldb/ldb_tdb/ldb_pack.o \
lib/ldb/ldb_tdb/ldb_index.o \
- lib/ldb/ldb_tdb/ldb_match.o \
lib/ldb/ldb_tdb/ldb_cache.o
REQUIRED_SUBSYSTEMS = \
LIBTDB
@@ -70,6 +69,9 @@ ADD_OBJ_FILES = \
lib/ldb/common/ldb_utf8.o \
lib/ldb/common/ldb_debug.o \
lib/ldb/common/ldb_modules.o \
+ lib/ldb/common/ldb_match.o \
+ lib/ldb/common/ldb_attributes.o \
+ lib/ldb/common/attrib_handlers.o \
lib/ldb/common/ldb_dn.o
REQUIRED_SUBSYSTEMS = \
LIBREPLACE LIBTALLOC LDBSAMBA
diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h
index 8feec9e002..868d005399 100644
--- a/source4/lib/ldb/include/ldb.h
+++ b/source4/lib/ldb/include/ldb.h
@@ -186,16 +186,40 @@ char *ldb_binary_encode(void *ctx, struct ldb_val val);
/*
- functions for controlling ldif encode/decode
+ functions for controlling attribute handling
*/
-typedef int (*ldb_ldif_handler_t)(struct ldb_context *, const struct ldb_val *, struct ldb_val *);
+typedef int (*ldb_attr_handler_t)(struct ldb_context *, const struct ldb_val *, struct ldb_val *);
+typedef int (*ldb_attr_comparison_t)(struct ldb_context *, const struct ldb_val *, const struct ldb_val *);
-struct ldb_ldif_handler {
+struct ldb_attrib_handler {
const char *attr;
- ldb_ldif_handler_t read_fn;
- ldb_ldif_handler_t write_fn;
+
+ /* LDB_ATTR_FLAG_* */
+ unsigned flags;
+
+ /* convert from ldif to binary format */
+ ldb_attr_handler_t ldif_read_fn;
+
+ /* convert from binary to ldif format */
+ ldb_attr_handler_t ldif_write_fn;
+
+ /* canonicalise a value, for use by indexing and dn construction */
+ ldb_attr_handler_t canonicalise_fn;
+
+ /* compare two values */
+ ldb_attr_comparison_t comparison_fn;
};
+#define LDB_ATTR_FLAG_HIDDEN (1<<0)
+#define LDB_ATTR_FLAG_WILDCARD (1<<1)
+
+/* well-known ldap attribute syntaxes - see rfc2252 section 4.3.2 */
+#define LDB_SYNTAX_DN "1.3.6.1.4.1.1466.115.121.1.12"
+#define LDB_SYNTAX_DIRECTORY_STRING "1.3.6.1.4.1.1466.115.121.1.15"
+#define LDB_SYNTAX_INTEGER "1.3.6.1.4.1.1466.115.121.1.27"
+#define LDB_SYNTAX_OCTET_STRING "1.3.6.1.4.1.1466.115.121.1.40"
+#define LDB_SYNTAX_WILDCARD "LDB_SYNTAX_WILDCARD"
+#define LDB_SYNTAX_OBJECTCLASS "LDB_SYNTAX_OBJECTCLASS"
/*
initialise a ldb context
@@ -296,9 +320,9 @@ struct ldb_ldif *ldb_ldif_read_string(struct ldb_context *ldb, const char *s);
int ldb_ldif_write_file(struct ldb_context *ldb, FILE *f, const struct ldb_ldif *msg);
char *ldb_base64_encode(void *mem_ctx, const char *buf, int len);
int ldb_base64_decode(char *s);
-int ldb_ldif_add_handlers(struct ldb_context *ldb,
- const struct ldb_ldif_handler *handlers,
- unsigned num_handlers);
+int ldb_attrib_add_handlers(struct ldb_context *ldb,
+ const struct ldb_attrib_handler *handlers,
+ unsigned num_handlers);
/* useful functions for ldb_message structure manipulation */
diff --git a/source4/lib/ldb/include/ldb_dn.h b/source4/lib/ldb/include/ldb_dn.h
index f355ee4879..723b89e316 100644
--- a/source4/lib/ldb/include/ldb_dn.h
+++ b/source4/lib/ldb/include/ldb_dn.h
@@ -38,5 +38,4 @@ struct ldb_dn {
struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn);
char *ldb_dn_linearize(void *mem_ctx, struct ldb_dn *edn);
int ldb_dn_compare(struct ldb_dn *edn0, struct ldb_dn *edn1);
-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);
diff --git a/source4/lib/ldb/include/ldb_private.h b/source4/lib/ldb/include/ldb_private.h
index f6c1c7ff46..43c925e036 100644
--- a/source4/lib/ldb/include/ldb_private.h
+++ b/source4/lib/ldb/include/ldb_private.h
@@ -68,6 +68,23 @@ struct ldb_module_ops {
const char * (*errstring)(struct ldb_module *);
};
+
+/*
+ schema related information needed for matching rules
+*/
+struct ldb_schema {
+ /* attribute handling table */
+ unsigned num_attrib_handlers;
+ struct ldb_attrib_handler *attrib_handlers;
+
+ /* objectclass information */
+ unsigned num_classes;
+ struct ldb_subclass {
+ char *name;
+ char **subclasses;
+ } *classes;
+};
+
/*
every ldb connection is started by establishing a ldb_context
*/
@@ -85,9 +102,7 @@ struct ldb_context {
void *value;
} *opaque;
- /* ldif attribute handling table */
- unsigned ldif_num_handlers;
- struct ldb_ldif_handler *ldif_handlers;
+ struct ldb_schema schema;
};
/* the modules init function */
@@ -146,4 +161,34 @@ int lsqlite3_connect(struct ldb_context *ldb,
struct ldb_module *timestamps_module_init(struct ldb_context *ldb, const char *options[]);
struct ldb_module *schema_module_init(struct ldb_context *ldb, const char *options[]);
+const struct ldb_attrib_handler *ldb_attrib_handler(struct ldb_context *ldb,
+ const char *attrib);
+
+int ldb_match_message(struct ldb_context *ldb,
+ struct ldb_message *msg,
+ struct ldb_parse_tree *tree,
+ const char *base,
+ enum ldb_scope scope);
+
+void ldb_remove_attrib_handler(struct ldb_context *ldb, const char *attrib);
+const struct ldb_attrib_handler *ldb_attrib_handler_syntax(struct ldb_context *ldb,
+ const char *syntax);
+int ldb_set_attrib_handlers(struct ldb_context *ldb,
+ const struct ldb_attrib_handler *handlers,
+ unsigned num_handlers);
+int ldb_setup_wellknown_attributes(struct ldb_context *ldb);
+
+struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn);
+char *ldb_dn_linearize(void *mem_ctx, struct ldb_dn *edn);
+int ldb_dn_compare(struct ldb_dn *edn0, struct ldb_dn *edn1);
+struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, struct ldb_dn *edn);
+const char **ldb_subclass_list(struct ldb_context *ldb, const char *class);
+void ldb_subclass_remove(struct ldb_context *ldb, const char *class);
+int ldb_subclass_add(struct ldb_context *ldb, const char *class, const char *subclass);
+
+int ldb_handler_copy(struct ldb_context *ldb,
+ const struct ldb_val *in, struct ldb_val *out);
+int ldb_comparison_binary(struct ldb_context *ldb,
+ const struct ldb_val *v1, const struct ldb_val *v2);
+
#endif
diff --git a/source4/lib/ldb/ldb_tdb/ldb_cache.c b/source4/lib/ldb/ldb_tdb/ldb_cache.c
index 0bc2d7b123..0b7ddad5db 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_cache.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_cache.c
@@ -37,6 +37,11 @@
#include "ldb/include/ldb_private.h"
#include "ldb/ldb_tdb/ldb_tdb.h"
+#define LTDB_FLAG_CASE_INSENSITIVE (1<<0)
+#define LTDB_FLAG_INTEGER (1<<1)
+#define LTDB_FLAG_WILDCARD (1<<2)
+#define LTDB_FLAG_HIDDEN (1<<3)
+#define LTDB_FLAG_OBJECTCLASS (1<<4)
/* valid attribute flags */
static const struct {
@@ -47,12 +52,182 @@ static const struct {
{ "INTEGER", LTDB_FLAG_INTEGER },
{ "WILDCARD", LTDB_FLAG_WILDCARD },
{ "HIDDEN", LTDB_FLAG_HIDDEN },
- { "NONE", LTDB_FLAG_NONE },
+ { "NONE", 0 },
{ NULL, 0 }
};
/*
+ de-register any special handlers for @ATTRIBUTES
+*/
+static void ltdb_attributes_unload(struct ldb_module *module)
+{
+ struct ltdb_private *ltdb = module->private_data;
+ struct ldb_message *msg;
+ int i;
+
+ if (ltdb->cache->attributes == NULL) {
+ /* no previously loaded attributes */
+ return;
+ }
+
+ msg = ltdb->cache->attributes;
+ for (i=0;i<msg->num_elements;i++) {
+ const struct ldb_attrib_handler *h;
+ /* this is rather ugly - a consequence of const handling */
+ h = ldb_attrib_handler(module->ldb, msg->elements[i].name);
+ ldb_remove_attrib_handler(module->ldb, msg->elements[i].name);
+ if (strcmp(h->attr, msg->elements[i].name) == 0) {
+ talloc_steal(msg, h->attr);
+ }
+ }
+
+ talloc_free(ltdb->cache->attributes);
+ ltdb->cache->attributes = NULL;
+}
+
+/*
+ add up the attrib flags for a @ATTRIBUTES element
+*/
+static int ltdb_attributes_flags(struct ldb_message_element *el, unsigned *v)
+{
+ int i;
+ unsigned value = 0;
+ for (i=0;i<el->num_values;i++) {
+ int j;
+ for (j=0;ltdb_valid_attr_flags[j].name;j++) {
+ if (strcmp(ltdb_valid_attr_flags[j].name,
+ el->values[i].data) == 0) {
+ value |= ltdb_valid_attr_flags[j].value;
+ break;
+ }
+ }
+ if (ltdb_valid_attr_flags[j].name == NULL) {
+ return -1;
+ }
+ }
+ *v = value;
+ return 0;
+}
+
+/*
+ register any special handlers from @ATTRIBUTES
+*/
+static int ltdb_attributes_load(struct ldb_module *module)
+{
+ struct ltdb_private *ltdb = module->private_data;
+ struct ldb_message *msg = ltdb->cache->attributes;
+ int i;
+
+ if (ltdb_search_dn1(module, LTDB_ATTRIBUTES, msg) == -1) {
+ goto failed;
+ }
+ /* mapping these flags onto ldap 'syntaxes' isn't strictly correct,
+ but its close enough for now */
+ for (i=0;i<msg->num_elements;i++) {
+ unsigned flags;
+ const char *syntax;
+ const struct ldb_attrib_handler *h;
+ struct ldb_attrib_handler h2;
+
+ if (ltdb_attributes_flags(&msg->elements[i], &flags) != 0) {
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Invalid @ATTRIBUTES element for '%s'\n", msg->elements[i].name);
+ goto failed;
+ }
+ switch (flags & ~LTDB_FLAG_HIDDEN) {
+ case 0:
+ syntax = LDB_SYNTAX_OCTET_STRING;
+ break;
+ case LTDB_FLAG_WILDCARD:
+ case LTDB_FLAG_WILDCARD | LTDB_FLAG_CASE_INSENSITIVE:
+ syntax = LDB_SYNTAX_WILDCARD;
+ break;
+ case LTDB_FLAG_CASE_INSENSITIVE:
+ syntax = LDB_SYNTAX_DIRECTORY_STRING;
+ break;
+ case LTDB_FLAG_INTEGER:
+ syntax = LDB_SYNTAX_INTEGER;
+ break;
+ default:
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR,
+ "Invalid flag combination 0x%x for '%s' in @ATTRIBUTES\n",
+ flags, msg->elements[i].name);
+ goto failed;
+ }
+
+ h = ldb_attrib_handler_syntax(module->ldb, syntax);
+ if (h == NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR,
+ "Invalid attribute syntax '%s' for '%s' in @ATTRIBUTES\n",
+ syntax, msg->elements[i].name);
+ goto failed;
+ }
+ h2 = *h;
+ h2.attr = talloc_strdup(module, msg->elements[i].name);
+ if (ldb_set_attrib_handlers(module->ldb, &h2, 1) != 0) {
+ goto failed;
+ }
+ }
+
+ return 0;
+failed:
+ return -1;
+}
+
+
+/*
+ register any subclasses from @SUBCLASSES
+*/
+static int ltdb_subclasses_load(struct ldb_module *module)
+{
+ struct ltdb_private *ltdb = module->private_data;
+ struct ldb_message *msg = ltdb->cache->subclasses;
+ int i, j;
+
+ if (ltdb_search_dn1(module, LTDB_SUBCLASSES, msg) == -1) {
+ goto failed;
+ }
+
+ for (i=0;i<msg->num_elements;i++) {
+ struct ldb_message_element *el = &msg->elements[i];
+ for (j=0;j<el->num_values;j++) {
+ if (ldb_subclass_add(module->ldb, el->name, el->values[j].data) != 0) {
+ goto failed;
+ }
+ }
+ }
+
+ return 0;
+failed:
+ return -1;
+}
+
+
+/*
+ de-register any @SUBCLASSES
+*/
+static void ltdb_subclasses_unload(struct ldb_module *module)
+{
+ struct ltdb_private *ltdb = module->private_data;
+ struct ldb_message *msg;
+ int i;
+
+ if (ltdb->cache->subclasses == NULL) {
+ /* no previously loaded subclasses */
+ return;
+ }
+
+ msg = ltdb->cache->subclasses;
+ for (i=0;i<msg->num_elements;i++) {
+ ldb_subclass_remove(module->ldb, msg->elements[i].name);
+ }
+
+ talloc_free(ltdb->cache->subclasses);
+ ltdb->cache->subclasses = NULL;
+}
+
+
+/*
initialise the baseinfo record
*/
static int ltdb_baseinfo_init(struct ldb_module *module)
@@ -122,6 +297,8 @@ static void ltdb_cache_free(struct ldb_module *module)
*/
int ltdb_cache_reload(struct ldb_module *module)
{
+ ltdb_attributes_unload(module);
+ ltdb_subclasses_unload(module);
ltdb_cache_free(module);
return ltdb_cache_load(module);
}
@@ -176,9 +353,11 @@ int ltdb_cache_load(struct ldb_module *module)
talloc_free(ltdb->cache->last_attribute.name);
memset(&ltdb->cache->last_attribute, 0, sizeof(ltdb->cache->last_attribute));
+ ltdb_attributes_unload(module);
+ ltdb_subclasses_unload(module);
+
talloc_free(ltdb->cache->indexlist);
talloc_free(ltdb->cache->subclasses);
- talloc_free(ltdb->cache->attributes);
ltdb->cache->indexlist = talloc_zero(ltdb->cache, struct ldb_message);
ltdb->cache->subclasses = talloc_zero(ltdb->cache, struct ldb_message);
@@ -192,10 +371,11 @@ int ltdb_cache_load(struct ldb_module *module)
if (ltdb_search_dn1(module, LTDB_INDEXLIST, ltdb->cache->indexlist) == -1) {
goto failed;
}
- if (ltdb_search_dn1(module, LTDB_SUBCLASSES, ltdb->cache->subclasses) == -1) {
+
+ if (ltdb_attributes_load(module) == -1) {
goto failed;
}
- if (ltdb_search_dn1(module, LTDB_ATTRIBUTES, ltdb->cache->attributes) == -1) {
+ if (ltdb_subclasses_load(module) == -1) {
goto failed;
}
diff --git a/source4/lib/ldb/ldb_tdb/ldb_index.c b/source4/lib/ldb/ldb_tdb/ldb_index.c
index 00b124a9cf..4d8a14f7f0 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_index.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_index.c
@@ -101,17 +101,45 @@ static char *ldb_dn_key(struct ldb_context *ldb,
const char *attr, const struct ldb_val *value)
{
char *ret = NULL;
+ struct ldb_val v;
+ const struct ldb_attrib_handler *h;
+ char *attr_folded;
- if (ldb_should_b64_encode(value)) {
+ attr_folded = ldb_casefold(ldb, attr);
+ if (!attr_folded) {
+ return NULL;
+ }
+
+ h = ldb_attrib_handler(ldb, attr);
+ if (h->canonicalise_fn(ldb, value, &v) != 0) {
+ /* canonicalisation can be refused. For example,
+ a attribute that takes wildcards will refuse to canonicalise
+ if the value contains a wildcard */
+ talloc_free(attr_folded);
+ return NULL;
+ }
+
+ if (ldb_should_b64_encode(&v)) {
char *vstr = ldb_base64_encode(ldb, value->data, value->length);
if (!vstr) return NULL;
- ret = talloc_asprintf(ldb, "%s:%s::%s", LTDB_INDEX, attr, vstr);
+ ret = talloc_asprintf(ldb, "%s:%s::%s", LTDB_INDEX, attr_folded, vstr);
talloc_free(vstr);
+ if (v.data != value->data) {
+ talloc_free(v.data);
+ }
+ talloc_free(attr_folded);
return ret;
}
- return talloc_asprintf(ldb, "%s:%s:%.*s",
- LTDB_INDEX, attr, value->length, (char *)value->data);
+ ret = talloc_asprintf(ldb, "%s:%s:%.*s",
+ LTDB_INDEX, attr_folded, v.length, (char *)v.data);
+
+ if (v.data != value->data) {
+ talloc_free(v.data);
+ }
+ talloc_free(attr_folded);
+
+ return ret;
}
/*
@@ -234,46 +262,50 @@ static int ltdb_index_dn_objectclass(struct ldb_module *module,
struct dn_list *list)
{
struct ldb_context *ldb = module->ldb;
- struct ltdb_private *ltdb = module->private_data;
unsigned int i;
int ret;
const char *target = tree->u.simple.value.data;
+ const char **subclasses;
list->count = 0;
list->dn = NULL;
ret = ltdb_index_dn_simple(module, tree, index_list, list);
- for (i=0;i<ltdb->cache->subclasses->num_elements;i++) {
- struct ldb_message_element *el = &ltdb->cache->subclasses->elements[i];
- if (ldb_attr_cmp(el->name, target) == 0) {
- unsigned int j;
- for (j=0;j<el->num_values;j++) {
- struct ldb_parse_tree tree2;
- struct dn_list *list2;
- tree2.operation = LDB_OP_SIMPLE;
- tree2.u.simple.attr = talloc_strdup(list, LTDB_OBJECTCLASS);
- if (!tree2.u.simple.attr) {
- return -1;
- }
- tree2.u.simple.value = el->values[j];
- list2 = talloc(list, struct dn_list);
- if (list2 == NULL) {
- return -1;
- }
- if (ltdb_index_dn_objectclass(module, &tree2,
- index_list, list2) == 1) {
- if (list->count == 0) {
- *list = *list2;
- ret = 1;
- } else {
- list_union(ldb, list, list2);
- talloc_free(list2);
- }
- }
- talloc_free(tree2.u.simple.attr);
+ subclasses = ldb_subclass_list(module->ldb, target);
+
+ if (subclasses == NULL) {
+ return ret;
+ }
+
+ for (i=0;subclasses[i];i++) {
+ struct ldb_parse_tree tree2;
+ struct dn_list *list2;
+ tree2.operation = LDB_OP_SIMPLE;
+ tree2.u.simple.attr = talloc_strdup(list, LTDB_OBJECTCLASS);
+ if (!tree2.u.simple.attr) {
+ return -1;
+ }
+ tree2.u.simple.value.data = talloc_strdup(tree2.u.simple.attr, subclasses[i]);
+ if (tree2.u.simple.value.data == NULL) {
+ return -1;
+ }
+ tree2.u.simple.value.length = strlen(subclasses[i]);
+ list2 = talloc(list, struct dn_list);
+ if (list2 == NULL) {
+ return -1;
+ }
+ if (ltdb_index_dn_objectclass(module, &tree2,
+ index_list, list2) == 1) {
+ if (list->count == 0) {
+ *list = *list2;
+ ret = 1;
+ } else {
+ list_union(ldb, list, list2);
+ talloc_free(list2);
}
}
+ talloc_free(tree2.u.simple.attr);
}
return ret;
@@ -607,7 +639,7 @@ static int ldb_index_filter(struct ldb_module *module, struct ldb_parse_tree *tr
}
ret = 0;
- if (ltdb_message_match(module, msg, tree, base, scope) == 1) {
+ if (ldb_match_message(module->ldb, msg, tree, base, scope) == 1) {
ret = ltdb_add_attr_results(module, msg, attrs, &count, res);
}
talloc_free(msg);
@@ -799,6 +831,10 @@ int ltdb_index_add(struct ldb_module *module, const struct ldb_message *msg)
int ret;
unsigned int i, j;
+ if (msg->dn[0] == '@') {
+ return 0;
+ }
+
if (ltdb->cache->indexlist->num_elements == 0) {
/* no indexed fields */
return 0;
@@ -834,6 +870,10 @@ int ltdb_index_del_value(struct ldb_module *module, const char *dn,
int ret, i;
unsigned int j;
+ if (dn[0] == '@') {
+ return 0;
+ }
+
dn_key = ldb_dn_key(ldb, el->name, &el->values[v_idx]);
if (!dn_key) {
return -1;
@@ -895,6 +935,10 @@ int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg)
int ret;
unsigned int i, j;
+ if (msg->dn[0] == '@') {
+ return 0;
+ }
+
/* find the list of indexed fields */
if (ltdb->cache->indexlist->num_elements == 0) {
/* no indexed fields */
diff --git a/source4/lib/ldb/ldb_tdb/ldb_match.c b/source4/lib/ldb/ldb_tdb/ldb_match.c
deleted file mode 100644
index b5b023bc09..0000000000
--- a/source4/lib/ldb/ldb_tdb/ldb_match.c
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- ldb database library
-
- Copyright (C) Andrew Tridgell 2004
-
- ** 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 for tdb backend
- *
- * Author: Andrew Tridgell
- */
-
-#include "includes.h"
-#include "ldb/include/ldb.h"
-#include "ldb/include/ldb_private.h"
-#include "ldb/ldb_tdb/ldb_tdb.h"
-#include <fnmatch.h>
-
-/*
- see if two ldb_val structures contain the same data as integers
- return 1 for a match, 0 for a mis-match
-*/
-static int ltdb_val_equal_integer(const struct ldb_val *v1, const struct ldb_val *v2)
-{
- uint64_t i1, i2;
-
- i1 = strtoull(v1->data, NULL, 0);
- i2 = strtoull(v2->data, NULL, 0);
-
- return i1 == i2;
-}
-
-/*
- see if two ldb_val structures contain the same data as case insensitive strings
- return 1 for a match, 0 for a mis-match
-*/
-static int ltdb_val_equal_case_insensitive(const struct ldb_val *v1,
- const struct ldb_val *v2)
-{
- if (v1->length != v2->length) {
- return 0;
- }
- if (strncasecmp(v1->data, v2->data, v1->length) == 0) {
- return 1;
- }
- return 0;
-}
-
-/*
- see if two ldb_val structures contain the same data with wildcards
- and case insensitive
- return 1 for a match, 0 for a mis-match
-*/
-static int ltdb_val_equal_wildcard_ci(struct ldb_module *module,
- const struct ldb_val *v1,
- const struct ldb_val *v2)
-{
- struct ldb_context *ldb = module->ldb;
- char *s1, *s2;
- int ret;
-
- if (!v1->data || !v2->data) {
- return v1->data == v2->data;
- }
-
- s1 = ldb_casefold(ldb, v1->data);
- if (!s1) {
- return -1;
- }
-
- s2 = ldb_casefold(ldb, v2->data);
- if (!s2) {
- talloc_free(s1);
- return -1;
- }
-
- ret = fnmatch(s2, s1, 0);
-
- talloc_free(s1);
- talloc_free(s2);
-
- if (ret == 0) {
- return 1;
- }
-
- return 0;
-}
-
-/*
- see if two ldb_val structures contain the same data with wildcards
- return 1 for a match, 0 for a mis-match
-*/
-static int ltdb_val_equal_wildcard(struct ldb_module *module,
- const struct ldb_val *v1,
- const struct ldb_val *v2,
- int flags)
-{
- if (flags & LTDB_FLAG_CASE_INSENSITIVE) {
- return ltdb_val_equal_wildcard_ci(module, v1, v2);
- }
- if (!v1->data || !v2->data) {
- return v1->data == v2->data;
- }
- if (fnmatch(v2->data, v1->data, 0) == 0) {
- return 1;
- }
- return 0;
-}
-
-
-/*
- see if two objectclasses are considered equal. This handles
- the subclass attributes
-
- v1 contains the in-database value, v2 contains the value
- that the user gave
-
- return 1 for a match, 0 for a mis-match
-*/
-static int ltdb_val_equal_objectclass(struct ldb_module *module,
- const struct ldb_val *v1, const struct ldb_val *v2)
-{
- struct ltdb_private *ltdb = module->private_data;
- unsigned int i;
-
- if (ltdb_val_equal_case_insensitive(v1, v2) == 1) {
- return 1;
- }
-
- for (i=0;i<ltdb->cache->subclasses->num_elements;i++) {
- struct ldb_message_element *el = &ltdb->cache->subclasses->elements[i];
- if (ldb_attr_cmp(el->name, v2->data) == 0) {
- unsigned int j;
- for (j=0;j<el->num_values;j++) {
- if (ltdb_val_equal_objectclass(module, v1, &el->values[j])) {
- return 1;
- }
- }
- }
- }
-
- return 0;
-}
-
-
-/*
- see if two ldb_val structures contain the same data
-
- v1 contains the in-database value, v2 contains the value
- that the user gave
-
- return 1 for a match, 0 for a mis-match
-*/
-int ltdb_val_equal(struct ldb_module *module,
- const char *attr_name,
- const struct ldb_val *v1, const struct ldb_val *v2)
-{
- int flags = ltdb_attribute_flags(module, attr_name);
-
- if (flags & LTDB_FLAG_OBJECTCLASS) {
- return ltdb_val_equal_objectclass(module, v1, v2);
- }
-
- if (flags & LTDB_FLAG_INTEGER) {
- return ltdb_val_equal_integer(v1, v2);
- }
-
- if (flags & LTDB_FLAG_WILDCARD) {
- return ltdb_val_equal_wildcard(module, v1, v2, flags);
- }
-
- if (flags & LTDB_FLAG_CASE_INSENSITIVE) {
- return ltdb_val_equal_case_insensitive(v1, v2);
- }
-
- if (v1->length != v2->length) return 0;
-
- if (v1->length == 0) return 1;
-
- if (memcmp(v1->data, v2->data, v1->length) == 0) {
- return 1;
- }
-
- return 0;
-}
-
-/*
- check if the scope matches in a search result
-*/
-static int scope_match(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 match_leaf(struct ldb_module *module,
- struct ldb_message *msg,
- struct ldb_parse_tree *tree,
- const char *base,
- enum ldb_scope scope)
-{
- unsigned int i;
- struct ldb_message_element *el;
-
- if (!scope_match(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;
- }
-
- for (i=0;i<el->num_values;i++) {
- if (ltdb_val_equal(module, el->name, &el->values[i],
- &tree->u.simple.value)) {
- return 1;
- }
- }
-
- return 0;
-}
-
-
-/*
- bitwise-and comparator
-*/
-static int 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 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 ltdb_extended_match(struct ldb_module *module,
- 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, comparator_and},
- { LDB_OID_COMPARATOR_OR, comparator_or}
- };
- int (*comp)(struct ldb_val *, struct ldb_val *) = NULL;
- struct ldb_message_element *el;
-
- if (tree->u.extended.dnAttributes) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb: dnAttributes extended match not supported yet");
- return -1;
- }
- if (tree->u.extended.rule_id == NULL) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet");
- return -1;
- }
- if (tree->u.extended.attr == NULL) {
- ldb_debug(module->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(module->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 ltdb_message_match(struct ldb_module *module,
- 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 ltdb_extended_match(module, msg, tree, base, scope);
-
- case LDB_OP_NOT:
- return ! ltdb_message_match(module, msg, tree->u.not.child, base, scope);
-
- case LDB_OP_AND:
- for (i=0;i<tree->u.list.num_elements;i++) {
- v = ltdb_message_match(module, 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 = ltdb_message_match(module, msg, tree->u.list.elements[i],
- base, scope);
- if (v) return 1;
- }
- return 0;
- }
-
- return match_leaf(module, msg, tree, base, scope);
-}
diff --git a/source4/lib/ldb/ldb_tdb/ldb_search.c b/source4/lib/ldb/ldb_tdb/ldb_search.c
index d6e7d66f68..e48043da88 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_search.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_search.c
@@ -92,8 +92,9 @@ static int msg_add_all_elements(struct ldb_module *module, struct ldb_message *r
unsigned int i;
for (i=0;i<msg->num_elements;i++) {
- int flags = ltdb_attribute_flags(module, msg->elements[i].name);
- if ((msg->dn[0] != '@') && (flags & LTDB_FLAG_HIDDEN)) {
+ const struct ldb_attrib_handler *h;
+ h = ldb_attrib_handler(ldb, msg->elements[i].name);
+ if ((msg->dn[0] != '@') && (h->flags & LDB_ATTR_FLAG_HIDDEN)) {
continue;
}
if (msg_add_element(ldb, ret, &msg->elements[i]) != 0) {
@@ -195,7 +196,7 @@ static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module,
int ltdb_has_wildcard(struct ldb_module *module, const char *attr_name,
const struct ldb_val *val)
{
- int flags;
+ const struct ldb_attrib_handler *h;
/* all attribute types recognise the "*" wildcard */
if (val->length == 1 && strncmp((char *)val->data, "*", 1) == 0) {
@@ -206,8 +207,8 @@ int ltdb_has_wildcard(struct ldb_module *module, const char *attr_name,
return 0;
}
- flags = ltdb_attribute_flags(module, attr_name);
- if (flags & LTDB_FLAG_WILDCARD) {
+ h = ldb_attrib_handler(module->ldb, attr_name);
+ if (h->flags & LDB_ATTR_FLAG_WILDCARD) {
return 1;
}
@@ -415,8 +416,8 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
}
/* see if it matches the given expression */
- if (!ltdb_message_match(sinfo->module, msg, sinfo->tree,
- sinfo->base, sinfo->scope)) {
+ if (!ldb_match_message(sinfo->module->ldb, msg, sinfo->tree,
+ sinfo->base, sinfo->scope)) {
talloc_free(msg);
return 0;
}
diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.c b/source4/lib/ldb/ldb_tdb/ldb_tdb.c
index bc61378f18..22797b96d1 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -41,21 +41,10 @@
#include "ldb/include/ldb_dn.h"
#include "ldb/ldb_tdb/ldb_tdb.h"
-#define LDBLOCK "INT_LDBLOCK"
+#define LDBLOCK "@INT_LDBLOCK"
/*
- callback function used in call to ldb_dn_fold() for determining whether an
- attribute type requires case folding.
-*/
-static int ltdb_case_fold_attr_required(void * user_data, char *attr)
-{
- struct ldb_module *module = talloc_get_type(user_data, struct ldb_module);
-
- return ltdb_attribute_flags(module, attr) & LTDB_FLAG_CASE_INSENSITIVE;
-}
-
-/*
form a TDB_DATA for a record key
caller frees
@@ -68,9 +57,6 @@ struct TDB_DATA ltdb_key(struct ldb_module *module, const char *dn)
TDB_DATA key;
char *key_str = NULL;
char *dn_folded = NULL;
- const char *prefix = LTDB_INDEX ":";
- const char *s;
- int flags;
/*
most DNs are case insensitive. The exception is index DNs for
@@ -78,52 +64,22 @@ struct TDB_DATA ltdb_key(struct ldb_module *module, const char *dn)
there are 3 cases dealt with in this code:
- 1) if the dn doesn't start with @INDEX: then uppercase the attribute
+ 1) if the dn doesn't start with @ then uppercase the attribute
names and the attributes values of case insensitive attributes
- 2) if the dn starts with @INDEX:attr and 'attr' is a case insensitive
- attribute then uppercase whole dn
- 3) if the dn starts with @INDEX:attr and 'attr' is a case sensitive
- attribute then uppercase up to the value of the attribute, but
- not the value itself
+ 2) if the dn starts with @ then leave it alone - the indexing code handles
+ the rest
*/
- if (strncmp(dn, prefix, strlen(prefix)) == 0 &&
- (s = strchr(dn+strlen(prefix), ':'))) {
- char *attr_name, *attr_name_folded;
- attr_name = talloc_strndup(ldb, dn+strlen(prefix), (s-(dn+strlen(prefix))));
- if (!attr_name) {
- goto failed;
- }
- flags = ltdb_attribute_flags(module, attr_name);
-
- if (flags & LTDB_FLAG_CASE_INSENSITIVE) {
- dn_folded = ldb_casefold(ldb, dn);
- } else {
- attr_name_folded = ldb_casefold(ldb, attr_name);
- if (!attr_name_folded) {
- goto failed;
- }
- dn_folded = talloc_asprintf(ldb, "%s:%s:%s",
- prefix, attr_name_folded,
- s+1);
- talloc_free(attr_name_folded);
- }
- talloc_free(attr_name);
- }
- /* special cases for tdb */
- else if (*dn == '@' || strncmp(LDBLOCK, dn, strlen(LDBLOCK)) == 0) {
-
+ if (*dn == '@') {
dn_folded = talloc_strdup(ldb, dn);
- }
- else {
+ } else {
struct ldb_dn *edn, *cedn;
edn = ldb_dn_explode(ldb, dn);
if (!edn)
goto failed;
- cedn = ldb_dn_casefold(ldb, edn, module,
- ltdb_case_fold_attr_required);
- if (!edn)
+ cedn = ldb_dn_casefold(ldb, edn);
+ if (!cedn)
goto failed;
dn_folded = ldb_dn_linearize(ldb, cedn);
@@ -563,6 +519,7 @@ static int msg_delete_element(struct ldb_module *module,
unsigned int i;
int found;
struct ldb_message_element *el;
+ const struct ldb_attrib_handler *h;
found = find_element(msg, name);
if (found == -1) {
@@ -571,8 +528,10 @@ static int msg_delete_element(struct ldb_module *module,
el = &msg->elements[found];
+ h = ldb_attrib_handler(ldb, el->name);
+
for (i=0;i<el->num_values;i++) {
- if (ltdb_val_equal(module, msg->elements[i].name, &el->values[i], val)) {
+ if (h->comparison_fn(ldb, &el->values[i], val) == 0) {
if (i<el->num_values-1) {
memmove(&el->values[i], &el->values[i+1],
sizeof(el->values[i])*(el->num_values-(i+1)));
diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.h b/source4/lib/ldb/ldb_tdb/ldb_tdb.h
index 6377092a21..46c5843d60 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_tdb.h
+++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -45,20 +45,11 @@ struct ltdb_private {
#define LTDB_SEQUENCE_NUMBER "sequenceNumber"
#define LTDB_OBJECTCLASS "objectClass"
-/* well known attribute flags */
-#define LTDB_FLAG_CASE_INSENSITIVE (1<<0)
-#define LTDB_FLAG_INTEGER (1<<1)
-#define LTDB_FLAG_WILDCARD (1<<2)
-#define LTDB_FLAG_OBJECTCLASS (1<<3)
-#define LTDB_FLAG_HIDDEN (1<<4)
-#define LTDB_FLAG_NONE 0
-
/* The following definitions come from lib/ldb/ldb_tdb/ldb_cache.c */
int ltdb_cache_reload(struct ldb_module *module);
int ltdb_cache_load(struct ldb_module *module);
int ltdb_increase_sequence_number(struct ldb_module *module);
-int ltdb_attribute_flags(struct ldb_module *module, const char *attr_name);
int ltdb_check_at_attributes_values(const struct ldb_val *value);
/* The following definitions come from lib/ldb/ldb_tdb/ldb_index.c */
@@ -111,16 +102,6 @@ int ltdb_modify_internal(struct ldb_module *module, const struct ldb_message *ms
int ltdb_lock_read(struct ldb_module *module);
int ltdb_unlock_read(struct ldb_module *module);
-/* The following definitions come from lib/ldb/ldb_tdb/ldb_match.c */
-int ltdb_val_equal(struct ldb_module *module,
- const char *attr_name,
- const struct ldb_val *v1, const struct ldb_val *v2);
-int ltdb_message_match(struct ldb_module *module,
- struct ldb_message *msg,
- struct ldb_parse_tree *tree,
- const char *base,
- enum ldb_scope scope);
-
int ltdb_index_del_value(struct ldb_module *module, const char *dn,
struct ldb_message_element *el, int v_idx);
diff --git a/source4/lib/ldb/samba/ldif_handlers.c b/source4/lib/ldb/samba/ldif_handlers.c
index 17a45df78d..13499b8428 100644
--- a/source4/lib/ldb/samba/ldif_handlers.c
+++ b/source4/lib/ldb/samba/ldif_handlers.c
@@ -75,9 +75,29 @@ static int ldif_write_objectSid(struct ldb_context *ldb, const struct ldb_val *i
return 0;
}
+/*
+ compare two objectSids
+*/
+static int ldb_comparison_objectSid(struct ldb_context *ldb,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ if (strncmp(v1->data, "S-", 2) == 0 &&
+ strncmp(v2->data, "S-", 2) == 0) {
+ return strcmp(v1->data, v2->data);
+ }
+ return ldb_comparison_binary(ldb, v1, v2);
+}
+
-static const struct ldb_ldif_handler samba_handlers[] = {
- { "objectSid", ldif_read_objectSid, ldif_write_objectSid }
+static const struct ldb_attrib_handler samba_handlers[] = {
+ {
+ .attr = "objectSid",
+ .flags = 0,
+ .ldif_read_fn = ldif_read_objectSid,
+ .ldif_write_fn = ldif_write_objectSid,
+ .canonicalise_fn = ldb_handler_copy,
+ .comparison_fn = ldb_comparison_objectSid
+ }
};
/*
@@ -85,5 +105,5 @@ static const struct ldb_ldif_handler samba_handlers[] = {
*/
int ldb_register_samba_handlers(struct ldb_context *ldb)
{
- return ldb_ldif_add_handlers(ldb, samba_handlers, ARRAY_SIZE(samba_handlers));
+ return ldb_set_attrib_handlers(ldb, samba_handlers, ARRAY_SIZE(samba_handlers));
}