34eb1bc2696a52591ba96e9976130f1f415e1574
[samba.git] / source3 / rpc_client / wsp_cli.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *
4  *  Window Search Service
5  *
6  *  Copyright (c)  Noel Power
7  *
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.
12  *
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.
17  *
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/>.
20  */
21
22 #include "includes.h"
23 #include "client.h"
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"
28 #include <tevent.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"
36
37 #define MSG_HDR_SIZE 16
38 #define USED 1
39 /*
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
44  * Windows Search 4.0.
45 */
46
47 static const uint32_t CLIENTVERSION = 0x00010700;
48
49 /*
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.
55  */
56 static int32_t scope_flags_vector[] = {0x00000001};
57 /*
58  * Search everywhere "\\" is the root scope
59  */
60 static const char * root_scope_string_vector[] = {"\\"};
61
62 /* sets sensible defaults */
63 static void init_wsp_prop(struct wsp_cdbprop *prop)
64 {
65         *prop = (struct wsp_cdbprop){0};
66         prop->colid.ekind = DBKIND_GUID_PROPID;
67 }
68
69
70 static bool create_restriction_array(TALLOC_CTX *ctx,
71                                struct wsp_crestriction **pelements,
72                                uint32_t nnodes)
73 {
74         struct wsp_crestriction *elements = talloc_zero_array(ctx,
75                                                        struct wsp_crestriction,
76                                                        nnodes);
77         if (elements == NULL) {
78                 return false;
79         }
80         *pelements = elements;
81         return true;
82 }
83
84
85 static bool create_noderestriction(TALLOC_CTX *ctx,
86                                struct wsp_cnoderestriction *pnode,
87                                uint32_t nnodes)
88 {
89         bool ok;
90         pnode->cnode = nnodes;
91         ok = create_restriction_array(ctx, &pnode->panode, nnodes);
92         return ok;
93 }
94
95 static bool fill_sortarray(TALLOC_CTX *ctx, struct wsp_csort **dest,
96                            struct wsp_csort *src, uint32_t num)
97 {
98         uint32_t i;
99         struct wsp_csort *psort = talloc_zero_array(ctx, struct wsp_csort,
100                                                     num);
101         if (psort == NULL) {
102                 return false;
103         }
104         for (i = 0; i < num; i++) {
105                 psort[i] = src[i];
106         }
107         *dest = psort;
108         return true;
109 }
110
111
112
113 static bool set_fullpropspec(TALLOC_CTX *ctx, struct wsp_cfullpropspec *prop,
114                              const char* propname, uint32_t kind)
115 {
116         struct GUID guid = {0};
117         const struct full_propset_info *prop_info = NULL;
118
119         prop_info = get_propset_info_with_guid(propname, &guid);
120         if (!prop_info) {
121                 DBG_ERR("Failed to handle property named %s\n",
122                         propname);
123                 return false;
124         }
125         prop->guidpropset = guid;
126         prop->ulkind = kind;
127         if (kind == PRSPEC_LPWSTR) {
128                 prop->name_or_id.propname.vstring = talloc_strdup(ctx,
129                                                                    propname);
130                 if (prop->name_or_id.propname.vstring == NULL) {
131                         DBG_ERR("out of memory");
132                         return false;
133                 }
134                 prop->name_or_id.propname.len = strlen(propname);
135         } else {
136                 prop->name_or_id.prspec = prop_info->id;
137         }
138         return true;
139 }
140
141 struct binding
142 {
143         uint32_t status_off;
144         uint32_t value_off;
145         uint32_t len_off;
146 };
147
148 static bool set_ctablecolumn(TALLOC_CTX *ctx, struct wsp_ctablecolumn *tablecol,
149                 const char* propname, struct binding *offsets,
150                 uint32_t value_size)
151 {
152         struct wsp_cfullpropspec *prop = &tablecol->propspec;
153
154         if (!set_fullpropspec(ctx, prop, propname, PRSPEC_PROPID)) {
155                 return false;
156         }
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;
166         return true;
167 }
168
169
170 static bool fill_uint32_vec(TALLOC_CTX* ctx,
171                             uint32_t **pdest,
172                             uint32_t* ivector, uint32_t elems)
173 {
174         uint32_t i;
175         uint32_t *dest = talloc_zero_array(ctx, uint32_t, elems);
176         if (dest == NULL) {
177                 return false;
178         }
179
180         for ( i = 0; i < elems; i++ ) {
181                 dest[ i ] = ivector[ i ];
182         }
183         *pdest = dest;
184         return true;
185 }
186
187 static bool init_propset1(TALLOC_CTX* tmp_ctx,
188                                         struct wsp_cdbpropset *propertyset)
189 {
190         uint32_t i;
191         GUID_from_string(DBPROPSET_FSCIFRMWRK_EXT,
192                          &propertyset->guidpropertyset);
193
194         propertyset->cproperties = 4;
195         propertyset->aprops =
196                 talloc_zero_array(tmp_ctx, struct wsp_cdbprop,
197                              propertyset->cproperties);
198         if (propertyset->aprops == NULL) {
199                 return false;
200         }
201
202         /* initialise first 4 props */
203         for( i = 0; i < propertyset->cproperties; i++) {
204                 init_wsp_prop(&propertyset->aprops[i]);
205         }
206
207         /*
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'
211          */
212
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");
217         /*
218          * set value prop[1] 'Regular Query'
219          */
220
221         propertyset->aprops[1].dbpropid = DBPROP_CI_QUERY_TYPE;
222         set_variant_i4(tmp_ctx, &propertyset->aprops[1].vvalue,
223                        CINORMAL);
224
225         /*
226          * set value prop[2] 'search subfolders'
227          */
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));
231
232         /*
233          * set value prop[3] 'root scope'
234          */
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));
240         return true;
241 }
242
243 static bool init_propset2(TALLOC_CTX* tmp_ctx,
244                           struct wsp_cdbpropset *propertyset,
245                           const char* server)
246 {
247         uint32_t i;
248
249         GUID_from_string(DBPROPSET_CIFRMWRKCORE_EXT,
250                          &propertyset->guidpropertyset);
251
252         propertyset->cproperties = 1;
253         propertyset->aprops =
254                 talloc_zero_array(tmp_ctx, struct wsp_cdbprop,
255                              propertyset->cproperties);
256         if (propertyset->aprops == NULL) {
257                 return false;
258         }
259
260         /* initialise first 1 props */
261         for( i = 0; i < propertyset->cproperties; i++) {
262                 init_wsp_prop(&propertyset->aprops[i]);
263         }
264
265         /*
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'
269          */
270         propertyset->aprops[0].dbpropid = DBPROP_MACHINE;
271         set_variant_bstr(tmp_ctx, &propertyset->aprops[0].vvalue,
272                         server);
273         return true;
274 }
275
276 static bool init_apropset0(TALLOC_CTX* tmp_ctx,
277                            struct wsp_cdbpropset *propertyset)
278 {
279         uint32_t i;
280
281         GUID_from_string(DBPROPSET_MSIDXS_ROWSETEXT,
282                          &propertyset->guidpropertyset);
283
284         propertyset->cproperties = 7;
285         propertyset->aprops =
286                 talloc_zero_array(tmp_ctx, struct wsp_cdbprop,
287                              propertyset->cproperties);
288         if (propertyset->aprops == NULL) {
289                 return false;
290         }
291
292         /* initialise props */
293         for( i = 0; i < propertyset->cproperties; i++) {
294                 init_wsp_prop(&propertyset->aprops[i]);
295         }
296
297         /*
298          * see MS-WSP 2.2.1.31.1 & 4.1 Protocol examples, Example 1
299          * set value prop[0]
300          * MSIDXSPROP_ROWSETQUERYSTATUS - 'ignored'
301          */
302         propertyset->aprops[0].dbpropid = MSIDXSPROP_ROWSETQUERYSTATUS;
303         set_variant_i4(tmp_ctx,  &propertyset->aprops[0].vvalue, 0x00000000);
304
305         /*
306          * set value prop[1]
307          * MSIDXSPROP_COMMAND_LOCALE_STRING - 'EN'
308          */
309         propertyset->aprops[1].dbpropid = MSIDXSPROP_COMMAND_LOCALE_STRING;
310         set_variant_bstr(tmp_ctx, &propertyset->aprops[1].vvalue,
311                         "en-us");
312
313         /*
314          * set value prop[2]
315          * MSIDXSPROP_QUERY_RESTRICTION - 'ignored'
316          */
317         propertyset->aprops[2].dbpropid = MSIDXSPROP_QUERY_RESTRICTION;
318         set_variant_bstr(tmp_ctx, &propertyset->aprops[2].vvalue,
319                         "");
320
321         /*
322          * set value prop[3]
323          * MSIDXSPROP_PARSE_TREE - 'ignored'
324          */
325         propertyset->aprops[3].dbpropid = MSIDXSPROP_PARSE_TREE;
326         set_variant_bstr(tmp_ctx, &propertyset->aprops[3].vvalue,
327                         "");
328
329         /*
330          * set value prop[4]
331          * MSIDXSPROP_MAX_RANK - 'ignored'
332          */
333         propertyset->aprops[4].dbpropid = MSIDXSPROP_MAX_RANK;
334         set_variant_i4(tmp_ctx,  &propertyset->aprops[4].vvalue, 0x00000000);
335
336         /*
337          * set value prop[5]
338          * MSIDXSPROP_RESULTS_FOUND - 'ignored'
339          */
340         propertyset->aprops[5].dbpropid = MSIDXSPROP_RESULTS_FOUND;
341         set_variant_i4(tmp_ctx,  &propertyset->aprops[5].vvalue, 0x00000000);
342
343         /*
344          * set value prop[6]
345          * ? - '' (unknown property id)
346          */
347         propertyset->aprops[6].dbpropid = 0x00000008;
348         set_variant_i4(tmp_ctx,  &propertyset->aprops[6].vvalue, 0x00000000);
349         return true;
350 }
351
352 static bool init_apropset1(TALLOC_CTX* tmp_ctx,
353                                struct wsp_cdbpropset *propertyset)
354 {
355         uint32_t i;
356         GUID_from_string(DBPROPSET_QUERYEXT,
357                          &propertyset->guidpropertyset);
358
359         propertyset->cproperties = 11;
360         propertyset->aprops =
361                 talloc_zero_array(tmp_ctx, struct wsp_cdbprop,
362                              propertyset->cproperties);
363         if (propertyset->aprops == NULL) {
364                 return false;
365         }
366
367         /* init properties */
368         for( i = 0; i < propertyset->cproperties; i++) {
369                 init_wsp_prop(&propertyset->aprops[i]);
370         }
371
372         /*
373          * see MS-WSP 2.2.1.31.1 & 4.1 Protocol examples, Example 1
374          * set value prop[0]
375          * DBPROP_USECONTENTINDEX - 'forced use of the full text index
376          *                           is false.'
377          */
378         propertyset->aprops[0].dbpropid = DBPROP_USECONTENTINDEX;
379         set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[0].vvalue, false);
380
381         /*
382          * set value prop[1]
383          * DBPROP_DEFERNONINDEXEDTRIMMING - 'trimming of security
384          *                                   results will not be deferred'
385          */
386         propertyset->aprops[1].dbpropid = DBPROP_DEFERNONINDEXEDTRIMMING;
387         set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[1].vvalue, false);
388
389         /*
390          * set value prop[2]
391          * DBPROP_USEEXTENDEDDBTYPES  - 'extended DB types are not used'
392          */
393         propertyset->aprops[2].dbpropid = DBPROP_USEEXTENDEDDBTYPES;
394         set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[2].vvalue, false);
395
396         /*
397          * set value prop[3]
398          * DBPROP_IGNORENOISEONLYCLAUSES = 'full text clauses consisting
399          *                                  entirely of noise words will
400          *                                  result in an error being returned'
401          */
402         propertyset->aprops[3].dbpropid = DBPROP_IGNORENOISEONLYCLAUSES;
403         set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[3].vvalue, false);
404
405         /*
406          * set value prop[4]
407          * DBPROP_GENERICOPTIONS_STRING - 'no generic options set'
408          */
409         propertyset->aprops[4].dbpropid = DBPROP_GENERICOPTIONS_STRING;
410         set_variant_bstr(tmp_ctx,  &propertyset->aprops[4].vvalue, "");
411
412         /*
413          * set value prop[5]
414          * DBPROP_DEFERCATALOGVERIFICATION - 'catalog verification is not
415          *                                    deferred.'
416          */
417         propertyset->aprops[5].dbpropid = DBPROP_DEFERCATALOGVERIFICATION;
418         set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[5].vvalue, false);
419
420         /*
421          * set value prop[6]
422          * DBPROP_IGNORESBRI - 'query can use the sort-by-rank index
423          *                      optimization'
424          */
425         propertyset->aprops[6].dbpropid = DBPROP_IGNORESBRI;
426         set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[6].vvalue, false);
427
428         /*
429          * set value prop[7]
430          * DBPROP_GENERATEPARSETREE - 'a parse tree is not generated for
431          *                             debugging.'
432          */
433         propertyset->aprops[7].dbpropid = DBPROP_GENERATEPARSETREE;
434         set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[7].vvalue, false);
435
436         /*
437          * set value prop[8]
438          * DBPROP_FREETEXTANYTERM - 'all terms from a FREETEXT clause
439          *                           appear in every matching document'
440          */
441         propertyset->aprops[8].dbpropid = DBPROP_FREETEXTANYTERM;
442         set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[8].vvalue, false);
443         /*
444          * set value prop[9]
445          * DBPROP_FREETEXTUSESTEMMING - 'stemming is not used when interpreting
446          *                               a FREETEXT clause'
447          */
448         propertyset->aprops[9].dbpropid = DBPROP_FREETEXTUSESTEMMING;
449         set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[9].vvalue, false);
450
451         /*
452          * set value prop[10]
453          * ? - ''
454          */
455         propertyset->aprops[10].dbpropid = 0x0000000f; /* ??? */
456         set_variant_vt_bool(tmp_ctx,  &propertyset->aprops[10].vvalue, false);
457         return true;
458 }
459
460 static bool init_apropset2(TALLOC_CTX* tmp_ctx,
461                            struct wsp_cdbpropset *propertyset,
462                            const char* server)
463 {
464         uint32_t i;
465         GUID_from_string(DBPROPSET_CIFRMWRKCORE_EXT,
466                          &propertyset->guidpropertyset);
467
468         propertyset->cproperties = 1;
469         propertyset->aprops =
470                 talloc_zero_array(tmp_ctx, struct wsp_cdbprop,
471                              propertyset->cproperties);
472         if (propertyset->aprops == NULL) {
473                 return false;
474         }
475
476         /* init properties */
477         for( i = 0; i < propertyset->cproperties; i++) {
478                 init_wsp_prop(&propertyset->aprops[i]);
479         }
480
481         /*
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
484          * set value prop[0]
485          * DBPROP_MACHINE - 'target server'
486          */
487         propertyset->aprops[0].dbpropid = DBPROP_MACHINE;
488         set_variant_bstr(tmp_ctx,  &propertyset->aprops[0].vvalue, server);
489         return true;
490 }
491
492
493 static bool init_apropset3(TALLOC_CTX* tmp_ctx,
494                            struct wsp_cdbpropset *propertyset)
495 {
496         uint32_t i;
497
498         GUID_from_string(DBPROPSET_FSCIFRMWRK_EXT,
499                          &propertyset->guidpropertyset);
500
501         propertyset->cproperties = 3;
502         propertyset->aprops =
503                 talloc_zero_array(tmp_ctx, struct wsp_cdbprop,
504                              propertyset->cproperties);
505         if (propertyset->aprops == NULL) {
506                 return false;
507         }
508
509         /* init properties */
510         for( i = 0; i < propertyset->cproperties; i++) {
511                 init_wsp_prop(&propertyset->aprops[i]);
512         }
513
514         /*
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
517          * set value prop[0]
518          * DBPROP_CI_INCLUDE_SCOPES - 'search everywhere'
519          */
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));
524
525         /*
526          * set value prop[1]
527          * DBPROP_CI_SCOPE_FLAGS - 'QUERY_DEEP'
528          */
529         propertyset->aprops[1].dbpropid = DBPROP_CI_SCOPE_FLAGS;
530         set_variant_array_i4(tmp_ctx, &propertyset->aprops[1].vvalue,
531                              scope_flags_vector,
532                              ARRAY_SIZE(scope_flags_vector));
533
534         /*
535          * set value prop[2]
536          * DBPROP_CI_CATALOG_NAME - 'index to use' (always the same)
537          */
538         propertyset->aprops[2].dbpropid = DBPROP_CI_CATALOG_NAME;
539         set_variant_bstr(tmp_ctx, &propertyset->aprops[2].vvalue,
540                          "Windows\\SystemIndex");
541         return true;
542 }
543
544 bool init_connectin_request(TALLOC_CTX *ctx,
545                             struct wsp_request* request,
546                             const char* clientmachine,
547                             const char* clientuser,
548                             const char* server)
549 {
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;
556         bool result;
557         struct wsp_cpmconnectin *connectin =
558                 &request->message.cpmconnect;
559
560         props = talloc_zero(ctx, struct connectin_propsets);
561         if (props == NULL) {
562                 result = false;
563                 DBG_ERR("out of memory\n");
564                 goto out;
565         }
566
567         ext_props = talloc_zero(ctx, struct connectin_extpropsets) ;
568         if (ext_props == NULL) {
569                 result = false;
570                 DBG_ERR("out of memory\n");
571                 goto out;
572         }
573
574         request->header.msg = CPMCONNECT;
575         connectin->iclientversion = CLIENTVERSION;
576         /*
577          * hmm just say the client is remote, if we
578          * are talking to windows it is, if not does
579          * it really matter?
580          */
581         connectin->fclientisremote = 0x00000001;
582         connectin->machinename = clientmachine;
583         connectin->username = clientuser;
584         props->cpropsets = 2;
585
586         /* =================== */
587         /* set up PropertySet1 */
588         /* =================== */
589         if (!init_propset1(ctx, &props->propertyset1)) {
590                 result = false;
591                 DBG_ERR("initialising propset1 failed\n");
592                 goto out;
593         }
594
595         /* =================== */
596         /* set up PropertySet2 */
597         /* =================== */
598         if (!init_propset2(ctx, &props->propertyset2, server)) {
599                 result = false;
600                 DBG_ERR("initialising propset2 failed\n");
601                 goto out;
602         }
603
604         /* 4 ExtPropSets */
605         ext_props->cextpropset = 4;
606         ext_props->apropertysets = talloc_zero_array(ctx, struct wsp_cdbpropset,
607                              ext_props->cextpropset);
608
609         if (ext_props->apropertysets == NULL) {
610                 result = false;
611                 DBG_ERR("out of memory\n");
612                 goto out;
613         }
614
615         /* ======================= */
616         /* set up aPropertySets[0] */
617         /* ======================= */
618         if (!init_apropset0(ctx, &ext_props->apropertysets[0])) {
619                 result = false;
620                 DBG_ERR("initialisation of apropset0 failed\n");
621                 goto out;
622         }
623
624         /* ======================= */
625         /* set up aPropertySets[1] */
626         /* ======================= */
627         if (!init_apropset1(ctx, &ext_props->apropertysets[1])) {
628                 result = false;
629                 DBG_ERR("initialisation of apropset1 failed\n");
630                 goto out;
631         }
632
633         /* ======================= */
634         /* set up aPropertySets[2] */
635         /* ======================= */
636         if (!init_apropset2(ctx, &ext_props->apropertysets[2], server)) {
637                 result = false;
638                 DBG_ERR("initialisation of apropset2 failed\n");
639                 goto out;
640         }
641
642         /* ======================= */
643         /* set up aPropertySets[3] */
644         /* ======================= */
645         if (!init_apropset3(ctx, &ext_props->apropertysets[3])) {
646                 result = false;
647                 DBG_ERR("initialisation of apropset3 failed\n");
648                 goto out;
649         }
650
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) {
654                 result = false;
655                 DBG_ERR("out of memory\n");
656                 goto out;
657         }
658
659         /* first connectin_propsets */
660         err = ndr_push_connectin_propsets(ndr_props, ndr_flags, props);
661         if (err) {
662                 DBG_ERR("Failed to push propset, error %d\n", err);
663                 result = false;
664                 goto out;
665         }
666         props_blob = ndr_push_blob(ndr_props);
667         connectin->cbblob1 = props_blob.length;
668         connectin->propsets = talloc_zero_array(ctx, uint8_t,
669                                    connectin->cbblob1);
670         if (connectin->propsets == NULL) {
671                 result = false;
672                 DBG_ERR("out of memory\n");
673                 goto out;
674         }
675
676         memcpy(connectin->propsets, props_blob.data, props_blob.length);
677
678         /* then connectin_extpropsets */
679         TALLOC_FREE(ndr_props);
680         ndr_props = ndr_push_init_ctx(ctx);
681
682         if (ndr_props == NULL) {
683                 result = false;
684                 DBG_ERR("out of memory\n");
685                 goto out;
686         }
687
688         err = ndr_push_connectin_extpropsets(ndr_props, ndr_flags, ext_props);
689
690         if (err) {
691                 DBG_ERR("Failed to push extpropset, error %d\n", err);
692                 result = false;
693                 goto out;
694         }
695
696         props_blob = ndr_push_blob(ndr_props);
697         connectin->cbblob2 = props_blob.length;
698         connectin->extpropsets = talloc_zero_array(ctx, uint8_t,
699                                                    connectin->cbblob2);
700
701         if (connectin->extpropsets == NULL) {
702                 result = false;
703                 DBG_ERR("out of memory\n");
704                 goto out;
705         }
706
707         memcpy(connectin->extpropsets, props_blob.data, props_blob.length);
708         TALLOC_FREE(ndr_props);
709         result = true;
710 out:
711         return result;
712 }
713
714 void create_seekat_getrows_request(TALLOC_CTX * ctx,
715                                    struct wsp_request* request,
716                                    uint32_t cursor,
717                                    uint32_t bookmark,
718                                    uint32_t skip,
719                                    uint32_t rows,
720                                    uint32_t cbreserved,
721                                    uint32_t ulclientbase,
722                                    uint32_t cbrowwidth,
723                                    uint32_t fbwdfetch)
724 {
725         struct wsp_cpmgetrowsin *getrows =
726                 &request->message.cpmgetrows;
727         /* msg type */
728         request->header.msg = CPMGETROWS;
729         /* position */
730         getrows->hcursor = cursor;
731         /* max no. rows to receive */
732         getrows->crowstotransfer = rows;
733         /*
734          * size (length) of row in bytes, determined from value set
735          * by CPMSetBindings message
736          */
737         getrows->cbrowWidth = cbrowwidth;
738         /*
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
742          * string/path)
743          */
744         getrows->cbreadbuffer = 0x00004000;
745         /*
746          * base value of buffer pointer
747          */
748         getrows->ulclientbase = ulclientbase;
749         getrows->cbreserved = cbreserved;
750         /* fetch rows in forward order */
751         getrows->fbwdfetch = fbwdfetch;
752         /* eRowSeekAt */
753         getrows->etype = EROWSEEKAT;
754         /* we don't handle chapters */
755         getrows->chapt = 0;
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;
760 }
761
762 static bool extract_rowbuf_variable_type(TALLOC_CTX *ctx,
763                 uint16_t type,
764                 uint32_t offset,
765                 DATA_BLOB *rows_buf, uint32_t len,
766                 struct wsp_cbasestoragevariant  *val)
767 {
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)",
774                         offset,
775                         rows_buf->length);
776                 return false;
777         }
778         variant_blob.data = rows_buf->data + offset;
779         variant_blob.length = len;
780         ndr_pull = ndr_pull_init_blob(&variant_blob, ctx);
781
782         if (ndr_pull == NULL) {
783                 DBG_ERR("out of memory\n");
784                 return false;
785         }
786
787         switch (type) {
788                 case VT_LPWSTR: {
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);
792                         if (err) {
793                                 DBG_ERR("error unmarshalling string from %p\n", variant_blob.data );
794                         } else {
795                                 DBG_INFO("\tstring val ->%s<-\n", string );
796                                 val->vtype = type;
797                                 val->vvalue.vt_lpwstr.value = string;
798                         }
799                         break;
800                 }
801                 default:
802                         DBG_ERR("#FIXME Unhandled variant type %s\n", get_vtype_name(type));
803                         break;
804         }
805         return true;
806 }
807
808 static bool convert_variant_array_to_vector(TALLOC_CTX *ctx,
809                 uint64_t count,
810                 struct wsp_cbasestoragevariant **variant_array,
811                 struct wsp_cbasestoragevariant *outval)
812 {
813         int i;
814         uint16_t vtype;
815         union variant_types vvalue = {0};
816         vtype = variant_array[0]->vtype;
817
818         if (outval == NULL) {
819                 return false;
820         }
821
822         if (count) {
823                 switch (vtype) {
824                         case VT_BSTR:
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) {
830                                         return false;
831                                 }
832                                 break;
833                         case VT_LPWSTR:
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) {
839                                         return false;
840                                 }
841                                 break;
842                         case VT_COMPRESSED_LPWSTR:
843                                 vvalue.vt_compresseed_lpwstr_v.vvector_elements
844                                         = count;
845                                 vvalue.vt_compresseed_lpwstr_v.vvector_data =
846                                         talloc_zero_array(ctx,
847                                                 struct vt_compressed_lpwstr,
848                                                 count);
849                                 if (vvalue.vt_compresseed_lpwstr_v.vvector_data == NULL) {
850                                         return false;
851                                 }
852                                 break;
853                         default:
854                                 DBG_ERR("Can't convert array of %s to VECTOR\n",
855                                         get_vtype_name(vtype));
856                                 return false;
857                 }
858         }
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 "
862                                 "type %s\n",
863                                 get_vtype_name(variant_array[i]->vtype),
864                                 get_vtype_name(vtype));
865                         return false;
866                 }
867                 switch (variant_array[i]->vtype) {
868                         case VT_BSTR:
869                                 vvalue.vt_bstr_v.vvector_data[i]
870                                         = variant_array[i]->vvalue.vt_bstr;
871                                 break;
872                         case VT_LPWSTR:
873                                 vvalue.vt_lpwstr_v.vvector_data[i]
874                                         = variant_array[i]->vvalue.vt_lpwstr;
875                                 break;
876                         case VT_COMPRESSED_LPWSTR:
877                                 vvalue.vt_compresseed_lpwstr_v.vvector_data[i]
878                                         = variant_array[i]->vvalue.vt_compressed_lpwstr;
879                                 break;
880                         default:
881                                 DBG_ERR("Can't convert array of %s to VECTOR\n",
882                                         get_vtype_name(vtype));
883                                 return false;
884                 }
885         }
886         outval->vtype = vtype | VT_VECTOR;
887         outval->vvalue = vvalue;
888         return true;
889 }
890
891 /*
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.
896  *
897  * addresses stored in pvec_address are adjusted by offset
898  *
899  */
900 static enum ndr_err_code extract_variant_addresses(TALLOC_CTX *ctx,
901                                struct wsp_ctablevariant *tablevar,
902                                bool is_64bit,
903                                struct ndr_pull *ndr_pull,
904                                ndr_flags_type flags,
905                                uint32_t offset,
906                                DATA_BLOB *rows_buf,
907                                uint64_t *pcount,
908                                uint64_t **pvec_address/*,
909                                struct wsp_cbasestoragevariant ***variant_array*/)
910 {
911         bool is_vector = tablevar->vtype & VT_VECTOR;
912         uint64_t count;
913         uint64_t addr;
914         uint64_t *vec_address = NULL;
915         enum ndr_err_code err;
916
917         /* read count (only if this is a vector) */
918         if (is_vector) {
919                 if (is_64bit) {
920                         err = ndr_pull_udlong(ndr_pull,
921                                         flags,
922                                         &count);
923                         if (err) {
924                                 DBG_ERR("Failed to extract count\n");
925                                 goto out;
926                         }
927                 } else {
928                         uint32_t count_32;
929                         err = ndr_pull_uint32(ndr_pull,
930                                         flags,
931                                         &count_32);
932                         if (err) {
933                                 DBG_ERR("Failed to extract count\n");
934                                 goto out;
935                         }
936                         count = (uint64_t)count_32;
937                 }
938         } else {
939                 count = 1;
940         }
941
942         /* read address */
943         if (is_64bit) {
944                 err = ndr_pull_udlong(ndr_pull,
945                                 flags,
946                                 &addr);
947                 if (err) {
948                         DBG_ERR("Failed to extract address\n");
949                         goto out;
950                 }
951         } else {
952                 uint32_t addr_32;
953                 err = ndr_pull_uint32(ndr_pull, flags, &addr_32);
954                 if (err) {
955                         DBG_ERR("Failed to extract address\n");
956                         goto out;
957                 }
958                 addr = addr_32;
959         }
960
961         addr = addr - offset;
962
963         if (addr >= rows_buf->length) {
964                 DBG_ERR("offset %"PRIu64" outside buffer range "
965                         "(buf len - %zu)\n",
966                         addr,
967                         rows_buf->length);
968                 err = NDR_ERR_VALIDATE;
969                 goto out;
970         }
971
972         vec_address = talloc_zero_array(ctx,
973                         uint64_t, count);
974
975         if (vec_address == NULL) {
976                 err = NDR_ERR_ALLOC;
977                 goto out;
978         }
979
980         if (is_vector == false) {
981                 vec_address[0] = addr;
982         } else {
983                 uint64_t array_addr = addr;
984                 uint64_t i;
985                 for (i = 0; i < count; i++) {
986                         if (is_64bit) {
987                                 vec_address[i] =
988                                         PULL_LE_I64(rows_buf->data,
989                                                 array_addr);
990                                 array_addr = array_addr + 8;
991                         } else {
992                                 vec_address[i] =
993                                         (uint32_t)PULL_LE_I32(rows_buf->data,
994                                                         array_addr);
995                                 array_addr = array_addr + 4;
996                         }
997                         /* adjust address */
998                         vec_address[i] -= offset;
999                 }
1000         }
1001         err  = NDR_ERR_SUCCESS;
1002         *pcount = count;
1003         *pvec_address = vec_address;
1004 out:
1005         return err;
1006 }
1007
1008 static enum ndr_err_code extract_crowvariant_variable(TALLOC_CTX *ctx,
1009         struct wsp_ctablevariant *tablevar,
1010         bool is_64bit,
1011         struct ndr_pull *ndr_pull,
1012         ndr_flags_type flags,
1013         uint32_t offset,
1014         DATA_BLOB *rows_buf,
1015         uint32_t len,
1016         struct wsp_cbasestoragevariant *val)
1017 {
1018         enum ndr_err_code err;
1019         bool is_vector = tablevar->vtype & VT_VECTOR;
1020         uint64_t count = 0;
1021
1022         uint64_t *vec_address = NULL;
1023         struct wsp_cbasestoragevariant **variant_array = NULL;
1024         int i;
1025
1026
1027         err = extract_variant_addresses(ctx,
1028                         tablevar,
1029                         is_64bit,
1030                         ndr_pull,
1031                         flags,
1032                         offset,
1033                         rows_buf,
1034                         &count,
1035                         &vec_address);
1036
1037         if (err) {
1038                 DBG_ERR("Failed to extract address and/or count\n");
1039                 goto out;
1040         }
1041
1042         variant_array = talloc_zero_array(ctx,
1043                         struct wsp_cbasestoragevariant*,
1044                         count);
1045
1046         if (variant_array == NULL) {
1047                 err = NDR_ERR_ALLOC;
1048                 goto out;
1049         }
1050
1051         if (is_vector == false) {
1052                 variant_array[0] = val;
1053         } else {
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;
1059                                         goto out;
1060                                 }
1061                 }
1062         }
1063
1064         for (i = 0; i < count; i++) {
1065                 uint32_t tmplen = len;
1066                 uint64_t addr;
1067                 addr = vec_address[i];
1068                 if (addr >= rows_buf->length) {
1069                         DBG_ERR("offset %"PRIu64" outside buffer range "
1070                                 "(buf len - %zu)\n",
1071                                 addr,
1072                                 rows_buf->length);
1073                         err = NDR_ERR_VALIDATE;
1074                         goto out;
1075                 }
1076                 if (is_64bit
1077                     && (tablevar->vtype & ~(VT_VECTOR)) == VT_LPWSTR) {
1078                         /*
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
1086                          */
1087                         tmplen = rows_buf->length - addr;
1088                 }
1089                 if (!extract_rowbuf_variable_type(ctx,
1090                                         tablevar->vtype & ~VT_VECTOR,
1091                                         addr,
1092                                         rows_buf,
1093                                         tmplen,
1094                                         variant_array[i])) {
1095                         err = NDR_ERR_VALIDATE;
1096                         goto out;
1097                 }
1098         }
1099
1100         if (is_vector) {
1101                 if (!convert_variant_array_to_vector(ctx,
1102                                                 count,
1103                                                 variant_array,
1104                                                 val)) {
1105                                 err = NDR_ERR_VALIDATE;
1106                                 goto out;
1107                         }
1108         }
1109         err  = NDR_ERR_SUCCESS;
1110 out:
1111         return err;
1112 }
1113
1114 static enum ndr_err_code extract_crowvariant(TALLOC_CTX *ctx,
1115                                struct wsp_ctablevariant *tablevar,
1116                                bool is_64bit,
1117                                struct ndr_pull *ndr_pull,
1118                                ndr_flags_type flags,
1119                                uint32_t offset,
1120                                DATA_BLOB *rows_buf, uint32_t len,
1121                                struct wsp_cbasestoragevariant *val)
1122 {
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;
1126
1127         if (is_array) {
1128                 DBG_ERR("Not handling ARRAYs!!!\n");
1129                 err = NDR_ERR_VALIDATE;
1130                 goto out;
1131         }
1132
1133         if (is_variable_size((tablevar->vtype & ~(VT_VECTOR)))) {
1134                 err = extract_crowvariant_variable(ctx,
1135                                 tablevar,
1136                                 is_64bit,
1137                                 ndr_pull,
1138                                 flags,
1139                                 offset,
1140                                 rows_buf,
1141                                 len,
1142                                 val);
1143
1144         } else {
1145                 if (is_vector) {
1146                         DBG_ERR("Not handling VECTORs of fixed size values!!!\n");
1147                         err = NDR_ERR_VALIDATE;
1148                         goto out;
1149                 }
1150                 NDR_CHECK(ndr_pull_set_switch_value(ndr_pull,
1151                                         &val->vvalue,
1152                                         tablevar->vtype));
1153                 NDR_CHECK(ndr_pull_variant_types(ndr_pull, NDR_SCALARS, &val->vvalue));
1154                 val->vtype = tablevar->vtype;
1155         }
1156 out:
1157         return err;
1158 }
1159
1160 static enum ndr_err_code process_columns(TALLOC_CTX *ctx,
1161                                          bool is_64bit,
1162                                          uint32_t cbreserved,
1163                                          uint64_t baseaddress,
1164                                          struct wsp_cpmsetbindingsin *bindingin,
1165                                          DATA_BLOB *rows_buf,
1166                                          uint32_t nrow,
1167                                          struct wsp_cbasestoragevariant *cols)
1168 {
1169         uint32_t i;
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;
1174
1175         if (nrow_offset >= rows_buf->length) {
1176                 DBG_ERR("offset %"PRIu64" outside buffer range (buf len - %zu)\n",
1177                         nrow_offset,
1178                         rows_buf->length);
1179                 err = NDR_ERR_ALLOC;
1180                 goto out;
1181         }
1182
1183         /*
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.
1187          */
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",
1201                                         val_offset,
1202                                         rows_buf->length);
1203                                 err = NDR_ERR_ALLOC;
1204                                 goto out;
1205                         }
1206                         DBG_INFO("\n\tstatusoffset 0x%x status is %s\n",
1207                               tab_col->statusoffset.value,
1208                               get_store_status(
1209                                       (uint8_t)*(rows_buf->data
1210                                         + val_offset)));
1211                 }
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",
1217                                         val_offset,
1218                                         rows_buf->length);
1219                                 err = NDR_ERR_ALLOC;
1220                                 goto out;
1221                         }
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,
1225                                         val_offset));
1226                 }
1227                 if (tab_col->valueused) {
1228                         uint64_t offset = baseaddress + cbreserved;
1229                         uint32_t len = 0;
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",
1234                                         val_offset,
1235                                         rows_buf->length);
1236                                 err = NDR_ERR_ALLOC;
1237                                 goto out;
1238                         }
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,
1243                                 val_offset);
1244
1245                         col_val_blob.data = rows_buf->data + val_offset;
1246                         col_val_blob.length = tab_col->valuesize.value;
1247
1248
1249                         if (tab_col->vtype != VT_VARIANT) {
1250                                 DBG_ERR("Not handling non variant column "
1251                                         "values\n");
1252                                 err = NDR_ERR_VALIDATE;
1253                                 goto out;
1254                         }
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");
1259                                 goto out;
1260                         }
1261
1262                         err = ndr_pull_wsp_ctablevariant(ndr_pull,
1263                                 ndr_flags,
1264                                 &tablevariant);
1265                         if (err) {
1266                                 DBG_ERR("!!! failed to pull fixed part of variant data for col data\n");
1267                                 goto out;
1268                         }
1269                         DBG_INFO("\n");
1270                         DBG_INFO("\tcrowvariant contains %s \n",
1271                                 get_vtype_name(tablevariant.vtype));
1272
1273                         if (tab_col->lengthused) {
1274                                 /*
1275                                  * it seems the size is what's at
1276                                  * lengthoffset - tab_col->valuesize.value
1277                                  */
1278                                 len = PULL_LE_I32(rows_buf->data,
1279                                         nrow_offset
1280                                         + tab_col->lengthoffset.value);
1281                                 len = len - tab_col->valuesize.value;
1282                         }
1283                         err = extract_crowvariant(ctx,
1284                                         &tablevariant,
1285                                         is_64bit,
1286                                         ndr_pull,
1287                                         ndr_flags,
1288                                         offset,
1289                                         rows_buf,
1290                                         len,
1291                                         &cols[i]);
1292                 }
1293         }
1294 out:
1295         return err;
1296 }
1297
1298 /*
1299  * extracts values from rows_buf into rowsarray
1300  * based on the information in bindingsin
1301  */
1302 enum ndr_err_code extract_rowsarray(
1303                         TALLOC_CTX * ctx,
1304                         DATA_BLOB *rows_buf,
1305                         bool is_64bit,
1306                         struct wsp_cpmsetbindingsin *bindingsin,
1307                         uint32_t cbreserved,
1308                         uint64_t baseaddress,
1309                         uint32_t rows,
1310                         struct wsp_cbasestoragevariant **rowsarray)
1311 {
1312         int i;
1313         enum ndr_err_code err  = NDR_ERR_SUCCESS;
1314
1315         for (i = 0; i < rows; i++ ) {
1316                 struct wsp_cbasestoragevariant *cols =
1317                                 talloc_zero_array(ctx,
1318                                           struct wsp_cbasestoragevariant,
1319                                           bindingsin->ccolumns);
1320                 if (cols == NULL) {
1321                         return NDR_ERR_ALLOC;
1322                 }
1323                 err = process_columns(ctx,
1324                                       is_64bit,
1325                                       cbreserved,
1326                                       baseaddress,
1327                                       bindingsin,
1328                                       rows_buf,
1329                                       i,
1330                                       cols);
1331                 if (err) {
1332                         break;
1333                 }
1334                 rowsarray[i] = cols;
1335         }
1336         return err;
1337 }
1338
1339 static bool process_query_node(TALLOC_CTX *ctx,
1340                         struct wsp_crestriction *crestriction,
1341                         t_query *node);
1342
1343 static bool process_andornot_node(TALLOC_CTX *ctx,
1344                         struct wsp_crestriction *crestr,
1345                         t_query *node,
1346                         struct wsp_crestriction **left,
1347                         struct wsp_crestriction **right)
1348 {
1349         struct wsp_cnoderestriction *restriction_node = NULL;
1350
1351         *left = NULL;
1352         *right = NULL;
1353
1354         restriction_node =
1355                 &crestr->restriction.cnoderestriction;
1356
1357         crestr->weight = 1000;
1358
1359         if (node->type == eAND || node->type == eOR) {
1360                 if (node->type == eAND) {
1361                         crestr->ultype = RTAND;
1362                 } else {
1363                         crestr->ultype = RTOR;
1364                 }
1365                 if (!create_noderestriction(ctx, restriction_node, 2)) {
1366                         return false;
1367                 }
1368                 *left = &restriction_node->panode[0];
1369                 *right = &restriction_node->panode[1];
1370         } else {
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");
1376                         return false;
1377                 }
1378                 crestr =
1379                         crestr->restriction.restriction.restriction;
1380         }
1381         if (*left == NULL) {
1382                 *left = crestr;
1383         }
1384         if (*right == NULL) {
1385                 *right = crestr;
1386         }
1387         return true;
1388 }
1389
1390 static void process_value_node(TALLOC_CTX *ctx,
1391                         struct wsp_crestriction *crestriction,
1392                         t_query *node)
1393 {
1394         *crestriction = *node->restriction;
1395 }
1396
1397 static bool process_query_node(TALLOC_CTX *ctx,
1398                         struct wsp_crestriction *crestriction,
1399                         t_query *node)
1400 {
1401         struct wsp_crestriction *left = NULL, *right = NULL;
1402         if (node == NULL) {
1403                 return true;
1404         }
1405         switch (node->type) {
1406                 case eAND:
1407                 case eOR:
1408                 case eNOT:
1409                         if (!process_andornot_node(ctx, crestriction, node,
1410                                               &left, &right)) {
1411                                 return false;
1412                         }
1413                         break;
1414                 case eVALUE:
1415                         process_value_node(ctx, crestriction, node);
1416                 default:
1417                         break;
1418         }
1419         if (!process_query_node(ctx, left, node->left)) {
1420                 return false;
1421         }
1422         if (!process_query_node(ctx, right, node->right)) {
1423                 return false;
1424         }
1425         return true;
1426 }
1427
1428 bool create_querysearch_request(TALLOC_CTX * ctx,
1429                                 struct wsp_request* request,
1430                                 t_select_stmt *sql)
1431 {
1432         uint32_t indices[sql->cols->num_cols];
1433         uint32_t i;
1434         uint32_t j;
1435         struct wsp_cpmcreatequeryin *createquery =
1436                 &request->message.cpmcreatequery;
1437
1438         for (i = 0; i < sql->cols->num_cols; i++) {
1439                 indices[i] = i;
1440         }
1441
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,
1446                         indices,
1447                         sql->cols->num_cols)) {
1448                 return false;
1449         }
1450
1451         /* handle restrictions */
1452         createquery->crestrictionpresent = 1;
1453         createquery->restrictionarray.restrictionarray.count = 1;
1454         createquery->restrictionarray.restrictionarray.ispresent = 1;
1455
1456         if (!create_restriction_array(ctx,
1457                  &createquery->restrictionarray.restrictionarray.restrictions,
1458                  createquery->restrictionarray.restrictionarray.count)) {
1459                 return false;
1460         }
1461
1462
1463         if (!process_query_node(ctx,
1464                 &createquery->restrictionarray.restrictionarray.restrictions[0],
1465                 sql->where)) {
1466                 return false;
1467         }
1468
1469
1470         /* handle rest */
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},
1476                 };
1477                 struct wsp_csortset *sortset = NULL;
1478                 struct wsp_cingroupsortaggregsets *aggregsets = NULL;
1479
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)) {
1491                         return false;
1492                 }
1493         }
1494
1495         createquery->ccategorizationsetpresent = 0;
1496
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;
1502
1503         createquery->pidmapper.count = sql->cols->num_cols;
1504         createquery->pidmapper.apropspec = talloc_zero_array(ctx,
1505                                                 struct wsp_cfullpropspec,
1506                                                 createquery->pidmapper.count);
1507
1508         if (createquery->pidmapper.apropspec == NULL) {
1509                 DBG_ERR("out of memory\n");
1510                 return false;
1511         }
1512
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];
1517                 /*
1518                  * don't put RowID in pidmapper or windows will reject
1519                  * the query.
1520                  */
1521                 if (strequal(propname, "System.Search.RowID")) {
1522                         continue;
1523                 }
1524                 if (!set_fullpropspec(ctx,
1525                                       prop, sql->cols->cols[i],
1526                                       PRSPEC_PROPID)) {
1527                         DBG_ERR("Failed to handle property named %s\n",
1528                                 sql->cols->cols[i]);
1529                         continue;
1530                 }
1531                 j++;
1532         }
1533         createquery->columnset.columnset.count = j;
1534         createquery->pidmapper.count = j;
1535         createquery->lcid = WSP_DEFAULT_LCID;
1536         return true;
1537 }
1538
1539 static int32_t getNextAddress(int32_t value_off,
1540                 int32_t status_off,
1541                 int32_t len_off,
1542                 int32_t max_value_size)
1543 {
1544         return MAX(MAX(value_off + max_value_size, status_off + 1), len_off + 2);
1545 }
1546
1547 static void create_binding_offsets(struct binding *binding, int no_cols,
1548                 int max_value_size)
1549 {
1550         uint32_t buf_addr = 0x0;
1551         uint32_t i;
1552
1553         uint32_t value_off = 0;
1554         uint32_t len_off = 0;
1555
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;
1561
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;
1567
1568                 if (status_remain <= 0) {
1569                         if (avail) {
1570                                 status_off = avail;
1571                                 status_remain = LEN_STAT_SIZE;
1572                                 avail = 0;
1573                         } else {
1574                                 /*
1575                                  * we prepare the address to allocate
1576                                  * another block from here. It will
1577                                  * be allocated automatically when we
1578                                  * re-enter the loop
1579                                  */
1580                                 status_off = getNextAddress(value_off,
1581                                                 status_off,
1582                                                 len_off,
1583                                                 max_value_size) + WINDOW;
1584                                 status_remain = LEN_STAT_SIZE;
1585                                 buf_addr = status_off;
1586                                 avail = buf_addr + LEN_STAT_SIZE;
1587                         }
1588                 } else {
1589                         status_off++;
1590                         buf_addr = getNextAddress(value_off,
1591                                         status_off,
1592                                         len_off,
1593                                         max_value_size);
1594                 }
1595
1596                 if (len_remain <= 0) {
1597                         if (avail) {
1598                                 len_off = avail;
1599                                 len_remain = LEN_STAT_SIZE;
1600                                 avail = 0;
1601                         } else {
1602                                 /*
1603                                  * we prepare the address to allocate
1604                                  * another block from here. It will
1605                                  * be allocated automatically when we
1606                                  * re-enter the loop
1607                                  */
1608                                 len_off = getNextAddress(value_off,
1609                                                 status_off,
1610                                                 len_off,
1611                                                 max_value_size) + WINDOW;
1612                                 len_remain = LEN_STAT_SIZE;
1613                                 buf_addr = len_off;
1614                                 avail = buf_addr + LEN_STAT_SIZE;
1615                         }
1616                 } else {
1617                         len_off += 0x4;
1618                         buf_addr = getNextAddress(value_off,
1619                                         status_off,
1620                                         len_off,
1621                                         max_value_size);
1622                 }
1623                 status_remain--;
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;
1628         }
1629 }
1630
1631 static bool fill_bindings(TALLOC_CTX *ctx,
1632                    struct wsp_cpmsetbindingsin *bindingsin,
1633                    char **col_names,
1634                    bool is_64bit)
1635 {
1636         uint32_t i;
1637         struct binding *offsets = NULL;
1638         uint32_t num_cols;
1639         int maxvalue = is_64bit ? 0x18 : 0x10;
1640
1641         struct wsp_ctablecolumn *tablecols = bindingsin->acolumns;
1642         bindingsin->brow = 0x0;
1643         num_cols = bindingsin->ccolumns;
1644
1645         offsets = talloc_zero_array(ctx, struct binding, num_cols);
1646
1647         if (offsets == NULL) {
1648                 DBG_ERR("out of memory\n");
1649                 return false;
1650         }
1651
1652         create_binding_offsets(offsets,
1653                         num_cols,
1654                         maxvalue);
1655
1656         for (i = 0; i < num_cols; i++) {
1657                 uint32_t max_off;
1658                 if (!set_ctablecolumn(ctx, &tablecols[i], col_names[i],
1659                                       &offsets[i], maxvalue)) {
1660                         DBG_ERR("Failed to handle property named %s\n",
1661                                 col_names[i]);
1662                         continue;
1663                 }
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;
1669                 }
1670         }
1671         /* important */
1672         bindingsin->brow += ndr_align_size(bindingsin->brow,4);
1673         return true;
1674 }
1675
1676 bool create_setbindings_request(TALLOC_CTX * ctx,
1677                                 struct wsp_request* request,
1678                                 t_select_stmt *sql,
1679                                 uint32_t cursor,
1680                                 bool is_64bit)
1681 {
1682         struct wsp_cpmsetbindingsin *bindingsin =
1683                 &request->message.cpmsetbindings;
1684
1685         request->header.msg = CPMSETBINDINGSIN;
1686         bindingsin->hcursor = cursor;
1687         bindingsin->ccolumns = sql->cols->num_cols;
1688
1689         bindingsin->acolumns = talloc_zero_array(ctx,
1690                         struct wsp_ctablecolumn,
1691                         bindingsin->ccolumns);
1692
1693         if (bindingsin->acolumns == NULL) {
1694                 DBG_ERR("out of memory\n");
1695                 return false;
1696         }
1697
1698         if (!fill_bindings(ctx, bindingsin, sql->cols->cols, is_64bit)) {
1699                 return false;
1700         }
1701
1702         return true;
1703 }
1704
1705 enum search_kind get_kind(const char* kind_str)
1706 {
1707         enum search_kind result = UNKNOWN;
1708         int i;
1709         const static struct {
1710                 const char* str;
1711                 enum search_kind search_kind;
1712         } kind_map[] = {
1713                 {"Calendar", CALENDAR},
1714                 {"Communication", COMMUNICATION},
1715                 {"Contact", CONTACT},
1716                 {"Document", DOCUMENT},
1717                 {"Email", EMAIL},
1718                 {"Feed", FEED},
1719                 {"Folder", FOLDER},
1720                 {"Game", GAME},
1721                 {"InstantMessage", INSTANTMESSAGE},
1722                 {"Journal", JOURNAL},
1723                 {"Link", LINK},
1724                 {"Movie", MOVIE},
1725                 {"Music", MUSIC},
1726                 {"Note", NOTE},
1727                 {"Picture", PICTURE},
1728                 {"Program", PROGRAM},
1729                 {"RecordedTV", RECORDEDTV},
1730                 {"SearchFolder", SEARCHFOLDER},
1731                 {"Task", TASK},
1732                 {"Video", VIDEO},
1733                 {"WebHistory", WEBHISTORY},
1734         };
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;
1738                         break;
1739                 }
1740         }
1741         return result;
1742 }
1743
1744 struct wsp_client_ctx
1745 {
1746         struct rpc_pipe_client *rpccli;
1747         struct cli_state *cli_state;
1748         struct dcerpc_binding_handle *h;
1749 };
1750
1751 static NTSTATUS wsp_resp_pdu_complete(struct tstream_context *stream,
1752                                       void *private_data,
1753                                       DATA_BLOB blob,
1754                                       size_t *packet_size)
1755 {
1756         ssize_t to_read;
1757
1758         to_read = tstream_pending_bytes(stream);
1759         if (to_read == -1) {
1760                 return NT_STATUS_IO_DEVICE_ERROR;
1761         }
1762
1763         if (to_read > 0) {
1764                 *packet_size = blob.length + to_read;
1765                 return STATUS_MORE_ENTRIES;
1766         }
1767
1768         return NT_STATUS_OK;
1769 }
1770
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)
1778 {
1779         struct wsp_client_ctx *ctx = NULL;
1780         struct dcerpc_binding_handle *h = NULL;
1781         struct tstream_context *stream = NULL;
1782         NTSTATUS status;
1783
1784         bool smb2_or_greater =
1785                 (lpcfg_client_max_protocol(lp_ctx) >= PROTOCOL_SMB2_02);
1786
1787         if (!smb2_or_greater) {
1788                 return NT_STATUS_PROTOCOL_NOT_SUPPORTED;
1789         }
1790
1791         ctx = talloc_zero(mem_ctx, struct wsp_client_ctx);
1792         if (ctx == NULL) {
1793                 return NT_STATUS_NO_MEMORY;
1794         }
1795
1796         ctx->cli_state = cli;
1797
1798
1799         status = smb2cli_ioctl_pipe_wait(
1800                         cli->conn,
1801                         cli->timeout,
1802                         cli->smb2.session,
1803                         cli->smb2.tcon,
1804                         "MsFteWds",
1805                         1);
1806
1807
1808         if (!NT_STATUS_IS_OK(status)) {
1809                 DBG_ERR("wait for pipe failed: %s)\n",
1810                         nt_errstr(status));
1811                 return status;
1812         }
1813
1814         status = rpc_pipe_open_np(cli,
1815                         &ndr_table_msftewds,
1816                         &ctx->rpccli);
1817
1818         if (!NT_STATUS_IS_OK(status)) {
1819                 DBG_ERR("failed to int the pipe)\n");
1820                 return status;
1821         }
1822
1823         stream = rpc_transport_get_tstream(ctx->rpccli->transport);
1824         h = tstream_binding_handle_create(ctx->rpccli,
1825                                           NULL,
1826                                           &stream,
1827                                           MSG_HDR_SIZE,
1828                                           wsp_resp_pdu_complete,
1829                                           ctx, 42280);
1830
1831         if (!h) {
1832                 DBG_ERR("failed to create the pipe handle)\n");
1833                 return NT_STATUS_UNSUCCESSFUL;
1834         }
1835
1836         ctx->rpccli->binding_handle = h;
1837         *wsp_ctx = ctx;
1838
1839         return status;
1840 }
1841
1842 static NTSTATUS write_something(TALLOC_CTX* ctx,
1843                                 struct rpc_pipe_client *p,
1844                                 DATA_BLOB *blob_in,
1845                                 DATA_BLOB *blob_out)
1846 {
1847         uint32_t outflags;
1848         struct dcerpc_binding_handle *handle = p->binding_handle;
1849         NTSTATUS status;
1850
1851         status = dcerpc_binding_handle_raw_call(handle,
1852                                                 NULL,
1853                                                 0,
1854                                                 0,
1855                                                 blob_in->data,
1856                                                 blob_in->length,
1857                                                 ctx,
1858                                                 &blob_out->data,
1859                                                 &blob_out->length,
1860                                                 &outflags);
1861         return status;
1862 }
1863
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,
1868                 DATA_BLOB *unread)
1869 {
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;
1874
1875         ndr = ndr_pull_init_blob(blob, ctx);
1876
1877         if (ndr == NULL) {
1878                 return NDR_ERR_ALLOC;
1879         }
1880
1881         /* peek at the status */
1882         status = PULL_LE_I32(blob->data, 4);
1883
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)));
1889                 goto out;
1890         }
1891         err = ndr_pull_wsp_response(ndr, ndr_flags, response);
1892         if (err) {
1893                 DBG_ERR("Failed to pull header from response blob error %d\n",  err);
1894                 goto out;
1895         }
1896         if (DEBUGLEVEL >=6) {
1897                 NDR_PRINT_DEBUG(wsp_response, response);
1898         }
1899         if (response->header.msg == CPMGETROWS) {
1900                 if (request) {
1901                         /* point to rows buffer */
1902                         struct wsp_cpmgetrowsin *getrows =
1903                                 &request->message.cpmgetrows;
1904                         ndr->offset = getrows->cbreserved;
1905                 }
1906         }
1907
1908         if (ndr->offset < blob->length) {
1909                 int bytes = blob->length - ndr->offset;
1910                 *unread = data_blob_named(blob->data + ndr->offset,
1911                                           bytes, "UNREAD");
1912                 DBG_WARNING("\nThere are unprocessed bytes (len 0x%x) "
1913                             "at end of message\n", bytes);
1914         }
1915
1916 out:
1917         return err;
1918 }
1919
1920 static void set_msg_checksum(DATA_BLOB *blob, struct wsp_header *hdr)
1921 {
1922         /* point at payload */
1923         uint32_t i;
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;
1929
1930         static const uint32_t xor_const = 0x59533959;
1931         for(i = 0; i < nwords; i++) {
1932                 checksum += PULL_LE_I32(buffer, offset);
1933                 offset += 4;
1934         }
1935
1936         checksum ^= xor_const;
1937         checksum -= hdr->msg;
1938         hdr->checksum = checksum;
1939 }
1940
1941 static enum ndr_err_code insert_header_and_checksum(TALLOC_CTX *ctx,
1942                 DATA_BLOB* blob,
1943                 struct wsp_header *header)
1944 {
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);
1948
1949         if (header_ndr == NULL) {
1950                 return NDR_ERR_ALLOC;
1951         }
1952
1953         if (header->msg == CPMCONNECT
1954         || header->msg == CPMCREATEQUERY
1955         || header->msg == CPMSETBINDINGSIN
1956         || header->msg == CPMGETROWS
1957         || header->msg == CPMFETCHVALUE) {
1958
1959                 set_msg_checksum(blob, header);
1960         }
1961         err = ndr_push_wsp_header(header_ndr, ndr_flags, header);
1962         if (err) {
1963                 DBG_ERR("Failed to push header, error %d\n", err);
1964                 return err;
1965         }
1966         memcpy(blob->data, header_ndr->data, MSG_HDR_SIZE);
1967         return err;
1968 }
1969
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,
1974                               DATA_BLOB *unread)
1975 {
1976         struct rpc_pipe_client *p = wsp_ctx->rpccli;
1977         NTSTATUS status = NT_STATUS_OK;
1978
1979         ndr_flags_type ndr_flags = NDR_SCALARS | NDR_BUFFERS;
1980         struct ndr_push* push_ndr = NULL;
1981
1982         enum ndr_err_code err;
1983
1984         DATA_BLOB req_blob;
1985         DATA_BLOB resp_blob;
1986
1987         ZERO_STRUCT(req_blob);
1988         ZERO_STRUCT(resp_blob);
1989
1990         push_ndr = ndr_push_init_ctx(ctx);
1991         if (push_ndr == NULL) {
1992                 return NT_STATUS_NO_MEMORY;
1993         }
1994
1995         /* write message payload first */
1996         push_ndr->offset = MSG_HDR_SIZE;
1997         DBG_INFO("\n");
1998
1999         switch(request->header.msg) {
2000                 case CPMCONNECT:
2001                 {
2002                         struct wsp_cpmconnectin *connectin =
2003                                 &request->message.cpmconnect;
2004                         err =  ndr_push_wsp_cpmconnectin(push_ndr, ndr_flags,
2005                                                 connectin);
2006                         break;
2007                  }
2008                 case CPMCREATEQUERY:
2009                 {
2010                         struct wsp_cpmcreatequeryin* createquery =
2011                                 &request->message.cpmcreatequery;
2012                         err = ndr_push_wsp_cpmcreatequeryin(push_ndr,
2013                                         ndr_flags,
2014                                         createquery);
2015                         req_blob = ndr_push_blob(push_ndr);
2016                         /* we need to set cpmcreatequery.size */
2017                         createquery->size =
2018                                 req_blob.length - MSG_HDR_SIZE;
2019                         PUSH_LE_U32(req_blob.data, MSG_HDR_SIZE,
2020                               createquery->size);
2021
2022                         break;
2023                 }
2024                 case CPMSETBINDINGSIN:
2025                 {
2026                         struct wsp_cpmsetbindingsin *bindingsin =
2027                                 &request->message.cpmsetbindings;
2028                         err = ndr_push_wsp_cpmsetbindingsin(push_ndr, ndr_flags,
2029                                                 bindingsin);
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);
2036                         break;
2037                 }
2038                 case CPMGETROWS:
2039                 {
2040                         struct wsp_cpmgetrowsin *getrows =
2041                                 &request->message.cpmgetrows;
2042                         err = ndr_push_wsp_cpmgetrowsin(push_ndr, ndr_flags,
2043                                                 getrows);
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,
2048                               getrows->cbseek);
2049                         PUSH_LE_U32(req_blob.data, MSG_HDR_SIZE + 16,
2050                               getrows->cbreserved);
2051                         break;
2052                 }
2053                 case CPMGETQUERYSTATUS:
2054                 {
2055                         struct wsp_cpmgetquerystatusin *querystatus =
2056                                 &request->message.cpmgetquerystatus;
2057                         err = ndr_push_wsp_cpmgetquerystatusin(
2058                                         push_ndr,
2059                                         ndr_flags,
2060                                         querystatus);
2061                         break;
2062                 }
2063                 case CPMGETQUERYSTATUSEX:
2064                 {
2065                         struct wsp_cpmgetquerystatusexin *statusexin =
2066                                 &request->message.cpmgetquerystatusex;
2067                         err = ndr_push_wsp_cpmgetquerystatusexin(
2068                                         push_ndr,
2069                                         ndr_flags,
2070                                         statusexin);
2071                         break;
2072                 }
2073                 case CPMFREECURSOR:
2074                 {
2075                         struct wsp_cpmfreecursorin *freecursor =
2076                                 &request->message.cpmfreecursor;
2077                         err = ndr_push_wsp_cpmfreecursorin(
2078                                         push_ndr,
2079                                         ndr_flags,
2080                                         freecursor);
2081                         break;
2082                 }
2083                 case CPMFETCHVALUE:
2084                 {
2085                         struct wsp_cpmfetchvaluein *fetchvalue =
2086                                 &request->message.cpmfetchvalue;
2087                         err = ndr_push_wsp_cpmfetchvaluein(
2088                                         push_ndr,
2089                                         ndr_flags,
2090                                         fetchvalue);
2091                         break;
2092                 }
2093
2094                 case CPMGETAPPROXIMATEPOSITION:
2095                 {
2096                         struct wsp_cpmgetapproximatepositionin *position =
2097                                 &request->message.getapproximateposition;
2098                         err = ndr_push_wsp_cpmgetapproximatepositionin(
2099                                 push_ndr,
2100                                 ndr_flags,
2101                                 position);
2102                         break;
2103                 }
2104                 default:
2105                         status = NT_STATUS_MESSAGE_NOT_FOUND;
2106                         goto out;
2107                         break;
2108         }
2109         if (err) {
2110                 DBG_ERR("failed to serialise message! (%d)\n", err);
2111                 status = NT_STATUS_UNSUCCESSFUL;
2112                 goto out;
2113         }
2114         if (!req_blob.data) {
2115                 req_blob = ndr_push_blob(push_ndr);
2116         }
2117         err = insert_header_and_checksum(ctx, &req_blob, &request->header);
2118
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");
2122
2123         dump_data(5, req_blob.data, req_blob.length);
2124
2125         status = write_something(ctx, p, &req_blob, &resp_blob);
2126
2127         if (!NT_STATUS_IS_OK(status)) {
2128                 DBG_ERR("Failed to write message\n");
2129                 goto out;
2130         }
2131         DBG_NOTICE("\nraw response from server\n");
2132         DBG_NOTICE(  "========================\n");
2133         dump_data(5,  resp_blob.data, resp_blob.length);
2134
2135         err = parse_blob(ctx,
2136                         &resp_blob,
2137                         request,
2138                         response,
2139                         unread);
2140         if (err) {
2141                 DBG_ERR("Failed to parse response error %d\n", err);
2142                 status = NT_STATUS_UNSUCCESSFUL;
2143                 goto out;
2144         }
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;
2149         }
2150 out:
2151         return status;
2152 }
2153
2154 struct dcerpc_binding_handle* get_wsp_pipe(struct wsp_client_ctx *ctx)
2155 {
2156         return ctx->rpccli->binding_handle;
2157 }