summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xlib/fuzzing/decode_ndr_X_crash12
-rw-r--r--lib/krb5_wrap/krb5_samba.h28
-rw-r--r--lib/ldb-samba/ldif_handlers.c94
-rw-r--r--lib/ldb/ABI/ldb-2.9.1.sigs305
-rw-r--r--lib/ldb/ABI/pyldb-util-2.9.1.sigs3
-rw-r--r--lib/ldb/common/attrib_handlers.c53
-rw-r--r--lib/ldb/common/ldb_dn.c30
-rw-r--r--lib/ldb/common/ldb_msg.c13
-rw-r--r--lib/ldb/common/qsort.c2
-rw-r--r--lib/ldb/include/ldb.h16
-rw-r--r--lib/ldb/modules/sort.c19
-rw-r--r--lib/ldb/wscript2
-rw-r--r--lib/socket/interfaces.c22
-rw-r--r--lib/torture/torture.h20
-rw-r--r--lib/util/charset/codepoints.c15
-rw-r--r--lib/util/charset/tests/charset.c31
-rw-r--r--lib/util/charset/util_str.c9
-rw-r--r--lib/util/data_blob.c5
-rw-r--r--lib/util/tests/binsearch.c6
-rw-r--r--lib/util/tests/test_ms_fnmatch.c2
-rw-r--r--lib/util/tsort.h19
-rw-r--r--libcli/http/http.c309
-rw-r--r--libcli/http/http_internal.h4
-rw-r--r--libcli/nbt/libnbt.h3
-rw-r--r--libcli/nbt/nbtsocket.c44
-rw-r--r--libcli/security/dom_sid.c14
-rw-r--r--libcli/smb/smbXcli_base.c104
-rw-r--r--libcli/smb/smbXcli_base.h5
28 files changed, 1067 insertions, 122 deletions
diff --git a/lib/fuzzing/decode_ndr_X_crash b/lib/fuzzing/decode_ndr_X_crash
index 63c3cd7..d90e7ef 100755
--- a/lib/fuzzing/decode_ndr_X_crash
+++ b/lib/fuzzing/decode_ndr_X_crash
@@ -61,8 +61,9 @@ def process_one_file(f):
def main():
parser = argparse.ArgumentParser()
- parser.add_argument('-p', '--pipe', default='$PIPE',
- help='pipe name (for output command line)')
+ parser.add_argument('-p', '--pipe', default=None,
+ help=('pipe name (for output command line, '
+ 'default is a guess or "$PIPE")'))
parser.add_argument('-t', '--type', default=None, choices=TYPES,
help='restrict to this type')
parser.add_argument('-o', '--opnum', default=None, type=int,
@@ -91,6 +92,13 @@ def main():
sys.exit(1)
for fn in args.FILES:
+ if pipe is None:
+ m = re.search(r'clusterfuzz-testcase.+-fuzz_ndr_([a-z]+)', fn)
+ if m is None:
+ pipe = '$PIPE'
+ else:
+ pipe = m.group(1)
+
if args.crash_filter is not None:
if not re.search(args.crash_filter, fn):
print_if_verbose(f"skipping {fn}")
diff --git a/lib/krb5_wrap/krb5_samba.h b/lib/krb5_wrap/krb5_samba.h
index e158a40..7951064 100644
--- a/lib/krb5_wrap/krb5_samba.h
+++ b/lib/krb5_wrap/krb5_samba.h
@@ -89,6 +89,34 @@
#endif
/*
+ * RFC8009 encryption types' defines have different names:
+ *
+ * KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128 in Heimdal
+ * ENCTYPE_AES128_CTS_HMAC_SHA256_128 in MIT
+ *
+ * and
+ *
+ * KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192 in Heimdal
+ * ENCTYPE_AES256_CTS_HMAC_SHA384_192 in MIT
+ */
+#if !defined(ENCTYPE_AES128_CTS_HMAC_SHA256_128)
+#define ENCTYPE_AES128_CTS_HMAC_SHA256_128 KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128
+#endif
+#if !defined(ENCTYPE_AES256_CTS_HMAC_SHA384_192)
+#define ENCTYPE_AES256_CTS_HMAC_SHA384_192 KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192
+#endif
+
+/*
+ * Same for older encryption types, rename to have the same defines
+ */
+#if !defined(ENCTYPE_AES128_CTS_HMAC_SHA1_96)
+#define ENCTYPE_AES128_CTS_HMAC_SHA1_96 KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96
+#endif
+#if !defined(ENCTYPE_AES256_CTS_HMAC_SHA1_96)
+#define ENCTYPE_AES256_CTS_HMAC_SHA1_96 KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96
+#endif
+
+/*
* KRB5_KU_OTHER_ENCRYPTED in Heimdal
* KRB5_KEYUSAGE_APP_DATA_ENCRYPT in MIT
*/
diff --git a/lib/ldb-samba/ldif_handlers.c b/lib/ldb-samba/ldif_handlers.c
index c30fd63..4f9d67e 100644
--- a/lib/ldb-samba/ldif_handlers.c
+++ b/lib/ldb-samba/ldif_handlers.c
@@ -150,36 +150,47 @@ bool ldif_comparision_objectSid_isString(const struct ldb_val *v)
/*
compare two objectSids
+
+ If the SIDs seem to be strings, they are converted to binary form.
*/
static int ldif_comparison_objectSid(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
- if (ldif_comparision_objectSid_isString(v1) && ldif_comparision_objectSid_isString(v2)) {
- return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
- } else if (ldif_comparision_objectSid_isString(v1)
- && !ldif_comparision_objectSid_isString(v2)) {
- struct ldb_val v;
- int ret;
- if (ldif_read_objectSid(ldb, mem_ctx, v1, &v) != 0) {
- /* Perhaps not a string after all */
- return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
+ bool v1_is_string = ldif_comparision_objectSid_isString(v1);
+ bool v2_is_string = ldif_comparision_objectSid_isString(v2);
+ struct ldb_val parsed_1 = {};
+ struct ldb_val parsed_2 = {};
+ int ret;
+ /*
+ * If the ldb_vals look like SID strings (i.e. start with "S-"
+ * or "s-"), we try to parse them as such. If that fails, we
+ * assume they are binary SIDs, even though that's not really
+ * possible -- the first two bytes of a struct dom_sid are the
+ * version (1), and the number of sub-auths (<= 15), neither
+ * of which are close to 'S' or '-'.
+ */
+ if (v1_is_string) {
+ int r = ldif_read_objectSid(ldb, mem_ctx, v1, &parsed_1);
+ if (r == 0) {
+ v1 = &parsed_1;
}
- ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
- talloc_free(v.data);
- return ret;
- } else if (!ldif_comparision_objectSid_isString(v1)
- && ldif_comparision_objectSid_isString(v2)) {
- struct ldb_val v;
- int ret;
- if (ldif_read_objectSid(ldb, mem_ctx, v2, &v) != 0) {
- /* Perhaps not a string after all */
- return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
+ }
+ if (v2_is_string) {
+ int r = ldif_read_objectSid(ldb, mem_ctx, v2, &parsed_2);
+ if (r == 0) {
+ v2 = &parsed_2;
}
- ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
- talloc_free(v.data);
- return ret;
}
- return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
+
+ ret = ldb_comparison_binary(ldb, mem_ctx, v1, v2);
+
+ if (v1_is_string) {
+ TALLOC_FREE(parsed_1.data);
+ }
+ if (v2_is_string) {
+ TALLOC_FREE(parsed_2.data);
+ }
+ return ret;
}
/*
@@ -1148,22 +1159,41 @@ static int samba_ldb_dn_link_comparison(struct ldb_context *ldb, void *mem_ctx,
struct ldb_dn *dn1 = NULL, *dn2 = NULL;
int ret;
+ /*
+ * In a sort context, Deleted DNs get shifted to the end.
+ * They never match in an equality
+ */
if (dsdb_dn_is_deleted_val(v1)) {
- /* If the DN is deleted, then we can't search for it */
- return -1;
- }
-
- if (dsdb_dn_is_deleted_val(v2)) {
- /* If the DN is deleted, then we can't search for it */
+ if (! dsdb_dn_is_deleted_val(v2)) {
+ return 1;
+ }
+ /*
+ * They are both deleted!
+ *
+ * The soundest thing to do at this point is carry on
+ * and compare the DNs normally. This matches the
+ * behaviour of samba_dn_extended_match() below.
+ */
+ } else if (dsdb_dn_is_deleted_val(v2)) {
return -1;
}
dn1 = ldb_dn_from_ldb_val(mem_ctx, ldb, v1);
- if ( ! ldb_dn_validate(dn1)) return -1;
-
dn2 = ldb_dn_from_ldb_val(mem_ctx, ldb, v2);
+
+ if ( ! ldb_dn_validate(dn1)) {
+ TALLOC_FREE(dn1);
+ if ( ! ldb_dn_validate(dn2)) {
+ TALLOC_FREE(dn2);
+ return 0;
+ }
+ TALLOC_FREE(dn2);
+ return 1;
+ }
+
if ( ! ldb_dn_validate(dn2)) {
- talloc_free(dn1);
+ TALLOC_FREE(dn1);
+ TALLOC_FREE(dn2);
return -1;
}
diff --git a/lib/ldb/ABI/ldb-2.9.1.sigs b/lib/ldb/ABI/ldb-2.9.1.sigs
new file mode 100644
index 0000000..759659a
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.9.1.sigs
@@ -0,0 +1,305 @@
+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_attrs_in_place: int (struct ldb_message *, const char * const *)
+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_match_scope: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *, enum ldb_scope)
+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_distinguished_name: int (struct ldb_message *)
+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_string_flags: int (struct ldb_message *, const char *, const char *, int)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_append_fmt: int (struct ldb_message *, int, const char *, const char *, ...)
+ldb_msg_append_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *, int)
+ldb_msg_append_steal_string: int (struct ldb_message *, const char *, char *, int)
+ldb_msg_append_steal_value: int (struct ldb_message *, const char *, struct ldb_val *, int)
+ldb_msg_append_string: int (struct ldb_message *, const char *, const char *, int)
+ldb_msg_append_value: int (struct ldb_message *, const char *, const struct ldb_val *, int)
+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_add_value: int (TALLOC_CTX *, struct ldb_message_element *, const struct ldb_val *)
+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_element_is_inaccessible: bool (const struct ldb_message_element *)
+ldb_msg_element_mark_inaccessible: void (struct ldb_message_element *)
+ldb_msg_elements_take_ownership: int (struct ldb_message *)
+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_remove_inaccessible: void (struct ldb_message *)
+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_shrink_to_fit: void (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_get_attr: const char *(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_register_redact_callback: int (struct ldb_context *, ldb_redact_fn, struct ldb_module *)
+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_as_bool: int (const struct ldb_val *, bool *)
+ldb_val_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_val *)
+ldb_val_as_int64: int (const struct ldb_val *, int64_t *)
+ldb_val_as_uint64: int (const struct ldb_val *, uint64_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.9.1.sigs b/lib/ldb/ABI/pyldb-util-2.9.1.sigs
new file mode 100644
index 0000000..164a806
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.9.1.sigs
@@ -0,0 +1,3 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
+pyldb_check_type: bool (PyObject *, const char *)
diff --git a/lib/ldb/common/attrib_handlers.c b/lib/ldb/common/attrib_handlers.c
index 15470cf..3d13e4b 100644
--- a/lib/ldb/common/attrib_handlers.c
+++ b/lib/ldb/common/attrib_handlers.c
@@ -281,15 +281,36 @@ static int ldb_canonicalise_Boolean(struct ldb_context *ldb, void *mem_ctx,
}
/*
- compare two Booleans
-*/
+ * compare two Booleans.
+ *
+ * According to RFC4517 4.2.2, "the booleanMatch rule is an equality matching
+ * rule", meaning it isn't used for ordering.
+ *
+ * However, it seems conceivable that Samba could be coerced into sorting on a
+ * field with Boolean syntax, so we might as well have consistent behaviour in
+ * that case.
+ *
+ * The most probably values are {"FALSE", 5} and {"TRUE", 4}. To save time we
+ * compare first by length, which makes FALSE > TRUE. This is somewhat
+ * contrary to convention, but is how Samba has worked forever.
+ *
+ * If somehow we are comparing incompletely normalised values where the length
+ * is the same (for example {"false", 5} and {"TRUE\0", 5}), the length is the
+ * same, and we fall back to a strncasecmp. In this case, since "FALSE" is
+ * alphabetically lower, we swap the order, so that "TRUE\0" again comes
+ * before "FALSE".
+ *
+ * ldb_canonicalise_Boolean (just above) gives us a clue as to what we might
+ * expect to cope with by way of invalid values.
+ */
static int ldb_comparison_Boolean(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
if (v1->length != v2->length) {
- return v1->length - v2->length;
+ return NUMERIC_CMP(v2->length, v1->length);
}
- return strncasecmp((char *)v1->data, (char *)v2->data, v1->length);
+ /* reversed, see long comment above */
+ return strncasecmp((char *)v2->data, (char *)v1->data, v1->length);
}
@@ -300,7 +321,7 @@ int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
if (v1->length != v2->length) {
- return v1->length - v2->length;
+ return NUMERIC_CMP(v1->length, v2->length);
}
return memcmp(v1->data, v2->data, v1->length);
}
@@ -372,17 +393,27 @@ utf8str:
b2 = ldb_casefold(ldb, mem_ctx, s2, n2);
if (!b1 || !b2) {
- /* One of the strings was not UTF8, so we have no
- * options but to do a binary compare */
+ /*
+ * One of the strings was not UTF8, so we have no
+ * options but to do a binary compare.
+ */
talloc_free(b1);
talloc_free(b2);
ret = memcmp(s1, s2, MIN(n1, n2));
if (ret == 0) {
- if (n1 == n2) return 0;
+ if (n1 == n2) {
+ return 0;
+ }
if (n1 > n2) {
- return (int)ldb_ascii_toupper(s1[n2]);
+ if (s1[n2] == '\0') {
+ return 0;
+ }
+ return 1;
} else {
- return -(int)ldb_ascii_toupper(s2[n1]);
+ if (s2[n1] == '\0') {
+ return 0;
+ }
+ return -1;
}
}
return ret;
@@ -404,7 +435,7 @@ utf8str:
while (*u1 == ' ') u1++;
while (*u2 == ' ') u2++;
}
- ret = (int)(*u1 - *u2);
+ ret = NUMERIC_CMP(*u1, *u2);
talloc_free(b1);
talloc_free(b2);
diff --git a/lib/ldb/common/ldb_dn.c b/lib/ldb/common/ldb_dn.c
index 601da57..8388fdb 100644
--- a/lib/ldb/common/ldb_dn.c
+++ b/lib/ldb/common/ldb_dn.c
@@ -1111,7 +1111,7 @@ int ldb_dn_compare_base(struct ldb_dn *base, struct ldb_dn *dn)
/* compare attr.cf_value. */
if (b_vlen != dn_vlen) {
- return b_vlen - dn_vlen;
+ return NUMERIC_CMP(b_vlen, dn_vlen);
}
ret = strncmp(b_vdata, dn_vdata, b_vlen);
if (ret != 0) return ret;
@@ -1132,8 +1132,32 @@ int ldb_dn_compare(struct ldb_dn *dn0, struct ldb_dn *dn1)
{
unsigned int i;
int ret;
+ /*
+ * If used in sort, we shift NULL and invalid DNs to the end.
+ *
+ * If ldb_dn_casefold_internal() fails, that goes to the end too, so
+ * we end up with:
+ *
+ * | normal DNs, sorted | casefold failed DNs | invalid DNs | NULLs |
+ */
- if (( ! dn0) || dn0->invalid || ! dn1 || dn1->invalid) {
+ if (dn0 == dn1) {
+ /* this includes the both-NULL case */
+ return 0;
+ }
+ if (dn0 == NULL) {
+ return 1;
+ }
+ if (dn1 == NULL) {
+ return -1;
+ }
+ if (dn0->invalid && dn1->invalid) {
+ return 0;
+ }
+ if (dn0->invalid) {
+ return 1;
+ }
+ if (dn1->invalid) {
return -1;
}
@@ -1190,7 +1214,7 @@ int ldb_dn_compare(struct ldb_dn *dn0, struct ldb_dn *dn1)
/* compare attr.cf_value. */
if (dn0_vlen != dn1_vlen) {
- return dn0_vlen - dn1_vlen;
+ return NUMERIC_CMP(dn0_vlen, dn1_vlen);
}
ret = strncmp(dn0_vdata, dn1_vdata, dn0_vlen);
if (ret != 0) {
diff --git a/lib/ldb/common/ldb_msg.c b/lib/ldb/common/ldb_msg.c
index afddbe4..c334d70 100644
--- a/lib/ldb/common/ldb_msg.c
+++ b/lib/ldb/common/ldb_msg.c
@@ -93,7 +93,7 @@ struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
static int ldb_val_cmp(const struct ldb_val *v1, const struct ldb_val *v2)
{
if (v1->length != v2->length) {
- return v1->length - v2->length;
+ return NUMERIC_CMP(v1->length, v2->length);
}
return memcmp(v1->data, v2->data, v1->length);
}
@@ -749,9 +749,16 @@ int ldb_msg_element_compare(struct ldb_message_element *el1,
unsigned int i;
if (el1->num_values != el2->num_values) {
- return el1->num_values - el2->num_values;
+ return NUMERIC_CMP(el1->num_values, el2->num_values);
}
-
+ /*
+ * Note this is an inconsistent comparison, unsuitable for
+ * sorting. If A has values {a, b} and B has values {b, c},
+ * then
+ *
+ * ldb_msg_element_compare(A, B) returns -1, meaning A < B
+ * ldb_msg_element_compare(B, A) returns -1, meaning B < A
+ */
for (i=0;i<el1->num_values;i++) {
if (!ldb_msg_find_val(el2, &el1->values[i])) {
return -1;
diff --git a/lib/ldb/common/qsort.c b/lib/ldb/common/qsort.c
index 012aaf3..bae35e6 100644
--- a/lib/ldb/common/qsort.c
+++ b/lib/ldb/common/qsort.c
@@ -227,7 +227,7 @@ void ldb_qsort (void *const pbase, size_t total_elems, size_t size,
while ((run_ptr += size) <= end_ptr)
{
tmp_ptr = run_ptr - size;
- while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, opaque) < 0)
+ while (tmp_ptr > base_ptr && (*cmp) ((void *) run_ptr, (void *) tmp_ptr, opaque) < 0)
tmp_ptr -= size;
tmp_ptr += size;
diff --git a/lib/ldb/include/ldb.h b/lib/ldb/include/ldb.h
index 5d83a27..98859d4 100644
--- a/lib/ldb/include/ldb.h
+++ b/lib/ldb/include/ldb.h
@@ -2326,6 +2326,22 @@ do { \
} while (0)
#endif
+#ifndef NUMERIC_CMP
+/*
+ * NUMERIC_CMP is a safe replacement for `a - b` in comparison
+ * functions. It will work on integers, pointers, and floats.
+ *
+ * Rather than
+ *
+ * return a - b;
+ *
+ * use
+ *
+ * return NUMERIC_CMP(a, b);
+ */
+#define NUMERIC_CMP(a, b) (((a) > (b)) - ((a) < (b)))
+#endif
+
/**
diff --git a/lib/ldb/modules/sort.c b/lib/ldb/modules/sort.c
index cb6f8df..72c60fc 100644
--- a/lib/ldb/modules/sort.c
+++ b/lib/ldb/modules/sort.c
@@ -121,15 +121,28 @@ static int sort_compare(struct ldb_message **msg1, struct ldb_message **msg2, vo
el1 = ldb_msg_find_element(*msg1, ac->attributeName);
el2 = ldb_msg_find_element(*msg2, ac->attributeName);
- if (!el1 && el2) {
+ /*
+ * NULL and empty elements sort at the end (regardless of ac->reverse flag).
+ * NULL elements come after empty ones.
+ */
+ if (el1 == el2) {
+ return 0;
+ }
+ if (el1 == NULL) {
return 1;
}
- if (el1 && !el2) {
+ if (el2 == NULL) {
return -1;
}
- if (!el1 && !el2) {
+ if (unlikely(el1->num_values == 0 && el2->num_values == 0)) {
return 0;
}
+ if (unlikely(el1->num_values == 0)) {
+ return 1;
+ }
+ if (unlikely(el2->num_values == 0)) {
+ return -1;
+ }
if (ac->reverse)
return ac->a->syntax->comparison_fn(ldb, ac, &el2->values[0], &el1->values[0]);
diff --git a/lib/ldb/wscript b/lib/ldb/wscript
index c249a82..936abe7 100644
--- a/lib/ldb/wscript
+++ b/lib/ldb/wscript
@@ -2,7 +2,7 @@
APPNAME = 'ldb'
# For Samba 4.20.x !
-VERSION = '2.9.0'
+VERSION = '2.9.1'
import sys, os
diff --git a/lib/socket/interfaces.c b/lib/socket/interfaces.c
index 4908b0f..2426ce2 100644
--- a/lib/socket/interfaces.c
+++ b/lib/socket/interfaces.c
@@ -386,18 +386,18 @@ static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
if (((struct sockaddr *)&i1->ip)->sa_family == AF_INET) {
struct sockaddr_in *s1 = (struct sockaddr_in *)&i1->ip;
struct sockaddr_in *s2 = (struct sockaddr_in *)&i2->ip;
-
- r = ntohl(s1->sin_addr.s_addr) -
- ntohl(s2->sin_addr.s_addr);
- if (r) {
- return r;
+ uint32_t a1 = ntohl(s1->sin_addr.s_addr);
+ uint32_t a2 = ntohl(s2->sin_addr.s_addr);
+ r = NUMERIC_CMP(a1, a2);
+ if (r == 0) {
+ /* compare netmasks as a tiebreaker */
+ s1 = (struct sockaddr_in *)&i1->netmask;
+ s2 = (struct sockaddr_in *)&i2->netmask;
+ a1 = ntohl(s1->sin_addr.s_addr);
+ a2 = ntohl(s2->sin_addr.s_addr);
+ r = NUMERIC_CMP(a1, a2);
}
-
- s1 = (struct sockaddr_in *)&i1->netmask;
- s2 = (struct sockaddr_in *)&i2->netmask;
-
- return ntohl(s1->sin_addr.s_addr) -
- ntohl(s2->sin_addr.s_addr);
+ return r;
}
return 0;
}
diff --git a/lib/torture/torture.h b/lib/torture/torture.h
index 2e86e31..2194703 100644
--- a/lib/torture/torture.h
+++ b/lib/torture/torture.h
@@ -534,6 +534,26 @@ static inline void torture_dump_data_str_cb(const char *buf, void *private_data)
} \
} while(0)
+#define torture_assert_int_less(torture_ctx,got,limit,cmt)\
+ do { int __got = (got), __limit = (limit); \
+ if (__got >= __limit) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %d (0x%X), expected < %d (0x%X): %s", \
+ __got, __got, __limit, __limit, cmt); \
+ return false; \
+ } \
+ } while(0)
+
+#define torture_assert_int_greater(torture_ctx,got,limit,cmt)\
+ do { int __got = (got), __limit = (limit); \
+ if (__got <= __limit) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %d (0x%X), expected > %d (0x%X): %s", \
+ __got, __got, __limit, __limit, cmt); \
+ return false; \
+ } \
+ } while(0)
+
#define torture_assert_int_equal_goto(torture_ctx,got,expected,ret,label,cmt)\
do { int __got = (got), __expected = (expected); \
if (__got != __expected) { \
diff --git a/lib/util/charset/codepoints.c b/lib/util/charset/codepoints.c
index ea2c4be..8022627 100644
--- a/lib/util/charset/codepoints.c
+++ b/lib/util/charset/codepoints.c
@@ -26,6 +26,7 @@
#include "dynconfig/dynconfig.h"
#include "lib/util/debug.h"
#include "lib/util/byteorder.h"
+#include "lib/util/tsort.h"
#ifdef strcasecmp
#undef strcasecmp
@@ -16479,11 +16480,23 @@ _PUBLIC_ bool isupper_m(codepoint_t val)
*/
_PUBLIC_ int codepoint_cmpi(codepoint_t c1, codepoint_t c2)
{
+ /*
+ * FIXME: this is unsuitable for use in a sort, as the
+ * comparison is intransitive.
+ *
+ * The problem is toupper_m() is only called on equality case,
+ * which has strange effects.
+ *
+ * Consider {'a', 'A', 'B'}.
+ * 'a' == 'A'
+ * 'a' > 'B' (lowercase letters come after upper)
+ * 'A' < 'B'
+ */
if (c1 == c2 ||
toupper_m(c1) == toupper_m(c2)) {
return 0;
}
- return c1 - c2;
+ return NUMERIC_CMP(c1, c2);
}
diff --git a/lib/util/charset/tests/charset.c b/lib/util/charset/tests/charset.c
index 547dc51..bca5449 100644
--- a/lib/util/charset/tests/charset.c
+++ b/lib/util/charset/tests/charset.c
@@ -72,16 +72,19 @@ static bool test_strcasecmp_m(struct torture_context *tctx)
const char file_iso8859_1[7] = { 0x66, 0x69, 0x6c, 0x65, 0x2d, 0xe9, 0 };
/* file.{accented e} in utf8 */
const char file_utf8[8] = { 0x66, 0x69, 0x6c, 0x65, 0x2d, 0xc3, 0xa9, 0 };
- torture_assert_int_equal(tctx, strcasecmp_m("foo", "bar"), 4, "different strings both lower");
- torture_assert_int_equal(tctx, strcasecmp_m("foo", "Bar"), 4, "different strings lower/upper");
- torture_assert_int_equal(tctx, strcasecmp_m("Foo", "bar"), 4, "different strings upper/lower");
- torture_assert_int_equal(tctx, strcasecmp_m("AFoo", "_bar"), 2, "different strings upper/lower");
+ torture_assert_int_greater(tctx, strcasecmp_m("foo", "bar"), 0, "different strings both lower");
+ torture_assert_int_less(tctx, strcasecmp_m("bar", "foo"), 0, "different strings both lower");
+ torture_assert_int_greater(tctx, strcasecmp_m("foo", "Bar"), 0, "different strings lower/upper");
+ torture_assert_int_greater(tctx, strcasecmp_m("Foo", "bar"), 0, "different strings upper/lower");
+ torture_assert_int_greater(tctx, strcasecmp_m("AFoo", "_bar"), 0, "different strings upper/lower");
torture_assert_int_equal(tctx, strcasecmp_m("foo", "foo"), 0, "same case strings");
torture_assert_int_equal(tctx, strcasecmp_m("foo", "Foo"), 0, "different case strings");
- torture_assert_int_equal(tctx, strcasecmp_m(NULL, "Foo"), -1, "one NULL");
- torture_assert_int_equal(tctx, strcasecmp_m("foo", NULL), 1, "other NULL");
+ torture_assert_int_greater(tctx, strcasecmp_m("food", "Foo"), 0, "strings differ towards the end");
+ torture_assert_int_less(tctx, strcasecmp_m("food", "Fool"), 0, "strings differ towards the end");
+ torture_assert_int_less(tctx, strcasecmp_m(NULL, "Foo"), 0, "one NULL");
+ torture_assert_int_greater(tctx, strcasecmp_m("foo", NULL), 0, "other NULL");
torture_assert_int_equal(tctx, strcasecmp_m(NULL, NULL), 0, "both NULL");
- torture_assert_int_equal(tctx, strcasecmp_m(file_iso8859_1, file_utf8), 38,
+ torture_assert_int_greater(tctx, strcasecmp_m(file_iso8859_1, file_utf8), 0,
"file.{accented e} should differ");
return true;
}
@@ -151,19 +154,19 @@ static bool test_strncasecmp_m(struct torture_context *tctx)
const char file_iso8859_1[7] = { 0x66, 0x69, 0x6c, 0x65, 0x2d, 0xe9, 0 };
/* file.{accented e} in utf8 */
const char file_utf8[8] = { 0x66, 0x69, 0x6c, 0x65, 0x2d, 0xc3, 0xa9, 0 };
- torture_assert_int_equal(tctx, strncasecmp_m("foo", "bar", 3), 4, "different strings both lower");
- torture_assert_int_equal(tctx, strncasecmp_m("foo", "Bar", 3), 4, "different strings lower/upper");
- torture_assert_int_equal(tctx, strncasecmp_m("Foo", "bar", 3), 4, "different strings upper/lower");
- torture_assert_int_equal(tctx, strncasecmp_m("AFoo", "_bar", 4), 2, "different strings upper/lower");
+ torture_assert_int_greater(tctx, strncasecmp_m("foo", "bar", 3), 0, "different strings both lower");
+ torture_assert_int_greater(tctx, strncasecmp_m("foo", "Bar", 3), 0, "different strings lower/upper");
+ torture_assert_int_greater(tctx, strncasecmp_m("Foo", "bar", 3), 0, "different strings upper/lower");
+ torture_assert_int_greater(tctx, strncasecmp_m("AFoo", "_bar", 4), 0, "different strings upper/lower");
torture_assert_int_equal(tctx, strncasecmp_m("foo", "foo", 3), 0, "same case strings");
torture_assert_int_equal(tctx, strncasecmp_m("foo", "Foo", 3), 0, "different case strings");
torture_assert_int_equal(tctx, strncasecmp_m("fool", "Foo", 3),0, "different case strings");
torture_assert_int_equal(tctx, strncasecmp_m("fool", "Fool", 40), 0, "over size");
torture_assert_int_equal(tctx, strncasecmp_m("BLA", "Fool", 0),0, "empty");
- torture_assert_int_equal(tctx, strncasecmp_m(NULL, "Foo", 3), -1, "one NULL");
- torture_assert_int_equal(tctx, strncasecmp_m("foo", NULL, 3), 1, "other NULL");
+ torture_assert_int_less(tctx, strncasecmp_m(NULL, "Foo", 3), 0, "one NULL");
+ torture_assert_int_greater(tctx, strncasecmp_m("foo", NULL, 3), 0, "other NULL");
torture_assert_int_equal(tctx, strncasecmp_m(NULL, NULL, 3), 0, "both NULL");
- torture_assert_int_equal(tctx, strncasecmp_m(file_iso8859_1, file_utf8, 6), 38,
+ torture_assert_int_greater(tctx, strncasecmp_m(file_iso8859_1, file_utf8, 6), 0,
"file.{accented e} should differ");
return true;
}
diff --git a/lib/util/charset/util_str.c b/lib/util/charset/util_str.c
index 1650c9b..c52b773 100644
--- a/lib/util/charset/util_str.c
+++ b/lib/util/charset/util_str.c
@@ -26,6 +26,7 @@
#include "system/locale.h"
#include "charset.h"
#include "lib/util/fault.h"
+#include "lib/util/tsort.h"
#ifdef strcasecmp
#undef strcasecmp
@@ -79,10 +80,10 @@ _PUBLIC_ int strcasecmp_m_handle(struct smb_iconv_handle *iconv_handle,
continue;
}
- return l1 - l2;
+ return NUMERIC_CMP(l1, l2);
}
- return *s1 - *s2;
+ return NUMERIC_CMP(*s1, *s2);
}
/**
@@ -156,14 +157,14 @@ _PUBLIC_ int strncasecmp_m_handle(struct smb_iconv_handle *iconv_handle,
continue;
}
- return l1 - l2;
+ return NUMERIC_CMP(l1, l2);
}
if (n == 0) {
return 0;
}
- return *s1 - *s2;
+ return NUMERIC_CMP(*s1, *s2);
}
/**
diff --git a/lib/util/data_blob.c b/lib/util/data_blob.c
index 69a340c..1558200 100644
--- a/lib/util/data_blob.c
+++ b/lib/util/data_blob.c
@@ -22,6 +22,7 @@
#include "attr.h"
#include "data_blob.h"
#include "lib/util/samba_util.h"
+#include "lib/util/tsort.h"
const DATA_BLOB data_blob_null = { NULL, 0 };
@@ -121,12 +122,12 @@ _PUBLIC_ int data_blob_cmp(const DATA_BLOB *d1, const DATA_BLOB *d2)
return 1;
}
if (d1->data == d2->data) {
- return d1->length - d2->length;
+ return NUMERIC_CMP(d1->length, d2->length);
}
ret = memcmp(d1->data, d2->data, MIN(d1->length, d2->length));
if (ret == 0) {
/* Note this ordering is used in conditional aces */
- return d1->length - d2->length;
+ return NUMERIC_CMP(d1->length, d2->length);
}
return ret;
}
diff --git a/lib/util/tests/binsearch.c b/lib/util/tests/binsearch.c
index b3ecda1..2484015 100644
--- a/lib/util/tests/binsearch.c
+++ b/lib/util/tests/binsearch.c
@@ -23,17 +23,19 @@
#include "includes.h"
#include "lib/util/binsearch.h"
+#include "lib/util/tsort.h"
#include "torture/torture.h"
#include "torture/local/proto.h"
static int int_cmp(int a, int b)
{
- return a - b;
+ return NUMERIC_CMP(a, b);
}
static int int_cmp_p(int a, int *b)
{
- return a - *b;
+ int _b = *b;
+ return NUMERIC_CMP(a, _b);
}
static bool test_binsearch_v(struct torture_context *tctx)
diff --git a/lib/util/tests/test_ms_fnmatch.c b/lib/util/tests/test_ms_fnmatch.c
index d11c7be..2261f9b 100644
--- a/lib/util/tests/test_ms_fnmatch.c
+++ b/lib/util/tests/test_ms_fnmatch.c
@@ -36,7 +36,7 @@ static void test_ms_fn_match_protocol_no_wildcard(void **state)
/* no wildcards in pattern, a simple strcasecmp_m */
cmp = ms_fnmatch_protocol("pattern", "string", PROTOCOL_COREPLUS,
true); /* case sensitive */
- assert_int_equal(cmp, -3);
+ assert_true(cmp < 0);
}
static void test_ms_fn_match_protocol_pattern_upgraded(void **state)
diff --git a/lib/util/tsort.h b/lib/util/tsort.h
index 811d6cd..18e82d6 100644
--- a/lib/util/tsort.h
+++ b/lib/util/tsort.h
@@ -37,4 +37,23 @@ do { \
} while (0)
#endif
+
+#ifndef NUMERIC_CMP
+/*
+ * NUMERIC_CMP is a safe replacement for `a - b` in comparison
+ * functions. It will work on integers, pointers, and floats.
+ *
+ * Rather than
+ *
+ * return a - b;
+ *
+ * use
+ *
+ * return NUMERIC_CMP(a, b);
+ *
+ * and you won't have any troubles if a - b would overflow.
+ */
+#define NUMERIC_CMP(a, b) (((a) > (b)) - ((a) < (b)))
+#endif
+
#endif
diff --git a/libcli/http/http.c b/libcli/http/http.c
index 96c573a..6f22214 100644
--- a/libcli/http/http.c
+++ b/libcli/http/http.c
@@ -28,16 +28,28 @@
#undef strcasecmp
+enum http_body_type {
+ BODY_NONE = 0,
+ BODY_CONTENT_LENGTH,
+ BODY_CHUNKED,
+ BODY_ERROR = -1
+};
+
/**
* Determines if a response should have a body.
- * @return 1 if the response MUST have a body; 0 if the response MUST NOT have
- * a body. Returns -1 on error.
+ * @return 2 if response MUST use chunked encoding,
+ * 1 if the response MUST have a body;
+ * 0 if the response MUST NOT have a body.
+ * Returns -1 on error.
*/
-static int http_response_needs_body(struct http_request *req)
+static enum http_body_type http_response_needs_body(
+ struct http_request *req)
{
struct http_header *h = NULL;
- if (!req) return -1;
+ if (!req) {
+ return BODY_ERROR;
+ }
for (h = req->headers; h != NULL; h = h->next) {
int cmp;
@@ -45,6 +57,18 @@ static int http_response_needs_body(struct http_request *req)
char c;
unsigned long long v;
+ cmp = strcasecmp(h->key, "Transfer-Encoding");
+ if (cmp == 0) {
+ cmp = strcasecmp(h->value, "chunked");
+ if (cmp == 0) {
+ return BODY_CHUNKED;
+ }
+ /* unsupported Transfer-Encoding type */
+ DBG_ERR("Unsupported transfer encoding type %s\n",
+ h->value);
+ return BODY_ERROR;
+ }
+
cmp = strcasecmp(h->key, "Content-Length");
if (cmp != 0) {
continue;
@@ -52,20 +76,25 @@ static int http_response_needs_body(struct http_request *req)
n = sscanf(h->value, "%llu%c", &v, &c);
if (n != 1) {
- return -1;
+ return BODY_ERROR;
}
req->remaining_content_length = v;
if (v != 0) {
- return 1;
+ return BODY_CONTENT_LENGTH;
}
- return 0;
+ return BODY_NONE;
}
- return 0;
+ return BODY_NONE;
}
+struct http_chunk
+{
+ struct http_chunk *prev, *next;
+ DATA_BLOB blob;
+};
struct http_read_response_state {
enum http_parser_state parser_state;
@@ -73,6 +102,7 @@ struct http_read_response_state {
uint64_t max_content_length;
DATA_BLOB buffer;
struct http_request *response;
+ struct http_chunk *chunks;
};
/**
@@ -86,7 +116,7 @@ static enum http_read_status http_parse_headers(struct http_read_response_state
char *key = NULL;
char *value = NULL;
int n = 0;
- int ret;
+ enum http_body_type ret;
/* Sanity checks */
if (!state || !state->response) {
@@ -119,19 +149,24 @@ static enum http_read_status http_parse_headers(struct http_read_response_state
ret = http_response_needs_body(state->response);
switch (ret) {
- case 1:
+ case BODY_CHUNKED:
+ DEBUG(11, ("%s: need to process chunks... %d\n", __func__,
+ state->response->response_code));
+ state->parser_state = HTTP_READING_CHUNK_SIZE;
+ break;
+ case BODY_CONTENT_LENGTH:
if (state->response->remaining_content_length <= state->max_content_length) {
DEBUG(11, ("%s: Start of read body\n", __func__));
state->parser_state = HTTP_READING_BODY;
break;
}
FALL_THROUGH;
- case 0:
+ case BODY_NONE:
DEBUG(11, ("%s: Skipping body for code %d\n", __func__,
state->response->response_code));
state->parser_state = HTTP_READING_DONE;
break;
- case -1:
+ case BODY_ERROR:
DEBUG(0, ("%s_: Error in http_response_needs_body\n", __func__));
TALLOC_FREE(line);
return HTTP_DATA_CORRUPTED;
@@ -162,6 +197,141 @@ error:
return status;
}
+static bool http_response_process_chunks(struct http_read_response_state *state)
+{
+ struct http_chunk *chunk = NULL;
+ struct http_request *resp = state->response;
+
+ for (chunk = state->chunks; chunk; chunk = chunk->next) {
+ DBG_DEBUG("processing chunk of size %zi\n",
+ chunk->blob.length);
+ if (resp->body.data == NULL) {
+ resp->body = chunk->blob;
+ chunk->blob = data_blob_null;
+ talloc_steal(resp, resp->body.data);
+ continue;
+ }
+
+ resp->body.data =
+ talloc_realloc(resp,
+ resp->body.data,
+ uint8_t,
+ resp->body.length + chunk->blob.length);
+ if (!resp->body.data) {
+ return false;
+ }
+ memcpy(resp->body.data + resp->body.length,
+ chunk->blob.data,
+ chunk->blob.length);
+
+ resp->body.length += chunk->blob.length;
+
+ TALLOC_FREE(chunk->blob.data);
+ chunk->blob = data_blob_null;
+ }
+ return true;
+}
+
+static enum http_read_status http_read_chunk_term(struct http_read_response_state *state)
+{
+ enum http_read_status status = HTTP_ALL_DATA_READ;
+ char *ptr = NULL;
+ char *line = NULL;
+
+ /* Sanity checks */
+ if (!state || !state->response) {
+ DBG_ERR("%s: Invalid Parameter\n", __func__);
+ return HTTP_DATA_CORRUPTED;
+ }
+
+ line = talloc_strndup(state, (char *)state->buffer.data, state->buffer.length);
+ if (!line) {
+ DBG_ERR("%s: Memory error\n", __func__);
+ return HTTP_DATA_CORRUPTED;
+ }
+ ptr = strstr(line, "\r\n");
+ if (ptr == NULL) {
+ TALLOC_FREE(line);
+ return HTTP_MORE_DATA_EXPECTED;
+ }
+
+ if (strncmp(line, "\r\n", 2) == 0) {
+ /* chunk terminator */
+ if (state->parser_state == HTTP_READING_FINAL_CHUNK_TERM) {
+ if (http_response_process_chunks(state) == false) {
+ status = HTTP_DATA_CORRUPTED;
+ goto out;
+ }
+ state->parser_state = HTTP_READING_DONE;
+ } else {
+ state->parser_state = HTTP_READING_CHUNK_SIZE;
+ }
+ status = HTTP_ALL_DATA_READ;
+ goto out;
+ }
+
+ status = HTTP_DATA_CORRUPTED;
+out:
+ TALLOC_FREE(line);
+ return status;
+}
+
+static enum http_read_status http_read_chunk_size(struct http_read_response_state *state)
+{
+ enum http_read_status status = HTTP_ALL_DATA_READ;
+ char *ptr = NULL;
+ char *line = NULL;
+ char *value = NULL;
+ int n = 0;
+ unsigned long long v;
+
+ /* Sanity checks */
+ if (!state || !state->response) {
+ DBG_ERR("%s: Invalid Parameter\n", __func__);
+ return HTTP_DATA_CORRUPTED;
+ }
+
+ line = talloc_strndup(state, (char *)state->buffer.data, state->buffer.length);
+ if (!line) {
+ DBG_ERR("%s: Memory error\n", __func__);
+ return HTTP_DATA_CORRUPTED;
+ }
+ ptr = strstr(line, "\r\n");
+ if (ptr == NULL) {
+ TALLOC_FREE(line);
+ return HTTP_MORE_DATA_EXPECTED;
+ }
+
+ n = sscanf(line, "%m[^\r\n]\r\n", &value);
+ if (n != 1) {
+ DBG_ERR("%s: Error parsing chunk size '%s'\n", __func__, line);
+ status = HTTP_DATA_CORRUPTED;
+ goto out;
+ }
+
+ DBG_DEBUG("Got chunk size string %s\n", value);
+ n = sscanf(value, "%llx", &v);
+ if (n != 1) {
+ DBG_ERR("%s: Error parsing chunk size '%s'\n", __func__, line);
+ status = HTTP_DATA_CORRUPTED;
+ goto out;
+ }
+ DBG_DEBUG("Got chunk size %llu 0x%llx\n", v, v);
+ if (v == 0) {
+ state->parser_state = HTTP_READING_FINAL_CHUNK_TERM;
+ } else {
+ state->parser_state = HTTP_READING_CHUNK;
+ }
+ state->response->remaining_content_length = v;
+ status = HTTP_ALL_DATA_READ;
+out:
+ if (value) {
+ free(value);
+ }
+ TALLOC_FREE(line);
+ return status;
+}
+
/**
* Parses the first line of a HTTP response
*/
@@ -301,6 +471,55 @@ static enum http_read_status http_read_body(struct http_read_response_state *sta
return HTTP_ALL_DATA_READ;
}
+static enum http_read_status http_read_chunk(struct http_read_response_state *state)
+{
+ struct http_request *resp = state->response;
+ struct http_chunk *chunk = NULL;
+ size_t total = 0;
+ size_t prev = 0;
+
+ if (state->buffer.length < resp->remaining_content_length) {
+ return HTTP_MORE_DATA_EXPECTED;
+ }
+
+ for (chunk = state->chunks; chunk; chunk = chunk->next) {
+ total += chunk->blob.length;
+ }
+
+ prev = total;
+ total = total + state->buffer.length;
+ if (total < prev) {
+ DBG_ERR("adding chunklen %zu to buf len %zu "
+ "will overflow\n",
+ state->buffer.length,
+ prev);
+ return HTTP_DATA_CORRUPTED;
+ }
+ if (total > state->max_content_length) {
+ DBG_DEBUG("size %zu exceeds "
+ "max content len %"PRIu64" skipping body\n",
+ total,
+ state->max_content_length);
+ state->parser_state = HTTP_READING_DONE;
+ goto out;
+ }
+
+ /* chunk read */
+ chunk = talloc_zero(state, struct http_chunk);
+ if (chunk == NULL) {
+ DBG_ERR("%s: Memory error\n", __func__);
+ return HTTP_DATA_CORRUPTED;
+ }
+ chunk->blob = state->buffer;
+ talloc_steal(chunk, chunk->blob.data);
+ DLIST_ADD_END(state->chunks, chunk);
+ state->parser_state = HTTP_READING_CHUNK_TERM;
+out:
+ state->buffer = data_blob_null;
+ resp->remaining_content_length = 0;
+ return HTTP_ALL_DATA_READ;
+}
+
static enum http_read_status http_read_trailer(struct http_read_response_state *state)
{
enum http_read_status status = HTTP_DATA_CORRUPTED;
@@ -323,6 +542,16 @@ static enum http_read_status http_parse_buffer(struct http_read_response_state *
case HTTP_READING_BODY:
return http_read_body(state);
break;
+ case HTTP_READING_FINAL_CHUNK_TERM:
+ case HTTP_READING_CHUNK_TERM:
+ return http_read_chunk_term(state);
+ break;
+ case HTTP_READING_CHUNK_SIZE:
+ return http_read_chunk_size(state);
+ break;
+ case HTTP_READING_CHUNK:
+ return http_read_chunk(state);
+ break;
case HTTP_READING_TRAILER:
return http_read_trailer(state);
break;
@@ -527,20 +756,60 @@ static int http_read_response_next_vector(struct tstream_context *stream,
*_count = 1;
}
break;
- case HTTP_MORE_DATA_EXPECTED:
- /* TODO Optimize, allocating byte by byte */
- state->buffer.data = talloc_realloc(state, state->buffer.data,
- uint8_t, state->buffer.length + 1);
+ case HTTP_MORE_DATA_EXPECTED: {
+ size_t toread = 1;
+ size_t total;
+ if (state->parser_state == HTTP_READING_BODY ||
+ state->parser_state == HTTP_READING_CHUNK) {
+ struct http_request *resp = state->response;
+ toread = resp->remaining_content_length -
+ state->buffer.length;
+ }
+
+ total = toread + state->buffer.length;
+
+ if (total < state->buffer.length) {
+ DBG_ERR("adding %zu to buf len %zu "
+ "will overflow\n",
+ toread,
+ state->buffer.length);
+ return -1;
+ }
+
+ /*
+ * test if content-length message exceeds the
+ * specified max_content_length
+ * Note: This check won't be hit at the moment
+ * due to an existing check in parse_headers
+ * which will skip the body. Check is here
+ * for completeness and to cater for future
+ * code changes.
+ */
+ if (state->parser_state == HTTP_READING_BODY) {
+ if (total > state->max_content_length) {
+ DBG_ERR("content size %zu exceeds "
+ "max content len %"PRIu64"\n",
+ total,
+ state->max_content_length);
+ return -1;
+ }
+ }
+
+ state->buffer.data =
+ talloc_realloc(state, state->buffer.data,
+ uint8_t,
+ state->buffer.length + toread);
if (!state->buffer.data) {
return -1;
}
- state->buffer.length++;
+ state->buffer.length += toread;
vector[0].iov_base = (void *)(state->buffer.data +
- state->buffer.length - 1);
- vector[0].iov_len = 1;
+ state->buffer.length - toread);
+ vector[0].iov_len = toread;
*_vector = vector;
*_count = 1;
break;
+ }
case HTTP_DATA_CORRUPTED:
case HTTP_REQUEST_CANCELED:
case HTTP_DATA_TOO_LONG:
@@ -603,7 +872,7 @@ static void http_read_response_done(struct tevent_req *subreq)
{
NTSTATUS status;
struct tevent_req *req;
- int ret;
+ enum http_body_type ret;
int sys_errno;
if (!subreq) {
diff --git a/libcli/http/http_internal.h b/libcli/http/http_internal.h
index ec17f7e..786ace6 100644
--- a/libcli/http/http_internal.h
+++ b/libcli/http/http_internal.h
@@ -28,6 +28,10 @@ enum http_parser_state {
HTTP_READING_BODY,
HTTP_READING_TRAILER,
HTTP_READING_DONE,
+ HTTP_READING_CHUNK_SIZE,
+ HTTP_READING_CHUNK,
+ HTTP_READING_CHUNK_TERM,
+ HTTP_READING_FINAL_CHUNK_TERM,
};
enum http_read_status {
diff --git a/libcli/nbt/libnbt.h b/libcli/nbt/libnbt.h
index 204484b..6a30c9f 100644
--- a/libcli/nbt/libnbt.h
+++ b/libcli/nbt/libnbt.h
@@ -331,6 +331,9 @@ NTSTATUS nbt_set_unexpected_handler(struct nbt_name_socket *nbtsock,
void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
struct socket_address *),
void *private_data);
+NTSTATUS nbt_name_send_raw(struct nbt_name_socket *nbtsock,
+ struct socket_address *dest,
+ const DATA_BLOB pkt_blob);
NTSTATUS nbt_name_reply_send(struct nbt_name_socket *nbtsock,
struct socket_address *dest,
struct nbt_name_packet *request);
diff --git a/libcli/nbt/nbtsocket.c b/libcli/nbt/nbtsocket.c
index 47e73cf..b2945ad 100644
--- a/libcli/nbt/nbtsocket.c
+++ b/libcli/nbt/nbtsocket.c
@@ -448,6 +448,50 @@ failed:
return NULL;
}
+/*
+ send off a nbt name packet
+*/
+_PUBLIC_ NTSTATUS nbt_name_send_raw(struct nbt_name_socket *nbtsock,
+ struct socket_address *dest,
+ const DATA_BLOB pkt_blob)
+{
+ struct nbt_name_request *req;
+
+ req = talloc_zero(nbtsock, struct nbt_name_request);
+ NT_STATUS_HAVE_NO_MEMORY(req);
+
+ req->nbtsock = nbtsock;
+ req->dest = socket_address_copy(req, dest);
+ if (req->dest == NULL) {
+ goto failed;
+ }
+ req->state = NBT_REQUEST_SEND;
+ /*
+ * We don't expect a response so
+ * just pretent it is a request,
+ * but we really don't care about the
+ * content.
+ */
+ req->is_reply = true;
+
+ req->encoded = data_blob_dup_talloc(req, pkt_blob);
+ if (req->encoded.length != pkt_blob.length) {
+ goto failed;
+ }
+
+ talloc_set_destructor(req, nbt_name_request_destructor);
+
+ DLIST_ADD_END(nbtsock->send_queue, req);
+
+ TEVENT_FD_WRITEABLE(nbtsock->fde);
+
+ return NT_STATUS_OK;
+
+failed:
+ talloc_free(req);
+ return NT_STATUS_NO_MEMORY;
+}
+
/*
send off a nbt name reply
diff --git a/libcli/security/dom_sid.c b/libcli/security/dom_sid.c
index eaece2a..21012b7 100644
--- a/libcli/security/dom_sid.c
+++ b/libcli/security/dom_sid.c
@@ -28,6 +28,7 @@
#include "librpc/gen_ndr/security.h"
#include "dom_sid.h"
#include "lib/util/smb_strtox.h"
+#include "lib/util/tsort.h"
/*****************************************************************
Compare the auth portion of two sids.
@@ -46,11 +47,12 @@ int dom_sid_compare_auth(const struct dom_sid *sid1,
return 1;
if (sid1->sid_rev_num != sid2->sid_rev_num)
- return sid1->sid_rev_num - sid2->sid_rev_num;
+ return NUMERIC_CMP(sid1->sid_rev_num, sid2->sid_rev_num);
for (i = 0; i < 6; i++)
- if (sid1->id_auth[i] != sid2->id_auth[i])
- return sid1->id_auth[i] - sid2->id_auth[i];
+ if (sid1->id_auth[i] != sid2->id_auth[i]) {
+ return NUMERIC_CMP(sid1->id_auth[i], sid2->id_auth[i]);
+ }
return 0;
}
@@ -71,9 +73,9 @@ int dom_sid_compare(const struct dom_sid *sid1, const struct dom_sid *sid2)
return 1;
/* Compare most likely different rids, first: i.e start at end */
- if (sid1->num_auths != sid2->num_auths)
- return sid1->num_auths - sid2->num_auths;
-
+ if (sid1->num_auths != sid2->num_auths) {
+ return NUMERIC_CMP(sid1->num_auths, sid2->num_auths);
+ }
for (i = sid1->num_auths-1; i >= 0; --i) {
if (sid1->sub_auths[i] < sid2->sub_auths[i]) {
return -1;
diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index a52a615..87acddf 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -166,6 +166,13 @@ struct smb2cli_session {
uint16_t channel_sequence;
bool replay_active;
bool require_signed_response;
+
+ /*
+ * The following are just for torture tests
+ */
+ bool anonymous_signing;
+ bool anonymous_encryption;
+ bool no_signing_disconnect;
};
struct smbXcli_session {
@@ -3999,6 +4006,9 @@ static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED) ||
NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) ||
+ (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ session != NULL &&
+ session->smb2->no_signing_disconnect) ||
NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
/*
* if the server returns
@@ -4042,8 +4052,29 @@ static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
/*
* If the signing check fails, we disconnect
* the connection.
+ *
+ * Unless
+ * smb2cli_session_torture_no_signing_disconnect
+ * was called in torture tests
*/
- return signing_status;
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ return signing_status;
+ }
+
+ if (!NT_STATUS_EQUAL(status, signing_status)) {
+ return signing_status;
+ }
+
+ if (session == NULL) {
+ return signing_status;
+ }
+
+ if (!session->smb2->no_signing_disconnect) {
+ return signing_status;
+ }
+
+ state->smb2.signing_skipped = true;
}
}
@@ -6332,6 +6363,23 @@ void smb2cli_session_require_signed_response(struct smbXcli_session *session,
session->smb2->require_signed_response = require_signed_response;
}
+void smb2cli_session_torture_anonymous_signing(struct smbXcli_session *session,
+ bool anonymous_signing)
+{
+ session->smb2->anonymous_signing = anonymous_signing;
+}
+
+void smb2cli_session_torture_anonymous_encryption(struct smbXcli_session *session,
+ bool anonymous_encryption)
+{
+ session->smb2->anonymous_encryption = anonymous_encryption;
+}
+
+void smb2cli_session_torture_no_signing_disconnect(struct smbXcli_session *session)
+{
+ session->smb2->no_signing_disconnect = true;
+}
+
NTSTATUS smb2cli_session_update_preauth(struct smbXcli_session *session,
const struct iovec *iov)
{
@@ -6432,6 +6480,10 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
conn->protocol,
preauth_hash);
+ if (session->smb2->anonymous_encryption) {
+ goto skip_signing_key;
+ }
+
status = smb2_signing_key_sign_create(session->smb2,
conn->smb2.server.sign_algo,
&_session_key,
@@ -6441,6 +6493,15 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
return status;
}
+ if (session->smb2->anonymous_signing) {
+ /*
+ * skip encryption and application keys
+ */
+ goto skip_application_key;
+ }
+
+skip_signing_key:
+
status = smb2_signing_key_cipher_create(session->smb2,
conn->smb2.server.cipher,
&_session_key,
@@ -6459,6 +6520,10 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
return status;
}
+ if (session->smb2->anonymous_encryption) {
+ goto skip_application_key;
+ }
+
status = smb2_signing_key_sign_create(session->smb2,
conn->smb2.server.sign_algo,
&_session_key,
@@ -6468,6 +6533,8 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
return status;
}
+skip_application_key:
+
status = smb2_signing_key_copy(session,
session->smb2->signing_key,
&session->smb2_channel.signing_key);
@@ -6477,6 +6544,18 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
check_signature = conn->mandatory_signing;
+ if (conn->protocol >= PROTOCOL_SMB3_11) {
+ check_signature = true;
+ }
+
+ if (session->smb2->anonymous_signing) {
+ check_signature = false;
+ }
+
+ if (session->smb2->anonymous_encryption) {
+ check_signature = false;
+ }
+
hdr_flags = IVAL(recv_iov[0].iov_base, SMB2_HDR_FLAGS);
if (hdr_flags & SMB2_HDR_FLAG_SIGNED) {
/*
@@ -6492,10 +6571,6 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
check_signature = true;
}
- if (conn->protocol >= PROTOCOL_SMB3_11) {
- check_signature = true;
- }
-
if (check_signature) {
status = smb2_signing_check_pdu(session->smb2_channel.signing_key,
recv_iov, 3);
@@ -6527,6 +6602,15 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
session->smb2->should_encrypt = false;
}
+ if (session->smb2->anonymous_signing) {
+ session->smb2->should_sign = true;
+ }
+
+ if (session->smb2->anonymous_encryption) {
+ session->smb2->should_encrypt = true;
+ session->smb2->should_sign = false;
+ }
+
/*
* CCM and GCM algorithms must never have their
* nonce wrap, or the security of the whole
@@ -6698,6 +6782,16 @@ NTSTATUS smb2cli_session_set_channel_key(struct smbXcli_session *session,
NTSTATUS smb2cli_session_encryption_on(struct smbXcli_session *session)
{
+ if (session->smb2->anonymous_signing) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (session->smb2->anonymous_encryption) {
+ SMB_ASSERT(session->smb2->should_encrypt);
+ SMB_ASSERT(!session->smb2->should_sign);
+ return NT_STATUS_OK;
+ }
+
if (!session->smb2->should_sign) {
/*
* We need required signing on the session
diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h
index 25ccd84..69fa131 100644
--- a/libcli/smb/smbXcli_base.h
+++ b/libcli/smb/smbXcli_base.h
@@ -535,6 +535,11 @@ void smb2cli_session_start_replay(struct smbXcli_session *session);
void smb2cli_session_stop_replay(struct smbXcli_session *session);
void smb2cli_session_require_signed_response(struct smbXcli_session *session,
bool require_signed_response);
+void smb2cli_session_torture_anonymous_signing(struct smbXcli_session *session,
+ bool anonymous_signing);
+void smb2cli_session_torture_anonymous_encryption(struct smbXcli_session *session,
+ bool anonymous_encryption);
+void smb2cli_session_torture_no_signing_disconnect(struct smbXcli_session *session);
NTSTATUS smb2cli_session_update_preauth(struct smbXcli_session *session,
const struct iovec *iov);
NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,