From b27d9afa29435b7af6335f228b8a315701b2607a Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 2 May 2019 07:45:39 +0200 Subject: [PATCH] s3:rpc_client: add a mdssvc client library Signed-off-by: Ralph Boehme Reviewed-by: Noel Power --- source3/rpc_client/cli_mdssvc.c | 1039 +++++++++++++++++++++++ source3/rpc_client/cli_mdssvc.h | 97 +++ source3/rpc_client/cli_mdssvc_private.h | 70 ++ source3/rpc_client/cli_mdssvc_util.c | 531 ++++++++++++ source3/rpc_client/cli_mdssvc_util.h | 41 + source3/wscript_build | 7 + 6 files changed, 1785 insertions(+) create mode 100644 source3/rpc_client/cli_mdssvc.c create mode 100644 source3/rpc_client/cli_mdssvc.h create mode 100644 source3/rpc_client/cli_mdssvc_private.h create mode 100644 source3/rpc_client/cli_mdssvc_util.c create mode 100644 source3/rpc_client/cli_mdssvc_util.h diff --git a/source3/rpc_client/cli_mdssvc.c b/source3/rpc_client/cli_mdssvc.c new file mode 100644 index 00000000000..76cceb42fe0 --- /dev/null +++ b/source3/rpc_client/cli_mdssvc.c @@ -0,0 +1,1039 @@ +/* + Unix SMB/CIFS implementation. + Main metadata server / Spotlight client functions + + Copyright (C) Ralph Boehme 2019 + + 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 "rpc_client.h" +#include "../librpc/gen_ndr/ndr_mdssvc_c.h" +#include "lib/util/tevent_ntstatus.h" +#include "rpc_server/mdssvc/dalloc.h" +#include "rpc_server/mdssvc/marshalling.h" +#include "cli_mdssvc.h" +#include "cli_mdssvc_private.h" +#include "cli_mdssvc_util.h" + +struct mdsctx_id mdscli_new_ctx_id(struct mdscli_ctx *mdscli_ctx) +{ + mdscli_ctx->ctx_id.id++; + return mdscli_ctx->ctx_id; +} + +char *mdscli_get_basepath(TALLOC_CTX *mem_ctx, + struct mdscli_ctx *mdscli_ctx) +{ + return talloc_strdup(mem_ctx, mdscli_ctx->mdscmd_open.share_path); +} + +struct mdscli_connect_state { + struct tevent_context *ev; + struct mdscli_ctx *mdscli_ctx; +}; + +static void mdscli_connect_open_done(struct tevent_req *subreq); +static void mdscli_connect_unknown1_done(struct tevent_req *subreq); + +struct tevent_req *mdscli_connect_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct dcerpc_binding_handle *bh, + const char *share_name, + const char *mount_path) +{ + struct tevent_req *req = NULL; + struct mdscli_connect_state *state = NULL; + struct tevent_req *subreq = NULL; + struct mdscli_ctx *ctx = NULL; + + req = tevent_req_create(req, &state, struct mdscli_connect_state); + if (req == NULL) { + return NULL; + } + + ctx = talloc_zero(state, struct mdscli_ctx); + if (tevent_req_nomem(ctx, req)) { + return tevent_req_post(req, ev); + } + + *state = (struct mdscli_connect_state) { + .ev = ev, + .mdscli_ctx = ctx, + }; + + *ctx = (struct mdscli_ctx) { + .bh = bh, + .max_fragment_size = 64 * 1024, + /* + * The connection id is a per tcon value sent by the client, + * 0x6b000060 is a value used most of the times for the first + * tcon. + */ + .ctx_id.connection = UINT64_C(0x6b000060), + }; + + subreq = dcerpc_mdssvc_open_send(state, + state->ev, + ctx->bh, + &ctx->dev, + &ctx->mdscmd_open.unkn2, + &ctx->mdscmd_open.unkn3, + mount_path, + share_name, + ctx->mdscmd_open.share_path, + &ctx->ph); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, state->ev); + } + tevent_req_set_callback(subreq, mdscli_connect_open_done, req); + ctx->async_pending++; + + return req; +} + +static void mdscli_connect_open_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct mdscli_connect_state *state = tevent_req_data( + req, struct mdscli_connect_state); + struct mdscli_ctx *mdscli_ctx = state->mdscli_ctx; + NTSTATUS status; + + status = dcerpc_mdssvc_open_recv(subreq, state); + TALLOC_FREE(subreq); + state->mdscli_ctx->async_pending--; + if (tevent_req_nterror(req, status)) { + return; + } + + subreq = dcerpc_mdssvc_unknown1_send( + state, + state->ev, + mdscli_ctx->bh, + mdscli_ctx->ph, + 0, + mdscli_ctx->dev, + mdscli_ctx->mdscmd_open.unkn2, + 0, + geteuid(), + getegid(), + &mdscli_ctx->mdscmd_unknown1.status, + &mdscli_ctx->flags, + &mdscli_ctx->mdscmd_unknown1.unkn7); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, mdscli_connect_unknown1_done, req); +} + +static void mdscli_connect_unknown1_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct mdscli_connect_state *state = tevent_req_data( + req, struct mdscli_connect_state); + NTSTATUS status; + + status = dcerpc_mdssvc_unknown1_recv(subreq, state); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + + tevent_req_done(req); +} + +NTSTATUS mdscli_connect_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct mdscli_ctx **mdscli_ctx) +{ + struct mdscli_connect_state *state = tevent_req_data( + req, struct mdscli_connect_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + + *mdscli_ctx = talloc_move(mem_ctx, &state->mdscli_ctx); + tevent_req_received(req); + return NT_STATUS_OK; +} + +NTSTATUS mdscli_connect(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *bh, + const char *share_name, + const char *mount_path, + struct mdscli_ctx **mdscli_ctx) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct tevent_req *req = NULL; + struct tevent_context *ev = NULL; + NTSTATUS status = NT_STATUS_NO_MEMORY; + + ev = samba_tevent_context_init(frame); + if (ev == NULL) { + goto fail; + } + + req = mdscli_connect_send(frame, + ev, + bh, + share_name, + mount_path); + if (req == NULL) { + goto fail; + } + if (!tevent_req_poll_ntstatus(req, ev, &status)) { + goto fail; + } + + status = mdscli_connect_recv(req, mem_ctx, mdscli_ctx); +fail: + TALLOC_FREE(frame); + return status; +} + +struct mdscli_search_state { + struct mdscli_search_ctx *search; + struct mdssvc_blob request_blob; + struct mdssvc_blob response_blob; +}; + +static void mdscli_search_cmd_done(struct tevent_req *subreq); + +struct tevent_req *mdscli_search_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct mdscli_ctx *mdscli_ctx, + const char *mds_query, + const char *path_scope_in, + bool live) +{ + struct tevent_req *req = NULL; + struct mdscli_search_state *state = NULL; + struct tevent_req *subreq = NULL; + struct mdscli_search_ctx *search = NULL; + char *path_scope = NULL; + NTSTATUS status; + + req = tevent_req_create(req, &state, struct mdscli_search_state); + if (req == NULL) { + return NULL; + } + + search = talloc_zero(state, struct mdscli_search_ctx); + if (tevent_req_nomem(search, req)) { + return tevent_req_post(req, ev); + } + + if (path_scope_in[0] == '/') { + path_scope = talloc_strdup(search, path_scope_in); + } else { + path_scope = talloc_asprintf(search, + "%s/%s", + mdscli_ctx->mdscmd_open.share_path, + path_scope_in); + } + if (tevent_req_nomem(path_scope, req)) { + return tevent_req_post(req, ev); + } + + *search = (struct mdscli_search_ctx) { + .mdscli_ctx = mdscli_ctx, + .ctx_id = mdscli_new_ctx_id(mdscli_ctx), + .unique_id = generate_random_u64(), + .live = live, + .path_scope = path_scope, + .mds_query = talloc_strdup(search, mds_query), + }; + if (tevent_req_nomem(search->mds_query, req)) { + return tevent_req_post(req, ev); + } + + *state = (struct mdscli_search_state) { + .search = search, + }; + + status = mdscli_blob_search(state, + search, + &state->request_blob); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + state->response_blob.spotlight_blob = talloc_array( + state, + uint8_t, + mdscli_ctx->max_fragment_size); + if (tevent_req_nomem(state->response_blob.spotlight_blob, req)) { + return tevent_req_post(req, ev); + } + state->response_blob.size = mdscli_ctx->max_fragment_size; + + subreq = dcerpc_mdssvc_cmd_send(state, + ev, + mdscli_ctx->bh, + mdscli_ctx->ph, + 0, + mdscli_ctx->dev, + mdscli_ctx->mdscmd_open.unkn2, + 0, + mdscli_ctx->flags, + state->request_blob, + 0, + mdscli_ctx->max_fragment_size, + 1, + mdscli_ctx->max_fragment_size, + 0, + 0, + &mdscli_ctx->mdscmd_cmd.fragment, + &state->response_blob, + &mdscli_ctx->mdscmd_cmd.unkn9); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, mdscli_search_cmd_done, req); + mdscli_ctx->async_pending++; + return req; +} + +static void mdscli_search_cmd_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct mdscli_search_state *state = tevent_req_data( + req, struct mdscli_search_state); + DALLOC_CTX *d = NULL; + uint64_t *uint64p = NULL; + NTSTATUS status; + bool ok; + + status = dcerpc_mdssvc_cmd_recv(subreq, state); + TALLOC_FREE(subreq); + state->search->mdscli_ctx->async_pending--; + if (tevent_req_nterror(req, status)) { + return; + } + + d = dalloc_new(state); + if (tevent_req_nomem(d, req)) { + return; + } + + ok = sl_unpack(d, + (char *)state->response_blob.spotlight_blob, + state->response_blob.length); + if (!ok) { + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return; + } + + uint64p = dalloc_get(d, + "DALLOC_CTX", 0, + "uint64_t", 0); + if (uint64p == NULL) { + DBG_DEBUG("Unexpected mds reponse: %s", dalloc_dump(d, 0)); + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return; + } + + if (*uint64p != 0) { + DBG_DEBUG("Unexpected mds result: 0x%" PRIx64, *uint64p); + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return; + } + + tevent_req_done(req); + return; +} + +NTSTATUS mdscli_search_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct mdscli_search_ctx **search) +{ + struct mdscli_search_state *state = tevent_req_data( + req, struct mdscli_search_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + + *search = talloc_move(mem_ctx, &state->search); + tevent_req_received(req); + return NT_STATUS_OK; +} + +NTSTATUS mdscli_search(TALLOC_CTX *mem_ctx, + struct mdscli_ctx *mdscli_ctx, + const char *mds_query, + const char *path_scope, + bool live, + struct mdscli_search_ctx **search) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct tevent_req *req = NULL; + struct tevent_context *ev = NULL; + NTSTATUS status = NT_STATUS_NO_MEMORY; + + if (mdscli_ctx->async_pending != 0) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + ev = samba_tevent_context_init(frame); + if (ev == NULL) { + goto fail; + } + + req = mdscli_search_send(frame, + ev, + mdscli_ctx, + mds_query, + path_scope, + live); + if (req == NULL) { + goto fail; + } + if (!tevent_req_poll_ntstatus(req, ev, &status)) { + goto fail; + } + + status = mdscli_search_recv(req, mem_ctx, search); +fail: + TALLOC_FREE(frame); + return status; +} + +struct mdscli_get_results_state { + struct mdscli_search_ctx *search; + struct mdssvc_blob request_blob; + struct mdssvc_blob response_blob; + uint64_t *cnids; +}; + +static void mdscli_get_results_cmd_done(struct tevent_req *subreq); + +struct tevent_req *mdscli_get_results_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct mdscli_search_ctx *search) +{ + struct tevent_req *req = NULL; + struct mdscli_get_results_state *state = NULL; + struct tevent_req *subreq = NULL; + struct mdscli_ctx *mdscli_ctx = search->mdscli_ctx; + NTSTATUS status; + + req = tevent_req_create(req, &state, struct mdscli_get_results_state); + if (req == NULL) { + return NULL; + } + + *state = (struct mdscli_get_results_state) { + .search = search, + }; + + status = mdscli_blob_get_results(state, + search, + &state->request_blob); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + state->response_blob.spotlight_blob = talloc_array( + state, + uint8_t, + mdscli_ctx->max_fragment_size); + if (tevent_req_nomem(state->response_blob.spotlight_blob, req)) { + return tevent_req_post(req, ev); + } + state->response_blob.size = mdscli_ctx->max_fragment_size; + + subreq = dcerpc_mdssvc_cmd_send(state, + ev, + mdscli_ctx->bh, + mdscli_ctx->ph, + 0, + mdscli_ctx->dev, + mdscli_ctx->mdscmd_open.unkn2, + 0, + mdscli_ctx->flags, + state->request_blob, + 0, + mdscli_ctx->max_fragment_size, + 1, + mdscli_ctx->max_fragment_size, + 0, + 0, + &mdscli_ctx->mdscmd_cmd.fragment, + &state->response_blob, + &mdscli_ctx->mdscmd_cmd.unkn9); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, mdscli_get_results_cmd_done, req); + mdscli_ctx->async_pending++; + return req; +} + +static void mdscli_get_results_cmd_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct mdscli_get_results_state *state = tevent_req_data( + req, struct mdscli_get_results_state); + DALLOC_CTX *d = NULL; + uint64_t *uint64p = NULL; + sl_cnids_t *cnids = NULL; + size_t ncnids; + size_t i; + NTSTATUS status; + bool ok; + + status = dcerpc_mdssvc_cmd_recv(subreq, state); + TALLOC_FREE(subreq); + state->search->mdscli_ctx->async_pending--; + if (tevent_req_nterror(req, status)) { + return; + } + + d = dalloc_new(state); + if (tevent_req_nomem(d, req)) { + return; + } + + ok = sl_unpack(d, + (char *)state->response_blob.spotlight_blob, + state->response_blob.length); + if (!ok) { + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return; + } + + uint64p = dalloc_get(d, + "DALLOC_CTX", 0, + "uint64_t", 0); + if (uint64p == NULL) { + DBG_DEBUG("Unexpected mds reponse: %s", dalloc_dump(d, 0)); + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return; + } + + if (*uint64p == 35) { + DBG_DEBUG("search done: %s", dalloc_dump(d, 0)); + tevent_req_done(req); + return; + } + + cnids = dalloc_get(d, "DALLOC_CTX", 0, "sl_cnids_t", 1); + if (cnids == NULL) { + DBG_DEBUG("cnids error: %s", dalloc_dump(d, 0)); + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return; + } + + ncnids = dalloc_size(cnids->ca_cnids); + if (ncnids == 0) { + tevent_req_nterror(req, NT_STATUS_NO_MORE_MATCHES); + return; + } + + if (cnids->ca_unkn1 != 0xadd) { + /* + * Whatever 0xadd means... but it seems to be the standard value + * macOS mdssvc returns here. + */ + DBG_DEBUG("unexpected ca_unkn1: %s", dalloc_dump(d, 0)); + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return; + } + + if (cnids->ca_context != state->search->ctx_id.connection ) { + DBG_DEBUG("unexpected ca_context: %s", dalloc_dump(d, 0)); + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return; + } + + state->cnids = talloc_zero_array(state, uint64_t, ncnids); + if (tevent_req_nomem(state->cnids, req)) { + return; + } + + for (i = 0; i < ncnids; i++) { + uint64_t *cnid = NULL; + + cnid = dalloc_get(cnids->ca_cnids, "uint64_t", i); + if (cnid == NULL) { + DBG_DEBUG("cnids error: %s", dalloc_dump(d, 0)); + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return; + } + state->cnids[i] = *cnid; + } + + tevent_req_done(req); + return; +} + +NTSTATUS mdscli_get_results_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + uint64_t **cnids) +{ + struct mdscli_get_results_state *state = tevent_req_data( + req, struct mdscli_get_results_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + + *cnids = talloc_move(mem_ctx, &state->cnids); + + tevent_req_received(req); + return NT_STATUS_OK; +} + +NTSTATUS mdscli_get_results(TALLOC_CTX *mem_ctx, + struct mdscli_search_ctx *search, + uint64_t **_cnids) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct tevent_req *req = NULL; + struct tevent_context *ev = NULL; + NTSTATUS status = NT_STATUS_NO_MEMORY; + + if (search->mdscli_ctx->async_pending != 0) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + ev = samba_tevent_context_init(frame); + if (ev == NULL) { + goto fail; + } + + req = mdscli_get_results_send(frame, + ev, + search); + if (req == NULL) { + goto fail; + } + if (!tevent_req_poll_ntstatus(req, ev, &status)) { + goto fail; + } + + status = mdscli_get_results_recv(req, mem_ctx, _cnids); +fail: + TALLOC_FREE(frame); + return status; +} + +struct mdscli_get_path_state { + struct mdscli_ctx *mdscli_ctx; + struct mdssvc_blob request_blob; + struct mdssvc_blob response_blob; + char *path; +}; + +static void mdscli_get_path_done(struct tevent_req *subreq); + +struct tevent_req *mdscli_get_path_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct mdscli_ctx *mdscli_ctx, + uint64_t cnid) +{ + struct tevent_req *req = NULL; + struct mdscli_get_path_state *state = NULL; + struct tevent_req *subreq = NULL; + NTSTATUS status; + + req = tevent_req_create(req, &state, struct mdscli_get_path_state); + if (req == NULL) { + return NULL; + } + *state = (struct mdscli_get_path_state) { + .mdscli_ctx = mdscli_ctx, + }; + + status = mdscli_blob_get_path(state, + mdscli_ctx, + cnid, + &state->request_blob); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + state->response_blob.spotlight_blob = talloc_array( + state, + uint8_t, + mdscli_ctx->max_fragment_size); + if (tevent_req_nomem(state->response_blob.spotlight_blob, req)) { + return tevent_req_post(req, ev); + } + state->response_blob.size = mdscli_ctx->max_fragment_size; + + subreq = dcerpc_mdssvc_cmd_send(state, + ev, + mdscli_ctx->bh, + mdscli_ctx->ph, + 0, + mdscli_ctx->dev, + mdscli_ctx->mdscmd_open.unkn2, + 0, + mdscli_ctx->flags, + state->request_blob, + 0, + mdscli_ctx->max_fragment_size, + 1, + mdscli_ctx->max_fragment_size, + 0, + 0, + &mdscli_ctx->mdscmd_cmd.fragment, + &state->response_blob, + &mdscli_ctx->mdscmd_cmd.unkn9); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, mdscli_get_path_done, req); + mdscli_ctx->async_pending++; + return req; +} + +static void mdscli_get_path_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct mdscli_get_path_state *state = tevent_req_data( + req, struct mdscli_get_path_state); + DALLOC_CTX *d = NULL; + char *path = NULL; + NTSTATUS status; + bool ok; + + status = dcerpc_mdssvc_cmd_recv(subreq, state); + TALLOC_FREE(subreq); + state->mdscli_ctx->async_pending--; + if (tevent_req_nterror(req, status)) { + return; + } + + d = dalloc_new(state); + if (tevent_req_nomem(d, req)) { + return; + } + + ok = sl_unpack(d, + (char *)state->response_blob.spotlight_blob, + state->response_blob.length); + if (!ok) { + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return; + } + + path = dalloc_get(d, + "DALLOC_CTX", 0, + "DALLOC_CTX", 2, + "DALLOC_CTX", 0, + "DALLOC_CTX", 1, + "char *", 0); + if (path == NULL) { + DBG_DEBUG("No path in mds reponse: %s", dalloc_dump(d, 0)); + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return; + } + state->path = talloc_move(state, &path); + DBG_DEBUG("path: %s\n", state->path); + + tevent_req_done(req); + return; +} + +NTSTATUS mdscli_get_path_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + char **path) +{ + struct mdscli_get_path_state *state = tevent_req_data( + req, struct mdscli_get_path_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + + *path = talloc_move(mem_ctx, &state->path); + tevent_req_received(req); + return NT_STATUS_OK; +} + +NTSTATUS mdscli_get_path(TALLOC_CTX *mem_ctx, + struct mdscli_ctx *mdscli_ctx, + uint64_t cnid, + char **path) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct tevent_req *req = NULL; + struct tevent_context *ev = NULL; + NTSTATUS status = NT_STATUS_NO_MEMORY; + + if (mdscli_ctx->async_pending != 0) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + ev = samba_tevent_context_init(frame); + if (ev == NULL) { + goto fail; + } + + req = mdscli_get_path_send(frame, ev, mdscli_ctx, cnid); + if (req == NULL) { + goto fail; + } + if (!tevent_req_poll_ntstatus(req, ev, &status)) { + goto fail; + } + + status = mdscli_get_path_recv(req, mem_ctx, path); +fail: + TALLOC_FREE(frame); + return status; +} + +struct mdscli_close_search_state { + struct mdscli_search_ctx *search; + struct mdssvc_blob request_blob; + struct mdssvc_blob response_blob; +}; + +static void mdscli_close_search_done(struct tevent_req *subreq); + +struct tevent_req *mdscli_close_search_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct mdscli_search_ctx **search) +{ + struct mdscli_ctx *mdscli_ctx = NULL; + struct tevent_req *req = NULL; + struct mdscli_close_search_state *state = NULL; + struct tevent_req *subreq = NULL; + NTSTATUS status; + + req = tevent_req_create(req, &state, struct mdscli_close_search_state); + if (req == NULL) { + return NULL; + } + *state = (struct mdscli_close_search_state) { + .search = talloc_move(state, search), + }; + mdscli_ctx = state->search->mdscli_ctx; + + status = mdscli_blob_close_search(state, + state->search, + &state->request_blob); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + state->response_blob.spotlight_blob = talloc_array( + state, + uint8_t, + mdscli_ctx->max_fragment_size); + if (tevent_req_nomem(state->response_blob.spotlight_blob, req)) { + return tevent_req_post(req, ev); + } + state->response_blob.size = mdscli_ctx->max_fragment_size; + + subreq = dcerpc_mdssvc_cmd_send(state, + ev, + mdscli_ctx->bh, + mdscli_ctx->ph, + 0, + mdscli_ctx->dev, + mdscli_ctx->mdscmd_open.unkn2, + 0, + mdscli_ctx->flags, + state->request_blob, + 0, + mdscli_ctx->max_fragment_size, + 1, + mdscli_ctx->max_fragment_size, + 0, + 0, + &mdscli_ctx->mdscmd_cmd.fragment, + &state->response_blob, + &mdscli_ctx->mdscmd_cmd.unkn9); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, mdscli_close_search_done, req); + mdscli_ctx->async_pending++; + return req; +} + +static void mdscli_close_search_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct mdscli_close_search_state *state = tevent_req_data( + req, struct mdscli_close_search_state); + NTSTATUS status; + + status = dcerpc_mdssvc_cmd_recv(subreq, state); + TALLOC_FREE(subreq); + state->search->mdscli_ctx->async_pending--; + if (tevent_req_nterror(req, status)) { + return; + } + + tevent_req_done(req); + return; +} + +NTSTATUS mdscli_close_search_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +NTSTATUS mdscli_close_search(struct mdscli_search_ctx **search) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct tevent_req *req = NULL; + struct tevent_context *ev = NULL; + NTSTATUS status = NT_STATUS_NO_MEMORY; + + if ((*search)->mdscli_ctx->async_pending != 0) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + ev = samba_tevent_context_init(frame); + if (ev == NULL) { + goto fail; + } + + req = mdscli_close_search_send(frame, ev, search); + if (req == NULL) { + goto fail; + } + if (!tevent_req_poll_ntstatus(req, ev, &status)) { + goto fail; + } + + status = mdscli_close_search_recv(req); +fail: + TALLOC_FREE(frame); + return status; +} + +struct mdscli_disconnect_state { + struct mdscli_ctx *mdscli_ctx; +}; + +static void mdscli_disconnect_done(struct tevent_req *subreq); + +struct tevent_req *mdscli_disconnect_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct mdscli_ctx *mdscli_ctx) +{ + struct tevent_req *req = NULL; + struct mdscli_disconnect_state *state = NULL; + struct tevent_req *subreq = NULL; + + req = tevent_req_create(req, &state, struct mdscli_disconnect_state); + if (req == NULL) { + return NULL; + } + *state = (struct mdscli_disconnect_state) { + .mdscli_ctx = mdscli_ctx, + }; + + subreq = dcerpc_mdssvc_close_send(state, + ev, + mdscli_ctx->bh, + mdscli_ctx->ph, + 0, + mdscli_ctx->dev, + mdscli_ctx->mdscmd_open.unkn2, + 0, + &mdscli_ctx->ph, + &mdscli_ctx->mdscmd_close.status); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, mdscli_disconnect_done, req); + mdscli_ctx->async_pending++; + return req; +} + +static void mdscli_disconnect_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct mdscli_disconnect_state *state = tevent_req_data( + req, struct mdscli_disconnect_state); + NTSTATUS status; + + status = dcerpc_mdssvc_close_recv(subreq, state); + TALLOC_FREE(subreq); + state->mdscli_ctx->async_pending--; + if (tevent_req_nterror(req, status)) { + return; + } + + tevent_req_done(req); + return; +} + +NTSTATUS mdscli_disconnect_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +NTSTATUS mdscli_disconnect(struct mdscli_ctx *mdscli_ctx) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct tevent_req *req = NULL; + struct tevent_context *ev = NULL; + NTSTATUS status = NT_STATUS_NO_MEMORY; + + if (mdscli_ctx->async_pending != 0) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + ev = samba_tevent_context_init(frame); + if (ev == NULL) { + goto fail; + } + + req = mdscli_disconnect_send(frame, ev, mdscli_ctx); + if (req == NULL) { + goto fail; + } + if (!tevent_req_poll_ntstatus(req, ev, &status)) { + goto fail; + } + + status = mdscli_disconnect_recv(req); +fail: + TALLOC_FREE(frame); + return status; +} diff --git a/source3/rpc_client/cli_mdssvc.h b/source3/rpc_client/cli_mdssvc.h new file mode 100644 index 00000000000..f8b15826b57 --- /dev/null +++ b/source3/rpc_client/cli_mdssvc.h @@ -0,0 +1,97 @@ +/* + Unix SMB/CIFS implementation. + mdssvc client functions + + Copyright (C) Ralph Boehme 2019 + + 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 . +*/ + +#ifndef _MDSCLI_H_ +#define _MDSCLI_H_ + +struct mdscli_ctx; +struct mdscli_search_ctx; + +struct mdsctx_id mdscli_new_ctx_id(struct mdscli_ctx *mdscli_ctx); +char *mdscli_get_basepath(TALLOC_CTX *mem_ctx, + struct mdscli_ctx *mdscli_ctx); +struct mdscli_ctx *mdscli_search_get_ctx(struct mdscli_search_ctx *search); + +struct tevent_req *mdscli_connect_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct dcerpc_binding_handle *bh, + const char *share_name, + const char *mount_path); +NTSTATUS mdscli_connect_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct mdscli_ctx **mdscli_ctx); +NTSTATUS mdscli_connect(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *bh, + const char *share_name, + const char *mount_path, + struct mdscli_ctx **mdscli_ctx); + +struct tevent_req *mdscli_search_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct mdscli_ctx *mdscli_ctx, + const char *mds_query, + const char *path_scope, + bool live); +NTSTATUS mdscli_search_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct mdscli_search_ctx **search); +NTSTATUS mdscli_search(TALLOC_CTX *mem_ctx, + struct mdscli_ctx *mdscli_ctx, + const char *mds_query, + const char *path_scope, + bool live, + struct mdscli_search_ctx **search); + +struct tevent_req *mdscli_get_results_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct mdscli_search_ctx *search); +NTSTATUS mdscli_get_results_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + uint64_t **cnids); +NTSTATUS mdscli_get_results(TALLOC_CTX *mem_ctx, + struct mdscli_search_ctx *search, + uint64_t **_cnids); + +struct tevent_req *mdscli_get_path_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct mdscli_ctx *mdscli_ctx, + uint64_t cnid); +NTSTATUS mdscli_get_path_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + char **path); +NTSTATUS mdscli_get_path(TALLOC_CTX *mem_ctx, + struct mdscli_ctx *mdscli_ctx, + uint64_t cnid, + char **path); + +struct tevent_req *mdscli_close_search_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct mdscli_search_ctx **_search); +NTSTATUS mdscli_close_search_recv(struct tevent_req *req); +NTSTATUS mdscli_close_search(struct mdscli_search_ctx **search); + +struct tevent_req *mdscli_disconnect_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct mdscli_ctx *mdscli_ctx); +NTSTATUS mdscli_disconnect_recv(struct tevent_req *req); +NTSTATUS mdscli_disconnect(struct mdscli_ctx *mdscli_ctx); + +#endif /* _MDSCLI_H_ */ diff --git a/source3/rpc_client/cli_mdssvc_private.h b/source3/rpc_client/cli_mdssvc_private.h new file mode 100644 index 00000000000..031af85bf58 --- /dev/null +++ b/source3/rpc_client/cli_mdssvc_private.h @@ -0,0 +1,70 @@ +/* + Unix SMB/CIFS implementation. + mdssvc client functions + + Copyright (C) Ralph Boehme 2019 + + 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 . +*/ + +#ifndef _MDSCLI_PRIVATE_H_ +#define _MDSCLI_PRIVATE_H_ + +struct mdsctx_id { + uint64_t id; + uint64_t connection; +}; + +struct mdscli_ctx { + uint64_t async_pending; + + struct dcerpc_binding_handle *bh; + struct policy_handle ph; + + struct mdsctx_id ctx_id; + size_t max_fragment_size; + + /* Known fields used across multiple commands */ + uint32_t dev; + uint32_t flags; + + /* cmd specific or unknown fields */ + struct { + char share_path[1025]; + uint32_t unkn2; + uint32_t unkn3; + } mdscmd_open; + struct { + uint32_t status; + uint32_t unkn7; + } mdscmd_unknown1; + struct { + uint32_t fragment; + uint32_t unkn9; + } mdscmd_cmd; + struct { + uint32_t status; + } mdscmd_close; +}; + +struct mdscli_search_ctx { + struct mdscli_ctx *mdscli_ctx; + struct mdsctx_id ctx_id; + uint64_t unique_id; + bool live; + char *path_scope; + char *mds_query; +}; + +#endif /* _MDSCLI_PRIVATE_H_ */ diff --git a/source3/rpc_client/cli_mdssvc_util.c b/source3/rpc_client/cli_mdssvc_util.c new file mode 100644 index 00000000000..fe5092c3790 --- /dev/null +++ b/source3/rpc_client/cli_mdssvc_util.c @@ -0,0 +1,531 @@ +/* + Unix SMB/CIFS implementation. + Main metadata server / Spotlight client functions + + Copyright (C) Ralph Boehme 2019 + + 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 "rpc_client.h" +#include "librpc/gen_ndr/mdssvc.h" +#include "cli_mdssvc.h" +#include "cli_mdssvc_private.h" +#include "cli_mdssvc_util.h" +#include "lib/util/tevent_ntstatus.h" +#include "rpc_server/mdssvc/dalloc.h" +#include "rpc_server/mdssvc/marshalling.h" + +NTSTATUS mdscli_blob_search(TALLOC_CTX *mem_ctx, + struct mdscli_search_ctx *search, + struct mdssvc_blob *blob) +{ + struct mdscli_ctx *ctx = search->mdscli_ctx; + DALLOC_CTX *d = NULL; + uint64_t *uint64p = NULL; + sl_array_t *array = NULL; + sl_array_t *cmd_array = NULL; + sl_dict_t *query_dict = NULL; + sl_array_t *attr_array = NULL; + sl_array_t *scope_array = NULL; + double dval; + uint64_t uint64val; + ssize_t len; + int ret; + + d = dalloc_new(mem_ctx); + if (d == NULL) { + return NT_STATUS_NO_MEMORY; + } + + array = dalloc_zero(d, sl_array_t); + if (array == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_add(d, array, sl_array_t); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + cmd_array = dalloc_zero(d, sl_array_t); + if (cmd_array == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_add(array, cmd_array, sl_array_t); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_stradd(cmd_array, "openQueryWithParams:forContext:"); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + uint64p = talloc_zero_array(cmd_array, uint64_t, 2); + if (uint64p == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + talloc_set_name(uint64p, "uint64_t *"); + + uint64p[0] = search->ctx_id.id; + uint64p[1] = search->ctx_id.connection; + + ret = dalloc_add(cmd_array, uint64p, uint64_t *); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + query_dict = dalloc_zero(array, sl_dict_t); + if (query_dict == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_add(array, query_dict, sl_dict_t); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_stradd(query_dict, "kMDQueryBatchFirstDelay"); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + dval = 1; + ret = dalloc_add_copy(query_dict, &dval, double); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_stradd(query_dict, "kMDQueryUniqueId"); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + ret = dalloc_add_copy(query_dict, &search->unique_id, uint64_t); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_stradd(query_dict, "kMDAttributeArray"); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + attr_array = dalloc_zero(query_dict, sl_array_t); + if (attr_array == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + ret = dalloc_add(query_dict, attr_array, sl_array_t); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + ret = dalloc_stradd(attr_array, "kMDItemFSName"); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_stradd(query_dict, "kMDQueryBatchFirstCount"); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + uint64val = 10; + ret = dalloc_add_copy(query_dict, &uint64val, uint64_t); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_stradd(query_dict, "kMDQueryBatchUpdateCount"); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + uint64val = 100; + ret = dalloc_add_copy(query_dict, &uint64val, uint64_t); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_stradd(query_dict, "kMDQueryString"); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + ret = dalloc_stradd(query_dict, search->mds_query); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_stradd(query_dict, "kMDScopeArray"); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + scope_array = dalloc_zero(query_dict, sl_array_t); + if (scope_array == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + ret = dalloc_add(query_dict, scope_array, sl_array_t); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + ret = dalloc_stradd(scope_array, search->path_scope); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + blob->spotlight_blob = talloc_array(d, + uint8_t, + ctx->max_fragment_size); + if (blob->spotlight_blob == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + blob->size = ctx->max_fragment_size; + + len = sl_pack(d, (char *)blob->spotlight_blob, blob->size); + TALLOC_FREE(d); + if (len == -1) { + return NT_STATUS_NO_MEMORY; + } + + blob->length = len; + blob->size = len; + return NT_STATUS_OK; +} + +NTSTATUS mdscli_blob_get_results(TALLOC_CTX *mem_ctx, + struct mdscli_search_ctx *search, + struct mdssvc_blob *blob) +{ + struct mdscli_ctx *ctx = search->mdscli_ctx; + DALLOC_CTX *d = NULL; + uint64_t *uint64p = NULL; + sl_array_t *array = NULL; + sl_array_t *cmd_array = NULL; + ssize_t len; + int ret; + + d = dalloc_new(mem_ctx); + if (d == NULL) { + return NT_STATUS_NO_MEMORY; + } + + array = dalloc_zero(d, sl_array_t); + if (array == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_add(d, array, sl_array_t); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + cmd_array = dalloc_zero(d, sl_array_t); + if (cmd_array == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_add(array, cmd_array, sl_array_t); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_stradd(cmd_array, "fetchQueryResultsForContext:"); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + uint64p = talloc_zero_array(cmd_array, uint64_t, 2); + if (uint64p == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + talloc_set_name(uint64p, "uint64_t *"); + + uint64p[0] = search->ctx_id.id; + uint64p[1] = search->ctx_id.connection; + + ret = dalloc_add(cmd_array, uint64p, uint64_t *); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + blob->spotlight_blob = talloc_array(d, + uint8_t, + ctx->max_fragment_size); + if (blob->spotlight_blob == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + blob->size = ctx->max_fragment_size; + + len = sl_pack(d, (char *)blob->spotlight_blob, blob->size); + TALLOC_FREE(d); + if (len == -1) { + return NT_STATUS_NO_MEMORY; + } + + blob->length = len; + blob->size = len; + return NT_STATUS_OK; +} + +NTSTATUS mdscli_blob_get_path(TALLOC_CTX *mem_ctx, + struct mdscli_ctx *ctx, + uint64_t cnid, + struct mdssvc_blob *blob) +{ + struct mdsctx_id ctx_id = mdscli_new_ctx_id(ctx); + DALLOC_CTX *d = NULL; + uint64_t *uint64var = NULL; + sl_array_t *array = NULL; + sl_array_t *cmd_array = NULL; + sl_array_t *attr_array = NULL; + sl_cnids_t *cnids = NULL; + ssize_t len; + int ret; + + d = dalloc_new(mem_ctx); + if (d == NULL) { + return NT_STATUS_NO_MEMORY; + } + + array = dalloc_zero(d, sl_array_t); + if (array == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_add(d, array, sl_array_t); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + cmd_array = dalloc_zero(d, sl_array_t); + if (cmd_array == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_add(array, cmd_array, sl_array_t); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_stradd(cmd_array, "fetchAttributes:forOIDArray:context:"); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + uint64var = talloc_zero_array(cmd_array, uint64_t, 2); + if (uint64var == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + talloc_set_name(uint64var, "uint64_t *"); + + uint64var[0] = ctx_id.id; + uint64var[1] = 0; + + ret = dalloc_add(cmd_array, &uint64var[0], uint64_t *); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + attr_array = dalloc_zero(d, sl_array_t); + if (attr_array == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_add(array, attr_array, sl_array_t); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_stradd(attr_array, "kMDItemPath"); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + /* CNIDs */ + cnids = talloc_zero(array, sl_cnids_t); + if (cnids == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + cnids->ca_cnids = dalloc_new(cnids); + if (cnids->ca_cnids == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + cnids->ca_unkn1 = 0xadd; + cnids->ca_context = 0x6b000020; + + ret = dalloc_add_copy(cnids->ca_cnids, &cnid, uint64_t); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_add(array, cnids, sl_cnids_t); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + blob->spotlight_blob = talloc_array(d, + uint8_t, + ctx->max_fragment_size); + if (blob->spotlight_blob == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + blob->size = ctx->max_fragment_size; + + len = sl_pack(d, (char *)blob->spotlight_blob, blob->size); + TALLOC_FREE(d); + if (len == -1) { + return NT_STATUS_NO_MEMORY; + } + + blob->length = len; + blob->size = len; + return NT_STATUS_OK; +} + +NTSTATUS mdscli_blob_close_search(TALLOC_CTX *mem_ctx, + struct mdscli_search_ctx *search, + struct mdssvc_blob *blob) +{ + struct mdscli_ctx *ctx = search->mdscli_ctx; + DALLOC_CTX *d = NULL; + uint64_t *uint64p = NULL; + sl_array_t *array = NULL; + sl_array_t *cmd_array = NULL; + ssize_t len; + int ret; + + d = dalloc_new(mem_ctx); + if (d == NULL) { + return NT_STATUS_NO_MEMORY; + } + + array = dalloc_zero(d, sl_array_t); + if (array == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_add(d, array, sl_array_t); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + cmd_array = dalloc_zero(d, sl_array_t); + if (cmd_array == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_add(array, cmd_array, sl_array_t); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + ret = dalloc_stradd(cmd_array, "closeQueryForContext:"); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + uint64p = talloc_zero_array(cmd_array, uint64_t, 2); + if (uint64p == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + talloc_set_name(uint64p, "uint64_t *"); + + uint64p[0] = search->ctx_id.id; + uint64p[1] = search->ctx_id.connection; + + ret = dalloc_add(cmd_array, uint64p, uint64_t *); + if (ret != 0) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + + blob->spotlight_blob = talloc_array(d, + uint8_t, + ctx->max_fragment_size); + if (blob->spotlight_blob == NULL) { + TALLOC_FREE(d); + return NT_STATUS_NO_MEMORY; + } + blob->size = ctx->max_fragment_size; + + len = sl_pack(d, (char *)blob->spotlight_blob, blob->size); + TALLOC_FREE(d); + if (len == -1) { + return NT_STATUS_NO_MEMORY; + } + + blob->length = len; + blob->size = len; + return NT_STATUS_OK; +} diff --git a/source3/rpc_client/cli_mdssvc_util.h b/source3/rpc_client/cli_mdssvc_util.h new file mode 100644 index 00000000000..7a98c854526 --- /dev/null +++ b/source3/rpc_client/cli_mdssvc_util.h @@ -0,0 +1,41 @@ +/* + Unix SMB/CIFS implementation. + Main metadata server / Spotlight client functions + + Copyright (C) Ralph Boehme 2019 + + 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 . +*/ + +#ifndef _MDSCLI_UTIL_H_ +#define _MDSCLI_UTIL_H_ + +NTSTATUS mdscli_blob_search(TALLOC_CTX *mem_ctx, + struct mdscli_search_ctx *search, + struct mdssvc_blob *blob); + +NTSTATUS mdscli_blob_get_results(TALLOC_CTX *mem_ctx, + struct mdscli_search_ctx *search, + struct mdssvc_blob *blob); + +NTSTATUS mdscli_blob_get_path(TALLOC_CTX *mem_ctx, + struct mdscli_ctx *mdscli_ctx, + uint64_t cnid, + struct mdssvc_blob *blob); + +NTSTATUS mdscli_blob_close_search(TALLOC_CTX *mem_ctx, + struct mdscli_search_ctx *search, + struct mdssvc_blob *blob); + +#endif /* _MDSCLI_UTIL_H_ */ diff --git a/source3/wscript_build b/source3/wscript_build index 6707b4bb146..51d24ee4098 100644 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -1053,6 +1053,13 @@ bld.SAMBA3_SUBSYSTEM('RPC_CLIENT_SCHANNEL', source='rpc_client/cli_pipe_schannel.c', deps='samba-util krb5samba') +bld.SAMBA3_SUBSYSTEM('RPCCLI_MDSSVC', + source=''' + rpc_client/cli_mdssvc.c + rpc_client/cli_mdssvc_util.c + ''', + deps='mdssvc RPC_NDR_MDSSVC') + bld.SAMBA3_SUBSYSTEM('INIT_LSA', source='rpc_client/init_lsa.c', deps='samba-util')