s3:utils: Remove condition that cannot be true (CID 1548341)
[samba.git] / source3 / utils / wspsearch.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 #include "includes.h"
22 #include "lib/util/debug.h"
23 #include "lib/cmdline/cmdline.h"
24 #include "lib/cmdline_contexts.h"
25 #include "param.h"
26 #include "client.h"
27 #include "libsmb/proto.h"
28 #include "librpc/rpc/rpc_common.h"
29 #include "librpc/wsp/wsp_util.h"
30 #include "rpc_client/cli_pipe.h"
31 #include "rpc_client/wsp_cli.h"
32 #include "libcli/wsp/wsp_aqs.h"
33 #include "librpc/gen_ndr/ndr_wsp.h"
34 #include "librpc/gen_ndr/ndr_wsp_data.h"
35 #include "dcerpc.h"
36
37 #define WIN_VERSION_64 0x10000
38
39 /* send connectin message */
40 static NTSTATUS wsp_connect(TALLOC_CTX *ctx,
41                         struct wsp_client_ctx *wsp_ctx,
42                         const char* clientmachine,
43                         const char* clientuser,
44                         const char* server,
45                         bool *is_64bit)
46 {
47         struct wsp_request *request = NULL;
48         struct wsp_response *response = NULL;
49         uint32_t client_ver;
50         uint32_t server_ver;
51         DATA_BLOB unread = data_blob_null;
52         NTSTATUS status;
53         TALLOC_CTX *local_ctx = talloc_new(ctx);
54
55
56         if (local_ctx == NULL) {
57                 status = NT_STATUS_NO_MEMORY;
58                 goto out;
59         }
60
61         response = talloc_zero(local_ctx, struct wsp_response);
62         if (!response) {
63                 status = NT_STATUS_NO_MEMORY;
64                 goto out;
65         }
66
67         request = talloc_zero(local_ctx, struct wsp_request);
68         if (!request) {
69                 status = NT_STATUS_NO_MEMORY;
70                 goto out;
71         }
72
73         if (!init_connectin_request(local_ctx, request,
74                                clientmachine, clientuser, server)) {
75                 DBG_ERR("Failed in initialise connection message\n");
76                 status = NT_STATUS_INVALID_PARAMETER;
77                 goto out;
78         }
79
80         status =  wsp_request_response(local_ctx, wsp_ctx,
81                         request, response, &unread);
82         if (NT_STATUS_IS_OK(status)) {
83                 client_ver = request->message.cpmconnect.iclientversion;
84                 server_ver = response->message.cpmconnect.server_version;
85                 *is_64bit =
86                         (server_ver & WIN_VERSION_64)
87                         && (client_ver & WIN_VERSION_64);
88         }
89
90 out:
91         data_blob_free(&unread);
92         TALLOC_FREE(local_ctx);
93         return status;
94 }
95
96 static NTSTATUS create_query(TALLOC_CTX *ctx,
97                              struct wsp_client_ctx *wsp_ctx,
98                              uint32_t limit,
99                              t_select_stmt *select,
100                              uint32_t *single_cursor)
101 {
102         struct wsp_request *request = NULL;
103         struct wsp_response *response = NULL;
104         NTSTATUS status;
105         DATA_BLOB unread = data_blob_null;
106         TALLOC_CTX *local_ctx = talloc_new(ctx);
107
108         if (local_ctx == NULL) {
109                 status = NT_STATUS_NO_MEMORY;
110                 goto out;
111         }
112
113         request = talloc_zero(local_ctx, struct wsp_request);
114         if (!request) {
115                 status = NT_STATUS_NO_MEMORY;
116                 goto out;
117         }
118
119         response = talloc_zero(local_ctx, struct wsp_response);
120         if (!response) {
121                 status = NT_STATUS_NO_MEMORY;
122                 goto out;;
123         }
124
125         if (!create_querysearch_request(ctx, request, select)) {
126                 DBG_ERR("error setting up query request message\n");
127                 status = NT_STATUS_INVALID_PARAMETER;
128                 goto out;
129         }
130
131         request->message.cpmcreatequery.rowsetproperties.cmaxresults = limit;
132
133         status = wsp_request_response(local_ctx,
134                         wsp_ctx,
135                         request,
136                         response,
137                         &unread);
138         if (NT_STATUS_IS_OK(status)) {
139                 if (unread.length == 4) {
140                         *single_cursor = IVAL(unread.data, 0);
141                 }
142         }
143
144 out:
145         data_blob_free(&unread);
146         TALLOC_FREE(local_ctx);
147         return status;
148 }
149
150 static NTSTATUS create_bindings(TALLOC_CTX *ctx,
151                                 struct wsp_client_ctx *wsp_ctx,
152                                 t_select_stmt *select,
153                                 uint32_t cursor,
154                                 struct wsp_cpmsetbindingsin *bindings_out,
155                                 bool is_64bit)
156 {
157         struct wsp_request *request = NULL;
158         struct wsp_response *response = NULL;
159         NTSTATUS status;
160         DATA_BLOB unread = data_blob_null;
161
162         request = talloc_zero(ctx, struct wsp_request);
163         if (!request) {
164                 status = NT_STATUS_NO_MEMORY;
165                 goto out;
166         }
167
168         response = talloc_zero(ctx, struct wsp_response);
169         if (!response) {
170                 status = NT_STATUS_NO_MEMORY;
171                 goto out;
172         }
173
174         if (!create_setbindings_request(ctx,
175                                 request,
176                                 select,
177                                 cursor,
178                                 is_64bit)) {
179                 DBG_ERR("Failed to create setbindings message\n");
180                 status = NT_STATUS_INVALID_PARAMETER;
181                 goto out;
182         }
183
184         status = wsp_request_response(ctx,
185                         wsp_ctx,
186                         request,
187                         response,
188                         &unread);
189         if (NT_STATUS_IS_OK(status)) {
190                 *bindings_out = request->message.cpmsetbindings;
191         }
192
193 out:
194         data_blob_free(&unread);
195         return status;
196 }
197
198 static NTSTATUS create_querystatusex(TALLOC_CTX *ctx,
199                                 struct wsp_client_ctx *wsp_ctx,
200                                 uint32_t cursor,
201                                 uint32_t *nrows)
202 {
203         struct wsp_request *request = NULL;
204         struct wsp_response *response = NULL;
205         struct wsp_cpmgetquerystatusexin *statusexin = NULL;
206         NTSTATUS status;
207         DATA_BLOB unread = data_blob_null;
208         TALLOC_CTX *local_ctx = talloc_new(ctx);
209
210         if (local_ctx == NULL) {
211                 status = NT_STATUS_NO_MEMORY;
212                 goto out;
213         }
214
215         request = talloc_zero(local_ctx, struct wsp_request);
216         if (!request) {
217                 status = NT_STATUS_NO_MEMORY;
218                 goto out;
219         }
220
221         response = talloc_zero(local_ctx, struct wsp_response);
222         if (!response) {
223                 status = NT_STATUS_NO_MEMORY;
224                 goto out;
225         }
226
227         statusexin = &request->message.cpmgetquerystatusex;
228
229         request->header.msg = CPMGETQUERYSTATUSEX;
230         statusexin->hcursor = cursor;
231         statusexin->bmk = 0xfffffffc;
232         status = wsp_request_response(local_ctx,
233                         wsp_ctx,
234                         request,
235                         response,
236                         &unread);
237         if (NT_STATUS_IS_OK(status)) {
238                 *nrows = response->message.cpmgetquerystatusex.resultsfound;
239         }
240
241 out:
242         data_blob_free(&unread);
243         TALLOC_FREE(local_ctx);
244         return status;
245 }
246
247 static NTSTATUS print_rowsreturned(
248                                 TALLOC_CTX *ctx,
249                                 DATA_BLOB *buffer,
250                                 bool is_64bit,
251                                 bool disp_all_cols,
252                                 struct wsp_cpmsetbindingsin *bindings,
253                                 uint32_t cbreserved,
254                                 uint64_t address,
255                                 uint32_t rowsreturned,
256                                 uint32_t *rows_processed)
257 {
258         NTSTATUS status;
259         uint32_t row = 0;
260         TALLOC_CTX *local_ctx = NULL;
261         struct wsp_cbasestoragevariant **rowsarray = NULL;
262         enum ndr_err_code err;
263
264         local_ctx = talloc_init("results");
265         if (local_ctx == NULL) {
266                 status = NT_STATUS_NO_MEMORY;
267                 goto out;
268         }
269
270         rowsarray = talloc_zero_array(local_ctx,
271                         struct wsp_cbasestoragevariant*,
272                         rowsreturned);
273         if (rowsarray == NULL) {
274                 status = NT_STATUS_NO_MEMORY;
275                 goto out;
276         }
277
278         err = extract_rowsarray(rowsarray,
279                         buffer,
280                         is_64bit,
281                         bindings,
282                         cbreserved,
283                         address,
284                         rowsreturned,
285                         rowsarray);
286         if (err) {
287                 DBG_ERR("failed to extract rows from getrows response\n");
288                 status = NT_STATUS_UNSUCCESSFUL;
289                 goto out;
290         }
291
292         for(row = 0; row < rowsreturned; row++) {
293                 TALLOC_CTX *row_ctx = NULL;
294                 const char *col_str = NULL;
295
296                 row_ctx = talloc_init("row");
297                 if (row_ctx == NULL) {
298                         status = NT_STATUS_NO_MEMORY;
299                         goto out;
300                 }
301
302                 if (disp_all_cols) {
303                         int i;
304                         for (i = 0; i < bindings->ccolumns; i++){
305                                 col_str =
306                                         variant_as_string(
307                                                 row_ctx,
308                                                 &rowsarray[row][i],
309                                                 true);
310                                 if (col_str) {
311                                         printf("%s%s",
312                                                 i ? ", " : "", col_str);
313                                 } else {
314                                         printf("%sN/A",
315                                                 i ? ", " : "");
316                                 }
317                         }
318                 } else {
319                         col_str = variant_as_string(
320                                         row_ctx,
321                                         &rowsarray[row][0],
322                                         true);
323                         printf("%s", col_str);
324                 }
325                 printf("\n");
326                 TALLOC_FREE(row_ctx);
327         }
328         status = NT_STATUS_OK;
329 out:
330         TALLOC_FREE(local_ctx);
331         *rows_processed = row;
332         return status;
333 }
334
335 static NTSTATUS create_getrows(TALLOC_CTX *ctx,
336                                struct wsp_client_ctx *wsp_ctx,
337                                struct wsp_cpmsetbindingsin *bindings,
338                                uint32_t cursor,
339                                uint32_t nrows,
340                                bool disp_all_cols,
341                                bool is_64bit)
342 {
343         struct wsp_request *request = NULL;
344         struct wsp_response *response = NULL;
345         NTSTATUS status;
346         DATA_BLOB unread = data_blob_null;
347         uint32_t bmk = 0xfffffffc;
348         uint32_t skip = 0;
349         uint32_t total_rows = 0;
350         uint32_t INITIAL_ROWS = 32;
351         uint32_t requested_rows = INITIAL_ROWS;
352         uint32_t rows_printed;
353         TALLOC_CTX *row_ctx;
354         bool loop_again;
355
356         do {
357                 row_ctx = talloc_new(NULL);
358                 if (!row_ctx) {
359                         status = NT_STATUS_UNSUCCESSFUL;
360                         goto out;
361                 }
362                 request = talloc_zero(row_ctx, struct wsp_request);
363                 if (!request) {
364                         status = NT_STATUS_NO_MEMORY;
365                         goto out;
366                 }
367                 response = talloc_zero(row_ctx, struct wsp_response);
368                 if (!response) {
369                         status = NT_STATUS_NO_MEMORY;
370                         goto out;
371                 }
372
373                 create_seekat_getrows_request(request,
374                                         request,
375                                         cursor,
376                                         bmk,
377                                         skip,
378                                         requested_rows,
379                                         40,
380                                         0xDEAbd860,
381                                         bindings->brow,
382                                         0);
383
384                 status = wsp_request_response(request,
385                                 wsp_ctx,
386                                 request,
387                                 response,
388                                 &unread);
389                 if (!NT_STATUS_IS_OK(status)) {
390                         goto out;
391                 }
392
393                 total_rows += response->message.cpmgetrows.rowsreturned;
394                 if (response->message.cpmgetrows.rowsreturned
395                    != requested_rows) {
396                         uint32_t rowsreturned =
397                                 response->message.cpmgetrows.rowsreturned;
398                         if (response->message.cpmgetrows.etype == EROWSEEKAT) {
399                                 struct wsp_cpmgetrowsout *resp;
400                                 struct wsp_crowseekat *seekat;
401                                 resp = &response->message.cpmgetrows;
402                                 seekat =
403                                         &resp->seekdescription.crowseekat;
404                                 bmk = seekat->bmkoffset;
405                                 skip = seekat->cskip;
406                         } else {
407                                 bmk = 0xfffffffc;
408                                 skip = total_rows;
409                         }
410                         requested_rows = requested_rows - rowsreturned;
411                 } else {
412                         requested_rows = INITIAL_ROWS;
413                         bmk = 0xfffffffc;
414                         skip = total_rows;
415                 }
416
417                 if (response->message.cpmgetrows.rowsreturned) {
418                         status = print_rowsreturned(row_ctx, &unread,
419                                 is_64bit,
420                                 disp_all_cols,
421                                 bindings, 40,
422                                 0xDEAbd860,
423                                 response->message.cpmgetrows.rowsreturned,
424                                 &rows_printed);
425                         if (!NT_STATUS_IS_OK(status)) {
426                                 goto out;
427                         }
428                         data_blob_free(&unread);
429                 }
430
431                 /*
432                  * response is a talloc child of row_ctx so we need to
433                  * assign loop_again before we delete row_ctx
434                  */
435                 loop_again = response->message.cpmgetrows.rowsreturned;
436
437                 TALLOC_FREE(row_ctx);
438                 if (nrows && total_rows > nrows) {
439                         DBG_ERR("Something is wrong, results returned %d "
440                                 "exceed expected number of results %d\n",
441                                 total_rows, nrows);
442                         status = NT_STATUS_UNSUCCESSFUL;
443                         goto out;
444                 }
445         } while (loop_again);
446 out:
447         data_blob_free(&unread);
448         TALLOC_FREE(row_ctx);
449         return status;
450 }
451
452 const char *default_column = "System.ItemUrl";
453
454 static bool is_valid_kind(const char *kind)
455 {
456         const char* kinds[] = {"calendar",
457                 "communication",
458                 "contact",
459                 "document",
460                 "email",
461                 "feed",
462                 "folder",
463                 "game",
464                 "instantMessage",
465                 "journal",
466                 "link",
467                 "movie",
468                 "music",
469                 "note",
470                 "picture",
471                 "program",
472                 "recordedtv",
473                 "searchfolder",
474                 "task",
475                 "video",
476                 "webhistory"};
477         char* search_kind = NULL;
478         int i;
479         bool found = false;
480
481         search_kind = strlower_talloc(NULL, kind);
482         if (search_kind == NULL) {
483                 DBG_ERR("couldn't convert %s to lower case\n",
484                                 kind);
485                 return NULL;
486         }
487
488         for (i=0; i<ARRAY_SIZE(kinds); i++) {
489                 if (strequal(search_kind, kinds[i])) {
490                         found = true;
491                         break;
492                 }
493         }
494
495         if (found == false) {
496                 DBG_ERR("Invalid kind %s\n", kind);
497         }
498         TALLOC_FREE(search_kind);
499         return found;
500 }
501
502 static char * build_default_sql(TALLOC_CTX *ctx,
503                                 const char *kind,
504                                 const char *phrase,
505                                 const char *location)
506 {
507         char *sql = NULL;
508         /* match what windows clients do */
509         sql = talloc_asprintf(ctx,
510                 "Scope:\"%s\"  AND NOT System.Shell.SFGAOFlagsStrings:hidden"
511                 "  AND NOT System.Shell.OmitFromView:true", location);
512
513         if (kind) {
514                 if (!is_valid_kind(kind)) {
515                         return NULL;
516                 }
517                 sql = talloc_asprintf(ctx, "System.Kind:%s AND %s",
518                                         kind, sql);
519         }
520
521         if (phrase) {
522                 sql = talloc_asprintf(ctx,
523                                 "All:$=\"%s\" OR All:$<\"%s\""
524                                 " AND %s", phrase, phrase, sql);
525         }
526         sql =  talloc_asprintf(ctx, "SELECT %s"
527                                 " WHERE %s", default_column, sql);
528         return sql;
529 }
530
531 int main(int argc, char **argv)
532 {
533         int opt;
534         int result = 0;
535         NTSTATUS status = NT_STATUS_OK;
536         poptContext pc;
537         char* server = NULL;
538         char* share = NULL;
539         char* path = NULL;
540         char* location = NULL;
541         char* query = NULL;
542         bool custom_query = false;
543         const char* phrase = NULL;
544         const char* kind = NULL;
545         uint32_t limit = 500;
546         uint32_t nrows = 0;
547         struct wsp_cpmsetbindingsin bindings_used = {0};
548         bool is_64bit = false;
549         struct poptOption long_options[] = {
550                 POPT_AUTOHELP
551                 { "limit",
552                         0,
553                         POPT_ARG_INT,
554                         &limit,
555                         0,
556                         "limit results",
557                         "default is 500, specifying 0 means unlimited" },
558                 { "search",
559                         0,
560                         POPT_ARG_STRING,
561                         &phrase,
562                         0,
563                         "Search phrase",
564                         "phrase" },
565                 { "kind", 0, POPT_ARG_STRING, &kind, 0,
566                         "Kind of thing to search for [Calendar|Communication|"
567                         "Contact|Document|Email|Feed|Folder|Game|"
568                         "InstantMessage|Journal|Link|Movie|Music|Note|Picture|"
569                         "Program|RecordedTV|SearchFolder|Task|Video"
570                         "|WebHistory]",
571                         "kind" },
572                 { "query",
573                         0,
574                         POPT_ARG_STRING,
575                         &query,
576                         0,
577                         "specify a more complex query",
578                         "query" },
579                 POPT_COMMON_SAMBA
580                 POPT_COMMON_CONNECTION
581                 POPT_COMMON_CREDENTIALS
582                 POPT_TABLEEND
583         };
584         TALLOC_CTX *frame = talloc_stackframe();
585         struct tevent_context *ev_ctx
586                 =  samba_tevent_context_init(talloc_tos());
587         uint32_t cursor = 0;
588         struct wsp_client_ctx *wsp_ctx = NULL;
589         t_select_stmt *select_stmt = NULL;
590         const char **const_argv = discard_const_p(const char *, argv);
591         struct dcerpc_binding_handle *h = NULL;
592         struct cli_state *c = NULL;
593         uint32_t flags = CLI_FULL_CONNECTION_IPC;
594         bool ok;
595
596         ok = samba_cmdline_init(frame,
597                                 SAMBA_CMDLINE_CONFIG_CLIENT,
598                                 false /* require_smbconf */);
599         if (!ok) {
600                 DBG_ERR("Failed to set up cmdline parser\n");
601                 result = -1;
602                 goto out;
603         }
604
605         pc = samba_popt_get_context("wspsearch",
606                         argc,
607                         const_argv,
608                         long_options,
609                         0);
610         poptSetOtherOptionHelp(pc, "[OPTIONS] //server1/share1");
611
612         while ((opt = poptGetNextOpt(pc)) != -1) ;
613
614         if(!poptPeekArg(pc)) {
615                 poptPrintUsage(pc, stderr, 0);
616                 result = -1;
617                 goto out;
618         }
619
620         path = talloc_strdup(talloc_tos(), poptGetArg(pc));
621         if (!path) {
622                 DBG_ERR("Invalid argument\n");
623                 result = -1;
624                 goto out;
625         }
626
627         string_replace(path,'/','\\');
628         server = talloc_strdup(talloc_tos(), path+2);
629         if (!server) {
630                 DBG_ERR("Invalid argument\n");
631                 return -1;
632         }
633
634         if (server) {
635                 /*
636                  * if we specify --query then we don't need actually need the
637                  * share part, if it is specified then we don't care as we
638                  * expect the scope to be part of the query (and if it isn't
639                  * then it will probably fail anyway)
640                  */
641                 share = strchr_m(server,'\\');
642                 if (!query && !share) {
643                         DBG_ERR("Invalid argument\n");
644                         return -1;
645                 }
646                 if (share) {
647                         *share = 0;
648                         share++;
649                 }
650         }
651
652         DBG_INFO("server name is %s\n", server ? server : "N/A");
653         DBG_INFO("share name is %s\n", share ? share : "N/A");
654         DBG_INFO("search phrase is %s\n", phrase ? phrase : "N/A");
655         DBG_INFO("search kind is %s\n", kind ? kind : "N/A");
656
657         if (!query && (kind == NULL && phrase == NULL)) {
658                 poptPrintUsage(pc, stderr, 0);
659                 result = -1;
660                 goto out;
661         }
662
663         if (!query) {
664                 location = talloc_asprintf(talloc_tos(),
665                                 "FILE://%s/%s", server, share);
666                 query = build_default_sql(talloc_tos(), kind, phrase, location);
667                 if (!query) {
668                         result = -1;
669                         goto out;
670                 }
671         } else {
672                 custom_query = true;
673         }
674
675         printf("custom_query %d\n", custom_query);
676         select_stmt = get_wsp_sql_tree(query);
677
678         poptFreeContext(pc);
679
680         if (select_stmt == NULL) {
681                 DBG_ERR("query failed\n");
682                 result = -1;
683                 goto out;
684         }
685
686         if (select_stmt->cols == NULL) {
687                 select_stmt->cols = talloc_zero(select_stmt, t_col_list);
688                 if (select_stmt->cols == NULL) {
689                         DBG_ERR("out of memory\n");
690                         result = -1;
691                         goto out;
692                 }
693                 select_stmt->cols->num_cols = 1;
694                 select_stmt->cols->cols =
695                         talloc_zero_array(select_stmt->cols, char*, 1);
696                 if (select_stmt->cols->cols == NULL) {
697                         DBG_ERR("out of memory\n");
698                         result = -1;
699                         goto out;
700                 }
701                 select_stmt->cols->cols[0] =
702                         talloc_strdup(select_stmt->cols, default_column);
703         }
704
705         status =  cli_full_connection_creds(&c,
706                                    lp_netbios_name(),
707                                    server,
708                                    NULL,
709                                    0,
710                                    "IPC$",
711                                    "IPC",
712                                    samba_cmdline_get_creds(),
713                                    flags);
714
715         if (!NT_STATUS_IS_OK(status)) {
716                 DBG_ERR("failed to connect to IPC$: %s\n",
717                       nt_errstr(status));
718                 result = -1;
719                 goto out;
720         }
721
722         status = wsp_server_connect(talloc_tos(),
723                         server,
724                         ev_ctx,
725                         samba_cmdline_get_lp_ctx(),
726                         samba_cmdline_get_creds(),
727                         c,
728                         &wsp_ctx);
729
730         if (!NT_STATUS_IS_OK(status)) {
731                 DBG_ERR("failed to connect to wsp: %s\n",
732                       nt_errstr(status));
733                 result = -1;
734                 goto out;
735         }
736
737         h = get_wsp_pipe(wsp_ctx);
738         if (h == NULL) {
739                 DBG_ERR("Failed to communicate with server, no pipe\n");
740                 result = -1;
741                 goto out;
742         }
743
744         dcerpc_binding_handle_set_timeout(h,
745                                           DCERPC_REQUEST_TIMEOUT * 1000);
746
747         /* connect */
748         DBG_INFO("sending connect\n");
749         status = wsp_connect(talloc_tos(),
750                          wsp_ctx,
751                          lpcfg_netbios_name(samba_cmdline_get_lp_ctx()),
752                          cli_credentials_get_username(
753                                  samba_cmdline_get_creds()),
754                          server,
755                          &is_64bit);
756
757         if (!NT_STATUS_IS_OK(status)) {
758                 DBG_ERR("failed to connect to wsp: %s\n",
759                       nt_errstr(status));
760                 result = -1;
761                 goto out;
762         }
763
764         DBG_INFO("sending query\n");
765
766         status = create_query(talloc_tos(),
767                         wsp_ctx,
768                         limit,
769                         select_stmt,
770                         &cursor);
771
772         if (!NT_STATUS_IS_OK(status)) {
773                 DBG_ERR("failed to send query: %s)\n",
774                       nt_errstr(status));
775                 result = -1;
776                 goto out;
777         }
778
779         DBG_INFO("sending createbindings\n");
780         /* set bindings */
781         status = create_bindings(talloc_tos(),
782                         wsp_ctx,
783                         select_stmt,
784                         cursor,
785                         &bindings_used,
786                         is_64bit);
787         if (!NT_STATUS_IS_OK(status)) {
788                 DBG_ERR("failed to setbindings: %s)\n",
789                       nt_errstr(status));
790                 result = -1;
791                 goto out;
792         }
793
794         status = create_querystatusex(talloc_tos(),
795                                       wsp_ctx,
796                                       bindings_used.hcursor,
797                                       &nrows);
798         if (!nrows) {
799                 result = 0;
800                 DBG_ERR("no results found\n");
801                 goto out;
802         }
803
804         printf("found %d results, returning %d \n",
805                         nrows,
806                         limit ? MIN(nrows, limit) : nrows);
807         status = create_getrows(talloc_tos(),
808                                 wsp_ctx,
809                                 &bindings_used,
810                                 bindings_used.hcursor,
811                                 limit ? MIN(nrows, limit) : nrows,
812                                 custom_query,
813                                 is_64bit);
814         if (!NT_STATUS_IS_OK(status)) {
815                 DBG_ERR("Failed to retrieve rows, error: %s\n",
816                         nt_errstr(status));
817                 result = -1;
818                 goto out;
819         }
820         result = 0;
821 out:
822         TALLOC_FREE(frame);
823         return result;
824 }