libcli/wsp: Add simple client api for wsp client code.
authorNoel Power <noel.power@suse.com>
Mon, 17 Oct 2022 19:15:32 +0000 (20:15 +0100)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 25 Oct 2023 22:23:38 +0000 (22:23 +0000)
Signed-off-by: Noel Power <noel.power@suse.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source3/rpc_client/wsp_cli.c [new file with mode: 0644]
source3/rpc_client/wsp_cli.h [new file with mode: 0644]
source3/wscript_build

diff --git a/source3/rpc_client/wsp_cli.c b/source3/rpc_client/wsp_cli.c
new file mode 100644 (file)
index 0000000..5f0dec1
--- /dev/null
@@ -0,0 +1,2157 @@
+/*
+ *  Unix SMB/CIFS implementation.
+ *
+ *  Window Search Service
+ *
+ *  Copyright (c)  Noel Power
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "client.h"
+#include "rpc_client/wsp_cli.h"
+#include "rpc_client/rpc_client.h"
+#include "param/param.h"
+#include "auth/credentials/credentials.h"
+#include <tevent.h>
+#include <util/tevent_ntstatus.h>
+#include "libcli/tstream_binding_handle/tstream_binding_handle.h"
+#include "lib/tsocket/tsocket.h"
+#include "librpc/wsp/wsp_util.h"
+#include "librpc/gen_ndr/ndr_wsp.h"
+#include "rpc_client/cli_pipe.h"
+#include "libcli/smb/smbXcli_base.h"
+
+#define MSG_HDR_SIZE 16
+#define USED 1
+/*
+ * 32-bit Windows XP operating system, 32-bit Windows Server 2003 operating
+ * system, 32-bit Windows Home Server server software, 32-bit Windows Vista
+ * with Windows Search 4.0, 32-bit Windows Server 2003 with Windows
+ * Search 4.0. All of these versions of Windows are running
+ * Windows Search 4.0.
+*/
+
+static const uint32_t CLIENTVERSION = 0x00010700;
+
+/*
+ * DBPROP_CI_SCOPE_FLAGS
+ * containing QUERY_DEEP
+ *    QUERY_DEEP (0x1) indicates that files in the scope directory and all
+ *    subdirectories are included in the results. If clear, only files in
+ *    the scope directory are included in the results.
+ */
+static int32_t scope_flags_vector[] = {0x00000001};
+/*
+ * Search everywhere "\\" is the root scope
+ */
+static const char * root_scope_string_vector[] = {"\\"};
+
+/* sets sensible defaults */
+static void init_wsp_prop(struct wsp_cdbprop *prop)
+{
+       *prop = (struct wsp_cdbprop){0};
+       prop->colid.ekind = DBKIND_GUID_PROPID;
+}
+
+
+static bool create_restriction_array(TALLOC_CTX *ctx,
+                              struct wsp_crestriction **pelements,
+                              uint32_t nnodes)
+{
+       struct wsp_crestriction *elements = talloc_zero_array(ctx,
+                                                      struct wsp_crestriction,
+                                                      nnodes);
+       if (elements == NULL) {
+               return false;
+       }
+       *pelements = elements;
+       return true;
+}
+
+
+static bool create_noderestriction(TALLOC_CTX *ctx,
+                              struct wsp_cnoderestriction *pnode,
+                              uint32_t nnodes)
+{
+       bool ok;
+       pnode->cnode = nnodes;
+       ok = create_restriction_array(ctx, &pnode->panode, nnodes);
+       return ok;
+}
+
+static bool fill_sortarray(TALLOC_CTX *ctx, struct wsp_csort **dest,
+                          struct wsp_csort *src, uint32_t num)
+{
+       uint32_t i;
+       struct wsp_csort *psort = talloc_zero_array(ctx, struct wsp_csort,
+                                                   num);
+       if (psort == NULL) {
+               return false;
+       }
+       for (i = 0; i < num; i++) {
+               psort[i] = src[i];
+       }
+       *dest = psort;
+       return true;
+}
+
+
+
+static bool set_fullpropspec(TALLOC_CTX *ctx, struct wsp_cfullpropspec *prop,
+                            const char* propname, uint32_t kind)
+{
+       struct GUID guid = {0};
+       const struct full_propset_info *prop_info = NULL;
+
+       prop_info = get_propset_info_with_guid(propname, &guid);
+       if (!prop_info) {
+               DBG_ERR("Failed to handle property named %s\n",
+                       propname);
+               return false;
+       }
+       prop->guidpropset = guid;
+       prop->ulkind = kind;
+       if (kind == PRSPEC_LPWSTR) {
+               prop->name_or_id.propname.vstring = talloc_strdup(ctx,
+                                                                  propname);
+               if (prop->name_or_id.propname.vstring == NULL) {
+                       DBG_ERR("out of memory");
+                       return false;
+               }
+               prop->name_or_id.propname.len = strlen(propname);
+       } else {
+               prop->name_or_id.prspec = prop_info->id;
+       }
+       return true;
+}
+
+struct binding
+{
+       uint32_t status_off;
+       uint32_t value_off;
+       uint32_t len_off;
+};
+
+static bool set_ctablecolumn(TALLOC_CTX *ctx, struct wsp_ctablecolumn *tablecol,
+               const char* propname, struct binding *offsets,
+               uint32_t value_size)
+{
+       struct wsp_cfullpropspec *prop = &tablecol->propspec;
+
+       if (!set_fullpropspec(ctx, prop, propname, PRSPEC_PROPID)) {
+               return false;
+       }
+       tablecol->vtype =VT_VARIANT ;
+       tablecol->aggregateused = USED;
+       tablecol->valueused = USED;
+       tablecol->valueoffset.value = offsets->value_off;
+       tablecol->valuesize.value = value_size;
+       tablecol->statusused = USED;
+       tablecol->statusoffset.value = offsets->status_off;
+       tablecol->lengthused = USED;
+       tablecol->lengthoffset.value = offsets->len_off;
+       return true;
+}
+
+
+static bool fill_uint32_vec(TALLOC_CTX* ctx,
+                           uint32_t **pdest,
+                           uint32_t* ivector, uint32_t elems)
+{
+       uint32_t i;
+       uint32_t *dest = talloc_zero_array(ctx, uint32_t, elems);
+       if (dest == NULL) {
+               return false;
+       }
+
+       for ( i = 0; i < elems; i++ ) {
+               dest[ i ] = ivector[ i ];
+       }
+       *pdest = dest;
+       return true;
+}
+
+static bool init_propset1(TALLOC_CTX* tmp_ctx,
+                                       struct wsp_cdbpropset *propertyset)
+{
+       uint32_t i;
+       GUID_from_string(DBPROPSET_FSCIFRMWRK_EXT,
+                        &propertyset->guidpropertyset);
+
+       propertyset->cproperties = 4;
+       propertyset->aprops =
+               talloc_zero_array(tmp_ctx, struct wsp_cdbprop,
+                            propertyset->cproperties);
+       if (propertyset->aprops == NULL) {
+               return false;
+       }
+
+       /* initialise first 4 props */
+       for( i = 0; i < propertyset->cproperties; i++) {
+               init_wsp_prop(&propertyset->aprops[i]);
+       }
+
+       /*
+        * see MS-WSP 2.2.1.31.1 & 4.1 Protocol examples, Example 1
+        *   and also as seen in various windows network traces
+        * set value prop[0] - 'catalog to search'
+        */
+
+       propertyset->aprops[0].dbpropid = DBPROP_CI_CATALOG_NAME;
+       /* The name of the Catalog to Query */
+       set_variant_lpwstr(tmp_ctx, &propertyset->aprops[0].vvalue,
+                       "Windows\\SystemIndex");
+       /*
+        * set value prop[1] 'Regular Query'
+        */
+
+       propertyset->aprops[1].dbpropid = DBPROP_CI_QUERY_TYPE;
+       set_variant_i4(tmp_ctx, &propertyset->aprops[1].vvalue,
+                      CINORMAL);
+
+       /*
+        * set value prop[2] 'search subfolders'
+        */
+       propertyset->aprops[2].dbpropid = DBPROP_CI_SCOPE_FLAGS;
+       set_variant_i4_vector(tmp_ctx, &propertyset->aprops[2].vvalue,
+                      scope_flags_vector, ARRAY_SIZE(scope_flags_vector));
+
+       /*
+        * set value prop[3] 'root scope'
+        */
+       propertyset->aprops[3].dbpropid = DBPROP_CI_INCLUDE_SCOPES;
+       set_variant_lpwstr_vector(tmp_ctx,
+                                 &propertyset->aprops[3].vvalue,
+                                 root_scope_string_vector,
+                                 ARRAY_SIZE(root_scope_string_vector));
+       return true;
+}
+
+static bool init_propset2(TALLOC_CTX* tmp_ctx,
+                         struct wsp_cdbpropset *propertyset,
+                         const char* server)
+{
+       uint32_t i;
+
+       GUID_from_string(DBPROPSET_CIFRMWRKCORE_EXT,
+                        &propertyset->guidpropertyset);
+
+       propertyset->cproperties = 1;
+       propertyset->aprops =
+               talloc_zero_array(tmp_ctx, struct wsp_cdbprop,
+                            propertyset->cproperties);
+       if (propertyset->aprops == NULL) {
+               return false;
+       }
+
+       /* initialise first 1 props */
+       for( i = 0; i < propertyset->cproperties; i++) {
+               init_wsp_prop(&propertyset->aprops[i]);
+       }
+
+       /*
+        * see MS-WSP 2.2.1.31.1 & 4.1 Protocol examples, Example 1
+        *   and also as seen in various windows network traces
+        * set value prop[0] - 'machines to search'
+        */
+       propertyset->aprops[0].dbpropid = DBPROP_MACHINE;
+       set_variant_bstr(tmp_ctx, &propertyset->aprops[0].vvalue,
+                       server);
+       return true;
+}
+
+static bool init_apropset0(TALLOC_CTX* tmp_ctx,
+                          struct wsp_cdbpropset *propertyset)
+{
+       uint32_t i;
+
+       GUID_from_string(DBPROPSET_MSIDXS_ROWSETEXT,
+                        &propertyset->guidpropertyset);
+
+       propertyset->cproperties = 7;
+       propertyset->aprops =
+               talloc_zero_array(tmp_ctx, struct wsp_cdbprop,
+                            propertyset->cproperties);
+       if (propertyset->aprops == NULL) {
+               return false;
+       }
+
+       /* initialise props */
+       for( i = 0; i < propertyset->cproperties; i++) {
+               init_wsp_prop(&propertyset->aprops[i]);
+       }
+
+       /*
+        * see MS-WSP 2.2.1.31.1 & 4.1 Protocol examples, Example 1
+        * set value prop[0]
+        * MSIDXSPROP_ROWSETQUERYSTATUS - 'ignored'
+        */
+       propertyset->aprops[0].dbpropid = MSIDXSPROP_ROWSETQUERYSTATUS;
+       set_variant_i4(tmp_ctx,  &propertyset->aprops[0].vvalue, 0x00000000);
+
+       /*
+        * set value prop[1]
+        * MSIDXSPROP_COMMAND_LOCALE_STRING - 'EN'
+        */
+       propertyset->aprops[1].dbpropid = MSIDXSPROP_COMMAND_LOCALE_STRING;
+       set_variant_bstr(tmp_ctx, &propertyset->aprops[1].vvalue,
+                       "en-us");
+
+       /*
+        * set value prop[2]
+        * MSIDXSPROP_QUERY_RESTRICTION - 'ignored'
+        */
+       propertyset->aprops[2].dbpropid = MSIDXSPROP_QUERY_RESTRICTION;
+       set_variant_bstr(tmp_ctx, &propertyset->aprops[2].vvalue,
+                       "");
+
+       /*
+        * set value prop[3]
+        * MSIDXSPROP_PARSE_TREE - 'ignored'
+        */
+       propertyset->aprops[3].dbpropid = MSIDXSPROP_PARSE_TREE;
+       set_variant_bstr(tmp_ctx, &propertyset->aprops[3].vvalue,
+                       "");
+
+       /*
+        * set value prop[4]
+        * MSIDXSPROP_MAX_RANK - 'ignored'
+        */
+       propertyset->aprops[4].dbpropid = MSIDXSPROP_MAX_RANK;
+       set_variant_i4(tmp_ctx,  &propertyset->aprops[4].vvalue, 0x00000000);
+
+       /*
+        * set value prop[5]
+        * MSIDXSPROP_RESULTS_FOUND - 'ignored'
+        */
+       propertyset->aprops[5].dbpropid = MSIDXSPROP_RESULTS_FOUND;
+       set_variant_i4(tmp_ctx,  &propertyset->aprops[5].vvalue, 0x00000000);
+
+       /*
+        * set value prop[6]
+        * ? - '' (unknown property id)
+        */
+       propertyset->aprops[6].dbpropid = 0x00000008;
+       set_variant_i4(tmp_ctx,  &propertyset->aprops[6].vvalue, 0x00000000);
+       return true;
+}
+
+static bool init_apropset1(TALLOC_CTX* tmp_ctx,
+                              struct wsp_cdbpropset *propertyset)
+{
+       uint32_t i;
+       GUID_from_string(DBPROPSET_QUERYEXT,
+                        &propertyset->guidpropertyset);
+
+       propertyset->cproperties = 11;
+       propertyset->aprops =
+               talloc_zero_array(tmp_ctx, struct wsp_cdbprop,
+                            propertyset->cproperties);
+       if (propertyset->aprops == NULL) {
+               return false;
+       }
+
+       /* init properties */
+       for( i = 0; i < propertyset->cproperties; i++) {
+               init_wsp_prop(&propertyset->aprops[i]);
+       }
+
+       /*
+        * see MS-WSP 2.2.1.31.1 & 4.1 Protocol examples, Example 1
+        * set value prop[0]
+        * DBPROP_USECONTENTINDEX - 'forced use of the full text index
+        *                           is false.'
+        */
+       propertyset->aprops[0].dbpropid = DBPROP_USECONTENTINDEX;
+       set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[0].vvalue, false);
+
+       /*
+        * set value prop[1]
+        * DBPROP_DEFERNONINDEXEDTRIMMING - 'trimming of security
+        *                                   results will not be deferred'
+        */
+       propertyset->aprops[1].dbpropid = DBPROP_DEFERNONINDEXEDTRIMMING;
+       set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[1].vvalue, false);
+
+       /*
+        * set value prop[2]
+        * DBPROP_USEEXTENDEDDBTYPES  - 'extended DB types are not used'
+        */
+       propertyset->aprops[2].dbpropid = DBPROP_USEEXTENDEDDBTYPES;
+       set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[2].vvalue, false);
+
+       /*
+        * set value prop[3]
+        * DBPROP_IGNORENOISEONLYCLAUSES = 'full text clauses consisting
+        *                                  entirely of noise words will
+        *                                  result in an error being returned'
+        */
+       propertyset->aprops[3].dbpropid = DBPROP_IGNORENOISEONLYCLAUSES;
+       set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[3].vvalue, false);
+
+       /*
+        * set value prop[4]
+        * DBPROP_GENERICOPTIONS_STRING - 'no generic options set'
+        */
+       propertyset->aprops[4].dbpropid = DBPROP_GENERICOPTIONS_STRING;
+       set_variant_bstr(tmp_ctx,  &propertyset->aprops[4].vvalue, "");
+
+       /*
+        * set value prop[5]
+        * DBPROP_DEFERCATALOGVERIFICATION - 'catalog verification is not
+        *                                    deferred.'
+        */
+       propertyset->aprops[5].dbpropid = DBPROP_DEFERCATALOGVERIFICATION;
+       set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[5].vvalue, false);
+
+       /*
+        * set value prop[6]
+        * DBPROP_IGNORESBRI - 'query can use the sort-by-rank index
+        *                      optimization'
+        */
+       propertyset->aprops[6].dbpropid = DBPROP_IGNORESBRI;
+       set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[6].vvalue, false);
+
+       /*
+        * set value prop[7]
+        * DBPROP_GENERATEPARSETREE - 'a parse tree is not generated for
+        *                             debugging.'
+        */
+       propertyset->aprops[7].dbpropid = DBPROP_GENERATEPARSETREE;
+       set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[7].vvalue, false);
+
+       /*
+        * set value prop[8]
+        * DBPROP_FREETEXTANYTERM - 'all terms from a FREETEXT clause
+        *                           appear in every matching document'
+        */
+       propertyset->aprops[8].dbpropid = DBPROP_FREETEXTANYTERM;
+       set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[8].vvalue, false);
+       /*
+        * set value prop[9]
+        * DBPROP_FREETEXTUSESTEMMING - 'stemming is not used when interpreting
+        *                               a FREETEXT clause'
+        */
+       propertyset->aprops[9].dbpropid = DBPROP_FREETEXTUSESTEMMING;
+       set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[9].vvalue, false);
+
+       /*
+        * set value prop[10]
+        * ? - ''
+        */
+       propertyset->aprops[10].dbpropid = 0x0000000f; /* ??? */
+       set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[10].vvalue, false);
+       return true;
+}
+
+static bool init_apropset2(TALLOC_CTX* tmp_ctx,
+                          struct wsp_cdbpropset *propertyset,
+                          const char* server)
+{
+       uint32_t i;
+       GUID_from_string(DBPROPSET_CIFRMWRKCORE_EXT,
+                        &propertyset->guidpropertyset);
+
+       propertyset->cproperties = 1;
+       propertyset->aprops =
+               talloc_zero_array(tmp_ctx, struct wsp_cdbprop,
+                            propertyset->cproperties);
+       if (propertyset->aprops == NULL) {
+               return false;
+       }
+
+       /* init properties */
+       for( i = 0; i < propertyset->cproperties; i++) {
+               init_wsp_prop(&propertyset->aprops[i]);
+       }
+
+       /*
+        * see MS-WSP 2.2.1.31.1 & 4.1 Protocol examples, Example 1
+        *   and also as seen in various windows network traces
+        * set value prop[0]
+        * DBPROP_MACHINE - 'target server'
+        */
+       propertyset->aprops[0].dbpropid = DBPROP_MACHINE;
+       set_variant_bstr(tmp_ctx,  &propertyset->aprops[0].vvalue, server);
+       return true;
+}
+
+
+static bool init_apropset3(TALLOC_CTX* tmp_ctx,
+                          struct wsp_cdbpropset *propertyset)
+{
+       uint32_t i;
+
+       GUID_from_string(DBPROPSET_FSCIFRMWRK_EXT,
+                        &propertyset->guidpropertyset);
+
+       propertyset->cproperties = 3;
+       propertyset->aprops =
+               talloc_zero_array(tmp_ctx, struct wsp_cdbprop,
+                            propertyset->cproperties);
+       if (propertyset->aprops == NULL) {
+               return false;
+       }
+
+       /* init properties */
+       for( i = 0; i < propertyset->cproperties; i++) {
+               init_wsp_prop(&propertyset->aprops[i]);
+       }
+
+       /*
+        * see MS-WSP 2.2.1.31.1 & 4.1 Protocol examples, Example 1
+        *   and also as seen in various windows network traces
+        * set value prop[0]
+        * DBPROP_CI_INCLUDE_SCOPES - 'search everywhere'
+        */
+       propertyset->aprops[0].dbpropid = DBPROP_CI_INCLUDE_SCOPES;
+       set_variant_array_bstr(tmp_ctx, &propertyset->aprops[0].vvalue,
+                              root_scope_string_vector,
+                              ARRAY_SIZE(root_scope_string_vector));
+
+       /*
+        * set value prop[1]
+        * DBPROP_CI_SCOPE_FLAGS - 'QUERY_DEEP'
+        */
+       propertyset->aprops[1].dbpropid = DBPROP_CI_SCOPE_FLAGS;
+       set_variant_array_i4(tmp_ctx, &propertyset->aprops[1].vvalue,
+                            scope_flags_vector,
+                            ARRAY_SIZE(scope_flags_vector));
+
+       /*
+        * set value prop[2]
+        * DBPROP_CI_CATALOG_NAME - 'index to use' (always the same)
+        */
+       propertyset->aprops[2].dbpropid = DBPROP_CI_CATALOG_NAME;
+       set_variant_bstr(tmp_ctx, &propertyset->aprops[2].vvalue,
+                        "Windows\\SystemIndex");
+       return true;
+}
+
+bool init_connectin_request(TALLOC_CTX *ctx,
+                           struct wsp_request* request,
+                           const char* clientmachine,
+                           const char* clientuser,
+                           const char* server)
+{
+       enum ndr_err_code err;
+       struct connectin_propsets *props = NULL;
+       struct connectin_extpropsets *ext_props = NULL;
+       DATA_BLOB props_blob = data_blob_null;
+       struct ndr_push *ndr_props = NULL;
+       int ndr_flags = NDR_SCALARS | NDR_BUFFERS;
+       bool result;
+       struct wsp_cpmconnectin *connectin =
+               &request->message.cpmconnect;
+
+       props = talloc_zero(ctx, struct connectin_propsets);
+       if (props == NULL) {
+               result = false;
+               DBG_ERR("out of memory\n");
+               goto out;
+       }
+
+       ext_props = talloc_zero(ctx, struct connectin_extpropsets) ;
+       if (ext_props == NULL) {
+               result = false;
+               DBG_ERR("out of memory\n");
+               goto out;
+       }
+
+       request->header.msg = CPMCONNECT;
+       connectin->iclientversion = CLIENTVERSION;
+       /*
+        * hmm just say the client is remote, if we
+        * are talking to windows it is, if not does
+        * it really matter?
+        */
+       connectin->fclientisremote = 0x00000001;
+       connectin->machinename = clientmachine;
+       connectin->username = clientuser;
+       props->cpropsets = 2;
+
+       /* =================== */
+       /* set up PropertySet1 */
+       /* =================== */
+       if (!init_propset1(ctx, &props->propertyset1)) {
+               result = false;
+               DBG_ERR("initialising propset1 failed\n");
+               goto out;
+       }
+
+       /* =================== */
+       /* set up PropertySet2 */
+       /* =================== */
+       if (!init_propset2(ctx, &props->propertyset2, server)) {
+               result = false;
+               DBG_ERR("initialising propset2 failed\n");
+               goto out;
+       }
+
+       /* 4 ExtPropSets */
+       ext_props->cextpropset = 4;
+       ext_props->apropertysets = talloc_zero_array(ctx, struct wsp_cdbpropset,
+                            ext_props->cextpropset);
+
+       if (ext_props->apropertysets == NULL) {
+               result = false;
+               DBG_ERR("out of memory\n");
+               goto out;
+       }
+
+       /* ======================= */
+       /* set up aPropertySets[0] */
+       /* ======================= */
+       if (!init_apropset0(ctx, &ext_props->apropertysets[0])) {
+               result = false;
+               DBG_ERR("initialisation of apropset0 failed\n");
+               goto out;
+       }
+
+       /* ======================= */
+       /* set up aPropertySets[1] */
+       /* ======================= */
+       if (!init_apropset1(ctx, &ext_props->apropertysets[1])) {
+               result = false;
+               DBG_ERR("initialisation of apropset1 failed\n");
+               goto out;
+       }
+
+       /* ======================= */
+       /* set up aPropertySets[2] */
+       /* ======================= */
+       if (!init_apropset2(ctx, &ext_props->apropertysets[2], server)) {
+               result = false;
+               DBG_ERR("initialisation of apropset2 failed\n");
+               goto out;
+       }
+
+       /* ======================= */
+       /* set up aPropertySets[3] */
+       /* ======================= */
+       if (!init_apropset3(ctx, &ext_props->apropertysets[3])) {
+               result = false;
+               DBG_ERR("initialisation of apropset3 failed\n");
+               goto out;
+       }
+
+       /* we also have to fill the opaque blobs that contain the propsets */
+       ndr_props = ndr_push_init_ctx(ctx);
+       if (ndr_props == NULL) {
+               result = false;
+               DBG_ERR("out of memory\n");
+               goto out;
+       }
+
+       /* first connectin_propsets */
+       err = ndr_push_connectin_propsets(ndr_props, ndr_flags, props);
+       if (err) {
+               DBG_ERR("Failed to push propset, error %d\n", err);
+               result = false;
+               goto out;
+       }
+       props_blob = ndr_push_blob(ndr_props);
+       connectin->cbblob1 = props_blob.length;
+       connectin->propsets = talloc_zero_array(ctx, uint8_t,
+                                  connectin->cbblob1);
+       if (connectin->propsets == NULL) {
+               result = false;
+               DBG_ERR("out of memory\n");
+               goto out;
+       }
+
+       memcpy(connectin->propsets, props_blob.data, props_blob.length);
+
+       /* then connectin_extpropsets */
+       TALLOC_FREE(ndr_props);
+       ndr_props = ndr_push_init_ctx(ctx);
+
+       if (ndr_props == NULL) {
+               result = false;
+               DBG_ERR("out of memory\n");
+               goto out;
+       }
+
+       err = ndr_push_connectin_extpropsets(ndr_props, ndr_flags, ext_props);
+
+       if (err) {
+               DBG_ERR("Failed to push extpropset, error %d\n", err);
+               result = false;
+               goto out;
+       }
+
+       props_blob = ndr_push_blob(ndr_props);
+       connectin->cbblob2 = props_blob.length;
+       connectin->extpropsets = talloc_zero_array(ctx, uint8_t,
+                                                  connectin->cbblob2);
+
+       if (connectin->extpropsets == NULL) {
+               result = false;
+               DBG_ERR("out of memory\n");
+               goto out;
+       }
+
+       memcpy(connectin->extpropsets, props_blob.data, props_blob.length);
+       TALLOC_FREE(ndr_props);
+       result = true;
+out:
+       return result;
+}
+
+void create_seekat_getrows_request(TALLOC_CTX * ctx,
+                                  struct wsp_request* request,
+                                  uint32_t cursor,
+                                  uint32_t bookmark,
+                                  uint32_t skip,
+                                  uint32_t rows,
+                                  uint32_t cbreserved,
+                                  uint32_t ulclientbase,
+                                  uint32_t cbrowwidth,
+                                  uint32_t fbwdfetch)
+{
+       struct wsp_cpmgetrowsin *getrows =
+               &request->message.cpmgetrows;
+       /* msg type */
+       request->header.msg = CPMGETROWS;
+       /* position */
+       getrows->hcursor = cursor;
+       /* max no. rows to receive */
+       getrows->crowstotransfer = rows;
+       /*
+        * size (length) of row in bytes, determined from value set
+        * by CPMSetBindings message
+        */
+       getrows->cbrowWidth = cbrowwidth;
+       /*
+        * according to we should calculate this (see MS-WSP 3.2.4.2.4)
+        * but it seems window always sets this to the max 16KB limit
+        * (most likely when any row value is variable size e.g. like a
+        * string/path)
+        */
+       getrows->cbreadbuffer = 0x00004000;
+       /*
+        * base value of buffer pointer
+        */
+       getrows->ulclientbase = ulclientbase;
+       getrows->cbreserved = cbreserved;
+       /* fetch rows in forward order */
+       getrows->fbwdfetch = fbwdfetch;
+       /* eRowSeekAt */
+       getrows->etype = EROWSEEKAT;
+       /* we don't handle chapters */
+       getrows->chapt = 0;
+       /* CRowsSeekAt (MS-WSP 2.2.1.37) */
+       getrows->seekdescription.crowseekat.bmkoffset = bookmark;
+       getrows->seekdescription.crowseekat.cskip = skip;
+       getrows->seekdescription.crowseekat.hregion = 0;
+}
+
+static bool extract_rowbuf_variable_type(TALLOC_CTX *ctx,
+               uint16_t type,
+               uint32_t offset,
+               DATA_BLOB *rows_buf, uint32_t len,
+               struct wsp_cbasestoragevariant  *val)
+{
+       enum ndr_err_code err;
+       struct ndr_pull *ndr_pull = NULL;
+       int ndr_flags = NDR_SCALARS | NDR_BUFFERS;
+       DATA_BLOB variant_blob = data_blob_null;
+       if (offset >= rows_buf->length) {
+               DBG_ERR("offset %d outside buffer range (buf len - %zu)",
+                       offset,
+                       rows_buf->length);
+               return false;
+       }
+       variant_blob.data = rows_buf->data + offset;
+       variant_blob.length = len;
+       ndr_pull = ndr_pull_init_blob(&variant_blob, ctx);
+
+       if (ndr_pull == NULL) {
+               DBG_ERR("out of memory\n");
+               return false;
+       }
+
+       switch (type) {
+               case VT_LPWSTR: {
+                       const char *string = NULL;
+                       ndr_set_flags(&ndr_pull->flags, LIBNDR_FLAG_STR_NULLTERM);
+                       err = ndr_pull_string(ndr_pull, ndr_flags, &string);
+                       if (err) {
+                               DBG_ERR("error unmarshalling string from %p\n", variant_blob.data );
+                       } else {
+                               DBG_INFO("\tstring val ->%s<-\n", string );
+                               val->vtype = type;
+                               val->vvalue.vt_lpwstr.value = string;
+                       }
+                       break;
+               }
+               default:
+                       DBG_ERR("#FIXME Unhandled variant type %s\n", get_vtype_name(type));
+                       break;
+       }
+       return true;
+}
+
+static bool convert_variant_array_to_vector(TALLOC_CTX *ctx,
+               uint64_t count,
+               struct wsp_cbasestoragevariant **variant_array,
+               struct wsp_cbasestoragevariant *outval)
+{
+       int i;
+       uint16_t vtype;
+       union variant_types vvalue = {0};
+       vtype = variant_array[0]->vtype;
+
+       if (outval == NULL) {
+               return false;
+       }
+
+       if (count) {
+               switch (vtype) {
+                       case VT_BSTR:
+                               vvalue.vt_bstr_v.vvector_elements = count;
+                               vvalue.vt_bstr_v.vvector_data =
+                                       talloc_zero_array(ctx,
+                                               struct vt_bstr, count);
+                               if (vvalue.vt_bstr_v.vvector_data == NULL) {
+                                       return false;
+                               }
+                               break;
+                       case VT_LPWSTR:
+                               vvalue.vt_lpwstr_v.vvector_elements = count;
+                               vvalue.vt_lpwstr_v.vvector_data =
+                                       talloc_zero_array(ctx,
+                                               struct vt_lpwstr, count);
+                               if (vvalue.vt_lpwstr_v.vvector_data == NULL) {
+                                       return false;
+                               }
+                               break;
+                       case VT_COMPRESSED_LPWSTR:
+                               vvalue.vt_compresseed_lpwstr_v.vvector_elements
+                                       = count;
+                               vvalue.vt_compresseed_lpwstr_v.vvector_data =
+                                       talloc_zero_array(ctx,
+                                               struct vt_compressed_lpwstr,
+                                               count);
+                               if (vvalue.vt_compresseed_lpwstr_v.vvector_data == NULL) {
+                                       return false;
+                               }
+                               break;
+                       default:
+                               DBG_ERR("Can't convert array of %s to VECTOR\n",
+                                       get_vtype_name(vtype));
+                               return false;
+               }
+       }
+       for (i = 0; i < count; i++) {
+               if (variant_array[i]->vtype != vtype) {
+                       DBG_ERR("array item type %s doesn't match extpected "
+                               "type %s\n",
+                               get_vtype_name(variant_array[i]->vtype),
+                               get_vtype_name(vtype));
+                       return false;
+               }
+               switch (variant_array[i]->vtype) {
+                       case VT_BSTR:
+                               vvalue.vt_bstr_v.vvector_data[i]
+                                       = variant_array[i]->vvalue.vt_bstr;
+                               break;
+                       case VT_LPWSTR:
+                               vvalue.vt_lpwstr_v.vvector_data[i]
+                                       = variant_array[i]->vvalue.vt_lpwstr;
+                               break;
+                       case VT_COMPRESSED_LPWSTR:
+                               vvalue.vt_compresseed_lpwstr_v.vvector_data[i]
+                                       = variant_array[i]->vvalue.vt_compressed_lpwstr;
+                               break;
+                       default:
+                               DBG_ERR("Can't convert array of %s to VECTOR\n",
+                                       get_vtype_name(vtype));
+                               return false;
+               }
+       }
+       outval->vtype = vtype | VT_VECTOR;
+       outval->vvalue = vvalue;
+       return true;
+}
+
+/*
+ * get the addresses in rowbuf of variants to read from
+ * pvec_address will point to addresses,
+ * an array of n elements for a vector or array of 1 element
+ * if non-vector item.
+ *
+ * addresses stored in pvec_address are adjusted by offset
+ *
+ */
+static enum ndr_err_code extract_variant_addresses(TALLOC_CTX *ctx,
+                              struct wsp_ctablevariant *tablevar,
+                              bool is_64bit,
+                              struct ndr_pull *ndr_pull,
+                              int flags,
+                              uint32_t offset,
+                              DATA_BLOB *rows_buf,
+                              uint64_t *pcount,
+                              uint64_t **pvec_address/*,
+                              struct wsp_cbasestoragevariant ***variant_array*/)
+{
+       bool is_vector = tablevar->vtype & VT_VECTOR;
+       uint64_t count;
+       uint64_t addr;
+       uint64_t *vec_address = NULL;
+       enum ndr_err_code err;
+
+       /* read count (only if this is a vector) */
+       if (is_vector) {
+               if (is_64bit) {
+                       err = ndr_pull_udlong(ndr_pull,
+                                       flags,
+                                       &count);
+                       if (err) {
+                               DBG_ERR("Failed to extract count\n");
+                               goto out;
+                       }
+               } else {
+                       uint32_t count_32;
+                       err = ndr_pull_uint32(ndr_pull,
+                                       flags,
+                                       &count_32);
+                       if (err) {
+                               DBG_ERR("Failed to extract count\n");
+                               goto out;
+                       }
+                       count = (uint64_t)count_32;
+               }
+       } else {
+               count = 1;
+       }
+
+       /* read address */
+       if (is_64bit) {
+               err = ndr_pull_udlong(ndr_pull,
+                               flags,
+                               &addr);
+               if (err) {
+                       DBG_ERR("Failed to extract address\n");
+                       goto out;
+               }
+       } else {
+               uint32_t addr_32;
+               err = ndr_pull_uint32(ndr_pull, flags, &addr_32);
+               if (err) {
+                       DBG_ERR("Failed to extract address\n");
+                       goto out;
+               }
+               addr = addr_32;
+       }
+
+       addr = addr - offset;
+
+       if (addr >= rows_buf->length) {
+               DBG_ERR("offset %"PRIu64" outside buffer range "
+                       "(buf len - %zu)\n",
+                       addr,
+                       rows_buf->length);
+               err = NDR_ERR_VALIDATE;
+               goto out;
+       }
+
+       vec_address = talloc_zero_array(ctx,
+                       uint64_t, count);
+
+       if (vec_address == NULL) {
+               err = NDR_ERR_ALLOC;
+               goto out;
+       }
+
+       if (is_vector == false) {
+               vec_address[0] = addr;
+       } else {
+               uint64_t array_addr = addr;
+               int i;
+               for (i = 0; i < count; i++) {
+                       if (is_64bit) {
+                               vec_address[i] =
+                                       PULL_LE_I64(rows_buf->data,
+                                               array_addr);
+                               array_addr = array_addr + 8;
+                       } else {
+                               vec_address[i] =
+                                       (uint32_t)PULL_LE_I32(rows_buf->data,
+                                                       array_addr);
+                               array_addr = array_addr + 4;
+                       }
+                       /* adjust address */
+                       vec_address[i] -= offset;
+               }
+       }
+       err  = NDR_ERR_SUCCESS;
+       *pcount = count;
+       *pvec_address = vec_address;
+out:
+       return err;
+}
+
+static enum ndr_err_code extract_crowvariant_variable(TALLOC_CTX *ctx,
+       struct wsp_ctablevariant *tablevar,
+       bool is_64bit,
+       struct ndr_pull *ndr_pull,
+       int flags,
+       uint32_t offset,
+       DATA_BLOB *rows_buf,
+       uint32_t len,
+       struct wsp_cbasestoragevariant *val)
+{
+       enum ndr_err_code err;
+       bool is_vector = tablevar->vtype & VT_VECTOR;
+       uint64_t count = 0;
+
+       uint64_t *vec_address = NULL;
+       struct wsp_cbasestoragevariant **variant_array = NULL;
+       int i;
+
+
+       err = extract_variant_addresses(ctx,
+                       tablevar,
+                       is_64bit,
+                       ndr_pull,
+                       flags,
+                       offset,
+                       rows_buf,
+                       &count,
+                       &vec_address);
+
+       if (err) {
+               DBG_ERR("Failed to extract address and/or count\n");
+               goto out;
+       }
+
+       variant_array = talloc_zero_array(ctx,
+                       struct wsp_cbasestoragevariant*,
+                       count);
+
+       if (variant_array == NULL) {
+               err = NDR_ERR_ALLOC;
+               goto out;
+       }
+
+       if (is_vector == false) {
+               variant_array[0] = val;
+       } else {
+               for (i = 0; i < count; i++) {
+                       variant_array[i] = talloc_zero(ctx,
+                               struct wsp_cbasestoragevariant);
+                       if (variant_array[i] == NULL) {
+                                       err = NDR_ERR_ALLOC;
+                                       goto out;
+                               }
+               }
+       }
+
+       for (i = 0; i < count; i++) {
+               uint32_t tmplen = len;
+               uint64_t addr;
+               addr = vec_address[i];
+               if (addr >= rows_buf->length) {
+                       DBG_ERR("offset %"PRIu64" outside buffer range "
+                               "(buf len - %zu)\n",
+                               addr,
+                               rows_buf->length);
+                       err = NDR_ERR_VALIDATE;
+                       goto out;
+               }
+               if (is_64bit
+                   && (tablevar->vtype & ~(VT_VECTOR)) == VT_LPWSTR) {
+                       /*
+                        * we can't trust len if 64 bit mode
+                        * (in 32 bit mode the length reported at len offset
+                        * seem consistent and correct)
+                        * So in this case instead of using the len
+                        * at len offset we just use the full buffer
+                        * from the point the value is stored at
+                        * till the end of the buffer
+                        */
+                       tmplen = rows_buf->length - addr;
+               }
+               if (!extract_rowbuf_variable_type(ctx,
+                                       tablevar->vtype & ~VT_VECTOR,
+                                       addr,
+                                       rows_buf,
+                                       tmplen,
+                                       variant_array[i])) {
+                       err = NDR_ERR_VALIDATE;
+                       goto out;
+               }
+       }
+
+       if (is_vector) {
+               if (!convert_variant_array_to_vector(ctx,
+                                               count,
+                                               variant_array,
+                                               val)) {
+                               err = NDR_ERR_VALIDATE;
+                               goto out;
+                       }
+       }
+       err  = NDR_ERR_SUCCESS;
+out:
+       return err;
+}
+
+static enum ndr_err_code extract_crowvariant(TALLOC_CTX *ctx,
+                              struct wsp_ctablevariant *tablevar,
+                              bool is_64bit,
+                              struct ndr_pull *ndr_pull,
+                              int flags,
+                              uint32_t offset,
+                              DATA_BLOB *rows_buf, uint32_t len,
+                              struct wsp_cbasestoragevariant *val)
+{
+       enum ndr_err_code err  = NDR_ERR_SUCCESS;
+       bool is_vector = tablevar->vtype & VT_VECTOR;
+       bool is_array = tablevar->vtype & VT_ARRAY;
+
+       if (is_array) {
+               DBG_ERR("Not handling ARRAYs!!!\n");
+               err = NDR_ERR_VALIDATE;
+               goto out;
+       }
+
+       if (is_variable_size((tablevar->vtype & ~(VT_VECTOR)))) {
+               err = extract_crowvariant_variable(ctx,
+                               tablevar,
+                               is_64bit,
+                               ndr_pull,
+                               flags,
+                               offset,
+                               rows_buf,
+                               len,
+                               val);
+
+       } else {
+               if (is_vector) {
+                       DBG_ERR("Not handling VECTORs of fixed size values!!!\n");
+                       err = NDR_ERR_VALIDATE;
+                       goto out;
+               }
+               NDR_CHECK(ndr_pull_set_switch_value(ndr_pull,
+                                       &val->vvalue,
+                                       tablevar->vtype));
+               NDR_CHECK(ndr_pull_variant_types(ndr_pull, NDR_SCALARS, &val->vvalue));
+               val->vtype = tablevar->vtype;
+       }
+out:
+       return err;
+}
+
+static enum ndr_err_code process_columns(TALLOC_CTX *ctx,
+                                        bool is_64bit,
+                                        uint32_t cbreserved,
+                                        uint64_t baseaddress,
+                                        struct wsp_cpmsetbindingsin *bindingin,
+                                        DATA_BLOB *rows_buf,
+                                        uint32_t nrow,
+                                        struct wsp_cbasestoragevariant *cols)
+{
+       uint32_t i;
+       enum ndr_err_code err  = NDR_ERR_SUCCESS;
+       struct ndr_pull *ndr_pull = NULL;
+       int ndr_flags = NDR_SCALARS | NDR_BUFFERS;
+       uint64_t nrow_offset = nrow * bindingin->brow;
+
+       if (nrow_offset >= rows_buf->length) {
+               DBG_ERR("offset %"PRIu64" outside buffer range (buf len - %zu)\n",
+                       nrow_offset,
+                       rows_buf->length);
+               err = NDR_ERR_ALLOC;
+               goto out;
+       }
+
+       /*
+        * process columns, column info is contained in cpmsetbindings
+        * for more information see 'Rows' description MS-WSP 2.2.4.1.2
+        * which describes how the server fills the buffer.
+        */
+       for (i = 0; i < bindingin->ccolumns; i++) {
+               struct wsp_ctablecolumn *tab_col = &bindingin->acolumns[i];
+               DATA_BLOB col_val_blob = data_blob_null;
+               uint64_t val_offset;
+               struct wsp_ctablevariant tablevariant = {0};
+               DBG_INFO("\nRow[%d]Col[%d] property %s type %s\n",nrow, i,
+                     prop_from_fullprop(ctx, &tab_col->propspec),
+                     get_vtype_name(tab_col->vtype));
+               if (tab_col->statusused) {
+                       val_offset = nrow_offset + tab_col->statusoffset.value;
+                       if (val_offset >=  rows_buf->length) {
+                               DBG_ERR("offset %"PRIu64" outside buffer range "
+                                       "(buf len - %zu)\n",
+                                       val_offset,
+                                       rows_buf->length);
+                               err = NDR_ERR_ALLOC;
+                               goto out;
+                       }
+                       DBG_INFO("\n\tstatusoffset 0x%x status is %s\n",
+                             tab_col->statusoffset.value,
+                             get_store_status(
+                                     (uint8_t)*(rows_buf->data
+                                       + val_offset)));
+               }
+               if (tab_col->lengthused) {
+                       val_offset = nrow_offset + tab_col->lengthoffset.value;
+                       if (val_offset >=  rows_buf->length) {
+                               DBG_ERR("offset %"PRIu64" outside buffer range "
+                                       "(buf len - %zu)\n",
+                                       val_offset,
+                                       rows_buf->length);
+                               err = NDR_ERR_ALLOC;
+                               goto out;
+                       }
+                       DBG_INFO("\n\tlen offset 0x%x value at length is 0x%x\n",
+                               tab_col->lengthoffset.value,
+                               PULL_LE_I32(rows_buf->data,
+                                       val_offset));
+               }
+               if (tab_col->valueused) {
+                       uint64_t offset = baseaddress + cbreserved;
+                       uint32_t len = 0;
+                       val_offset = nrow_offset + tab_col->valueoffset.value;
+                       if (val_offset >=  rows_buf->length) {
+                               DBG_ERR("offset %"PRIu64" outside buffer range "
+                                       "(buf len - %zu)\n",
+                                       val_offset,
+                                       rows_buf->length);
+                               err = NDR_ERR_ALLOC;
+                               goto out;
+                       }
+                       DBG_INFO("\n\tvalueoffset:valuesize 0x%x:0x%x "
+                               "crowvariant address = 0x%"PRIx64"\n",
+                               tab_col->valueoffset.value,
+                               tab_col->valuesize.value,
+                               val_offset);
+
+                       col_val_blob.data = rows_buf->data + val_offset;
+                       col_val_blob.length = tab_col->valuesize.value;
+
+
+                       if (tab_col->vtype != VT_VARIANT) {
+                               DBG_ERR("Not handling non variant column "
+                                       "values\n");
+                               err = NDR_ERR_VALIDATE;
+                               goto out;
+                       }
+                       ndr_pull = ndr_pull_init_blob(&col_val_blob, ctx);
+                       if (ndr_pull == NULL) {
+                               err = NDR_ERR_ALLOC;
+                               DBG_ERR("out of memory\n");
+                               goto out;
+                       }
+
+                       err = ndr_pull_wsp_ctablevariant(ndr_pull,
+                               ndr_flags,
+                               &tablevariant);
+                       if (err) {
+                               DBG_ERR("!!! failed to pull fixed part of variant data for col data\n");
+                               goto out;
+                       }
+                       DBG_INFO("\n");
+                       DBG_INFO("\tcrowvariant contains %s \n",
+                               get_vtype_name(tablevariant.vtype));
+
+                       if (tab_col->lengthused) {
+                               /*
+                                * it seems the size is what's at
+                                * lengthoffset - tab_col->valuesize.value
+                                */
+                               len = PULL_LE_I32(rows_buf->data,
+                                       nrow_offset
+                                       + tab_col->lengthoffset.value);
+                               len = len - tab_col->valuesize.value;
+                       }
+                       err = extract_crowvariant(ctx,
+                                       &tablevariant,
+                                       is_64bit,
+                                       ndr_pull,
+                                       ndr_flags,
+                                       offset,
+                                       rows_buf,
+                                       len,
+                                       &cols[i]);
+               }
+       }
+out:
+       return err;
+}
+
+/*
+ * extracts values from rows_buf into rowsarray
+ * based on the information in bindingsin
+ */
+enum ndr_err_code extract_rowsarray(
+                       TALLOC_CTX * ctx,
+                       DATA_BLOB *rows_buf,
+                       bool is_64bit,
+                       struct wsp_cpmsetbindingsin *bindingsin,
+                       uint32_t cbreserved,
+                       uint64_t baseaddress,
+                       uint32_t rows,
+                       struct wsp_cbasestoragevariant **rowsarray)
+{
+       int i;
+       enum ndr_err_code err  = NDR_ERR_SUCCESS;
+
+       for (i = 0; i < rows; i++ ) {
+               struct wsp_cbasestoragevariant *cols =
+                               talloc_zero_array(ctx,
+                                         struct wsp_cbasestoragevariant,
+                                         bindingsin->ccolumns);
+               if (cols == NULL) {
+                       return NDR_ERR_ALLOC;
+               }
+               err = process_columns(ctx,
+                                     is_64bit,
+                                     cbreserved,
+                                     baseaddress,
+                                     bindingsin,
+                                     rows_buf,
+                                     i,
+                                     cols);
+               if (err) {
+                       break;
+               }
+               rowsarray[i] = cols;
+       }
+       return err;
+}
+
+static bool process_query_node(TALLOC_CTX *ctx,
+                       struct wsp_crestriction *crestriction,
+                       t_query *node);
+
+static bool process_andornot_node(TALLOC_CTX *ctx,
+                       struct wsp_crestriction *crestr,
+                       t_query *node,
+                       struct wsp_crestriction **left,
+                       struct wsp_crestriction **right)
+{
+       struct wsp_cnoderestriction *restriction_node = NULL;
+
+       *left = NULL;
+       *right = NULL;
+
+       restriction_node =
+               &crestr->restriction.cnoderestriction;
+
+       crestr->weight = 1000;
+
+       if (node->type == eAND || node->type == eOR) {
+               if (node->type == eAND) {
+                       crestr->ultype = RTAND;
+               } else {
+                       crestr->ultype = RTOR;
+               }
+               if (!create_noderestriction(ctx, restriction_node, 2)) {
+                       return false;
+               }
+               *left = &restriction_node->panode[0];
+               *right = &restriction_node->panode[1];
+       } else {
+               crestr->ultype = RTNOT;
+               crestr->restriction.restriction.restriction =
+                       talloc_zero(ctx, struct wsp_crestriction);
+               if (crestr->restriction.restriction.restriction == NULL) {
+                       DBG_ERR("out of memory\n");
+                       return false;
+               }
+               crestr =
+                       crestr->restriction.restriction.restriction;
+       }
+       if (*left == NULL) {
+               *left = crestr;
+       }
+       if (*right == NULL) {
+               *right = crestr;
+       }
+       return true;
+}
+
+static void process_value_node(TALLOC_CTX *ctx,
+                       struct wsp_crestriction *crestriction,
+                       t_query *node)
+{
+       *crestriction = *node->restriction;
+}
+
+static bool process_query_node(TALLOC_CTX *ctx,
+                       struct wsp_crestriction *crestriction,
+                       t_query *node)
+{
+       struct wsp_crestriction *left = NULL, *right = NULL;
+       if (node == NULL) {
+               return true;
+       }
+       switch (node->type) {
+               case eAND:
+               case eOR:
+               case eNOT:
+                       if (!process_andornot_node(ctx, crestriction, node,
+                                             &left, &right)) {
+                               return false;
+                       }
+                       break;
+               case eVALUE:
+                       process_value_node(ctx, crestriction, node);
+               default:
+                       break;
+       }
+       if (!process_query_node(ctx, left, node->left)) {
+               return false;
+       }
+       if (!process_query_node(ctx, right, node->right)) {
+               return false;
+       }
+       return true;
+}
+
+bool create_querysearch_request(TALLOC_CTX * ctx,
+                               struct wsp_request* request,
+                               t_select_stmt *sql)
+{
+       uint32_t indices[sql->cols->num_cols];
+       uint32_t i;
+       uint32_t j;
+       struct wsp_cpmcreatequeryin *createquery =
+               &request->message.cpmcreatequery;
+
+       for (i = 0; i < sql->cols->num_cols; i++) {
+               indices[i] = i;
+       }
+
+       request->header.msg = CPMCREATEQUERY;
+       createquery->ccolumnsetpresent = 1;
+       createquery->columnset.columnset.count = sql->cols->num_cols;
+       if (!fill_uint32_vec(ctx, &createquery->columnset.columnset.indexes,
+                       indices,
+                       sql->cols->num_cols)) {
+               return false;
+       }
+
+       /* handle restrictions */
+       createquery->crestrictionpresent = 1;
+       createquery->restrictionarray.restrictionarray.count = 1;
+       createquery->restrictionarray.restrictionarray.ispresent = 1;
+
+       if (!create_restriction_array(ctx,
+                &createquery->restrictionarray.restrictionarray.restrictions,
+                createquery->restrictionarray.restrictionarray.count)) {
+               return false;
+       }
+
+
+       if (!process_query_node(ctx,
+               &createquery->restrictionarray.restrictionarray.restrictions[0],
+               sql->where)) {
+               return false;
+       }
+
+
+       /* handle rest */
+       createquery->csortsetpresent = 1;
+       if (createquery->csortsetpresent) {
+               /* sort on first column */
+               struct wsp_csort data[] = {
+                       {0x00000000, 0x00000000, 0x00000000, WSP_DEFAULT_LCID},
+               };
+               struct wsp_csortset *sortset = NULL;
+               struct wsp_cingroupsortaggregsets *aggregsets = NULL;
+
+               aggregsets = &createquery->sortset.groupsortaggregsets;
+               aggregsets->ccount = 1;
+               aggregsets->sortsets =
+                       talloc_zero_array(ctx,
+                                         struct wsp_cingroupsortaggregset,
+                                         aggregsets->ccount);
+               sortset = &aggregsets->sortsets[0].sortaggregset;
+               sortset->count = ARRAY_SIZE(data);
+               if (!fill_sortarray(ctx,
+                               &sortset->sortarray,
+                               data,sortset->count)) {
+                       return false;
+               }
+       }
+
+       createquery->ccategorizationsetpresent = 0;
+
+       createquery->rowsetproperties.ubooleanoptions = 0x00000203;
+       createquery->rowsetproperties.ulmaxopenrows = 0x00000000;
+       createquery->rowsetproperties.ulmemoryusage = 0x00000000;
+       createquery->rowsetproperties.cmaxresults = 0x00000000;
+       createquery->rowsetproperties.ccmdtimeout = 0x00000005;
+
+       createquery->pidmapper.count = sql->cols->num_cols;
+       createquery->pidmapper.apropspec = talloc_zero_array(ctx,
+                                               struct wsp_cfullpropspec,
+                                               createquery->pidmapper.count);
+
+       if (createquery->pidmapper.apropspec == NULL) {
+               DBG_ERR("out of memory\n");
+               return false;
+       }
+
+       for(i = 0, j = 0; i < sql->cols->num_cols; i++) {
+               struct wsp_cfullpropspec *prop =
+                               &createquery->pidmapper.apropspec[j];
+               char *propname = sql->cols->cols[i];
+               /*
+                * don't put RowID in pidmapper or windows will reject
+                * the query.
+                */
+               if (strequal(propname, "System.Search.RowID")) {
+                       continue;
+               }
+               if (!set_fullpropspec(ctx,
+                                     prop, sql->cols->cols[i],
+                                     PRSPEC_PROPID)) {
+                       DBG_ERR("Failed to handle property named %s\n",
+                               sql->cols->cols[i]);
+                       continue;
+               }
+               j++;
+       }
+       createquery->columnset.columnset.count = j;
+       createquery->pidmapper.count = j;
+       createquery->lcid = WSP_DEFAULT_LCID;
+       return true;
+}
+
+static int32_t getNextAddress(int32_t value_off,
+               int32_t status_off,
+               int32_t len_off,
+               int32_t max_value_size)
+{
+       return MAX(MAX(value_off + max_value_size, status_off + 1), len_off + 2);
+}
+
+static void create_binding_offsets(struct binding *binding, int no_cols,
+               int max_value_size)
+{
+       uint32_t buf_addr = 0x0;
+       uint32_t i;
+
+       uint32_t value_off = 0;
+       uint32_t len_off = 0;
+
+       /* initial state this will get incremented to the desired 0x2 */
+       uint32_t status_off = 0x1;
+       uint32_t avail = 0x4;
+       int status_remain = 0x2;
+       int len_remain = -1;
+
+       const static uint32_t WINDOW = 0x8;
+       const static uint32_t LEN_STAT_SIZE = 0x4;
+       for (i = 0; i < no_cols; i++) {
+               buf_addr = buf_addr + WINDOW;
+               value_off = buf_addr;
+
+               if (status_remain <= 0) {
+                       if (avail) {
+                               status_off = avail;
+                               status_remain = LEN_STAT_SIZE;
+                               avail = 0;
+                       } else {
+                               /*
+                                * we prepare the address to allocate
+                                * another block from here. It will
+                                * be allocated automatically when we
+                                * re-enter the loop
+                                */
+                               status_off = getNextAddress(value_off,
+                                               status_off,
+                                               len_off,
+                                               max_value_size) + WINDOW;
+                               status_remain = LEN_STAT_SIZE;
+                               buf_addr = status_off;
+                               avail = buf_addr + LEN_STAT_SIZE;
+                       }
+               } else {
+                       status_off++;
+                       buf_addr = getNextAddress(value_off,
+                                       status_off,
+                                       len_off,
+                                       max_value_size);
+               }
+
+               if (len_remain <= 0) {
+                       if (avail) {
+                               len_off = avail;
+                               len_remain = LEN_STAT_SIZE;
+                               avail = 0;
+                       } else {
+                               /*
+                                * we prepare the address to allocate
+                                * another block from here. It will
+                                * be allocated automatically when we
+                                * re-enter the loop
+                                */
+                               len_off = getNextAddress(value_off,
+                                               status_off,
+                                               len_off,
+                                               max_value_size) + WINDOW;
+                               len_remain = LEN_STAT_SIZE;
+                               buf_addr = len_off;
+                               avail = buf_addr + LEN_STAT_SIZE;
+                       }
+               } else {
+                       len_off += 0x4;
+                       buf_addr = getNextAddress(value_off,
+                                       status_off,
+                                       len_off,
+                                       max_value_size);
+               }
+               status_remain--;
+               len_remain -= LEN_STAT_SIZE;
+               binding[i].value_off = value_off;
+               binding[i].status_off = status_off;
+               binding[i].len_off = len_off;
+       }
+}
+
+static bool fill_bindings(TALLOC_CTX *ctx,
+                  struct wsp_cpmsetbindingsin *bindingsin,
+                  char **col_names,
+                  bool is_64bit)
+{
+       uint32_t i;
+       struct binding *offsets = NULL;
+       uint32_t num_cols;
+       int maxvalue = is_64bit ? 0x18 : 0x10;
+
+       struct wsp_ctablecolumn *tablecols = bindingsin->acolumns;
+       bindingsin->brow = 0x0;
+       num_cols = bindingsin->ccolumns;
+
+       offsets = talloc_zero_array(ctx, struct binding, num_cols);
+
+       if (offsets == NULL) {
+               DBG_ERR("out of memory\n");
+               return false;
+       }
+
+       create_binding_offsets(offsets,
+                       num_cols,
+                       maxvalue);
+
+       for (i = 0; i < num_cols; i++) {
+               uint32_t max_off;
+               if (!set_ctablecolumn(ctx, &tablecols[i], col_names[i],
+                                     &offsets[i], maxvalue)) {
+                       DBG_ERR("Failed to handle property named %s\n",
+                               col_names[i]);
+                       continue;
+               }
+               max_off = MAX(offsets[i].value_off + maxvalue,
+                             offsets[i].status_off + 1);
+               max_off = MAX(max_off, offsets[i].len_off + 2);
+               if (max_off > bindingsin->brow) {
+                       bindingsin->brow = max_off;
+               }
+       }
+       /* important */
+       bindingsin->brow += ndr_align_size(bindingsin->brow,4);
+       return true;
+}
+
+bool create_setbindings_request(TALLOC_CTX * ctx,
+                               struct wsp_request* request,
+                               t_select_stmt *sql,
+                               uint32_t cursor,
+                               bool is_64bit)
+{
+       struct wsp_cpmsetbindingsin *bindingsin =
+               &request->message.cpmsetbindings;
+
+       request->header.msg = CPMSETBINDINGSIN;
+       bindingsin->hcursor = cursor;
+       bindingsin->ccolumns = sql->cols->num_cols;
+
+       bindingsin->acolumns = talloc_zero_array(ctx,
+                       struct wsp_ctablecolumn,
+                       bindingsin->ccolumns);
+
+       if (bindingsin->acolumns == NULL) {
+               DBG_ERR("out of memory\n");
+               return false;
+       }
+
+       if (!fill_bindings(ctx, bindingsin, sql->cols->cols, is_64bit)) {
+               return false;
+       }
+
+       return true;
+}
+
+enum search_kind get_kind(const char* kind_str)
+{
+       enum search_kind result = UNKNOWN;
+       int i;
+       const static struct {
+               const char* str;
+               enum search_kind search_kind;
+       } kind_map[] = {
+               {"Calendar", CALENDAR},
+               {"Communication", COMMUNICATION},
+               {"Contact", CONTACT},
+               {"Document", DOCUMENT},
+               {"Email", EMAIL},
+               {"Feed", FEED},
+               {"Folder", FOLDER},
+               {"Game", GAME},
+               {"InstantMessage", INSTANTMESSAGE},
+               {"Journal", JOURNAL},
+               {"Link", LINK},
+               {"Movie", MOVIE},
+               {"Music", MUSIC},
+               {"Note", NOTE},
+               {"Picture", PICTURE},
+               {"Program", PROGRAM},
+               {"RecordedTV", RECORDEDTV},
+               {"SearchFolder", SEARCHFOLDER},
+               {"Task", TASK},
+               {"Video", VIDEO},
+               {"WebHistory", WEBHISTORY},
+       };
+       for (i = 0; i < ARRAY_SIZE(kind_map); i++) {
+               if (strequal(kind_str, kind_map[i].str)) {
+                       result = kind_map[i].search_kind;
+                       break;
+               }
+       }
+       return result;
+}
+
+struct wsp_client_ctx
+{
+       struct rpc_pipe_client *rpccli;
+       struct cli_state *cli_state;
+       struct dcerpc_binding_handle *h;
+};
+
+static NTSTATUS wsp_resp_pdu_complete(struct tstream_context *stream,
+                                     void *private_data,
+                                     DATA_BLOB blob,
+                                     size_t *packet_size)
+{
+       ssize_t to_read;
+
+       to_read = tstream_pending_bytes(stream);
+       if (to_read == -1) {
+               return NT_STATUS_IO_DEVICE_ERROR;
+       }
+
+       if (to_read > 0) {
+               *packet_size = blob.length + to_read;
+               return STATUS_MORE_ENTRIES;
+       }
+
+       return NT_STATUS_OK;
+}
+
+NTSTATUS wsp_server_connect(TALLOC_CTX *mem_ctx,
+                           const char *servername,
+                           struct tevent_context *ev_ctx,
+                           struct loadparm_context *lp_ctx,
+                           struct cli_credentials *credentials,
+                           struct cli_state *cli,
+                           struct wsp_client_ctx **wsp_ctx)
+{
+       struct wsp_client_ctx *ctx = NULL;
+       struct dcerpc_binding_handle *h = NULL;
+       struct tstream_context *stream = NULL;
+       NTSTATUS status;
+
+       bool smb2_or_greater =
+               (lpcfg_client_max_protocol(lp_ctx) >= PROTOCOL_SMB2_02);
+
+       if (!smb2_or_greater) {
+               return NT_STATUS_PROTOCOL_NOT_SUPPORTED;
+       }
+
+       ctx = talloc_zero(mem_ctx, struct wsp_client_ctx);
+       if (ctx == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ctx->cli_state = cli;
+
+
+       status = smb2cli_ioctl_pipe_wait(
+                       cli->conn,
+                       cli->timeout,
+                       cli->smb2.session,
+                       cli->smb2.tcon,
+                       "MsFteWds",
+                       1);
+
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_ERR("wait for pipe failed: %s)\n",
+                       nt_errstr(status));
+               return status;
+       }
+
+       status = rpc_pipe_open_np(cli,
+                       &ndr_table_msftewds,
+                       &ctx->rpccli);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_ERR("failed to int the pipe)\n");
+               return status;
+       }
+
+       stream = rpc_transport_get_tstream(ctx->rpccli->transport);
+       h = tstream_binding_handle_create(ctx->rpccli,
+                                         NULL,
+                                         &stream,
+                                         MSG_HDR_SIZE,
+                                         wsp_resp_pdu_complete,
+                                         ctx, 42280);
+
+       if (!h) {
+               DBG_ERR("failed to create the pipe handle)\n");
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       ctx->rpccli->binding_handle = h;
+       *wsp_ctx = ctx;
+
+       return status;
+}
+
+static NTSTATUS write_something(TALLOC_CTX* ctx,
+                               struct rpc_pipe_client *p,
+                               DATA_BLOB *blob_in,
+                               DATA_BLOB *blob_out)
+{
+       uint32_t outflags;
+       struct dcerpc_binding_handle *handle = p->binding_handle;
+       NTSTATUS status;
+
+       status = dcerpc_binding_handle_raw_call(handle,
+                                               NULL,
+                                               0,
+                                               0,
+                                               blob_in->data,
+                                               blob_in->length,
+                                               ctx,
+                                               &blob_out->data,
+                                               &blob_out->length,
+                                               &outflags);
+       return status;
+}
+
+/* msg is expected to be created on the heap with talloc */
+static enum ndr_err_code parse_blob(TALLOC_CTX *ctx, DATA_BLOB *blob,
+               struct wsp_request *request,
+               struct wsp_response *response,
+               DATA_BLOB *unread)
+{
+       struct ndr_pull *ndr = NULL;
+       enum ndr_err_code err;
+       int ndr_flags = NDR_SCALARS | NDR_BUFFERS;
+       uint32_t status = 0;
+
+       ndr = ndr_pull_init_blob(blob, ctx);
+
+       if (ndr == NULL) {
+               return NDR_ERR_ALLOC;
+       }
+
+       /* peek at the status */
+       status = PULL_LE_I32(blob->data, 4);
+
+       /* is hard error ?*/
+       if (status & 0x80000000 && blob->length == MSG_HDR_SIZE) {
+               /* just pull the header */
+               err = ndr_pull_wsp_header(ndr, ndr_flags, &response->header);
+               DBG_ERR("error: %s\n", nt_errstr(NT_STATUS(status)));
+               goto out;
+       }
+       err = ndr_pull_wsp_response(ndr, ndr_flags, response);
+       if (err) {
+               DBG_ERR("Failed to pull header from response blob error %d\n",  err);
+               goto out;
+       }
+       if (DEBUGLEVEL >=6) {
+               NDR_PRINT_DEBUG(wsp_response, response);
+       }
+       if (response->header.msg == CPMGETROWS) {
+               if (request) {
+                       /* point to rows buffer */
+                       struct wsp_cpmgetrowsin *getrows =
+                               &request->message.cpmgetrows;
+                       ndr->offset = getrows->cbreserved;
+               }
+       }
+
+       if (ndr->offset < blob->length) {
+               int bytes = blob->length - ndr->offset;
+               *unread = data_blob_named(blob->data + ndr->offset,
+                                         bytes, "UNREAD");
+               DBG_WARNING("\nThere are unprocessed bytes (len 0x%x) "
+                           "at end of message\n", bytes);
+       }
+
+out:
+       return err;
+}
+
+static void set_msg_checksum(DATA_BLOB *blob, struct wsp_header *hdr)
+{
+       /* point at payload */
+       uint32_t i;
+       uint8_t *buffer = blob->data + MSG_HDR_SIZE;
+       uint32_t buf_size = blob->length - MSG_HDR_SIZE;
+       uint32_t nwords = buf_size/4;
+       uint32_t offset = 0;
+       uint32_t checksum = 0;
+
+       static const uint32_t xor_const = 0x59533959;
+       for(i = 0; i < nwords; i++) {
+               checksum += PULL_LE_I32(buffer, offset);
+               offset += 4;
+       }
+
+       checksum ^= xor_const;
+       checksum -= hdr->msg;
+       hdr->checksum = checksum;
+}
+
+static enum ndr_err_code insert_header_and_checksum(TALLOC_CTX *ctx,
+               DATA_BLOB* blob,
+               struct wsp_header *header)
+{
+       enum ndr_err_code err;
+       int ndr_flags = NDR_SCALARS | NDR_BUFFERS;
+       struct ndr_push *header_ndr = ndr_push_init_ctx(ctx);
+
+       if (header_ndr == NULL) {
+               return NDR_ERR_ALLOC;
+       }
+
+       if (header->msg == CPMCONNECT
+       || header->msg == CPMCREATEQUERY
+       || header->msg == CPMSETBINDINGSIN
+       || header->msg == CPMGETROWS
+       || header->msg == CPMFETCHVALUE) {
+
+               set_msg_checksum(blob, header);
+       }
+       err = ndr_push_wsp_header(header_ndr, ndr_flags, header);
+       if (err) {
+               DBG_ERR("Failed to push header, error %d\n", err);
+               return err;
+       }
+       memcpy(blob->data, header_ndr->data, MSG_HDR_SIZE);
+       return err;
+}
+
+NTSTATUS wsp_request_response(TALLOC_CTX* ctx,
+                             struct wsp_client_ctx *wsp_ctx,
+                             struct wsp_request* request,
+                             struct wsp_response *response,
+                             DATA_BLOB *unread)
+{
+       struct rpc_pipe_client *p = wsp_ctx->rpccli;
+       NTSTATUS status = NT_STATUS_OK;
+
+       int ndr_flags = NDR_SCALARS | NDR_BUFFERS;
+       struct ndr_push* push_ndr = NULL;
+
+       enum ndr_err_code err;
+
+       DATA_BLOB req_blob;
+       DATA_BLOB resp_blob;
+
+       ZERO_STRUCT(req_blob);
+       ZERO_STRUCT(resp_blob);
+
+       push_ndr = ndr_push_init_ctx(ctx);
+       if (push_ndr == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       /* write message payload first */
+       push_ndr->offset = MSG_HDR_SIZE;
+       DBG_INFO("\n");
+
+       switch(request->header.msg) {
+               case CPMCONNECT:
+               {
+                       struct wsp_cpmconnectin *connectin =
+                               &request->message.cpmconnect;
+                       err =  ndr_push_wsp_cpmconnectin(push_ndr, ndr_flags,
+                                               connectin);
+                       break;
+                }
+               case CPMCREATEQUERY:
+               {
+                       struct wsp_cpmcreatequeryin* createquery =
+                               &request->message.cpmcreatequery;
+                       err = ndr_push_wsp_cpmcreatequeryin(push_ndr,
+                                       ndr_flags,
+                                       createquery);
+                       req_blob = ndr_push_blob(push_ndr);
+                       /* we need to set cpmcreatequery.size */
+                       createquery->size =
+                               req_blob.length - MSG_HDR_SIZE;
+                       PUSH_LE_U32(req_blob.data, MSG_HDR_SIZE,
+                             createquery->size);
+
+                       break;
+               }
+               case CPMSETBINDINGSIN:
+               {
+                       struct wsp_cpmsetbindingsin *bindingsin =
+                               &request->message.cpmsetbindings;
+                       err = ndr_push_wsp_cpmsetbindingsin(push_ndr, ndr_flags,
+                                               bindingsin);
+                       req_blob = ndr_push_blob(push_ndr);
+                       /* we need to set cpmsetbindings.bbindingdesc (size) */
+                       bindingsin->bbindingdesc =
+                                       req_blob.length - MSG_HDR_SIZE - 16;
+                       PUSH_LE_U32(req_blob.data, MSG_HDR_SIZE + 8,
+                             bindingsin->bbindingdesc);
+                       break;
+               }
+               case CPMGETROWS:
+               {
+                       struct wsp_cpmgetrowsin *getrows =
+                               &request->message.cpmgetrows;
+                       err = ndr_push_wsp_cpmgetrowsin(push_ndr, ndr_flags,
+                                               getrows);
+                       req_blob = ndr_push_blob(push_ndr);
+                       getrows->cbseek = req_blob.length - MSG_HDR_SIZE - 32;
+                       /* we need to set cpmgetrowsin.cbseek (size) */
+                       PUSH_LE_U32(req_blob.data, MSG_HDR_SIZE + 12,
+                             getrows->cbseek);
+                       PUSH_LE_U32(req_blob.data, MSG_HDR_SIZE + 16,
+                             getrows->cbreserved);
+                       break;
+               }
+               case CPMGETQUERYSTATUS:
+               {
+                       struct wsp_cpmgetquerystatusin *querystatus =
+                               &request->message.cpmgetquerystatus;
+                       err = ndr_push_wsp_cpmgetquerystatusin(
+                                       push_ndr,
+                                       ndr_flags,
+                                       querystatus);
+                       break;
+               }
+               case CPMGETQUERYSTATUSEX:
+               {
+                       struct wsp_cpmgetquerystatusexin *statusexin =
+                               &request->message.cpmgetquerystatusex;
+                       err = ndr_push_wsp_cpmgetquerystatusexin(
+                                       push_ndr,
+                                       ndr_flags,
+                                       statusexin);
+                       break;
+               }
+               case CPMFREECURSOR:
+               {
+                       struct wsp_cpmfreecursorin *freecursor =
+                               &request->message.cpmfreecursor;
+                       err = ndr_push_wsp_cpmfreecursorin(
+                                       push_ndr,
+                                       ndr_flags,
+                                       freecursor);
+                       break;
+               }
+               case CPMFETCHVALUE:
+               {
+                       struct wsp_cpmfetchvaluein *fetchvalue =
+                               &request->message.cpmfetchvalue;
+                       err = ndr_push_wsp_cpmfetchvaluein(
+                                       push_ndr,
+                                       ndr_flags,
+                                       fetchvalue);
+                       break;
+               }
+
+               case CPMGETAPPROXIMATEPOSITION:
+               {
+                       struct wsp_cpmgetapproximatepositionin *position =
+                               &request->message.getapproximateposition;
+                       err = ndr_push_wsp_cpmgetapproximatepositionin(
+                               push_ndr,
+                               ndr_flags,
+                               position);
+                       break;
+               }
+               default:
+                       status = NT_STATUS_MESSAGE_NOT_FOUND;
+                       goto out;
+                       break;
+       }
+       if (err) {
+               DBG_ERR("failed to serialise message! (%d)\n", err);
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
+       }
+       if (!req_blob.data) {
+               req_blob = ndr_push_blob(push_ndr);
+       }
+       err = insert_header_and_checksum(ctx, &req_blob, &request->header);
+
+       DBG_NOTICE("\nsending raw message from client len %d\n", (int)req_blob.length);
+       DBG_NOTICE("\nsending raw message from client\n");
+       DBG_NOTICE(  "===============================\n");
+
+       dump_data(5, req_blob.data, req_blob.length);
+
+       status = write_something(ctx, p, &req_blob, &resp_blob);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_ERR("Failed to write message\n");
+               goto out;
+       }
+       DBG_NOTICE("\nraw response from server\n");
+       DBG_NOTICE(  "========================\n");
+       dump_data(5,  resp_blob.data, resp_blob.length);
+
+       err = parse_blob(ctx,
+                       &resp_blob,
+                       request,
+                       response,
+                       unread);
+       if (err) {
+               DBG_ERR("Failed to parse response error %d\n", err);
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
+       }
+       DBG_NOTICE("response status is 0x%x\n", response->header.status);
+       /* propagate error status to return status */
+       if (response->header.status & 0x80000000) {
+               status = NT_STATUS_UNSUCCESSFUL;
+       }
+out:
+       return status;
+}
+
+struct dcerpc_binding_handle* get_wsp_pipe(struct wsp_client_ctx *ctx)
+{
+       return ctx->rpccli->binding_handle;
+}
diff --git a/source3/rpc_client/wsp_cli.h b/source3/rpc_client/wsp_cli.h
new file mode 100644 (file)
index 0000000..3159bd2
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ *  Unix SMB/CIFS implementation.
+ *
+ *  Window Search Service
+ *
+ *  Copyright (c)  Noel Power
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __LIBCLI_WSP_WSP_CLI
+#define __LIBCLI_WSP_WSP_CLI
+
+#include "libcli/wsp/wsp_aqs.h"
+
+enum search_kind {
+       CALENDAR,
+       COMMUNICATION,
+       CONTACT,
+       DOCUMENT,
+       EMAIL,
+       FEED,
+       FOLDER,
+       GAME,
+       INSTANTMESSAGE,
+       JOURNAL,
+       LINK,
+       MOVIE,
+       MUSIC,
+       NOTE,
+       PICTURE,
+       PROGRAM,
+       RECORDEDTV,
+       SEARCHFOLDER,
+       TASK,
+       VIDEO,
+       WEBHISTORY,
+       NONE,
+       UNKNOWN,
+};
+
+enum search_kind get_kind(const char* kind_str);
+
+struct wsp_cpmcreatequeryin;
+struct wsp_cpmsetbindingsin;
+struct wsp_cpmgetrowsin;
+struct dcerpc_binding_handle;
+
+bool init_connectin_request(TALLOC_CTX *ctx,
+                           struct wsp_request* request,
+                           const char* clientmachine,
+                           const char* clientuser,
+                           const char* server);
+
+bool create_querysearch_request(TALLOC_CTX * ctx,
+                               struct wsp_request* request,
+                               t_select_stmt *sql);
+
+bool create_setbindings_request(TALLOC_CTX * ctx,
+                               struct wsp_request* request,
+                               t_select_stmt *sql,
+                               uint32_t cursor,
+                               bool is_64bit);
+
+void create_seekat_getrows_request(TALLOC_CTX * ctx,
+                                  struct wsp_request* request,
+                                  uint32_t cursor,
+                                  uint32_t bookmark,
+                                  uint32_t skip,
+                                  uint32_t rows,
+                                  uint32_t cbreserved,
+                                  uint32_t ulclientbase,
+                                  uint32_t cbrowwidth,
+                                  uint32_t fbwdfetch);
+
+enum ndr_err_code extract_rowsarray(TALLOC_CTX * ctx,
+                                   DATA_BLOB *rows_buf,
+                                   bool is_64bit,
+                                   struct wsp_cpmsetbindingsin *bindingsin,
+                                   uint32_t cbreserved,
+                                   uint64_t baseaddress,
+                                   uint32_t rows,
+                                   struct wsp_cbasestoragevariant **rowsarray);
+
+struct wsp_client_ctx;
+struct cli_credentials;
+
+NTSTATUS wsp_server_connect(TALLOC_CTX *mem_ctx,
+                           const char *servername,
+                           struct tevent_context *ev_ctx,
+                           struct loadparm_context *lp_ctx,
+                           struct cli_credentials *credential,
+                           struct cli_state *cli,
+                           struct wsp_client_ctx **ctx);
+
+/* simple sync api */
+NTSTATUS wsp_request_response(TALLOC_CTX* ctx,
+                             struct wsp_client_ctx *wsp_ctx,
+                             struct wsp_request* request,
+                             struct wsp_response *response,
+                             DATA_BLOB *unread);
+
+struct dcerpc_binding_handle* get_wsp_pipe(struct wsp_client_ctx *ctx);
+#endif
index 2efcbc629676533a8bd838dd9dee440d1d2812fc..d965da78c4c84afc263f75466511041d192c88ae 100644 (file)
@@ -1080,6 +1080,12 @@ bld.SAMBA3_SUBSYSTEM('RPCCLI_MDSSVC',
                     ''',
                     deps='mdssvc RPC_NDR_MDSSVC')
 
+bld.SAMBA3_SUBSYSTEM('RPCCLI_WSP',
+                    source='''
+                    rpc_client/wsp_cli.c
+                    ''',
+                    deps='tevent-util tstream_binding_handle')
+
 bld.SAMBA3_SUBSYSTEM('INIT_LSA',
                     source='rpc_client/init_lsa.c',
                     deps='samba-util')