summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2018-03-15 06:19:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2018-03-15 06:19:49 +0000
commit1b7e3c6496229f6d5dd420097933dbaf37e436e6 (patch)
tree239dca9451e3b4c96b1d4f97625fa90271a19542
parentReleasing progress-linux version 2:1.2.3-1~dschinn1. (diff)
downloadldb-1b7e3c6496229f6d5dd420097933dbaf37e436e6.zip
ldb-1b7e3c6496229f6d5dd420097933dbaf37e436e6.tar.xz
Merging upstream version 2:1.3.2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--ABI/ldb-1.3.0.sigs279
-rw-r--r--ABI/ldb-1.3.1.sigs279
-rw-r--r--ABI/ldb-1.3.2.sigs279
-rw-r--r--ABI/pyldb-util-1.3.0.sigs2
-rw-r--r--ABI/pyldb-util-1.3.1.sigs2
-rw-r--r--ABI/pyldb-util-1.3.2.sigs2
-rw-r--r--ABI/pyldb-util.py3-1.3.0.sigs2
-rw-r--r--ABI/pyldb-util.py3-1.3.1.sigs2
-rw-r--r--ABI/pyldb-util.py3-1.3.2.sigs2
-rw-r--r--buildtools/wafsamba/nothreads.py4
-rw-r--r--buildtools/wafsamba/samba_autoconf.py23
-rw-r--r--buildtools/wafsamba/samba_conftests.py2
-rw-r--r--buildtools/wafsamba/samba_dist.py6
-rw-r--r--buildtools/wafsamba/samba_patterns.py1
-rw-r--r--buildtools/wafsamba/samba_python.py2
-rw-r--r--buildtools/wafsamba/samba_third_party.py25
-rw-r--r--buildtools/wafsamba/wafsamba.py23
-rw-r--r--buildtools/wafsamba/wscript4
-rw-r--r--common/ldb_attributes.c14
-rw-r--r--common/ldb_match.c22
-rw-r--r--common/ldb_modules.c2
-rw-r--r--include/ldb_module.h25
-rw-r--r--include/ldb_private.h22
-rw-r--r--ldb_tdb/ldb_cache.c54
-rw-r--r--ldb_tdb/ldb_index.c1272
-rw-r--r--ldb_tdb/ldb_search.c287
-rw-r--r--ldb_tdb/ldb_tdb.c334
-rw-r--r--ldb_tdb/ldb_tdb.h50
-rw-r--r--lib/replace/replace.c5
-rw-r--r--lib/replace/replace.h4
-rw-r--r--lib/replace/system/nis.h83
-rw-r--r--lib/replace/system/readline.h3
-rw-r--r--lib/replace/system/wscript_configure8
-rw-r--r--lib/replace/wscript54
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.10.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.11.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util.py3-2.1.10.sigs15
-rw-r--r--lib/talloc/ABI/pytalloc-util.py3-2.1.11.sigs15
-rw-r--r--lib/talloc/ABI/talloc-2.1.10.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.1.11.sigs65
-rw-r--r--lib/talloc/talloc.c128
-rw-r--r--lib/talloc/talloc.h2
-rw-r--r--lib/talloc/testsuite.c68
-rw-r--r--lib/talloc/wscript29
-rw-r--r--lib/tdb/ABI/tdb-1.3.15.sigs71
-rw-r--r--lib/tdb/common/dump.c6
-rw-r--r--lib/tdb/common/io.c103
-rw-r--r--lib/tdb/common/lock.c28
-rw-r--r--lib/tdb/common/open.c70
-rw-r--r--lib/tdb/common/tdb.c9
-rw-r--r--lib/tdb/common/tdb_private.h18
-rw-r--r--lib/tdb/common/transaction.c34
-rw-r--r--lib/tdb/common/traverse.c40
-rw-r--r--lib/tdb/wscript2
-rw-r--r--lib/tevent/ABI/tevent-0.9.35.sigs99
-rw-r--r--lib/tevent/ABI/tevent-0.9.36.sigs100
-rw-r--r--lib/tevent/echo_server.c1
-rw-r--r--lib/tevent/testsuite.c2
-rw-r--r--lib/tevent/tevent.h29
-rw-r--r--lib/tevent/tevent_internal.h1
-rw-r--r--lib/tevent/tevent_queue.c13
-rw-r--r--lib/tevent/tevent_threads.c4
-rw-r--r--lib/tevent/wscript2
-rw-r--r--lib/util/binsearch.h121
-rw-r--r--pyldb.c32
-rw-r--r--tests/ldb_mod_op_test.c776
-rwxr-xr-xtests/python/api.py564
-rwxr-xr-xtests/test-generic.sh17
-rw-r--r--wscript3
69 files changed, 5171 insertions, 571 deletions
diff --git a/ABI/ldb-1.3.0.sigs b/ABI/ldb-1.3.0.sigs
new file mode 100644
index 0000000..a31b84e
--- /dev/null
+++ b/ABI/ldb-1.3.0.sigs
@@ -0,0 +1,279 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/ABI/ldb-1.3.1.sigs b/ABI/ldb-1.3.1.sigs
new file mode 100644
index 0000000..a31b84e
--- /dev/null
+++ b/ABI/ldb-1.3.1.sigs
@@ -0,0 +1,279 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/ABI/ldb-1.3.2.sigs b/ABI/ldb-1.3.2.sigs
new file mode 100644
index 0000000..a31b84e
--- /dev/null
+++ b/ABI/ldb-1.3.2.sigs
@@ -0,0 +1,279 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/ABI/pyldb-util-1.3.0.sigs b/ABI/pyldb-util-1.3.0.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util-1.3.0.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/ABI/pyldb-util-1.3.1.sigs b/ABI/pyldb-util-1.3.1.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util-1.3.1.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/ABI/pyldb-util-1.3.2.sigs b/ABI/pyldb-util-1.3.2.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util-1.3.2.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/ABI/pyldb-util.py3-1.3.0.sigs b/ABI/pyldb-util.py3-1.3.0.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util.py3-1.3.0.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/ABI/pyldb-util.py3-1.3.1.sigs b/ABI/pyldb-util.py3-1.3.1.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util.py3-1.3.1.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/ABI/pyldb-util.py3-1.3.2.sigs b/ABI/pyldb-util.py3-1.3.2.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util.py3-1.3.2.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/buildtools/wafsamba/nothreads.py b/buildtools/wafsamba/nothreads.py
index d194eb8..9bd33e8 100644
--- a/buildtools/wafsamba/nothreads.py
+++ b/buildtools/wafsamba/nothreads.py
@@ -43,7 +43,7 @@ def process(tsk):
if tsk.__class__.stat: ret = tsk.__class__.stat(tsk)
# actual call to task's run() function
else: ret = tsk.call_run()
- except Exception, e:
+ except Exception as e:
tsk.err_msg = Utils.ex_stack()
tsk.hasrun = EXCEPTION
@@ -177,7 +177,7 @@ class Parallel(object):
try:
st = tsk.runnable_status()
- except Exception, e:
+ except Exception as e:
self.processed += 1
if self.stop and not Options.options.keep:
tsk.hasrun = SKIPPED
diff --git a/buildtools/wafsamba/samba_autoconf.py b/buildtools/wafsamba/samba_autoconf.py
index 795d130..cc08e0d 100644
--- a/buildtools/wafsamba/samba_autoconf.py
+++ b/buildtools/wafsamba/samba_autoconf.py
@@ -454,7 +454,8 @@ def CHECK_CODE(conf, code, define,
@conf
def CHECK_STRUCTURE_MEMBER(conf, structname, member,
- always=False, define=None, headers=None):
+ always=False, define=None, headers=None,
+ lib=None):
'''check for a structure member'''
if define is None:
define = 'HAVE_%s' % member.upper()
@@ -463,6 +464,7 @@ def CHECK_STRUCTURE_MEMBER(conf, structname, member,
define,
execute=False,
link=False,
+ lib=lib,
always=always,
headers=headers,
local_include=False,
@@ -473,10 +475,13 @@ def CHECK_STRUCTURE_MEMBER(conf, structname, member,
def CHECK_CFLAGS(conf, cflags, fragment='int main(void) { return 0; }\n'):
'''check if the given cflags are accepted by the compiler
'''
+ check_cflags = TO_LIST(cflags)
+ if 'WERROR_CFLAGS' in conf.env:
+ check_cflags.extend(conf.env['WERROR_CFLAGS'])
return conf.check(fragment=fragment,
execute=0,
type='nolink',
- ccflags=cflags,
+ ccflags=check_cflags,
msg="Checking compiler accepts %s" % cflags)
@conf
@@ -708,7 +713,9 @@ def SAMBA_CONFIG_H(conf, path=None):
testflags=True)
conf.ADD_CFLAGS('-Wformat=2 -Wno-format-y2k', testflags=True)
- conf.ADD_CFLAGS('-Werror=format-security -Wformat-security', testflags=True)
+ conf.ADD_CFLAGS('-Wno-format-zero-length', testflags=True)
+ conf.ADD_CFLAGS('-Werror=format-security -Wformat-security',
+ testflags=True, prereq_flags='-Wformat')
# This check is because for ldb_search(), a NULL format string
# is not an error, but some compilers complain about that.
if CHECK_CFLAGS(conf, ["-Werror=format", "-Wformat=2"], '''
@@ -769,14 +776,15 @@ def CONFIG_PATH(conf, name, default):
conf.env[name] = conf.env['PREFIX'] + default
@conf
-def ADD_NAMED_CFLAGS(conf, name, flags, testflags=False):
+def ADD_NAMED_CFLAGS(conf, name, flags, testflags=False, prereq_flags=[]):
'''add some CFLAGS to the command line
optionally set testflags to ensure all the flags work
'''
+ prereq_flags = TO_LIST(prereq_flags)
if testflags:
ok_flags=[]
for f in flags.split():
- if CHECK_CFLAGS(conf, f):
+ if CHECK_CFLAGS(conf, [f] + prereq_flags):
ok_flags.append(f)
flags = ok_flags
if not name in conf.env:
@@ -784,11 +792,12 @@ def ADD_NAMED_CFLAGS(conf, name, flags, testflags=False):
conf.env[name].extend(TO_LIST(flags))
@conf
-def ADD_CFLAGS(conf, flags, testflags=False):
+def ADD_CFLAGS(conf, flags, testflags=False, prereq_flags=[]):
'''add some CFLAGS to the command line
optionally set testflags to ensure all the flags work
'''
- ADD_NAMED_CFLAGS(conf, 'EXTRA_CFLAGS', flags, testflags=testflags)
+ ADD_NAMED_CFLAGS(conf, 'EXTRA_CFLAGS', flags, testflags=testflags,
+ prereq_flags=prereq_flags)
@conf
def ADD_LDFLAGS(conf, flags, testflags=False):
diff --git a/buildtools/wafsamba/samba_conftests.py b/buildtools/wafsamba/samba_conftests.py
index 511176d..b52727b 100644
--- a/buildtools/wafsamba/samba_conftests.py
+++ b/buildtools/wafsamba/samba_conftests.py
@@ -50,7 +50,7 @@ def check(self, *k, **kw):
ret = None
try:
ret = self.run_c_code(*k, **kw)
- except Configure.ConfigurationError, e:
+ except Configure.ConfigurationError as e:
self.check_message_2(kw['errmsg'], 'YELLOW')
if 'mandatory' in kw and kw['mandatory']:
if Logs.verbose > 1:
diff --git a/buildtools/wafsamba/samba_dist.py b/buildtools/wafsamba/samba_dist.py
index dbcb02a..8d51632 100644
--- a/buildtools/wafsamba/samba_dist.py
+++ b/buildtools/wafsamba/samba_dist.py
@@ -115,7 +115,7 @@ def dist(appname='', version=''):
blacklisted = True
if blacklisted:
continue
- if os.path.isdir(abspath):
+ if os.path.isdir(abspath) and not os.path.islink(abspath):
continue
if dstsubdir != '.':
f = dstsubdir + '/' + f
@@ -167,7 +167,7 @@ def dist(appname='', version=''):
absdir = os.path.join(srcdir, dir)
try:
files = vcs_dir_contents(absdir)
- except Exception, e:
+ except Exception as e:
Logs.error('unable to get contents of %s: %s' % (absdir, e))
sys.exit(1)
add_files_to_tarball(tar, srcdir, dir, dist_base, destdir, blacklist, files)
@@ -182,7 +182,7 @@ def dist(appname='', version=''):
absfile = os.path.join(srcdir, file)
- if os.path.isdir(absfile):
+ if os.path.isdir(absfile) and not os.path.islink(absfile):
destdir = destfile
dir = file
files = list_directory_files(dir)
diff --git a/buildtools/wafsamba/samba_patterns.py b/buildtools/wafsamba/samba_patterns.py
index e809f26..2b93937 100644
--- a/buildtools/wafsamba/samba_patterns.py
+++ b/buildtools/wafsamba/samba_patterns.py
@@ -108,6 +108,7 @@ def write_build_options_header(fp):
fp.write(" output(screen,\" PIDDIR: %s\\n\", get_dyn_PIDDIR());\n")
fp.write(" output(screen,\" SMB_PASSWD_FILE: %s\\n\",get_dyn_SMB_PASSWD_FILE());\n")
fp.write(" output(screen,\" PRIVATE_DIR: %s\\n\",get_dyn_PRIVATE_DIR());\n")
+ fp.write(" output(screen,\" BINDDNS_DIR: %s\\n\",get_dyn_BINDDNS_DIR());\n")
fp.write("\n")
def write_build_options_footer(fp):
diff --git a/buildtools/wafsamba/samba_python.py b/buildtools/wafsamba/samba_python.py
index f97439c..cb99fe9 100644
--- a/buildtools/wafsamba/samba_python.py
+++ b/buildtools/wafsamba/samba_python.py
@@ -109,6 +109,7 @@ def SAMBA_PYTHON(bld, name,
public_deps='',
realname=None,
cflags='',
+ cflags_end=None,
includes='',
init_function_sentinel=None,
local_include=True,
@@ -154,6 +155,7 @@ def SAMBA_PYTHON(bld, name,
public_deps=public_deps,
includes=includes,
cflags=cflags,
+ cflags_end=cflags_end,
local_include=local_include,
vars=vars,
realname=realname,
diff --git a/buildtools/wafsamba/samba_third_party.py b/buildtools/wafsamba/samba_third_party.py
index ac77be7..1144f81 100644
--- a/buildtools/wafsamba/samba_third_party.py
+++ b/buildtools/wafsamba/samba_third_party.py
@@ -39,3 +39,28 @@ def CHECK_CMOCKA(conf):
return conf.CHECK_BUNDLED_SYSTEM_PKG('cmocka', minversion='1.1.1')
Build.BuildContext.CHECK_CMOCKA = CHECK_CMOCKA
+
+@conf
+def CHECK_SOCKET_WRAPPER(conf):
+ return conf.CHECK_BUNDLED_SYSTEM_PKG('socket_wrapper', minversion='1.1.9')
+Build.BuildContext.CHECK_SOCKET_WRAPPER = CHECK_SOCKET_WRAPPER
+
+@conf
+def CHECK_NSS_WRAPPER(conf):
+ return conf.CHECK_BUNDLED_SYSTEM_PKG('nss_wrapper', minversion='1.1.3')
+Build.BuildContext.CHECK_NSS_WRAPPER = CHECK_NSS_WRAPPER
+
+@conf
+def CHECK_RESOLV_WRAPPER(conf):
+ return conf.CHECK_BUNDLED_SYSTEM_PKG('resolv_wrapper', minversion='1.1.4')
+Build.BuildContext.CHECK_RESOLV_WRAPPER = CHECK_RESOLV_WRAPPER
+
+@conf
+def CHECK_UID_WRAPPER(conf):
+ return conf.CHECK_BUNDLED_SYSTEM_PKG('uid_wrapper', minversion='1.2.4')
+Build.BuildContext.CHECK_UID_WRAPPER = CHECK_UID_WRAPPER
+
+@conf
+def CHECK_PAM_WRAPPER(conf):
+ return conf.CHECK_BUNDLED_SYSTEM_PKG('pam_wrapper', minversion='1.0.4')
+Build.BuildContext.CHECK_PAM_WRAPPER = CHECK_PAM_WRAPPER
diff --git a/buildtools/wafsamba/wafsamba.py b/buildtools/wafsamba/wafsamba.py
index 1bdabf6..1e331e5 100644
--- a/buildtools/wafsamba/wafsamba.py
+++ b/buildtools/wafsamba/wafsamba.py
@@ -112,6 +112,7 @@ def SAMBA_LIBRARY(bld, libname, source,
vnum=None,
soname=None,
cflags='',
+ cflags_end=None,
ldflags='',
external_library=False,
realname=None,
@@ -195,6 +196,7 @@ def SAMBA_LIBRARY(bld, libname, source,
private_headers= private_headers,
header_path = header_path,
cflags = cflags,
+ cflags_end = cflags_end,
group = subsystem_group,
autoproto = autoproto,
autoproto_extra_source=autoproto_extra_source,
@@ -885,13 +887,30 @@ def INSTALL_WILDCARD(bld, destdir, pattern, chmod=MODE_644, flat=False,
python_fixup=python_fixup, base_name=trim_path)
Build.BuildContext.INSTALL_WILDCARD = INSTALL_WILDCARD
+def INSTALL_DIR(bld, path, chmod=0o755, env=None):
+ """Install a directory if it doesn't exist, always set permissions."""
-def INSTALL_DIRS(bld, destdir, dirs):
+ if not path:
+ return []
+
+ destpath = bld.get_install_path(path, env)
+
+ if bld.is_install > 0:
+ if not os.path.isdir(destpath):
+ try:
+ os.makedirs(destpath)
+ os.chmod(destpath, chmod)
+ except OSError as e:
+ if not os.path.isdir(destpath):
+ raise Utils.WafError("Cannot create the folder '%s' (error: %s)" % (path, e))
+Build.BuildContext.INSTALL_DIR = INSTALL_DIR
+
+def INSTALL_DIRS(bld, destdir, dirs, chmod=0o755, env=None):
'''install a set of directories'''
destdir = bld.EXPAND_VARIABLES(destdir)
dirs = bld.EXPAND_VARIABLES(dirs)
for d in TO_LIST(dirs):
- bld.install_dir(os.path.join(destdir, d))
+ INSTALL_DIR(bld, os.path.join(destdir, d), chmod, env)
Build.BuildContext.INSTALL_DIRS = INSTALL_DIRS
diff --git a/buildtools/wafsamba/wscript b/buildtools/wafsamba/wscript
index 430d164..3b36b57 100644
--- a/buildtools/wafsamba/wscript
+++ b/buildtools/wafsamba/wscript
@@ -313,10 +313,6 @@ def configure(conf):
conf.env.GIT_LOCAL_CHANGES = Options.options.GIT_LOCAL_CHANGES
- conf.CHECK_COMMAND(['uname', '-a'],
- msg='Checking build system',
- define='BUILD_SYSTEM',
- on_target=False)
conf.CHECK_UNAME()
# see if we can compile and run a simple C program
diff --git a/common/ldb_attributes.c b/common/ldb_attributes.c
index 98ec5a4..32f25fd 100644
--- a/common/ldb_attributes.c
+++ b/common/ldb_attributes.c
@@ -395,3 +395,17 @@ void ldb_schema_set_override_indexlist(struct ldb_context *ldb,
ldb->schema.index_handler_override = true;
ldb->schema.one_level_indexes = one_level_indexes;
}
+
+/*
+ * set that the GUID index mode is in operation
+ *
+ * The caller must ensure the supplied strings do not go out of
+ * scope (they are typically constant memory).
+ */
+void ldb_schema_set_override_GUID_index(struct ldb_context *ldb,
+ const char *GUID_index_attribute,
+ const char *GUID_index_dn_component)
+{
+ ldb->schema.GUID_index_attribute = GUID_index_attribute;
+ ldb->schema.GUID_index_dn_component = GUID_index_dn_component;
+}
diff --git a/common/ldb_match.c b/common/ldb_match.c
index 1415fac..25fe3f9 100644
--- a/common/ldb_match.c
+++ b/common/ldb_match.c
@@ -515,17 +515,18 @@ static int ldb_match_extended(struct ldb_context *ldb,
}
/*
- return 0 if the given parse tree matches the given message. Assumes
- the message is in sorted order
+ Check if a particular message will match the given filter
- return 1 if it matches, and 0 if it doesn't match
+ set *matched to true if it matches, false otherwise
+
+ returns LDB_SUCCESS or an error
this is a recursive function, and does short-circuit evaluation
*/
-static int ldb_match_message(struct ldb_context *ldb,
- const struct ldb_message *msg,
- const struct ldb_parse_tree *tree,
- enum ldb_scope scope, bool *matched)
+int ldb_match_message(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ enum ldb_scope scope, bool *matched)
{
unsigned int i;
int ret;
@@ -587,6 +588,13 @@ static int ldb_match_message(struct ldb_context *ldb,
return LDB_ERR_INAPPROPRIATE_MATCHING;
}
+/*
+ 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
+*/
+
int ldb_match_msg(struct ldb_context *ldb,
const struct ldb_message *msg,
const struct ldb_parse_tree *tree,
diff --git a/common/ldb_modules.c b/common/ldb_modules.c
index 25551e1..cc067ab 100644
--- a/common/ldb_modules.c
+++ b/common/ldb_modules.c
@@ -1103,7 +1103,7 @@ static int ldb_modules_load_dir(const char *modules_dir, const char *version)
*/
void ldb_set_modules_dir(struct ldb_context *ldb, const char *path)
{
- int ret = ldb_modules_load_path(path, LDB_VERSION);
+ int ret = ldb_modules_load_dir(path, LDB_VERSION);
if (ret != LDB_SUCCESS) {
ldb_asprintf_errstring(ldb, "Failed to load modules from: %s\n", path);
}
diff --git a/include/ldb_module.h b/include/ldb_module.h
index 71b4074..fd88c62 100644
--- a/include/ldb_module.h
+++ b/include/ldb_module.h
@@ -87,6 +87,15 @@ struct ldb_module;
/* force single value checking on this attribute */
#define LDB_FLAG_INTERNAL_FORCE_SINGLE_VALUE_CHECK 0x80
+/*
+ * ensure that this value is unique on an index
+ * (despite the index not otherwise being configured as UNIQUE).
+ * For example, all words starting with 'a' must be unique, but duplicates of
+ * words starting with b are allowed. This is specifically for Samba's
+ * objectSid index which is unique in the primary domain only.
+ */
+#define LDB_FLAG_INTERNAL_FORCE_UNIQUE_INDEX 0x100
+
/* an extended match rule that always fails to match */
#define SAMBA_LDAP_MATCH_ALWAYS_FALSE "1.3.6.1.4.1.7165.4.5.1"
@@ -183,6 +192,22 @@ void ldb_schema_attribute_set_override_handler(struct ldb_context *ldb,
void ldb_schema_set_override_indexlist(struct ldb_context *ldb,
bool one_level_indexes);
+/**
+
+ \param ldb The ldb context
+ \param GUID_index_attribute The globally attribute (eg objectGUID)
+ on each entry
+ \param GUID_index_attribute The DN component matching the
+ globally attribute on each entry (eg GUID)
+
+ The caller must ensure the supplied strings do not go out of
+ scope (they are typically constant memory).
+
+*/
+void ldb_schema_set_override_GUID_index(struct ldb_context *ldb,
+ const char *GUID_index_attribute,
+ const char *GUID_index_dn_component);
+
/* A useful function to build comparison functions with */
int ldb_any_comparison(struct ldb_context *ldb, void *mem_ctx,
ldb_attr_handler_t canonicalise_fn,
diff --git a/include/ldb_private.h b/include/ldb_private.h
index ae7ec3c..f999f75 100644
--- a/include/ldb_private.h
+++ b/include/ldb_private.h
@@ -98,6 +98,9 @@ struct ldb_schema {
*/
bool index_handler_override;
bool one_level_indexes;
+
+ const char *GUID_index_attribute;
+ const char *GUID_index_dn_component;
};
/*
@@ -287,5 +290,24 @@ int ldb_msg_find_duplicate_val(struct ldb_context *ldb,
const struct ldb_message_element *el,
struct ldb_val **duplicate,
uint32_t options);
+/**
+ Check if a particular message will match the given filter
+
+ \param ldb an ldb context
+ \param msg the message to be checked
+ \param tree the filter tree to check against
+ \param scope the scope to match against
+ (to avoid matching special DNs except on a base search)
+ \param matched a pointer to a boolean set true if it matches,
+ false otherwise
+
+ returns LDB_SUCCESS or an error
+
+ \note this is a recursive function, and does short-circuit evaluation
+ */
+int ldb_match_message(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ enum ldb_scope scope, bool *matched);
#endif
diff --git a/ldb_tdb/ldb_cache.c b/ldb_tdb/ldb_cache.c
index f08e073..5b90bd9 100644
--- a/ldb_tdb/ldb_cache.c
+++ b/ldb_tdb/ldb_cache.c
@@ -36,7 +36,7 @@
#define LTDB_FLAG_CASE_INSENSITIVE (1<<0)
#define LTDB_FLAG_INTEGER (1<<1)
-#define LTDB_FLAG_HIDDEN (1<<2)
+#define LTDB_FLAG_UNIQUE_INDEX (1<<2)
/* valid attribute flags */
static const struct {
@@ -45,7 +45,8 @@ static const struct {
} ltdb_valid_attr_flags[] = {
{ "CASE_INSENSITIVE", LTDB_FLAG_CASE_INSENSITIVE },
{ "INTEGER", LTDB_FLAG_INTEGER },
- { "HIDDEN", LTDB_FLAG_HIDDEN },
+ { "HIDDEN", 0 },
+ { "UNIQUE_INDEX", LTDB_FLAG_UNIQUE_INDEX},
{ "NONE", 0 },
{ NULL, 0 }
};
@@ -150,7 +151,7 @@ static int ltdb_attributes_load(struct ldb_module *module)
/* mapping these flags onto ldap 'syntaxes' isn't strictly correct,
but its close enough for now */
for (i=0;i<attrs_msg->num_elements;i++) {
- unsigned flags;
+ unsigned flags = 0, attr_flags = 0;
const char *syntax;
const struct ldb_schema_syntax *s;
const struct ldb_schema_attribute *a =
@@ -167,17 +168,20 @@ static int ltdb_attributes_load(struct ldb_module *module)
attrs_msg->elements[i].name);
goto failed;
}
- switch (flags & ~LTDB_FLAG_HIDDEN) {
- case 0:
- syntax = LDB_SYNTAX_OCTET_STRING;
- break;
- case LTDB_FLAG_CASE_INSENSITIVE:
+
+ if (flags & LTDB_FLAG_UNIQUE_INDEX) {
+ attr_flags = LDB_ATTR_FLAG_UNIQUE_INDEX;
+ }
+ flags &= ~LTDB_FLAG_UNIQUE_INDEX;
+
+ /* These are not currently flags, each is exclusive */
+ if (flags == LTDB_FLAG_CASE_INSENSITIVE) {
syntax = LDB_SYNTAX_DIRECTORY_STRING;
- break;
- case LTDB_FLAG_INTEGER:
+ } else if (flags == LTDB_FLAG_INTEGER) {
syntax = LDB_SYNTAX_INTEGER;
- break;
- default:
+ } else if (flags == 0) {
+ syntax = LDB_SYNTAX_OCTET_STRING;
+ } else {
ldb_debug(ldb, LDB_DEBUG_ERROR,
"Invalid flag combination 0x%x for '%s' "
"in @ATTRIBUTES",
@@ -194,12 +198,12 @@ static int ltdb_attributes_load(struct ldb_module *module)
goto failed;
}
- flags |= LDB_ATTR_FLAG_ALLOCATED | LDB_ATTR_FLAG_FROM_DB;
+ attr_flags |= LDB_ATTR_FLAG_ALLOCATED | LDB_ATTR_FLAG_FROM_DB;
r = ldb_schema_attribute_fill_with_syntax(ldb,
attrs,
attrs_msg->elements[i].name,
- flags, s,
+ attr_flags, s,
&attrs[num_loaded_attrs + ldb->schema.num_attributes]);
if (r != 0) {
goto failed;
@@ -243,6 +247,10 @@ static int ltdb_index_load(struct ldb_module *module,
*/
ltdb->cache->attribute_indexes = true;
ltdb->cache->one_level_indexes = ldb->schema.one_level_indexes;
+ ltdb->cache->GUID_index_attribute
+ = ldb->schema.GUID_index_attribute;
+ ltdb->cache->GUID_index_dn_component
+ = ldb->schema.GUID_index_dn_component;
return 0;
}
@@ -276,6 +284,12 @@ static int ltdb_index_load(struct ldb_module *module,
if (ldb_msg_find_element(ltdb->cache->indexlist, LTDB_IDXATTR) != NULL) {
ltdb->cache->attribute_indexes = true;
}
+ ltdb->cache->GUID_index_attribute
+ = ldb_msg_find_attr_as_string(ltdb->cache->indexlist,
+ LTDB_IDXGUID, NULL);
+ ltdb->cache->GUID_index_dn_component
+ = ldb_msg_find_attr_as_string(ltdb->cache->indexlist,
+ LTDB_IDX_DN_GUID, NULL);
return 0;
}
@@ -371,6 +385,7 @@ int ltdb_cache_load(struct ldb_module *module)
struct ldb_dn *baseinfo_dn = NULL, *options_dn = NULL;
uint64_t seq;
struct ldb_message *baseinfo = NULL, *options = NULL;
+ const struct ldb_schema_attribute *a;
int r;
ldb = ldb_module_get_ctx(module);
@@ -474,6 +489,17 @@ int ltdb_cache_load(struct ldb_module *module)
goto failed;
}
+ ltdb->GUID_index_syntax = NULL;
+ if (ltdb->cache->GUID_index_attribute != NULL) {
+ /*
+ * Now the attributes are loaded, set the guid_index_syntax.
+ * This can't fail, it will return a default at worst
+ */
+ a = ldb_schema_attribute_by_name(ldb,
+ ltdb->cache->GUID_index_attribute);
+ ltdb->GUID_index_syntax = a->syntax;
+ }
+
done:
talloc_free(options);
talloc_free(baseinfo);
diff --git a/ldb_tdb/ldb_index.c b/ldb_tdb/ldb_index.c
index 56ecf93..99fef23 100644
--- a/ldb_tdb/ldb_index.c
+++ b/ldb_tdb/ldb_index.c
@@ -31,12 +31,133 @@
* Author: Andrew Tridgell
*/
+/*
+
+LDB Index design and choice of TDB key:
+=======================================
+
+LDB has index records held as LDB objects with a special record like:
+
+dn: @INDEX:attr:value
+
+value may be base64 encoded, if it is deemed not printable:
+
+dn: @INDEX:attr::base64-value
+
+In each record, there is two possible formats:
+
+The original format is:
+-----------------------
+
+dn: @INDEX:NAME:DNSUPDATEPROXY
+@IDXVERSION: 2
+@IDX: CN=DnsUpdateProxy,CN=Users,DC=addom,DC=samba,DC=example,DC=com
+
+In this format, @IDX is multi-valued, one entry for each match
+
+The corrosponding entry is stored in a TDB record with key:
+
+DN=CN=DNSUPDATEPROXY,CN=USERS,DC=ADDOM,DC=SAMBA,DC=EXAMPLE,DC=COM
+
+(This allows a scope BASE search to directly find the record via
+a simple casefold of the DN).
+
+The original mixed-case DN is stored in the entry iself.
+
+
+The new 'GUID index' format is:
+-------------------------------
+
+dn: @INDEX:NAME:DNSUPDATEPROXY
+@IDXVERSION: 3
+@IDX: <binary GUID>[<binary GUID>[...]]
+
+The binary guid is 16 bytes, as bytes and not expanded as hexidecimal
+or pretty-printed. The GUID is chosen from the message to be stored
+by the @IDXGUID attribute on @INDEXLIST.
+
+If there are multiple values the @IDX value simply becomes longer,
+in multiples of 16.
+
+The corrosponding entry is stored in a TDB record with key:
+
+GUID=<binary GUID>
+
+This allows a very quick translation between the fixed-length index
+values and the TDB key, while seperating entries from other data
+in the TDB, should they be unlucky enough to start with the bytes of
+the 'DN=' prefix.
+
+Additionally, this allows a scope BASE search to directly find the
+record via a simple match on a GUID= extended DN, controlled via
+@IDX_DN_GUID on @INDEXLIST
+
+Exception for special @ DNs:
+
+@BASEINFO, @INDEXLIST and all other special DNs are stored as per the
+original format, as they are never referenced in an index and are used
+to bootstrap the database.
+
+
+Control points for choice of index mode
+---------------------------------------
+
+The choice of index and TDB key mode is made based (for example, from
+Samba) on entries in the @INDEXLIST DN:
+
+dn: @INDEXLIST
+@IDXGUID: objectGUID
+@IDX_DN_GUID: GUID
+
+By default, the original DN format is used.
+
+
+Control points for choosing indexed attributes
+----------------------------------------------
+
+@IDXATTR controls if an attribute is indexed
+
+dn: @INDEXLIST
+@IDXATTR: samAccountName
+@IDXATTR: nETBIOSName
+
+
+C Override functions
+--------------------
+
+void ldb_schema_set_override_GUID_index(struct ldb_context *ldb,
+ const char *GUID_index_attribute,
+ const char *GUID_index_dn_component)
+
+This is used, particularly in combination with the below, instead of
+the @IDXGUID and @IDX_DN_GUID values in @INDEXLIST.
+
+void ldb_schema_set_override_indexlist(struct ldb_context *ldb,
+ bool one_level_indexes);
+void ldb_schema_attribute_set_override_handler(struct ldb_context *ldb,
+ ldb_attribute_handler_override_fn_t override,
+ void *private_data);
+
+When the above two functions are called in combination, the @INDEXLIST
+values are not read from the DB, so
+ldb_schema_set_override_GUID_index() must be called.
+
+*/
+
#include "ldb_tdb.h"
#include "ldb_private.h"
+#include "lib/util/binsearch.h"
struct dn_list {
unsigned int count;
struct ldb_val *dn;
+ /*
+ * Do not optimise the intersection of this list,
+ * we must never return an entry not in this
+ * list. This allows the index for
+ * SCOPE_ONELEVEL to be trusted.
+ */
+ bool strict;
};
struct ltdb_idxptr {
@@ -44,11 +165,24 @@ struct ltdb_idxptr {
int error;
};
+static int ltdb_write_index_dn_guid(struct ldb_module *module,
+ const struct ldb_message *msg,
+ int add);
+static int ltdb_index_dn_base_dn(struct ldb_module *module,
+ struct ltdb_private *ltdb,
+ struct ldb_dn *base_dn,
+ struct dn_list *dn_list);
+
+static void ltdb_dn_list_sort(struct ltdb_private *ltdb,
+ struct dn_list *list);
+
/* we put a @IDXVERSION attribute on index entries. This
allows us to tell if it was written by an older version
*/
#define LTDB_INDEXING_VERSION 2
+#define LTDB_GUID_INDEXING_VERSION 3
+
/* enable the idxptr mode when transactions start */
int ltdb_index_transaction_start(struct ldb_module *module)
{
@@ -61,48 +195,98 @@ int ltdb_index_transaction_start(struct ldb_module *module)
return LDB_SUCCESS;
}
-/* compare two DN entries in a dn_list. Take account of possible
- * differences in string termination */
-static int dn_list_cmp(const struct ldb_val *v1, const struct ldb_val *v2)
+/*
+ see if two ldb_val structures contain exactly the same data
+ return -1 or 1 for a mismatch, 0 for match
+*/
+static int ldb_val_equal_exact_for_qsort(const struct ldb_val *v1,
+ const struct ldb_val *v2)
{
- if (v1->length > v2->length && v1->data[v2->length] != 0) {
+ if (v1->length > v2->length) {
return -1;
}
- if (v1->length < v2->length && v2->data[v1->length] != 0) {
+ if (v1->length < v2->length) {
return 1;
}
- return strncmp((char *)v1->data, (char *)v2->data, v1->length);
+ return memcmp(v1->data, v2->data, v1->length);
+}
+
+/*
+ see if two ldb_val structures contain exactly the same data
+ return -1 or 1 for a mismatch, 0 for match
+*/
+static int ldb_val_equal_exact_ordered(const struct ldb_val v1,
+ const struct ldb_val *v2)
+{
+ if (v1.length > v2->length) {
+ return -1;
+ }
+ if (v1.length < v2->length) {
+ return 1;
+ }
+ return memcmp(v1.data, v2->data, v1.length);
}
/*
find a entry in a dn_list, using a ldb_val. Uses a case sensitive
- comparison with the dn returns -1 if not found
+ binary-safe comparison for the 'dn' returns -1 if not found
+
+ This is therefore safe when the value is a GUID in the future
*/
static int ltdb_dn_list_find_val(struct ltdb_private *ltdb,
const struct dn_list *list,
const struct ldb_val *v)
{
unsigned int i;
- for (i=0; i<list->count; i++) {
- if (dn_list_cmp(&list->dn[i], v) == 0) {
- return i;
+ struct ldb_val *exact = NULL, *next = NULL;
+
+ if (ltdb->cache->GUID_index_attribute == NULL) {
+ for (i=0; i<list->count; i++) {
+ if (ldb_val_equal_exact(&list->dn[i], v) == 1) {
+ return i;
+ }
}
+ return -1;
+ }
+
+ BINARY_ARRAY_SEARCH_GTE(list->dn, list->count,
+ *v, ldb_val_equal_exact_ordered,
+ exact, next);
+ if (exact == NULL) {
+ return -1;
+ }
+ /* Not required, but keeps the compiler quiet */
+ if (next != NULL) {
+ return -1;
}
- return -1;
+
+ i = exact - list->dn;
+ return i;
}
/*
find a entry in a dn_list. Uses a case sensitive comparison with the dn
returns -1 if not found
*/
-static int ltdb_dn_list_find_str(struct ltdb_private *ltdb,
+static int ltdb_dn_list_find_msg(struct ltdb_private *ltdb,
struct dn_list *list,
- const char *dn)
+ const struct ldb_message *msg)
{
struct ldb_val v;
- v.data = discard_const_p(unsigned char, dn);
- v.length = strlen(dn);
+ const struct ldb_val *key_val;
+ if (ltdb->cache->GUID_index_attribute == NULL) {
+ const char *dn_str = ldb_dn_get_linearized(msg->dn);
+ v.data = discard_const_p(unsigned char, dn_str);
+ v.length = strlen(dn_str);
+ } else {
+ key_val = ldb_msg_find_ldb_val(msg,
+ ltdb->cache->GUID_index_attribute);
+ if (key_val == NULL) {
+ return -1;
+ }
+ v = *key_val;
+ }
return ltdb_dn_list_find_val(ltdb, list, &v);
}
@@ -144,12 +328,12 @@ static struct dn_list *ltdb_index_idxptr(struct ldb_module *module, TDB_DATA rec
struct dn_list
*/
static int ltdb_dn_list_load(struct ldb_module *module,
+ struct ltdb_private *ltdb,
struct ldb_dn *dn, struct dn_list *list)
{
struct ldb_message *msg;
- int ret;
+ int ret, version;
struct ldb_message_element *el;
- struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private);
TDB_DATA rec;
struct dn_list *list2;
TDB_DATA key;
@@ -196,29 +380,127 @@ normal_index:
return ret;
}
- /* TODO: check indexing version number */
-
el = ldb_msg_find_element(msg, LTDB_IDX);
if (!el) {
talloc_free(msg);
return LDB_SUCCESS;
}
+ version = ldb_msg_find_attr_as_int(msg, LTDB_IDXVERSION, 0);
+
/*
* we avoid copying the strings by stealing the list. We have
* to steal msg onto el->values (which looks odd) because we
* asked for the memory to be allocated on msg, not on each
* value with LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC above
*/
- talloc_steal(el->values, msg);
- list->dn = talloc_steal(list, el->values);
- list->count = el->num_values;
+ if (ltdb->cache->GUID_index_attribute == NULL) {
+ /* check indexing version number */
+ if (version != LTDB_INDEXING_VERSION) {
+ ldb_debug_set(ldb_module_get_ctx(module),
+ LDB_DEBUG_ERROR,
+ "Wrong DN index version %d "
+ "expected %d for %s",
+ version, LTDB_INDEXING_VERSION,
+ ldb_dn_get_linearized(dn));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ talloc_steal(el->values, msg);
+ list->dn = talloc_steal(list, el->values);
+ list->count = el->num_values;
+ } else {
+ unsigned int i;
+ if (version != LTDB_GUID_INDEXING_VERSION) {
+ /* This is quite likely during the DB startup
+ on first upgrade to using a GUID index */
+ ldb_debug_set(ldb_module_get_ctx(module),
+ LDB_DEBUG_ERROR,
+ "Wrong GUID index version %d "
+ "expected %d for %s",
+ version, LTDB_GUID_INDEXING_VERSION,
+ ldb_dn_get_linearized(dn));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (el->num_values != 1) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if ((el->values[0].length % LTDB_GUID_SIZE) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ list->count = el->values[0].length / LTDB_GUID_SIZE;
+ list->dn = talloc_array(list, struct ldb_val, list->count);
+
+ /*
+ * The actual data is on msg, due to
+ * LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC
+ */
+ talloc_steal(list->dn, msg);
+ for (i = 0; i < list->count; i++) {
+ list->dn[i].data
+ = &el->values[0].data[i * LTDB_GUID_SIZE];
+ list->dn[i].length = LTDB_GUID_SIZE;
+ }
+ }
/* We don't need msg->elements any more */
talloc_free(msg->elements);
return LDB_SUCCESS;
}
+int ltdb_key_dn_from_idx(struct ldb_module *module,
+ struct ltdb_private *ltdb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn,
+ TDB_DATA *tdb_key)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ int ret;
+ struct dn_list *list = talloc(mem_ctx, struct dn_list);
+ if (list == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ltdb_index_dn_base_dn(module, ltdb, dn, list);
+ if (ret != LDB_SUCCESS) {
+ TALLOC_FREE(list);
+ return ret;
+ }
+
+ if (list->count == 0) {
+ TALLOC_FREE(list);
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+ if (list->count > 1) {
+ const char *dn_str = ldb_dn_get_linearized(dn);
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ __location__
+ ": Failed to read DN index "
+ "against %s for %s: too many "
+ "values (%u > 1)",
+ ltdb->cache->GUID_index_attribute,
+ dn_str, list->count);
+ TALLOC_FREE(list);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ /* The tdb_key memory is allocated by the caller */
+ ret = ltdb_guid_to_key(module, ltdb,
+ &list->dn[0], tdb_key);
+ TALLOC_FREE(list);
+
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return LDB_SUCCESS;
+}
+
+
/*
save a dn_list into a full @IDX style record
@@ -231,26 +513,38 @@ static int ltdb_dn_list_store_full(struct ldb_module *module,
struct ldb_message *msg;
int ret;
+ msg = ldb_msg_new(module);
+ if (!msg) {
+ return ldb_module_oom(module);
+ }
+
+ msg->dn = dn;
+
if (list->count == 0) {
- ret = ltdb_delete_noindex(module, dn);
+ ret = ltdb_delete_noindex(module, msg);
if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ talloc_free(msg);
return LDB_SUCCESS;
}
return ret;
}
- msg = ldb_msg_new(module);
- if (!msg) {
- return ldb_module_oom(module);
- }
-
- ret = ldb_msg_add_fmt(msg, LTDB_IDXVERSION, "%u", LTDB_INDEXING_VERSION);
- if (ret != LDB_SUCCESS) {
- talloc_free(msg);
- return ldb_module_oom(module);
+ if (ltdb->cache->GUID_index_attribute == NULL) {
+ ret = ldb_msg_add_fmt(msg, LTDB_IDXVERSION, "%u",
+ LTDB_INDEXING_VERSION);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ return ldb_module_oom(module);
+ }
+ } else {
+ ret = ldb_msg_add_fmt(msg, LTDB_IDXVERSION, "%u",
+ LTDB_GUID_INDEXING_VERSION);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ return ldb_module_oom(module);
+ }
}
- msg->dn = dn;
if (list->count > 0) {
struct ldb_message_element *el;
@@ -259,8 +553,43 @@ static int ltdb_dn_list_store_full(struct ldb_module *module,
talloc_free(msg);
return ldb_module_oom(module);
}
- el->values = list->dn;
- el->num_values = list->count;
+
+ if (ltdb->cache->GUID_index_attribute == NULL) {
+ el->values = list->dn;
+ el->num_values = list->count;
+ } else {
+ struct ldb_val v;
+ unsigned int i;
+ el->values = talloc_array(msg,
+ struct ldb_val, 1);
+ if (el->values == NULL) {
+ talloc_free(msg);
+ return ldb_module_oom(module);
+ }
+
+ v.data = talloc_array_size(el->values,
+ list->count,
+ LTDB_GUID_SIZE);
+ if (v.data == NULL) {
+ talloc_free(msg);
+ return ldb_module_oom(module);
+ }
+
+ v.length = talloc_get_size(v.data);
+
+ for (i = 0; i < list->count; i++) {
+ if (list->dn[i].length !=
+ LTDB_GUID_SIZE) {
+ talloc_free(msg);
+ return ldb_module_operr(module);
+ }
+ memcpy(&v.data[LTDB_GUID_SIZE*i],
+ list->dn[i].data,
+ LTDB_GUID_SIZE);
+ }
+ el->values[0] = v;
+ el->num_values = 1;
+ }
}
ret = ltdb_store(module, msg, TDB_REPLACE);
@@ -317,6 +646,11 @@ static int ltdb_dn_list_store(struct ldb_module *module, struct ldb_dn *dn,
rec.dptr = (uint8_t *)&list2;
rec.dsize = sizeof(void *);
+
+ /*
+ * This is not a store into the main DB, but into an in-memory
+ * TDB, so we don't need a guard on ltdb->read_only
+ */
ret = tdb_store(ltdb->idxptr->itdb, key, rec, TDB_INSERT);
if (ret != 0) {
return ltdb_err_map(tdb_error(ltdb->idxptr->itdb));
@@ -407,45 +741,89 @@ int ltdb_index_transaction_cancel(struct ldb_module *module)
the caller is responsible for freeing
*/
static struct ldb_dn *ltdb_index_key(struct ldb_context *ldb,
+ struct ltdb_private *ltdb,
const char *attr, const struct ldb_val *value,
const struct ldb_schema_attribute **ap)
{
struct ldb_dn *ret;
struct ldb_val v;
- const struct ldb_schema_attribute *a;
- char *attr_folded;
+ const struct ldb_schema_attribute *a = NULL;
+ char *attr_folded = NULL;
+ const char *attr_for_dn = NULL;
int r;
+ bool should_b64_encode;
- attr_folded = ldb_attr_casefold(ldb, attr);
- if (!attr_folded) {
- return NULL;
+ if (attr[0] == '@') {
+ attr_for_dn = attr;
+ v = *value;
+ if (ap != NULL) {
+ *ap = NULL;
+ }
+ } else {
+ attr_folded = ldb_attr_casefold(ldb, attr);
+ if (!attr_folded) {
+ return NULL;
+ }
+
+ attr_for_dn = attr_folded;
+
+ a = ldb_schema_attribute_by_name(ldb, attr);
+ if (ap) {
+ *ap = a;
+ }
+ r = a->syntax->canonicalise_fn(ldb, ldb, value, &v);
+ if (r != LDB_SUCCESS) {
+ const char *errstr = ldb_errstring(ldb);
+ /* canonicalisation can be refused. For
+ example, a attribute that takes wildcards
+ will refuse to canonicalise if the value
+ contains a wildcard */
+ ldb_asprintf_errstring(ldb,
+ "Failed to create index "
+ "key for attribute '%s':%s%s%s",
+ attr, ldb_strerror(r),
+ (errstr?":":""),
+ (errstr?errstr:""));
+ talloc_free(attr_folded);
+ return NULL;
+ }
}
- a = ldb_schema_attribute_by_name(ldb, attr);
- if (ap) {
- *ap = a;
- }
- r = a->syntax->canonicalise_fn(ldb, ldb, value, &v);
- if (r != LDB_SUCCESS) {
- const char *errstr = ldb_errstring(ldb);
- /* canonicalisation can be refused. For example,
- a attribute that takes wildcards will refuse to canonicalise
- if the value contains a wildcard */
- ldb_asprintf_errstring(ldb, "Failed to create index key for attribute '%s':%s%s%s",
- attr, ldb_strerror(r), (errstr?":":""), (errstr?errstr:""));
- talloc_free(attr_folded);
- return NULL;
+ /*
+ * We do not base 64 encode a DN in a key, it has already been
+ * casefold and lineraized, that is good enough. That already
+ * avoids embedded NUL etc.
+ */
+ if (ltdb->cache->GUID_index_attribute != NULL) {
+ if (strcmp(attr, LTDB_IDXDN) == 0) {
+ should_b64_encode = false;
+ } else if (strcmp(attr, LTDB_IDXONE) == 0) {
+ /*
+ * We can only change the behaviour for IDXONE
+ * when the GUID index is enabled
+ */
+ should_b64_encode = false;
+ } else {
+ should_b64_encode
+ = ldb_should_b64_encode(ldb, &v);
+ }
+ } else {
+ should_b64_encode = ldb_should_b64_encode(ldb, &v);
}
- if (ldb_should_b64_encode(ldb, &v)) {
+
+ if (should_b64_encode) {
char *vstr = ldb_base64_encode(ldb, (char *)v.data, v.length);
if (!vstr) {
talloc_free(attr_folded);
return NULL;
}
- ret = ldb_dn_new_fmt(ldb, ldb, "%s:%s::%s", LTDB_INDEX, attr_folded, vstr);
+ ret = ldb_dn_new_fmt(ldb, ldb, "%s:%s::%s", LTDB_INDEX,
+ attr_for_dn, vstr);
talloc_free(vstr);
} else {
- ret = ldb_dn_new_fmt(ldb, ldb, "%s:%s:%.*s", LTDB_INDEX, attr_folded, (int)v.length, (char *)v.data);
+ ret = ldb_dn_new_fmt(ldb, ldb, "%s:%s:%.*s", LTDB_INDEX,
+ attr_for_dn,
+ (int)v.length, (char *)v.data);
}
if (v.data != value->data) {
@@ -467,6 +845,12 @@ static bool ltdb_is_indexed(struct ldb_module *module,
unsigned int i;
struct ldb_message_element *el;
+ if ((ltdb->cache->GUID_index_attribute != NULL) &&
+ (ldb_attr_cmp(attr,
+ ltdb->cache->GUID_index_attribute) == 0)) {
+ /* Implicity covered, this is the index key */
+ return false;
+ }
if (ldb->schema.index_handler_override) {
const struct ldb_schema_attribute *a
= ldb_schema_attribute_by_name(ldb, attr);
@@ -538,16 +922,20 @@ static int ltdb_index_dn_simple(struct ldb_module *module,
/* the attribute is indexed. Pull the list of DNs that match the
search criterion */
- dn = ltdb_index_key(ldb, tree->u.equality.attr, &tree->u.equality.value, NULL);
+ dn = ltdb_index_key(ldb, ltdb,
+ tree->u.equality.attr,
+ &tree->u.equality.value, NULL);
if (!dn) return LDB_ERR_OPERATIONS_ERROR;
- ret = ltdb_dn_list_load(module, dn, list);
+ ret = ltdb_dn_list_load(module, ltdb, dn, list);
talloc_free(dn);
return ret;
}
-static bool list_union(struct ldb_context *, struct dn_list *, const struct dn_list *);
+static bool list_union(struct ldb_context *ldb,
+ struct ltdb_private *ltdb,
+ struct dn_list *list, struct dn_list *list2);
/*
return a list of dn's that might match a leaf indexed search
@@ -564,16 +952,59 @@ static int ltdb_index_dn_leaf(struct ldb_module *module,
list->count = 0;
return LDB_SUCCESS;
}
+ if (tree->u.equality.attr[0] == '@') {
+ /* Do not allow a indexed search against an @ */
+ list->dn = NULL;
+ list->count = 0;
+ return LDB_SUCCESS;
+ }
if (ldb_attr_dn(tree->u.equality.attr) == 0) {
+ struct ldb_dn *dn
+ = ldb_dn_from_ldb_val(list,
+ ldb_module_get_ctx(module),
+ &tree->u.equality.value);
+ if (dn == NULL) {
+ /* If we can't parse it, no match */
+ list->dn = NULL;
+ list->count = 0;
+ return LDB_SUCCESS;
+ }
+
+ /*
+ * Re-use the same code we use for a SCOPE_BASE
+ * search
+ *
+ * We can't call TALLOC_FREE(dn) as this must belong
+ * to list for the memory to remain valid.
+ */
+ return ltdb_index_dn_base_dn(module, ltdb, dn, list);
+
+ } else if ((ltdb->cache->GUID_index_attribute != NULL) &&
+ (ldb_attr_cmp(tree->u.equality.attr,
+ ltdb->cache->GUID_index_attribute) == 0)) {
+ int ret;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
list->dn = talloc_array(list, struct ldb_val, 1);
if (list->dn == NULL) {
ldb_module_oom(module);
return LDB_ERR_OPERATIONS_ERROR;
}
- list->dn[0] = tree->u.equality.value;
+ /*
+ * We need to go via the canonicalise_fn() to
+ * ensure we get the index in binary, rather
+ * than a string
+ */
+ ret = ltdb->GUID_index_syntax->canonicalise_fn(ldb,
+ list->dn,
+ &tree->u.equality.value,
+ &list->dn[0]);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
list->count = 1;
return LDB_SUCCESS;
}
+
return ltdb_index_dn_simple(module, ltdb, tree, list);
}
@@ -586,6 +1017,7 @@ static bool list_intersect(struct ldb_context *ldb,
struct ltdb_private *ltdb,
struct dn_list *list, const struct dn_list *list2)
{
+ const struct dn_list *short_list, *long_list;
struct dn_list *list3;
unsigned int i;
@@ -604,10 +1036,10 @@ static bool list_intersect(struct ldb_context *ldb,
what really matches, as all results are filtered by the
full expression at the end - this shortcut avoids a lot of
work in some cases */
- if (list->count < 2 && list2->count > 10) {
+ if (list->count < 2 && list2->count > 10 && list2->strict == false) {
return true;
}
- if (list2->count < 2 && list->count > 10) {
+ if (list2->count < 2 && list->count > 10 && list->strict == false) {
list->count = list2->count;
list->dn = list2->dn;
/* note that list2 may not be the parent of list2->dn,
@@ -618,26 +1050,37 @@ static bool list_intersect(struct ldb_context *ldb,
return true;
}
+ if (list->count > list2->count) {
+ short_list = list2;
+ long_list = list;
+ } else {
+ short_list = list;
+ long_list = list2;
+ }
+
list3 = talloc_zero(list, struct dn_list);
if (list3 == NULL) {
return false;
}
- list3->dn = talloc_array(list3, struct ldb_val, list->count);
+ list3->dn = talloc_array(list3, struct ldb_val,
+ MIN(list->count, list2->count));
if (!list3->dn) {
talloc_free(list3);
return false;
}
list3->count = 0;
- for (i=0;i<list->count;i++) {
- if (ltdb_dn_list_find_val(ltdb, list2,
- &list->dn[i]) != -1) {
- list3->dn[list3->count] = list->dn[i];
+ for (i=0;i<short_list->count;i++) {
+ /* For the GUID index case, this is a binary search */
+ if (ltdb_dn_list_find_val(ltdb, long_list,
+ &short_list->dn[i]) != -1) {
+ list3->dn[list3->count] = short_list->dn[i];
list3->count++;
}
}
+ list->strict |= list2->strict;
list->dn = talloc_steal(list, list3->dn);
list->count = list3->count;
talloc_free(list3);
@@ -651,9 +1094,11 @@ static bool list_intersect(struct ldb_context *ldb,
list = list | list2
*/
static bool list_union(struct ldb_context *ldb,
- struct dn_list *list, const struct dn_list *list2)
+ struct ltdb_private *ltdb,
+ struct dn_list *list, struct dn_list *list2)
{
struct ldb_val *dn3;
+ unsigned int i = 0, j = 0, k = 0;
if (list2->count == 0) {
/* X | 0 == X */
@@ -672,18 +1117,51 @@ static bool list_union(struct ldb_context *ldb,
return true;
}
+ /*
+ * Sort the lists (if not in GUID DN mode) so we can do
+ * the de-duplication during the merge
+ */
+ ltdb_dn_list_sort(ltdb, list);
+ ltdb_dn_list_sort(ltdb, list2);
+
dn3 = talloc_array(list, struct ldb_val, list->count + list2->count);
if (!dn3) {
ldb_oom(ldb);
return false;
}
- /* we allow for duplicates here, and get rid of them later */
- memcpy(dn3, list->dn, sizeof(list->dn[0])*list->count);
- memcpy(dn3+list->count, list2->dn, sizeof(list2->dn[0])*list2->count);
+ while (i < list->count || j < list2->count) {
+ int cmp;
+ if (i >= list->count) {
+ cmp = 1;
+ } else if (j >= list2->count) {
+ cmp = -1;
+ } else {
+ cmp = ldb_val_equal_exact_ordered(list->dn[i],
+ &list2->dn[j]);
+ }
+
+ if (cmp < 0) {
+ /* Take list */
+ dn3[k] = list->dn[i];
+ i++;
+ k++;
+ } else if (cmp > 0) {
+ /* Take list2 */
+ dn3[k] = list2->dn[j];
+ j++;
+ k++;
+ } else {
+ /* Equal, take list */
+ dn3[k] = list->dn[i];
+ i++;
+ j++;
+ k++;
+ }
+ }
list->dn = dn3;
- list->count += list2->count;
+ list->count = k;
return true;
}
@@ -734,7 +1212,7 @@ static int ltdb_index_dn_or(struct ldb_module *module,
return ret;
}
- if (!list_union(ldb, list, list2)) {
+ if (!list_union(ldb, ltdb, list, list2)) {
talloc_free(list2);
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -767,11 +1245,24 @@ static int ltdb_index_dn_not(struct ldb_module *module,
return LDB_ERR_OPERATIONS_ERROR;
}
-
+/*
+ * These things are unique, so avoid a full scan if this is a search
+ * by GUID, DN or a unique attribute
+ */
static bool ltdb_index_unique(struct ldb_context *ldb,
+ struct ltdb_private *ltdb,
const char *attr)
{
const struct ldb_schema_attribute *a;
+ if (ltdb->cache->GUID_index_attribute != NULL) {
+ if (ldb_attr_cmp(attr, ltdb->cache->GUID_index_attribute) == 0) {
+ return true;
+ }
+ }
+ if (ldb_attr_dn(attr) == 0) {
+ return true;
+ }
+
a = ldb_schema_attribute_by_name(ldb, attr);
if (a->flags & LDB_ATTR_FLAG_UNIQUE_INDEX) {
return true;
@@ -804,7 +1295,8 @@ static int ltdb_index_dn_and(struct ldb_module *module,
int ret;
if (subtree->operation != LDB_OP_EQUALITY ||
- !ltdb_index_unique(ldb, subtree->u.equality.attr)) {
+ !ltdb_index_unique(ldb, ltdb,
+ subtree->u.equality.attr)) {
continue;
}
@@ -884,9 +1376,11 @@ static int ltdb_index_dn_and(struct ldb_module *module,
/*
return a list of matching objects using a one-level index
*/
-static int ltdb_index_dn_one(struct ldb_module *module,
- struct ldb_dn *parent_dn,
- struct dn_list *list)
+static int ltdb_index_dn_attr(struct ldb_module *module,
+ struct ltdb_private *ltdb,
+ const char *attr,
+ struct ldb_dn *dn,
+ struct dn_list *list)
{
struct ldb_context *ldb;
struct ldb_dn *key;
@@ -896,15 +1390,15 @@ static int ltdb_index_dn_one(struct ldb_module *module,
ldb = ldb_module_get_ctx(module);
/* work out the index key from the parent DN */
- val.data = (uint8_t *)((uintptr_t)ldb_dn_get_casefold(parent_dn));
+ val.data = (uint8_t *)((uintptr_t)ldb_dn_get_casefold(dn));
val.length = strlen((char *)val.data);
- key = ltdb_index_key(ldb, LTDB_IDXONE, &val, NULL);
+ key = ltdb_index_key(ldb, ltdb, attr, &val, NULL);
if (!key) {
ldb_oom(ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ltdb_dn_list_load(module, key, list);
+ ret = ltdb_dn_list_load(module, ltdb, key, list);
talloc_free(key);
if (ret != LDB_SUCCESS) {
return ret;
@@ -918,6 +1412,66 @@ static int ltdb_index_dn_one(struct ldb_module *module,
}
/*
+ return a list of matching objects using a one-level index
+ */
+static int ltdb_index_dn_one(struct ldb_module *module,
+ struct ltdb_private *ltdb,
+ struct ldb_dn *parent_dn,
+ struct dn_list *list)
+{
+ /* Ensure we do not shortcut on intersection for this list */
+ list->strict = true;
+ return ltdb_index_dn_attr(module, ltdb,
+ LTDB_IDXONE, parent_dn, list);
+}
+
+/*
+ return a list of matching objects using the DN index
+ */
+static int ltdb_index_dn_base_dn(struct ldb_module *module,
+ struct ltdb_private *ltdb,
+ struct ldb_dn *base_dn,
+ struct dn_list *dn_list)
+{
+ const struct ldb_val *guid_val = NULL;
+ if (ltdb->cache->GUID_index_attribute == NULL) {
+ dn_list->dn = talloc_array(dn_list, struct ldb_val, 1);
+ if (dn_list->dn == NULL) {
+ return ldb_module_oom(module);
+ }
+ dn_list->dn[0].data = discard_const_p(unsigned char,
+ ldb_dn_get_linearized(base_dn));
+ if (dn_list->dn[0].data == NULL) {
+ return ldb_module_oom(module);
+ }
+ dn_list->dn[0].length = strlen((char *)dn_list->dn[0].data);
+ dn_list->count = 1;
+
+ return LDB_SUCCESS;
+ }
+
+ if (ltdb->cache->GUID_index_dn_component != NULL) {
+ guid_val = ldb_dn_get_extended_component(base_dn,
+ ltdb->cache->GUID_index_dn_component);
+ }
+
+ if (guid_val != NULL) {
+ dn_list->dn = talloc_array(dn_list, struct ldb_val, 1);
+ if (dn_list->dn == NULL) {
+ return ldb_module_oom(module);
+ }
+ dn_list->dn[0].data = guid_val->data;
+ dn_list->dn[0].length = guid_val->length;
+ dn_list->count = 1;
+
+ return LDB_SUCCESS;
+ }
+
+ return ltdb_index_dn_attr(module, ltdb,
+ LTDB_IDXDN, base_dn, dn_list);
+}
+
+/*
return a list of dn's that might match a indexed search or
an error. return LDB_ERR_NO_SUCH_OBJECT for no matches, or LDB_SUCCESS for matches
*/
@@ -976,7 +1530,11 @@ static int ltdb_index_filter(struct ltdb_private *ltdb,
ldb = ldb_module_get_ctx(ac->module);
for (i = 0; i < dn_list->count; i++) {
- struct ldb_dn *dn;
+ uint8_t guid_key[LTDB_GUID_KEY_SIZE];
+ TDB_DATA tdb_key = {
+ .dptr = guid_key,
+ .dsize = sizeof(guid_key)
+ };
int ret;
bool matched;
@@ -985,16 +1543,20 @@ static int ltdb_index_filter(struct ltdb_private *ltdb,
return LDB_ERR_OPERATIONS_ERROR;
}
- dn = ldb_dn_from_ldb_val(msg, ldb, &dn_list->dn[i]);
- if (dn == NULL) {
- talloc_free(msg);
- return LDB_ERR_OPERATIONS_ERROR;
+ ret = ltdb_idx_to_key(ac->module, ltdb,
+ ac, &dn_list->dn[i],
+ &tdb_key);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
- ret = ltdb_search_dn1(ac->module, dn, msg,
+ ret = ltdb_search_key(ac->module, ltdb,
+ tdb_key, msg,
LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC|
LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC);
- talloc_free(dn);
+ if (tdb_key.dptr != guid_key) {
+ TALLOC_FREE(tdb_key.dptr);
+ }
if (ret == LDB_ERR_NO_SUCH_OBJECT) {
/* the record has disappeared? yes, this can happen */
talloc_free(msg);
@@ -1007,8 +1569,18 @@ static int ltdb_index_filter(struct ltdb_private *ltdb,
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ldb_match_msg_error(ldb, msg,
- ac->tree, ac->base, ac->scope, &matched);
+ /* We trust the index for SCOPE_ONELEVEL and SCOPE_BASE */
+ if ((ac->scope == LDB_SCOPE_ONELEVEL
+ && ltdb->cache->one_level_indexes)
+ || ac->scope == LDB_SCOPE_BASE) {
+ ret = ldb_match_message(ldb, msg, ac->tree,
+ ac->scope, &matched);
+ } else {
+ ret = ldb_match_msg_error(ldb, msg,
+ ac->tree, ac->base,
+ ac->scope, &matched);
+ }
+
if (ret != LDB_SUCCESS) {
talloc_free(msg);
return ret;
@@ -1043,29 +1615,22 @@ static int ltdb_index_filter(struct ltdb_private *ltdb,
}
/*
- remove any duplicated entries in a indexed result
+ sort a DN list
*/
-static void ltdb_dn_list_remove_duplicates(struct dn_list *list)
+static void ltdb_dn_list_sort(struct ltdb_private *ltdb,
+ struct dn_list *list)
{
- unsigned int i, new_count;
-
if (list->count < 2) {
return;
}
- TYPESAFE_QSORT(list->dn, list->count, dn_list_cmp);
-
- new_count = 1;
- for (i=1; i<list->count; i++) {
- if (dn_list_cmp(&list->dn[i], &list->dn[new_count-1]) != 0) {
- if (new_count != i) {
- list->dn[new_count] = list->dn[i];
- }
- new_count++;
- }
+ /* We know the list is sorted when using the GUID index */
+ if (ltdb->cache->GUID_index_attribute != NULL) {
+ return;
}
- list->count = new_count;
+ TYPESAFE_QSORT(list->dn, list->count,
+ ldb_val_equal_exact_for_qsort);
}
/*
@@ -1079,6 +1644,7 @@ int ltdb_search_indexed(struct ltdb_context *ac, uint32_t *match_count)
struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(ac->module), struct ltdb_private);
struct dn_list *dn_list;
int ret;
+ enum ldb_scope index_scope;
/* see if indexing is enabled */
if (!ltdb->cache->attribute_indexes &&
@@ -1093,94 +1659,105 @@ int ltdb_search_indexed(struct ltdb_context *ac, uint32_t *match_count)
return ldb_module_oom(ac->module);
}
- switch (ac->scope) {
+ /*
+ * For the purposes of selecting the switch arm below, if we
+ * don't have a one-level index then treat it like a subtree
+ * search
+ */
+ if (ac->scope == LDB_SCOPE_ONELEVEL &&
+ !ltdb->cache->one_level_indexes) {
+ index_scope = LDB_SCOPE_SUBTREE;
+ } else {
+ index_scope = ac->scope;
+ }
+
+ switch (index_scope) {
case LDB_SCOPE_BASE:
- dn_list->dn = talloc_array(dn_list, struct ldb_val, 1);
- if (dn_list->dn == NULL) {
- talloc_free(dn_list);
- return ldb_module_oom(ac->module);
- }
- dn_list->dn[0].data = discard_const_p(unsigned char, ldb_dn_get_linearized(ac->base));
- if (dn_list->dn[0].data == NULL) {
+ /*
+ * If we ever start to also load the index values for
+ * the tree, we must ensure we strictly intersect with
+ * this list, as we trust the BASE index
+ */
+ ret = ltdb_index_dn_base_dn(ac->module, ltdb,
+ ac->base, dn_list);
+ if (ret != LDB_SUCCESS) {
talloc_free(dn_list);
- return ldb_module_oom(ac->module);
+ return ret;
}
- dn_list->dn[0].length = strlen((char *)dn_list->dn[0].data);
- dn_list->count = 1;
break;
case LDB_SCOPE_ONELEVEL:
- {
- struct dn_list *idx_one_tree_list = NULL;
- if (!ltdb->cache->one_level_indexes) {
- talloc_free(dn_list);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- ret = ltdb_index_dn_one(ac->module, ac->base, dn_list);
+ /*
+ * If we ever start to also load the index values for
+ * the tree, we must ensure we strictly intersect with
+ * this list, as we trust the ONELEVEL index
+ */
+ ret = ltdb_index_dn_one(ac->module, ltdb, ac->base, dn_list);
if (ret != LDB_SUCCESS) {
talloc_free(dn_list);
return ret;
}
/*
- * If we have too many matches, also try the filter
- * tree and do index work there
+ * If we have too many matches, running the filter
+ * tree over the SCOPE_ONELEVEL can be quite expensive
+ * so we now check the filter tree index as well.
*
* We only do this in the GUID index mode, which is
* O(n*log(m)) otherwise the intersection below will
* be too costly at O(n*m).
+ *
+ * We don't set a heuristic for 'too many' but instead
+ * do it always and rely on the index lookup being
+ * fast enough in the small case.
*/
- idx_one_tree_list
- = talloc_zero(ac, struct dn_list);
- if (idx_one_tree_list == NULL) {
- return ldb_module_oom(ac->module);
- }
-
- if (!ltdb->cache->attribute_indexes) {
- talloc_free(idx_one_tree_list);
- talloc_free(dn_list);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- /*
- * Here we load the index for the tree.
- */
- ret = ltdb_index_dn(ac->module, ltdb, ac->tree,
- idx_one_tree_list);
- if (ret != LDB_SUCCESS) {
- talloc_free(idx_one_tree_list);
- talloc_free(dn_list);
- return ret;
- }
+ if (ltdb->cache->GUID_index_attribute != NULL) {
+ struct dn_list *idx_one_tree_list
+ = talloc_zero(ac, struct dn_list);
+ if (idx_one_tree_list == NULL) {
+ return ldb_module_oom(ac->module);
+ }
+
+ if (!ltdb->cache->attribute_indexes) {
+ talloc_free(idx_one_tree_list);
+ talloc_free(dn_list);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ /*
+ * Here we load the index for the tree.
+ */
+ ret = ltdb_index_dn(ac->module, ltdb, ac->tree,
+ idx_one_tree_list);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(idx_one_tree_list);
+ talloc_free(dn_list);
+ return ret;
+ }
- /*
- * We have to avoid the O(n*m) behaviour here blowing
- * up, so we only intersect the lists if it will
- * really help
- */
- if (idx_one_tree_list->count < 10) {
if (!list_intersect(ldb, ltdb,
dn_list, idx_one_tree_list)) {
talloc_free(idx_one_tree_list);
talloc_free(dn_list);
return LDB_ERR_OPERATIONS_ERROR;
}
- } else {
- talloc_free(idx_one_tree_list);
}
break;
- }
+
case LDB_SCOPE_SUBTREE:
case LDB_SCOPE_DEFAULT:
if (!ltdb->cache->attribute_indexes) {
talloc_free(dn_list);
return LDB_ERR_OPERATIONS_ERROR;
}
+ /*
+ * Here we load the index for the tree. We have no
+ * index for the subtree.
+ */
ret = ltdb_index_dn(ac->module, ltdb, ac->tree, dn_list);
if (ret != LDB_SUCCESS) {
talloc_free(dn_list);
return ret;
}
- ltdb_dn_list_remove_duplicates(dn_list);
break;
}
@@ -1211,7 +1788,7 @@ int ltdb_search_indexed(struct ltdb_context *ac, uint32_t *match_count)
*/
static int ltdb_index_add1(struct ldb_module *module,
struct ltdb_private *ltdb,
- const char *dn,
+ const struct ldb_message *msg,
struct ldb_message_element *el, int v_idx)
{
struct ldb_context *ldb;
@@ -1228,38 +1805,86 @@ static int ltdb_index_add1(struct ldb_module *module,
return LDB_ERR_OPERATIONS_ERROR;
}
- dn_key = ltdb_index_key(ldb, el->name, &el->values[v_idx], &a);
+ dn_key = ltdb_index_key(ldb, ltdb,
+ el->name, &el->values[v_idx], &a);
if (!dn_key) {
talloc_free(list);
return LDB_ERR_OPERATIONS_ERROR;
}
talloc_steal(list, dn_key);
- ret = ltdb_dn_list_load(module, dn_key, list);
+ ret = ltdb_dn_list_load(module, ltdb, dn_key, list);
if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
talloc_free(list);
return ret;
}
+ /*
+ * Check for duplicates in the @IDXDN DN -> GUID record
+ *
+ * This is very normal, it just means a duplicate DN creation
+ * was attempted, so don't set the error string or print scary
+ * messages.
+ */
if (list->count > 0 &&
- a->flags & LDB_ATTR_FLAG_UNIQUE_INDEX) {
+ ldb_attr_cmp(el->name, LTDB_IDXDN) == 0) {
+ talloc_free(list);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ /*
+ * Check for duplicates in unique indexes
+ */
+ if (list->count > 0 &&
+ ((a != NULL
+ && (a->flags & LDB_ATTR_FLAG_UNIQUE_INDEX ||
+ (el->flags & LDB_FLAG_INTERNAL_FORCE_UNIQUE_INDEX))))) {
/*
* We do not want to print info about a possibly
* confidential DN that the conflict was with in the
* user-visible error string
*/
- ldb_debug(ldb, LDB_DEBUG_WARNING,
- __location__ ": unique index violation on %s in %s, "
- "conficts with %*.*s in %s",
- el->name, dn,
- (int)list->dn[0].length,
- (int)list->dn[0].length,
- list->dn[0].data,
- ldb_dn_get_linearized(dn_key));
- ldb_asprintf_errstring(ldb, __location__ ": unique index violation on %s in %s",
- el->name, dn);
+
+ if (ltdb->cache->GUID_index_attribute == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING,
+ __location__
+ ": unique index violation on %s in %s, "
+ "conficts with %*.*s in %s",
+ el->name, ldb_dn_get_linearized(msg->dn),
+ (int)list->dn[0].length,
+ (int)list->dn[0].length,
+ list->dn[0].data,
+ ldb_dn_get_linearized(dn_key));
+ } else {
+ /* This can't fail, gives a default at worst */
+ const struct ldb_schema_attribute *attr
+ = ldb_schema_attribute_by_name(
+ ldb,
+ ltdb->cache->GUID_index_attribute);
+ struct ldb_val v;
+ ret = attr->syntax->ldif_write_fn(ldb, list,
+ &list->dn[0], &v);
+ if (ret == LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING,
+ __location__
+ ": unique index violation on %s in "
+ "%s, conficts with %s %*.*s in %s",
+ el->name,
+ ldb_dn_get_linearized(msg->dn),
+ ltdb->cache->GUID_index_attribute,
+ (int)v.length,
+ (int)v.length,
+ v.data,
+ ldb_dn_get_linearized(dn_key));
+ }
+ }
+ ldb_asprintf_errstring(ldb,
+ __location__ ": unique index violation "
+ "on %s in %s",
+ el->name,
+ ldb_dn_get_linearized(msg->dn));
talloc_free(list);
- return LDB_ERR_ENTRY_ALREADY_EXISTS;
+ return LDB_ERR_CONSTRAINT_VIOLATION;
}
/* overallocate the list a bit, to reduce the number of
@@ -1271,13 +1896,50 @@ static int ltdb_index_add1(struct ldb_module *module,
return LDB_ERR_OPERATIONS_ERROR;
}
- list->dn[list->count].data
- = (uint8_t *)talloc_strdup(list->dn, dn);
- if (list->dn[list->count].data == NULL) {
- talloc_free(list);
- return LDB_ERR_OPERATIONS_ERROR;
+ if (ltdb->cache->GUID_index_attribute == NULL) {
+ const char *dn_str = ldb_dn_get_linearized(msg->dn);
+ list->dn[list->count].data
+ = (uint8_t *)talloc_strdup(list->dn, dn_str);
+ if (list->dn[list->count].data == NULL) {
+ talloc_free(list);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ list->dn[list->count].length = strlen(dn_str);
+ } else {
+ const struct ldb_val *key_val;
+ struct ldb_val *exact = NULL, *next = NULL;
+ key_val = ldb_msg_find_ldb_val(msg,
+ ltdb->cache->GUID_index_attribute);
+ if (key_val == NULL) {
+ talloc_free(list);
+ return ldb_module_operr(module);
+ }
+
+ if (key_val->length != LTDB_GUID_SIZE) {
+ talloc_free(list);
+ return ldb_module_operr(module);
+ }
+
+ BINARY_ARRAY_SEARCH_GTE(list->dn, list->count,
+ *key_val, ldb_val_equal_exact_ordered,
+ exact, next);
+ if (exact != NULL) {
+ talloc_free(list);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (next == NULL) {
+ next = &list->dn[list->count];
+ } else {
+ memmove(&next[1], next,
+ sizeof(*next) * (list->count - (next - list->dn)));
+ }
+ *next = ldb_val_dup(list->dn, key_val);
+ if (next->data == NULL) {
+ talloc_free(list);
+ return ldb_module_operr(module);
+ }
}
- list->dn[list->count].length = strlen(dn);
list->count++;
ret = ltdb_dn_list_store(module, dn_key, list);
@@ -1292,13 +1954,13 @@ static int ltdb_index_add1(struct ldb_module *module,
*/
static int ltdb_index_add_el(struct ldb_module *module,
struct ltdb_private *ltdb,
- const char *dn,
+ const struct ldb_message *msg,
struct ldb_message_element *el)
{
unsigned int i;
for (i = 0; i < el->num_values; i++) {
int ret = ltdb_index_add1(module, ltdb,
- dn, el, i);
+ msg, el, i);
if (ret != LDB_SUCCESS) {
return ret;
}
@@ -1312,32 +1974,44 @@ static int ltdb_index_add_el(struct ldb_module *module,
*/
static int ltdb_index_add_all(struct ldb_module *module,
struct ltdb_private *ltdb,
- const char *dn,
- struct ldb_message_element *elements,
- unsigned int num_el)
+ const struct ldb_message *msg)
{
+ struct ldb_message_element *elements = msg->elements;
unsigned int i;
+ const char *dn_str;
+ int ret;
- if (dn[0] == '@') {
+ if (ldb_dn_is_special(msg->dn)) {
return LDB_SUCCESS;
}
+ dn_str = ldb_dn_get_linearized(msg->dn);
+ if (dn_str == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ltdb_write_index_dn_guid(module, msg, 1);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
if (!ltdb->cache->attribute_indexes) {
/* no indexed fields */
return LDB_SUCCESS;
}
- for (i = 0; i < num_el; i++) {
- int ret;
+ for (i = 0; i < msg->num_elements; i++) {
if (!ltdb_is_indexed(module, ltdb, elements[i].name)) {
continue;
}
- ret = ltdb_index_add_el(module, ltdb, dn, &elements[i]);
+ ret = ltdb_index_add_el(module, ltdb,
+ msg, &elements[i]);
if (ret != LDB_SUCCESS) {
struct ldb_context *ldb = ldb_module_get_ctx(module);
ldb_asprintf_errstring(ldb,
__location__ ": Failed to re-index %s in %s - %s",
- elements[i].name, dn, ldb_errstring(ldb));
+ elements[i].name, dn_str,
+ ldb_errstring(ldb));
return ret;
}
}
@@ -1347,17 +2021,67 @@ static int ltdb_index_add_all(struct ldb_module *module,
/*
+ insert a DN index for a message
+*/
+static int ltdb_modify_index_dn(struct ldb_module *module,
+ struct ltdb_private *ltdb,
+ const struct ldb_message *msg,
+ struct ldb_dn *dn,
+ const char *index, int add)
+{
+ struct ldb_message_element el;
+ struct ldb_val val;
+ int ret;
+
+ val.data = (uint8_t *)((uintptr_t)ldb_dn_get_casefold(dn));
+ if (val.data == NULL) {
+ const char *dn_str = ldb_dn_get_linearized(dn);
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ __location__
+ ": Failed to modify %s "
+ "against %s in %s: failed "
+ "to get casefold DN",
+ index,
+ ltdb->cache->GUID_index_attribute,
+ dn_str);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ val.length = strlen((char *)val.data);
+ el.name = index;
+ el.values = &val;
+ el.num_values = 1;
+
+ if (add) {
+ ret = ltdb_index_add1(module, ltdb, msg, &el, 0);
+ } else { /* delete */
+ ret = ltdb_index_del_value(module, ltdb, msg, &el, 0);
+ }
+
+ if (ret != LDB_SUCCESS) {
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ const char *dn_str = ldb_dn_get_linearized(dn);
+ ldb_asprintf_errstring(ldb,
+ __location__
+ ": Failed to modify %s "
+ "against %s in %s - %s",
+ index,
+ ltdb->cache->GUID_index_attribute,
+ dn_str, ldb_errstring(ldb));
+ return ret;
+ }
+ return ret;
+}
+
+/*
insert a one level index for a message
*/
static int ltdb_index_onelevel(struct ldb_module *module,
const struct ldb_message *msg, int add)
-{
+{
struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module),
struct ltdb_private);
- struct ldb_message_element el;
- struct ldb_val val;
struct ldb_dn *pdn;
- const char *dn;
int ret;
/* We index for ONE Level only if requested */
@@ -1369,32 +2093,39 @@ static int ltdb_index_onelevel(struct ldb_module *module,
if (pdn == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
+ ret = ltdb_modify_index_dn(module, ltdb,
+ msg, pdn, LTDB_IDXONE, add);
- dn = ldb_dn_get_linearized(msg->dn);
- if (dn == NULL) {
- talloc_free(pdn);
- return LDB_ERR_OPERATIONS_ERROR;
- }
+ talloc_free(pdn);
- val.data = (uint8_t *)((uintptr_t)ldb_dn_get_casefold(pdn));
- if (val.data == NULL) {
- talloc_free(pdn);
- return LDB_ERR_OPERATIONS_ERROR;
- }
+ return ret;
+}
- val.length = strlen((char *)val.data);
- el.name = LTDB_IDXONE;
- el.values = &val;
- el.num_values = 1;
+/*
+ insert a one level index for a message
+*/
+static int ltdb_write_index_dn_guid(struct ldb_module *module,
+ const struct ldb_message *msg,
+ int add)
+{
+ int ret;
+ struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module),
+ struct ltdb_private);
- if (add) {
- ret = ltdb_index_add1(module, ltdb, dn, &el, 0);
- } else { /* delete */
- ret = ltdb_index_del_value(module, ltdb, msg->dn, &el, 0);
+ /* We index for DN only if using a GUID index */
+ if (ltdb->cache->GUID_index_attribute == NULL) {
+ return LDB_SUCCESS;
}
- talloc_free(pdn);
+ ret = ltdb_modify_index_dn(module, ltdb, msg, msg->dn,
+ LTDB_IDXDN, add);
+ if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ "Entry %s already exists",
+ ldb_dn_get_linearized(msg->dn));
+ ret = LDB_ERR_ENTRY_ALREADY_EXISTS;
+ }
return ret;
}
@@ -1404,17 +2135,16 @@ static int ltdb_index_onelevel(struct ldb_module *module,
*/
int ltdb_index_add_element(struct ldb_module *module,
struct ltdb_private *ltdb,
- struct ldb_dn *dn,
+ const struct ldb_message *msg,
struct ldb_message_element *el)
{
- if (ldb_dn_is_special(dn)) {
+ if (ldb_dn_is_special(msg->dn)) {
return LDB_SUCCESS;
}
if (!ltdb_is_indexed(module, ltdb, el->name)) {
return LDB_SUCCESS;
}
- return ltdb_index_add_el(module, ltdb,
- ldb_dn_get_linearized(dn), el);
+ return ltdb_index_add_el(module, ltdb, msg, el);
}
/*
@@ -1424,25 +2154,37 @@ int ltdb_index_add_new(struct ldb_module *module,
struct ltdb_private *ltdb,
const struct ldb_message *msg)
{
- const char *dn;
int ret;
if (ldb_dn_is_special(msg->dn)) {
return LDB_SUCCESS;
}
- dn = ldb_dn_get_linearized(msg->dn);
- if (dn == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
+ ret = ltdb_index_add_all(module, ltdb, msg);
+ if (ret != LDB_SUCCESS) {
+ /*
+ * Because we can't trust the caller to be doing
+ * transactions properly, clean up any index for this
+ * entry rather than relying on a transaction
+ * cleanup
+ */
+
+ ltdb_index_delete(module, msg);
+ return ret;
}
- ret = ltdb_index_add_all(module, ltdb, dn, msg->elements,
- msg->num_elements);
+ ret = ltdb_index_onelevel(module, msg, 1);
if (ret != LDB_SUCCESS) {
+ /*
+ * Because we can't trust the caller to be doing
+ * transactions properly, clean up any index for this
+ * entry rather than relying on a transaction
+ * cleanup
+ */
+ ltdb_index_delete(module, msg);
return ret;
}
-
- return ltdb_index_onelevel(module, msg, 1);
+ return ret;
}
@@ -1451,7 +2193,7 @@ int ltdb_index_add_new(struct ldb_module *module,
*/
int ltdb_index_del_value(struct ldb_module *module,
struct ltdb_private *ltdb,
- struct ldb_dn *dn,
+ const struct ldb_message *msg,
struct ldb_message_element *el, unsigned int v_idx)
{
struct ldb_context *ldb;
@@ -1460,6 +2202,7 @@ int ltdb_index_del_value(struct ldb_module *module,
int ret, i;
unsigned int j;
struct dn_list *list;
+ struct ldb_dn *dn = msg->dn;
ldb = ldb_module_get_ctx(module);
@@ -1472,7 +2215,8 @@ int ltdb_index_del_value(struct ldb_module *module,
return LDB_SUCCESS;
}
- dn_key = ltdb_index_key(ldb, el->name, &el->values[v_idx], NULL);
+ dn_key = ltdb_index_key(ldb, ltdb,
+ el->name, &el->values[v_idx], NULL);
if (!dn_key) {
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -1483,7 +2227,7 @@ int ltdb_index_del_value(struct ldb_module *module,
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ltdb_dn_list_load(module, dn_key, list);
+ ret = ltdb_dn_list_load(module, ltdb, dn_key, list);
if (ret == LDB_ERR_NO_SUCH_OBJECT) {
/* it wasn't indexed. Did we have an earlier error? If we did then
its gone now */
@@ -1496,7 +2240,7 @@ int ltdb_index_del_value(struct ldb_module *module,
return ret;
}
- i = ltdb_dn_list_find_str(ltdb, list, dn_str);
+ i = ltdb_dn_list_find_msg(ltdb, list, msg);
if (i == -1) {
/* nothing to delete */
talloc_free(dn_key);
@@ -1528,7 +2272,7 @@ int ltdb_index_del_value(struct ldb_module *module,
*/
int ltdb_index_del_element(struct ldb_module *module,
struct ltdb_private *ltdb,
- struct ldb_dn *dn,
+ const struct ldb_message *msg,
struct ldb_message_element *el)
{
const char *dn_str;
@@ -1540,7 +2284,7 @@ int ltdb_index_del_element(struct ldb_module *module,
return LDB_SUCCESS;
}
- dn_str = ldb_dn_get_linearized(dn);
+ dn_str = ldb_dn_get_linearized(msg->dn);
if (dn_str == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -1553,7 +2297,7 @@ int ltdb_index_del_element(struct ldb_module *module,
return LDB_SUCCESS;
}
for (i = 0; i < el->num_values; i++) {
- ret = ltdb_index_del_value(module, ltdb, dn, el, i);
+ ret = ltdb_index_del_value(module, ltdb, msg, el, i);
if (ret != LDB_SUCCESS) {
return ret;
}
@@ -1581,6 +2325,11 @@ int ltdb_index_delete(struct ldb_module *module, const struct ldb_message *msg)
return ret;
}
+ ret = ltdb_write_index_dn_guid(module, msg, 0);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
if (!ltdb->cache->attribute_indexes) {
/* no indexed fields */
return LDB_SUCCESS;
@@ -1588,7 +2337,7 @@ int ltdb_index_delete(struct ldb_module *module, const struct ldb_message *msg)
for (i = 0; i < msg->num_elements; i++) {
ret = ltdb_index_del_element(module, ltdb,
- msg->dn, &msg->elements[i]);
+ msg, &msg->elements[i]);
if (ret != LDB_SUCCESS) {
return ret;
}
@@ -1599,7 +2348,12 @@ int ltdb_index_delete(struct ldb_module *module, const struct ldb_message *msg)
/*
- traversal function that deletes all @INDEX records
+ traversal function that deletes all @INDEX records in the in-memory
+ TDB.
+
+ This does not touch the actual DB, that is done at transaction
+ commit, which in turn greatly reduces DB churn as we will likely
+ be able to do a direct update into the old record.
*/
static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
{
@@ -1624,6 +2378,11 @@ static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, vo
v.length = strnlen((char *)key.dptr, key.dsize) - 3;
dn = ldb_dn_from_ldb_val(ltdb, ldb_module_get_ctx(module), &v);
+
+ /*
+ * This does not actually touch the DB quite yet, just
+ * the in-memory index cache
+ */
ret = ltdb_dn_list_store(module, dn, &list);
if (ret != LDB_SUCCESS) {
ldb_asprintf_errstring(ldb_module_get_ctx(module),
@@ -1639,6 +2398,7 @@ static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, vo
struct ltdb_reindex_context {
struct ldb_module *module;
int error;
+ uint32_t count;
};
/*
@@ -1699,9 +2459,10 @@ static int re_key(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *st
return -1;
}
- /* check if the DN key has changed, perhaps due to the
- case insensitivity of an element changing */
- key2 = ltdb_key(module, msg->dn);
+ /* check if the DN key has changed, perhaps due to the case
+ insensitivity of an element changing, or a change from DN
+ to GUID keys */
+ key2 = ltdb_key_msg(module, msg, msg);
if (key2.dptr == NULL) {
/* probably a corrupt record ... darn */
ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid DN in re_index: %s",
@@ -1742,6 +2503,13 @@ static int re_key(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *st
talloc_free(msg);
+ ctx->count++;
+ if (ctx->count % 10000 == 0) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING,
+ "Reindexing: re-keyed %u records so far",
+ ctx->count);
+ }
+
return 0;
}
@@ -1756,7 +2524,6 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module),
struct ltdb_private);
struct ldb_message *msg;
- const char *dn = NULL;
unsigned int nb_elements_in_db;
const struct ldb_val val = {
.data = data.dptr,
@@ -1803,8 +2570,6 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
(char *)key.dptr);
talloc_free(msg);
return -1;
- } else {
- dn = ldb_dn_get_linearized(msg->dn);
}
ret = ltdb_index_onelevel(module, msg, 1);
@@ -1816,8 +2581,7 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
return -1;
}
- ret = ltdb_index_add_all(module, ltdb, dn,
- msg->elements, msg->num_elements);
+ ret = ltdb_index_add_all(module, ltdb, msg);
if (ret != LDB_SUCCESS) {
ctx->error = ret;
@@ -1827,6 +2591,13 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
talloc_free(msg);
+ ctx->count++;
+ if (ctx->count % 10000 == 0) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING,
+ "Reindexing: re-indexed %u records so far",
+ ctx->count);
+ }
+
return 0;
}
@@ -1839,6 +2610,14 @@ int ltdb_reindex(struct ldb_module *module)
int ret;
struct ltdb_reindex_context ctx;
+ /*
+ * Only triggered after a modification, but make clear we do
+ * not re-index a read-only DB
+ */
+ if (ltdb->read_only) {
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
if (ltdb_cache_reload(module) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -1866,13 +2645,9 @@ int ltdb_reindex(struct ldb_module *module)
return LDB_ERR_OPERATIONS_ERROR;
}
- /* if we don't have indexes we have nothing todo */
- if (!ltdb->cache->attribute_indexes) {
- return LDB_SUCCESS;
- }
-
ctx.module = module;
ctx.error = 0;
+ ctx.count = 0;
/* now traverse adding any indexes for normal LDB records */
ret = tdb_traverse(ltdb->tdb, re_key, &ctx);
@@ -1890,6 +2665,7 @@ int ltdb_reindex(struct ldb_module *module)
}
ctx.error = 0;
+ ctx.count = 0;
/* now traverse adding any indexes for normal LDB records */
ret = tdb_traverse(ltdb->tdb, re_index, &ctx);
@@ -1906,5 +2682,11 @@ int ltdb_reindex(struct ldb_module *module)
return ctx.error;
}
+ if (ctx.count > 10000) {
+ ldb_debug(ldb_module_get_ctx(module),
+ LDB_DEBUG_WARNING, "Reindexing: re_index successful on %s, "
+ "final index write-out will be in transaction commit",
+ tdb_name(ltdb->tdb));
+ }
return LDB_SUCCESS;
}
diff --git a/ldb_tdb/ldb_search.c b/ldb_tdb/ldb_search.c
index a6c408a..0af230f 100644
--- a/ldb_tdb/ldb_search.c
+++ b/ldb_tdb/ldb_search.c
@@ -113,26 +113,61 @@ static int msg_add_distinguished_name(struct ldb_message *msg)
return LDB_ERR_NO_SUCH_OBJECT on record-not-found
and LDB_SUCCESS on success
*/
-static int ltdb_search_base(struct ldb_module *module, struct ldb_dn *dn)
+int ltdb_search_base(struct ldb_module *module,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn,
+ struct ldb_dn **ret_dn)
{
- void *data = ldb_module_get_private(module);
- struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
- TDB_DATA tdb_key;
int exists;
+ int ret;
+ struct ldb_message *msg = NULL;
if (ldb_dn_is_null(dn)) {
return LDB_ERR_NO_SUCH_OBJECT;
}
- /* form the key */
- tdb_key = ltdb_key(module, dn);
- if (!tdb_key.dptr) {
+ /*
+ * We can't use tdb_exists() directly on a key when the TDB
+ * key is the GUID one, not the DN based one. So we just do a
+ * normal search and avoid most of the allocation with the
+ * LDB_UNPACK_DATA_FLAG_NO_DN and
+ * LDB_UNPACK_DATA_FLAG_NO_ATTRS flags
+ */
+ msg = ldb_msg_new(module);
+ if (msg == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
- exists = tdb_exists(ltdb->tdb, tdb_key);
- talloc_free(tdb_key.dptr);
-
+ ret = ltdb_search_dn1(module, dn,
+ msg,
+ LDB_UNPACK_DATA_FLAG_NO_ATTRS);
+ if (ret == LDB_SUCCESS) {
+ const char *dn_linearized
+ = ldb_dn_get_linearized(dn);
+ const char *msg_dn_linearlized
+ = ldb_dn_get_linearized(msg->dn);
+
+ if (strcmp(dn_linearized, msg_dn_linearlized) == 0) {
+ /*
+ * Re-use the full incoming DN for
+ * subtree checks
+ */
+ *ret_dn = dn;
+ } else {
+ /*
+ * Use the string DN from the unpack, so that
+ * we have a case-exact match of the base
+ */
+ *ret_dn = talloc_steal(mem_ctx, msg->dn);
+ }
+ exists = true;
+ } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ exists = false;
+ } else {
+ talloc_free(msg);
+ return ret;
+ }
+ talloc_free(msg);
if (exists) {
return LDB_SUCCESS;
}
@@ -200,25 +235,18 @@ static int ltdb_parse_data_unpack(TDB_DATA key, TDB_DATA data,
return LDB_ERR_NO_SUCH_OBJECT on record-not-found
and LDB_SUCCESS on success
*/
-int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_message *msg,
+int ltdb_search_key(struct ldb_module *module, struct ltdb_private *ltdb,
+ const struct TDB_DATA tdb_key,
+ struct ldb_message *msg,
unsigned int unpack_flags)
{
- void *data = ldb_module_get_private(module);
- struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
int ret;
- TDB_DATA tdb_key;
struct ltdb_parse_data_unpack_ctx ctx = {
.msg = msg,
.module = module,
.unpack_flags = unpack_flags
};
- /* form the key */
- tdb_key = ltdb_key(module, dn);
- if (!tdb_key.dptr) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
memset(msg, 0, sizeof(*msg));
msg->num_elements = 0;
@@ -226,17 +254,92 @@ int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_mes
ret = tdb_parse_record(ltdb->tdb, tdb_key,
ltdb_parse_data_unpack, &ctx);
- talloc_free(tdb_key.dptr);
if (ret == -1) {
- if (tdb_error(ltdb->tdb) == TDB_ERR_NOEXIST) {
- return LDB_ERR_NO_SUCH_OBJECT;
+ ret = ltdb_err_map(tdb_error(ltdb->tdb));
+ if (ret == LDB_SUCCESS) {
+ /*
+ * Just to be sure we don't turn errors
+ * into success
+ */
+ return LDB_ERR_OPERATIONS_ERROR;
}
- return LDB_ERR_OPERATIONS_ERROR;
+ return ret;
} else if (ret != LDB_SUCCESS) {
return ret;
}
+ return LDB_SUCCESS;
+}
+
+/*
+ search the database for a single simple dn, returning all attributes
+ in a single message
+
+ return LDB_ERR_NO_SUCH_OBJECT on record-not-found
+ and LDB_SUCCESS on success
+*/
+int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_message *msg,
+ unsigned int unpack_flags)
+{
+ void *data = ldb_module_get_private(module);
+ struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
+ int ret;
+ uint8_t guid_key[LTDB_GUID_KEY_SIZE];
+ TDB_DATA tdb_key = {
+ .dptr = guid_key,
+ .dsize = sizeof(guid_key)
+ };
+ TALLOC_CTX *tdb_key_ctx = NULL;
+
+ if (ltdb->cache->GUID_index_attribute == NULL) {
+ tdb_key_ctx = talloc_new(msg);
+ if (!tdb_key_ctx) {
+ return ldb_module_oom(module);
+ }
+
+ /* form the key */
+ tdb_key = ltdb_key_dn(module, tdb_key_ctx, dn);
+ if (!tdb_key.dptr) {
+ TALLOC_FREE(tdb_key_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ } else if (ldb_dn_is_special(dn)) {
+ tdb_key_ctx = talloc_new(msg);
+ if (!tdb_key_ctx) {
+ return ldb_module_oom(module);
+ }
+
+ /* form the key */
+ tdb_key = ltdb_key_dn(module, tdb_key_ctx, dn);
+ if (!tdb_key.dptr) {
+ TALLOC_FREE(tdb_key_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ } else {
+ /*
+ * Look in the index to find the key for this DN.
+ *
+ * the tdb_key memory is allocated above, msg is just
+ * used for internal memory.
+ *
+ */
+ ret = ltdb_key_dn_from_idx(module, ltdb,
+ msg,
+ dn, &tdb_key);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ ret = ltdb_search_key(module, ltdb, tdb_key, msg, unpack_flags);
+
+ TALLOC_FREE(tdb_key_ctx);
+
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
if ((unpack_flags & LDB_UNPACK_DATA_FLAG_NO_DN) == 0) {
if (!msg->dn) {
msg->dn = ldb_dn_copy(msg, dn);
@@ -501,6 +604,106 @@ static int ltdb_search_full(struct ltdb_context *ctx)
return ctx->error;
}
+static int ltdb_search_and_return_base(struct ltdb_private *ltdb,
+ struct ltdb_context *ctx)
+{
+ struct ldb_message *msg, *filtered_msg;
+ struct ldb_context *ldb = ldb_module_get_ctx(ctx->module);
+ const char *dn_linearized;
+ const char *msg_dn_linearlized;
+ int ret;
+ bool matched;
+
+ msg = ldb_msg_new(ctx);
+ if (!msg) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = ltdb_search_dn1(ctx->module, ctx->base, msg,
+ LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC|
+ LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC);
+
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ if (ltdb->check_base == false) {
+ /*
+ * In this case, we are done, as no base
+ * checking is allowed in this DB
+ */
+ talloc_free(msg);
+ return LDB_SUCCESS;
+ }
+ ldb_asprintf_errstring(ldb,
+ "No such Base DN: %s",
+ ldb_dn_get_linearized(ctx->base));
+ }
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ return ret;
+ }
+
+
+ /*
+ * We use this, not ldb_match_msg_error() as we know
+ * we matched on the scope BASE, as we just fetched
+ * the base DN
+ */
+
+ ret = ldb_match_message(ldb, msg,
+ ctx->tree,
+ ctx->scope,
+ &matched);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ return ret;
+ }
+ if (!matched) {
+ talloc_free(msg);
+ return LDB_SUCCESS;
+ }
+
+ dn_linearized = ldb_dn_get_linearized(ctx->base);
+ msg_dn_linearlized = ldb_dn_get_linearized(msg->dn);
+
+ if (strcmp(dn_linearized, msg_dn_linearlized) == 0) {
+ /*
+ * If the DN is exactly the same string, then
+ * re-use the full incoming DN for the
+ * returned result, as it has already been
+ * casefolded
+ */
+ msg->dn = ctx->base;
+ }
+
+ /*
+ * filter the attributes that the user wants.
+ *
+ * This copies msg->dn including the casefolding, so the above
+ * assignment is safe
+ */
+ ret = ltdb_filter_attrs(ctx, msg, ctx->attrs, &filtered_msg);
+
+ /*
+ * Remove any extended components possibly copied in from
+ * msg->dn, we just want the casefold components
+ */
+ ldb_dn_remove_extended_components(filtered_msg->dn);
+ talloc_free(msg);
+
+ if (ret == -1) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_module_send_entry(ctx->req, filtered_msg, NULL);
+ if (ret != LDB_SUCCESS) {
+ /* Regardless of success or failure, the msg
+ * is the callbacks responsiblity, and should
+ * not be talloc_free()'ed */
+ ctx->request_terminated = true;
+ return ret;
+ }
+
+ return LDB_SUCCESS;
+}
+
/*
search the database with a LDAP-like expression.
choses a search method
@@ -532,6 +735,11 @@ int ltdb_search(struct ltdb_context *ctx)
return LDB_ERR_OPERATIONS_ERROR;
}
+ ctx->tree = req->op.search.tree;
+ ctx->scope = req->op.search.scope;
+ ctx->base = req->op.search.base;
+ ctx->attrs = req->op.search.attrs;
+
if ((req->op.search.base == NULL) || (ldb_dn_is_null(req->op.search.base) == true)) {
/* Check what we should do with a NULL dn */
@@ -559,9 +767,31 @@ int ltdb_search(struct ltdb_context *ctx)
ldb_dn_get_linearized(req->op.search.base));
ret = LDB_ERR_INVALID_DN_SYNTAX;
+ } else if (req->op.search.scope == LDB_SCOPE_BASE) {
+
+ /*
+ * If we are LDB_SCOPE_BASE, do just one search and
+ * return early. This is critical to ensure we do not
+ * go into the index code for special DNs, as that
+ * will try to look up an index record for a special
+ * record (which doesn't exist).
+ */
+ ret = ltdb_search_and_return_base(ltdb, ctx);
+
+ ltdb_unlock_read(module);
+
+ return ret;
+
} else if (ltdb->check_base) {
- /* This database has been marked as 'checkBaseOnSearch', so do a spot check of the base dn */
- ret = ltdb_search_base(module, req->op.search.base);
+ /*
+ * This database has been marked as
+ * 'checkBaseOnSearch', so do a spot check of the base
+ * dn. Also optimise the subsequent filter by filling
+ * in the ctx->base to be exactly case correct
+ */
+ ret = ltdb_search_base(module, ctx,
+ req->op.search.base,
+ &ctx->base);
if (ret == LDB_ERR_NO_SUCH_OBJECT) {
ldb_asprintf_errstring(ldb,
@@ -574,11 +804,6 @@ int ltdb_search(struct ltdb_context *ctx)
ret = LDB_SUCCESS;
}
- ctx->tree = req->op.search.tree;
- ctx->scope = req->op.search.scope;
- ctx->base = req->op.search.base;
- ctx->attrs = req->op.search.attrs;
-
if (ret == LDB_SUCCESS) {
uint32_t match_count = 0;
diff --git a/ldb_tdb/ldb_tdb.c b/ldb_tdb/ldb_tdb.c
index afa0f9e..16e4b8e 100644
--- a/ldb_tdb/ldb_tdb.c
+++ b/ldb_tdb/ldb_tdb.c
@@ -98,15 +98,26 @@ int ltdb_lock_read(struct ldb_module *module)
{
void *data = ldb_module_get_private(module);
struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
- int ret = 0;
+ int tdb_ret = 0;
+ int ret;
if (ltdb->in_transaction == 0 &&
ltdb->read_lock_count == 0) {
- ret = tdb_lockall_read(ltdb->tdb);
+ tdb_ret = tdb_lockall_read(ltdb->tdb);
}
- if (ret == 0) {
+ if (tdb_ret == 0) {
ltdb->read_lock_count++;
+ return LDB_SUCCESS;
+ }
+ ret = ltdb_err_map(tdb_error(ltdb->tdb));
+ if (ret == LDB_SUCCESS) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
}
+ ldb_debug_set(ldb_module_get_ctx(module),
+ LDB_DEBUG_FATAL,
+ "Failure during ltdb_lock_read(): %s -> %s",
+ tdb_errorstr(ltdb->tdb),
+ ldb_strerror(ret));
return ret;
}
@@ -145,11 +156,12 @@ bool ltdb_key_is_record(TDB_DATA key)
return true;
}
- if (key.dsize < 6) {
+ if (key.dsize < sizeof(LTDB_GUID_KEY_PREFIX)) {
return false;
}
- if (memcmp(key.dptr, "GUID=", 5) == 0) {
+ if (memcmp(key.dptr, LTDB_GUID_KEY_PREFIX,
+ sizeof(LTDB_GUID_KEY_PREFIX) - 1) == 0) {
return true;
}
@@ -163,9 +175,9 @@ bool ltdb_key_is_record(TDB_DATA key)
note that the key for a record can depend on whether the
dn refers to a case sensitive index record or not
*/
-TDB_DATA ltdb_key(struct ldb_module *module, struct ldb_dn *dn)
+TDB_DATA ltdb_key_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn)
{
- struct ldb_context *ldb = ldb_module_get_ctx(module);
TDB_DATA key;
char *key_str = NULL;
const char *dn_folded = NULL;
@@ -187,7 +199,7 @@ TDB_DATA ltdb_key(struct ldb_module *module, struct ldb_dn *dn)
goto failed;
}
- key_str = talloc_strdup(ldb, "DN=");
+ key_str = talloc_strdup(mem_ctx, "DN=");
if (!key_str) {
goto failed;
}
@@ -209,6 +221,121 @@ failed:
return key;
}
+/* The caller is to provide a correctly sized key */
+int ltdb_guid_to_key(struct ldb_module *module,
+ struct ltdb_private *ltdb,
+ const struct ldb_val *GUID_val,
+ TDB_DATA *key)
+{
+ const char *GUID_prefix = LTDB_GUID_KEY_PREFIX;
+ const int GUID_prefix_len = sizeof(LTDB_GUID_KEY_PREFIX) - 1;
+
+ if (key->dsize != (GUID_val->length+GUID_prefix_len)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ memcpy(key->dptr, GUID_prefix, GUID_prefix_len);
+ memcpy(&key->dptr[GUID_prefix_len],
+ GUID_val->data, GUID_val->length);
+ return LDB_SUCCESS;
+}
+
+/*
+ * The caller is to provide a correctly sized key, used only in
+ * the GUID index mode
+ */
+int ltdb_idx_to_key(struct ldb_module *module,
+ struct ltdb_private *ltdb,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_val *idx_val,
+ TDB_DATA *key)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct ldb_dn *dn;
+
+ if (ltdb->cache->GUID_index_attribute != NULL) {
+ return ltdb_guid_to_key(module, ltdb,
+ idx_val, key);
+ }
+
+ dn = ldb_dn_from_ldb_val(mem_ctx, ldb, idx_val);
+ if (dn == NULL) {
+ /*
+ * LDB_ERR_INVALID_DN_SYNTAX would just be confusing
+ * to the caller, as this in an invalid index value
+ */
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ /* form the key */
+ *key = ltdb_key_dn(module, mem_ctx, dn);
+ TALLOC_FREE(dn);
+ if (!key->dptr) {
+ return ldb_module_oom(module);
+ }
+ return LDB_SUCCESS;
+}
+
+/*
+ form a TDB_DATA for a record key
+ caller frees mem_ctx, which may or may not have the key
+ as a child.
+
+ note that the key for a record can depend on whether a
+ GUID index is in use, or the DN is used as the key
+*/
+TDB_DATA ltdb_key_msg(struct ldb_module *module, TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg)
+{
+ void *data = ldb_module_get_private(module);
+ struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
+ TDB_DATA key;
+ const struct ldb_val *guid_val;
+ int ret;
+
+ if (ltdb->cache->GUID_index_attribute == NULL) {
+ return ltdb_key_dn(module, mem_ctx, msg->dn);
+ }
+
+ if (ldb_dn_is_special(msg->dn)) {
+ return ltdb_key_dn(module, mem_ctx, msg->dn);
+ }
+
+ guid_val = ldb_msg_find_ldb_val(msg,
+ ltdb->cache->GUID_index_attribute);
+ if (guid_val == NULL) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ "Did not find GUID attribute %s "
+ "in %s, required for TDB record "
+ "key in " LTDB_IDXGUID " mode.",
+ ltdb->cache->GUID_index_attribute,
+ ldb_dn_get_linearized(msg->dn));
+ errno = EINVAL;
+ key.dptr = NULL;
+ key.dsize = 0;
+ return key;
+ }
+
+ /* In this case, allocate with talloc */
+ key.dptr = talloc_size(mem_ctx, LTDB_GUID_KEY_SIZE);
+ if (key.dptr == NULL) {
+ errno = ENOMEM;
+ key.dptr = NULL;
+ key.dsize = 0;
+ return key;
+ }
+ key.dsize = talloc_get_size(key.dptr);
+
+ ret = ltdb_guid_to_key(module, ltdb, guid_val, &key);
+
+ if (ret != LDB_SUCCESS) {
+ errno = EINVAL;
+ key.dptr = NULL;
+ key.dsize = 0;
+ return key;
+ }
+ return key;
+}
+
/*
check special dn's have valid attributes
currently only @ATTRIBUTES is checked
@@ -296,16 +423,26 @@ int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flg
TDB_DATA tdb_key, tdb_data;
struct ldb_val ldb_data;
int ret = LDB_SUCCESS;
+ TALLOC_CTX *tdb_key_ctx = talloc_new(module);
- tdb_key = ltdb_key(module, msg->dn);
+ if (tdb_key_ctx == NULL) {
+ return ldb_module_oom(module);
+ }
+
+ if (ltdb->read_only) {
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ tdb_key = ltdb_key_msg(module, tdb_key_ctx, msg);
if (tdb_key.dptr == NULL) {
+ TALLOC_FREE(tdb_key_ctx);
return LDB_ERR_OTHER;
}
ret = ldb_pack_data(ldb_module_get_ctx(module),
msg, &ldb_data);
if (ret == -1) {
- talloc_free(tdb_key.dptr);
+ TALLOC_FREE(tdb_key_ctx);
return LDB_ERR_OTHER;
}
@@ -314,12 +451,23 @@ int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flg
ret = tdb_store(ltdb->tdb, tdb_key, tdb_data, flgs);
if (ret != 0) {
+ bool is_special = ldb_dn_is_special(msg->dn);
ret = ltdb_err_map(tdb_error(ltdb->tdb));
+
+ /*
+ * LDB_ERR_ENTRY_ALREADY_EXISTS means the DN, not
+ * the GUID, so re-map
+ */
+ if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS
+ && !is_special
+ && ltdb->cache->GUID_index_attribute != NULL) {
+ ret = LDB_ERR_CONSTRAINT_VIOLATION;
+ }
goto done;
}
done:
- talloc_free(tdb_key.dptr);
+ TALLOC_FREE(tdb_key_ctx);
talloc_free(ldb_data.data);
return ret;
@@ -412,6 +560,24 @@ static int ltdb_add_internal(struct ldb_module *module,
ret = ltdb_store(module, msg, TDB_INSERT);
if (ret != LDB_SUCCESS) {
+ /*
+ * Try really hard to get the right error code for
+ * a re-add situation, as this can matter!
+ */
+ if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
+ int ret2;
+ struct ldb_dn *dn2 = NULL;
+ TALLOC_CTX *mem_ctx = talloc_new(module);
+ if (mem_ctx == NULL) {
+ return ldb_module_operr(module);
+ }
+ ret2 = ltdb_search_base(module, module,
+ msg->dn, &dn2);
+ TALLOC_FREE(mem_ctx);
+ if (ret2 == LDB_SUCCESS) {
+ ret = LDB_ERR_ENTRY_ALREADY_EXISTS;
+ }
+ }
if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
ldb_asprintf_errstring(ldb,
"Entry %s already exists",
@@ -422,6 +588,17 @@ static int ltdb_add_internal(struct ldb_module *module,
ret = ltdb_index_add_new(module, ltdb, msg);
if (ret != LDB_SUCCESS) {
+ /*
+ * If we failed to index, delete the message again.
+ *
+ * This is particularly important for the GUID index
+ * case, which will only fail for a duplicate DN
+ * in the index add.
+ *
+ * Note that the caller may not cancel the transation
+ * and this means the above add might really show up!
+ */
+ ltdb_delete_noindex(module, msg);
return ret;
}
@@ -462,20 +639,31 @@ static int ltdb_add(struct ltdb_context *ctx)
delete a record from the database, not updating indexes (used for deleting
index records)
*/
-int ltdb_delete_noindex(struct ldb_module *module, struct ldb_dn *dn)
+int ltdb_delete_noindex(struct ldb_module *module,
+ const struct ldb_message *msg)
{
void *data = ldb_module_get_private(module);
struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
TDB_DATA tdb_key;
int ret;
+ TALLOC_CTX *tdb_key_ctx = talloc_new(module);
+
+ if (tdb_key_ctx == NULL) {
+ return ldb_module_oom(module);
+ }
- tdb_key = ltdb_key(module, dn);
+ if (ltdb->read_only) {
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ tdb_key = ltdb_key_msg(module, tdb_key_ctx, msg);
if (!tdb_key.dptr) {
+ TALLOC_FREE(tdb_key_ctx);
return LDB_ERR_OTHER;
}
ret = tdb_delete(ltdb->tdb, tdb_key);
- talloc_free(tdb_key.dptr);
+ TALLOC_FREE(tdb_key_ctx);
if (ret != 0) {
ret = ltdb_err_map(tdb_error(ltdb->tdb));
@@ -502,7 +690,7 @@ static int ltdb_delete_internal(struct ldb_module *module, struct ldb_dn *dn)
goto done;
}
- ret = ltdb_delete_noindex(module, dn);
+ ret = ltdb_delete_noindex(module, msg);
if (ret != LDB_SUCCESS) {
goto done;
}
@@ -619,6 +807,17 @@ static int msg_delete_attribute(struct ldb_module *module,
unsigned int i;
int ret;
struct ldb_message_element *el;
+ bool is_special = ldb_dn_is_special(msg->dn);
+
+ if (!is_special
+ && ltdb->cache->GUID_index_attribute != NULL
+ && ldb_attr_cmp(name, ltdb->cache->GUID_index_attribute) == 0) {
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ ldb_asprintf_errstring(ldb, "Must not modify GUID "
+ "attribute %s (used as DB index)",
+ ltdb->cache->GUID_index_attribute);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
el = ldb_msg_find_element(msg, name);
if (el == NULL) {
@@ -626,7 +825,7 @@ static int msg_delete_attribute(struct ldb_module *module,
}
i = el - msg->elements;
- ret = ltdb_index_del_element(module, ltdb, msg->dn, el);
+ ret = ltdb_index_del_element(module, ltdb, msg, el);
if (ret != LDB_SUCCESS) {
return ret;
}
@@ -685,7 +884,7 @@ static int msg_delete_element(struct ldb_module *module,
ltdb, msg, name);
}
- ret = ltdb_index_del_value(module, ltdb, msg->dn, el, i);
+ ret = ltdb_index_del_value(module, ltdb, msg, el, i);
if (ret != LDB_SUCCESS) {
return ret;
}
@@ -810,7 +1009,7 @@ int ltdb_modify_internal(struct ldb_module *module,
goto done;
}
ret = ltdb_index_add_element(module, ltdb,
- msg2->dn,
+ msg2,
el);
if (ret != LDB_SUCCESS) {
goto done;
@@ -892,7 +1091,7 @@ int ltdb_modify_internal(struct ldb_module *module,
el2->num_values += el->num_values;
ret = ltdb_index_add_element(module, ltdb,
- msg2->dn, el);
+ msg2, el);
if (ret != LDB_SUCCESS) {
goto done;
}
@@ -971,7 +1170,7 @@ int ltdb_modify_internal(struct ldb_module *module,
}
ret = ltdb_index_add_element(module, ltdb,
- msg2->dn, el);
+ msg2, el);
if (ret != LDB_SUCCESS) {
goto done;
}
@@ -1086,6 +1285,7 @@ static int ltdb_rename(struct ltdb_context *ctx)
struct ldb_message *msg;
int ret = LDB_SUCCESS;
TDB_DATA tdb_key, tdb_key_old;
+ struct ldb_dn *db_dn;
ldb_request_set_state(req, LDB_ASYNC_PENDING);
@@ -1108,33 +1308,54 @@ static int ltdb_rename(struct ltdb_context *ctx)
/* We need to, before changing the DB, check if the new DN
* exists, so we can return this error to the caller with an
- * unmodified DB */
- tdb_key = ltdb_key(module, req->op.rename.newdn);
+ * unmodified DB
+ *
+ * Even in GUID index mode we use ltdb_key_dn() as we are
+ * trying to figure out if this is just a case rename
+ */
+ tdb_key = ltdb_key_dn(module, msg, req->op.rename.newdn);
if (!tdb_key.dptr) {
talloc_free(msg);
return LDB_ERR_OPERATIONS_ERROR;
}
- tdb_key_old = ltdb_key(module, req->op.rename.olddn);
+ tdb_key_old = ltdb_key_dn(module, msg, req->op.rename.olddn);
if (!tdb_key_old.dptr) {
talloc_free(msg);
talloc_free(tdb_key.dptr);
return LDB_ERR_OPERATIONS_ERROR;
}
- /* Only declare a conflict if the new DN already exists, and it isn't a case change on the old DN */
- if (tdb_key_old.dsize != tdb_key.dsize || memcmp(tdb_key.dptr, tdb_key_old.dptr, tdb_key.dsize) != 0) {
- if (tdb_exists(ltdb->tdb, tdb_key)) {
- talloc_free(tdb_key_old.dptr);
- talloc_free(tdb_key.dptr);
- ldb_asprintf_errstring(ldb_module_get_ctx(module),
- "Entry %s already exists",
- ldb_dn_get_linearized(req->op.rename.newdn));
- /* finding the new record already in the DB is an error */
- talloc_free(msg);
- return LDB_ERR_ENTRY_ALREADY_EXISTS;
+ /*
+ * Only declare a conflict if the new DN already exists,
+ * and it isn't a case change on the old DN
+ */
+ if (tdb_key_old.dsize != tdb_key.dsize
+ || memcmp(tdb_key.dptr, tdb_key_old.dptr, tdb_key.dsize) != 0) {
+ ret = ltdb_search_base(module, msg,
+ req->op.rename.newdn,
+ &db_dn);
+ if (ret == LDB_SUCCESS) {
+ ret = LDB_ERR_ENTRY_ALREADY_EXISTS;
+ } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ ret = LDB_SUCCESS;
}
}
+
+ /* finding the new record already in the DB is an error */
+
+ if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ "Entry %s already exists",
+ ldb_dn_get_linearized(req->op.rename.newdn));
+ }
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tdb_key_old.dptr);
+ talloc_free(tdb_key.dptr);
+ talloc_free(msg);
+ return ret;
+ }
+
talloc_free(tdb_key_old.dptr);
talloc_free(tdb_key.dptr);
@@ -1170,6 +1391,11 @@ static int ltdb_start_trans(struct ldb_module *module)
void *data = ldb_module_get_private(module);
struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
+ /* Do not take out the transaction lock on a read-only DB */
+ if (ltdb->read_only) {
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
if (tdb_transaction_start(ltdb->tdb) != 0) {
return ltdb_err_map(tdb_error(ltdb->tdb));
}
@@ -1201,10 +1427,12 @@ static int ltdb_prepare_commit(struct ldb_module *module)
if (tdb_transaction_prepare_commit(ltdb->tdb) != 0) {
ret = ltdb_err_map(tdb_error(ltdb->tdb));
ltdb->in_transaction--;
- ldb_asprintf_errstring(ldb_module_get_ctx(module),
- "Failure during tdb_transaction_prepare_commit(): %s -> %s",
- tdb_errorstr(ltdb->tdb),
- ldb_strerror(ret));
+ ldb_debug_set(ldb_module_get_ctx(module),
+ LDB_DEBUG_FATAL,
+ "Failure during "
+ "tdb_transaction_prepare_commit(): %s -> %s",
+ tdb_errorstr(ltdb->tdb),
+ ldb_strerror(ret));
return ret;
}
@@ -1651,20 +1879,36 @@ static int ltdb_connect(struct ldb_context *ldb, const char *url,
tdb_flags |= TDB_NOMMAP;
}
+ ltdb = talloc_zero(ldb, struct ltdb_private);
+ if (!ltdb) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
if (flags & LDB_FLG_RDONLY) {
- open_flags = O_RDONLY;
+ /*
+ * This is weird, but because we can only have one tdb
+ * in this process, and the other one could be
+ * read-write, we can't use the tdb readonly. Plus a
+ * read only tdb prohibits the all-record lock.
+ */
+ open_flags = O_RDWR;
+
+ ltdb->read_only = true;
+
} else if (flags & LDB_FLG_DONT_CREATE_DB) {
+ /*
+ * This is used by ldbsearch to prevent creation of the database
+ * if the name is wrong
+ */
open_flags = O_RDWR;
} else {
+ /*
+ * This is the normal case
+ */
open_flags = O_CREAT | O_RDWR;
}
- ltdb = talloc_zero(ldb, struct ltdb_private);
- if (!ltdb) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
/* note that we use quite a large default hash size */
ltdb->tdb = ltdb_wrap_open(ltdb, path, 10000,
tdb_flags, open_flags,
diff --git a/ldb_tdb/ldb_tdb.h b/ldb_tdb/ldb_tdb.h
index 7871cbc..7e18249 100644
--- a/ldb_tdb/ldb_tdb.h
+++ b/ldb_tdb/ldb_tdb.h
@@ -20,6 +20,8 @@ struct ltdb_private {
struct ldb_message *indexlist;
bool one_level_indexes;
bool attribute_indexes;
+ const char *GUID_index_attribute;
+ const char *GUID_index_dn_component;
} *cache;
int in_transaction;
@@ -32,6 +34,10 @@ struct ltdb_private {
bool warn_unindexed;
bool warn_reindex;
+
+ bool read_only;
+
+ const struct ldb_schema_syntax *GUID_index_syntax;
};
struct ltdb_context {
@@ -59,6 +65,9 @@ struct ltdb_context {
#define LTDB_IDXVERSION "@IDXVERSION"
#define LTDB_IDXATTR "@IDXATTR"
#define LTDB_IDXONE "@IDXONE"
+#define LTDB_IDXDN "@IDXDN"
+#define LTDB_IDXGUID "@IDXGUID"
+#define LTDB_IDX_DN_GUID "@IDX_DN_GUID"
#define LTDB_BASEINFO "@BASEINFO"
#define LTDB_OPTIONS "@OPTIONS"
#define LTDB_ATTRIBUTES "@ATTRIBUTES"
@@ -70,6 +79,11 @@ struct ltdb_context {
#define LTDB_MOD_TIMESTAMP "whenChanged"
#define LTDB_OBJECTCLASS "objectClass"
+/* DB keys */
+#define LTDB_GUID_KEY_PREFIX "GUID="
+#define LTDB_GUID_SIZE 16
+#define LTDB_GUID_KEY_SIZE (LTDB_GUID_SIZE + sizeof(LTDB_GUID_KEY_PREFIX) - 1)
+
/* The following definitions come from lib/ldb/ldb_tdb/ldb_cache.c */
int ltdb_cache_reload(struct ldb_module *module);
@@ -88,20 +102,25 @@ int ltdb_index_add_new(struct ldb_module *module,
int ltdb_index_delete(struct ldb_module *module, const struct ldb_message *msg);
int ltdb_index_del_element(struct ldb_module *module,
struct ltdb_private *ltdb,
- struct ldb_dn *dn,
+ const struct ldb_message *msg,
struct ldb_message_element *el);
int ltdb_index_add_element(struct ldb_module *module,
struct ltdb_private *ltdb,
- struct ldb_dn *dn,
+ const struct ldb_message *msg,
struct ldb_message_element *el);
int ltdb_index_del_value(struct ldb_module *module,
struct ltdb_private *ltdb,
- struct ldb_dn *dn,
+ const struct ldb_message *msg,
struct ldb_message_element *el, unsigned int v_idx);
int ltdb_reindex(struct ldb_module *module);
int ltdb_index_transaction_start(struct ldb_module *module);
int ltdb_index_transaction_commit(struct ldb_module *module);
int ltdb_index_transaction_cancel(struct ldb_module *module);
+int ltdb_key_dn_from_idx(struct ldb_module *module,
+ struct ltdb_private *ltdb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn,
+ TDB_DATA *tdb_key);
/* The following definitions come from lib/ldb/ldb_tdb/ldb_search.c */
@@ -110,6 +129,14 @@ int ltdb_has_wildcard(struct ldb_module *module, const char *attr_name,
void ltdb_search_dn1_free(struct ldb_module *module, struct ldb_message *msg);
int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_message *msg,
unsigned int unpack_flags);
+int ltdb_search_base(struct ldb_module *module,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn,
+ struct ldb_dn **ret_dn);
+int ltdb_search_key(struct ldb_module *module, struct ltdb_private *ltdb,
+ struct TDB_DATA tdb_key,
+ struct ldb_message *msg,
+ unsigned int unpack_flags);
int ltdb_filter_attrs(TALLOC_CTX *mem_ctx,
const struct ldb_message *msg, const char * const *attrs,
struct ldb_message **filtered_msg);
@@ -123,10 +150,23 @@ int ltdb_unlock_read(struct ldb_module *module);
* index, the old DN index and a possible future ID=
*/
bool ltdb_key_is_record(TDB_DATA key);
-TDB_DATA ltdb_key(struct ldb_module *module, struct ldb_dn *dn);
+TDB_DATA ltdb_key_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn);
+TDB_DATA ltdb_key_msg(struct ldb_module *module, TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg);
+int ltdb_guid_to_key(struct ldb_module *module,
+ struct ltdb_private *ltdb,
+ const struct ldb_val *GUID_val,
+ TDB_DATA *key);
+int ltdb_idx_to_key(struct ldb_module *module,
+ struct ltdb_private *ltdb,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_val *idx_val,
+ TDB_DATA *key);
int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flgs);
int ltdb_modify_internal(struct ldb_module *module, const struct ldb_message *msg, struct ldb_request *req);
-int ltdb_delete_noindex(struct ldb_module *module, struct ldb_dn *dn);
+int ltdb_delete_noindex(struct ldb_module *module,
+ const struct ldb_message *msg);
int ltdb_err_map(enum TDB_ERROR tdb_code);
struct tdb_context *ltdb_wrap_open(TALLOC_CTX *mem_ctx,
diff --git a/lib/replace/replace.c b/lib/replace/replace.c
index 9351b6c..dc81e9c 100644
--- a/lib/replace/replace.c
+++ b/lib/replace/replace.c
@@ -942,3 +942,8 @@ void rep_setproctitle(const char *fmt, ...)
{
}
#endif
+#ifndef HAVE_SETPROCTITLE_INIT
+void rep_setproctitle_init(int argc, char *argv[], char *envp[])
+{
+}
+#endif
diff --git a/lib/replace/replace.h b/lib/replace/replace.h
index a41e9f8..128978c 100644
--- a/lib/replace/replace.h
+++ b/lib/replace/replace.h
@@ -918,6 +918,10 @@ int usleep(useconds_t);
void rep_setproctitle(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
#endif
+#ifndef HAVE_SETPROCTITLE_INIT
+#define setproctitle_init rep_setproctitle_init
+void rep_setproctitle_init(int argc, char *argv[], char *envp[]);
+#endif
bool nss_wrapper_enabled(void);
bool nss_wrapper_hosts_enabled(void);
bool socket_wrapper_enabled(void);
diff --git a/lib/replace/system/nis.h b/lib/replace/system/nis.h
new file mode 100644
index 0000000..068595a
--- /dev/null
+++ b/lib/replace/system/nis.h
@@ -0,0 +1,83 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ nis system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** 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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _nis_passwd_h
+#define _nis_passwd_h
+
+#if defined(HAVE_RPC_RPC_H)
+/*
+ * Check for AUTH_ERROR define conflict with rpc/rpc.h in prot.h.
+ */
+#if defined(HAVE_SYS_SECURITY_H) && defined(HAVE_RPC_AUTH_ERROR_CONFLICT)
+#undef AUTH_ERROR
+#endif /* HAVE_SYS_SECURITY_H && HAVE_RPC_AUTH_ERROR_CONFLICT */
+/*
+ * HP-UX 11.X has TCP_NODELAY and TCP_MAXSEG defined in <netinet/tcp.h> which
+ * was included above. However <rpc/rpc.h> includes <sys/xti.h> which defines
+ * them again without checking if they already exsist. This generates
+ * two "Redefinition of macro" warnings for every single .c file that is
+ * compiled.
+ */
+#if defined(HPUX) && defined(TCP_NODELAY)
+#undef TCP_NODELAY
+#endif /* HPUX && TCP_NODELAY */
+
+#if defined(HPUX) && defined(TCP_MAXSEG)
+#undef TCP_MAXSEG
+#endif /* HPUX && TCP_MAXSEG */
+
+#include <rpc/rpc.h>
+#endif /* HAVE_RPC_RPC_H */
+
+
+#if defined (HAVE_NETGROUP)
+
+#if defined(HAVE_RPCSVC_YP_PROT_H)
+/*
+ * HP-UX 11.X has TCP_NODELAY and TCP_MAXSEG defined in <netinet/tcp.h> which
+ * was included above. However <rpc/rpc.h> includes <sys/xti.h> which defines
+ * them again without checking if they already exsist. This generates
+ * two "Redefinition of macro" warnings for every single .c file that is
+ * compiled.
+ */
+#if defined(HPUX) && defined(TCP_NODELAY)
+#undef TCP_NODELAY
+#endif /* HPUX && TCP_MAXSEG */
+
+#if defined(HPUX) && defined(TCP_MAXSEG)
+#undef TCP_MAXSEG
+#endif /* HPUX && TCP_MAXSEG */
+
+#include <rpcsvc/yp_prot.h>
+
+#endif /* HAVE_RPCSVC_YP_PROT_H */
+
+#if defined(HAVE_RPCSVC_YPCLNT_H)
+#include <rpcsvc/ypclnt.h>
+#endif /* HAVE_RPCSVC_YPCLNT_H */
+
+#endif /* HAVE_NETGROUP */
+
+#endif /* _nis_passwd_h */
diff --git a/lib/replace/system/readline.h b/lib/replace/system/readline.h
index e6b8fb9..5dc3e75 100644
--- a/lib/replace/system/readline.h
+++ b/lib/replace/system/readline.h
@@ -26,6 +26,9 @@
#ifdef HAVE_LIBREADLINE
# ifdef HAVE_READLINE_READLINE_H
+# ifdef HAVE_READLINE_READLINE_WORKAROUND
+# define _FUNCTION_DEF
+# endif
# include <readline/readline.h>
# ifdef HAVE_READLINE_HISTORY_H
# include <readline/history.h>
diff --git a/lib/replace/system/wscript_configure b/lib/replace/system/wscript_configure
index 2035474..ecd9964 100644
--- a/lib/replace/system/wscript_configure
+++ b/lib/replace/system/wscript_configure
@@ -1,8 +1,5 @@
#!/usr/bin/env python
-conf.CHECK_HEADERS('sys/capability.h')
-conf.CHECK_FUNCS('getpwnam_r getpwuid_r getpwent_r')
-
# solaris varients of getXXent_r
conf.CHECK_C_PROTOTYPE('getpwent_r',
'struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)',
@@ -19,8 +16,3 @@ conf.CHECK_C_PROTOTYPE('getgrent_r',
'struct group *getgrent_r(struct group *src, char *buf, size_t buflen)',
define='SOLARIS_GETGRENT_R', headers='grp.h')
-conf.CHECK_FUNCS('getgrouplist')
-conf.CHECK_HEADERS('ctype.h locale.h langinfo.h')
-conf.CHECK_HEADERS('fnmatch.h locale.h langinfo.h')
-conf.CHECK_HEADERS('sys/ipc.h sys/mman.h sys/shm.h')
-conf.CHECK_HEADERS('termios.h termio.h sys/termio.h')
diff --git a/lib/replace/wscript b/lib/replace/wscript
index 7357eea..a2e2d11 100644
--- a/lib/replace/wscript
+++ b/lib/replace/wscript
@@ -5,7 +5,7 @@ VERSION = '1.2.1'
blddir = 'bin'
-import sys, os
+import Logs, sys, os
# find the buildtools directory
srcdir = '.'
@@ -65,14 +65,41 @@ def configure(conf):
headers='sys/inotify.h')
conf.CHECK_HEADERS('security/pam_appl.h zlib.h asm/unistd.h')
- conf.CHECK_HEADERS('aio.h sys/unistd.h rpc/rpc.h rpc/nettype.h alloca.h float.h')
+ conf.CHECK_HEADERS('aio.h sys/unistd.h alloca.h float.h')
+
+ conf.SET_TARGET_TYPE('tirpc', 'EMPTY')
+ conf.CHECK_HEADERS('rpc/rpc.h rpc/nettype.h')
+ if not conf.CONFIG_SET('HAVE_RPC_RPC_H'):
+ if conf.CHECK_CFG(package='libtirpc', args='--cflags --libs',
+ msg='Checking for libtirpc headers',
+ uselib_store='TIRPC'):
+ conf.CHECK_HEADERS('rpc/rpc.h rpc/nettype.h', lib='tirpc', together=True)
+ conf.SET_TARGET_TYPE('tirpc', 'SYSLIB')
+ if not conf.CONFIG_SET('HAVE_RPC_RPC_H'):
+ if conf.CHECK_CFG(package='libntirpc', args='--cflags',
+ msg='Checking for libntirpc headers',
+ uselib_store='TIRPC'):
+ conf.CHECK_HEADERS('rpc/rpc.h rpc/nettype.h', lib='tirpc', together=True)
+ conf.SET_TARGET_TYPE('tirpc', 'SYSLIB')
+ if not conf.CONFIG_SET('HAVE_RPC_RPC_H'):
+ Logs.warn('No rpc/rpc.h header found, tirpc or libntirpc missing?')
+
+ conf.SET_TARGET_TYPE('nsl', 'EMPTY')
+ conf.CHECK_HEADERS('rpc/rpc.h rpcsvc/yp_prot.h', lib='tirpc')
+ if not conf.CONFIG_SET('HAVE_RPCSVC_YP_PROT_H'):
+ if conf.CHECK_CFG(package='libnsl', args='--cflags --libs',
+ msg='Checking for libnsl',
+ uselib_store='NSL'):
+ conf.SET_TARGET_TYPE('nsl', 'SYSLIB')
+ conf.CHECK_HEADERS('rpc/rpc.h rpcsvc/yp_prot.h', lib='tirpc nsl')
+ else:
+ conf.SET_TARGET_TYPE('nsl', 'SYSLIB')
+ conf.CHECK_HEADERS('rpcsvc/nis.h rpcsvc/ypclnt.h', lib='tirpc nsl')
- conf.CHECK_HEADERS('rpcsvc/nis.h rpcsvc/ypclnt.h sys/sysctl.h')
+ conf.CHECK_HEADERS('sys/sysctl.h')
conf.CHECK_HEADERS('sys/fileio.h sys/filesys.h sys/dustat.h sys/sysmacros.h')
conf.CHECK_HEADERS('xfs/libxfs.h netgroup.h')
- conf.CHECK_CODE('', headers='rpc/rpc.h rpcsvc/yp_prot.h', define='HAVE_RPCSVC_YP_PROT_H')
-
conf.CHECK_HEADERS('valgrind.h valgrind/valgrind.h valgrind/memcheck.h')
conf.CHECK_HEADERS('nss_common.h nsswitch.h ns_api.h')
conf.CHECK_HEADERS('sys/extattr.h sys/ea.h sys/proplist.h sys/cdefs.h')
@@ -84,6 +111,9 @@ def configure(conf):
if conf.CHECK_CFLAGS('-Wno-format-truncation'):
conf.define('HAVE_WNO_FORMAT_TRUNCATION', '1')
+ if conf.CHECK_CFLAGS('-Wno-unused-function'):
+ conf.define('HAVE_WNO_UNUSED_FUNCTION', '1')
+
# Check for process set name support
conf.CHECK_CODE('''
#include <sys/prctl.h>
@@ -249,6 +279,18 @@ def configure(conf):
if conf.CONFIG_SET('HAVE_MEMALIGN'):
conf.CHECK_DECLS('memalign', headers='malloc.h')
+ # glibc up to 2.3.6 had dangerously broken posix_fallocate(). DON'T USE IT.
+ if conf.CHECK_CODE('''
+#define _XOPEN_SOURCE 600
+#include <stdlib.h>
+#if defined(__GLIBC__) && ((__GLIBC__ < 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 4))
+#error probably broken posix_fallocate
+#endif
+''',
+ '_POSIX_FALLOCATE_CAPABLE_LIBC',
+ msg='Checking for posix_fallocate-capable libc'):
+ conf.CHECK_FUNCS('posix_fallocate')
+
conf.CHECK_FUNCS('prctl dirname basename')
strlcpy_in_bsd = False
@@ -262,6 +304,8 @@ def configure(conf):
conf.CHECK_FUNCS_IN('getpeereid', 'bsd', headers='sys/types.h bsd/unistd.h')
if not conf.CHECK_FUNCS_IN('setproctitle', 'setproctitle', headers='setproctitle.h'):
conf.CHECK_FUNCS_IN('setproctitle', 'bsd', headers='sys/types.h bsd/unistd.h')
+ if not conf.CHECK_FUNCS('setproctitle_init'):
+ conf.CHECK_FUNCS_IN('setproctitle_init', 'bsd', headers='sys/types.h bsd/unistd.h')
if not conf.CHECK_FUNCS('closefrom'):
conf.CHECK_FUNCS_IN('closefrom', 'bsd', headers='bsd/unistd.h')
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.10.sigs b/lib/talloc/ABI/pytalloc-util-2.1.10.sigs
new file mode 100644
index 0000000..9d4d4d1
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.10.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.11.sigs b/lib/talloc/ABI/pytalloc-util-2.1.11.sigs
new file mode 100644
index 0000000..9d4d4d1
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.11.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util.py3-2.1.10.sigs b/lib/talloc/ABI/pytalloc-util.py3-2.1.10.sigs
new file mode 100644
index 0000000..62f066f
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util.py3-2.1.10.sigs
@@ -0,0 +1,15 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util.py3-2.1.11.sigs b/lib/talloc/ABI/pytalloc-util.py3-2.1.11.sigs
new file mode 100644
index 0000000..62f066f
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util.py3-2.1.11.sigs
@@ -0,0 +1,15 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/talloc-2.1.10.sigs b/lib/talloc/ABI/talloc-2.1.10.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.10.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.11.sigs b/lib/talloc/ABI/talloc-2.1.11.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.11.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 7721fa4..cd159ef 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -75,12 +75,13 @@
#define TALLOC_MAGIC_REFERENCE ((const char *)1)
#define TALLOC_MAGIC_BASE 0xe814ec70
-static unsigned int talloc_magic = (
- ~TALLOC_FLAG_MASK & (
- TALLOC_MAGIC_BASE +
- (TALLOC_BUILD_VERSION_MAJOR << 24) +
- (TALLOC_BUILD_VERSION_MINOR << 16) +
- (TALLOC_BUILD_VERSION_RELEASE << 8)));
+#define TALLOC_MAGIC_NON_RANDOM ( \
+ ~TALLOC_FLAG_MASK & ( \
+ TALLOC_MAGIC_BASE + \
+ (TALLOC_BUILD_VERSION_MAJOR << 24) + \
+ (TALLOC_BUILD_VERSION_MINOR << 16) + \
+ (TALLOC_BUILD_VERSION_RELEASE << 8)))
+static unsigned int talloc_magic = TALLOC_MAGIC_NON_RANDOM;
/* by default we abort when given a bad pointer (such as when talloc_free() is called
on a pointer that came from malloc() */
@@ -332,6 +333,48 @@ _PUBLIC_ int talloc_test_get_magic(void)
return talloc_magic;
}
+static inline void _talloc_chunk_set_free(struct talloc_chunk *tc,
+ const char *location)
+{
+ /*
+ * Mark this memory as free, and also over-stamp the talloc
+ * magic with the old-style magic.
+ *
+ * Why? This tries to avoid a memory read use-after-free from
+ * disclosing our talloc magic, which would then allow an
+ * attacker to prepare a valid header and so run a destructor.
+ *
+ */
+ tc->flags = TALLOC_MAGIC_NON_RANDOM | TALLOC_FLAG_FREE
+ | (tc->flags & TALLOC_FLAG_MASK);
+
+ /* we mark the freed memory with where we called the free
+ * from. This means on a double free error we can report where
+ * the first free came from
+ */
+ if (location) {
+ tc->name = location;
+ }
+}
+
+static inline void _talloc_chunk_set_not_free(struct talloc_chunk *tc)
+{
+ /*
+ * Mark this memory as not free.
+ *
+ * Why? This is memory either in a pool (and so available for
+ * talloc's re-use or after the realloc(). We need to mark
+ * the memory as free() before any realloc() call as we can't
+ * write to the memory after that.
+ *
+ * We put back the normal magic instead of the 'not random'
+ * magic.
+ */
+
+ tc->flags = talloc_magic |
+ ((tc->flags & TALLOC_FLAG_MASK) & ~TALLOC_FLAG_FREE);
+}
+
static void (*talloc_log_fn)(const char *message);
_PUBLIC_ void talloc_set_log_fn(void (*log_fn)(const char *message))
@@ -429,11 +472,6 @@ static void talloc_abort(const char *reason)
talloc_abort_fn(reason);
}
-static void talloc_abort_magic(unsigned magic)
-{
- talloc_abort("Bad talloc magic value - wrong talloc version used/mixed");
-}
-
static void talloc_abort_access_after_free(void)
{
talloc_abort("Bad talloc magic value - access after free");
@@ -450,19 +488,15 @@ static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
const char *pp = (const char *)ptr;
struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE);
if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~TALLOC_FLAG_MASK)) != talloc_magic)) {
- if ((tc->flags & (~TALLOC_FLAG_MASK)) == talloc_magic) {
- talloc_abort_magic(tc->flags & (~TALLOC_FLAG_MASK));
- return NULL;
- }
-
- if (tc->flags & TALLOC_FLAG_FREE) {
+ if ((tc->flags & (TALLOC_FLAG_FREE | ~TALLOC_FLAG_MASK))
+ == (TALLOC_MAGIC_NON_RANDOM | TALLOC_FLAG_FREE)) {
talloc_log("talloc: access after free error - first free may be at %s\n", tc->name);
talloc_abort_access_after_free();
return NULL;
- } else {
- talloc_abort_unknown_value();
- return NULL;
}
+
+ talloc_abort_unknown_value();
+ return NULL;
}
return tc;
}
@@ -947,13 +981,7 @@ static inline void _tc_free_poolmem(struct talloc_chunk *tc,
pool_tc = talloc_chunk_from_pool(pool);
next_tc = tc_next_chunk(tc);
- tc->flags |= TALLOC_FLAG_FREE;
-
- /* we mark the freed memory with where we called the free
- * from. This means on a double free error we can report where
- * the first free came from
- */
- tc->name = location;
+ _talloc_chunk_set_free(tc, location);
TC_INVALIDATE_FULL_CHUNK(tc);
@@ -1103,13 +1131,7 @@ static inline int _tc_free_internal(struct talloc_chunk *tc,
_tc_free_children_internal(tc, ptr, location);
- tc->flags |= TALLOC_FLAG_FREE;
-
- /* we mark the freed memory with where we called the free
- * from. This means on a double free error we can report where
- * the first free came from
- */
- tc->name = location;
+ _talloc_chunk_set_free(tc, location);
if (tc->flags & TALLOC_FLAG_POOL) {
struct talloc_pool_hdr *pool;
@@ -1806,8 +1828,22 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
}
#endif
- /* by resetting magic we catch users of the old memory */
- tc->flags |= TALLOC_FLAG_FREE;
+ /*
+ * by resetting magic we catch users of the old memory
+ *
+ * We mark this memory as free, and also over-stamp the talloc
+ * magic with the old-style magic.
+ *
+ * Why? This tries to avoid a memory read use-after-free from
+ * disclosing our talloc magic, which would then allow an
+ * attacker to prepare a valid header and so run a destructor.
+ *
+ * What else? We have to re-stamp back a valid normal magic
+ * on this memory once realloc() is done, as it will have done
+ * a memcpy() into the new valid memory. We can't do this in
+ * reverse as that would be a real use-after-free.
+ */
+ _talloc_chunk_set_free(tc, NULL);
#if ALWAYS_REALLOC
if (pool_hdr) {
@@ -1906,7 +1942,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
if (new_chunk_size == old_chunk_size) {
TC_UNDEFINE_GROW_CHUNK(tc, size);
- tc->flags &= ~TALLOC_FLAG_FREE;
+ _talloc_chunk_set_not_free(tc);
tc->size = size;
return ptr;
}
@@ -1921,7 +1957,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
if (space_left >= space_needed) {
TC_UNDEFINE_GROW_CHUNK(tc, size);
- tc->flags &= ~TALLOC_FLAG_FREE;
+ _talloc_chunk_set_not_free(tc);
tc->size = size;
pool_hdr->end = tc_next_chunk(tc);
return ptr;
@@ -1951,12 +1987,24 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
got_new_ptr:
#endif
if (unlikely(!new_ptr)) {
- tc->flags &= ~TALLOC_FLAG_FREE;
+ /*
+ * Ok, this is a strange spot. We have to put back
+ * the old talloc_magic and any flags, except the
+ * TALLOC_FLAG_FREE as this was not free'ed by the
+ * realloc() call after all
+ */
+ _talloc_chunk_set_not_free(tc);
return NULL;
}
+ /*
+ * tc is now the new value from realloc(), the old memory we
+ * can't access any more and was preemptively marked as
+ * TALLOC_FLAG_FREE before the call. Now we mark it as not
+ * free again
+ */
tc = (struct talloc_chunk *)new_ptr;
- tc->flags &= ~TALLOC_FLAG_FREE;
+ _talloc_chunk_set_not_free(tc);
if (malloced) {
tc->flags &= ~TALLOC_FLAG_POOLMEM;
}
diff --git a/lib/talloc/talloc.h b/lib/talloc/talloc.h
index 618430a..dda308d 100644
--- a/lib/talloc/talloc.h
+++ b/lib/talloc/talloc.h
@@ -1226,7 +1226,7 @@ size_t talloc_array_length(const void *ctx);
*
* @code
* ptr = talloc_array(ctx, type, count);
- * if (ptr) memset(ptr, sizeof(type) * count);
+ * if (ptr) memset(ptr, 0, sizeof(type) * count);
* @endcode
*/
void *talloc_zero_array(const void *ctx, #type, unsigned count);
diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c
index dfaeec1..35309e2 100644
--- a/lib/talloc/testsuite.c
+++ b/lib/talloc/testsuite.c
@@ -2006,6 +2006,72 @@ static bool test_magic_protection(void)
return true;
}
+static void test_magic_free_protection_abort(const char *reason)
+{
+ /* exit with errcode 42 to communicate successful test to the parent process */
+ if (strcmp(reason, "Bad talloc magic value - access after free") == 0) {
+ _exit(42);
+ }
+ /* not 42 */
+ _exit(404);
+}
+
+static bool test_magic_free_protection(void)
+{
+ void *pool = talloc_pool(NULL, 1024);
+ int *p1, *p2, *p3;
+ pid_t pid;
+ int exit_status;
+
+ printf("test: magic_free_protection\n");
+ p1 = talloc(pool, int);
+ p2 = talloc(pool, int);
+
+ /* To avoid complaints from the compiler assign values to the p1 & p2. */
+ *p1 = 6;
+ *p2 = 9;
+
+ p3 = talloc_realloc(pool, p2, int, 2048);
+ torture_assert("pool realloc 2048",
+ p3 != p2,
+ "failed: pointer not changed");
+
+ /*
+ * Now access the memory in the pool after the realloc(). It
+ * should be marked as free, so use of the old pointer should
+ * trigger the abort function
+ */
+ pid = fork();
+ if (pid == 0) {
+ talloc_set_abort_fn(test_magic_free_protection_abort);
+
+ talloc_get_name(p2);
+
+ /* Never reached. Make compilers happy */
+ return true;
+ }
+
+ while (wait(&exit_status) != pid);
+
+ if (!WIFEXITED(exit_status)) {
+ printf("Child exited through unexpected abnormal means\n");
+ return false;
+ }
+ if (WEXITSTATUS(exit_status) != 42) {
+ printf("Child exited with wrong exit status\n");
+ return false;
+ }
+ if (WIFSIGNALED(exit_status)) {
+ printf("Child recieved unexpected signal\n");
+ return false;
+ }
+
+ talloc_free(pool);
+
+ printf("success: magic_free_protection\n");
+ return true;
+}
+
static void test_reset(void)
{
talloc_set_log_fn(test_log_stdout);
@@ -2092,6 +2158,8 @@ bool torture_local_talloc(struct torture_context *tctx)
ret &= test_autofree();
test_reset();
ret &= test_magic_protection();
+ test_reset();
+ ret &= test_magic_free_protection();
test_reset();
talloc_disable_null_tracking();
diff --git a/lib/talloc/wscript b/lib/talloc/wscript
index df7e6be..0afa162 100644
--- a/lib/talloc/wscript
+++ b/lib/talloc/wscript
@@ -1,7 +1,7 @@
#!/usr/bin/env python
APPNAME = 'talloc'
-VERSION = '2.1.9'
+VERSION = '2.1.11'
blddir = 'bin'
@@ -74,19 +74,22 @@ def configure(conf):
implied_deps='replace'):
conf.define('USING_SYSTEM_TALLOC', 1)
- using_system_pytalloc_util = True
- if not conf.CHECK_BUNDLED_SYSTEM_PKG('pytalloc-util', minversion=VERSION,
- implied_deps='talloc replace'):
+ if conf.env.disable_python:
using_system_pytalloc_util = False
-
- # We need to get a pytalloc-util for all the python versions
- # we are building for
- if conf.env['EXTRA_PYTHON']:
- name = 'pytalloc-util' + conf.all_envs['extrapython']['PYTHON_SO_ABI_FLAG']
- if not conf.CHECK_BUNDLED_SYSTEM_PKG(name, minversion=VERSION,
+ else:
+ using_system_pytalloc_util = True
+ if not conf.CHECK_BUNDLED_SYSTEM_PKG('pytalloc-util', minversion=VERSION,
implied_deps='talloc replace'):
using_system_pytalloc_util = False
+ # We need to get a pytalloc-util for all the python versions
+ # we are building for
+ if conf.env['EXTRA_PYTHON']:
+ name = 'pytalloc-util' + conf.all_envs['extrapython']['PYTHON_SO_ABI_FLAG']
+ if not conf.CHECK_BUNDLED_SYSTEM_PKG(name, minversion=VERSION,
+ implied_deps='talloc replace'):
+ using_system_pytalloc_util = False
+
if using_system_pytalloc_util:
conf.define('USING_SYSTEM_PYTALLOC_UTIL', 1)
@@ -171,12 +174,18 @@ def build(bld):
def test(ctx):
'''run talloc testsuite'''
import Utils, samba_utils
+
+ samba_utils.ADD_LD_LIBRARY_PATH('bin/shared')
+ samba_utils.ADD_LD_LIBRARY_PATH('bin/shared/private')
+
cmd = os.path.join(Utils.g_module.blddir, 'talloc_testsuite')
ret = samba_utils.RUN_COMMAND(cmd)
print("testsuite returned %d" % ret)
magic_helper_cmd = os.path.join(Utils.g_module.blddir, 'talloc_test_magic_differs_helper')
magic_cmd = os.path.join(srcdir, 'lib', 'talloc',
'test_magic_differs.sh')
+ if not os.path.exists(magic_cmd):
+ magic_cmd = os.path.join(srcdir, 'test_magic_differs.sh')
magic_ret = samba_utils.RUN_COMMAND(magic_cmd + " " + magic_helper_cmd)
print("magic differs test returned %d" % magic_ret)
diff --git a/lib/tdb/ABI/tdb-1.3.15.sigs b/lib/tdb/ABI/tdb-1.3.15.sigs
new file mode 100644
index 0000000..61ce5e6
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.15.sigs
@@ -0,0 +1,71 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_active: bool (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/common/dump.c b/lib/tdb/common/dump.c
index 5f6a78b..73286b8 100644
--- a/lib/tdb/common/dump.c
+++ b/lib/tdb/common/dump.c
@@ -62,7 +62,11 @@ static int tdb_dump_chain(struct tdb_context *tdb, int i)
{
tdb_off_t rec_ptr, top;
- top = TDB_HASH_TOP(i);
+ if (i == -1) {
+ top = FREELIST_TOP;
+ } else {
+ top = TDB_HASH_TOP(i);
+ }
if (tdb_lock(tdb, i, F_WRLCK) != 0)
return -1;
diff --git a/lib/tdb/common/io.c b/lib/tdb/common/io.c
index fe47d18..15ba5b7 100644
--- a/lib/tdb/common/io.c
+++ b/lib/tdb/common/io.c
@@ -52,29 +52,68 @@ static bool tdb_adjust_offset(struct tdb_context *tdb, off_t *off)
static ssize_t tdb_pwrite(struct tdb_context *tdb, const void *buf,
size_t count, off_t offset)
{
+ ssize_t ret;
+
if (!tdb_adjust_offset(tdb, &offset)) {
return -1;
}
- return pwrite(tdb->fd, buf, count, offset);
+
+ do {
+ ret = pwrite(tdb->fd, buf, count, offset);
+ } while ((ret == -1) && (errno == EINTR));
+
+ return ret;
}
static ssize_t tdb_pread(struct tdb_context *tdb, void *buf,
size_t count, off_t offset)
{
+ ssize_t ret;
+
if (!tdb_adjust_offset(tdb, &offset)) {
return -1;
}
- return pread(tdb->fd, buf, count, offset);
+
+ do {
+ ret = pread(tdb->fd, buf, count, offset);
+ } while ((ret == -1) && (errno == EINTR));
+
+ return ret;
}
static int tdb_ftruncate(struct tdb_context *tdb, off_t length)
{
+ ssize_t ret;
+
if (!tdb_adjust_offset(tdb, &length)) {
return -1;
}
- return ftruncate(tdb->fd, length);
+
+ do {
+ ret = ftruncate(tdb->fd, length);
+ } while ((ret == -1) && (errno == EINTR));
+
+ return ret;
}
+#if HAVE_POSIX_FALLOCATE
+static int tdb_posix_fallocate(struct tdb_context *tdb, off_t offset,
+ off_t len)
+{
+ ssize_t ret;
+
+ if (!tdb_adjust_offset(tdb, &offset)) {
+ return -1;
+ }
+
+ do {
+ ret = posix_fallocate(tdb->fd, offset, len);
+ } while ((ret == -1) && (errno == EINTR));
+
+ return ret;
+}
+#endif
+
static int tdb_fstat(struct tdb_context *tdb, struct stat *buf)
{
int ret;
@@ -358,6 +397,7 @@ static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t ad
{
char buf[8192];
tdb_off_t new_size;
+ int ret;
if (tdb->read_only || tdb->traverse_read) {
tdb->ecode = TDB_ERR_RDONLY;
@@ -373,7 +413,36 @@ static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t ad
return -1;
}
- if (tdb_ftruncate(tdb, new_size) == -1) {
+#if HAVE_POSIX_FALLOCATE
+ ret = tdb_posix_fallocate(tdb, size, addition);
+ if (ret == 0) {
+ return 0;
+ }
+ if (ret == ENOSPC) {
+ /*
+ * The Linux glibc (at least as of 2.24) fallback if
+ * the file system does not support fallocate does not
+ * reset the file size back to where it was. Also, to
+ * me it is unclear from the posix spec of
+ * posix_fallocate whether this is allowed or
+ * not. Better be safe than sorry and "goto fail" but
+ * "return -1" here, leaving the EOF pointer too
+ * large.
+ */
+ goto fail;
+ }
+
+ /*
+ * Retry the "old" way. Possibly unnecessary, but looking at
+ * our configure script there seem to be weird failure modes
+ * for posix_fallocate. See commit 3264a98ff16de, which
+ * probably refers to
+ * https://sourceware.org/bugzilla/show_bug.cgi?id=1083.
+ */
+#endif
+
+ ret = tdb_ftruncate(tdb, new_size);
+ if (ret == -1) {
char b = 0;
ssize_t written = tdb_pwrite(tdb, &b, 1, new_size - 1);
if (written == 0) {
@@ -409,14 +478,14 @@ static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t ad
TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write "
"returned 0 twice: giving up!\n"));
errno = ENOSPC;
- return -1;
+ goto fail;
}
if (written == -1) {
tdb->ecode = TDB_ERR_OOM;
TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of "
"%u bytes failed (%s)\n", (int)n,
strerror(errno)));
- return -1;
+ goto fail;
}
if (written != n) {
TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: wrote "
@@ -427,6 +496,28 @@ static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t ad
size += written;
}
return 0;
+
+fail:
+ {
+ int err = errno;
+
+ /*
+ * We're holding the freelist lock or are inside a
+ * transaction. Cutting the file is safe, the space we
+ * tried to allocate can't have been used anywhere in
+ * the meantime.
+ */
+
+ ret = tdb_ftruncate(tdb, size);
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: "
+ "retruncate to %ju failed\n",
+ (uintmax_t)size));
+ }
+ errno = err;
+ }
+
+ return -1;
}
diff --git a/lib/tdb/common/lock.c b/lib/tdb/common/lock.c
index e330201..9f30c7a 100644
--- a/lib/tdb/common/lock.c
+++ b/lib/tdb/common/lock.c
@@ -137,7 +137,33 @@ static int fcntl_unlock(struct tdb_context *tdb, int rw, off_t off, off_t len)
return fcntl(tdb->fd, F_SETLKW, &fl);
}
-/* list -1 is the alloc list, otherwise a hash chain. */
+/*
+ * Calculate the lock offset for a list
+ *
+ * list -1 is the freelist, otherwise a hash chain.
+ *
+ * Note that we consistently (but without real reason) lock hash chains at an
+ * offset that is 4 bytes below the real offset of the corresponding list head
+ * in the db.
+ *
+ * This is the memory layout of the hashchain array:
+ *
+ * FREELIST_TOP + 0 = freelist
+ * FREELIST_TOP + 4 = hashtbale list 0
+ * FREELIST_TOP + 8 = hashtbale list 1
+ * ...
+ *
+ * Otoh lock_offset computes:
+ *
+ * freelist = FREELIST_TOP - 4
+ * list 0 = FREELIST_TOP + 0
+ * list 1 = FREELIST_TOP + 4
+ * ...
+ *
+ * Unfortunately we can't change this calculation in order to align the locking
+ * offset with the memory layout, as that would make the locking incompatible
+ * between different tdb versions.
+ */
static tdb_off_t lock_offset(int list)
{
return FREELIST_TOP + 4*list;
diff --git a/lib/tdb/common/open.c b/lib/tdb/common/open.c
index f3ef856..cfb476d 100644
--- a/lib/tdb/common/open.c
+++ b/lib/tdb/common/open.c
@@ -300,7 +300,8 @@ _PUBLIC_ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int td
struct tdb_header header;
struct tdb_context *tdb;
struct stat st;
- int rev = 0, locked = 0;
+ int rev = 0;
+ bool locked = false;
unsigned char *vp;
uint32_t vertest;
unsigned v;
@@ -512,37 +513,42 @@ _PUBLIC_ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int td
/* we need to zero database if we are the only one with it open */
if ((tdb_flags & TDB_CLEAR_IF_FIRST) &&
- (!tdb->read_only) &&
- (locked = (tdb_nest_lock(tdb, ACTIVE_LOCK, F_WRLCK, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE) == 0))) {
- ret = tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0,
- TDB_LOCK_WAIT);
- if (ret == -1) {
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
- "tdb_brlock failed for %s: %s\n",
- name, strerror(errno)));
- goto fail;
- }
- ret = tdb_new_database(tdb, &header, hash_size);
- if (ret == -1) {
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
- "tdb_new_database failed for %s: %s\n",
- name, strerror(errno)));
- tdb_unlockall(tdb);
- goto fail;
- }
- ret = tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0);
- if (ret == -1) {
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
- "tdb_unlockall failed for %s: %s\n",
- name, strerror(errno)));
- goto fail;
- }
- ret = lseek(tdb->fd, 0, SEEK_SET);
- if (ret == -1) {
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
- "lseek failed for %s: %s\n",
- name, strerror(errno)));
- goto fail;
+ (!tdb->read_only)) {
+ ret = tdb_nest_lock(tdb, ACTIVE_LOCK, F_WRLCK,
+ TDB_LOCK_NOWAIT|TDB_LOCK_PROBE);
+ locked = (ret == 0);
+
+ if (locked) {
+ ret = tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0,
+ TDB_LOCK_WAIT);
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+ "tdb_brlock failed for %s: %s\n",
+ name, strerror(errno)));
+ goto fail;
+ }
+ ret = tdb_new_database(tdb, &header, hash_size);
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+ "tdb_new_database failed for "
+ "%s: %s\n", name, strerror(errno)));
+ tdb_unlockall(tdb);
+ goto fail;
+ }
+ ret = tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0);
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+ "tdb_unlockall failed for %s: %s\n",
+ name, strerror(errno)));
+ goto fail;
+ }
+ ret = lseek(tdb->fd, 0, SEEK_SET);
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+ "lseek failed for %s: %s\n",
+ name, strerror(errno)));
+ goto fail;
+ }
}
}
diff --git a/lib/tdb/common/tdb.c b/lib/tdb/common/tdb.c
index a67d8fb..04f7f97 100644
--- a/lib/tdb/common/tdb.c
+++ b/lib/tdb/common/tdb.c
@@ -541,6 +541,11 @@ static int _tdb_storev(struct tdb_context *tdb, TDB_DATA key,
for (i=0; i<num_dbufs; i++) {
size_t dsize = dbufs[i].dsize;
+ if ((dsize != 0) && (dbufs[i].dptr == NULL)) {
+ tdb->ecode = TDB_ERR_EINVAL;
+ goto fail;
+ }
+
dbufs_len += dsize;
if (dbufs_len < dsize) {
tdb->ecode = TDB_ERR_OOM;
@@ -614,6 +619,10 @@ static int _tdb_storev(struct tdb_context *tdb, TDB_DATA key,
ofs += key.dsize;
for (i=0; i<num_dbufs; i++) {
+ if (dbufs[i].dsize == 0) {
+ continue;
+ }
+
ret = tdb->methods->tdb_write(tdb, ofs, dbufs[i].dptr,
dbufs[i].dsize);
if (ret == -1) {
diff --git a/lib/tdb/common/tdb_private.h b/lib/tdb/common/tdb_private.h
index 7ff29aa..eeac10a 100644
--- a/lib/tdb/common/tdb_private.h
+++ b/lib/tdb/common/tdb_private.h
@@ -126,6 +126,22 @@ void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op,
#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
#endif
+/*
+ * Note: the BUCKET macro is broken as it returns an unexpected result when
+ * called as BUCKET(-1) for the freelist:
+ *
+ * -1 is sign converted to an unsigned int 4294967295 and then the modulo
+ * tdb->hashtable_size is computed. So with a hashtable_size of 10 the result
+ * is
+ *
+ * 4294967295 % hashtable_size = 5.
+ *
+ * where it should be -1 (C uses symmetric modulo).
+ *
+ * As all callers will lock the same wrong list consistently locking is still
+ * consistent. We can not change this without an incompatible on-disk format
+ * change, otherwise different tdb versions would use incompatible locking.
+ */
#define BUCKET(hash) ((hash) % tdb->hash_size)
#define DOCONV() (tdb->flags & TDB_CONVERT)
@@ -178,7 +194,7 @@ struct tdb_lock_type {
struct tdb_traverse_lock {
struct tdb_traverse_lock *next;
uint32_t off;
- uint32_t hash;
+ uint32_t list;
int lock_rw;
};
diff --git a/lib/tdb/common/transaction.c b/lib/tdb/common/transaction.c
index 9b975ea..7d281fc 100644
--- a/lib/tdb/common/transaction.c
+++ b/lib/tdb/common/transaction.c
@@ -43,7 +43,7 @@
tdb_free() the old record to place it on the normal tdb freelist
before allocating the new record
- - during transactions, keep a linked list of writes all that have
+ - during transactions, keep a linked list of all writes that have
been performed by intercepting all tdb_write() calls. The hooked
transaction versions of tdb_read() and tdb_write() check this
linked list and try to use the elements of the list in preference
@@ -210,6 +210,10 @@ static int transaction_write(struct tdb_context *tdb, tdb_off_t off,
{
uint32_t blk;
+ if (buf == NULL) {
+ return -1;
+ }
+
/* Only a commit is allowed on a prepared transaction */
if (tdb->transaction->prepared) {
tdb->ecode = TDB_ERR_EINVAL;
@@ -234,9 +238,7 @@ static int transaction_write(struct tdb_context *tdb, tdb_off_t off,
}
len -= len2;
off += len2;
- if (buf != NULL) {
- buf = (const void *)(len2 + (const char *)buf);
- }
+ buf = (const void *)(len2 + (const char *)buf);
}
if (len == 0) {
@@ -289,11 +291,7 @@ static int transaction_write(struct tdb_context *tdb, tdb_off_t off,
}
/* overwrite part of an existing block */
- if (buf == NULL) {
- memset(tdb->transaction->blocks[blk] + off, 0, len);
- } else {
- memcpy(tdb->transaction->blocks[blk] + off, buf, len);
- }
+ memcpy(tdb->transaction->blocks[blk] + off, buf, len);
if (blk == tdb->transaction->num_blocks-1) {
if (len + off > tdb->transaction->last_block_size) {
tdb->transaction->last_block_size = len + off;
@@ -393,10 +391,20 @@ static int transaction_oob(struct tdb_context *tdb, tdb_off_t off,
static int transaction_expand_file(struct tdb_context *tdb, tdb_off_t size,
tdb_off_t addition)
{
- /* add a write to the transaction elements, so subsequent
- reads see the zero data */
- if (transaction_write(tdb, size, NULL, addition) != 0) {
- return -1;
+ const char buf_zero[8192] = {0};
+ size_t buf_len = sizeof(buf_zero);
+
+ while (addition > 0) {
+ size_t n = MIN(addition, buf_len);
+ int ret;
+
+ ret = transaction_write(tdb, size, buf_zero, n);
+ if (ret != 0) {
+ return ret;
+ }
+
+ addition -= n;
+ size += n;
}
tdb->transaction->expanded = true;
diff --git a/lib/tdb/common/traverse.c b/lib/tdb/common/traverse.c
index f62306e..9b83379 100644
--- a/lib/tdb/common/traverse.c
+++ b/lib/tdb/common/traverse.c
@@ -37,8 +37,8 @@ static tdb_off_t tdb_next_lock(struct tdb_context *tdb, struct tdb_traverse_lock
int want_next = (tlock->off != 0);
/* Lock each chain from the start one. */
- for (; tlock->hash < tdb->hash_size; tlock->hash++) {
- if (!tlock->off && tlock->hash != 0) {
+ for (; tlock->list < tdb->hash_size; tlock->list++) {
+ if (!tlock->off && tlock->list != 0) {
/* this is an optimisation for the common case where
the hash chain is empty, which is particularly
common for the use of tdb with ldb, where large
@@ -67,18 +67,18 @@ static tdb_off_t tdb_next_lock(struct tdb_context *tdb, struct tdb_traverse_lock
factor of around 80 in speed on a linux 2.6.x
system (testing using ldbtest).
*/
- tdb->methods->next_hash_chain(tdb, &tlock->hash);
- if (tlock->hash == tdb->hash_size) {
+ tdb->methods->next_hash_chain(tdb, &tlock->list);
+ if (tlock->list == tdb->hash_size) {
continue;
}
}
- if (tdb_lock(tdb, tlock->hash, tlock->lock_rw) == -1)
+ if (tdb_lock(tdb, tlock->list, tlock->lock_rw) == -1)
return TDB_NEXT_LOCK_ERR;
/* No previous record? Start at top of chain. */
if (!tlock->off) {
- if (tdb_ofs_read(tdb, TDB_HASH_TOP(tlock->hash),
+ if (tdb_ofs_read(tdb, TDB_HASH_TOP(tlock->list),
&tlock->off) == -1)
goto fail;
} else {
@@ -121,7 +121,7 @@ static tdb_off_t tdb_next_lock(struct tdb_context *tdb, struct tdb_traverse_lock
tdb_do_delete(tdb, current, rec) != 0)
goto fail;
}
- tdb_unlock(tdb, tlock->hash, tlock->lock_rw);
+ tdb_unlock(tdb, tlock->list, tlock->lock_rw);
want_next = 0;
}
/* We finished iteration without finding anything */
@@ -130,7 +130,7 @@ static tdb_off_t tdb_next_lock(struct tdb_context *tdb, struct tdb_traverse_lock
fail:
tlock->off = 0;
- if (tdb_unlock(tdb, tlock->hash, tlock->lock_rw) != 0)
+ if (tdb_unlock(tdb, tlock->list, tlock->lock_rw) != 0)
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_next_lock: On error unlock failed!\n"));
return TDB_NEXT_LOCK_ERR;
}
@@ -181,7 +181,7 @@ static int tdb_traverse_internal(struct tdb_context *tdb,
if (key.dptr == NULL) {
ret = -1;
- if (tdb_unlock(tdb, tl->hash, tl->lock_rw)
+ if (tdb_unlock(tdb, tl->list, tl->lock_rw)
!= 0) {
goto out;
}
@@ -205,7 +205,7 @@ static int tdb_traverse_internal(struct tdb_context *tdb,
key.dptr, full_len, 0);
if (nread == -1) {
ret = -1;
- if (tdb_unlock(tdb, tl->hash, tl->lock_rw) != 0)
+ if (tdb_unlock(tdb, tl->list, tl->lock_rw) != 0)
goto out;
if (tdb_unlock_record(tdb, tl->off) != 0)
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_traverse: key.dptr == NULL and unlock_record failed!\n"));
@@ -218,7 +218,7 @@ static int tdb_traverse_internal(struct tdb_context *tdb,
tdb_trace_1rec_retrec(tdb, "traverse", key, dbuf);
/* Drop chain lock, call out */
- if (tdb_unlock(tdb, tl->hash, tl->lock_rw) != 0) {
+ if (tdb_unlock(tdb, tl->list, tl->lock_rw) != 0) {
ret = -1;
goto out;
}
@@ -314,7 +314,7 @@ _PUBLIC_ TDB_DATA tdb_firstkey(struct tdb_context *tdb)
/* release any old lock */
if (tdb_unlock_record(tdb, tdb->travlocks.off) != 0)
return tdb_null;
- tdb->travlocks.off = tdb->travlocks.hash = 0;
+ tdb->travlocks.off = tdb->travlocks.list = 0;
tdb->travlocks.lock_rw = F_RDLCK;
/* Grab first record: locks chain and returned record. */
@@ -330,7 +330,7 @@ _PUBLIC_ TDB_DATA tdb_firstkey(struct tdb_context *tdb)
tdb_trace_retrec(tdb, "tdb_firstkey", key);
/* Unlock the hash chain of the record we just read. */
- if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0)
+ if (tdb_unlock(tdb, tdb->travlocks.list, tdb->travlocks.lock_rw) != 0)
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_firstkey: error occurred while tdb_unlocking!\n"));
return key;
}
@@ -338,7 +338,7 @@ _PUBLIC_ TDB_DATA tdb_firstkey(struct tdb_context *tdb)
/* find the next entry in the database, returning its key */
_PUBLIC_ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
{
- uint32_t oldhash;
+ uint32_t oldlist;
TDB_DATA key = tdb_null;
struct tdb_record rec;
unsigned char *k = NULL;
@@ -346,7 +346,7 @@ _PUBLIC_ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
/* Is locked key the old key? If so, traverse will be reliable. */
if (tdb->travlocks.off) {
- if (tdb_lock(tdb,tdb->travlocks.hash,tdb->travlocks.lock_rw))
+ if (tdb_lock(tdb,tdb->travlocks.list,tdb->travlocks.lock_rw))
return tdb_null;
if (tdb_rec_read(tdb, tdb->travlocks.off, &rec) == -1
|| !(k = tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),
@@ -359,7 +359,7 @@ _PUBLIC_ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
SAFE_FREE(k);
return tdb_null;
}
- if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0) {
+ if (tdb_unlock(tdb, tdb->travlocks.list, tdb->travlocks.lock_rw) != 0) {
SAFE_FREE(k);
return tdb_null;
}
@@ -376,13 +376,13 @@ _PUBLIC_ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
tdb_trace_1rec_retrec(tdb, "tdb_nextkey", oldkey, tdb_null);
return tdb_null;
}
- tdb->travlocks.hash = BUCKET(rec.full_hash);
+ tdb->travlocks.list = BUCKET(rec.full_hash);
if (tdb_lock_record(tdb, tdb->travlocks.off) != 0) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: lock_record failed (%s)!\n", strerror(errno)));
return tdb_null;
}
}
- oldhash = tdb->travlocks.hash;
+ oldlist = tdb->travlocks.list;
/* Grab next record: locks chain and returned record,
unlocks old record */
@@ -392,11 +392,11 @@ _PUBLIC_ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
key.dptr = tdb_alloc_read(tdb, tdb->travlocks.off+sizeof(rec),
key.dsize);
/* Unlock the chain of this new record */
- if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0)
+ if (tdb_unlock(tdb, tdb->travlocks.list, tdb->travlocks.lock_rw) != 0)
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
}
/* Unlock the chain of old record */
- if (tdb_unlock(tdb, BUCKET(oldhash), tdb->travlocks.lock_rw) != 0)
+ if (tdb_unlock(tdb, oldlist, tdb->travlocks.lock_rw) != 0)
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
tdb_trace_1rec_retrec(tdb, "tdb_nextkey", oldkey, key);
return key;
diff --git a/lib/tdb/wscript b/lib/tdb/wscript
index 4782550..11bc0db 100644
--- a/lib/tdb/wscript
+++ b/lib/tdb/wscript
@@ -1,7 +1,7 @@
#!/usr/bin/env python
APPNAME = 'tdb'
-VERSION = '1.3.14'
+VERSION = '1.3.15'
blddir = 'bin'
diff --git a/lib/tevent/ABI/tevent-0.9.35.sigs b/lib/tevent/ABI/tevent-0.9.35.sigs
new file mode 100644
index 0000000..7a6a236
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.35.sigs
@@ -0,0 +1,99 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.36.sigs b/lib/tevent/ABI/tevent-0.9.36.sigs
new file mode 100644
index 0000000..8a579c8
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.36.sigs
@@ -0,0 +1,100 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_entry_untrigger: void (struct tevent_queue_entry *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/echo_server.c b/lib/tevent/echo_server.c
index 6e7f181..f93d8bc 100644
--- a/lib/tevent/echo_server.c
+++ b/lib/tevent/echo_server.c
@@ -118,6 +118,7 @@ static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
tevent_req_error(req, errno);
return;
}
+ smb_set_close_on_exec(ret);
state->sock = ret;
tevent_req_done(req);
}
diff --git a/lib/tevent/testsuite.c b/lib/tevent/testsuite.c
index ee29e5b..e508452 100644
--- a/lib/tevent/testsuite.c
+++ b/lib/tevent/testsuite.c
@@ -25,7 +25,7 @@
*/
#include "includes.h"
-#include "lib/tevent/tevent.h"
+#include "tevent.h"
#include "system/filesys.h"
#include "system/select.h"
#include "system/network.h"
diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h
index 728cf62..7bb9c61 100644
--- a/lib/tevent/tevent.h
+++ b/lib/tevent/tevent.h
@@ -936,8 +936,8 @@ void tevent_req_set_cancel_fn(struct tevent_req *req, tevent_req_cancel_fn fn);
*
* @param[in] req The request to use.
*
- * @return This function returns true is the request is cancelable,
- * othererwise false is returned.
+ * @return This function returns true if the request is
+ * cancelable, otherwise false is returned.
*
* @note Even if the function returns true, the caller need to wait
* for the function to complete normally.
@@ -1611,6 +1611,9 @@ struct tevent_queue_entry *tevent_queue_add_entry(
* already called tevent_req_notify_callback(), tevent_req_error(),
* tevent_req_done() or a similar function.
*
+ * The trigger function has no chance to see the returned
+ * queue_entry in the optimized case.
+ *
* The request can be removed from the queue by calling talloc_free()
* (or a similar function) on the returned queue entry.
*
@@ -1641,6 +1644,28 @@ struct tevent_queue_entry *tevent_queue_add_optimize_empty(
void *private_data);
/**
+ * @brief Untrigger an already triggered queue entry.
+ *
+ * If a trigger function detects that it needs to remain
+ * in the queue, it needs to call tevent_queue_stop()
+ * followed by tevent_queue_entry_untrigger().
+ *
+ * @note In order to call tevent_queue_entry_untrigger()
+ * the queue must be already stopped and the given queue_entry
+ * must be the first one in the queue! Otherwise it calls abort().
+ *
+ * @note You can't use this together with tevent_queue_add_optimize_empty()
+ * because the trigger function don't have access to the quene entry
+ * in the case of an empty queue.
+ *
+ * @param[in] queue_entry The queue entry to rearm.
+ *
+ * @see tevent_queue_add_entry()
+ * @see tevent_queue_stop()
+ */
+void tevent_queue_entry_untrigger(struct tevent_queue_entry *entry);
+
+/**
* @brief Start a tevent queue.
*
* The queue is started by default.
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index 47ea39b..ec3955e 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -235,7 +235,6 @@ struct tevent_threaded_context {
pthread_mutex_t event_ctx_mutex;
#endif
struct tevent_context *event_ctx;
- int wakeup_fd;
};
struct tevent_debug_ops {
diff --git a/lib/tevent/tevent_queue.c b/lib/tevent/tevent_queue.c
index 5516c6c..9c3973b 100644
--- a/lib/tevent/tevent_queue.c
+++ b/lib/tevent/tevent_queue.c
@@ -266,6 +266,19 @@ struct tevent_queue_entry *tevent_queue_add_optimize_empty(
trigger, private_data, true);
}
+void tevent_queue_entry_untrigger(struct tevent_queue_entry *entry)
+{
+ if (entry->queue->running) {
+ abort();
+ }
+
+ if (entry->queue->list != entry) {
+ abort();
+ }
+
+ entry->triggered = false;
+}
+
void tevent_queue_start(struct tevent_queue *queue)
{
if (queue->running) {
diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c
index 2e83f1b..2c6e66b 100644
--- a/lib/tevent/tevent_threads.c
+++ b/lib/tevent/tevent_threads.c
@@ -424,7 +424,6 @@ struct tevent_threaded_context *tevent_threaded_context_create(
return NULL;
}
tctx->event_ctx = ev;
- tctx->wakeup_fd = ev->wakeup_fd;
ret = pthread_mutex_init(&tctx->event_ctx_mutex, NULL);
if (ret != 0) {
@@ -489,14 +488,13 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
}
DLIST_ADD_END(ev->scheduled_immediates, im);
+ wakeup_fd = ev->wakeup_fd;
ret = pthread_mutex_unlock(&ev->scheduled_mutex);
if (ret != 0) {
abort();
}
- wakeup_fd = tctx->wakeup_fd;
-
ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
if (ret != 0) {
abort();
diff --git a/lib/tevent/wscript b/lib/tevent/wscript
index 31f7ee7..94d190f 100644
--- a/lib/tevent/wscript
+++ b/lib/tevent/wscript
@@ -1,7 +1,7 @@
#!/usr/bin/env python
APPNAME = 'tevent'
-VERSION = '0.9.34'
+VERSION = '0.9.36'
blddir = 'bin'
diff --git a/lib/util/binsearch.h b/lib/util/binsearch.h
new file mode 100644
index 0000000..8ae9da2
--- /dev/null
+++ b/lib/util/binsearch.h
@@ -0,0 +1,121 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ a generic binary search macro
+
+ Copyright (C) Andrew Tridgell 2009
+
+ ** NOTE! The following LGPL license applies to the binsearch.h
+ ** header. 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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _BINSEARCH_H
+#define _BINSEARCH_H
+
+/* a binary array search, where the array is an array of pointers to structures,
+ and we want to find a match for 'target' on 'field' in those structures.
+
+ Inputs:
+ array: base pointer to an array of structures
+ arrray_size: number of elements in the array
+ field: the name of the field in the structure we are keying off
+ target: the field value we are looking for
+ comparison_fn: the comparison function
+ result: where the result of the search is put
+
+ if the element is found, then 'result' is set to point to the found array element. If not,
+ then 'result' is set to NULL.
+
+ The array is assumed to be sorted by the same comparison_fn as the
+ search (with, for example, qsort)
+ */
+#define BINARY_ARRAY_SEARCH_P(array, array_size, field, target, comparison_fn, result) do { \
+ int32_t _b, _e; \
+ (result) = NULL; \
+ if (array_size) { for (_b = 0, _e = (array_size)-1; _b <= _e; ) { \
+ int32_t _i = (_b+_e)/2; \
+ int _r = comparison_fn(target, array[_i]->field); \
+ if (_r == 0) { (result) = array[_i]; break; } \
+ if (_r < 0) _e = _i - 1; else _b = _i + 1; \
+ }} } while (0)
+
+/*
+ like BINARY_ARRAY_SEARCH_P, but assumes that the array is an array
+ of structures, rather than pointers to structures
+
+ result points to the found structure, or NULL
+ */
+#define BINARY_ARRAY_SEARCH(array, array_size, field, target, comparison_fn, result) do { \
+ int32_t _b, _e; \
+ (result) = NULL; \
+ if (array_size) { for (_b = 0, _e = (array_size)-1; _b <= _e; ) { \
+ int32_t _i = (_b+_e)/2; \
+ int _r = comparison_fn(target, array[_i].field); \
+ if (_r == 0) { (result) = &array[_i]; break; } \
+ if (_r < 0) _e = _i - 1; else _b = _i + 1; \
+ }} } while (0)
+
+/*
+ like BINARY_ARRAY_SEARCH_P, but assumes that the array is an array
+ of elements, rather than pointers to structures
+
+ result points to the found structure, or NULL
+ */
+#define BINARY_ARRAY_SEARCH_V(array, array_size, target, comparison_fn, result) do { \
+ int32_t _b, _e; \
+ (result) = NULL; \
+ if (array_size) { for (_b = 0, _e = (array_size)-1; _b <= _e; ) { \
+ int32_t _i = (_b+_e)/2; \
+ int _r = comparison_fn(target, array[_i]); \
+ if (_r == 0) { (result) = &array[_i]; break; } \
+ if (_r < 0) _e = _i - 1; else _b = _i + 1; \
+ }} } while (0)
+
+
+/*
+ like BINARY_ARRAY_SEARCH_V, but if an exact result is not found, the 'next'
+ argument will point to the element after the place where the exact result
+ would have been. If an exact result is found, 'next' will be NULL. If the
+ target is beyond the end of the list, both 'exact' and 'next' will be NULL.
+ Unlike other binsearch macros, where there are several elements that compare
+ the same, the exact result will always point to the first one.
+
+ If you don't care to distinguish between the 'greater than' and 'equals'
+ cases, you can use the same pointer for both 'exact' and 'next'.
+
+ As with all the binsearch macros, the comparison function is always called
+ with the search term first.
+ */
+#define BINARY_ARRAY_SEARCH_GTE(array, array_size, target, comparison_fn, \
+ exact, next) do { \
+ int32_t _b, _e; \
+ (exact) = NULL; (next) = NULL; \
+ if ((array_size) > 0) { \
+ for (_b = 0, _e = (array_size)-1; _b <= _e; ) { \
+ int32_t _i = (_b + _e) / 2; \
+ int _r = comparison_fn(target, &array[_i]); \
+ if (_r == 0) { \
+ (exact) = &array[_i]; \
+ _e = _i - 1; \
+ } else if (_r < 0) { _e = _i - 1; \
+ } else { _b = _i + 1; } \
+ } \
+ if ((exact) == NULL &&_b < (array_size)) { \
+ (next) = &array[_b]; \
+ } } } while (0)
+
+#endif
diff --git a/pyldb.c b/pyldb.c
index 515a69e..4b02edb 100644
--- a/pyldb.c
+++ b/pyldb.c
@@ -510,10 +510,10 @@ static PyObject *py_ldb_dn_set_extended_component(PyLdbDnObject *self, PyObject
{
char *name;
int err;
- uint8_t *value;
+ uint8_t *value = NULL;
Py_ssize_t size = 0;
- if (!PyArg_ParseTuple(args, "sz#", &name, (const char**)&value, &size))
+ if (!PyArg_ParseTuple(args, "sz#", &name, (char **)&value, &size))
return NULL;
if (value == NULL) {
@@ -1669,6 +1669,7 @@ static PyObject *py_ldb_parse_ldif(PyLdbObject *self, PyObject *args)
PyObject *list, *ret;
struct ldb_ldif *ldif;
const char *s;
+ struct ldb_dn *last_dn = NULL;
TALLOC_CTX *mem_ctx;
@@ -1686,8 +1687,29 @@ static PyObject *py_ldb_parse_ldif(PyLdbObject *self, PyObject *args)
talloc_steal(mem_ctx, ldif);
if (ldif) {
PyList_Append(list, ldb_ldif_to_pyobject(ldif));
+ last_dn = ldif->msg->dn;
} else {
- PyErr_SetString(PyExc_ValueError, "unable to parse ldif string");
+ const char *last_dn_str = NULL;
+ const char *err_string = NULL;
+ if (last_dn == NULL) {
+ PyErr_SetString(PyExc_ValueError,
+ "unable to parse LDIF "
+ "string at first chunk");
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ last_dn_str
+ = ldb_dn_get_linearized(last_dn);
+
+ err_string
+ = talloc_asprintf(mem_ctx,
+ "unable to parse ldif "
+ "string AFTER %s",
+ last_dn_str);
+
+ PyErr_SetString(PyExc_ValueError,
+ err_string);
talloc_free(mem_ctx);
return NULL;
}
@@ -4204,6 +4226,10 @@ static PyObject* module_init(void)
ADD_LDB_INT(FLG_NOSYNC);
ADD_LDB_INT(FLG_RECONNECT);
ADD_LDB_INT(FLG_NOMMAP);
+ ADD_LDB_INT(FLG_SHOW_BINARY);
+ ADD_LDB_INT(FLG_ENABLE_TRACING);
+ ADD_LDB_INT(FLG_DONT_CREATE_DB);
+
/* Historical misspelling */
PyModule_AddIntConstant(m, "ERR_ALIAS_DEREFERINCING_PROBLEM", LDB_ERR_ALIAS_DEREFERENCING_PROBLEM);
diff --git a/tests/ldb_mod_op_test.c b/tests/ldb_mod_op_test.c
index 5e439f8..766ca79 100644
--- a/tests/ldb_mod_op_test.c
+++ b/tests/ldb_mod_op_test.c
@@ -2861,6 +2861,747 @@ static void test_ldb_rename_dn_case_change(void **state)
/* FIXME - test the values didn't change */
}
+static int ldb_read_only_setup(void **state)
+{
+ struct ldbtest_ctx *test_ctx;
+
+ ldbtest_setup((void **) &test_ctx);
+
+ *state = test_ctx;
+ return 0;
+}
+
+static int ldb_read_only_teardown(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ ldbtest_teardown((void **) &test_ctx);
+ return 0;
+}
+
+static void test_read_only(void **state)
+{
+ struct ldb_context *ro_ldb = NULL;
+ struct ldb_context *rw_ldb = NULL;
+ int ret;
+ TALLOC_CTX *tmp_ctx = NULL;
+
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ /*
+ * Close the ldb context freeing it this will ensure it exists on
+ * disk and can be opened in read only mode
+ */
+ TALLOC_FREE(test_ctx->ldb);
+
+ /*
+ * Open the database in read only and read write mode,
+ * ensure it's opend in read only mode first
+ */
+ ro_ldb = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ro_ldb, test_ctx->dbpath, LDB_FLG_RDONLY, NULL);
+ assert_int_equal(ret, 0);
+
+ rw_ldb = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(rw_ldb, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+
+ /*
+ * Set up a context for the temporary variables
+ */
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /*
+ * Ensure that we can search the read write database
+ */
+ {
+ struct ldb_result *result = NULL;
+ struct ldb_dn *dn = ldb_dn_new_fmt(tmp_ctx, rw_ldb,
+ "dc=test");
+ assert_non_null(dn);
+
+ ret = ldb_search(rw_ldb, tmp_ctx, &result, dn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+ TALLOC_FREE(result);
+ TALLOC_FREE(dn);
+ }
+
+ /*
+ * Ensure that we can search the read only database
+ */
+ {
+ struct ldb_result *result = NULL;
+ struct ldb_dn *dn = ldb_dn_new_fmt(tmp_ctx, ro_ldb,
+ "dc=test");
+ assert_non_null(dn);
+
+ ret = ldb_search(ro_ldb, tmp_ctx, &result, dn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+ TALLOC_FREE(result);
+ TALLOC_FREE(dn);
+ }
+ /*
+ * Ensure that a write to the read only database fails
+ */
+ {
+ struct ldb_message *msg = NULL;
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(msg, ro_ldb, "dc=test");
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(ro_ldb, msg);
+ assert_int_equal(ret, LDB_ERR_UNWILLING_TO_PERFORM);
+ TALLOC_FREE(msg);
+ }
+
+ /*
+ * Ensure that a write to the read write database succeeds
+ */
+ {
+ struct ldb_message *msg = NULL;
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(msg, ro_ldb, "dc=test");
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(rw_ldb, msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ TALLOC_FREE(msg);
+ }
+
+ /*
+ * Ensure that a delete from a read only database fails
+ */
+ {
+ struct ldb_dn *dn = ldb_dn_new_fmt(tmp_ctx, ro_ldb, "dc=test");
+ assert_non_null(dn);
+
+ ret = ldb_delete(ro_ldb, dn);
+ assert_int_equal(ret, LDB_ERR_UNWILLING_TO_PERFORM);
+ TALLOC_FREE(dn);
+ }
+
+
+ /*
+ * Ensure that a delete from a read write succeeds
+ */
+ {
+ struct ldb_dn *dn = ldb_dn_new_fmt(tmp_ctx, rw_ldb, "dc=test");
+ assert_non_null(dn);
+
+ ret = ldb_delete(rw_ldb, dn);
+ assert_int_equal(ret, LDB_SUCCESS);
+ TALLOC_FREE(dn);
+ }
+ TALLOC_FREE(tmp_ctx);
+}
+
+static bool unique_values = false;
+
+static int unique_index_test_module_add(
+ struct ldb_module *module,
+ struct ldb_request *req)
+{
+ if (unique_values) {
+ struct ldb_message *msg = discard_const(req->op.add.message);
+ struct ldb_message_element *el = NULL;
+ el = ldb_msg_find_element(msg, "cn");
+ if (el != NULL) {
+ el->flags |= LDB_FLAG_INTERNAL_FORCE_UNIQUE_INDEX;
+ }
+ }
+
+ return ldb_next_request(module, req);
+}
+
+static int unique_index_test_module_init(struct ldb_module *module)
+{
+ return ldb_next_init(module);
+}
+
+static const struct ldb_module_ops ldb_unique_index_test_module_ops = {
+ .name = "unique_index_test",
+ .init_context = unique_index_test_module_init,
+ .add = unique_index_test_module_add,
+};
+
+static int ldb_unique_index_test_setup(void **state)
+{
+ int ret;
+ struct ldb_ldif *ldif;
+ struct ldbtest_ctx *ldb_test_ctx;
+ const char *attrs_ldif = \
+ "dn: @ATTRIBUTES\n"
+ "cn: UNIQUE_INDEX\n"
+ "\n";
+ const char *index_ldif = \
+ "dn: @INDEXLIST\n"
+ "@IDXATTR: cn\n"
+ "\n";
+ const char *options[] = {"modules:unique_index_test"};
+
+
+ ret = ldb_register_module(&ldb_unique_index_test_module_ops);
+ assert_true(ret == LDB_SUCCESS || ret == LDB_ERR_ENTRY_ALREADY_EXISTS);
+ ldbtest_noconn_setup((void **) &ldb_test_ctx);
+
+
+ ret = ldb_connect(ldb_test_ctx->ldb, ldb_test_ctx->dbpath, 0, options);
+ assert_int_equal(ret, 0);
+
+ while ((ldif = ldb_ldif_read_string(ldb_test_ctx->ldb, &attrs_ldif))) {
+ ret = ldb_add(ldb_test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ while ((ldif = ldb_ldif_read_string(ldb_test_ctx->ldb, &index_ldif))) {
+ ret = ldb_add(ldb_test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ unique_values = true;
+
+ *state = ldb_test_ctx;
+ return 0;
+}
+
+static int ldb_unique_index_test_teardown(void **state)
+{
+ int ret;
+ struct ldbtest_ctx *ldb_test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ struct ldb_dn *del_dn;
+
+ del_dn = ldb_dn_new_fmt(ldb_test_ctx,
+ ldb_test_ctx->ldb,
+ "@INDEXLIST");
+ assert_non_null(del_dn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ "@INDEXLIST");
+
+ TALLOC_FREE(del_dn);
+
+ del_dn = ldb_dn_new_fmt(ldb_test_ctx,
+ ldb_test_ctx->ldb,
+ "@ATTRIBUTES");
+ assert_non_null(del_dn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ "@ATTRIBUTES");
+
+ ldbtest_teardown((void **) &ldb_test_ctx);
+ return 0;
+}
+
+
+static void test_ldb_add_unique_value_to_unique_index(void **state)
+{
+ int ret;
+ struct ldb_message *msg;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "dc=test");
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ talloc_free(tmp_ctx);
+}
+
+static int ldb_non_unique_index_test_setup(void **state)
+{
+ int ret;
+ struct ldb_ldif *ldif;
+ struct ldbtest_ctx *ldb_test_ctx;
+ const char *index_ldif = \
+ "dn: @INDEXLIST\n"
+ "@IDXATTR: cn\n"
+ "\n";
+ const char *options[] = {"modules:unique_index_test"};
+
+
+ ret = ldb_register_module(&ldb_unique_index_test_module_ops);
+ assert_true(ret == LDB_SUCCESS || ret == LDB_ERR_ENTRY_ALREADY_EXISTS);
+ ldbtest_noconn_setup((void **) &ldb_test_ctx);
+
+
+ ret = ldb_connect(ldb_test_ctx->ldb, ldb_test_ctx->dbpath, 0, options);
+ assert_int_equal(ret, 0);
+
+ while ((ldif = ldb_ldif_read_string(ldb_test_ctx->ldb, &index_ldif))) {
+ ret = ldb_add(ldb_test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ unique_values = true;
+
+ *state = ldb_test_ctx;
+ return 0;
+}
+
+static int ldb_non_unique_index_test_teardown(void **state)
+{
+ int ret;
+ struct ldbtest_ctx *ldb_test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ struct ldb_dn *del_dn;
+
+ del_dn = ldb_dn_new_fmt(ldb_test_ctx,
+ ldb_test_ctx->ldb,
+ "@INDEXLIST");
+ assert_non_null(del_dn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ "@INDEXLIST");
+
+ TALLOC_FREE(del_dn);
+
+ ldbtest_teardown((void **) &ldb_test_ctx);
+ return 0;
+}
+
+static void test_ldb_add_duplicate_value_to_unique_index(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg02);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test02");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_ERR_CONSTRAINT_VIOLATION);
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_add_to_index_duplicates_allowed(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+
+ unique_values = false;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg02);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test02");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_SUCCESS);
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_add_to_index_unique_values_required(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+
+ unique_values = true;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg02);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test02");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_ERR_CONSTRAINT_VIOLATION);
+ talloc_free(tmp_ctx);
+}
+
+static void ldb_debug_string(void *context, enum ldb_debug_level level,
+ const char *fmt, va_list ap)
+{
+
+ if (level <= LDB_DEBUG_WARNING) {
+ *((char **)context) = talloc_vasprintf(NULL, fmt, ap);
+ }
+}
+
+static void test_ldb_unique_index_duplicate_logging(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+ char *debug_string = NULL;
+ char *p = NULL;
+
+ ldb_set_debug(test_ctx->ldb, ldb_debug_string, &debug_string);
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg02);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test02");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_ERR_CONSTRAINT_VIOLATION);
+
+ assert_non_null(debug_string);
+ p = strstr(
+ debug_string,
+ "unique index violation on cn "
+ "in dc=test02, conficts with dc=test01 in "
+ "@INDEX:CN:test_unique_index");
+ assert_non_null(p);
+ TALLOC_FREE(debug_string);
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_duplicate_dn_logging(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+ char *debug_string = NULL;
+
+ ldb_set_debug(test_ctx->ldb, ldb_debug_string, &debug_string);
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index01");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg02);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index02");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_ERR_ENTRY_ALREADY_EXISTS);
+
+ assert_null(debug_string);
+ talloc_free(tmp_ctx);
+}
+
+static int ldb_guid_index_test_setup(void **state)
+{
+ int ret;
+ struct ldb_ldif *ldif;
+ struct ldbtest_ctx *ldb_test_ctx;
+ const char *attrs_ldif = \
+ "dn: @ATTRIBUTES\n"
+ "cn: UNIQUE_INDEX\n"
+ "\n";
+ const char *index_ldif = \
+ "dn: @INDEXLIST\n"
+ "@IDXATTR: cn\n"
+ "@IDXGUID: objectUUID\n"
+ "@IDX_DN_GUID: GUID\n"
+ "\n";
+
+ ldbtest_noconn_setup((void **) &ldb_test_ctx);
+
+
+ ret = ldb_connect(ldb_test_ctx->ldb, ldb_test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+ while ((ldif = ldb_ldif_read_string(ldb_test_ctx->ldb, &attrs_ldif))) {
+ ret = ldb_add(ldb_test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ while ((ldif = ldb_ldif_read_string(ldb_test_ctx->ldb, &index_ldif))) {
+ ret = ldb_add(ldb_test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ *state = ldb_test_ctx;
+ return 0;
+}
+
+static int ldb_guid_index_test_teardown(void **state)
+{
+ int ret;
+ struct ldbtest_ctx *ldb_test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ struct ldb_dn *del_dn;
+
+ del_dn = ldb_dn_new_fmt(ldb_test_ctx,
+ ldb_test_ctx->ldb,
+ "@INDEXLIST");
+ assert_non_null(del_dn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ "@INDEXLIST");
+
+ TALLOC_FREE(del_dn);
+
+ del_dn = ldb_dn_new_fmt(ldb_test_ctx,
+ ldb_test_ctx->ldb,
+ "@ATTRIBUTES");
+ assert_non_null(del_dn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ "@ATTRIBUTES");
+
+ ldbtest_teardown((void **) &ldb_test_ctx);
+ return 0;
+}
+
+
+static void test_ldb_unique_index_duplicate_with_guid(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+ char *debug_string = NULL;
+ char *p = NULL;
+
+ ldb_set_debug(test_ctx->ldb, ldb_debug_string, &debug_string);
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg01, "objectUUID", "0123456789abcdef");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test02");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg02, "objectUUID", "0123456789abcde0");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_ERR_CONSTRAINT_VIOLATION);
+
+ assert_non_null(debug_string);
+ p = strstr(
+ debug_string,
+ "unique index violation on cn in dc=test02, conficts with "
+ "objectUUID 0123456789abcdef in @INDEX:CN:test_unique_index");
+ assert_non_null(p);
+ TALLOC_FREE(debug_string);
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_guid_index_duplicate_dn_logging(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+ char *debug_string = NULL;
+
+ ldb_set_debug(test_ctx->ldb, ldb_debug_string, &debug_string);
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index01");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg01, "objectUUID", "0123456789abcdef");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg02);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index02");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg02, "objectUUID", "0123456789abcde1");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_ERR_ENTRY_ALREADY_EXISTS);
+
+ assert_null(debug_string);
+ talloc_free(tmp_ctx);
+}
+
+
int main(int argc, const char **argv)
{
const struct CMUnitTest tests[] = {
@@ -2981,6 +3722,41 @@ int main(int argc, const char **argv)
cmocka_unit_test_setup_teardown(test_ldb_rename_dn_case_change,
ldb_rename_test_setup,
ldb_rename_test_teardown),
+ cmocka_unit_test_setup_teardown(test_read_only,
+ ldb_read_only_setup,
+ ldb_read_only_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_add_unique_value_to_unique_index,
+ ldb_unique_index_test_setup,
+ ldb_unique_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_add_duplicate_value_to_unique_index,
+ ldb_unique_index_test_setup,
+ ldb_unique_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_add_to_index_duplicates_allowed,
+ ldb_non_unique_index_test_setup,
+ ldb_non_unique_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_add_to_index_unique_values_required,
+ ldb_non_unique_index_test_setup,
+ ldb_non_unique_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_unique_index_duplicate_logging,
+ ldb_unique_index_test_setup,
+ ldb_unique_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_duplicate_dn_logging,
+ ldb_unique_index_test_setup,
+ ldb_unique_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_guid_index_duplicate_dn_logging,
+ ldb_guid_index_test_setup,
+ ldb_guid_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_unique_index_duplicate_with_guid,
+ ldb_guid_index_test_setup,
+ ldb_guid_index_test_teardown),
};
return cmocka_run_group_tests(tests, NULL, NULL);
diff --git a/tests/python/api.py b/tests/python/api.py
index b95266b..85fe1bc 100755
--- a/tests/python/api.py
+++ b/tests/python/api.py
@@ -55,6 +55,9 @@ class SimpleLdb(TestCase):
def tearDown(self):
shutil.rmtree(self.testdir)
super(SimpleLdb, self).tearDown()
+ # Ensure the LDB is closed now, so we close the FD
+ del(self.ldb)
+
def test_connect(self):
ldb.Ldb(self.filename)
@@ -610,85 +613,123 @@ class SearchTests(TestCase):
shutil.rmtree(self.testdir)
super(SearchTests, self).tearDown()
+ # Ensure the LDB is closed now, so we close the FD
+ del(self.l)
+
+
def setUp(self):
super(SearchTests, self).setUp()
self.testdir = tempdir()
self.filename = os.path.join(self.testdir, "search_test.ldb")
self.l = ldb.Ldb(self.filename, options=["modules:rdn_name"])
- self.l.add({"dn": "DC=SAMBA,DC=ORG", "name": b"samba.org"})
+ self.l.add({"dn": "@ATTRIBUTES",
+ "DC": "CASE_INSENSITIVE"})
+
+ # Note that we can't use the name objectGUID here, as we
+ # want to stay clear of the objectGUID handler in LDB and
+ # instead use just the 16 bytes raw, which we just keep
+ # to printable chars here for ease of handling.
+
+ self.l.add({"dn": "DC=SAMBA,DC=ORG",
+ "name": b"samba.org",
+ "objectUUID": b"0123456789abcddf"})
self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG",
"name": b"Admins",
- "x": "z", "y": "a"})
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde1"})
self.l.add({"dn": "OU=USERS,DC=SAMBA,DC=ORG",
"name": b"Users",
- "x": "z", "y": "a"})
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
self.l.add({"dn": "OU=OU1,DC=SAMBA,DC=ORG",
"name": b"OU #1",
- "x": "y", "y": "a"})
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcde3"})
self.l.add({"dn": "OU=OU2,DC=SAMBA,DC=ORG",
"name": b"OU #2",
- "x": "y", "y": "a"})
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcde4"})
self.l.add({"dn": "OU=OU3,DC=SAMBA,DC=ORG",
"name": b"OU #3",
- "x": "y", "y": "a"})
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcde5"})
self.l.add({"dn": "OU=OU4,DC=SAMBA,DC=ORG",
"name": b"OU #4",
- "x": "y", "y": "a"})
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcde6"})
self.l.add({"dn": "OU=OU5,DC=SAMBA,DC=ORG",
"name": b"OU #5",
- "x": "y", "y": "a"})
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcde7"})
self.l.add({"dn": "OU=OU6,DC=SAMBA,DC=ORG",
"name": b"OU #6",
- "x": "y", "y": "a"})
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcde8"})
self.l.add({"dn": "OU=OU7,DC=SAMBA,DC=ORG",
"name": b"OU #7",
- "x": "y", "y": "a"})
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcde9"})
self.l.add({"dn": "OU=OU8,DC=SAMBA,DC=ORG",
"name": b"OU #8",
- "x": "y", "y": "a"})
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcde0"})
self.l.add({"dn": "OU=OU9,DC=SAMBA,DC=ORG",
"name": b"OU #9",
- "x": "y", "y": "a"})
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcdea"})
self.l.add({"dn": "OU=OU10,DC=SAMBA,DC=ORG",
"name": b"OU #10",
- "x": "y", "y": "a"})
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcdeb"})
self.l.add({"dn": "OU=OU11,DC=SAMBA,DC=ORG",
"name": b"OU #10",
- "x": "y", "y": "a"})
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcdec"})
self.l.add({"dn": "OU=OU12,DC=SAMBA,DC=ORG",
"name": b"OU #10",
- "x": "y", "y": "b"})
+ "x": "y", "y": "b",
+ "objectUUID": b"0123456789abcded"})
self.l.add({"dn": "OU=OU13,DC=SAMBA,DC=ORG",
"name": b"OU #10",
- "x": "x", "y": "b"})
+ "x": "x", "y": "b",
+ "objectUUID": b"0123456789abcdee"})
self.l.add({"dn": "OU=OU14,DC=SAMBA,DC=ORG",
"name": b"OU #10",
- "x": "x", "y": "b"})
+ "x": "x", "y": "b",
+ "objectUUID": b"0123456789abcd01"})
self.l.add({"dn": "OU=OU15,DC=SAMBA,DC=ORG",
"name": b"OU #10",
- "x": "x", "y": "b"})
+ "x": "x", "y": "b",
+ "objectUUID": b"0123456789abcd02"})
self.l.add({"dn": "OU=OU16,DC=SAMBA,DC=ORG",
"name": b"OU #10",
- "x": "x", "y": "b"})
+ "x": "x", "y": "b",
+ "objectUUID": b"0123456789abcd03"})
self.l.add({"dn": "OU=OU17,DC=SAMBA,DC=ORG",
"name": b"OU #10",
- "x": "x", "y": "b"})
+ "x": "x", "y": "b",
+ "objectUUID": b"0123456789abcd04"})
self.l.add({"dn": "OU=OU18,DC=SAMBA,DC=ORG",
"name": b"OU #10",
- "x": "x", "y": "b"})
+ "x": "x", "y": "b",
+ "objectUUID": b"0123456789abcd05"})
self.l.add({"dn": "OU=OU19,DC=SAMBA,DC=ORG",
"name": b"OU #10",
- "x": "x", "y": "b"})
+ "x": "x", "y": "b",
+ "objectUUID": b"0123456789abcd06"})
self.l.add({"dn": "OU=OU20,DC=SAMBA,DC=ORG",
"name": b"OU #10",
- "x": "x", "y": "b"})
+ "x": "x", "y": "b",
+ "objectUUID": b"0123456789abcd07"})
self.l.add({"dn": "OU=OU21,DC=SAMBA,DC=ORG",
"name": b"OU #10",
- "x": "x", "y": "c"})
+ "x": "x", "y": "c",
+ "objectUUID": b"0123456789abcd08"})
self.l.add({"dn": "OU=OU22,DC=SAMBA,DC=ORG",
"name": b"OU #10",
- "x": "x", "y": "c"})
+ "x": "x", "y": "c",
+ "objectUUID": b"0123456789abcd09"})
def test_base(self):
"""Testing a search"""
@@ -697,6 +738,13 @@ class SearchTests(TestCase):
scope=ldb.SCOPE_BASE)
self.assertEqual(len(res11), 1)
+ def test_base_lower(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="OU=OU11,DC=samba,DC=org",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res11), 1)
+
def test_base_or(self):
"""Testing a search"""
@@ -746,7 +794,16 @@ class SearchTests(TestCase):
def test_check_base_error(self):
"""Testing a search"""
- self.l.add({"dn": "@OPTIONS", "checkBaseOnSearch": b"TRUE"})
+ checkbaseonsearch = {"dn": "@OPTIONS",
+ "checkBaseOnSearch": b"TRUE"}
+ try:
+ self.l.add(checkbaseonsearch)
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
+ m = ldb.Message.from_dict(self.l,
+ checkbaseonsearch)
+ self.l.modify(m)
try:
res11 = self.l.search(base="OU=OU11x,DC=SAMBA,DC=ORG",
@@ -773,6 +830,14 @@ class SearchTests(TestCase):
expression="(&(x=y)(|(y=b)(y=c)))")
self.assertEqual(len(res11), 1)
+ def test_subtree_and2_lower(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=samba,DC=org",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(x=y)(|(y=b)(y=c)))")
+ self.assertEqual(len(res11), 1)
+
def test_subtree_or(self):
"""Testing a search"""
@@ -829,6 +894,14 @@ class SearchTests(TestCase):
expression="(|(x=y)(y=b))")
self.assertEqual(len(res11), 20)
+ def test_one_or2_lower(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=samba,DC=org",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(|(x=y)(y=b))")
+ self.assertEqual(len(res11), 20)
+
def test_subtree_and_or(self):
"""Testing a search"""
@@ -893,6 +966,70 @@ class SearchTests(TestCase):
expression="(&(ou=ouX)(y=a))")
self.assertEqual(len(res11), 0)
+ def test_subtree_and_idx_record(self):
+ """Testing a search against the index record"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(@IDXDN=DC=SAMBA,DC=ORG)")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_and_idxone_record(self):
+ """Testing a search against the index record"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(@IDXONE=DC=SAMBA,DC=ORG)")
+ self.assertEqual(len(res11), 0)
+
+ def test_dn_filter_one(self):
+ """Testing that a dn= filter succeeds
+ (or fails with disallowDNFilter
+ set and IDXGUID or (IDX and not IDXONE) mode)
+ when the scope is SCOPE_ONELEVEL.
+
+ This should be made more consistent, but for now lock in
+ the behaviour
+
+ """
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(dn=OU=OU1,DC=SAMBA,DC=ORG)")
+ if hasattr(self, 'disallowDNFilter') and \
+ hasattr(self, 'IDX') and \
+ (hasattr(self, 'IDXGUID') or \
+ ((hasattr(self, 'IDXONE') == False and hasattr(self, 'IDX')))):
+ self.assertEqual(len(res11), 0)
+ else:
+ self.assertEqual(len(res11), 1)
+
+ def test_dn_filter_subtree(self):
+ """Testing that a dn= filter succeeds
+ (or fails with disallowDNFilter set)
+ when the scope is SCOPE_SUBTREE"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(dn=OU=OU1,DC=SAMBA,DC=ORG)")
+ if hasattr(self, 'disallowDNFilter') \
+ and hasattr(self, 'IDX'):
+ self.assertEqual(len(res11), 0)
+ else:
+ self.assertEqual(len(res11), 1)
+
+ def test_dn_filter_base(self):
+ """Testing that (incorrectly) a dn= filter works
+ when the scope is SCOPE_BASE"""
+
+ res11 = self.l.search(base="OU=OU1,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(dn=OU=OU1,DC=SAMBA,DC=ORG)")
+
+ # At some point we should fix this, but it isn't trivial
+ self.assertEqual(len(res11), 1)
+
+
class IndexedSearchTests(SearchTests):
"""Test searches using the index, to ensure the index doesn't
@@ -900,8 +1037,345 @@ class IndexedSearchTests(SearchTests):
def setUp(self):
super(IndexedSearchTests, self).setUp()
self.l.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"]})
+ self.IDX = True
+
+class IndexedSearchDnFilterTests(SearchTests):
+ """Test searches using the index, to ensure the index doesn't
+ break things"""
+ def setUp(self):
+ super(IndexedSearchDnFilterTests, self).setUp()
+ self.l.add({"dn": "@OPTIONS",
+ "disallowDNFilter": "TRUE"})
+ self.disallowDNFilter = True
+
+ self.l.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"]})
+ self.IDX = True
+
+class IndexedAndOneLevelSearchTests(SearchTests):
+ """Test searches using the index including @IDXONE, to ensure
+ the index doesn't break things"""
+ def setUp(self):
+ super(IndexedAndOneLevelSearchTests, self).setUp()
+ self.l.add({"dn": "@INDEXLIST",
"@IDXATTR": [b"x", b"y", b"ou"],
"@IDXONE": [b"1"]})
+ self.IDX = True
+
+class IndexedAndOneLevelDNFilterSearchTests(SearchTests):
+ """Test searches using the index including @IDXONE, to ensure
+ the index doesn't break things"""
+ def setUp(self):
+ super(IndexedAndOneLevelDNFilterSearchTests, self).setUp()
+ self.l.add({"dn": "@OPTIONS",
+ "disallowDNFilter": "TRUE"})
+ self.disallowDNFilter = True
+
+ self.l.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"],
+ "@IDXONE": [b"1"]})
+ self.IDX = True
+ self.IDXONE = True
+
+class GUIDIndexedSearchTests(SearchTests):
+ """Test searches using the index, to ensure the index doesn't
+ break things"""
+ def setUp(self):
+ super(GUIDIndexedSearchTests, self).setUp()
+
+ self.l.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]})
+ self.IDXGUID = True
+ self.IDXONE = True
+
+class GUIDIndexedDNFilterSearchTests(SearchTests):
+ """Test searches using the index, to ensure the index doesn't
+ break things"""
+ def setUp(self):
+ super(GUIDIndexedDNFilterSearchTests, self).setUp()
+ self.l.add({"dn": "@OPTIONS",
+ "disallowDNFilter": "TRUE"})
+ self.disallowDNFilter = True
+
+ self.l.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]})
+ self.IDX = True
+ self.IDXGUID = True
+
+class GUIDAndOneLevelIndexedSearchTests(SearchTests):
+ """Test searches using the index including @IDXONE, to ensure
+ the index doesn't break things"""
+ def setUp(self):
+ super(GUIDAndOneLevelIndexedSearchTests, self).setUp()
+ self.l.add({"dn": "@OPTIONS",
+ "disallowDNFilter": "TRUE"})
+ self.disallowDNFilter = True
+
+ self.l.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"],
+ "@IDXONE": [b"1"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]})
+ self.IDX = True
+ self.IDXGUID = True
+ self.IDXONE = True
+
+
+class AddModifyTests(TestCase):
+ def tearDown(self):
+ shutil.rmtree(self.testdir)
+ super(AddModifyTests, self).tearDown()
+
+ # Ensure the LDB is closed now, so we close the FD
+ del(self.l)
+
+ def setUp(self):
+ super(AddModifyTests, self).setUp()
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "add_test.ldb")
+ self.l = ldb.Ldb(self.filename, options=["modules:rdn_name"])
+ self.l.add({"dn": "DC=SAMBA,DC=ORG",
+ "name": b"samba.org",
+ "objectUUID": b"0123456789abcdef"})
+ self.l.add({"dn": "@ATTRIBUTES",
+ "objectUUID": "UNIQUE_INDEX"})
+
+ def test_add_dup(self):
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde1"})
+ try:
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
+ self.fail("Should have failed adding dupliate entry")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
+
+ def test_add_del_add(self):
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde1"})
+ self.l.delete("OU=DUP,DC=SAMBA,DC=ORG")
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
+
+ def test_add_move_add(self):
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde1"})
+ self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
+ "OU=DUP2,DC=SAMBA,DC=ORG")
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
+
+ def test_add_move_fail_move_move(self):
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde1"})
+ self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
+ try:
+ self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
+ "OU=DUP2,DC=SAMBA,DC=ORG")
+ self.fail("Should have failed on duplicate DN")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
+
+ self.l.rename("OU=DUP2,DC=SAMBA,DC=ORG",
+ "OU=DUP3,DC=SAMBA,DC=ORG")
+
+ self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
+ "OU=DUP2,DC=SAMBA,DC=ORG")
+
+ res2 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(objectUUID=0123456789abcde1)")
+ self.assertEqual(len(res2), 1)
+ self.assertEqual(str(res2[0].dn), "OU=DUP2,DC=SAMBA,DC=ORG")
+
+ res3 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(objectUUID=0123456789abcde2)")
+ self.assertEqual(len(res3), 1)
+ self.assertEqual(str(res3[0].dn), "OU=DUP3,DC=SAMBA,DC=ORG")
+
+ def test_move_missing(self):
+ try:
+ self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
+ "OU=DUP2,DC=SAMBA,DC=ORG")
+ self.fail("Should have failed on missing")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_NO_SUCH_OBJECT)
+
+ def test_move_missing2(self):
+ self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
+
+ try:
+ self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
+ "OU=DUP2,DC=SAMBA,DC=ORG")
+ self.fail("Should have failed on missing")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_NO_SUCH_OBJECT)
+
+ def test_move_fail_move_add(self):
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde1"})
+ self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
+ try:
+ self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
+ "OU=DUP2,DC=SAMBA,DC=ORG")
+ self.fail("Should have failed on duplicate DN")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
+
+ self.l.rename("OU=DUP2,DC=SAMBA,DC=ORG",
+ "OU=DUP3,DC=SAMBA,DC=ORG")
+
+ self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde3"})
+
+class IndexedAddModifyTests(AddModifyTests):
+ """Test searches using the index, to ensure the index doesn't
+ break things"""
+ def setUp(self):
+ super(IndexedAddModifyTests, self).setUp()
+ self.l.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou", b"objectUUID"],
+ "@IDXONE": [b"1"]})
+
+ def test_duplicate_GUID(self):
+ try:
+ self.l.add({"dn": "OU=DUPGUID,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcdef"})
+ self.fail("Should have failed adding dupliate GUID")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_CONSTRAINT_VIOLATION)
+
+ def test_duplicate_name_dup_GUID(self):
+ self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"a123456789abcdef"})
+ try:
+ self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"a123456789abcdef"})
+ self.fail("Should have failed adding dupliate GUID")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
+
+ def test_duplicate_name_dup_GUID2(self):
+ self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"abc3456789abcdef"})
+ try:
+ self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"aaa3456789abcdef"})
+ self.fail("Should have failed adding dupliate DN")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
+
+ # Checking the GUID didn't stick in the index
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"aaa3456789abcdef"})
+
+ def test_add_dup_guid_add(self):
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde1"})
+ try:
+ self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde1"})
+ self.fail("Should have failed on duplicate GUID")
+
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_CONSTRAINT_VIOLATION)
+
+ self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
+
+class GUIDIndexedAddModifyTests(IndexedAddModifyTests):
+ """Test searches using the index, to ensure the index doesn't
+ break things"""
+ def setUp(self):
+ super(GUIDIndexedAddModifyTests, self).setUp()
+ indexlist = {"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"],
+ "@IDXONE": [b"1"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]}
+ m = ldb.Message.from_dict(self.l, indexlist, ldb.FLAG_MOD_REPLACE)
+ self.l.modify(m)
+
+
+class GUIDTransIndexedAddModifyTests(GUIDIndexedAddModifyTests):
+ """Test GUID index behaviour insdie the transaction"""
+ def setUp(self):
+ super(GUIDTransIndexedAddModifyTests, self).setUp()
+ self.l.transaction_start()
+
+ def tearDown(self):
+ self.l.transaction_commit()
+ super(GUIDTransIndexedAddModifyTests, self).tearDown()
+
+class TransIndexedAddModifyTests(IndexedAddModifyTests):
+ """Test index behaviour insdie the transaction"""
+ def setUp(self):
+ super(TransIndexedAddModifyTests, self).setUp()
+ self.l.transaction_start()
+
+ def tearDown(self):
+ self.l.transaction_commit()
+ super(TransIndexedAddModifyTests, self).tearDown()
@@ -909,13 +1383,11 @@ class DnTests(TestCase):
def setUp(self):
super(DnTests, self).setUp()
- self.testdir = tempdir()
- self.filename = os.path.join(self.testdir, "test.ldb")
- self.ldb = ldb.Ldb(self.filename)
+ self.ldb = ldb.Ldb()
def tearDown(self):
- shutil.rmtree(self.testdir)
super(DnTests, self).tearDown()
+ del(self.ldb)
def test_set_dn_invalid(self):
x = ldb.Message()
@@ -1040,9 +1512,11 @@ class DnTests(TestCase):
dn3 = ldb.Dn(self.ldb, "cn=bar,dc=base")
dn4 = ldb.Dn(self.ldb, "cn=baz,cn=bar,dc=base")
+ self.assertTrue(dn1.is_child_of(dn1))
self.assertTrue(dn2.is_child_of(dn1))
self.assertTrue(dn4.is_child_of(dn1))
self.assertTrue(dn4.is_child_of(dn3))
+ self.assertTrue(dn4.is_child_of(dn4))
self.assertFalse(dn3.is_child_of(dn2))
self.assertFalse(dn1.is_child_of(dn4))
@@ -1058,9 +1532,11 @@ class DnTests(TestCase):
dn3 = ldb.Dn(self.ldb, dn3_str)
dn4 = ldb.Dn(self.ldb, dn4_str)
+ self.assertTrue(dn1.is_child_of(dn1_str))
self.assertTrue(dn2.is_child_of(dn1_str))
self.assertTrue(dn4.is_child_of(dn1_str))
self.assertTrue(dn4.is_child_of(dn3_str))
+ self.assertTrue(dn4.is_child_of(dn4_str))
self.assertFalse(dn3.is_child_of(dn2_str))
self.assertFalse(dn1.is_child_of(dn4_str))
@@ -1150,12 +1626,6 @@ class LdbMsgTests(TestCase):
def setUp(self):
super(LdbMsgTests, self).setUp()
self.msg = ldb.Message()
- self.testdir = tempdir()
- self.filename = os.path.join(self.testdir, "test.ldb")
-
- def tearDown(self):
- shutil.rmtree(self.testdir)
- super(LdbMsgTests, self).tearDown()
def test_init_dn(self):
self.msg = ldb.Message(ldb.Dn(ldb.Ldb(), "dc=foo27"))
@@ -1163,11 +1633,11 @@ class LdbMsgTests(TestCase):
def test_iter_items(self):
self.assertEqual(0, len(self.msg.items()))
- self.msg.dn = ldb.Dn(ldb.Ldb(self.filename), "dc=foo28")
+ self.msg.dn = ldb.Dn(ldb.Ldb(), "dc=foo28")
self.assertEqual(1, len(self.msg.items()))
def test_repr(self):
- self.msg.dn = ldb.Dn(ldb.Ldb(self.filename), "dc=foo29")
+ self.msg.dn = ldb.Dn(ldb.Ldb(), "dc=foo29")
self.msg["dc"] = b"foo"
if PY3:
self.assertIn(repr(self.msg), [
@@ -1245,37 +1715,37 @@ class LdbMsgTests(TestCase):
self.assertEqual(["bar"], list(self.msg.text["foo"]))
def test_keys(self):
- self.msg.dn = ldb.Dn(ldb.Ldb(self.filename), "@BASEINFO")
+ self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
self.msg["foo"] = [b"bla"]
self.msg["bar"] = [b"bla"]
self.assertEqual(["dn", "foo", "bar"], self.msg.keys())
def test_keys_text(self):
- self.msg.dn = ldb.Dn(ldb.Ldb(self.filename), "@BASEINFO")
+ self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
self.msg["foo"] = ["bla"]
self.msg["bar"] = ["bla"]
self.assertEqual(["dn", "foo", "bar"], self.msg.text.keys())
def test_dn(self):
- self.msg.dn = ldb.Dn(ldb.Ldb(self.filename), "@BASEINFO")
+ self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
self.assertEqual("@BASEINFO", self.msg.dn.__str__())
def test_get_dn(self):
- self.msg.dn = ldb.Dn(ldb.Ldb(self.filename), "@BASEINFO")
+ self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
self.assertEqual("@BASEINFO", self.msg.get("dn").__str__())
def test_dn_text(self):
- self.msg.text.dn = ldb.Dn(ldb.Ldb(self.filename), "@BASEINFO")
+ self.msg.text.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
self.assertEqual("@BASEINFO", str(self.msg.dn))
self.assertEqual("@BASEINFO", str(self.msg.text.dn))
def test_get_dn_text(self):
- self.msg.dn = ldb.Dn(ldb.Ldb(self.filename), "@BASEINFO")
+ self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
self.assertEqual("@BASEINFO", str(self.msg.get("dn")))
self.assertEqual("@BASEINFO", str(self.msg.text.get("dn")))
def test_get_invalid(self):
- self.msg.dn = ldb.Dn(ldb.Ldb(self.filename), "@BASEINFO")
+ self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
self.assertRaises(TypeError, self.msg.get, 42)
def test_get_other(self):
@@ -1323,7 +1793,7 @@ class LdbMsgTests(TestCase):
self.assertEqual(msg1, msg2)
def test_equal_simplel(self):
- db = ldb.Ldb(self.filename)
+ db = ldb.Ldb()
msg1 = ldb.Message()
msg1.dn = ldb.Dn(db, "foo=bar")
msg2 = ldb.Message()
@@ -1543,6 +2013,8 @@ class LdbResultTests(TestCase):
def tearDown(self):
shutil.rmtree(self.testdir)
super(LdbResultTests, self).tearDown()
+ # Ensure the LDB is closed now, so we close the FD
+ del(self.l)
def test_return_type(self):
res = self.l.search()
diff --git a/tests/test-generic.sh b/tests/test-generic.sh
index e1f8e79..8177da5 100755
--- a/tests/test-generic.sh
+++ b/tests/test-generic.sh
@@ -119,16 +119,20 @@ echo "*TODO* Testing UTF8 upper lower case searches !!"
echo "Testing compare"
count=`$VALGRIND ldbsearch '(cn>=t)' cn | grep '^dn' | wc -l`
-if [ $count != 2 ]; then
- echo returned $count records - expected 2
- echo "this fails on openLdap ..."
+if [ $count != 1 ]; then
+ # only "cn: test_multi_test_multi_test_multi" (comes after "t")
+ # upper-cased words come before "t" - hence excluded
+ echo returned $count records - expected 1
+ exit 1
fi
$VALGRIND ldbsearch '(cn>t)' cn && exit 1 # strictly greater should not work
count=`$VALGRIND ldbsearch '(cn<=t)' cn | grep '^dn' | wc -l`
-if [ $count != 13 ]; then
- echo returned $count records - expected 13
- echo "this fails on openLdap ..."
+if [ $count != 18 ]; then
+ # everything except "cn: test_multi_test_multi_test_multi" (comes after "t")
+ # upper-cased letters come before "t" - hence included
+ echo returned $count records - expected 18
+ exit 1
fi
$VALGRIND ldbsearch '(cn<t)' cn && exit 1 # strictly less should not work
@@ -140,7 +144,6 @@ checkcount() {
n=`$VALGRIND ldbsearch -s "$scope" -b "$basedn" "$expression" | grep '^dn' | wc -l`
if [ $n != $count ]; then
echo "Got $n but expected $count for $expression"
- bin/ldbsearch "$expression"
exit 1
fi
echo "OK: $count $expression"
diff --git a/wscript b/wscript
index 5ea5231..6a204c0 100644
--- a/wscript
+++ b/wscript
@@ -1,7 +1,7 @@
#!/usr/bin/env python
APPNAME = 'ldb'
-VERSION = '1.2.3'
+VERSION = '1.3.2'
blddir = 'bin'
@@ -21,6 +21,7 @@ samba_dist.DIST_DIRS('''lib/ldb:. lib/replace:lib/replace lib/talloc:lib/talloc
third_party/cmocka:third_party/cmocka
buildtools:buildtools third_party/waf:third_party/waf''')
+samba_dist.DIST_FILES('''lib/util/binsearch.h:lib/util/binsearch.h''')
def set_options(opt):
opt.BUILTIN_DEFAULT('replace')