diff options
author | Andrew Tridgell <tridge@samba.org> | 2005-07-01 06:21:26 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:19:01 -0500 |
commit | a06d66a3a669c3a0a0f816438e2b3e91e208f398 (patch) | |
tree | 0a80e63dad3f00cd584263e56df6f751b46de58e | |
parent | 8ab3f59a10d00357cb129a2051fd0f694b5c8081 (diff) | |
download | samba-a06d66a3a669c3a0a0f816438e2b3e91e208f398.tar.gz samba-a06d66a3a669c3a0a0f816438e2b3e91e208f398.tar.bz2 samba-a06d66a3a669c3a0a0f816438e2b3e91e208f398.zip |
r8037: a fairly major update to the internals of ldb. Changes are:
- moved the knowledge of attribute types out of ldb_tdb and into the
generic ldb code. This allows the ldb_match() message match logic
to be generic, so it can be used by other backend
- added the generic ability to load attribute handlers, for
canonicalisation, compare, ldif read and ldif write. In the future
this will be used by the schema module to allow us to correctly
obey the attributetype schema elements
- added attribute handlers for some of the core ldap attribute types,
Integer, DirectoryString, DN, ObjectClass etc
- added automatic registration of attribute handlers for well-known
attribute names 'cn', 'dc', 'dn', 'ou' and 'objectClass'
- converted the objectSid special handlers for Samba to the new system
- added more correct handling of indexing in tdb backend based on the
attribute canonicalisation function
- added generic support for subclasses, moving it out of the tdb
backend. This will be used in future by the schema module
- fixed several bugs in the dn_explode code. It still needs more
work, but doesn't corrupt ldb dbs any more.
(This used to be commit 944c5844ab441b96d8e5d7b2d151982139d1fab9)
-rw-r--r-- | source4/lib/ldb/Makefile.in | 5 | ||||
-rw-r--r-- | source4/lib/ldb/common/attrib_handlers.c | 335 | ||||
-rw-r--r-- | source4/lib/ldb/common/ldb.c | 8 | ||||
-rw-r--r-- | source4/lib/ldb/common/ldb_attributes.c | 281 | ||||
-rw-r--r-- | source4/lib/ldb/common/ldb_dn.c | 132 | ||||
-rw-r--r-- | source4/lib/ldb/common/ldb_ldif.c | 78 | ||||
-rw-r--r-- | source4/lib/ldb/common/ldb_match.c | 260 | ||||
-rw-r--r-- | source4/lib/ldb/common/ldb_utf8.c | 4 | ||||
-rw-r--r-- | source4/lib/ldb/config.mk | 4 | ||||
-rw-r--r-- | source4/lib/ldb/include/ldb.h | 40 | ||||
-rw-r--r-- | source4/lib/ldb/include/ldb_dn.h | 3 | ||||
-rw-r--r-- | source4/lib/ldb/include/ldb_private.h | 51 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_cache.c | 188 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_index.c | 112 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_match.c | 426 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_search.c | 15 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_tdb.c | 65 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_tdb.h | 19 | ||||
-rw-r--r-- | source4/lib/ldb/samba/ldif_handlers.c | 26 |
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(<db->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 = <db->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 = <db->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)); } |