static int samldb_sam_account_upn_clash(struct samldb_ctx *ac)
{
	struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
	int ret;
	struct ldb_dn *base_dn = ldb_get_default_basedn(ldb);
	TALLOC_CTX *tmp_ctx = NULL;
	const char *real_sam = NULL;
	const char *real_upn = NULL;
	char *implied_sam = NULL;
	char *implied_upn = NULL;
	const char *realm = NULL;

	ret = samldb_get_single_valued_attr(ldb, ac,
					    "sAMAccountName",
					    &real_sam);
	if (ret != LDB_SUCCESS) {
		return ret;
	}
	ret = samldb_get_single_valued_attr(ldb, ac,
					    "userPrincipalName",
					    &real_upn);
	if (ret != LDB_SUCCESS) {
		return ret;
	}
	if (real_upn == NULL && real_sam == NULL) {
		/* Not changing these things, so we're done */
		return LDB_SUCCESS;
	}

	tmp_ctx = talloc_new(ac);
	realm = samdb_dn_to_dns_domain(tmp_ctx, base_dn);
	if (realm == NULL) {
		talloc_free(tmp_ctx);
		return ldb_operr(ldb);
	}

	if (real_upn != NULL) {
		/*
		 * note we take the last @ in the upn because the first (i.e.
		 * sAMAccountName equivalent) part can contain @.
		 *
		 * It is also OK (per Windows) for a UPN to have zero @s.
		 */
		char *at = NULL;
		char *upn_realm = NULL;
		implied_sam = talloc_strdup(tmp_ctx, real_upn);
		if (implied_sam == NULL) {
			talloc_free(tmp_ctx);
			return ldb_module_oom(ac->module);
		}

		at = strrchr(implied_sam, '@');
		if (at == NULL) {
			/*
			 * there is no @ in this UPN, so we treat the whole
			 * thing as a sAMAccountName for the purposes of a
			 * clash.
			 */
			DBG_INFO("samldb: userPrincipalName '%s' contains "
				 "no '@' character\n", implied_sam);
		} else {
			/*
			 * Now, this upn only implies a sAMAccountName if the
			 * realm is our realm. So we need to compare the tail
			 * of the upn to the realm.
			 */
			*at = '\0';
			upn_realm = at + 1;
			if (strcasecmp(upn_realm, realm) != 0) {
				/* implied_sam is not the implied
				 * sAMAccountName after all, because it is
				 * from a different realm. */
				TALLOC_FREE(implied_sam);
			}
		}
	}

	if (real_sam != NULL) {
		implied_upn = talloc_asprintf(tmp_ctx, "%s@%s",
					      real_sam, realm);
		if (implied_upn == NULL) {
			talloc_free(tmp_ctx);
			return ldb_module_oom(ac->module);
		}
	}

	/*
	 * Now we have all of the actual and implied names, in which to search
	 * for conflicts.
	 */
	if (real_sam != NULL) {
		ret = samldb_sam_account_upn_clash_sub_search(
			ac, tmp_ctx, base_dn, "sAMAccountName",
			real_sam, "");

		if (ret != LDB_SUCCESS) {
			talloc_free(tmp_ctx);
			return ret;
		}
		ret = samaccountname_bad_chars_check(ac, real_sam);
		if (ret != LDB_SUCCESS) {
			talloc_free(tmp_ctx);
			return ret;
		}
	}
	if (implied_upn != NULL) {
		ret = samldb_sam_account_upn_clash_sub_search(
			ac, tmp_ctx, base_dn, "userPrincipalName", implied_upn,
			"(implied by sAMAccountName)");

		if (ret != LDB_SUCCESS) {
			talloc_free(tmp_ctx);
			return ret;
		}
	}
	if (real_upn != NULL) {
		ret = samldb_sam_account_upn_clash_sub_search(
			ac, tmp_ctx, base_dn, "userPrincipalName",
			real_upn, "");

		if (ret != LDB_SUCCESS) {
			talloc_free(tmp_ctx);
			return ret;
		}
	}
	if (implied_sam != NULL) {
		ret = samldb_sam_account_upn_clash_sub_search(
			ac, tmp_ctx, base_dn, "sAMAccountName", implied_sam,
			"(implied by userPrincipalName)");
		if (ret != LDB_SUCCESS) {
			talloc_free(tmp_ctx);
			return ret;
		}
	}

	talloc_free(tmp_ctx);
	return LDB_SUCCESS;
}
static int samldb_sam_account_upn_clash(struct samldb_ctx *ac)
{
	struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
	int ret;
	struct ldb_dn *base_dn = ldb_get_default_basedn(ldb);
	TALLOC_CTX *tmp_ctx = NULL;
	const char *real_sam = NULL;
	const char *real_upn = NULL;
	char *implied_sam = NULL;
	char *implied_upn = NULL;
	const char *realm = NULL;

	ret = samldb_get_single_valued_attr(ldb, ac,
					    "sAMAccountName",
					    &real_sam);
	if (ret != LDB_SUCCESS) {
		return ret;
	}
	ret = samldb_get_single_valued_attr(ldb, ac,
					    "userPrincipalName",
					    &real_upn);
	if (ret != LDB_SUCCESS) {
		return ret;
	}
	if (real_upn == NULL && real_sam == NULL) {
		 
		return LDB_SUCCESS;
	}

	tmp_ctx = talloc_new(ac);
	realm = samdb_dn_to_dns_domain(tmp_ctx, base_dn);
	if (realm == NULL) {
		talloc_free(tmp_ctx);
		return ldb_operr(ldb);
	}

	if (real_upn != NULL) {
		 
		char *at = NULL;
		char *upn_realm = NULL;
		implied_sam = talloc_strdup(tmp_ctx, real_upn);
		if (implied_sam == NULL) {
			talloc_free(tmp_ctx);
			return ldb_module_oom(ac->module);
		}

		at = strrchr(implied_sam, '@');
		if (at == NULL) {
			 
			DBG_INFO("samldb: userPrincipalName '%s' contains "
				 "no '@' character\n", implied_sam);
		} else {
			 
			*at = '\0';
			upn_realm = at + 1;
			if (strcasecmp(upn_realm, realm) != 0) {
				 
				TALLOC_FREE(implied_sam);
			}
		}
	}

	if (real_sam != NULL) {
		implied_upn = talloc_asprintf(tmp_ctx, "%s@%s",
					      real_sam, realm);
		if (implied_upn == NULL) {
			talloc_free(tmp_ctx);
			return ldb_module_oom(ac->module);
		}
	}

	 
	if (real_sam != NULL) {
		ret = samldb_sam_account_upn_clash_sub_search(
			ac, tmp_ctx, base_dn, "sAMAccountName",
			real_sam, "");

		if (ret != LDB_SUCCESS) {
			talloc_free(tmp_ctx);
			return ret;
		}
		ret = samaccountname_bad_chars_check(ac, real_sam);
		if (ret != LDB_SUCCESS) {
			talloc_free(tmp_ctx);
			return ret;
		}
	}
	if (implied_upn != NULL) {
		ret = samldb_sam_account_upn_clash_sub_search(
			ac, tmp_ctx, base_dn, "userPrincipalName", implied_upn,
			"(implied by sAMAccountName)");

		if (ret != LDB_SUCCESS) {
			talloc_free(tmp_ctx);
			return ret;
		}
	}
	if (real_upn != NULL) {
		ret = samldb_sam_account_upn_clash_sub_search(
			ac, tmp_ctx, base_dn, "userPrincipalName",
			real_upn, "");

		if (ret != LDB_SUCCESS) {
			talloc_free(tmp_ctx);
			return ret;
		}
	}
	if (implied_sam != NULL) {
		ret = samldb_sam_account_upn_clash_sub_search(
			ac, tmp_ctx, base_dn, "sAMAccountName", implied_sam,
			"(implied by userPrincipalName)");
		if (ret != LDB_SUCCESS) {
			talloc_free(tmp_ctx);
			return ret;
		}
	}

	talloc_free(tmp_ctx);
	return LDB_SUCCESS;
}