int ldb_msg_difference(struct ldb_context *ldb,
		       TALLOC_CTX *mem_ctx,
		       struct ldb_message *msg1,
		       struct ldb_message *msg2,
		       struct ldb_message **_msg_out)
{
	int ldb_res;
	unsigned int i;
	struct ldb_message *mod;
	struct ldb_message_element *el;
	TALLOC_CTX *temp_ctx;

	temp_ctx = talloc_new(mem_ctx);
	if (!temp_ctx) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	mod = ldb_msg_new(temp_ctx);
	if (mod == NULL) {
		goto failed;
	}

	mod->dn = msg1->dn;
	mod->num_elements = 0;
	mod->elements = NULL;

	/*
	 * Canonicalize *msg2 so we have no repeated elements
	 * Resulting message is allocated in *mod's mem context,
	 * as we are going to move some elements from *msg2 to
	 * *mod object later
	 */
	ldb_res = ldb_msg_normalize(ldb, mod, msg2, &msg2);
	if (ldb_res != LDB_SUCCESS) {
		goto failed;
	}

	/* look in msg2 to find elements that need to be added or modified */
	for (i=0;i<msg2->num_elements;i++) {
		el = ldb_msg_find_element(msg1, msg2->elements[i].name);

		if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
			continue;
		}

		ldb_res = ldb_msg_add(mod,
		                      &msg2->elements[i],
		                      el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
		if (ldb_res != LDB_SUCCESS) {
			goto failed;
		}
	}

	/* look in msg1 to find elements that need to be deleted */
	for (i=0;i<msg1->num_elements;i++) {
		el = ldb_msg_find_element(msg2, msg1->elements[i].name);
		if (el == NULL) {
			ldb_res = ldb_msg_add_empty(mod,
			                            msg1->elements[i].name,
			                            LDB_FLAG_MOD_DELETE, NULL);
			if (ldb_res != LDB_SUCCESS) {
				goto failed;
			}
		}
	}

	/* steal resulting message into supplied context */
	talloc_steal(mem_ctx, mod);
	*_msg_out = mod;

	talloc_free(temp_ctx);
	return LDB_SUCCESS;

failed:
	talloc_free(temp_ctx);
	return LDB_ERR_OPERATIONS_ERROR;
}
int ldb_msg_difference(struct ldb_context *ldb,
		       TALLOC_CTX *mem_ctx,
		       struct ldb_message *msg1,
		       struct ldb_message *msg2,
		       struct ldb_message **_msg_out)
{
	int ldb_res;
	unsigned int i;
	struct ldb_message *mod;
	struct ldb_message_element *el;
	TALLOC_CTX *temp_ctx;

	temp_ctx = talloc_new(mem_ctx);
	if (!temp_ctx) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	mod = ldb_msg_new(temp_ctx);
	if (mod == NULL) {
		goto failed;
	}

	mod->dn = msg1->dn;
	mod->num_elements = 0;
	mod->elements = NULL;

	 
	ldb_res = ldb_msg_normalize(ldb, mod, msg2, &msg2);
	if (ldb_res != LDB_SUCCESS) {
		goto failed;
	}

	 
	for (i=0;i<msg2->num_elements;i++) {
		el = ldb_msg_find_element(msg1, msg2->elements[i].name);

		if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
			continue;
		}

		ldb_res = ldb_msg_add(mod,
		                      &msg2->elements[i],
		                      el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
		if (ldb_res != LDB_SUCCESS) {
			goto failed;
		}
	}

	 
	for (i=0;i<msg1->num_elements;i++) {
		el = ldb_msg_find_element(msg2, msg1->elements[i].name);
		if (el == NULL) {
			ldb_res = ldb_msg_add_empty(mod,
			                            msg1->elements[i].name,
			                            LDB_FLAG_MOD_DELETE, NULL);
			if (ldb_res != LDB_SUCCESS) {
				goto failed;
			}
		}
	}

	 
	talloc_steal(mem_ctx, mod);
	*_msg_out = mod;

	talloc_free(temp_ctx);
	return LDB_SUCCESS;

failed:
	talloc_free(temp_ctx);
	return LDB_ERR_OPERATIONS_ERROR;
}