1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-07 17:18:11 +03:00
samba-mirror/source3/rpc_client/cli_mdssvc.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1215 lines
29 KiB
C
Raw Normal View History

/*
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 <http://www.gnu.org/licenses/>.
*/
#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;
CVE-2023-34968: mdscli: return share relative paths The next commit will change the Samba Spotlight server to return absolute paths that start with the sharename as "/SHARENAME/..." followed by the share path relative appended. So given a share [spotlight] path = /foo/bar spotlight = yes and a file inside this share with a full path of /foo/bar/dir/file previously a search that matched this file would returns the absolute server-side pato of the file, ie /foo/bar/dir/file This will be change to /spotlight/dir/file As currently the mdscli library and hence the mdsearch tool print out these paths returned from the server, we have to change the output to accomodate these fake paths. The only way to do this sensibly is by makeing the paths relative to the containing share, so just dir/file in the example above. The client learns about the share root path prefix – real server-side of fake in the future – in an initial handshake in the "share_path" out argument of the mdssvc_open() RPC call, so the client can use this path to convert the absolute path to relative. There is however an additional twist: the macOS Spotlight server prefixes this absolute path with another prefix, typically "/System/Volumes/Data", so in the example above the full path for the same search would be /System/Volumes/Data/foo/bar/dir/file So macOS does return the full server-side path too, just prefixed with an additional path. This path prefixed can be queried by the client in the mdssvc_cmd() RPC call with an Spotlight command of "fetchPropertiesForContext:" and the path is returned in a dictionary with key "kMDSStorePathScopes". Samba just returns "/" for this. Currently the mdscli library doesn't issue this Spotlight RPC request (fetchPropertiesForContext), so this is added in this commit. In the end, all search result paths are stripped of the combined prefix kMDSStorePathScopes + share_path (from mdssvc_open). eg kMDSStorePathScopes = /System/Volumes/Data share_path = /foo/bar search result = /System/Volumes/Data/foo/bar/dir/file relative path returned by mdscli = dir/file Makes sense? :) BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
2023-06-17 14:53:27 +03:00
struct mdssvc_blob response_blob;
};
static void mdscli_connect_open_done(struct tevent_req *subreq);
static void mdscli_connect_unknown1_done(struct tevent_req *subreq);
CVE-2023-34968: mdscli: return share relative paths The next commit will change the Samba Spotlight server to return absolute paths that start with the sharename as "/SHARENAME/..." followed by the share path relative appended. So given a share [spotlight] path = /foo/bar spotlight = yes and a file inside this share with a full path of /foo/bar/dir/file previously a search that matched this file would returns the absolute server-side pato of the file, ie /foo/bar/dir/file This will be change to /spotlight/dir/file As currently the mdscli library and hence the mdsearch tool print out these paths returned from the server, we have to change the output to accomodate these fake paths. The only way to do this sensibly is by makeing the paths relative to the containing share, so just dir/file in the example above. The client learns about the share root path prefix – real server-side of fake in the future – in an initial handshake in the "share_path" out argument of the mdssvc_open() RPC call, so the client can use this path to convert the absolute path to relative. There is however an additional twist: the macOS Spotlight server prefixes this absolute path with another prefix, typically "/System/Volumes/Data", so in the example above the full path for the same search would be /System/Volumes/Data/foo/bar/dir/file So macOS does return the full server-side path too, just prefixed with an additional path. This path prefixed can be queried by the client in the mdssvc_cmd() RPC call with an Spotlight command of "fetchPropertiesForContext:" and the path is returned in a dictionary with key "kMDSStorePathScopes". Samba just returns "/" for this. Currently the mdscli library doesn't issue this Spotlight RPC request (fetchPropertiesForContext), so this is added in this commit. In the end, all search result paths are stripped of the combined prefix kMDSStorePathScopes + share_path (from mdssvc_open). eg kMDSStorePathScopes = /System/Volumes/Data share_path = /foo/bar search result = /System/Volumes/Data/foo/bar/dir/file relative path returned by mdscli = dir/file Makes sense? :) BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
2023-06-17 14:53:27 +03:00
static void mdscli_connect_fetch_props_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;
CVE-2023-34968: mdscli: return share relative paths The next commit will change the Samba Spotlight server to return absolute paths that start with the sharename as "/SHARENAME/..." followed by the share path relative appended. So given a share [spotlight] path = /foo/bar spotlight = yes and a file inside this share with a full path of /foo/bar/dir/file previously a search that matched this file would returns the absolute server-side pato of the file, ie /foo/bar/dir/file This will be change to /spotlight/dir/file As currently the mdscli library and hence the mdsearch tool print out these paths returned from the server, we have to change the output to accomodate these fake paths. The only way to do this sensibly is by makeing the paths relative to the containing share, so just dir/file in the example above. The client learns about the share root path prefix – real server-side of fake in the future – in an initial handshake in the "share_path" out argument of the mdssvc_open() RPC call, so the client can use this path to convert the absolute path to relative. There is however an additional twist: the macOS Spotlight server prefixes this absolute path with another prefix, typically "/System/Volumes/Data", so in the example above the full path for the same search would be /System/Volumes/Data/foo/bar/dir/file So macOS does return the full server-side path too, just prefixed with an additional path. This path prefixed can be queried by the client in the mdssvc_cmd() RPC call with an Spotlight command of "fetchPropertiesForContext:" and the path is returned in a dictionary with key "kMDSStorePathScopes". Samba just returns "/" for this. Currently the mdscli library doesn't issue this Spotlight RPC request (fetchPropertiesForContext), so this is added in this commit. In the end, all search result paths are stripped of the combined prefix kMDSStorePathScopes + share_path (from mdssvc_open). eg kMDSStorePathScopes = /System/Volumes/Data share_path = /foo/bar search result = /System/Volumes/Data/foo/bar/dir/file relative path returned by mdscli = dir/file Makes sense? :) BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
2023-06-17 14:53:27 +03:00
size_t share_path_len;
NTSTATUS status;
status = dcerpc_mdssvc_open_recv(subreq, state);
TALLOC_FREE(subreq);
state->mdscli_ctx->async_pending--;
if (tevent_req_nterror(req, status)) {
return;
}
CVE-2023-34968: mdscli: return share relative paths The next commit will change the Samba Spotlight server to return absolute paths that start with the sharename as "/SHARENAME/..." followed by the share path relative appended. So given a share [spotlight] path = /foo/bar spotlight = yes and a file inside this share with a full path of /foo/bar/dir/file previously a search that matched this file would returns the absolute server-side pato of the file, ie /foo/bar/dir/file This will be change to /spotlight/dir/file As currently the mdscli library and hence the mdsearch tool print out these paths returned from the server, we have to change the output to accomodate these fake paths. The only way to do this sensibly is by makeing the paths relative to the containing share, so just dir/file in the example above. The client learns about the share root path prefix – real server-side of fake in the future – in an initial handshake in the "share_path" out argument of the mdssvc_open() RPC call, so the client can use this path to convert the absolute path to relative. There is however an additional twist: the macOS Spotlight server prefixes this absolute path with another prefix, typically "/System/Volumes/Data", so in the example above the full path for the same search would be /System/Volumes/Data/foo/bar/dir/file So macOS does return the full server-side path too, just prefixed with an additional path. This path prefixed can be queried by the client in the mdssvc_cmd() RPC call with an Spotlight command of "fetchPropertiesForContext:" and the path is returned in a dictionary with key "kMDSStorePathScopes". Samba just returns "/" for this. Currently the mdscli library doesn't issue this Spotlight RPC request (fetchPropertiesForContext), so this is added in this commit. In the end, all search result paths are stripped of the combined prefix kMDSStorePathScopes + share_path (from mdssvc_open). eg kMDSStorePathScopes = /System/Volumes/Data share_path = /foo/bar search result = /System/Volumes/Data/foo/bar/dir/file relative path returned by mdscli = dir/file Makes sense? :) BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
2023-06-17 14:53:27 +03:00
share_path_len = strlen(mdscli_ctx->mdscmd_open.share_path);
if (share_path_len < 1 || share_path_len > UINT16_MAX) {
tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
return;
}
mdscli_ctx->mdscmd_open.share_path_len = share_path_len;
if (mdscli_ctx->mdscmd_open.share_path[share_path_len-1] == '/') {
mdscli_ctx->mdscmd_open.share_path[share_path_len-1] = '\0';
mdscli_ctx->mdscmd_open.share_path_len--;
}
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);
CVE-2023-34968: mdscli: return share relative paths The next commit will change the Samba Spotlight server to return absolute paths that start with the sharename as "/SHARENAME/..." followed by the share path relative appended. So given a share [spotlight] path = /foo/bar spotlight = yes and a file inside this share with a full path of /foo/bar/dir/file previously a search that matched this file would returns the absolute server-side pato of the file, ie /foo/bar/dir/file This will be change to /spotlight/dir/file As currently the mdscli library and hence the mdsearch tool print out these paths returned from the server, we have to change the output to accomodate these fake paths. The only way to do this sensibly is by makeing the paths relative to the containing share, so just dir/file in the example above. The client learns about the share root path prefix – real server-side of fake in the future – in an initial handshake in the "share_path" out argument of the mdssvc_open() RPC call, so the client can use this path to convert the absolute path to relative. There is however an additional twist: the macOS Spotlight server prefixes this absolute path with another prefix, typically "/System/Volumes/Data", so in the example above the full path for the same search would be /System/Volumes/Data/foo/bar/dir/file So macOS does return the full server-side path too, just prefixed with an additional path. This path prefixed can be queried by the client in the mdssvc_cmd() RPC call with an Spotlight command of "fetchPropertiesForContext:" and the path is returned in a dictionary with key "kMDSStorePathScopes". Samba just returns "/" for this. Currently the mdscli library doesn't issue this Spotlight RPC request (fetchPropertiesForContext), so this is added in this commit. In the end, all search result paths are stripped of the combined prefix kMDSStorePathScopes + share_path (from mdssvc_open). eg kMDSStorePathScopes = /System/Volumes/Data share_path = /foo/bar search result = /System/Volumes/Data/foo/bar/dir/file relative path returned by mdscli = dir/file Makes sense? :) BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
2023-06-17 14:53:27 +03:00
struct mdscli_ctx *mdscli_ctx = state->mdscli_ctx;
struct mdssvc_blob request_blob;
NTSTATUS status;
status = dcerpc_mdssvc_unknown1_recv(subreq, state);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
CVE-2023-34968: mdscli: return share relative paths The next commit will change the Samba Spotlight server to return absolute paths that start with the sharename as "/SHARENAME/..." followed by the share path relative appended. So given a share [spotlight] path = /foo/bar spotlight = yes and a file inside this share with a full path of /foo/bar/dir/file previously a search that matched this file would returns the absolute server-side pato of the file, ie /foo/bar/dir/file This will be change to /spotlight/dir/file As currently the mdscli library and hence the mdsearch tool print out these paths returned from the server, we have to change the output to accomodate these fake paths. The only way to do this sensibly is by makeing the paths relative to the containing share, so just dir/file in the example above. The client learns about the share root path prefix – real server-side of fake in the future – in an initial handshake in the "share_path" out argument of the mdssvc_open() RPC call, so the client can use this path to convert the absolute path to relative. There is however an additional twist: the macOS Spotlight server prefixes this absolute path with another prefix, typically "/System/Volumes/Data", so in the example above the full path for the same search would be /System/Volumes/Data/foo/bar/dir/file So macOS does return the full server-side path too, just prefixed with an additional path. This path prefixed can be queried by the client in the mdssvc_cmd() RPC call with an Spotlight command of "fetchPropertiesForContext:" and the path is returned in a dictionary with key "kMDSStorePathScopes". Samba just returns "/" for this. Currently the mdscli library doesn't issue this Spotlight RPC request (fetchPropertiesForContext), so this is added in this commit. In the end, all search result paths are stripped of the combined prefix kMDSStorePathScopes + share_path (from mdssvc_open). eg kMDSStorePathScopes = /System/Volumes/Data share_path = /foo/bar search result = /System/Volumes/Data/foo/bar/dir/file relative path returned by mdscli = dir/file Makes sense? :) BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
2023-06-17 14:53:27 +03:00
status = mdscli_blob_fetch_props(state,
state->mdscli_ctx,
&request_blob);
if (tevent_req_nterror(req, status)) {
return;
}
subreq = dcerpc_mdssvc_cmd_send(state,
state->ev,
mdscli_ctx->bh,
&mdscli_ctx->ph,
0,
mdscli_ctx->dev,
mdscli_ctx->mdscmd_open.unkn2,
0,
mdscli_ctx->flags,
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_set_callback(subreq, mdscli_connect_fetch_props_done, req);
mdscli_ctx->async_pending++;
return;
}
static void mdscli_connect_fetch_props_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;
DALLOC_CTX *d = NULL;
sl_array_t *path_scope_array = NULL;
char *path_scope = 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_scope_array = dalloc_value_for_key(d,
"DALLOC_CTX", 0,
"kMDSStorePathScopes",
"sl_array_t");
if (path_scope_array == NULL) {
DBG_ERR("Missing kMDSStorePathScopes\n");
tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
return;
}
path_scope = dalloc_get(path_scope_array, "char *", 0);
if (path_scope == NULL) {
DBG_ERR("Missing path in kMDSStorePathScopes\n");
tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
return;
}
mdscli_ctx->path_scope_len = strlen(path_scope);
if (mdscli_ctx->path_scope_len < 1 ||
mdscli_ctx->path_scope_len > UINT16_MAX)
{
DBG_ERR("Bad path_scope: %s\n", path_scope);
tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
return;
}
mdscli_ctx->path_scope = talloc_strdup(mdscli_ctx, path_scope);
if (tevent_req_nomem(mdscli_ctx->path_scope, req)) {
return;
}
if (mdscli_ctx->path_scope[mdscli_ctx->path_scope_len-1] == '/') {
mdscli_ctx->path_scope[mdscli_ctx->path_scope_len-1] = '\0';
mdscli_ctx->path_scope_len--;
}
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);
}
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 response: %s", dalloc_dump(d, 0));
tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
return;
}
if (*uint64p != 0) {
DBG_DEBUG("Unexpected mds result: 0x%" PRIx64 "\n", *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 tevent_context *ev;
struct mdscli_search_ctx *search;
struct mdssvc_blob request_blob;
struct mdssvc_blob response_fragment;
DATA_BLOB response_data;
uint64_t *cnids;
uint32_t fragment;
};
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) {
.ev = ev,
.search = search,
};
status = mdscli_blob_get_results(state,
search,
&state->request_blob);
if (tevent_req_nterror(req, status)) {
return tevent_req_post(req, ev);
}
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,
&state->fragment,
&state->response_fragment,
&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);
struct mdscli_ctx *mdscli_ctx = state->search->mdscli_ctx;
size_t oldsize, newsize;
DALLOC_CTX *d = NULL;
uint64_t *uint64p = NULL;
bool search_in_progress = false;
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;
}
oldsize = state->response_data.length;
newsize = oldsize + state->response_fragment.length;
if (newsize < oldsize) {
tevent_req_nterror(req, NT_STATUS_INTEGER_OVERFLOW);
return;
}
ok = data_blob_realloc(state, &state->response_data, newsize);
if (!ok) {
tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
(void)memcpy(state->response_data.data + oldsize,
state->response_fragment.spotlight_blob,
state->response_fragment.length);
TALLOC_FREE(state->response_fragment.spotlight_blob);
state->response_fragment.length = 0;
state->response_fragment.size = 0;
if (state->fragment != 0) {
subreq = dcerpc_mdssvc_cmd_send(
state,
state->ev,
mdscli_ctx->bh,
&mdscli_ctx->ph,
0,
mdscli_ctx->dev,
mdscli_ctx->mdscmd_open.unkn2,
1,
mdscli_ctx->flags,
state->request_blob,
0,
mdscli_ctx->max_fragment_size,
1,
mdscli_ctx->max_fragment_size,
0,
0,
&state->fragment,
&state->response_fragment,
&mdscli_ctx->mdscmd_cmd.unkn9);
if (tevent_req_nomem(subreq, req)) {
tevent_req_post(req, state->ev);
return;
}
tevent_req_set_callback(subreq,
mdscli_get_results_cmd_done,
req);
mdscli_ctx->async_pending++;
return;
}
d = dalloc_new(state);
if (tevent_req_nomem(d, req)) {
return;
}
ok = sl_unpack(d,
(char *)state->response_data.data,
state->response_data.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 response: %s", dalloc_dump(d, 0));
tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
return;
}
if (*uint64p == 35) {
DBG_DEBUG("Search in progress\n");
search_in_progress = true;
}
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 && !search_in_progress) {
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);
}
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;
CVE-2023-34968: mdscli: return share relative paths The next commit will change the Samba Spotlight server to return absolute paths that start with the sharename as "/SHARENAME/..." followed by the share path relative appended. So given a share [spotlight] path = /foo/bar spotlight = yes and a file inside this share with a full path of /foo/bar/dir/file previously a search that matched this file would returns the absolute server-side pato of the file, ie /foo/bar/dir/file This will be change to /spotlight/dir/file As currently the mdscli library and hence the mdsearch tool print out these paths returned from the server, we have to change the output to accomodate these fake paths. The only way to do this sensibly is by makeing the paths relative to the containing share, so just dir/file in the example above. The client learns about the share root path prefix – real server-side of fake in the future – in an initial handshake in the "share_path" out argument of the mdssvc_open() RPC call, so the client can use this path to convert the absolute path to relative. There is however an additional twist: the macOS Spotlight server prefixes this absolute path with another prefix, typically "/System/Volumes/Data", so in the example above the full path for the same search would be /System/Volumes/Data/foo/bar/dir/file So macOS does return the full server-side path too, just prefixed with an additional path. This path prefixed can be queried by the client in the mdssvc_cmd() RPC call with an Spotlight command of "fetchPropertiesForContext:" and the path is returned in a dictionary with key "kMDSStorePathScopes". Samba just returns "/" for this. Currently the mdscli library doesn't issue this Spotlight RPC request (fetchPropertiesForContext), so this is added in this commit. In the end, all search result paths are stripped of the combined prefix kMDSStorePathScopes + share_path (from mdssvc_open). eg kMDSStorePathScopes = /System/Volumes/Data share_path = /foo/bar search result = /System/Volumes/Data/foo/bar/dir/file relative path returned by mdscli = dir/file Makes sense? :) BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
2023-06-17 14:53:27 +03:00
size_t pathlen;
size_t prefixlen;
char *path = NULL;
CVE-2023-34968: mdscli: return share relative paths The next commit will change the Samba Spotlight server to return absolute paths that start with the sharename as "/SHARENAME/..." followed by the share path relative appended. So given a share [spotlight] path = /foo/bar spotlight = yes and a file inside this share with a full path of /foo/bar/dir/file previously a search that matched this file would returns the absolute server-side pato of the file, ie /foo/bar/dir/file This will be change to /spotlight/dir/file As currently the mdscli library and hence the mdsearch tool print out these paths returned from the server, we have to change the output to accomodate these fake paths. The only way to do this sensibly is by makeing the paths relative to the containing share, so just dir/file in the example above. The client learns about the share root path prefix – real server-side of fake in the future – in an initial handshake in the "share_path" out argument of the mdssvc_open() RPC call, so the client can use this path to convert the absolute path to relative. There is however an additional twist: the macOS Spotlight server prefixes this absolute path with another prefix, typically "/System/Volumes/Data", so in the example above the full path for the same search would be /System/Volumes/Data/foo/bar/dir/file So macOS does return the full server-side path too, just prefixed with an additional path. This path prefixed can be queried by the client in the mdssvc_cmd() RPC call with an Spotlight command of "fetchPropertiesForContext:" and the path is returned in a dictionary with key "kMDSStorePathScopes". Samba just returns "/" for this. Currently the mdscli library doesn't issue this Spotlight RPC request (fetchPropertiesForContext), so this is added in this commit. In the end, all search result paths are stripped of the combined prefix kMDSStorePathScopes + share_path (from mdssvc_open). eg kMDSStorePathScopes = /System/Volumes/Data share_path = /foo/bar search result = /System/Volumes/Data/foo/bar/dir/file relative path returned by mdscli = dir/file Makes sense? :) BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
2023-06-17 14:53:27 +03:00
const char *p = 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 response: %s", dalloc_dump(d, 0));
tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
return;
}
CVE-2023-34968: mdscli: return share relative paths The next commit will change the Samba Spotlight server to return absolute paths that start with the sharename as "/SHARENAME/..." followed by the share path relative appended. So given a share [spotlight] path = /foo/bar spotlight = yes and a file inside this share with a full path of /foo/bar/dir/file previously a search that matched this file would returns the absolute server-side pato of the file, ie /foo/bar/dir/file This will be change to /spotlight/dir/file As currently the mdscli library and hence the mdsearch tool print out these paths returned from the server, we have to change the output to accomodate these fake paths. The only way to do this sensibly is by makeing the paths relative to the containing share, so just dir/file in the example above. The client learns about the share root path prefix – real server-side of fake in the future – in an initial handshake in the "share_path" out argument of the mdssvc_open() RPC call, so the client can use this path to convert the absolute path to relative. There is however an additional twist: the macOS Spotlight server prefixes this absolute path with another prefix, typically "/System/Volumes/Data", so in the example above the full path for the same search would be /System/Volumes/Data/foo/bar/dir/file So macOS does return the full server-side path too, just prefixed with an additional path. This path prefixed can be queried by the client in the mdssvc_cmd() RPC call with an Spotlight command of "fetchPropertiesForContext:" and the path is returned in a dictionary with key "kMDSStorePathScopes". Samba just returns "/" for this. Currently the mdscli library doesn't issue this Spotlight RPC request (fetchPropertiesForContext), so this is added in this commit. In the end, all search result paths are stripped of the combined prefix kMDSStorePathScopes + share_path (from mdssvc_open). eg kMDSStorePathScopes = /System/Volumes/Data share_path = /foo/bar search result = /System/Volumes/Data/foo/bar/dir/file relative path returned by mdscli = dir/file Makes sense? :) BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
2023-06-17 14:53:27 +03:00
/* Path is prefixed by /PATHSCOPE/SHARENAME/, strip it */
pathlen = strlen(path);
/*
* path_scope_len and share_path_len are already checked to be smaller
* then UINT16_MAX so this can't overflow
*/
prefixlen = state->mdscli_ctx->path_scope_len
+ state->mdscli_ctx->mdscmd_open.share_path_len;
if (pathlen < prefixlen) {
DBG_DEBUG("Bad path: %s\n", path);
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
return;
}
p = path + prefixlen;
while (*p == '/') {
p++;
}
if (*p == '\0') {
DBG_DEBUG("Bad path: %s\n", path);
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
return;
}
state->path = talloc_strdup(state, p);
if (state->path == NULL) {
tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
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);
}
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;
}