From 8daa83a594a2e98f39d764422bfbdbc62c9efd44 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 19:20:00 +0200 Subject: Adding upstream version 2:4.20.0+dfsg. Signed-off-by: Daniel Baumann --- source3/utils/wspsearch.c | 842 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 842 insertions(+) create mode 100644 source3/utils/wspsearch.c (limited to 'source3/utils/wspsearch.c') diff --git a/source3/utils/wspsearch.c b/source3/utils/wspsearch.c new file mode 100644 index 0000000..063b952 --- /dev/null +++ b/source3/utils/wspsearch.c @@ -0,0 +1,842 @@ +/* + * Unix SMB/CIFS implementation. + * + * Window Search Service + * + * Copyright (c) Noel Power + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#include "includes.h" +#include "lib/util/debug.h" +#include "lib/cmdline/cmdline.h" +#include "lib/cmdline_contexts.h" +#include "param.h" +#include "client.h" +#include "libsmb/proto.h" +#include "librpc/rpc/rpc_common.h" +#include "librpc/wsp/wsp_util.h" +#include "rpc_client/cli_pipe.h" +#include "rpc_client/wsp_cli.h" +#include "libcli/wsp/wsp_aqs.h" +#include "librpc/gen_ndr/ndr_wsp.h" +#include "librpc/gen_ndr/ndr_wsp_data.h" +#include "dcerpc.h" + +#define WIN_VERSION_64 0x10000 + +/* send connectin message */ +static NTSTATUS wsp_connect(TALLOC_CTX *ctx, + struct wsp_client_ctx *wsp_ctx, + const char* clientmachine, + const char* clientuser, + const char* server, + bool *is_64bit) +{ + struct wsp_request *request = NULL; + struct wsp_response *response = NULL; + uint32_t client_ver; + uint32_t server_ver; + DATA_BLOB unread = data_blob_null; + NTSTATUS status; + TALLOC_CTX *local_ctx = talloc_new(ctx); + + + if (local_ctx == NULL) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + + response = talloc_zero(local_ctx, struct wsp_response); + if (!response) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + + request = talloc_zero(local_ctx, struct wsp_request); + if (!request) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + + if (!init_connectin_request(local_ctx, request, + clientmachine, clientuser, server)) { + DBG_ERR("Failed in initialise connection message\n"); + status = NT_STATUS_INVALID_PARAMETER; + goto out; + } + + status = wsp_request_response(local_ctx, wsp_ctx, + request, response, &unread); + if (NT_STATUS_IS_OK(status)) { + client_ver = request->message.cpmconnect.iclientversion; + server_ver = response->message.cpmconnect.server_version; + *is_64bit = + (server_ver & WIN_VERSION_64) + && (client_ver & WIN_VERSION_64); + } + +out: + data_blob_free(&unread); + TALLOC_FREE(local_ctx); + return status; +} + +static NTSTATUS create_query(TALLOC_CTX *ctx, + struct wsp_client_ctx *wsp_ctx, + uint32_t limit, + t_select_stmt *select, + uint32_t *single_cursor) +{ + struct wsp_request *request = NULL; + struct wsp_response *response = NULL; + NTSTATUS status; + DATA_BLOB unread = data_blob_null; + TALLOC_CTX *local_ctx = talloc_new(ctx); + + if (local_ctx == NULL) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + + request = talloc_zero(local_ctx, struct wsp_request); + if (!request) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + + response = talloc_zero(local_ctx, struct wsp_response); + if (!response) { + status = NT_STATUS_NO_MEMORY; + goto out;; + } + + if (!create_querysearch_request(ctx, request, select)) { + DBG_ERR("error setting up query request message\n"); + status = NT_STATUS_INVALID_PARAMETER; + goto out; + } + + request->message.cpmcreatequery.rowsetproperties.cmaxresults = limit; + + status = wsp_request_response(local_ctx, + wsp_ctx, + request, + response, + &unread); + if (NT_STATUS_IS_OK(status)) { + if (unread.length == 4) { + *single_cursor = IVAL(unread.data, 0); + } + } + +out: + data_blob_free(&unread); + TALLOC_FREE(local_ctx); + return status; +} + +static NTSTATUS create_bindings(TALLOC_CTX *ctx, + struct wsp_client_ctx *wsp_ctx, + t_select_stmt *select, + uint32_t cursor, + struct wsp_cpmsetbindingsin *bindings_out, + bool is_64bit) +{ + struct wsp_request *request = NULL; + struct wsp_response *response = NULL; + NTSTATUS status; + DATA_BLOB unread = data_blob_null; + + request = talloc_zero(ctx, struct wsp_request); + if (!request) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + + response = talloc_zero(ctx, struct wsp_response); + if (!response) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + + if (!create_setbindings_request(ctx, + request, + select, + cursor, + is_64bit)) { + DBG_ERR("Failed to create setbindings message\n"); + status = NT_STATUS_INVALID_PARAMETER; + goto out; + } + + status = wsp_request_response(ctx, + wsp_ctx, + request, + response, + &unread); + if (NT_STATUS_IS_OK(status)) { + *bindings_out = request->message.cpmsetbindings; + } + +out: + data_blob_free(&unread); + return status; +} + +static NTSTATUS create_querystatusex(TALLOC_CTX *ctx, + struct wsp_client_ctx *wsp_ctx, + uint32_t cursor, + uint32_t *nrows) +{ + struct wsp_request *request = NULL; + struct wsp_response *response = NULL; + struct wsp_cpmgetquerystatusexin *statusexin = NULL; + NTSTATUS status; + DATA_BLOB unread = data_blob_null; + TALLOC_CTX *local_ctx = talloc_new(ctx); + + if (local_ctx == NULL) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + + request = talloc_zero(local_ctx, struct wsp_request); + if (!request) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + + response = talloc_zero(local_ctx, struct wsp_response); + if (!response) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + + statusexin = &request->message.cpmgetquerystatusex; + + request->header.msg = CPMGETQUERYSTATUSEX; + statusexin->hcursor = cursor; + statusexin->bmk = 0xfffffffc; + status = wsp_request_response(local_ctx, + wsp_ctx, + request, + response, + &unread); + if (NT_STATUS_IS_OK(status)) { + *nrows = response->message.cpmgetquerystatusex.resultsfound; + } + +out: + data_blob_free(&unread); + TALLOC_FREE(local_ctx); + return status; +} + +static NTSTATUS print_rowsreturned( + TALLOC_CTX *ctx, + DATA_BLOB *buffer, + bool is_64bit, + bool disp_all_cols, + struct wsp_cpmsetbindingsin *bindings, + uint32_t cbreserved, + uint64_t address, + uint32_t rowsreturned, + uint32_t *rows_processed) +{ + NTSTATUS status; + uint32_t row = 0; + TALLOC_CTX *local_ctx = NULL; + struct wsp_cbasestoragevariant **rowsarray = NULL; + enum ndr_err_code err; + + local_ctx = talloc_init("results"); + if (local_ctx == NULL) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + + rowsarray = talloc_zero_array(local_ctx, + struct wsp_cbasestoragevariant*, + rowsreturned); + if (rowsarray == NULL) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + + err = extract_rowsarray(rowsarray, + buffer, + is_64bit, + bindings, + cbreserved, + address, + rowsreturned, + rowsarray); + if (err) { + DBG_ERR("failed to extract rows from getrows response\n"); + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + + for(row = 0; row < rowsreturned; row++) { + TALLOC_CTX *row_ctx = NULL; + const char *col_str = NULL; + + row_ctx = talloc_init("row"); + if (row_ctx == NULL) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + + if (disp_all_cols) { + int i; + for (i = 0; i < bindings->ccolumns; i++){ + col_str = + variant_as_string( + row_ctx, + &rowsarray[row][i], + true); + if (col_str) { + printf("%s%s", + i ? ", " : "", col_str); + } else { + printf("%sN/A", + i ? ", " : ""); + } + } + } else { + col_str = variant_as_string( + row_ctx, + &rowsarray[row][0], + true); + printf("%s", col_str); + } + printf("\n"); + TALLOC_FREE(row_ctx); + } + status = NT_STATUS_OK; +out: + TALLOC_FREE(local_ctx); + *rows_processed = row; + return status; +} + +static NTSTATUS create_getrows(TALLOC_CTX *ctx, + struct wsp_client_ctx *wsp_ctx, + struct wsp_cpmsetbindingsin *bindings, + uint32_t cursor, + uint32_t nrows, + bool disp_all_cols, + bool is_64bit) +{ + struct wsp_request *request = NULL; + struct wsp_response *response = NULL; + NTSTATUS status; + DATA_BLOB unread = data_blob_null; + uint32_t bmk = 0xfffffffc; + uint32_t skip = 0; + uint32_t total_rows = 0; + uint32_t INITIAL_ROWS = 32; + uint32_t requested_rows = INITIAL_ROWS; + uint32_t rows_printed; + uint64_t baseaddress; + uint32_t offset_lowbits = 0xdeabd860; + uint32_t offset_hibits = 0xfeeddeaf; + + TALLOC_CTX *row_ctx; + bool loop_again; + + do { + row_ctx = talloc_new(NULL); + if (!row_ctx) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + request = talloc_zero(row_ctx, struct wsp_request); + if (!request) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + response = talloc_zero(row_ctx, struct wsp_response); + if (!response) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + + create_seekat_getrows_request(request, + request, + cursor, + bmk, + skip, + requested_rows, + 40, + offset_lowbits, + bindings->brow, + 0); + + if (is_64bit) { + /* + * MS-WSP 2.2.2 + * ulreservered holds the high 32-bits part of + * a 64-bit offset if 64-bit offsets are being used. + */ + request->header.ulreserved2 = offset_hibits; + baseaddress = request->header.ulreserved2; + baseaddress <<= 32; + baseaddress += offset_lowbits; + } else { + baseaddress = offset_lowbits; + } + + status = wsp_request_response(request, + wsp_ctx, + request, + response, + &unread); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + total_rows += response->message.cpmgetrows.rowsreturned; + if (response->message.cpmgetrows.rowsreturned + != requested_rows) { + uint32_t rowsreturned = + response->message.cpmgetrows.rowsreturned; + if (response->message.cpmgetrows.etype == EROWSEEKAT) { + struct wsp_cpmgetrowsout *resp; + struct wsp_crowseekat *seekat; + resp = &response->message.cpmgetrows; + seekat = + &resp->seekdescription.crowseekat; + bmk = seekat->bmkoffset; + skip = seekat->cskip; + } else { + bmk = 0xfffffffc; + skip = total_rows; + } + requested_rows = requested_rows - rowsreturned; + } else { + requested_rows = INITIAL_ROWS; + bmk = 0xfffffffc; + skip = total_rows; + } + + if (response->message.cpmgetrows.rowsreturned) { + status = print_rowsreturned(row_ctx, &unread, + is_64bit, + disp_all_cols, + bindings, 40, + baseaddress, + response->message.cpmgetrows.rowsreturned, + &rows_printed); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + data_blob_free(&unread); + } + + /* + * response is a talloc child of row_ctx so we need to + * assign loop_again before we delete row_ctx + */ + loop_again = response->message.cpmgetrows.rowsreturned; + + TALLOC_FREE(row_ctx); + if (nrows && total_rows > nrows) { + DBG_ERR("Something is wrong, results returned %d " + "exceed expected number of results %d\n", + total_rows, nrows); + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + } while (loop_again); +out: + data_blob_free(&unread); + TALLOC_FREE(row_ctx); + return status; +} + +const char *default_column = "System.ItemUrl"; + +static bool is_valid_kind(const char *kind) +{ + const char* kinds[] = {"calendar", + "communication", + "contact", + "document", + "email", + "feed", + "folder", + "game", + "instantMessage", + "journal", + "link", + "movie", + "music", + "note", + "picture", + "program", + "recordedtv", + "searchfolder", + "task", + "video", + "webhistory"}; + char* search_kind = NULL; + int i; + bool found = false; + + search_kind = strlower_talloc(NULL, kind); + if (search_kind == NULL) { + DBG_ERR("couldn't convert %s to lower case\n", + kind); + return NULL; + } + + for (i=0; icols == NULL) { + select_stmt->cols = talloc_zero(select_stmt, t_col_list); + if (select_stmt->cols == NULL) { + DBG_ERR("out of memory\n"); + result = -1; + goto out; + } + select_stmt->cols->num_cols = 1; + select_stmt->cols->cols = + talloc_zero_array(select_stmt->cols, char*, 1); + if (select_stmt->cols->cols == NULL) { + DBG_ERR("out of memory\n"); + result = -1; + goto out; + } + select_stmt->cols->cols[0] = + talloc_strdup(select_stmt->cols, default_column); + } + + status = cli_full_connection_creds(&c, + lp_netbios_name(), + server, + NULL, + 0, + "IPC$", + "IPC", + samba_cmdline_get_creds(), + flags); + + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("failed to connect to IPC$: %s\n", + nt_errstr(status)); + result = -1; + goto out; + } + + status = wsp_server_connect(talloc_tos(), + server, + ev_ctx, + samba_cmdline_get_lp_ctx(), + samba_cmdline_get_creds(), + c, + &wsp_ctx); + + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("failed to connect to wsp: %s\n", + nt_errstr(status)); + result = -1; + goto out; + } + + h = get_wsp_pipe(wsp_ctx); + if (h == NULL) { + DBG_ERR("Failed to communicate with server, no pipe\n"); + result = -1; + goto out; + } + + dcerpc_binding_handle_set_timeout(h, + DCERPC_REQUEST_TIMEOUT * 1000); + + /* connect */ + DBG_INFO("sending connect\n"); + status = wsp_connect(talloc_tos(), + wsp_ctx, + lpcfg_netbios_name(samba_cmdline_get_lp_ctx()), + cli_credentials_get_username( + samba_cmdline_get_creds()), + server, + &is_64bit); + + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("failed to connect to wsp: %s\n", + nt_errstr(status)); + result = -1; + goto out; + } + + DBG_INFO("sending query\n"); + + status = create_query(talloc_tos(), + wsp_ctx, + limit, + select_stmt, + &cursor); + + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("failed to send query: %s)\n", + nt_errstr(status)); + result = -1; + goto out; + } + + DBG_INFO("sending createbindings\n"); + /* set bindings */ + status = create_bindings(talloc_tos(), + wsp_ctx, + select_stmt, + cursor, + &bindings_used, + is_64bit); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("failed to setbindings: %s)\n", + nt_errstr(status)); + result = -1; + goto out; + } + + status = create_querystatusex(talloc_tos(), + wsp_ctx, + bindings_used.hcursor, + &nrows); + if (!nrows) { + result = 0; + DBG_ERR("no results found\n"); + goto out; + } + + printf("found %d results, returning %d \n", + nrows, + limit ? MIN(nrows, limit) : nrows); + status = create_getrows(talloc_tos(), + wsp_ctx, + &bindings_used, + bindings_used.hcursor, + limit ? MIN(nrows, limit) : nrows, + custom_query, + is_64bit); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("Failed to retrieve rows, error: %s\n", + nt_errstr(status)); + result = -1; + goto out; + } + result = 0; +out: + TALLOC_FREE(frame); + return result; +} -- cgit v1.2.3