From f5ebc8e404f4397c0ef2c8b838984df1767c955c Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Sat, 4 Feb 2006 00:38:48 +0000 Subject: r13324: From now on check attribute names obey rfc2251 Also add a way to provide utf8 compliant functions by registering them with ldb_set_utf8_fns() Next comes code to register samba internal utf8 functions. Simo. (This used to be commit ac9b8a41ffca8e06c5e849d544d3203a665b8e0d) --- source4/lib/ldb/Makefile.in | 2 +- source4/lib/ldb/common/ldb.c | 2 + source4/lib/ldb/common/ldb_dn.c | 26 ++-------- source4/lib/ldb/common/ldb_ldif.c | 36 +------------- source4/lib/ldb/common/ldb_msg.c | 5 ++ source4/lib/ldb/common/ldb_utf8.c | 81 ++++++++++++++++++++++++++++--- source4/lib/ldb/include/ldb.h | 36 ++++++++++++-- source4/lib/ldb/include/ldb_private.h | 7 +++ source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 38 ++++----------- source4/lib/ldb/ldb_tdb/ldb_index.c | 2 +- source4/lib/ldb/tools/ldbtest.c | 2 +- 11 files changed, 139 insertions(+), 98 deletions(-) diff --git a/source4/lib/ldb/Makefile.in b/source4/lib/ldb/Makefile.in index 320b9c281f..43d1674d08 100644 --- a/source4/lib/ldb/Makefile.in +++ b/source4/lib/ldb/Makefile.in @@ -188,7 +188,7 @@ endif test: $(BINS) test-tdb test-ldap test-sqlite3 test-schema install: all - cp include/ldb.h $(includedir) + cp include/ldb.h include/ldb_errors.h $(includedir) cp $(LDB_LIB) $(libdir) cp $(BINS) $(bindir) cp ldb.pc $(libdir)/pkgconfig diff --git a/source4/lib/ldb/common/ldb.c b/source4/lib/ldb/common/ldb.c index 41b1a3efb7..0857c07ad4 100644 --- a/source4/lib/ldb/common/ldb.c +++ b/source4/lib/ldb/common/ldb.c @@ -50,6 +50,8 @@ struct ldb_context *ldb_init(void *mem_ctx) return NULL; } + ldb_set_utf8_default(ldb); + return ldb; } diff --git a/source4/lib/ldb/common/ldb_dn.c b/source4/lib/ldb/common/ldb_dn.c index e0c6f4a103..c2212fd6fe 100644 --- a/source4/lib/ldb/common/ldb_dn.c +++ b/source4/lib/ldb/common/ldb_dn.c @@ -55,23 +55,6 @@ int ldb_dn_check_special(const struct ldb_dn *dn, const char *check) return ! strcmp((char *)dn->components[0].value.data, check); } -static int ldb_dn_is_valid_attribute_name(const char *name) -{ - if (name == NULL) return 0; - - while (*name) { - if (! isascii(*name)) { - return 0; - } - if (! (isalnum((unsigned char)*name) || *name == '-')) { - return 0; - } - name++; - } - - return 1; -} - char *ldb_dn_escape_value(void *mem_ctx, struct ldb_val value) { const char *p, *s, *src; @@ -301,7 +284,7 @@ static struct ldb_dn_component ldb_dn_explode_component(void *mem_ctx, char *raw if (!dc.name) return dc; - if (! ldb_dn_is_valid_attribute_name(dc.name)) { + if (! ldb_valid_attr_name(dc.name)) { goto failed; } @@ -519,7 +502,8 @@ int ldb_dn_compare_base(struct ldb_context *ldb, const struct ldb_attrib_handler *h; /* compare names (attribute names are guaranteed to be ASCII only) */ - ret = ldb_caseless_cmp(base->components[n0].name, + ret = ldb_caseless_cmp(ldb, + base->components[n0].name, dn->components[n1].name); if (ret) { return ret; @@ -598,7 +582,7 @@ struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, const struct ldb_dn *edn struct ldb_dn_component dc; const struct ldb_attrib_handler *h; - dc.name = ldb_casefold(cedn, edn->components[i].name); + dc.name = ldb_casefold(ldb, cedn, edn->components[i].name); LDB_DN_NULL_FAILED(dc.name); h = ldb_attrib_handler(ldb, dc.name); @@ -761,7 +745,7 @@ struct ldb_dn *ldb_dn_build_child(void *mem_ctx, const char *attr, const struct ldb_dn *base) { struct ldb_dn *new; - if (! ldb_dn_is_valid_attribute_name(attr)) return NULL; + if (! ldb_valid_attr_name(attr)) return NULL; if (value == NULL || value == '\0') return NULL; if (base != NULL) { diff --git a/source4/lib/ldb/common/ldb_ldif.c b/source4/lib/ldb/common/ldb_ldif.c index 53dadcc6fe..7501e89222 100644 --- a/source4/lib/ldb/common/ldb_ldif.c +++ b/source4/lib/ldb/common/ldb_ldif.c @@ -498,40 +498,6 @@ void ldb_ldif_read_free(struct ldb_context *ldb, struct ldb_ldif *ldif) talloc_free(ldif); } -/* - add an empty element -*/ -static int msg_add_empty(struct ldb_context *ldb, - struct ldb_message *msg, const char *name, unsigned flags) -{ - struct ldb_message_element *el2, *el; - - el2 = talloc_realloc(msg, msg->elements, - struct ldb_message_element, msg->num_elements+1); - if (!el2) { - errno = ENOMEM; - return -1; - } - - msg->elements = el2; - - el = &msg->elements[msg->num_elements]; - - el->name = talloc_strdup(msg->elements, name); - el->num_values = 0; - el->values = NULL; - el->flags = flags; - - if (!el->name) { - errno = ENOMEM; - return -1; - } - - msg->num_elements++; - - return 0; -} - /* read from a LDIF source, creating a ldb_message */ @@ -630,7 +596,7 @@ struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb, } if (empty) { - if (msg_add_empty(ldb, msg, (char *)value.data, flags) != 0) { + if (ldb_msg_add_empty(msg, (char *)value.data, flags) != 0) { goto failed; } continue; diff --git a/source4/lib/ldb/common/ldb_msg.c b/source4/lib/ldb/common/ldb_msg.c index 513a4de1f8..497d2cb0d5 100644 --- a/source4/lib/ldb/common/ldb_msg.c +++ b/source4/lib/ldb/common/ldb_msg.c @@ -123,6 +123,10 @@ int ldb_msg_add_empty(struct ldb_message *msg, const char *attr_name, int flags) { struct ldb_message_element *els; + if (! ldb_valid_attr_name(attr_name)) { + return -1; + } + els = talloc_realloc(msg, msg->elements, struct ldb_message_element, msg->num_elements+1); if (!els) { @@ -135,6 +139,7 @@ int ldb_msg_add_empty(struct ldb_message *msg, const char *attr_name, int flags) els[msg->num_elements].flags = flags; els[msg->num_elements].name = talloc_strdup(els, attr_name); if (!els[msg->num_elements].name) { + errno = ENOMEM; return -1; } diff --git a/source4/lib/ldb/common/ldb_utf8.c b/source4/lib/ldb/common/ldb_utf8.c index c2d31d440b..4735b35af6 100644 --- a/source4/lib/ldb/common/ldb_utf8.c +++ b/source4/lib/ldb/common/ldb_utf8.c @@ -35,11 +35,29 @@ #include "includes.h" #include "ldb/include/includes.h" + /* - TODO: - a simple case folding function - will be replaced by a UTF8 aware function later + this allow the user to pass in a caseless comparison + function to handle utf8 caseless comparisons + */ +void ldb_set_utf8_fns(struct ldb_context *ldb, + void *context, + int (*cmp)(void *, const char *, const char *), + char *(*casefold)(void *, void *, const char *)) +{ + if (context) + ldb->utf8_fns.context = context; + if (cmp) + ldb->utf8_fns.caseless_cmp = cmp; + if (casefold) + ldb->utf8_fns.casefold = casefold; +} + +/* + a simple case folding function + NOTE: does not handle UTF8 */ -char *ldb_casefold(void *mem_ctx, const char *s) +char *ldb_casefold_default(void *context, void *mem_ctx, const char *s) { int i; char *ret = talloc_strdup(mem_ctx, s); @@ -55,20 +73,69 @@ char *ldb_casefold(void *mem_ctx, const char *s) /* a caseless compare, optimised for 7 bit - TODO: doesn't yet handle UTF8 + NOTE: doesn't handle UTF8 */ -int ldb_caseless_cmp(const char *s1, const char *s2) + +int ldb_caseless_cmp_default(void *context, const char *s1, const char *s2) +{ + return strcasecmp(s1,s2); +} + +void ldb_set_utf8_default(struct ldb_context *ldb) +{ + ldb_set_utf8_fns(ldb, NULL, ldb_caseless_cmp_default, ldb_casefold_default); +} + +char *ldb_casefold(struct ldb_context *ldb, void *mem_ctx, const char *s) +{ + return ldb->utf8_fns.casefold(ldb->utf8_fns.context, mem_ctx, s); +} + +int ldb_caseless_cmp(struct ldb_context *ldb, const char *s1, const char *s2) +{ + return ldb->utf8_fns.caseless_cmp(ldb->utf8_fns.context, s1, s2); +} + +/* + check the attribute name is valid according to rfc2251 + returns 1 if the name is ok + */ + +int ldb_valid_attr_name(const char *s) { - return strcasecmp(s1, s2); + int i; + + if (!s || !s[0]) + return 0; + + /* handle special ldb_tdb wildcard */ + if (strcmp(s, "*") == 0) return 1; + + for (i = 0; s[i]; i++) { + if (! isascii(s[i])) { + return 0; + } + if (i == 0) { /* first char must be an alpha (or our special '@' identifier) */ + if (! (isalpha(s[i]) || (s[i] == '@'))) { + return 0; + } + } else { + if (! (isalnum(s[i]) || (s[i] == '-'))) { + return 0; + } + } + } + return 1; } /* compare two attribute names + attribute names are restricted by rfc2251 so using strcasecmp here is ok. return 0 for match */ int ldb_attr_cmp(const char *attr1, const char *attr2) { - return ldb_caseless_cmp(attr1, attr2); + return strcasecmp(attr1, attr2); } /* diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h index 9139e6d2f5..a8c2d176b5 100644 --- a/source4/lib/ldb/include/ldb.h +++ b/source4/lib/ldb/include/ldb.h @@ -208,6 +208,16 @@ struct ldb_debug_ops { void *context; }; +/** + The user can optionally supply a custom utf8 functions, + to handle comparisons and casefolding. +*/ +struct ldb_utf8_fns { + void *context; + int (*caseless_cmp)(void *context, const char *s1, const char *s2); + char *(*casefold)(void *context, void *mem_ctx, const char *s); +}; + /** Flag value for database connection mode. @@ -718,30 +728,48 @@ int ldb_transaction_cancel(struct ldb_context *ldb); */ const char *ldb_errstring(struct ldb_context *ldb); +/** + setup the default utf8 functions + FIXME: these functions do not yet handle utf8 +*/ +void ldb_set_utf8_default(struct ldb_context *ldb); + /** Casefold a string + \param ldb the ldb context \param mem_ctx the memory context to allocate the result string memory from. \param s the string that is to be folded \return a copy of the string, converted to upper case - \todo This function should be UTF8 aware, but currently is not. + \note The default function is not yet UTF8 aware. Provide your own + set of functions through ldb_set_utf8_fns() */ -char *ldb_casefold(void *mem_ctx, const char *s); +char *ldb_casefold(struct ldb_context *ldb, void *mem_ctx, const char *s); /** Compare two strings, without regard to case. + \param ldb the ldb context \param s1 the first string to compare \param s2 the second string to compare \return 0 if the strings are the same, non-zero if there are any differences except for case. - \note This function is not UTF8 aware. + \note The default function is not yet UTF8 aware. Provide your own + set of functions through ldb_set_utf8_fns() +*/ +int ldb_caseless_cmp(struct ldb_context *ldb, const char *s1, const char *s2); + +/** + Check the attribute name is valid according to rfc2251 + \param s tthe string to check + + \return 1 if the name is ok */ -int ldb_caseless_cmp(const char *s1, const char *s2); +int ldb_valid_attr_name(const char *s); /* ldif manipulation functions diff --git a/source4/lib/ldb/include/ldb_private.h b/source4/lib/ldb/include/ldb_private.h index 6871d8d552..fffda77ff8 100644 --- a/source4/lib/ldb/include/ldb_private.h +++ b/source4/lib/ldb/include/ldb_private.h @@ -90,6 +90,9 @@ struct ldb_context { /* debugging operations */ struct ldb_debug_ops debug_ops; + /* custom utf8 functions */ + struct ldb_utf8_fns utf8_fns; + /* backend specific opaque parameters */ struct ldb_opaque { struct ldb_opaque *next; @@ -191,4 +194,8 @@ int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx, struct ldb_control *get_control_from_list(struct ldb_control **controls, const char *oid); int save_controls(struct ldb_control *exclude, struct ldb_request *req, struct ldb_control ***saver); int check_critical_controls(struct ldb_control **controls); + +/* The following definitions come from lib/ldb/common/ldb_utf8.c */ +char *ldb_casefold_default(void *context, void *mem_ctx, const char *s); +int ldb_caseless_cmp_default(void *context, const char *s1, const char *s2); #endif diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 4c00998fa9..fbbbf037b3 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -289,7 +289,7 @@ static char *parsetree_to_sql(struct ldb_module *module, * For simple searches, we want to retrieve the list of EIDs that * match the criteria. */ - attr = ldb_casefold(mem_ctx, t->u.equality.attr); + attr = ldb_casefold(module->ldb, mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); @@ -353,7 +353,7 @@ static char *parsetree_to_sql(struct ldb_module *module, wild_card_string[strlen(wild_card_string) - 1] = '\0'; } - attr = ldb_casefold(mem_ctx, t->u.substring.attr); + attr = ldb_casefold(module->ldb, mem_ctx, t->u.substring.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); @@ -374,7 +374,7 @@ static char *parsetree_to_sql(struct ldb_module *module, value.data); case LDB_OP_GREATER: - attr = ldb_casefold(mem_ctx, t->u.equality.attr); + attr = ldb_casefold(module->ldb, mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); @@ -393,7 +393,7 @@ static char *parsetree_to_sql(struct ldb_module *module, attr); case LDB_OP_LESS: - attr = ldb_casefold(mem_ctx, t->u.equality.attr); + attr = ldb_casefold(module->ldb, mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); @@ -416,7 +416,7 @@ static char *parsetree_to_sql(struct ldb_module *module, return talloc_strdup(mem_ctx, "SELECT eid FROM ldb_entry"); } - attr = ldb_casefold(mem_ctx, t->u.present.attr); + attr = ldb_casefold(module->ldb, mem_ctx, t->u.present.attr); if (attr == NULL) return NULL; return lsqlite3_tprintf(mem_ctx, @@ -425,7 +425,7 @@ static char *parsetree_to_sql(struct ldb_module *module, attr); case LDB_OP_APPROX: - attr = ldb_casefold(mem_ctx, t->u.equality.attr); + attr = ldb_casefold(module->ldb, mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); @@ -715,26 +715,8 @@ static int lsqlite3_search_callback(void *result, int col_num, char **cols, char if (!found) return 0; } - msg->elements = talloc_realloc(msg, - msg->elements, - struct ldb_message_element, - msg->num_elements + 1); - if (msg->elements == NULL) return SQLITE_ABORT; - - msg->elements[msg->num_elements].flags = 0; - msg->elements[msg->num_elements].name = talloc_strdup(msg->elements, cols[2]); - if (msg->elements[msg->num_elements].name == NULL) return SQLITE_ABORT; - - msg->elements[msg->num_elements].num_values = 1; - msg->elements[msg->num_elements].values = talloc_array(msg->elements, - struct ldb_val, 1); - if (msg->elements[msg->num_elements].values == NULL) return SQLITE_ABORT; - - msg->elements[msg->num_elements].values[0].length = strlen(cols[3]); - msg->elements[msg->num_elements].values[0].data = talloc_strdup(msg->elements, cols[3]); - if (msg->elements[msg->num_elements].values[0].data == NULL) return SQLITE_ABORT; - - msg->num_elements++; + if (ldb_msg_add_string(msg, cols[2], cols[3]) != 0) + return SQLITE_ABORT; return SQLITE_OK; } @@ -1076,7 +1058,7 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg int j; /* Get a case-folded copy of the attribute name */ - attr = ldb_casefold(local_ctx, el->name); + attr = ldb_casefold(module->ldb, local_ctx, el->name); if (attr == NULL) { ret = LDB_ERR_OTHER; goto failed; @@ -1175,7 +1157,7 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * int j; /* Get a case-folded copy of the attribute name */ - attr = ldb_casefold(local_ctx, el->name); + attr = ldb_casefold(module->ldb, local_ctx, el->name); if (attr == NULL) { ret = LDB_ERR_OTHER; goto failed; diff --git a/source4/lib/ldb/ldb_tdb/ldb_index.c b/source4/lib/ldb/ldb_tdb/ldb_index.c index c74ce62fbf..fb29a9ddbf 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_index.c +++ b/source4/lib/ldb/ldb_tdb/ldb_index.c @@ -106,7 +106,7 @@ static struct ldb_dn *ldb_dn_key(struct ldb_context *ldb, const struct ldb_attrib_handler *h; char *attr_folded; - attr_folded = ldb_casefold(ldb, attr); + attr_folded = ldb_casefold(ldb, ldb, attr); if (!attr_folded) { return NULL; } diff --git a/source4/lib/ldb/tools/ldbtest.c b/source4/lib/ldb/tools/ldbtest.c index f2efd4d22a..69362d0f20 100644 --- a/source4/lib/ldb/tools/ldbtest.c +++ b/source4/lib/ldb/tools/ldbtest.c @@ -94,7 +94,7 @@ static void add_records(struct ldb_context *ldb, el[2].name = talloc_strdup(tmp_ctx, "uid"); el[2].num_values = 1; el[2].values = vals[2]; - vals[2][0].data = (uint8_t *)ldb_casefold(tmp_ctx, name); + vals[2][0].data = (uint8_t *)ldb_casefold(ldb, tmp_ctx, name); vals[2][0].length = strlen((char *)vals[2][0].data); el[3].flags = 0; -- cgit