static int vlv_search(struct ldb_module *module, struct ldb_request *req)
{
	struct ldb_context *ldb;
	struct ldb_control *control;
	struct ldb_control *sort_control;
	struct private_data *priv;
	struct ldb_vlv_req_control *vlv_ctrl;
	struct ldb_server_sort_control **sort_ctrl;
	struct ldb_request *search_req;
	struct vlv_context *ac;
	int ret, i, critical;

	ldb = ldb_module_get_ctx(module);

	control = ldb_request_get_control(req, LDB_CONTROL_VLV_REQ_OID);
	if (control == NULL) {
		/* There is no VLV. go on */
		return ldb_next_request(module, req);
	}
	critical = control->critical;
	control->critical = 0;

	sort_control = ldb_request_get_control(req, LDB_CONTROL_SERVER_SORT_OID);
	if (sort_control == NULL) {
		/* VLV needs sort */
		return LDB_ERR_OPERATIONS_ERROR;
	}

	vlv_ctrl = talloc_get_type(control->data, struct ldb_vlv_req_control);
	if (vlv_ctrl == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	sort_ctrl = talloc_get_type(sort_control->data, struct ldb_server_sort_control *);
	if (sort_ctrl == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	priv = talloc_get_type(ldb_module_get_private(module),
			       struct private_data);

	ac = talloc_zero(req, struct vlv_context);
	if (ac == NULL) {
		ldb_set_errstring(ldb, "Out of Memory");
		return LDB_ERR_OPERATIONS_ERROR;
	}

	ac->module = module;
	ac->req = req;
	ac->priv = priv;
	/* If there is no cookie, this is a new request, and we need to do the
	 * search in the database. Otherwise we try to refer to a previously
	 * saved search.
	 */
	if (vlv_ctrl->ctxid_len == 0) {
		static const char * const attrs[2] = {
			"objectGUID", NULL
		};

		ac->store = new_store(priv);
		if (ac->store == NULL) {
			return LDB_ERR_OPERATIONS_ERROR;
		}

		ret = copy_search_details(ac->store, vlv_ctrl, sort_ctrl[0]);
		if (ret != LDB_SUCCESS) {
			return ret;
		}

		ret = ldb_build_search_req_ex(&search_req, ldb, ac,
					      req->op.search.base,
					      req->op.search.scope,
					      req->op.search.tree,
					      attrs,
					      req->controls,
					      ac,
					      vlv_search_callback,
					      req);
		if (ret != LDB_SUCCESS) {
			return ret;
		}
		/* save it locally and remove it from the list */
		/* we do not need to replace them later as we
		 * are keeping the original req intact */
		if (!ldb_save_controls(control, search_req, NULL)) {
			return LDB_ERR_OPERATIONS_ERROR;
		}

		ac->store->down_controls = vlv_copy_down_controls(ac->store,
								  req->controls);

		if (ac->store->down_controls == NULL) {
			return LDB_ERR_OPERATIONS_ERROR;
		}

		return ldb_next_request(module, search_req);

	} else {
		struct results_store *current = NULL;
		uint8_t *id = vlv_ctrl->contextId;

		if (vlv_ctrl->ctxid_len != sizeof(uint32_t)){
			return LDB_ERR_UNWILLING_TO_PERFORM;
		}

		for (i = 0; i < priv->n_stores; i++) {
			current = priv->store[i];
			if (current == NULL) {
				continue;
			}
			if (memcmp(&current->contextId, id, sizeof(uint32_t)) == 0) {
				current->timestamp = time(NULL);
				break;
			}
		}
		if (i == priv->n_stores) {
			/* We were given a context id that we don't know about. */
			if (critical) {
				return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
			} else {
				return ldb_next_request(module, req);
			}
		}

		ac->store = current;
		ret = copy_search_details(ac->store, vlv_ctrl, sort_ctrl[0]);
		if (ret != LDB_SUCCESS) {
			return ret;
		}

		ret = vlv_results(ac, NULL);
		if (ret != LDB_SUCCESS) {
			return ret;
		}
		return ldb_module_done(req, ac->controls, NULL,
				       LDB_SUCCESS);
	}
}