Commit message: CVE-2015-3223: lib: ldb: Use memmem binary search, not strstr text search.

Values might have embedded zeros.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11325

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
CVE: CVE-2015-3223
CWE: CWE-189
Vulnerability description: The ldb_wildcard_compare function in ldb_match.c in ldb before 1.1.24, as used in the AD LDAP server in Samba 4.x before 4.1.22, 4.2.x before 4.2.7, and 4.3.x before 4.3.3, mishandles certain zero values, which allows remote attackers to cause a denial of service (infinite loop) via crafted packets.

Project: samba
File: ldb_match.c

static int ldb_match_message(struct ldb_context *ldb, 
			     const struct ldb_message *msg,
			     const struct ldb_parse_tree *tree,
			     enum ldb_scope scope, bool *matched)
{
	unsigned int i;
	int ret;

	*matched = false;

	if (scope != LDB_SCOPE_BASE && ldb_dn_is_special(msg->dn)) {
		/* don't match special records except on base searches */
		return LDB_SUCCESS;
	}

	switch (tree->operation) {
	case LDB_OP_AND:
		for (i=0;i<tree->u.list.num_elements;i++) {
			ret = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope, matched);
			if (ret != LDB_SUCCESS) return ret;
			if (!*matched) return LDB_SUCCESS;
		}
		*matched = true;
		return LDB_SUCCESS;

	case LDB_OP_OR:
		for (i=0;i<tree->u.list.num_elements;i++) {
			ret = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope, matched);
			if (ret != LDB_SUCCESS) return ret;
			if (*matched) return LDB_SUCCESS;
		}
		*matched = false;
		return LDB_SUCCESS;

	case LDB_OP_NOT:
		ret = ldb_match_message(ldb, msg, tree->u.isnot.child, scope, matched);
		if (ret != LDB_SUCCESS) return ret;
		*matched = ! *matched;
		return LDB_SUCCESS;

	case LDB_OP_EQUALITY:
		return ldb_match_equality(ldb, msg, tree, scope, matched);

	case LDB_OP_SUBSTRING:
		return ldb_match_substring(ldb, msg, tree, scope, matched);

	case LDB_OP_GREATER:
		return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_GREATER, matched);

	case LDB_OP_LESS:
		return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_LESS, matched);

	case LDB_OP_PRESENT:
		return ldb_match_present(ldb, msg, tree, scope, matched);

	case LDB_OP_APPROX:
		return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_APPROX, matched);

	case LDB_OP_EXTENDED:
		return ldb_match_extended(ldb, msg, tree, scope, matched);
	}

	return LDB_ERR_INAPPROPRIATE_MATCHING;
}

Project: samba
File: ldb_match.c

int ldb_register_extended_match_rule(struct ldb_context *ldb,
				     const struct ldb_extended_match_rule *rule)
{
	const struct ldb_extended_match_rule *lookup_rule;
	struct ldb_extended_match_entry *entry;

	lookup_rule = ldb_find_extended_match_rule(ldb, rule->oid);
	if (lookup_rule) {
		return LDB_ERR_ENTRY_ALREADY_EXISTS;
	}

	entry = talloc_zero(ldb, struct ldb_extended_match_entry);
	if (!entry) {
		return LDB_ERR_OPERATIONS_ERROR;
	}
	entry->rule = rule;
	DLIST_ADD_END(ldb->extended_match_rules, entry, struct ldb_extended_match_entry);

	return LDB_SUCCESS;
}

Project: samba
File: ldb_match.c

static int ldb_match_extended(struct ldb_context *ldb, 
			      const struct ldb_message *msg,
			      const struct ldb_parse_tree *tree,
			      enum ldb_scope scope, bool *matched)
{
	const struct ldb_extended_match_rule *rule;

	if (tree->u.extended.dnAttributes) {
		/* FIXME: We really need to find out what this ":dn" part in
		 * an extended match means and how to handle it. For now print
		 * only a warning to have s3 winbind and other tools working
		 * against us. - Matthias */
		ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb: dnAttributes extended match not supported yet");
	}
	if (tree->u.extended.rule_id == NULL) {
		ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet");
		return LDB_ERR_INAPPROPRIATE_MATCHING;
	}
	if (tree->u.extended.attr == NULL) {
		ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-attribute extended matches not supported yet");
		return LDB_ERR_INAPPROPRIATE_MATCHING;
	}

	rule = ldb_find_extended_match_rule(ldb, tree->u.extended.rule_id);
	if (rule == NULL) {
		ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s",
			  tree->u.extended.rule_id);
		return LDB_ERR_INAPPROPRIATE_MATCHING;
	}

	return rule->callback(ldb, rule->oid, msg,
			      tree->u.extended.attr,
			      &tree->u.extended.value, matched);
}