static NTSTATUS dcesrv_lsa_SetSecret(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
			      struct lsa_SetSecret *r)
{

	struct dcesrv_handle *h;
	struct lsa_secret_state *secret_state;
	struct ldb_message *msg;
	DATA_BLOB session_key;
	DATA_BLOB crypt_secret, secret;
	struct ldb_val val;
	int ret;
	NTSTATUS status = NT_STATUS_OK;

	struct timeval now = timeval_current();
	NTTIME nt_now = timeval_to_nttime(&now);

	DCESRV_PULL_HANDLE(h, r->in.sec_handle, LSA_HANDLE_SECRET);

	secret_state = h->data;

	msg = ldb_msg_new(mem_ctx);
	if (msg == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	msg->dn = talloc_reference(mem_ctx, secret_state->secret_dn);
	if (!msg->dn) {
		return NT_STATUS_NO_MEMORY;
	}
	status = dcesrv_transport_session_key(dce_call, &session_key);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	if (r->in.old_val) {
		/* Decrypt */
		crypt_secret.data = r->in.old_val->data;
		crypt_secret.length = r->in.old_val->size;

		status = sess_decrypt_blob(mem_ctx, &crypt_secret, &session_key, &secret);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}

		val.data = secret.data;
		val.length = secret.length;

		/* set value */
		if (ldb_msg_add_value(msg, "priorValue", &val, NULL) != LDB_SUCCESS) {
			return NT_STATUS_NO_MEMORY;
		}

		/* set old value mtime */
		if (samdb_msg_add_uint64(secret_state->sam_ldb,
					 mem_ctx, msg, "priorSetTime", nt_now) != LDB_SUCCESS) {
			return NT_STATUS_NO_MEMORY;
		}

	} else {
		/* If the old value is not set, then migrate the
		 * current value to the old value */
		const struct ldb_val *old_val;
		NTTIME last_set_time;
		struct ldb_message **res;
		const char *attrs[] = {
			"currentValue",
			"lastSetTime",
			NULL
		};

		/* search for the secret record */
		ret = gendb_search_dn(secret_state->sam_ldb,mem_ctx,
				      secret_state->secret_dn, &res, attrs);
		if (ret == 0) {
			return NT_STATUS_OBJECT_NAME_NOT_FOUND;
		}

		if (ret != 1) {
			DEBUG(0,("Found %d records matching dn=%s\n", ret,
				 ldb_dn_get_linearized(secret_state->secret_dn)));
			return NT_STATUS_INTERNAL_DB_CORRUPTION;
		}

		old_val = ldb_msg_find_ldb_val(res[0], "currentValue");
		last_set_time = ldb_msg_find_attr_as_uint64(res[0], "lastSetTime", 0);

		if (old_val) {
			/* set old value */
			if (ldb_msg_add_value(msg, "priorValue",
					      old_val, NULL) != LDB_SUCCESS) {
				return NT_STATUS_NO_MEMORY;
			}
		} else {
			if (samdb_msg_add_delete(secret_state->sam_ldb,
						 mem_ctx, msg, "priorValue") != LDB_SUCCESS) {
				return NT_STATUS_NO_MEMORY;
			}
		}

		/* set old value mtime */
		if (ldb_msg_find_ldb_val(res[0], "lastSetTime")) {
			if (samdb_msg_add_uint64(secret_state->sam_ldb,
						 mem_ctx, msg, "priorSetTime", last_set_time) != LDB_SUCCESS) {
				return NT_STATUS_NO_MEMORY;
			}
		} else {
			if (samdb_msg_add_uint64(secret_state->sam_ldb,
						 mem_ctx, msg, "priorSetTime", nt_now) != LDB_SUCCESS) {
				return NT_STATUS_NO_MEMORY;
			}
		}
	}

	if (r->in.new_val) {
		/* Decrypt */
		crypt_secret.data = r->in.new_val->data;
		crypt_secret.length = r->in.new_val->size;

		status = sess_decrypt_blob(mem_ctx, &crypt_secret, &session_key, &secret);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}

		val.data = secret.data;
		val.length = secret.length;

		/* set value */
		if (ldb_msg_add_value(msg, "currentValue", &val, NULL) != LDB_SUCCESS) {
			return NT_STATUS_NO_MEMORY;
		}

		/* set new value mtime */
		if (samdb_msg_add_uint64(secret_state->sam_ldb,
					 mem_ctx, msg, "lastSetTime", nt_now) != LDB_SUCCESS) {
			return NT_STATUS_NO_MEMORY;
		}
	} else {
		/* NULL out the NEW value */
		if (samdb_msg_add_uint64(secret_state->sam_ldb,
					 mem_ctx, msg, "lastSetTime", nt_now) != LDB_SUCCESS) {
			return NT_STATUS_NO_MEMORY;
		}
		if (samdb_msg_add_delete(secret_state->sam_ldb,
					 mem_ctx, msg, "currentValue") != LDB_SUCCESS) {
			return NT_STATUS_NO_MEMORY;
		}
	}

	/* modify the samdb record */
	ret = dsdb_replace(secret_state->sam_ldb, msg, 0);
	if (ret != LDB_SUCCESS) {
		return dsdb_ldb_err_to_ntstatus(ret);
	}

	return NT_STATUS_OK;
}
static NTSTATUS dcesrv_lsa_SetSecret(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
			      struct lsa_SetSecret *r)
{

	struct dcesrv_handle *h;
	struct lsa_secret_state *secret_state;
	struct ldb_message *msg;
	DATA_BLOB session_key;
	DATA_BLOB crypt_secret, secret;
	struct ldb_val val;
	int ret;
	NTSTATUS status = NT_STATUS_OK;

	struct timeval now = timeval_current();
	NTTIME nt_now = timeval_to_nttime(&now);

	DCESRV_PULL_HANDLE(h, r->in.sec_handle, LSA_HANDLE_SECRET);

	secret_state = h->data;

	msg = ldb_msg_new(mem_ctx);
	if (msg == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	msg->dn = talloc_reference(mem_ctx, secret_state->secret_dn);
	if (!msg->dn) {
		return NT_STATUS_NO_MEMORY;
	}
	status = dcesrv_transport_session_key(dce_call, &session_key);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	if (r->in.old_val) {
		 
		crypt_secret.data = r->in.old_val->data;
		crypt_secret.length = r->in.old_val->size;

		status = sess_decrypt_blob(mem_ctx, &crypt_secret, &session_key, &secret);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}

		val.data = secret.data;
		val.length = secret.length;

		 
		if (ldb_msg_add_value(msg, "priorValue", &val, NULL) != LDB_SUCCESS) {
			return NT_STATUS_NO_MEMORY;
		}

		 
		if (samdb_msg_add_uint64(secret_state->sam_ldb,
					 mem_ctx, msg, "priorSetTime", nt_now) != LDB_SUCCESS) {
			return NT_STATUS_NO_MEMORY;
		}

	} else {
		 
		const struct ldb_val *old_val;
		NTTIME last_set_time;
		struct ldb_message **res;
		const char *attrs[] = {
			"currentValue",
			"lastSetTime",
			NULL
		};

		 
		ret = gendb_search_dn(secret_state->sam_ldb,mem_ctx,
				      secret_state->secret_dn, &res, attrs);
		if (ret == 0) {
			return NT_STATUS_OBJECT_NAME_NOT_FOUND;
		}

		if (ret != 1) {
			DEBUG(0,("Found %d records matching dn=%s\n", ret,
				 ldb_dn_get_linearized(secret_state->secret_dn)));
			return NT_STATUS_INTERNAL_DB_CORRUPTION;
		}

		old_val = ldb_msg_find_ldb_val(res[0], "currentValue");
		last_set_time = ldb_msg_find_attr_as_uint64(res[0], "lastSetTime", 0);

		if (old_val) {
			 
			if (ldb_msg_add_value(msg, "priorValue",
					      old_val, NULL) != LDB_SUCCESS) {
				return NT_STATUS_NO_MEMORY;
			}
		} else {
			if (samdb_msg_add_delete(secret_state->sam_ldb,
						 mem_ctx, msg, "priorValue") != LDB_SUCCESS) {
				return NT_STATUS_NO_MEMORY;
			}
		}

		 
		if (ldb_msg_find_ldb_val(res[0], "lastSetTime")) {
			if (samdb_msg_add_uint64(secret_state->sam_ldb,
						 mem_ctx, msg, "priorSetTime", last_set_time) != LDB_SUCCESS) {
				return NT_STATUS_NO_MEMORY;
			}
		} else {
			if (samdb_msg_add_uint64(secret_state->sam_ldb,
						 mem_ctx, msg, "priorSetTime", nt_now) != LDB_SUCCESS) {
				return NT_STATUS_NO_MEMORY;
			}
		}
	}

	if (r->in.new_val) {
		 
		crypt_secret.data = r->in.new_val->data;
		crypt_secret.length = r->in.new_val->size;

		status = sess_decrypt_blob(mem_ctx, &crypt_secret, &session_key, &secret);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}

		val.data = secret.data;
		val.length = secret.length;

		 
		if (ldb_msg_add_value(msg, "currentValue", &val, NULL) != LDB_SUCCESS) {
			return NT_STATUS_NO_MEMORY;
		}

		 
		if (samdb_msg_add_uint64(secret_state->sam_ldb,
					 mem_ctx, msg, "lastSetTime", nt_now) != LDB_SUCCESS) {
			return NT_STATUS_NO_MEMORY;
		}
	} else {
		 
		if (samdb_msg_add_uint64(secret_state->sam_ldb,
					 mem_ctx, msg, "lastSetTime", nt_now) != LDB_SUCCESS) {
			return NT_STATUS_NO_MEMORY;
		}
		if (samdb_msg_add_delete(secret_state->sam_ldb,
					 mem_ctx, msg, "currentValue") != LDB_SUCCESS) {
			return NT_STATUS_NO_MEMORY;
		}
	}

	 
	ret = dsdb_replace(secret_state->sam_ldb, msg, 0);
	if (ret != LDB_SUCCESS) {
		return dsdb_ldb_err_to_ntstatus(ret);
	}

	return NT_STATUS_OK;
}