diff options
Diffstat (limited to 'source4/lib/ldb')
-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)); } |