WERROR dns_common_name2dn(struct ldb_context *samdb,
			  struct dns_server_zone *zones,
			  TALLOC_CTX *mem_ctx,
			  const char *name,
			  struct ldb_dn **_dn)
{
	struct ldb_dn *base;
	struct ldb_dn *dn;
	const struct dns_server_zone *z;
	size_t host_part_len = 0;
	struct ldb_val host_part;
	WERROR werr;
	bool ok;
	const char *casefold = NULL;

	if (name == NULL) {
		return DNS_ERR(FORMAT_ERROR);
	}

	if (strcmp(name, "") == 0) {
		base = ldb_get_default_basedn(samdb);
		dn = ldb_dn_copy(mem_ctx, base);
		ok = ldb_dn_add_child_fmt(dn,
					  "DC=@,DC=RootDNSServers,CN=MicrosoftDNS,CN=System");
		if (ok == false) {
			TALLOC_FREE(dn);
			return WERR_NOT_ENOUGH_MEMORY;
		}

		*_dn = dn;
		return WERR_OK;
	}

	/* Check non-empty names */
	werr = dns_name_check(mem_ctx, strlen(name), name);
	if (!W_ERROR_IS_OK(werr)) {
		return werr;
	}

	for (z = zones; z != NULL; z = z->next) {
		bool match;

		match = dns_name_match(z->name, name, &host_part_len);
		if (match) {
			break;
		}
	}

	if (z == NULL) {
		return DNS_ERR(NAME_ERROR);
	}

	if (host_part_len == 0) {
		dn = ldb_dn_copy(mem_ctx, z->dn);
		ok = ldb_dn_add_child_fmt(dn, "DC=@");
		if (! ok) {
			TALLOC_FREE(dn);
			return WERR_NOT_ENOUGH_MEMORY;
		}
		*_dn = dn;
		return WERR_OK;
	}

	dn = ldb_dn_copy(mem_ctx, z->dn);
	if (dn == NULL) {
		TALLOC_FREE(dn);
		return WERR_NOT_ENOUGH_MEMORY;
	}

	host_part = data_blob_const(name, host_part_len);

	ok = ldb_dn_add_child_val(dn, "DC", host_part);

	if (ok == false) {
		TALLOC_FREE(dn);
		return WERR_NOT_ENOUGH_MEMORY;
	}

	/*
	 * Check the new DN here for validity, so as to catch errors
	 * early
	 */
	ok = ldb_dn_validate(dn);
	if (ok == false) {
		TALLOC_FREE(dn);
		return DNS_ERR(NAME_ERROR);
	}

	/*
	 * The value from this check is saved in the DN, and doing
	 * this here allows an easy return here.
	 */
	casefold = ldb_dn_get_casefold(dn);
	if (casefold == NULL) {
		TALLOC_FREE(dn);
		return DNS_ERR(NAME_ERROR);
	}

	*_dn = dn;
	return WERR_OK;
}
WERROR dns_common_name2dn(struct ldb_context *samdb,
			  struct dns_server_zone *zones,
			  TALLOC_CTX *mem_ctx,
			  const char *name,
			  struct ldb_dn **_dn)
{
	struct ldb_dn *base;
	struct ldb_dn *dn;
	const struct dns_server_zone *z;
	size_t host_part_len = 0;
	struct ldb_val host_part;
	WERROR werr;
	bool ok;
	const char *casefold = NULL;

	if (name == NULL) {
		return DNS_ERR(FORMAT_ERROR);
	}

	if (strcmp(name, "") == 0) {
		base = ldb_get_default_basedn(samdb);
		dn = ldb_dn_copy(mem_ctx, base);
		ok = ldb_dn_add_child_fmt(dn,
					  "DC=@,DC=RootDNSServers,CN=MicrosoftDNS,CN=System");
		if (ok == false) {
			TALLOC_FREE(dn);
			return WERR_NOT_ENOUGH_MEMORY;
		}

		*_dn = dn;
		return WERR_OK;
	}

	 
	werr = dns_name_check(mem_ctx, strlen(name), name);
	if (!W_ERROR_IS_OK(werr)) {
		return werr;
	}

	for (z = zones; z != NULL; z = z->next) {
		bool match;

		match = dns_name_match(z->name, name, &host_part_len);
		if (match) {
			break;
		}
	}

	if (z == NULL) {
		return DNS_ERR(NAME_ERROR);
	}

	if (host_part_len == 0) {
		dn = ldb_dn_copy(mem_ctx, z->dn);
		ok = ldb_dn_add_child_fmt(dn, "DC=@");
		if (! ok) {
			TALLOC_FREE(dn);
			return WERR_NOT_ENOUGH_MEMORY;
		}
		*_dn = dn;
		return WERR_OK;
	}

	dn = ldb_dn_copy(mem_ctx, z->dn);
	if (dn == NULL) {
		TALLOC_FREE(dn);
		return WERR_NOT_ENOUGH_MEMORY;
	}

	host_part = data_blob_const(name, host_part_len);

	ok = ldb_dn_add_child_val(dn, "DC", host_part);

	if (ok == false) {
		TALLOC_FREE(dn);
		return WERR_NOT_ENOUGH_MEMORY;
	}

	 
	ok = ldb_dn_validate(dn);
	if (ok == false) {
		TALLOC_FREE(dn);
		return DNS_ERR(NAME_ERROR);
	}

	 
	casefold = ldb_dn_get_casefold(dn);
	if (casefold == NULL) {
		TALLOC_FREE(dn);
		return DNS_ERR(NAME_ERROR);
	}

	*_dn = dn;
	return WERR_OK;
}