summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarolin Seeger <kseeger@samba.org>2020-04-28 13:50:10 +0200
committerKarolin Seeger <kseeger@samba.org>2020-04-28 13:50:10 +0200
commit94c0fbebc6cf32b82e3b25a1f254e22efbc3fcdf (patch)
treeca120a420e7e9cb2a8fda38d17c914d72a9c8b1b
parent34bfaafc77e35c8808452f678111c73bbbdd705d (diff)
parent86c951a1336b2073f35c9ccc16673b6f99251fcc (diff)
downloadsamba-94c0fbebc6cf32b82e3b25a1f254e22efbc3fcdf.tar.gz
Merge tag 'samba-4.11.8' into v4-11-test
samba: tag release samba-4.11.8
-rw-r--r--WHATSNEW.txt65
-rw-r--r--auth/gensec/gensec_util.c2
-rw-r--r--docs-xml/smbdotconf/ldap/ldapmaxanonrequest.xml18
-rw-r--r--docs-xml/smbdotconf/ldap/ldapmaxauthrequest.xml18
-rw-r--r--docs-xml/smbdotconf/ldap/ldapmaxsearchrequest.xml18
-rw-r--r--lib/ldb/ABI/ldb-2.0.10.sigs283
-rw-r--r--lib/ldb/ABI/pyldb-util-2.0.10.sigs2
-rw-r--r--lib/ldb/modules/asq.c12
-rw-r--r--lib/ldb/wscript2
-rw-r--r--lib/param/loadparm.c7
-rw-r--r--lib/util/asn1.c37
-rw-r--r--lib/util/asn1.h10
-rw-r--r--lib/util/tests/asn1_tests.c2
-rw-r--r--libcli/auth/spnego_parse.c6
-rw-r--r--libcli/cldap/cldap.c20
-rw-r--r--libcli/ldap/ldap_message.c7
-rw-r--r--libcli/ldap/ldap_message.h5
-rw-r--r--libcli/ldap/tests/data/10000-or.datbin0 -> 39875 bytes
-rw-r--r--libcli/ldap/tests/data/ldap-recursive.datbin0 -> 970 bytes
-rw-r--r--libcli/ldap/tests/ldap_message_test.c287
-rw-r--r--libcli/ldap/wscript_build15
-rw-r--r--python/samba/tests/ldap_raw.py234
-rw-r--r--source3/lib/tldap.c4
-rw-r--r--source3/lib/tldap_util.c4
-rw-r--r--source3/libsmb/clispnego.c4
-rw-r--r--source3/param/loadparm.c4
-rw-r--r--source3/torture/torture.c2
-rw-r--r--source4/auth/gensec/gensec_krb5.c4
-rw-r--r--source4/dsdb/samdb/ldb_modules/paged_results.c18
-rw-r--r--source4/dsdb/tests/python/asq.py171
-rw-r--r--source4/ldap_server/ldap_server.c108
-rw-r--r--source4/libcli/ldap/ldap_client.c5
-rw-r--r--source4/libcli/ldap/ldap_controls.c48
-rwxr-xr-xsource4/selftest/tests.py8
34 files changed, 1362 insertions, 68 deletions
diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index 89e730b605e..3502516273e 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -1,4 +1,65 @@
==============================
+ Release Notes for Samba 4.11.8
+ April 28, 2020
+ ==============================
+
+
+This is a security release in order to address the following defects:
+
+o CVE-2020-10700: Use-after-free in Samba AD DC LDAP Server with ASQ
+o CVE-2020-10704: LDAP Denial of Service (stack overflow) in Samba AD DC
+
+
+=======
+Details
+=======
+
+o CVE-2020-10700:
+ A client combining the 'ASQ' and 'Paged Results' LDAP controls can cause a
+ use-after-free in Samba's AD DC LDAP server.
+o CVE-2020-10704:
+ A deeply nested filter in an un-authenticated LDAP search can exhaust the
+ LDAP server's stack memory causing a SIGSEGV.
+
+For more details, please refer to the security advisories.
+
+
+Changes since 4.11.7
+--------------------
+
+o Andrew Bartlett <abartlet@samba.org>
+ * BUG 14331: CVE-2020-10700: Fix use-after-free in AD DC LDAP server when
+ ASQ and paged_results combined.
+
+o Gary Lockyer <gary@catalyst.net.nz>
+ * BUG 20454: CVE-2020-10704: Fix LDAP Denial of Service (stack overflow) in
+ Samba AD DC.
+
+
+#######################################
+Reporting bugs & Development Discussion
+#######################################
+
+Please discuss this release on the samba-technical mailing list or by
+joining the #samba-technical IRC channel on irc.freenode.net.
+
+If you do report problems then please try to send high quality
+feedback. If you don't provide vital information to help us track down
+the problem then you will probably be ignored. All bug reports should
+be filed under the "Samba 4.1 and newer" product in the project's Bugzilla
+database (https://bugzilla.samba.org/).
+
+
+======================================================================
+== Our Code, Our Bugs, Our Responsibility.
+== The Samba Team
+======================================================================
+
+
+Release notes for older releases follow:
+----------------------------------------
+
+ ==============================
Release Notes for Samba 4.11.7
March 10, 2020
==============================
@@ -59,8 +120,8 @@ database (https://bugzilla.samba.org/).
======================================================================
-Release notes for older releases follow:
-----------------------------------------
+----------------------------------------------------------------------
+
==============================
Release Notes for Samba 4.11.6
diff --git a/auth/gensec/gensec_util.c b/auth/gensec/gensec_util.c
index 20c9c2a1fbb..e185acc0c20 100644
--- a/auth/gensec/gensec_util.c
+++ b/auth/gensec/gensec_util.c
@@ -76,7 +76,7 @@ NTSTATUS gensec_generate_session_info_pac(TALLOC_CTX *mem_ctx,
static bool gensec_gssapi_check_oid(const DATA_BLOB *blob, const char *oid)
{
bool ret = false;
- struct asn1_data *data = asn1_init(NULL);
+ struct asn1_data *data = asn1_init(NULL, ASN1_MAX_TREE_DEPTH);
if (!data) return false;
diff --git a/docs-xml/smbdotconf/ldap/ldapmaxanonrequest.xml b/docs-xml/smbdotconf/ldap/ldapmaxanonrequest.xml
new file mode 100644
index 00000000000..61bdcec674d
--- /dev/null
+++ b/docs-xml/smbdotconf/ldap/ldapmaxanonrequest.xml
@@ -0,0 +1,18 @@
+<samba:parameter name="ldap max anonymous request size"
+ context="G"
+ type="integer"
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+ <para>
+ This parameter specifies the maximum permitted size (in bytes)
+ for an LDAP request received on an anonymous connection.
+ </para>
+
+ <para>
+ If the request size exceeds this limit the request will be
+ rejected.
+ </para>
+</description>
+<value type="default">256000</value>
+<value type="example">500000</value>
+</samba:parameter>
diff --git a/docs-xml/smbdotconf/ldap/ldapmaxauthrequest.xml b/docs-xml/smbdotconf/ldap/ldapmaxauthrequest.xml
new file mode 100644
index 00000000000..c5934f73f95
--- /dev/null
+++ b/docs-xml/smbdotconf/ldap/ldapmaxauthrequest.xml
@@ -0,0 +1,18 @@
+<samba:parameter name="ldap max authenticated request size"
+ context="G"
+ type="integer"
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+ <para>
+ This parameter specifies the maximum permitted size (in bytes)
+ for an LDAP request received on an authenticated connection.
+ </para>
+
+ <para>
+ If the request size exceeds this limit the request will be
+ rejected.
+ </para>
+</description>
+<value type="default">16777216</value>
+<value type="example">4194304</value>
+</samba:parameter>
diff --git a/docs-xml/smbdotconf/ldap/ldapmaxsearchrequest.xml b/docs-xml/smbdotconf/ldap/ldapmaxsearchrequest.xml
new file mode 100644
index 00000000000..ebeb0816c01
--- /dev/null
+++ b/docs-xml/smbdotconf/ldap/ldapmaxsearchrequest.xml
@@ -0,0 +1,18 @@
+<samba:parameter name="ldap max search request size"
+ context="G"
+ type="integer"
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+ <para>
+ This parameter specifies the maximum permitted size (in bytes)
+ for an LDAP search request.
+ </para>
+
+ <para>
+ If the request size exceeds this limit the request will be
+ rejected.
+ </para>
+</description>
+<value type="default">256000</value>
+<value type="example">4194304</value>
+</samba:parameter>
diff --git a/lib/ldb/ABI/ldb-2.0.10.sigs b/lib/ldb/ABI/ldb-2.0.10.sigs
new file mode 100644
index 00000000000..5049dc64ce1
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.0.10.sigs
@@ -0,0 +1,283 @@
+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_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+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_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+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_copy: const char **(TALLOC_CTX *, const char **)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_options_get: const char **(struct ldb_context *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+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_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+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/lib/ldb/ABI/pyldb-util-2.0.10.sigs b/lib/ldb/ABI/pyldb-util-2.0.10.sigs
new file mode 100644
index 00000000000..74d6719d2bc
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.0.10.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/lib/ldb/modules/asq.c b/lib/ldb/modules/asq.c
index 7482de826f0..4eba941ae0b 100644
--- a/lib/ldb/modules/asq.c
+++ b/lib/ldb/modules/asq.c
@@ -311,12 +311,9 @@ static int asq_build_multiple_requests(struct asq_context *ac, bool *terminated)
static int asq_search_continue(struct asq_context *ac)
{
- struct ldb_context *ldb;
bool terminated = false;
int ret;
- ldb = ldb_module_get_ctx(ac->module);
-
switch (ac->step) {
case ASQ_SEARCH_BASE:
@@ -328,7 +325,7 @@ static int asq_search_continue(struct asq_context *ac)
ac->step = ASQ_SEARCH_MULTI;
- return ldb_request(ldb, ac->reqs[ac->cur_req]);
+ return ldb_next_request(ac->module, ac->reqs[ac->cur_req]);
case ASQ_SEARCH_MULTI:
@@ -339,7 +336,7 @@ static int asq_search_continue(struct asq_context *ac)
return asq_search_terminate(ac);
}
- return ldb_request(ldb, ac->reqs[ac->cur_req]);
+ return ldb_next_request(ac->module, ac->reqs[ac->cur_req]);
}
return LDB_ERR_OPERATIONS_ERROR;
@@ -347,14 +344,11 @@ static int asq_search_continue(struct asq_context *ac)
static int asq_search(struct ldb_module *module, struct ldb_request *req)
{
- struct ldb_context *ldb;
struct ldb_request *base_req;
struct ldb_control *control;
struct asq_context *ac;
int ret;
- ldb = ldb_module_get_ctx(module);
-
/* check if there's an ASQ control */
control = ldb_request_get_control(req, LDB_CONTROL_ASQ_OID);
if (control == NULL) {
@@ -385,7 +379,7 @@ static int asq_search(struct ldb_module *module, struct ldb_request *req)
ac->step = ASQ_SEARCH_BASE;
- return ldb_request(ldb, base_req);
+ return ldb_next_request(ac->module, base_req);
}
static int asq_init(struct ldb_module *module)
diff --git a/lib/ldb/wscript b/lib/ldb/wscript
index c3f2f42b8c1..43571a7593f 100644
--- a/lib/ldb/wscript
+++ b/lib/ldb/wscript
@@ -1,7 +1,7 @@
#!/usr/bin/env python
APPNAME = 'ldb'
-VERSION = '2.0.9'
+VERSION = '2.0.10'
import sys, os
diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c
index 883d4167bf4..e0c6adec9c8 100644
--- a/lib/param/loadparm.c
+++ b/lib/param/loadparm.c
@@ -3025,6 +3025,13 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
lpcfg_do_global_parameter(lp_ctx, "debug encryption", "no");
+ lpcfg_do_global_parameter(
+ lp_ctx, "ldap max anonymous request size", "256000");
+ lpcfg_do_global_parameter(
+ lp_ctx, "ldap max authenticated request size", "16777216");
+ lpcfg_do_global_parameter(
+ lp_ctx, "ldap max search request size", "256000");
+
for (i = 0; parm_table[i].label; i++) {
if (!(lp_ctx->flags[i] & FLAG_CMDLINE)) {
lp_ctx->flags[i] |= FLAG_DEFAULT;
diff --git a/lib/util/asn1.c b/lib/util/asn1.c
index 51da5424956..32d7981d28f 100644
--- a/lib/util/asn1.c
+++ b/lib/util/asn1.c
@@ -36,15 +36,19 @@ struct asn1_data {
off_t ofs;
struct nesting *nesting;
bool has_error;
+ unsigned depth;
+ unsigned max_depth;
};
/* allocate an asn1 structure */
-struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx)
+struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx, unsigned max_depth)
{
struct asn1_data *ret = talloc_zero(mem_ctx, struct asn1_data);
if (ret == NULL) {
DEBUG(0,("asn1_init failed! out of memory\n"));
+ return ret;
}
+ ret->max_depth = max_depth;
return ret;
}
@@ -480,6 +484,11 @@ bool asn1_check_BOOLEAN(struct asn1_data *data, bool v)
/* load a struct asn1_data structure with a lump of data, ready to be parsed */
bool asn1_load(struct asn1_data *data, DATA_BLOB blob)
{
+ /*
+ * Save the maximum depth
+ */
+ unsigned max_depth = data->max_depth;
+
ZERO_STRUCTP(data);
data->data = (uint8_t *)talloc_memdup(data, blob.data, blob.length);
if (!data->data) {
@@ -487,6 +496,7 @@ bool asn1_load(struct asn1_data *data, DATA_BLOB blob)
return false;
}
data->length = blob.length;
+ data->max_depth = max_depth;
return true;
}
@@ -637,6 +647,16 @@ bool asn1_start_tag(struct asn1_data *data, uint8_t tag)
uint8_t b;
struct nesting *nesting;
+ /*
+ * Check the depth of the parse tree and prevent it from growing
+ * too large.
+ */
+ data->depth++;
+ if (data->depth > data->max_depth) {
+ data->has_error = true;
+ return false;
+ }
+
if (!asn1_read_uint8(data, &b))
return false;
@@ -693,6 +713,9 @@ bool asn1_end_tag(struct asn1_data *data)
{
struct nesting *nesting;
+ if (data->depth > 0) {
+ data->depth--;
+ }
/* make sure we read it all */
if (asn1_tag_remaining(data) != 0) {
data->has_error = true;
@@ -1103,9 +1126,14 @@ bool asn1_extract_blob(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
*/
void asn1_load_nocopy(struct asn1_data *data, uint8_t *buf, size_t len)
{
+ /*
+ * Save max_depth
+ */
+ unsigned max_depth = data->max_depth;
ZERO_STRUCTP(data);
data->data = buf;
data->length = len;
+ data->max_depth = max_depth;
}
int asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size)
@@ -1131,3 +1159,10 @@ int asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size)
*packet_size = size;
return 0;
}
+
+/*
+ * Get the length of the ASN.1 data
+ */
+size_t asn1_get_length(const struct asn1_data *asn1) {
+ return asn1->length;
+}
diff --git a/lib/util/asn1.h b/lib/util/asn1.h
index ddd69863574..de92a767f14 100644
--- a/lib/util/asn1.h
+++ b/lib/util/asn1.h
@@ -45,7 +45,14 @@ typedef struct asn1_data ASN1_DATA;
#define ASN1_MAX_OIDS 20
-struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx);
+/*
+ * The maximum permitted depth for an ASN.1 parse tree, the limit is chosen
+ * to align with the value for windows. Note that this value will trigger
+ * ASAN stack overflow errors.
+ */
+#define ASN1_MAX_TREE_DEPTH 512
+
+struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx, unsigned max_depth);
void asn1_free(struct asn1_data *data);
bool asn1_has_error(const struct asn1_data *data);
void asn1_set_error(struct asn1_data *data);
@@ -99,5 +106,6 @@ bool asn1_extract_blob(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
DATA_BLOB *pblob);
void asn1_load_nocopy(struct asn1_data *data, uint8_t *buf, size_t len);
int asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size);
+size_t asn1_get_length(const struct asn1_data *asn1);
#endif /* _ASN_1_H */
diff --git a/lib/util/tests/asn1_tests.c b/lib/util/tests/asn1_tests.c
index e4b386ad785..ab5262c4ffb 100644
--- a/lib/util/tests/asn1_tests.c
+++ b/lib/util/tests/asn1_tests.c
@@ -330,7 +330,7 @@ static bool test_asn1_Integer(struct torture_context *tctx)
DATA_BLOB blob;
int val;
- data = asn1_init(mem_ctx);
+ data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
if (!data) {
goto err;
}
diff --git a/libcli/auth/spnego_parse.c b/libcli/auth/spnego_parse.c
index f538b44552c..f7f19b10778 100644
--- a/libcli/auth/spnego_parse.c
+++ b/libcli/auth/spnego_parse.c
@@ -296,7 +296,7 @@ ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data
return ret;
}
- asn1 = asn1_init(mem_ctx);
+ asn1 = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
if (asn1 == NULL) {
return -1;
}
@@ -339,7 +339,7 @@ ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data
ssize_t spnego_write_data(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct spnego_data *spnego)
{
- struct asn1_data *asn1 = asn1_init(mem_ctx);
+ struct asn1_data *asn1 = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
ssize_t ret = -1;
if (asn1 == NULL) {
@@ -411,7 +411,7 @@ bool spnego_write_mech_types(TALLOC_CTX *mem_ctx,
DATA_BLOB *blob)
{
bool ret = false;
- struct asn1_data *asn1 = asn1_init(mem_ctx);
+ struct asn1_data *asn1 = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
if (asn1 == NULL) {
return false;
diff --git a/libcli/cldap/cldap.c b/libcli/cldap/cldap.c
index daba37a21d7..25c1b40f8d9 100644
--- a/libcli/cldap/cldap.c
+++ b/libcli/cldap/cldap.c
@@ -111,6 +111,11 @@ struct cldap_search_state {
struct tevent_req *req;
};
+/*
+ * For CLDAP we limit the maximum search request size to 4kb
+ */
+#define MAX_SEARCH_REQUEST 4096
+
static int cldap_socket_destructor(struct cldap_socket *c)
{
while (c->searches.list) {
@@ -224,12 +229,15 @@ static bool cldap_socket_recv_dgram(struct cldap_socket *c,
void *p;
struct cldap_search_state *search;
NTSTATUS status;
+ struct ldap_request_limits limits = {
+ .max_search_size = MAX_SEARCH_REQUEST
+ };
if (in->recv_errno != 0) {
goto error;
}
- asn1 = asn1_init(in);
+ asn1 = asn1_init(in, ASN1_MAX_TREE_DEPTH);
if (!asn1) {
goto nomem;
}
@@ -242,7 +250,7 @@ static bool cldap_socket_recv_dgram(struct cldap_socket *c,
}
/* this initial decode is used to find the message id */
- status = ldap_decode(asn1, NULL, in->ldap_msg);
+ status = ldap_decode(asn1, &limits, NULL, in->ldap_msg);
if (!NT_STATUS_IS_OK(status)) {
goto nterror;
}
@@ -770,6 +778,9 @@ NTSTATUS cldap_search_recv(struct tevent_req *req,
struct cldap_search_state);
struct ldap_message *ldap_msg;
NTSTATUS status;
+ struct ldap_request_limits limits = {
+ .max_search_size = MAX_SEARCH_REQUEST
+ };
if (tevent_req_is_nterror(req, &status)) {
goto failed;
@@ -780,7 +791,7 @@ NTSTATUS cldap_search_recv(struct tevent_req *req,
goto nomem;
}
- status = ldap_decode(state->response.asn1, NULL, ldap_msg);
+ status = ldap_decode(state->response.asn1, &limits, NULL, ldap_msg);
if (!NT_STATUS_IS_OK(status)) {
goto failed;
}
@@ -796,7 +807,8 @@ NTSTATUS cldap_search_recv(struct tevent_req *req,
*io->out.response = ldap_msg->r.SearchResultEntry;
/* decode the 2nd part */
- status = ldap_decode(state->response.asn1, NULL, ldap_msg);
+ status = ldap_decode(
+ state->response.asn1, &limits, NULL, ldap_msg);
if (!NT_STATUS_IS_OK(status)) {
goto failed;
}
diff --git a/libcli/ldap/ldap_message.c b/libcli/ldap/ldap_message.c
index f21598374a1..69a48279532 100644
--- a/libcli/ldap/ldap_message.c
+++ b/libcli/ldap/ldap_message.c
@@ -390,7 +390,7 @@ _PUBLIC_ bool ldap_encode(struct ldap_message *msg,
const struct ldap_control_handler *control_handlers,
DATA_BLOB *result, TALLOC_CTX *mem_ctx)
{
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
int i, j;
if (!data) return false;
@@ -1162,6 +1162,7 @@ static bool ldap_decode_attribs(TALLOC_CTX *mem_ctx, struct asn1_data *data,
/* This routine returns LDAP status codes */
_PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data,
+ const struct ldap_request_limits *limits,
const struct ldap_control_handler *control_handlers,
struct ldap_message *msg)
{
@@ -1258,7 +1259,11 @@ _PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data,
struct ldap_SearchRequest *r = &msg->r.SearchRequest;
int sizelimit, timelimit;
const char **attrs = NULL;
+ size_t request_size = asn1_get_length(data);
msg->type = LDAP_TAG_SearchRequest;
+ if (request_size > limits->max_search_size) {
+ goto prot_err;
+ }
if (!asn1_start_tag(data, tag)) goto prot_err;
if (!asn1_read_OctetString_talloc(msg, data, &r->basedn)) goto prot_err;
if (!asn1_read_enumerated(data, (int *)(void *)&(r->scope))) goto prot_err;
diff --git a/libcli/ldap/ldap_message.h b/libcli/ldap/ldap_message.h
index 2f64881c053..19bfb99ac97 100644
--- a/libcli/ldap/ldap_message.h
+++ b/libcli/ldap/ldap_message.h
@@ -213,10 +213,15 @@ struct ldap_control_handler {
bool (*encode)(void *mem_ctx, void *in, DATA_BLOB *out);
};
+struct ldap_request_limits {
+ unsigned max_search_size;
+};
+
struct asn1_data;
struct ldap_message *new_ldap_message(TALLOC_CTX *mem_ctx);
NTSTATUS ldap_decode(struct asn1_data *data,
+ const struct ldap_request_limits *limits,
const struct ldap_control_handler *control_handlers,
struct ldap_message *msg);
bool ldap_encode(struct ldap_message *msg,
diff --git a/libcli/ldap/tests/data/10000-or.dat b/libcli/ldap/tests/data/10000-or.dat
new file mode 100644
index 00000000000..e2d6de2ce33
--- /dev/null
+++ b/libcli/ldap/tests/data/10000-or.dat
Binary files differ
diff --git a/libcli/ldap/tests/data/ldap-recursive.dat b/libcli/ldap/tests/data/ldap-recursive.dat
new file mode 100644
index 00000000000..dd18d857660
--- /dev/null
+++ b/libcli/ldap/tests/data/ldap-recursive.dat
Binary files differ
diff --git a/libcli/ldap/tests/ldap_message_test.c b/libcli/ldap/tests/ldap_message_test.c
new file mode 100644
index 00000000000..c5aacd4bc6b
--- /dev/null
+++ b/libcli/ldap/tests/ldap_message_test.c
@@ -0,0 +1,287 @@
+/*
+ * Unit tests for ldap_message.
+ *
+ * Copyright (C) Catalyst.NET Ltd 2020
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ *
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "lib/util/attr.h"
+#include "includes.h"
+#include "lib/util/asn1.h"
+#include "libcli/ldap/ldap_message.h"
+#include "libcli/ldap/ldap_proto.h"
+
+/*
+ * declare the internal cmocka cm_print so we can output messages in
+ * sub unit format
+ */
+void cm_print_error(const char * const format, ...);
+/*
+ * helper function and macro to compare an ldap error code constant with the
+ * coresponding nt_status code
+ */
+#define NT_STATUS_LDAP_V(code) (0xF2000000 | code)
+static void _assert_ldap_status_equal(
+ int a,
+ NTSTATUS b,
+ const char * const file,
+ const int line)
+{
+ _assert_int_equal(NT_STATUS_LDAP_V(a), NT_STATUS_V(b), file, line);
+}
+
+#define assert_ldap_status_equal(a, b) \
+ _assert_ldap_status_equal((a), (b), __FILE__, __LINE__)
+
+/*
+ * helper function and macro to assert there were no errors in the last
+ * file operation
+ */
+static void _assert_not_ferror(
+ FILE *f,
+ const char * const file,
+ const int line)
+{
+ if (f == NULL || ferror(f)) {
+ cm_print_error("ferror (%d) %s\n", errno, strerror(errno));
+ _fail(file, line);
+ }
+}
+
+#define assert_not_ferror(f) \
+ _assert_not_ferror((f), __FILE__, __LINE__)
+
+struct test_ctx {
+};
+
+static int setup(void **state)
+{
+ struct test_ctx *test_ctx;
+
+ test_ctx = talloc_zero(NULL, struct test_ctx);
+ *state = test_ctx;
+ return 0;
+}
+
+static int teardown(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+
+ TALLOC_FREE(test_ctx);
+ return 0;
+}
+
+/*
+ * Test that an empty request is handled correctly
+ */
+static void test_empty_input(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct asn1_data *asn1;
+ struct ldap_message *ldap_msg;
+ NTSTATUS status;
+ uint8_t buf[0];
+ size_t len = 0;
+ struct ldap_request_limits limits = {
+ .max_search_size = 256000,
+ };
+
+
+ asn1 = asn1_init(test_ctx, ASN1_MAX_TREE_DEPTH);
+ assert_non_null(asn1);
+
+ asn1_load_nocopy(asn1, buf, len);
+
+ ldap_msg = talloc(test_ctx, struct ldap_message);
+ assert_non_null(ldap_msg);
+
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
+ assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status);
+}
+
+/*
+ * Check that a request is rejected it it's recursion depth exceeds
+ * the maximum value specified. This test uses a very deeply nested query,
+ * 10,000 or clauses.
+ *
+ */
+static void test_recursion_depth_large(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct asn1_data *asn1;
+ struct ldap_message *ldap_msg;
+ NTSTATUS status;
+ FILE *f = NULL;
+ uint8_t *buffer = NULL;
+ const size_t BUFF_SIZE = 1048576;
+ size_t len;
+ struct ldap_request_limits limits = {
+ .max_search_size = 256000,
+ };
+
+
+ /*
+ * Load a test data file containg 10,000 or clauses in encoded as
+ * an ASN.1 packet.
+ */
+ buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
+ f = fopen("./libcli/ldap/tests/data/10000-or.dat", "r");
+ assert_not_ferror(f);
+ len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f);
+ assert_not_ferror(f);
+ assert_true(len > 0);
+
+ asn1 = asn1_init(test_ctx, ASN1_MAX_TREE_DEPTH);
+ assert_non_null(asn1);
+ asn1_load_nocopy(asn1, buffer, len);
+
+ ldap_msg = talloc(test_ctx, struct ldap_message);
+ assert_non_null(ldap_msg);
+
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
+ assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status);
+}
+
+/*
+ * Check that a request is not rejected it it's recursion depth equals the
+ * maximum value
+ */
+static void test_recursion_depth_equals_max(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct asn1_data *asn1;
+ struct ldap_message *ldap_msg;
+ NTSTATUS status;
+ FILE *f = NULL;
+ uint8_t *buffer = NULL;
+ const size_t BUFF_SIZE = 1048576;
+ size_t len;
+ struct ldap_request_limits limits = {
+ .max_search_size = 256000,
+ };
+
+
+ buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
+ f = fopen("./libcli/ldap/tests/data/ldap-recursive.dat", "r");
+ assert_not_ferror(f);
+ len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f);
+ assert_not_ferror(f);
+ assert_true(len > 0);
+
+ asn1 = asn1_init(test_ctx, 4);
+ assert_non_null(asn1);
+ asn1_load_nocopy(asn1, buffer, len);
+
+ ldap_msg = talloc(test_ctx, struct ldap_message);
+ assert_non_null(ldap_msg);
+
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
+ assert_true(NT_STATUS_IS_OK(status));
+}
+
+/*
+ * Check that a request is rejected it it's recursion depth is greater than the
+ * maximum value
+ */
+static void test_recursion_depth_greater_than_max(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct asn1_data *asn1;
+ struct ldap_message *ldap_msg;
+ NTSTATUS status;
+ FILE *f = NULL;
+ uint8_t *buffer = NULL;
+ const size_t BUFF_SIZE = 1048576;
+ size_t len;
+ struct ldap_request_limits limits = {
+ .max_search_size = 256000,
+ };
+
+
+ buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
+ f = fopen("./libcli/ldap/tests/data/ldap-recursive.dat", "r");
+ assert_not_ferror(f);
+ len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f);
+ assert_not_ferror(f);
+ assert_true(len > 0);
+
+ asn1 = asn1_init(test_ctx, 3);
+ assert_non_null(asn1);
+ asn1_load_nocopy(asn1, buffer, len);
+
+ ldap_msg = talloc(test_ctx, struct ldap_message);
+ assert_non_null(ldap_msg);
+
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
+ assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status);
+}
+
+int main(_UNUSED_ int argc, _UNUSED_ const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(
+ test_empty_input,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_recursion_depth_large,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_recursion_depth_equals_max,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_recursion_depth_greater_than_max,
+ setup,
+ teardown),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/libcli/ldap/wscript_build b/libcli/ldap/wscript_build
index db5b1df497a..d0aa7c11ced 100644
--- a/libcli/ldap/wscript_build
+++ b/libcli/ldap/wscript_build
@@ -6,3 +6,18 @@ bld.SAMBA_LIBRARY('cli-ldap-common',
private_headers='ldap_message.h ldap_errors.h ldap_ndr.h',
deps='samba-util asn1util NDR_SECURITY tevent',
private_library=True)
+
+bld.SAMBA_BINARY(
+ 'test_ldap_message',
+ source='tests/ldap_message_test.c',
+ deps='''
+ cmocka
+ talloc
+ ldb
+ samba-util
+ asn1util
+ NDR_SECURITY
+ cli-ldap
+ ''',
+ install=False
+)
diff --git a/python/samba/tests/ldap_raw.py b/python/samba/tests/ldap_raw.py
new file mode 100644
index 00000000000..334fabce230
--- /dev/null
+++ b/python/samba/tests/ldap_raw.py
@@ -0,0 +1,234 @@
+# Integration tests for the ldap server, using raw socket IO
+#
+# Tests for handling of malformed or large packets.
+#
+# Copyright (C) Catalyst.Net Ltd 2020
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import socket
+
+import samba.tests
+from samba.tests import TestCase
+
+
+#
+# LDAP Operations
+#
+SEARCH = b'\x63'
+
+EQUALS = b'\xa3'
+
+
+#
+# ASN.1 Element types
+#
+BOOLEAN = b'\x01'
+INTEGER = b'\x02'
+OCTET_STRING = b'\x04'
+NULL = b'\x05'
+ENUMERATED = b'\x0a'
+SEQUENCE = b'\x30'
+SET = b'\x31'
+
+
+#
+# ASN.1 Helper functions.
+#
+def encode_element(ber_type, data):
+ ''' Encode an ASN.1 BER element. '''
+ if data is None:
+ return ber_type + encode_length(0)
+ return ber_type + encode_length(len(data)) + data
+
+
+def encode_length(length):
+ ''' Encode the length of an ASN.1 BER element. '''
+
+ if length > 0xFFFFFF:
+ return b'\x84' + length.to_bytes(4, "big")
+ if length > 0xFFFF:
+ return b'\x83' + length.to_bytes(3, "big")
+ if length > 0xFF:
+ return b'\x82' + length.to_bytes(2, "big")
+ if length > 0x7F:
+ return b'\x81' + length.to_bytes(1, "big")
+ return length.to_bytes(1, "big")
+
+
+def encode_string(string):
+ ''' Encode an octet string '''
+ return encode_element(OCTET_STRING, string)
+
+
+def encode_boolean(boolean):
+ ''' Encode a boolean value '''
+ if boolean:
+ return encode_element(BOOLEAN, b'\xFF')
+ return encode_element(BOOLEAN, b'\x00')
+
+
+def encode_integer(integer):
+ ''' Encode an integer value '''
+ bit_len = integer.bit_length()
+ byte_len = (bit_len // 8) + 1
+ return encode_element(INTEGER, integer.to_bytes(byte_len, "big"))
+
+
+def encode_enumerated(enum):
+ ''' Encode an enumerated value '''
+ return encode_element(ENUMERATED, enum.to_bytes(1, "big"))
+
+
+def encode_sequence(sequence):
+ ''' Encode a sequence '''
+ return encode_element(SEQUENCE, sequence)
+
+
+class RawLdapTest(TestCase):
+ """A raw Ldap Test case."""
+
+ def setUp(self):
+ super(RawLdapTest, self).setUp()
+
+ self.host = samba.tests.env_get_var_value('SERVER')
+ self.port = 389
+ self.socket = None
+ self.connect()
+
+ def tearDown(self):
+ self.disconnect()
+ super(RawLdapTest, self).tearDown()
+
+ def disconnect(self):
+ ''' Disconnect from and clean up the connection to the server '''
+ if self.socket is None:
+ return
+ self.socket.close()
+ self.socket = None
+
+ def connect(self):
+ ''' Open a socket stream connection to the server '''
+ try:
+ self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.socket.settimeout(10)
+ self.socket.connect((self.host, self.port))
+ except socket.error:
+ self.socket.close()
+ raise
+
+ def send(self, req):
+ ''' Send the request to the server '''
+ try:
+ self.socket.sendall(req)
+ except socket.error:
+ self.disconnect()
+ raise
+
+ def recv(self, num_recv=0xffff, timeout=None):
+ ''' recv an array of bytes from the server '''
+ data = None
+ try:
+ if timeout is not None:
+ self.socket.settimeout(timeout)
+ data = self.socket.recv(num_recv, 0)
+ self.socket.settimeout(10)
+ if len(data) == 0:
+ self.disconnect()
+ return None
+ except socket.timeout:
+ # We ignore timeout's as the ldap server will drop the connection
+ # on the errors we're testing. So returning None on a timeout is
+ # the desired behaviour.
+ self.socket.settimeout(10)
+ except socket.error:
+ self.disconnect()
+ raise
+ return data
+
+ def test_search_equals_maximum_permitted_size(self):
+ '''
+ Check that an LDAP search request equal to the maximum size is accepted
+ '''
+
+ # Lets build an ldap search packet to query the RootDSE
+ header = encode_string(None) # Base DN, ""
+ header += encode_enumerated(0) # Enumeration scope
+ header += encode_enumerated(0) # Enumeration dereference
+ header += encode_integer(0) # Integer size limit
+ header += encode_integer(0) # Integer time limit
+ header += encode_boolean(False) # Boolean attributes only
+
+ #
+ # build an equality search of the form x...x=y...y
+ # With the length of x...x and y...y chosen to generate an
+ # ldap request of 256000 bytes.
+ x = encode_string(b'x' * 127974)
+ y = encode_string(b'y' * 127979)
+ equals = encode_element(EQUALS, x + y)
+ trailer = encode_sequence(None)
+ search = encode_element(SEARCH, header + equals + trailer)
+
+ msg_no = encode_integer(1)
+ packet = encode_sequence(msg_no + search)
+ #
+ # The length of the packet should be equal to the
+ # Maximum length of a search query
+ self.assertEqual(256000, len(packet))
+
+ self.send(packet)
+ data = self.recv()
+ self.assertIsNotNone(data)
+
+ # Should be a sequence
+ self.assertEqual(SEQUENCE, data[0:1])
+
+ def test_search_exceeds_maximum_permitted_size(self):
+ '''
+ Test that a search query longer than the maximum permitted
+ size is rejected.
+ '''
+
+ # Lets build an ldap search packet to query the RootDSE
+ header = encode_string(None) # Base DN, ""
+ header += encode_enumerated(0) # Enumeration scope
+ header += encode_enumerated(0) # Enumeration dereference
+ header += encode_integer(0) # Integer size limit
+ header += encode_integer(0) # Integer time limit
+ header += encode_boolean(False) # Boolean attributes only
+
+ #
+ # build an equality search of the form x...x=y...y
+ # With the length of x...x and y...y chosen to generate an
+ # ldap request of 256001 bytes.
+ x = encode_string(b'x' * 127979)
+ y = encode_string(b'y' * 127975)
+ equals = encode_element(EQUALS, x + y)
+ trailer = encode_sequence(None)
+ search = encode_element(SEARCH, header + equals + trailer)
+
+ msg_no = encode_integer(1)
+ packet = encode_sequence(msg_no + search)
+ #
+ # The length of the sequence data should be one greater than the
+ # Maximum length of a search query
+ self.assertEqual(256001, len(packet))
+
+ self.send(packet)
+ data = self.recv()
+ #
+ # The connection should be closed by the server and we should not
+ # see any data.
+ self.assertIsNone(data)
diff --git a/source3/lib/tldap.c b/source3/lib/tldap.c
index d6c6e8859a6..bf5fc05d785 100644
--- a/source3/lib/tldap.c
+++ b/source3/lib/tldap.c
@@ -632,7 +632,7 @@ static void tldap_msg_received(struct tevent_req *subreq)
goto fail;
}
- data = asn1_init(talloc_tos());
+ data = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
if (data == NULL) {
status = TLDAP_NO_MEMORY;
goto fail;
@@ -763,7 +763,7 @@ static struct tevent_req *tldap_req_create(TALLOC_CTX *mem_ctx,
if (req == NULL) {
return NULL;
}
- state->out = asn1_init(state);
+ state->out = asn1_init(state, ASN1_MAX_TREE_DEPTH);
if (state->out == NULL) {
goto err;
}
diff --git a/source3/lib/tldap_util.c b/source3/lib/tldap_util.c
index 1b86962a32e..168932a8a96 100644
--- a/source3/lib/tldap_util.c
+++ b/source3/lib/tldap_util.c
@@ -644,7 +644,7 @@ static struct tevent_req *tldap_ship_paged_search(
struct tldap_control *pgctrl;
struct asn1_data *asn1 = NULL;
- asn1 = asn1_init(state);
+ asn1 = asn1_init(state, ASN1_MAX_TREE_DEPTH);
if (asn1 == NULL) {
return NULL;
}
@@ -783,7 +783,7 @@ static void tldap_search_paged_done(struct tevent_req *subreq)
TALLOC_FREE(state->cookie.data);
- asn1 = asn1_init(talloc_tos());
+ asn1 = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
if (tevent_req_nomem(asn1, req)) {
return;
}
diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c
index 4a0fbcd73af..1608f6a9960 100644
--- a/source3/libsmb/clispnego.c
+++ b/source3/libsmb/clispnego.c
@@ -50,7 +50,7 @@ bool spnego_parse_negTokenInit(TALLOC_CTX *ctx,
*secblob = data_blob_null;
}
- data = asn1_init(talloc_tos());
+ data = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
if (data == NULL) {
return false;
}
@@ -171,7 +171,7 @@ DATA_BLOB spnego_gen_krb5_wrap(TALLOC_CTX *ctx, const DATA_BLOB ticket, const ui
ASN1_DATA *data;
DATA_BLOB ret = data_blob_null;
- data = asn1_init(talloc_tos());
+ data = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
if (data == NULL) {
return data_blob_null;
}
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index a8d5fdc5954..5ee6d33c7fc 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -956,6 +956,10 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
Globals.prefork_backoff_increment = 10;
Globals.prefork_maximum_backoff = 120;
+ Globals.ldap_max_anonymous_request_size = 256000;
+ Globals.ldap_max_authenticated_request_size = 16777216;
+ Globals.ldap_max_search_request_size = 256000;
+
/* Now put back the settings that were set with lp_set_cmdline() */
apply_lp_set_cmdline();
}
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index a795e61125f..c4b0a7bc4f9 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -11370,7 +11370,7 @@ tldap_build_extended_control(enum tldap_extended_val val)
ZERO_STRUCT(empty_control);
if (val != EXTENDED_NONE) {
- data = asn1_init(talloc_tos());
+ data = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
if (!data) {
return NULL;
diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c
index 0323da87d29..b735063656a 100644
--- a/source4/auth/gensec/gensec_krb5.c
+++ b/source4/auth/gensec/gensec_krb5.c
@@ -444,7 +444,7 @@ static DATA_BLOB gensec_gssapi_gen_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLO
struct asn1_data *data;
DATA_BLOB ret = data_blob_null;
- data = asn1_init(mem_ctx);
+ data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
if (!data || !ticket->data) {
return ret;
}
@@ -478,7 +478,7 @@ static DATA_BLOB gensec_gssapi_gen_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLO
static bool gensec_gssapi_parse_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, DATA_BLOB *ticket, uint8_t tok_id[2])
{
bool ret = false;
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
int data_remaining;
if (!data) {
diff --git a/source4/dsdb/samdb/ldb_modules/paged_results.c b/source4/dsdb/samdb/ldb_modules/paged_results.c
index 940d2254fb0..dc211dd18ce 100644
--- a/source4/dsdb/samdb/ldb_modules/paged_results.c
+++ b/source4/dsdb/samdb/ldb_modules/paged_results.c
@@ -483,8 +483,14 @@ paged_results_copy_down_controls(TALLOC_CTX *mem_ctx,
if (control->oid == NULL) {
continue;
}
- if (strncmp(control->oid, LDB_CONTROL_PAGED_RESULTS_OID,
- sizeof(LDB_CONTROL_PAGED_RESULTS_OID)) == 0) {
+ if (strcmp(control->oid, LDB_CONTROL_PAGED_RESULTS_OID) == 0) {
+ continue;
+ }
+ /*
+ * ASQ changes everything, do not copy it down for the
+ * per-GUID search
+ */
+ if (strcmp(control->oid, LDB_CONTROL_ASQ_OID) == 0) {
continue;
}
new_controls[j] = talloc_steal(new_controls, control);
@@ -534,21 +540,23 @@ static bool paged_controls_same(struct ldb_request *req,
num_non_null_req_controls = 0;
for (i=0; req->controls[i] != NULL; i++) {
- if (req->controls[i]->oid != NULL) {
+ if (req->controls[i]->oid != NULL &&
+ strcmp(req->controls[i]->oid,
+ LDB_CONTROL_ASQ_OID) != 0) {
num_non_null_req_controls++;
}
}
/* At this point we have the number of non-null entries for both
* control lists and we know that:
- * 1. down_controls does not contain the paged control
+ * 1. down_controls does not contain the paged control or ASQ
* (because paged_results_copy_down_controls excludes it)
* 2. req->controls does contain the paged control
* (because this function is only called if this is true)
* 3. down_controls is a subset of non-null controls in req->controls
* (checked above)
* So to confirm that the two lists are identical except for the paged
- * control, all we need to check is: */
+ * control and possibly ASQ, all we need to check is: */
if (num_non_null_req_controls == num_down_controls + 1) {
return true;
}
diff --git a/source4/dsdb/tests/python/asq.py b/source4/dsdb/tests/python/asq.py
new file mode 100644
index 00000000000..a32c9f40cd3
--- /dev/null
+++ b/source4/dsdb/tests/python/asq.py
@@ -0,0 +1,171 @@
+#!/usr/bin/env python3
+#
+# Test ASQ LDAP control behaviour in Samba
+# Copyright (C) Andrew Bartlett 2019-2020
+#
+# Based on Unit tests for the notification control
+# Copyright (C) Stefan Metzmacher 2016
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import optparse
+import sys
+import os
+import random
+
+sys.path.insert(0, "bin/python")
+import samba
+from samba.tests.subunitrun import SubunitOptions, TestProgram
+
+import samba.getopt as options
+
+from samba.auth import system_session
+from samba import ldb
+from samba.samdb import SamDB
+from samba.ndr import ndr_unpack
+from samba import gensec
+from samba.credentials import Credentials
+import samba.tests
+
+from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError
+from ldb import ERR_TIME_LIMIT_EXCEEDED, ERR_ADMIN_LIMIT_EXCEEDED, ERR_UNWILLING_TO_PERFORM
+from ldb import Message
+
+parser = optparse.OptionParser("large_ldap.py [options] <host>")
+sambaopts = options.SambaOptions(parser)
+parser.add_option_group(sambaopts)
+parser.add_option_group(options.VersionOptions(parser))
+# use command line creds if available
+credopts = options.CredentialsOptions(parser)
+parser.add_option_group(credopts)
+subunitopts = SubunitOptions(parser)
+parser.add_option_group(subunitopts)
+opts, args = parser.parse_args()
+
+if len(args) < 1:
+ parser.print_usage()
+ sys.exit(1)
+
+url = args[0]
+
+lp = sambaopts.get_loadparm()
+creds = credopts.get_credentials(lp)
+
+
+class ASQLDAPTest(samba.tests.TestCase):
+
+ def setUp(self):
+ super(ASQLDAPTest, self).setUp()
+ self.ldb = samba.Ldb(url, credentials=creds, session_info=system_session(lp), lp=lp)
+ self.base_dn = self.ldb.get_default_basedn()
+ self.NAME_ASQ="asq_" + format(random.randint(0, 99999), "05")
+ self.OU_NAME_ASQ= self.NAME_ASQ + "_ou"
+ self.ou_dn = ldb.Dn(self.ldb, "ou=" + self.OU_NAME_ASQ + "," + str(self.base_dn))
+
+ samba.tests.delete_force(self.ldb, self.ou_dn,
+ controls=['tree_delete:1'])
+
+ self.ldb.add({
+ "dn": self.ou_dn,
+ "objectclass": "organizationalUnit",
+ "ou": self.OU_NAME_ASQ})
+
+ self.members = []
+ self.members2 = []
+
+ for x in range(20):
+ name = self.NAME_ASQ + "_" + str(x)
+ dn = ldb.Dn(self.ldb,
+ "cn=" + name + "," + str(self.ou_dn))
+ self.members.append(dn)
+ self.ldb.add({
+ "dn": dn,
+ "objectclass": "group"})
+
+ for x in range(20):
+ name = self.NAME_ASQ + "_" + str(x + 20)
+ dn = ldb.Dn(self.ldb,
+ "cn=" + name + "," + str(self.ou_dn))
+ self.members2.append(dn)
+ self.ldb.add({
+ "dn": dn,
+ "objectclass": "group",
+ "member": [str(x) for x in self.members]})
+
+ name = self.NAME_ASQ + "_" + str(x + 40)
+ self.top_dn = ldb.Dn(self.ldb,
+ "cn=" + name + "," + str(self.ou_dn))
+ self.ldb.add({
+ "dn": self.top_dn,
+ "objectclass": "group",
+ "member": [str(x) for x in self.members2]})
+
+ def tearDown(self):
+ samba.tests.delete_force(self.ldb, self.ou_dn,
+ controls=['tree_delete:1'])
+
+ def test_asq(self):
+ """Testing ASQ behaviour.
+
+ ASQ is very strange, it turns a BASE search into a search for
+ all the objects pointed to by the specified attribute,
+ returning multiple entries!
+
+ """
+
+ msgs = self.ldb.search(base=self.top_dn,
+ scope=ldb.SCOPE_BASE,
+ attrs=["objectGUID", "cn", "member"],
+ controls=["asq:1:member"])
+
+ self.assertEqual(len(msgs), 20)
+
+ for msg in msgs:
+ self.assertNotEqual(msg.dn, self.top_dn)
+ self.assertIn(msg.dn, self.members2)
+ for group in msg["member"]:
+ self.assertIn(ldb.Dn(self.ldb, str(group)),
+ self.members)
+
+ def test_asq_paged(self):
+ """Testing ASQ behaviour with paged_results set.
+
+ ASQ is very strange, it turns a BASE search into a search for
+ all the objects pointed to by the specified attribute,
+ returning multiple entries!
+
+ """
+
+ msgs = self.ldb.search(base=self.top_dn,
+ scope=ldb.SCOPE_BASE,
+ attrs=["objectGUID", "cn", "member"],
+ controls=["asq:1:member",
+ "paged_results:1:1024"])
+
+ self.assertEqual(len(msgs), 20)
+
+ for msg in msgs:
+ self.assertNotEqual(msg.dn, self.top_dn)
+ self.assertIn(msg.dn, self.members2)
+ for group in msg["member"]:
+ self.assertIn(ldb.Dn(self.ldb, str(group)),
+ self.members)
+
+if "://" not in url:
+ if os.path.isfile(url):
+ url = "tdb://%s" % url
+ else:
+ url = "ldap://%s" % url
+
+TestProgram(module=__name__, opts=subunitopts)
diff --git a/source4/ldap_server/ldap_server.c b/source4/ldap_server/ldap_server.c
index 709b7bcacfa..a9b162b284e 100644
--- a/source4/ldap_server/ldap_server.c
+++ b/source4/ldap_server/ldap_server.c
@@ -441,6 +441,10 @@ static void ldapsrv_accept_tls_done(struct tevent_req *subreq)
}
static void ldapsrv_call_read_done(struct tevent_req *subreq);
+static NTSTATUS ldapsrv_packet_check(
+ void *private_data,
+ DATA_BLOB blob,
+ size_t *packet_size);
static bool ldapsrv_call_read_next(struct ldapsrv_connection *conn)
{
@@ -494,7 +498,7 @@ static bool ldapsrv_call_read_next(struct ldapsrv_connection *conn)
conn->connection->event.ctx,
conn->sockets.active,
7, /* initial_read_size */
- ldap_full_packet,
+ ldapsrv_packet_check,
conn);
if (subreq == NULL) {
ldapsrv_terminate_connection(conn, "ldapsrv_call_read_next: "
@@ -520,6 +524,9 @@ static bool ldapsrv_call_read_next(struct ldapsrv_connection *conn)
}
static void ldapsrv_call_process_done(struct tevent_req *subreq);
+static int ldapsrv_check_packet_size(
+ struct ldapsrv_connection *conn,
+ size_t size);
static void ldapsrv_call_read_done(struct tevent_req *subreq)
{
@@ -530,6 +537,8 @@ static void ldapsrv_call_read_done(struct tevent_req *subreq)
struct ldapsrv_call *call;
struct asn1_data *asn1;
DATA_BLOB blob;
+ int ret = LDAP_SUCCESS;
+ struct ldap_request_limits limits = {0};
conn->sockets.read_req = NULL;
@@ -560,7 +569,15 @@ static void ldapsrv_call_read_done(struct tevent_req *subreq)
return;
}
- asn1 = asn1_init(call);
+ ret = ldapsrv_check_packet_size(conn, blob.length);
+ if (ret != LDAP_SUCCESS) {
+ ldapsrv_terminate_connection(
+ conn,
+ "Request packet too large");
+ return;
+ }
+
+ asn1 = asn1_init(call, ASN1_MAX_TREE_DEPTH);
if (asn1 == NULL) {
ldapsrv_terminate_connection(conn, "no memory");
return;
@@ -577,8 +594,13 @@ static void ldapsrv_call_read_done(struct tevent_req *subreq)
return;
}
- status = ldap_decode(asn1, samba_ldap_control_handlers(),
- call->request);
+ limits.max_search_size =
+ lpcfg_ldap_max_search_request_size(conn->lp_ctx);
+ status = ldap_decode(
+ asn1,
+ &limits,
+ samba_ldap_control_handlers(),
+ call->request);
if (!NT_STATUS_IS_OK(status)) {
ldapsrv_terminate_connection(conn, nt_errstr(status));
return;
@@ -1362,6 +1384,84 @@ static void ldapsrv_post_fork(struct task_server *task, struct process_details *
}
}
+/*
+ * Check the size of an ldap request packet.
+ *
+ * For authenticated connections the maximum packet size is controlled by
+ * the smb.conf parameter "ldap max authenticated request size"
+ *
+ * For anonymous connections the maximum packet size is controlled by
+ * the smb.conf parameter "ldap max anonymous request size"
+ */
+static int ldapsrv_check_packet_size(
+ struct ldapsrv_connection *conn,
+ size_t size)
+{
+ bool is_anonymous = false;
+ size_t max_size = 0;
+
+ max_size = lpcfg_ldap_max_anonymous_request_size(conn->lp_ctx);
+ if (size <= max_size) {
+ return LDAP_SUCCESS;
+ }
+
+ /*
+ * Request is larger than the maximum unauthenticated request size.
+ * As this code is called frequently we avoid calling
+ * security_token_is_anonymous if possible
+ */
+ if (conn->session_info != NULL &&
+ conn->session_info->security_token != NULL) {
+ is_anonymous = security_token_is_anonymous(
+ conn->session_info->security_token);
+ }
+
+ if (is_anonymous) {
+ DBG_WARNING(
+ "LDAP request size (%zu) exceeds (%zu)\n",
+ size,
+ max_size);
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+
+ max_size = lpcfg_ldap_max_authenticated_request_size(conn->lp_ctx);
+ if (size > max_size) {
+ DBG_WARNING(
+ "LDAP request size (%zu) exceeds (%zu)\n",
+ size,
+ max_size);
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+ return LDAP_SUCCESS;
+
+}
+
+/*
+ * Check that the blob contains enough data to be a valid packet
+ * If there is a packet header check the size to ensure that it does not
+ * exceed the maximum sizes.
+ *
+ */
+static NTSTATUS ldapsrv_packet_check(
+ void *private_data,
+ DATA_BLOB blob,
+ size_t *packet_size)
+{
+ NTSTATUS ret;
+ struct ldapsrv_connection *conn = private_data;
+ int result = LDB_SUCCESS;
+
+ ret = ldap_full_packet(private_data, blob, packet_size);
+ if (!NT_STATUS_IS_OK(ret)) {
+ return ret;
+ }
+ result = ldapsrv_check_packet_size(conn, *packet_size);
+ if (result != LDAP_SUCCESS) {
+ return NT_STATUS_LDAP(result);
+ }
+ return NT_STATUS_OK;
+}
+
NTSTATUS server_service_ldap_init(TALLOC_CTX *ctx)
{
static const struct service_details details = {
diff --git a/source4/libcli/ldap/ldap_client.c b/source4/libcli/ldap/ldap_client.c
index da84adc7769..cf276679594 100644
--- a/source4/libcli/ldap/ldap_client.c
+++ b/source4/libcli/ldap/ldap_client.c
@@ -277,6 +277,7 @@ static void ldap_connection_recv_done(struct tevent_req *subreq)
struct ldap_message *msg;
struct asn1_data *asn1;
DATA_BLOB blob;
+ struct ldap_request_limits limits = {0};
msg = talloc_zero(conn, struct ldap_message);
if (msg == NULL) {
@@ -284,7 +285,7 @@ static void ldap_connection_recv_done(struct tevent_req *subreq)
return;
}
- asn1 = asn1_init(conn);
+ asn1 = asn1_init(conn, ASN1_MAX_TREE_DEPTH);
if (asn1 == NULL) {
TALLOC_FREE(msg);
ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
@@ -306,7 +307,7 @@ static void ldap_connection_recv_done(struct tevent_req *subreq)
asn1_load_nocopy(asn1, blob.data, blob.length);
- status = ldap_decode(asn1, samba_ldap_control_handlers(), msg);
+ status = ldap_decode(asn1, &limits, samba_ldap_control_handlers(), msg);
asn1_free(asn1);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(msg);
diff --git a/source4/libcli/ldap/ldap_controls.c b/source4/libcli/ldap/ldap_controls.c
index 716ca148308..df012a158e0 100644
--- a/source4/libcli/ldap/ldap_controls.c
+++ b/source4/libcli/ldap/ldap_controls.c
@@ -32,7 +32,7 @@ static bool decode_server_sort_response(void *mem_ctx, DATA_BLOB in, void *_out)
{
void **out = (void **)_out;
DATA_BLOB attr;
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
struct ldb_sort_resp_control *lsrc;
if (!data) return false;
@@ -79,7 +79,7 @@ static bool decode_server_sort_request(void *mem_ctx, DATA_BLOB in, void *_out)
void **out = (void **)_out;
DATA_BLOB attr;
DATA_BLOB rule;
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
struct ldb_server_sort_control **lssc;
int num;
@@ -166,7 +166,7 @@ static bool decode_extended_dn_request(void *mem_ctx, DATA_BLOB in, void *_out)
return true;
}
- data = asn1_init(mem_ctx);
+ data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
if (!data) return false;
if (!asn1_load(data, in)) {
@@ -198,7 +198,7 @@ static bool decode_extended_dn_request(void *mem_ctx, DATA_BLOB in, void *_out)
static bool decode_sd_flags_request(void *mem_ctx, DATA_BLOB in, void *_out)
{
void **out = (void **)_out;
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
struct ldb_sd_flags_control *lsdfc;
if (!data) return false;
@@ -232,7 +232,7 @@ static bool decode_sd_flags_request(void *mem_ctx, DATA_BLOB in, void *_out)
static bool decode_search_options_request(void *mem_ctx, DATA_BLOB in, void *_out)
{
void **out = (void **)_out;
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
struct ldb_search_options_control *lsoc;
if (!data) return false;
@@ -267,7 +267,7 @@ static bool decode_paged_results_request(void *mem_ctx, DATA_BLOB in, void *_out
{
void **out = (void **)_out;
DATA_BLOB cookie;
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
struct ldb_paged_control *lprc;
if (!data) return false;
@@ -316,7 +316,7 @@ static bool decode_dirsync_request(void *mem_ctx, DATA_BLOB in, void *_out)
{
void **out = (void **)_out;
DATA_BLOB cookie;
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
struct ldb_dirsync_control *ldc;
if (!data) return false;
@@ -372,7 +372,7 @@ static bool decode_asq_control(void *mem_ctx, DATA_BLOB in, void *_out)
{
void **out = (void **)_out;
DATA_BLOB source_attribute;
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
struct ldb_asq_control *lac;
if (!data) return false;
@@ -433,7 +433,7 @@ static bool decode_verify_name_request(void *mem_ctx, DATA_BLOB in, void *_out)
{
void **out = (void **)_out;
DATA_BLOB name;
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
struct ldb_verify_name_control *lvnc;
int len;
@@ -485,7 +485,7 @@ static bool decode_verify_name_request(void *mem_ctx, DATA_BLOB in, void *_out)
static bool encode_verify_name_request(void *mem_ctx, void *in, DATA_BLOB *out)
{
struct ldb_verify_name_control *lvnc = talloc_get_type(in, struct ldb_verify_name_control);
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
DATA_BLOB gc_utf16;
if (!data) return false;
@@ -528,7 +528,7 @@ static bool decode_vlv_request(void *mem_ctx, DATA_BLOB in, void *_out)
{
void **out = (void **)_out;
DATA_BLOB assertion_value, context_id;
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
struct ldb_vlv_req_control *lvrc;
if (!data) return false;
@@ -626,7 +626,7 @@ static bool decode_vlv_response(void *mem_ctx, DATA_BLOB in, void *_out)
{
void **out = (void **)_out;
DATA_BLOB context_id;
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
struct ldb_vlv_resp_control *lvrc;
if (!data) return false;
@@ -682,7 +682,7 @@ static bool decode_vlv_response(void *mem_ctx, DATA_BLOB in, void *_out)
static bool encode_server_sort_response(void *mem_ctx, void *in, DATA_BLOB *out)
{
struct ldb_sort_resp_control *lsrc = talloc_get_type(in, struct ldb_sort_resp_control);
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
if (!data) return false;
@@ -716,7 +716,7 @@ static bool encode_server_sort_response(void *mem_ctx, void *in, DATA_BLOB *out)
static bool encode_server_sort_request(void *mem_ctx, void *in, DATA_BLOB *out)
{
struct ldb_server_sort_control **lssc = talloc_get_type(in, struct ldb_server_sort_control *);
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
int num;
if (!data) return false;
@@ -782,7 +782,7 @@ static bool encode_extended_dn_request(void *mem_ctx, void *in, DATA_BLOB *out)
return true;
}
- data = asn1_init(mem_ctx);
+ data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
if (!data) return false;
@@ -810,7 +810,7 @@ static bool encode_extended_dn_request(void *mem_ctx, void *in, DATA_BLOB *out)
static bool encode_sd_flags_request(void *mem_ctx, void *in, DATA_BLOB *out)
{
struct ldb_sd_flags_control *lsdfc = talloc_get_type(in, struct ldb_sd_flags_control);
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
if (!data) return false;
@@ -838,7 +838,7 @@ static bool encode_sd_flags_request(void *mem_ctx, void *in, DATA_BLOB *out)
static bool encode_search_options_request(void *mem_ctx, void *in, DATA_BLOB *out)
{
struct ldb_search_options_control *lsoc = talloc_get_type(in, struct ldb_search_options_control);
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
if (!data) return false;
@@ -866,7 +866,7 @@ static bool encode_search_options_request(void *mem_ctx, void *in, DATA_BLOB *ou
static bool encode_paged_results_request(void *mem_ctx, void *in, DATA_BLOB *out)
{
struct ldb_paged_control *lprc = talloc_get_type(in, struct ldb_paged_control);
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
if (!data) return false;
@@ -901,7 +901,7 @@ static bool encode_paged_results_request(void *mem_ctx, void *in, DATA_BLOB *out
static bool encode_asq_control(void *mem_ctx, void *in, DATA_BLOB *out)
{
struct ldb_asq_control *lac = talloc_get_type(in, struct ldb_asq_control);
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
if (!data) return false;
@@ -936,7 +936,7 @@ static bool encode_asq_control(void *mem_ctx, void *in, DATA_BLOB *out)
static bool encode_dirsync_request(void *mem_ctx, void *in, DATA_BLOB *out)
{
struct ldb_dirsync_control *ldc = talloc_get_type(in, struct ldb_dirsync_control);
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
if (!data) return false;
@@ -972,7 +972,7 @@ static bool encode_dirsync_request(void *mem_ctx, void *in, DATA_BLOB *out)
static bool encode_vlv_request(void *mem_ctx, void *in, DATA_BLOB *out)
{
struct ldb_vlv_req_control *lvrc = talloc_get_type(in, struct ldb_vlv_req_control);
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
if (!data) return false;
@@ -1040,7 +1040,7 @@ static bool encode_vlv_request(void *mem_ctx, void *in, DATA_BLOB *out)
static bool encode_vlv_response(void *mem_ctx, void *in, DATA_BLOB *out)
{
struct ldb_vlv_resp_control *lvrc = talloc_get_type(in, struct ldb_vlv_resp_control);
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
if (!data) return false;
@@ -1083,7 +1083,7 @@ static bool encode_openldap_dereference(void *mem_ctx, void *in, DATA_BLOB *out)
{
struct dsdb_openldap_dereference_control *control = talloc_get_type(in, struct dsdb_openldap_dereference_control);
int i,j;
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
if (!data) return false;
@@ -1132,7 +1132,7 @@ static bool encode_openldap_dereference(void *mem_ctx, void *in, DATA_BLOB *out)
static bool decode_openldap_dereference(void *mem_ctx, DATA_BLOB in, void *_out)
{
void **out = (void **)_out;
- struct asn1_data *data = asn1_init(mem_ctx);
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
struct dsdb_openldap_dereference_result_control *control;
struct dsdb_openldap_dereference_result **r = NULL;
int i = 0;
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index ae2b10ae659..f7645365384 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -881,10 +881,16 @@ plantestsuite_loadlist("samba4.ldap_modify_order.normal_user.python(ad_dc_defaul
'$LOADLIST',
'$LISTOPT'])
+planoldpythontestsuite("ad_dc",
+ "samba.tests.ldap_raw",
+ extra_args=['-U"$USERNAME%$PASSWORD"'],
+ environ={'TEST_ENV': 'ad_dc'})
+
plantestsuite_loadlist("samba4.tokengroups.krb5.python(ad_dc_default)", "ad_dc_default:local", [python, os.path.join(DSDB_PYTEST_DIR, "token_group.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '-k', 'yes', '$LOADLIST', '$LISTOPT'])
plantestsuite_loadlist("samba4.tokengroups.ntlm.python(ad_dc_default)", "ad_dc_default:local", [python, os.path.join(DSDB_PYTEST_DIR, "token_group.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '-k', 'no', '$LOADLIST', '$LISTOPT'])
plantestsuite("samba4.sam.python(fl2008r2dc)", "fl2008r2dc", [python, os.path.join(DSDB_PYTEST_DIR, "sam.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN'])
plantestsuite("samba4.sam.python(ad_dc_default)", "ad_dc_default", [python, os.path.join(DSDB_PYTEST_DIR, "sam.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN'])
+plantestsuite("samba4.asq.python(ad_dc_default)", "ad_dc_default", [python, os.path.join(DSDB_PYTEST_DIR, "asq.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN'])
plantestsuite("samba4.user_account_control.python(ad_dc_default)", "ad_dc_default", [python, os.path.join(DSDB_PYTEST_DIR, "user_account_control.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN'])
for env in ['ad_dc_default:local', 'schema_dc:local']:
@@ -1321,6 +1327,8 @@ plantestsuite("samba4.dcerpc.dnsserver.dnsutils", "none",
[os.path.join(bindir(), "test_rpc_dns_server_dnsutils")])
plantestsuite("libcli.drsuapi.repl_decrypt", "none",
[os.path.join(bindir(), "test_repl_decrypt")])
+plantestsuite("libcli.ldap.ldap_message", "none",
+ [os.path.join(bindir(), "test_ldap_message")])
# process restart and limit tests, these break the environment so need to run
# in their own specific environment