summaryrefslogtreecommitdiffstats
path: root/source3/rpc_client/wsp_cli.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
commit8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch)
tree4099e8021376c7d8c05bdf8503093d80e9c7bad0 /source3/rpc_client/wsp_cli.c
parentInitial commit. (diff)
downloadsamba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz
samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source3/rpc_client/wsp_cli.c')
-rw-r--r--source3/rpc_client/wsp_cli.c2221
1 files changed, 2221 insertions, 0 deletions
diff --git a/source3/rpc_client/wsp_cli.c b/source3/rpc_client/wsp_cli.c
new file mode 100644
index 0000000..15b6e36
--- /dev/null
+++ b/source3/rpc_client/wsp_cli.c
@@ -0,0 +1,2221 @@
+/*
+ * 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;
+ ndr_flags_type 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,
+ uint64_t offset,
+ DATA_BLOB *rows_buf, uint32_t len,
+ struct wsp_cbasestoragevariant *val)
+{
+ enum ndr_err_code err;
+ struct ndr_pull *ndr_pull = NULL;
+ ndr_flags_type ndr_flags = NDR_SCALARS | NDR_BUFFERS;
+ DATA_BLOB variant_blob = data_blob_null;
+ if (offset >= rows_buf->length) {
+ DBG_ERR("offset %"PRIu64" 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)
+{
+ uint64_t 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
+ *
+ */
+static enum ndr_err_code extract_variant_addresses(TALLOC_CTX *ctx,
+ struct wsp_ctablevariant *tablevar,
+ bool is_64bit,
+ struct ndr_pull *ndr_pull,
+ ndr_flags_type flags,
+ uint64_t baseaddress,
+ DATA_BLOB *rows_buf,
+ uint64_t *pcount,
+ uint64_t **pvec_address)
+{
+ 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;
+ }
+
+ /* ensure count is at least within buffer range */
+ if (count >= MAX_ROW_BUFF_SIZE || count >= rows_buf->length) {
+ DBG_ERR("count %"PRIu64" either exceeds max buffer size "
+ "or buffer size (%zu)",
+ count, rows_buf->length);
+ err = NDR_ERR_VALIDATE;
+ goto out;
+ }
+
+ /* 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;
+ }
+
+ if ((addr - baseaddress) >= rows_buf->length) {
+ DBG_ERR("offset %"PRIu64" outside buffer range "
+ "(buf len - %zu)\n",
+ addr - baseaddress,
+ 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;
+ }
+
+ /*
+ * non vector case addr points to value
+ * otherwise addr points to list of addresses
+ * for the values in vector
+ */
+ if (is_vector == false) {
+ vec_address[0] = addr;
+ } else {
+ uint64_t array_offset = addr - baseaddress;
+ uint64_t i;
+ uint32_t intsize;
+
+ if (is_64bit) {
+ intsize = 8;
+ } else {
+ intsize = 4;
+ }
+
+ if (array_offset >= MAX_ROW_BUFF_SIZE
+ || array_offset >= rows_buf->length) {
+ DBG_ERR("offset %"PRIu64" either exceeds max buf size "
+ "or buffer size (%zu)",
+ array_offset, rows_buf->length);
+ err = NDR_ERR_VALIDATE;
+ goto out;
+ }
+
+ /* addr points to a list of int32 or int64 addresses */
+ for (i = 0; i < count; i++) {
+ /*
+ * read the addresses of the vector elements
+ * note: we can safely convert the uint64_t
+ * values here to uint32_t values as
+ * we are sure they are within range
+ * due to previous checks above.
+ */
+ if (smb_buffer_oob((uint32_t)rows_buf->length,
+ (uint32_t)array_offset,
+ intsize)) {
+ DBG_ERR("offset %"PRIu64" will be outside "
+ "buffer range (buf len - %zu) after "
+ "reading %s address\n",
+ array_offset,
+ rows_buf->length,
+ is_64bit ? "64 bit" : "32 bit");
+ err = NDR_ERR_VALIDATE;
+ goto out;
+ }
+ if (is_64bit) {
+ vec_address[i] =
+ PULL_LE_I64(rows_buf->data,
+ array_offset);
+ } else {
+ vec_address[i] =
+ (uint32_t)PULL_LE_I32(rows_buf->data,
+ array_offset);
+ }
+ array_offset += intsize;
+ }
+ }
+ 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,
+ ndr_flags_type flags,
+ uint64_t baseaddress,
+ 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,
+ baseaddress,
+ 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 buf_offset;
+ buf_offset = vec_address[i] - baseaddress;
+ if (buf_offset >= rows_buf->length) {
+ DBG_ERR("offset %"PRIu64" outside buffer range "
+ "(buf len - %zu)\n",
+ buf_offset,
+ 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 - buf_offset;
+ }
+ if (!extract_rowbuf_variable_type(ctx,
+ tablevar->vtype & ~VT_VECTOR,
+ buf_offset,
+ 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,
+ ndr_flags_type flags,
+ uint64_t baseaddress,
+ 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,
+ baseaddress,
+ 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,
+ 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;
+ ndr_flags_type ndr_flags = NDR_SCALARS | NDR_BUFFERS;
+ uint64_t nrow_offset = (uint64_t)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) {
+ 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,
+ baseaddress,
+ 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)
+{
+ uint32_t i;
+ enum ndr_err_code err = NDR_ERR_SUCCESS;
+ /*
+ * limit check the size of rows_buf
+ * see MS-WSP 2.2.3.11 which describes the size
+ * of the rows buffer MUST not exceed 0x0004000 bytes.
+ * This limit will ensure we can safely check
+ * limits based on uint32_t offsets
+ */
+
+ if (rows_buf->length > MAX_ROW_BUFF_SIZE) {
+ DBG_ERR("Buffer size 0x%zx exceeds 0x%x max buffer size\n",
+ rows_buf->length, MAX_ROW_BUFF_SIZE);
+ return NDR_ERR_BUFSIZE;
+ }
+
+ for (i = 0; i < rows; i++ ) {
+ struct wsp_cbasestoragevariant *cols =
+ talloc_zero_array(ctx,
+ struct wsp_cbasestoragevariant,
+ bindingsin->ccolumns);
+ uint64_t adjusted_address;
+ if (cols == NULL) {
+ return NDR_ERR_ALLOC;
+ }
+
+ /*
+ * cater for paddingrows (see MS-WSP 2.2.3.12)
+ * Rows buffer starts cbreserved bytes into messages
+ */
+ adjusted_address = baseaddress + cbreserved;
+
+ err = process_columns(ctx,
+ is_64bit,
+ adjusted_address,
+ 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);
+ break;
+ 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;
+ ndr_flags_type 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;
+ ndr_flags_type 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;
+
+ ndr_flags_type 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;
+}