static int paged_search(struct ldb_module *module, struct ldb_request *req)
{
	struct ldb_context *ldb;
	struct ldb_control *control;
	struct ldb_control *vlv_control;
	struct private_data *private_data;
	struct ldb_paged_control *paged_ctrl;
	struct ldb_request *search_req;
	struct paged_context *ac;
	int ret;

	ldb = ldb_module_get_ctx(module);

	/* check if there's a paged request control */
	control = ldb_request_get_control(req, LDB_CONTROL_PAGED_RESULTS_OID);
	if (control == NULL) {
		/* not found go on */
		return ldb_next_request(module, req);
	}

	paged_ctrl = talloc_get_type(control->data, struct ldb_paged_control);
	if (!paged_ctrl) {
		return LDB_ERR_PROTOCOL_ERROR;
	}

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

	vlv_control = ldb_request_get_control(req, LDB_CONTROL_VLV_REQ_OID);
	if (vlv_control != NULL) {
		/*
		 * VLV and paged_results are not allowed at the same
		 * time
		 */
		return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
	}

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

	ac->module = module;
	ac->req = req;
	ac->size = paged_ctrl->size;
	if (ac->size < 0) {
		/*
		 * Apparently some clients send more than 2^31. This
		 * violates the ldap standard, but we need to cope.
		 * In the future, if maximum result sizes are implemented in
		 * Samba, we should also clamp the page size to the maximum
		 * result size.
		 */
		ac->size = 0x7FFFFFFF;
	}

	/* check if it is a continuation search the store */
	if (paged_ctrl->cookie_len == 0) {
		struct ldb_control *ext_ctrl;
		struct ldb_control **controls;
		static const char * const attrs[1] = { NULL };

		if (paged_ctrl->size == 0) {
			return LDB_ERR_OPERATIONS_ERROR;
		}

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

		controls = req->controls;
		ext_ctrl = ldb_request_get_control(req,
					LDB_CONTROL_EXTENDED_DN_OID);
		if (ext_ctrl == NULL) {
			/*
			 * Add extended_dn control to the request if there
			 * isn't already one.  We'll get the GUID out of it in
			 * the callback.  This is a workaround for the case
			 * where ntsecuritydescriptor forbids fetching GUIDs
			 * for the current user.
			 */
			struct ldb_request *req_extended_dn;
			struct ldb_extended_dn_control *ext_ctrl_data;
			req_extended_dn = talloc_zero(req, struct ldb_request);
			req_extended_dn->controls = req->controls;
			ext_ctrl_data = talloc_zero(req,
					struct ldb_extended_dn_control);
			ext_ctrl_data->type = 1;

			ret = ldb_request_add_control(req_extended_dn,
					      LDB_CONTROL_EXTENDED_DN_OID,
						      true,
						      ext_ctrl_data);
			if (ret != LDB_SUCCESS) {
				return ret;
			}
			controls = req_extended_dn->controls;
		}

		ret = ldb_build_search_req_ex(&search_req, ldb, ac,
						req->op.search.base,
						req->op.search.scope,
						req->op.search.tree,
						attrs,
						controls,
						ac,
						paged_search_callback,
						req);
		if (ret != LDB_SUCCESS) {
			return ret;
		}

		ac->store->expr = talloc_steal(ac->store, req->op.search.tree);
		ac->store->expr_str = ldb_filter_from_tree(ac->store,
							  req->op.search.tree);
		ac->store->attrs = paged_copy_attrs(ac->store,
						    req->op.search.attrs);

		/* 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 =
		    paged_results_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;
		char *expr_str;
		bool bool_ret;

		/* TODO: age out old outstanding requests */
		for (current = private_data->store; current != NULL;
		     current = current->next) {
			if (strcmp(current->cookie, paged_ctrl->cookie) == 0) {
				current->timestamp = time(NULL);
				break;
			}
		}
		if (current == NULL) {
			return LDB_ERR_UNWILLING_TO_PERFORM;
		}

		/* Get the expression string and make sure it didn't change */
		expr_str = ldb_filter_from_tree(ac, req->op.search.tree);
		if (expr_str == NULL) {
			return LDB_ERR_OPERATIONS_ERROR;
		}

		ret = strcmp(current->expr_str, expr_str);
		if (ret != 0) {
			return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
		}

		bool_ret = paged_controls_same(req, current->down_controls);
		if (bool_ret == false) {
			return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
		}

		bool_ret = paged_attrs_same(req->op.search.attrs,
					    current->attrs);
		if (bool_ret == false) {
			return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
		}

		DLIST_PROMOTE(private_data->store, current);

		ac->store = current;

		/* check if it is an abandon */
		if (ac->size == 0) {
			return ldb_module_done(req, NULL, NULL,
								LDB_SUCCESS);
		}

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