diff options
Diffstat (limited to '')
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, |