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