2 * Unix SMB/CIFS implementation.
4 * Window Search Service
6 * Copyright (c) Noel Power
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
24 #include "rpc_client/wsp_cli.h"
25 #include "rpc_client/rpc_client.h"
26 #include "param/param.h"
27 #include "auth/credentials/credentials.h"
29 #include <util/tevent_ntstatus.h>
30 #include "libcli/tstream_binding_handle/tstream_binding_handle.h"
31 #include "lib/tsocket/tsocket.h"
32 #include "librpc/wsp/wsp_util.h"
33 #include "librpc/gen_ndr/ndr_wsp.h"
34 #include "rpc_client/cli_pipe.h"
35 #include "libcli/smb/smbXcli_base.h"
37 #define MSG_HDR_SIZE 16
40 * 32-bit Windows XP operating system, 32-bit Windows Server 2003 operating
41 * system, 32-bit Windows Home Server server software, 32-bit Windows Vista
42 * with Windows Search 4.0, 32-bit Windows Server 2003 with Windows
43 * Search 4.0. All of these versions of Windows are running
47 static const uint32_t CLIENTVERSION = 0x00010700;
50 * DBPROP_CI_SCOPE_FLAGS
51 * containing QUERY_DEEP
52 * QUERY_DEEP (0x1) indicates that files in the scope directory and all
53 * subdirectories are included in the results. If clear, only files in
54 * the scope directory are included in the results.
56 static int32_t scope_flags_vector[] = {0x00000001};
58 * Search everywhere "\\" is the root scope
60 static const char * root_scope_string_vector[] = {"\\"};
62 /* sets sensible defaults */
63 static void init_wsp_prop(struct wsp_cdbprop *prop)
65 *prop = (struct wsp_cdbprop){0};
66 prop->colid.ekind = DBKIND_GUID_PROPID;
70 static bool create_restriction_array(TALLOC_CTX *ctx,
71 struct wsp_crestriction **pelements,
74 struct wsp_crestriction *elements = talloc_zero_array(ctx,
75 struct wsp_crestriction,
77 if (elements == NULL) {
80 *pelements = elements;
85 static bool create_noderestriction(TALLOC_CTX *ctx,
86 struct wsp_cnoderestriction *pnode,
90 pnode->cnode = nnodes;
91 ok = create_restriction_array(ctx, &pnode->panode, nnodes);
95 static bool fill_sortarray(TALLOC_CTX *ctx, struct wsp_csort **dest,
96 struct wsp_csort *src, uint32_t num)
99 struct wsp_csort *psort = talloc_zero_array(ctx, struct wsp_csort,
104 for (i = 0; i < num; i++) {
113 static bool set_fullpropspec(TALLOC_CTX *ctx, struct wsp_cfullpropspec *prop,
114 const char* propname, uint32_t kind)
116 struct GUID guid = {0};
117 const struct full_propset_info *prop_info = NULL;
119 prop_info = get_propset_info_with_guid(propname, &guid);
121 DBG_ERR("Failed to handle property named %s\n",
125 prop->guidpropset = guid;
127 if (kind == PRSPEC_LPWSTR) {
128 prop->name_or_id.propname.vstring = talloc_strdup(ctx,
130 if (prop->name_or_id.propname.vstring == NULL) {
131 DBG_ERR("out of memory");
134 prop->name_or_id.propname.len = strlen(propname);
136 prop->name_or_id.prspec = prop_info->id;
148 static bool set_ctablecolumn(TALLOC_CTX *ctx, struct wsp_ctablecolumn *tablecol,
149 const char* propname, struct binding *offsets,
152 struct wsp_cfullpropspec *prop = &tablecol->propspec;
154 if (!set_fullpropspec(ctx, prop, propname, PRSPEC_PROPID)) {
157 tablecol->vtype =VT_VARIANT ;
158 tablecol->aggregateused = USED;
159 tablecol->valueused = USED;
160 tablecol->valueoffset.value = offsets->value_off;
161 tablecol->valuesize.value = value_size;
162 tablecol->statusused = USED;
163 tablecol->statusoffset.value = offsets->status_off;
164 tablecol->lengthused = USED;
165 tablecol->lengthoffset.value = offsets->len_off;
170 static bool fill_uint32_vec(TALLOC_CTX* ctx,
172 uint32_t* ivector, uint32_t elems)
175 uint32_t *dest = talloc_zero_array(ctx, uint32_t, elems);
180 for ( i = 0; i < elems; i++ ) {
181 dest[ i ] = ivector[ i ];
187 static bool init_propset1(TALLOC_CTX* tmp_ctx,
188 struct wsp_cdbpropset *propertyset)
191 GUID_from_string(DBPROPSET_FSCIFRMWRK_EXT,
192 &propertyset->guidpropertyset);
194 propertyset->cproperties = 4;
195 propertyset->aprops =
196 talloc_zero_array(tmp_ctx, struct wsp_cdbprop,
197 propertyset->cproperties);
198 if (propertyset->aprops == NULL) {
202 /* initialise first 4 props */
203 for( i = 0; i < propertyset->cproperties; i++) {
204 init_wsp_prop(&propertyset->aprops[i]);
208 * see MS-WSP 2.2.1.31.1 & 4.1 Protocol examples, Example 1
209 * and also as seen in various windows network traces
210 * set value prop[0] - 'catalog to search'
213 propertyset->aprops[0].dbpropid = DBPROP_CI_CATALOG_NAME;
214 /* The name of the Catalog to Query */
215 set_variant_lpwstr(tmp_ctx, &propertyset->aprops[0].vvalue,
216 "Windows\\SystemIndex");
218 * set value prop[1] 'Regular Query'
221 propertyset->aprops[1].dbpropid = DBPROP_CI_QUERY_TYPE;
222 set_variant_i4(tmp_ctx, &propertyset->aprops[1].vvalue,
226 * set value prop[2] 'search subfolders'
228 propertyset->aprops[2].dbpropid = DBPROP_CI_SCOPE_FLAGS;
229 set_variant_i4_vector(tmp_ctx, &propertyset->aprops[2].vvalue,
230 scope_flags_vector, ARRAY_SIZE(scope_flags_vector));
233 * set value prop[3] 'root scope'
235 propertyset->aprops[3].dbpropid = DBPROP_CI_INCLUDE_SCOPES;
236 set_variant_lpwstr_vector(tmp_ctx,
237 &propertyset->aprops[3].vvalue,
238 root_scope_string_vector,
239 ARRAY_SIZE(root_scope_string_vector));
243 static bool init_propset2(TALLOC_CTX* tmp_ctx,
244 struct wsp_cdbpropset *propertyset,
249 GUID_from_string(DBPROPSET_CIFRMWRKCORE_EXT,
250 &propertyset->guidpropertyset);
252 propertyset->cproperties = 1;
253 propertyset->aprops =
254 talloc_zero_array(tmp_ctx, struct wsp_cdbprop,
255 propertyset->cproperties);
256 if (propertyset->aprops == NULL) {
260 /* initialise first 1 props */
261 for( i = 0; i < propertyset->cproperties; i++) {
262 init_wsp_prop(&propertyset->aprops[i]);
266 * see MS-WSP 2.2.1.31.1 & 4.1 Protocol examples, Example 1
267 * and also as seen in various windows network traces
268 * set value prop[0] - 'machines to search'
270 propertyset->aprops[0].dbpropid = DBPROP_MACHINE;
271 set_variant_bstr(tmp_ctx, &propertyset->aprops[0].vvalue,
276 static bool init_apropset0(TALLOC_CTX* tmp_ctx,
277 struct wsp_cdbpropset *propertyset)
281 GUID_from_string(DBPROPSET_MSIDXS_ROWSETEXT,
282 &propertyset->guidpropertyset);
284 propertyset->cproperties = 7;
285 propertyset->aprops =
286 talloc_zero_array(tmp_ctx, struct wsp_cdbprop,
287 propertyset->cproperties);
288 if (propertyset->aprops == NULL) {
292 /* initialise props */
293 for( i = 0; i < propertyset->cproperties; i++) {
294 init_wsp_prop(&propertyset->aprops[i]);
298 * see MS-WSP 2.2.1.31.1 & 4.1 Protocol examples, Example 1
300 * MSIDXSPROP_ROWSETQUERYSTATUS - 'ignored'
302 propertyset->aprops[0].dbpropid = MSIDXSPROP_ROWSETQUERYSTATUS;
303 set_variant_i4(tmp_ctx, &propertyset->aprops[0].vvalue, 0x00000000);
307 * MSIDXSPROP_COMMAND_LOCALE_STRING - 'EN'
309 propertyset->aprops[1].dbpropid = MSIDXSPROP_COMMAND_LOCALE_STRING;
310 set_variant_bstr(tmp_ctx, &propertyset->aprops[1].vvalue,
315 * MSIDXSPROP_QUERY_RESTRICTION - 'ignored'
317 propertyset->aprops[2].dbpropid = MSIDXSPROP_QUERY_RESTRICTION;
318 set_variant_bstr(tmp_ctx, &propertyset->aprops[2].vvalue,
323 * MSIDXSPROP_PARSE_TREE - 'ignored'
325 propertyset->aprops[3].dbpropid = MSIDXSPROP_PARSE_TREE;
326 set_variant_bstr(tmp_ctx, &propertyset->aprops[3].vvalue,
331 * MSIDXSPROP_MAX_RANK - 'ignored'
333 propertyset->aprops[4].dbpropid = MSIDXSPROP_MAX_RANK;
334 set_variant_i4(tmp_ctx, &propertyset->aprops[4].vvalue, 0x00000000);
338 * MSIDXSPROP_RESULTS_FOUND - 'ignored'
340 propertyset->aprops[5].dbpropid = MSIDXSPROP_RESULTS_FOUND;
341 set_variant_i4(tmp_ctx, &propertyset->aprops[5].vvalue, 0x00000000);
345 * ? - '' (unknown property id)
347 propertyset->aprops[6].dbpropid = 0x00000008;
348 set_variant_i4(tmp_ctx, &propertyset->aprops[6].vvalue, 0x00000000);
352 static bool init_apropset1(TALLOC_CTX* tmp_ctx,
353 struct wsp_cdbpropset *propertyset)
356 GUID_from_string(DBPROPSET_QUERYEXT,
357 &propertyset->guidpropertyset);
359 propertyset->cproperties = 11;
360 propertyset->aprops =
361 talloc_zero_array(tmp_ctx, struct wsp_cdbprop,
362 propertyset->cproperties);
363 if (propertyset->aprops == NULL) {
367 /* init properties */
368 for( i = 0; i < propertyset->cproperties; i++) {
369 init_wsp_prop(&propertyset->aprops[i]);
373 * see MS-WSP 2.2.1.31.1 & 4.1 Protocol examples, Example 1
375 * DBPROP_USECONTENTINDEX - 'forced use of the full text index
378 propertyset->aprops[0].dbpropid = DBPROP_USECONTENTINDEX;
379 set_variant_vt_bool(tmp_ctx, &propertyset->aprops[0].vvalue, false);
383 * DBPROP_DEFERNONINDEXEDTRIMMING - 'trimming of security
384 * results will not be deferred'
386 propertyset->aprops[1].dbpropid = DBPROP_DEFERNONINDEXEDTRIMMING;
387 set_variant_vt_bool(tmp_ctx, &propertyset->aprops[1].vvalue, false);
391 * DBPROP_USEEXTENDEDDBTYPES - 'extended DB types are not used'
393 propertyset->aprops[2].dbpropid = DBPROP_USEEXTENDEDDBTYPES;
394 set_variant_vt_bool(tmp_ctx, &propertyset->aprops[2].vvalue, false);
398 * DBPROP_IGNORENOISEONLYCLAUSES = 'full text clauses consisting
399 * entirely of noise words will
400 * result in an error being returned'
402 propertyset->aprops[3].dbpropid = DBPROP_IGNORENOISEONLYCLAUSES;
403 set_variant_vt_bool(tmp_ctx, &propertyset->aprops[3].vvalue, false);
407 * DBPROP_GENERICOPTIONS_STRING - 'no generic options set'
409 propertyset->aprops[4].dbpropid = DBPROP_GENERICOPTIONS_STRING;
410 set_variant_bstr(tmp_ctx, &propertyset->aprops[4].vvalue, "");
414 * DBPROP_DEFERCATALOGVERIFICATION - 'catalog verification is not
417 propertyset->aprops[5].dbpropid = DBPROP_DEFERCATALOGVERIFICATION;
418 set_variant_vt_bool(tmp_ctx, &propertyset->aprops[5].vvalue, false);
422 * DBPROP_IGNORESBRI - 'query can use the sort-by-rank index
425 propertyset->aprops[6].dbpropid = DBPROP_IGNORESBRI;
426 set_variant_vt_bool(tmp_ctx, &propertyset->aprops[6].vvalue, false);
430 * DBPROP_GENERATEPARSETREE - 'a parse tree is not generated for
433 propertyset->aprops[7].dbpropid = DBPROP_GENERATEPARSETREE;
434 set_variant_vt_bool(tmp_ctx, &propertyset->aprops[7].vvalue, false);
438 * DBPROP_FREETEXTANYTERM - 'all terms from a FREETEXT clause
439 * appear in every matching document'
441 propertyset->aprops[8].dbpropid = DBPROP_FREETEXTANYTERM;
442 set_variant_vt_bool(tmp_ctx, &propertyset->aprops[8].vvalue, false);
445 * DBPROP_FREETEXTUSESTEMMING - 'stemming is not used when interpreting
448 propertyset->aprops[9].dbpropid = DBPROP_FREETEXTUSESTEMMING;
449 set_variant_vt_bool(tmp_ctx, &propertyset->aprops[9].vvalue, false);
455 propertyset->aprops[10].dbpropid = 0x0000000f; /* ??? */
456 set_variant_vt_bool(tmp_ctx, &propertyset->aprops[10].vvalue, false);
460 static bool init_apropset2(TALLOC_CTX* tmp_ctx,
461 struct wsp_cdbpropset *propertyset,
465 GUID_from_string(DBPROPSET_CIFRMWRKCORE_EXT,
466 &propertyset->guidpropertyset);
468 propertyset->cproperties = 1;
469 propertyset->aprops =
470 talloc_zero_array(tmp_ctx, struct wsp_cdbprop,
471 propertyset->cproperties);
472 if (propertyset->aprops == NULL) {
476 /* init properties */
477 for( i = 0; i < propertyset->cproperties; i++) {
478 init_wsp_prop(&propertyset->aprops[i]);
482 * see MS-WSP 2.2.1.31.1 & 4.1 Protocol examples, Example 1
483 * and also as seen in various windows network traces
485 * DBPROP_MACHINE - 'target server'
487 propertyset->aprops[0].dbpropid = DBPROP_MACHINE;
488 set_variant_bstr(tmp_ctx, &propertyset->aprops[0].vvalue, server);
493 static bool init_apropset3(TALLOC_CTX* tmp_ctx,
494 struct wsp_cdbpropset *propertyset)
498 GUID_from_string(DBPROPSET_FSCIFRMWRK_EXT,
499 &propertyset->guidpropertyset);
501 propertyset->cproperties = 3;
502 propertyset->aprops =
503 talloc_zero_array(tmp_ctx, struct wsp_cdbprop,
504 propertyset->cproperties);
505 if (propertyset->aprops == NULL) {
509 /* init properties */
510 for( i = 0; i < propertyset->cproperties; i++) {
511 init_wsp_prop(&propertyset->aprops[i]);
515 * see MS-WSP 2.2.1.31.1 & 4.1 Protocol examples, Example 1
516 * and also as seen in various windows network traces
518 * DBPROP_CI_INCLUDE_SCOPES - 'search everywhere'
520 propertyset->aprops[0].dbpropid = DBPROP_CI_INCLUDE_SCOPES;
521 set_variant_array_bstr(tmp_ctx, &propertyset->aprops[0].vvalue,
522 root_scope_string_vector,
523 ARRAY_SIZE(root_scope_string_vector));
527 * DBPROP_CI_SCOPE_FLAGS - 'QUERY_DEEP'
529 propertyset->aprops[1].dbpropid = DBPROP_CI_SCOPE_FLAGS;
530 set_variant_array_i4(tmp_ctx, &propertyset->aprops[1].vvalue,
532 ARRAY_SIZE(scope_flags_vector));
536 * DBPROP_CI_CATALOG_NAME - 'index to use' (always the same)
538 propertyset->aprops[2].dbpropid = DBPROP_CI_CATALOG_NAME;
539 set_variant_bstr(tmp_ctx, &propertyset->aprops[2].vvalue,
540 "Windows\\SystemIndex");
544 bool init_connectin_request(TALLOC_CTX *ctx,
545 struct wsp_request* request,
546 const char* clientmachine,
547 const char* clientuser,
550 enum ndr_err_code err;
551 struct connectin_propsets *props = NULL;
552 struct connectin_extpropsets *ext_props = NULL;
553 DATA_BLOB props_blob = data_blob_null;
554 struct ndr_push *ndr_props = NULL;
555 ndr_flags_type ndr_flags = NDR_SCALARS | NDR_BUFFERS;
557 struct wsp_cpmconnectin *connectin =
558 &request->message.cpmconnect;
560 props = talloc_zero(ctx, struct connectin_propsets);
563 DBG_ERR("out of memory\n");
567 ext_props = talloc_zero(ctx, struct connectin_extpropsets) ;
568 if (ext_props == NULL) {
570 DBG_ERR("out of memory\n");
574 request->header.msg = CPMCONNECT;
575 connectin->iclientversion = CLIENTVERSION;
577 * hmm just say the client is remote, if we
578 * are talking to windows it is, if not does
581 connectin->fclientisremote = 0x00000001;
582 connectin->machinename = clientmachine;
583 connectin->username = clientuser;
584 props->cpropsets = 2;
586 /* =================== */
587 /* set up PropertySet1 */
588 /* =================== */
589 if (!init_propset1(ctx, &props->propertyset1)) {
591 DBG_ERR("initialising propset1 failed\n");
595 /* =================== */
596 /* set up PropertySet2 */
597 /* =================== */
598 if (!init_propset2(ctx, &props->propertyset2, server)) {
600 DBG_ERR("initialising propset2 failed\n");
605 ext_props->cextpropset = 4;
606 ext_props->apropertysets = talloc_zero_array(ctx, struct wsp_cdbpropset,
607 ext_props->cextpropset);
609 if (ext_props->apropertysets == NULL) {
611 DBG_ERR("out of memory\n");
615 /* ======================= */
616 /* set up aPropertySets[0] */
617 /* ======================= */
618 if (!init_apropset0(ctx, &ext_props->apropertysets[0])) {
620 DBG_ERR("initialisation of apropset0 failed\n");
624 /* ======================= */
625 /* set up aPropertySets[1] */
626 /* ======================= */
627 if (!init_apropset1(ctx, &ext_props->apropertysets[1])) {
629 DBG_ERR("initialisation of apropset1 failed\n");
633 /* ======================= */
634 /* set up aPropertySets[2] */
635 /* ======================= */
636 if (!init_apropset2(ctx, &ext_props->apropertysets[2], server)) {
638 DBG_ERR("initialisation of apropset2 failed\n");
642 /* ======================= */
643 /* set up aPropertySets[3] */
644 /* ======================= */
645 if (!init_apropset3(ctx, &ext_props->apropertysets[3])) {
647 DBG_ERR("initialisation of apropset3 failed\n");
651 /* we also have to fill the opaque blobs that contain the propsets */
652 ndr_props = ndr_push_init_ctx(ctx);
653 if (ndr_props == NULL) {
655 DBG_ERR("out of memory\n");
659 /* first connectin_propsets */
660 err = ndr_push_connectin_propsets(ndr_props, ndr_flags, props);
662 DBG_ERR("Failed to push propset, error %d\n", err);
666 props_blob = ndr_push_blob(ndr_props);
667 connectin->cbblob1 = props_blob.length;
668 connectin->propsets = talloc_zero_array(ctx, uint8_t,
670 if (connectin->propsets == NULL) {
672 DBG_ERR("out of memory\n");
676 memcpy(connectin->propsets, props_blob.data, props_blob.length);
678 /* then connectin_extpropsets */
679 TALLOC_FREE(ndr_props);
680 ndr_props = ndr_push_init_ctx(ctx);
682 if (ndr_props == NULL) {
684 DBG_ERR("out of memory\n");
688 err = ndr_push_connectin_extpropsets(ndr_props, ndr_flags, ext_props);
691 DBG_ERR("Failed to push extpropset, error %d\n", err);
696 props_blob = ndr_push_blob(ndr_props);
697 connectin->cbblob2 = props_blob.length;
698 connectin->extpropsets = talloc_zero_array(ctx, uint8_t,
701 if (connectin->extpropsets == NULL) {
703 DBG_ERR("out of memory\n");
707 memcpy(connectin->extpropsets, props_blob.data, props_blob.length);
708 TALLOC_FREE(ndr_props);
714 void create_seekat_getrows_request(TALLOC_CTX * ctx,
715 struct wsp_request* request,
721 uint32_t ulclientbase,
725 struct wsp_cpmgetrowsin *getrows =
726 &request->message.cpmgetrows;
728 request->header.msg = CPMGETROWS;
730 getrows->hcursor = cursor;
731 /* max no. rows to receive */
732 getrows->crowstotransfer = rows;
734 * size (length) of row in bytes, determined from value set
735 * by CPMSetBindings message
737 getrows->cbrowWidth = cbrowwidth;
739 * according to we should calculate this (see MS-WSP 3.2.4.2.4)
740 * but it seems window always sets this to the max 16KB limit
741 * (most likely when any row value is variable size e.g. like a
744 getrows->cbreadbuffer = 0x00004000;
746 * base value of buffer pointer
748 getrows->ulclientbase = ulclientbase;
749 getrows->cbreserved = cbreserved;
750 /* fetch rows in forward order */
751 getrows->fbwdfetch = fbwdfetch;
753 getrows->etype = EROWSEEKAT;
754 /* we don't handle chapters */
756 /* CRowsSeekAt (MS-WSP 2.2.1.37) */
757 getrows->seekdescription.crowseekat.bmkoffset = bookmark;
758 getrows->seekdescription.crowseekat.cskip = skip;
759 getrows->seekdescription.crowseekat.hregion = 0;
762 static bool extract_rowbuf_variable_type(TALLOC_CTX *ctx,
765 DATA_BLOB *rows_buf, uint32_t len,
766 struct wsp_cbasestoragevariant *val)
768 enum ndr_err_code err;
769 struct ndr_pull *ndr_pull = NULL;
770 ndr_flags_type ndr_flags = NDR_SCALARS | NDR_BUFFERS;
771 DATA_BLOB variant_blob = data_blob_null;
772 if (offset >= rows_buf->length) {
773 DBG_ERR("offset %d outside buffer range (buf len - %zu)",
778 variant_blob.data = rows_buf->data + offset;
779 variant_blob.length = len;
780 ndr_pull = ndr_pull_init_blob(&variant_blob, ctx);
782 if (ndr_pull == NULL) {
783 DBG_ERR("out of memory\n");
789 const char *string = NULL;
790 ndr_set_flags(&ndr_pull->flags, LIBNDR_FLAG_STR_NULLTERM);
791 err = ndr_pull_string(ndr_pull, ndr_flags, &string);
793 DBG_ERR("error unmarshalling string from %p\n", variant_blob.data );
795 DBG_INFO("\tstring val ->%s<-\n", string );
797 val->vvalue.vt_lpwstr.value = string;
802 DBG_ERR("#FIXME Unhandled variant type %s\n", get_vtype_name(type));
808 static bool convert_variant_array_to_vector(TALLOC_CTX *ctx,
810 struct wsp_cbasestoragevariant **variant_array,
811 struct wsp_cbasestoragevariant *outval)
815 union variant_types vvalue = {0};
816 vtype = variant_array[0]->vtype;
818 if (outval == NULL) {
825 vvalue.vt_bstr_v.vvector_elements = count;
826 vvalue.vt_bstr_v.vvector_data =
827 talloc_zero_array(ctx,
828 struct vt_bstr, count);
829 if (vvalue.vt_bstr_v.vvector_data == NULL) {
834 vvalue.vt_lpwstr_v.vvector_elements = count;
835 vvalue.vt_lpwstr_v.vvector_data =
836 talloc_zero_array(ctx,
837 struct vt_lpwstr, count);
838 if (vvalue.vt_lpwstr_v.vvector_data == NULL) {
842 case VT_COMPRESSED_LPWSTR:
843 vvalue.vt_compresseed_lpwstr_v.vvector_elements
845 vvalue.vt_compresseed_lpwstr_v.vvector_data =
846 talloc_zero_array(ctx,
847 struct vt_compressed_lpwstr,
849 if (vvalue.vt_compresseed_lpwstr_v.vvector_data == NULL) {
854 DBG_ERR("Can't convert array of %s to VECTOR\n",
855 get_vtype_name(vtype));
859 for (i = 0; i < count; i++) {
860 if (variant_array[i]->vtype != vtype) {
861 DBG_ERR("array item type %s doesn't match extpected "
863 get_vtype_name(variant_array[i]->vtype),
864 get_vtype_name(vtype));
867 switch (variant_array[i]->vtype) {
869 vvalue.vt_bstr_v.vvector_data[i]
870 = variant_array[i]->vvalue.vt_bstr;
873 vvalue.vt_lpwstr_v.vvector_data[i]
874 = variant_array[i]->vvalue.vt_lpwstr;
876 case VT_COMPRESSED_LPWSTR:
877 vvalue.vt_compresseed_lpwstr_v.vvector_data[i]
878 = variant_array[i]->vvalue.vt_compressed_lpwstr;
881 DBG_ERR("Can't convert array of %s to VECTOR\n",
882 get_vtype_name(vtype));
886 outval->vtype = vtype | VT_VECTOR;
887 outval->vvalue = vvalue;
892 * get the addresses in rowbuf of variants to read from
893 * pvec_address will point to addresses,
894 * an array of n elements for a vector or array of 1 element
895 * if non-vector item.
897 * addresses stored in pvec_address are adjusted by offset
900 static enum ndr_err_code extract_variant_addresses(TALLOC_CTX *ctx,
901 struct wsp_ctablevariant *tablevar,
903 struct ndr_pull *ndr_pull,
904 ndr_flags_type flags,
908 uint64_t **pvec_address/*,
909 struct wsp_cbasestoragevariant ***variant_array*/)
911 bool is_vector = tablevar->vtype & VT_VECTOR;
914 uint64_t *vec_address = NULL;
915 enum ndr_err_code err;
917 /* read count (only if this is a vector) */
920 err = ndr_pull_udlong(ndr_pull,
924 DBG_ERR("Failed to extract count\n");
929 err = ndr_pull_uint32(ndr_pull,
933 DBG_ERR("Failed to extract count\n");
936 count = (uint64_t)count_32;
944 err = ndr_pull_udlong(ndr_pull,
948 DBG_ERR("Failed to extract address\n");
953 err = ndr_pull_uint32(ndr_pull, flags, &addr_32);
955 DBG_ERR("Failed to extract address\n");
961 addr = addr - offset;
963 if (addr >= rows_buf->length) {
964 DBG_ERR("offset %"PRIu64" outside buffer range "
968 err = NDR_ERR_VALIDATE;
972 vec_address = talloc_zero_array(ctx,
975 if (vec_address == NULL) {
980 if (is_vector == false) {
981 vec_address[0] = addr;
983 uint64_t array_addr = addr;
985 for (i = 0; i < count; i++) {
988 PULL_LE_I64(rows_buf->data,
990 array_addr = array_addr + 8;
993 (uint32_t)PULL_LE_I32(rows_buf->data,
995 array_addr = array_addr + 4;
998 vec_address[i] -= offset;
1001 err = NDR_ERR_SUCCESS;
1003 *pvec_address = vec_address;
1008 static enum ndr_err_code extract_crowvariant_variable(TALLOC_CTX *ctx,
1009 struct wsp_ctablevariant *tablevar,
1011 struct ndr_pull *ndr_pull,
1012 ndr_flags_type flags,
1014 DATA_BLOB *rows_buf,
1016 struct wsp_cbasestoragevariant *val)
1018 enum ndr_err_code err;
1019 bool is_vector = tablevar->vtype & VT_VECTOR;
1022 uint64_t *vec_address = NULL;
1023 struct wsp_cbasestoragevariant **variant_array = NULL;
1027 err = extract_variant_addresses(ctx,
1038 DBG_ERR("Failed to extract address and/or count\n");
1042 variant_array = talloc_zero_array(ctx,
1043 struct wsp_cbasestoragevariant*,
1046 if (variant_array == NULL) {
1047 err = NDR_ERR_ALLOC;
1051 if (is_vector == false) {
1052 variant_array[0] = val;
1054 for (i = 0; i < count; i++) {
1055 variant_array[i] = talloc_zero(ctx,
1056 struct wsp_cbasestoragevariant);
1057 if (variant_array[i] == NULL) {
1058 err = NDR_ERR_ALLOC;
1064 for (i = 0; i < count; i++) {
1065 uint32_t tmplen = len;
1067 addr = vec_address[i];
1068 if (addr >= rows_buf->length) {
1069 DBG_ERR("offset %"PRIu64" outside buffer range "
1070 "(buf len - %zu)\n",
1073 err = NDR_ERR_VALIDATE;
1077 && (tablevar->vtype & ~(VT_VECTOR)) == VT_LPWSTR) {
1079 * we can't trust len if 64 bit mode
1080 * (in 32 bit mode the length reported at len offset
1081 * seem consistent and correct)
1082 * So in this case instead of using the len
1083 * at len offset we just use the full buffer
1084 * from the point the value is stored at
1085 * till the end of the buffer
1087 tmplen = rows_buf->length - addr;
1089 if (!extract_rowbuf_variable_type(ctx,
1090 tablevar->vtype & ~VT_VECTOR,
1094 variant_array[i])) {
1095 err = NDR_ERR_VALIDATE;
1101 if (!convert_variant_array_to_vector(ctx,
1105 err = NDR_ERR_VALIDATE;
1109 err = NDR_ERR_SUCCESS;
1114 static enum ndr_err_code extract_crowvariant(TALLOC_CTX *ctx,
1115 struct wsp_ctablevariant *tablevar,
1117 struct ndr_pull *ndr_pull,
1118 ndr_flags_type flags,
1120 DATA_BLOB *rows_buf, uint32_t len,
1121 struct wsp_cbasestoragevariant *val)
1123 enum ndr_err_code err = NDR_ERR_SUCCESS;
1124 bool is_vector = tablevar->vtype & VT_VECTOR;
1125 bool is_array = tablevar->vtype & VT_ARRAY;
1128 DBG_ERR("Not handling ARRAYs!!!\n");
1129 err = NDR_ERR_VALIDATE;
1133 if (is_variable_size((tablevar->vtype & ~(VT_VECTOR)))) {
1134 err = extract_crowvariant_variable(ctx,
1146 DBG_ERR("Not handling VECTORs of fixed size values!!!\n");
1147 err = NDR_ERR_VALIDATE;
1150 NDR_CHECK(ndr_pull_set_switch_value(ndr_pull,
1153 NDR_CHECK(ndr_pull_variant_types(ndr_pull, NDR_SCALARS, &val->vvalue));
1154 val->vtype = tablevar->vtype;
1160 static enum ndr_err_code process_columns(TALLOC_CTX *ctx,
1162 uint32_t cbreserved,
1163 uint64_t baseaddress,
1164 struct wsp_cpmsetbindingsin *bindingin,
1165 DATA_BLOB *rows_buf,
1167 struct wsp_cbasestoragevariant *cols)
1170 enum ndr_err_code err = NDR_ERR_SUCCESS;
1171 struct ndr_pull *ndr_pull = NULL;
1172 ndr_flags_type ndr_flags = NDR_SCALARS | NDR_BUFFERS;
1173 uint64_t nrow_offset = nrow * bindingin->brow;
1175 if (nrow_offset >= rows_buf->length) {
1176 DBG_ERR("offset %"PRIu64" outside buffer range (buf len - %zu)\n",
1179 err = NDR_ERR_ALLOC;
1184 * process columns, column info is contained in cpmsetbindings
1185 * for more information see 'Rows' description MS-WSP 2.2.4.1.2
1186 * which describes how the server fills the buffer.
1188 for (i = 0; i < bindingin->ccolumns; i++) {
1189 struct wsp_ctablecolumn *tab_col = &bindingin->acolumns[i];
1190 DATA_BLOB col_val_blob = data_blob_null;
1191 uint64_t val_offset;
1192 struct wsp_ctablevariant tablevariant = {0};
1193 DBG_INFO("\nRow[%d]Col[%d] property %s type %s\n",nrow, i,
1194 prop_from_fullprop(ctx, &tab_col->propspec),
1195 get_vtype_name(tab_col->vtype));
1196 if (tab_col->statusused) {
1197 val_offset = nrow_offset + tab_col->statusoffset.value;
1198 if (val_offset >= rows_buf->length) {
1199 DBG_ERR("offset %"PRIu64" outside buffer range "
1200 "(buf len - %zu)\n",
1203 err = NDR_ERR_ALLOC;
1206 DBG_INFO("\n\tstatusoffset 0x%x status is %s\n",
1207 tab_col->statusoffset.value,
1209 (uint8_t)*(rows_buf->data
1212 if (tab_col->lengthused) {
1213 val_offset = nrow_offset + tab_col->lengthoffset.value;
1214 if (val_offset >= rows_buf->length) {
1215 DBG_ERR("offset %"PRIu64" outside buffer range "
1216 "(buf len - %zu)\n",
1219 err = NDR_ERR_ALLOC;
1222 DBG_INFO("\n\tlen offset 0x%x value at length is 0x%x\n",
1223 tab_col->lengthoffset.value,
1224 PULL_LE_I32(rows_buf->data,
1227 if (tab_col->valueused) {
1228 uint64_t offset = baseaddress + cbreserved;
1230 val_offset = nrow_offset + tab_col->valueoffset.value;
1231 if (val_offset >= rows_buf->length) {
1232 DBG_ERR("offset %"PRIu64" outside buffer range "
1233 "(buf len - %zu)\n",
1236 err = NDR_ERR_ALLOC;
1239 DBG_INFO("\n\tvalueoffset:valuesize 0x%x:0x%x "
1240 "crowvariant address = 0x%"PRIx64"\n",
1241 tab_col->valueoffset.value,
1242 tab_col->valuesize.value,
1245 col_val_blob.data = rows_buf->data + val_offset;
1246 col_val_blob.length = tab_col->valuesize.value;
1249 if (tab_col->vtype != VT_VARIANT) {
1250 DBG_ERR("Not handling non variant column "
1252 err = NDR_ERR_VALIDATE;
1255 ndr_pull = ndr_pull_init_blob(&col_val_blob, ctx);
1256 if (ndr_pull == NULL) {
1257 err = NDR_ERR_ALLOC;
1258 DBG_ERR("out of memory\n");
1262 err = ndr_pull_wsp_ctablevariant(ndr_pull,
1266 DBG_ERR("!!! failed to pull fixed part of variant data for col data\n");
1270 DBG_INFO("\tcrowvariant contains %s \n",
1271 get_vtype_name(tablevariant.vtype));
1273 if (tab_col->lengthused) {
1275 * it seems the size is what's at
1276 * lengthoffset - tab_col->valuesize.value
1278 len = PULL_LE_I32(rows_buf->data,
1280 + tab_col->lengthoffset.value);
1281 len = len - tab_col->valuesize.value;
1283 err = extract_crowvariant(ctx,
1299 * extracts values from rows_buf into rowsarray
1300 * based on the information in bindingsin
1302 enum ndr_err_code extract_rowsarray(
1304 DATA_BLOB *rows_buf,
1306 struct wsp_cpmsetbindingsin *bindingsin,
1307 uint32_t cbreserved,
1308 uint64_t baseaddress,
1310 struct wsp_cbasestoragevariant **rowsarray)
1313 enum ndr_err_code err = NDR_ERR_SUCCESS;
1315 for (i = 0; i < rows; i++ ) {
1316 struct wsp_cbasestoragevariant *cols =
1317 talloc_zero_array(ctx,
1318 struct wsp_cbasestoragevariant,
1319 bindingsin->ccolumns);
1321 return NDR_ERR_ALLOC;
1323 err = process_columns(ctx,
1334 rowsarray[i] = cols;
1339 static bool process_query_node(TALLOC_CTX *ctx,
1340 struct wsp_crestriction *crestriction,
1343 static bool process_andornot_node(TALLOC_CTX *ctx,
1344 struct wsp_crestriction *crestr,
1346 struct wsp_crestriction **left,
1347 struct wsp_crestriction **right)
1349 struct wsp_cnoderestriction *restriction_node = NULL;
1355 &crestr->restriction.cnoderestriction;
1357 crestr->weight = 1000;
1359 if (node->type == eAND || node->type == eOR) {
1360 if (node->type == eAND) {
1361 crestr->ultype = RTAND;
1363 crestr->ultype = RTOR;
1365 if (!create_noderestriction(ctx, restriction_node, 2)) {
1368 *left = &restriction_node->panode[0];
1369 *right = &restriction_node->panode[1];
1371 crestr->ultype = RTNOT;
1372 crestr->restriction.restriction.restriction =
1373 talloc_zero(ctx, struct wsp_crestriction);
1374 if (crestr->restriction.restriction.restriction == NULL) {
1375 DBG_ERR("out of memory\n");
1379 crestr->restriction.restriction.restriction;
1381 if (*left == NULL) {
1384 if (*right == NULL) {
1390 static void process_value_node(TALLOC_CTX *ctx,
1391 struct wsp_crestriction *crestriction,
1394 *crestriction = *node->restriction;
1397 static bool process_query_node(TALLOC_CTX *ctx,
1398 struct wsp_crestriction *crestriction,
1401 struct wsp_crestriction *left = NULL, *right = NULL;
1405 switch (node->type) {
1409 if (!process_andornot_node(ctx, crestriction, node,
1415 process_value_node(ctx, crestriction, node);
1419 if (!process_query_node(ctx, left, node->left)) {
1422 if (!process_query_node(ctx, right, node->right)) {
1428 bool create_querysearch_request(TALLOC_CTX * ctx,
1429 struct wsp_request* request,
1432 uint32_t indices[sql->cols->num_cols];
1435 struct wsp_cpmcreatequeryin *createquery =
1436 &request->message.cpmcreatequery;
1438 for (i = 0; i < sql->cols->num_cols; i++) {
1442 request->header.msg = CPMCREATEQUERY;
1443 createquery->ccolumnsetpresent = 1;
1444 createquery->columnset.columnset.count = sql->cols->num_cols;
1445 if (!fill_uint32_vec(ctx, &createquery->columnset.columnset.indexes,
1447 sql->cols->num_cols)) {
1451 /* handle restrictions */
1452 createquery->crestrictionpresent = 1;
1453 createquery->restrictionarray.restrictionarray.count = 1;
1454 createquery->restrictionarray.restrictionarray.ispresent = 1;
1456 if (!create_restriction_array(ctx,
1457 &createquery->restrictionarray.restrictionarray.restrictions,
1458 createquery->restrictionarray.restrictionarray.count)) {
1463 if (!process_query_node(ctx,
1464 &createquery->restrictionarray.restrictionarray.restrictions[0],
1471 createquery->csortsetpresent = 1;
1472 if (createquery->csortsetpresent) {
1473 /* sort on first column */
1474 struct wsp_csort data[] = {
1475 {0x00000000, 0x00000000, 0x00000000, WSP_DEFAULT_LCID},
1477 struct wsp_csortset *sortset = NULL;
1478 struct wsp_cingroupsortaggregsets *aggregsets = NULL;
1480 aggregsets = &createquery->sortset.groupsortaggregsets;
1481 aggregsets->ccount = 1;
1482 aggregsets->sortsets =
1483 talloc_zero_array(ctx,
1484 struct wsp_cingroupsortaggregset,
1485 aggregsets->ccount);
1486 sortset = &aggregsets->sortsets[0].sortaggregset;
1487 sortset->count = ARRAY_SIZE(data);
1488 if (!fill_sortarray(ctx,
1489 &sortset->sortarray,
1490 data,sortset->count)) {
1495 createquery->ccategorizationsetpresent = 0;
1497 createquery->rowsetproperties.ubooleanoptions = 0x00000203;
1498 createquery->rowsetproperties.ulmaxopenrows = 0x00000000;
1499 createquery->rowsetproperties.ulmemoryusage = 0x00000000;
1500 createquery->rowsetproperties.cmaxresults = 0x00000000;
1501 createquery->rowsetproperties.ccmdtimeout = 0x00000005;
1503 createquery->pidmapper.count = sql->cols->num_cols;
1504 createquery->pidmapper.apropspec = talloc_zero_array(ctx,
1505 struct wsp_cfullpropspec,
1506 createquery->pidmapper.count);
1508 if (createquery->pidmapper.apropspec == NULL) {
1509 DBG_ERR("out of memory\n");
1513 for(i = 0, j = 0; i < sql->cols->num_cols; i++) {
1514 struct wsp_cfullpropspec *prop =
1515 &createquery->pidmapper.apropspec[j];
1516 char *propname = sql->cols->cols[i];
1518 * don't put RowID in pidmapper or windows will reject
1521 if (strequal(propname, "System.Search.RowID")) {
1524 if (!set_fullpropspec(ctx,
1525 prop, sql->cols->cols[i],
1527 DBG_ERR("Failed to handle property named %s\n",
1528 sql->cols->cols[i]);
1533 createquery->columnset.columnset.count = j;
1534 createquery->pidmapper.count = j;
1535 createquery->lcid = WSP_DEFAULT_LCID;
1539 static int32_t getNextAddress(int32_t value_off,
1542 int32_t max_value_size)
1544 return MAX(MAX(value_off + max_value_size, status_off + 1), len_off + 2);
1547 static void create_binding_offsets(struct binding *binding, int no_cols,
1550 uint32_t buf_addr = 0x0;
1553 uint32_t value_off = 0;
1554 uint32_t len_off = 0;
1556 /* initial state this will get incremented to the desired 0x2 */
1557 uint32_t status_off = 0x1;
1558 uint32_t avail = 0x4;
1559 int status_remain = 0x2;
1560 int len_remain = -1;
1562 const static uint32_t WINDOW = 0x8;
1563 const static uint32_t LEN_STAT_SIZE = 0x4;
1564 for (i = 0; i < no_cols; i++) {
1565 buf_addr = buf_addr + WINDOW;
1566 value_off = buf_addr;
1568 if (status_remain <= 0) {
1571 status_remain = LEN_STAT_SIZE;
1575 * we prepare the address to allocate
1576 * another block from here. It will
1577 * be allocated automatically when we
1580 status_off = getNextAddress(value_off,
1583 max_value_size) + WINDOW;
1584 status_remain = LEN_STAT_SIZE;
1585 buf_addr = status_off;
1586 avail = buf_addr + LEN_STAT_SIZE;
1590 buf_addr = getNextAddress(value_off,
1596 if (len_remain <= 0) {
1599 len_remain = LEN_STAT_SIZE;
1603 * we prepare the address to allocate
1604 * another block from here. It will
1605 * be allocated automatically when we
1608 len_off = getNextAddress(value_off,
1611 max_value_size) + WINDOW;
1612 len_remain = LEN_STAT_SIZE;
1614 avail = buf_addr + LEN_STAT_SIZE;
1618 buf_addr = getNextAddress(value_off,
1624 len_remain -= LEN_STAT_SIZE;
1625 binding[i].value_off = value_off;
1626 binding[i].status_off = status_off;
1627 binding[i].len_off = len_off;
1631 static bool fill_bindings(TALLOC_CTX *ctx,
1632 struct wsp_cpmsetbindingsin *bindingsin,
1637 struct binding *offsets = NULL;
1639 int maxvalue = is_64bit ? 0x18 : 0x10;
1641 struct wsp_ctablecolumn *tablecols = bindingsin->acolumns;
1642 bindingsin->brow = 0x0;
1643 num_cols = bindingsin->ccolumns;
1645 offsets = talloc_zero_array(ctx, struct binding, num_cols);
1647 if (offsets == NULL) {
1648 DBG_ERR("out of memory\n");
1652 create_binding_offsets(offsets,
1656 for (i = 0; i < num_cols; i++) {
1658 if (!set_ctablecolumn(ctx, &tablecols[i], col_names[i],
1659 &offsets[i], maxvalue)) {
1660 DBG_ERR("Failed to handle property named %s\n",
1664 max_off = MAX(offsets[i].value_off + maxvalue,
1665 offsets[i].status_off + 1);
1666 max_off = MAX(max_off, offsets[i].len_off + 2);
1667 if (max_off > bindingsin->brow) {
1668 bindingsin->brow = max_off;
1672 bindingsin->brow += ndr_align_size(bindingsin->brow,4);
1676 bool create_setbindings_request(TALLOC_CTX * ctx,
1677 struct wsp_request* request,
1682 struct wsp_cpmsetbindingsin *bindingsin =
1683 &request->message.cpmsetbindings;
1685 request->header.msg = CPMSETBINDINGSIN;
1686 bindingsin->hcursor = cursor;
1687 bindingsin->ccolumns = sql->cols->num_cols;
1689 bindingsin->acolumns = talloc_zero_array(ctx,
1690 struct wsp_ctablecolumn,
1691 bindingsin->ccolumns);
1693 if (bindingsin->acolumns == NULL) {
1694 DBG_ERR("out of memory\n");
1698 if (!fill_bindings(ctx, bindingsin, sql->cols->cols, is_64bit)) {
1705 enum search_kind get_kind(const char* kind_str)
1707 enum search_kind result = UNKNOWN;
1709 const static struct {
1711 enum search_kind search_kind;
1713 {"Calendar", CALENDAR},
1714 {"Communication", COMMUNICATION},
1715 {"Contact", CONTACT},
1716 {"Document", DOCUMENT},
1721 {"InstantMessage", INSTANTMESSAGE},
1722 {"Journal", JOURNAL},
1727 {"Picture", PICTURE},
1728 {"Program", PROGRAM},
1729 {"RecordedTV", RECORDEDTV},
1730 {"SearchFolder", SEARCHFOLDER},
1733 {"WebHistory", WEBHISTORY},
1735 for (i = 0; i < ARRAY_SIZE(kind_map); i++) {
1736 if (strequal(kind_str, kind_map[i].str)) {
1737 result = kind_map[i].search_kind;
1744 struct wsp_client_ctx
1746 struct rpc_pipe_client *rpccli;
1747 struct cli_state *cli_state;
1748 struct dcerpc_binding_handle *h;
1751 static NTSTATUS wsp_resp_pdu_complete(struct tstream_context *stream,
1754 size_t *packet_size)
1758 to_read = tstream_pending_bytes(stream);
1759 if (to_read == -1) {
1760 return NT_STATUS_IO_DEVICE_ERROR;
1764 *packet_size = blob.length + to_read;
1765 return STATUS_MORE_ENTRIES;
1768 return NT_STATUS_OK;
1771 NTSTATUS wsp_server_connect(TALLOC_CTX *mem_ctx,
1772 const char *servername,
1773 struct tevent_context *ev_ctx,
1774 struct loadparm_context *lp_ctx,
1775 struct cli_credentials *credentials,
1776 struct cli_state *cli,
1777 struct wsp_client_ctx **wsp_ctx)
1779 struct wsp_client_ctx *ctx = NULL;
1780 struct dcerpc_binding_handle *h = NULL;
1781 struct tstream_context *stream = NULL;
1784 bool smb2_or_greater =
1785 (lpcfg_client_max_protocol(lp_ctx) >= PROTOCOL_SMB2_02);
1787 if (!smb2_or_greater) {
1788 return NT_STATUS_PROTOCOL_NOT_SUPPORTED;
1791 ctx = talloc_zero(mem_ctx, struct wsp_client_ctx);
1793 return NT_STATUS_NO_MEMORY;
1796 ctx->cli_state = cli;
1799 status = smb2cli_ioctl_pipe_wait(
1808 if (!NT_STATUS_IS_OK(status)) {
1809 DBG_ERR("wait for pipe failed: %s)\n",
1814 status = rpc_pipe_open_np(cli,
1815 &ndr_table_msftewds,
1818 if (!NT_STATUS_IS_OK(status)) {
1819 DBG_ERR("failed to int the pipe)\n");
1823 stream = rpc_transport_get_tstream(ctx->rpccli->transport);
1824 h = tstream_binding_handle_create(ctx->rpccli,
1828 wsp_resp_pdu_complete,
1832 DBG_ERR("failed to create the pipe handle)\n");
1833 return NT_STATUS_UNSUCCESSFUL;
1836 ctx->rpccli->binding_handle = h;
1842 static NTSTATUS write_something(TALLOC_CTX* ctx,
1843 struct rpc_pipe_client *p,
1845 DATA_BLOB *blob_out)
1848 struct dcerpc_binding_handle *handle = p->binding_handle;
1851 status = dcerpc_binding_handle_raw_call(handle,
1864 /* msg is expected to be created on the heap with talloc */
1865 static enum ndr_err_code parse_blob(TALLOC_CTX *ctx, DATA_BLOB *blob,
1866 struct wsp_request *request,
1867 struct wsp_response *response,
1870 struct ndr_pull *ndr = NULL;
1871 enum ndr_err_code err;
1872 ndr_flags_type ndr_flags = NDR_SCALARS | NDR_BUFFERS;
1873 uint32_t status = 0;
1875 ndr = ndr_pull_init_blob(blob, ctx);
1878 return NDR_ERR_ALLOC;
1881 /* peek at the status */
1882 status = PULL_LE_I32(blob->data, 4);
1884 /* is hard error ?*/
1885 if (status & 0x80000000 && blob->length == MSG_HDR_SIZE) {
1886 /* just pull the header */
1887 err = ndr_pull_wsp_header(ndr, ndr_flags, &response->header);
1888 DBG_ERR("error: %s\n", nt_errstr(NT_STATUS(status)));
1891 err = ndr_pull_wsp_response(ndr, ndr_flags, response);
1893 DBG_ERR("Failed to pull header from response blob error %d\n", err);
1896 if (DEBUGLEVEL >=6) {
1897 NDR_PRINT_DEBUG(wsp_response, response);
1899 if (response->header.msg == CPMGETROWS) {
1901 /* point to rows buffer */
1902 struct wsp_cpmgetrowsin *getrows =
1903 &request->message.cpmgetrows;
1904 ndr->offset = getrows->cbreserved;
1908 if (ndr->offset < blob->length) {
1909 int bytes = blob->length - ndr->offset;
1910 *unread = data_blob_named(blob->data + ndr->offset,
1912 DBG_WARNING("\nThere are unprocessed bytes (len 0x%x) "
1913 "at end of message\n", bytes);
1920 static void set_msg_checksum(DATA_BLOB *blob, struct wsp_header *hdr)
1922 /* point at payload */
1924 uint8_t *buffer = blob->data + MSG_HDR_SIZE;
1925 uint32_t buf_size = blob->length - MSG_HDR_SIZE;
1926 uint32_t nwords = buf_size/4;
1927 uint32_t offset = 0;
1928 uint32_t checksum = 0;
1930 static const uint32_t xor_const = 0x59533959;
1931 for(i = 0; i < nwords; i++) {
1932 checksum += PULL_LE_I32(buffer, offset);
1936 checksum ^= xor_const;
1937 checksum -= hdr->msg;
1938 hdr->checksum = checksum;
1941 static enum ndr_err_code insert_header_and_checksum(TALLOC_CTX *ctx,
1943 struct wsp_header *header)
1945 enum ndr_err_code err;
1946 ndr_flags_type ndr_flags = NDR_SCALARS | NDR_BUFFERS;
1947 struct ndr_push *header_ndr = ndr_push_init_ctx(ctx);
1949 if (header_ndr == NULL) {
1950 return NDR_ERR_ALLOC;
1953 if (header->msg == CPMCONNECT
1954 || header->msg == CPMCREATEQUERY
1955 || header->msg == CPMSETBINDINGSIN
1956 || header->msg == CPMGETROWS
1957 || header->msg == CPMFETCHVALUE) {
1959 set_msg_checksum(blob, header);
1961 err = ndr_push_wsp_header(header_ndr, ndr_flags, header);
1963 DBG_ERR("Failed to push header, error %d\n", err);
1966 memcpy(blob->data, header_ndr->data, MSG_HDR_SIZE);
1970 NTSTATUS wsp_request_response(TALLOC_CTX* ctx,
1971 struct wsp_client_ctx *wsp_ctx,
1972 struct wsp_request* request,
1973 struct wsp_response *response,
1976 struct rpc_pipe_client *p = wsp_ctx->rpccli;
1977 NTSTATUS status = NT_STATUS_OK;
1979 ndr_flags_type ndr_flags = NDR_SCALARS | NDR_BUFFERS;
1980 struct ndr_push* push_ndr = NULL;
1982 enum ndr_err_code err;
1985 DATA_BLOB resp_blob;
1987 ZERO_STRUCT(req_blob);
1988 ZERO_STRUCT(resp_blob);
1990 push_ndr = ndr_push_init_ctx(ctx);
1991 if (push_ndr == NULL) {
1992 return NT_STATUS_NO_MEMORY;
1995 /* write message payload first */
1996 push_ndr->offset = MSG_HDR_SIZE;
1999 switch(request->header.msg) {
2002 struct wsp_cpmconnectin *connectin =
2003 &request->message.cpmconnect;
2004 err = ndr_push_wsp_cpmconnectin(push_ndr, ndr_flags,
2008 case CPMCREATEQUERY:
2010 struct wsp_cpmcreatequeryin* createquery =
2011 &request->message.cpmcreatequery;
2012 err = ndr_push_wsp_cpmcreatequeryin(push_ndr,
2015 req_blob = ndr_push_blob(push_ndr);
2016 /* we need to set cpmcreatequery.size */
2018 req_blob.length - MSG_HDR_SIZE;
2019 PUSH_LE_U32(req_blob.data, MSG_HDR_SIZE,
2024 case CPMSETBINDINGSIN:
2026 struct wsp_cpmsetbindingsin *bindingsin =
2027 &request->message.cpmsetbindings;
2028 err = ndr_push_wsp_cpmsetbindingsin(push_ndr, ndr_flags,
2030 req_blob = ndr_push_blob(push_ndr);
2031 /* we need to set cpmsetbindings.bbindingdesc (size) */
2032 bindingsin->bbindingdesc =
2033 req_blob.length - MSG_HDR_SIZE - 16;
2034 PUSH_LE_U32(req_blob.data, MSG_HDR_SIZE + 8,
2035 bindingsin->bbindingdesc);
2040 struct wsp_cpmgetrowsin *getrows =
2041 &request->message.cpmgetrows;
2042 err = ndr_push_wsp_cpmgetrowsin(push_ndr, ndr_flags,
2044 req_blob = ndr_push_blob(push_ndr);
2045 getrows->cbseek = req_blob.length - MSG_HDR_SIZE - 32;
2046 /* we need to set cpmgetrowsin.cbseek (size) */
2047 PUSH_LE_U32(req_blob.data, MSG_HDR_SIZE + 12,
2049 PUSH_LE_U32(req_blob.data, MSG_HDR_SIZE + 16,
2050 getrows->cbreserved);
2053 case CPMGETQUERYSTATUS:
2055 struct wsp_cpmgetquerystatusin *querystatus =
2056 &request->message.cpmgetquerystatus;
2057 err = ndr_push_wsp_cpmgetquerystatusin(
2063 case CPMGETQUERYSTATUSEX:
2065 struct wsp_cpmgetquerystatusexin *statusexin =
2066 &request->message.cpmgetquerystatusex;
2067 err = ndr_push_wsp_cpmgetquerystatusexin(
2075 struct wsp_cpmfreecursorin *freecursor =
2076 &request->message.cpmfreecursor;
2077 err = ndr_push_wsp_cpmfreecursorin(
2085 struct wsp_cpmfetchvaluein *fetchvalue =
2086 &request->message.cpmfetchvalue;
2087 err = ndr_push_wsp_cpmfetchvaluein(
2094 case CPMGETAPPROXIMATEPOSITION:
2096 struct wsp_cpmgetapproximatepositionin *position =
2097 &request->message.getapproximateposition;
2098 err = ndr_push_wsp_cpmgetapproximatepositionin(
2105 status = NT_STATUS_MESSAGE_NOT_FOUND;
2110 DBG_ERR("failed to serialise message! (%d)\n", err);
2111 status = NT_STATUS_UNSUCCESSFUL;
2114 if (!req_blob.data) {
2115 req_blob = ndr_push_blob(push_ndr);
2117 err = insert_header_and_checksum(ctx, &req_blob, &request->header);
2119 DBG_NOTICE("\nsending raw message from client len %d\n", (int)req_blob.length);
2120 DBG_NOTICE("\nsending raw message from client\n");
2121 DBG_NOTICE( "===============================\n");
2123 dump_data(5, req_blob.data, req_blob.length);
2125 status = write_something(ctx, p, &req_blob, &resp_blob);
2127 if (!NT_STATUS_IS_OK(status)) {
2128 DBG_ERR("Failed to write message\n");
2131 DBG_NOTICE("\nraw response from server\n");
2132 DBG_NOTICE( "========================\n");
2133 dump_data(5, resp_blob.data, resp_blob.length);
2135 err = parse_blob(ctx,
2141 DBG_ERR("Failed to parse response error %d\n", err);
2142 status = NT_STATUS_UNSUCCESSFUL;
2145 DBG_NOTICE("response status is 0x%x\n", response->header.status);
2146 /* propagate error status to return status */
2147 if (response->header.status & 0x80000000) {
2148 status = NT_STATUS_UNSUCCESSFUL;
2154 struct dcerpc_binding_handle* get_wsp_pipe(struct wsp_client_ctx *ctx)
2156 return ctx->rpccli->binding_handle;