2 Unix SMB/CIFS implementation.
3 Main metadata server / Spotlight client functions
5 Copyright (C) Ralph Boehme 2019
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "rpc_client.h"
23 #include "../librpc/gen_ndr/ndr_mdssvc_c.h"
24 #include "lib/util/tevent_ntstatus.h"
25 #include "rpc_server/mdssvc/dalloc.h"
26 #include "rpc_server/mdssvc/marshalling.h"
27 #include "cli_mdssvc.h"
28 #include "cli_mdssvc_private.h"
29 #include "cli_mdssvc_util.h"
31 struct mdsctx_id mdscli_new_ctx_id(struct mdscli_ctx *mdscli_ctx)
33 mdscli_ctx->ctx_id.id++;
34 return mdscli_ctx->ctx_id;
37 char *mdscli_get_basepath(TALLOC_CTX *mem_ctx,
38 struct mdscli_ctx *mdscli_ctx)
40 return talloc_strdup(mem_ctx, mdscli_ctx->mdscmd_open.share_path);
43 struct mdscli_connect_state {
44 struct tevent_context *ev;
45 struct mdscli_ctx *mdscli_ctx;
46 struct mdssvc_blob response_blob;
49 static void mdscli_connect_open_done(struct tevent_req *subreq);
50 static void mdscli_connect_unknown1_done(struct tevent_req *subreq);
51 static void mdscli_connect_fetch_props_done(struct tevent_req *subreq);
53 struct tevent_req *mdscli_connect_send(TALLOC_CTX *mem_ctx,
54 struct tevent_context *ev,
55 struct dcerpc_binding_handle *bh,
56 const char *share_name,
57 const char *mount_path)
59 struct tevent_req *req = NULL;
60 struct mdscli_connect_state *state = NULL;
61 struct tevent_req *subreq = NULL;
62 struct mdscli_ctx *ctx = NULL;
64 req = tevent_req_create(req, &state, struct mdscli_connect_state);
69 ctx = talloc_zero(state, struct mdscli_ctx);
70 if (tevent_req_nomem(ctx, req)) {
71 return tevent_req_post(req, ev);
74 *state = (struct mdscli_connect_state) {
79 *ctx = (struct mdscli_ctx) {
81 .max_fragment_size = 64 * 1024,
83 * The connection id is a per tcon value sent by the client,
84 * 0x6b000060 is a value used most of the times for the first
87 .ctx_id.connection = UINT64_C(0x6b000060),
90 subreq = dcerpc_mdssvc_open_send(state,
94 &ctx->mdscmd_open.unkn2,
95 &ctx->mdscmd_open.unkn3,
98 ctx->mdscmd_open.share_path,
100 if (tevent_req_nomem(subreq, req)) {
101 return tevent_req_post(req, state->ev);
103 tevent_req_set_callback(subreq, mdscli_connect_open_done, req);
104 ctx->async_pending++;
109 static void mdscli_connect_open_done(struct tevent_req *subreq)
111 struct tevent_req *req = tevent_req_callback_data(
112 subreq, struct tevent_req);
113 struct mdscli_connect_state *state = tevent_req_data(
114 req, struct mdscli_connect_state);
115 struct mdscli_ctx *mdscli_ctx = state->mdscli_ctx;
116 size_t share_path_len;
119 status = dcerpc_mdssvc_open_recv(subreq, state);
121 state->mdscli_ctx->async_pending--;
122 if (tevent_req_nterror(req, status)) {
126 share_path_len = strlen(mdscli_ctx->mdscmd_open.share_path);
127 if (share_path_len < 1 || share_path_len > UINT16_MAX) {
128 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
131 mdscli_ctx->mdscmd_open.share_path_len = share_path_len;
133 if (mdscli_ctx->mdscmd_open.share_path[share_path_len-1] == '/') {
134 mdscli_ctx->mdscmd_open.share_path[share_path_len-1] = '\0';
135 mdscli_ctx->mdscmd_open.share_path_len--;
138 subreq = dcerpc_mdssvc_unknown1_send(
145 mdscli_ctx->mdscmd_open.unkn2,
149 &mdscli_ctx->mdscmd_unknown1.status,
151 &mdscli_ctx->mdscmd_unknown1.unkn7);
152 if (tevent_req_nomem(subreq, req)) {
155 tevent_req_set_callback(subreq, mdscli_connect_unknown1_done, req);
158 static void mdscli_connect_unknown1_done(struct tevent_req *subreq)
160 struct tevent_req *req = tevent_req_callback_data(
161 subreq, struct tevent_req);
162 struct mdscli_connect_state *state = tevent_req_data(
163 req, struct mdscli_connect_state);
164 struct mdscli_ctx *mdscli_ctx = state->mdscli_ctx;
165 struct mdssvc_blob request_blob;
168 status = dcerpc_mdssvc_unknown1_recv(subreq, state);
170 if (tevent_req_nterror(req, status)) {
174 status = mdscli_blob_fetch_props(state,
177 if (tevent_req_nterror(req, status)) {
181 subreq = dcerpc_mdssvc_cmd_send(state,
187 mdscli_ctx->mdscmd_open.unkn2,
192 mdscli_ctx->max_fragment_size,
194 mdscli_ctx->max_fragment_size,
197 &mdscli_ctx->mdscmd_cmd.fragment,
198 &state->response_blob,
199 &mdscli_ctx->mdscmd_cmd.unkn9);
200 if (tevent_req_nomem(subreq, req)) {
203 tevent_req_set_callback(subreq, mdscli_connect_fetch_props_done, req);
204 mdscli_ctx->async_pending++;
208 static void mdscli_connect_fetch_props_done(struct tevent_req *subreq)
210 struct tevent_req *req = tevent_req_callback_data(
211 subreq, struct tevent_req);
212 struct mdscli_connect_state *state = tevent_req_data(
213 req, struct mdscli_connect_state);
214 struct mdscli_ctx *mdscli_ctx = state->mdscli_ctx;
215 DALLOC_CTX *d = NULL;
216 sl_array_t *path_scope_array = NULL;
217 char *path_scope = NULL;
221 status = dcerpc_mdssvc_cmd_recv(subreq, state);
223 state->mdscli_ctx->async_pending--;
224 if (tevent_req_nterror(req, status)) {
228 d = dalloc_new(state);
229 if (tevent_req_nomem(d, req)) {
234 (char *)state->response_blob.spotlight_blob,
235 state->response_blob.length);
237 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
241 path_scope_array = dalloc_value_for_key(d,
243 "kMDSStorePathScopes",
245 if (path_scope_array == NULL) {
246 DBG_ERR("Missing kMDSStorePathScopes\n");
247 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
251 path_scope = dalloc_get(path_scope_array, "char *", 0);
252 if (path_scope == NULL) {
253 DBG_ERR("Missing path in kMDSStorePathScopes\n");
254 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
258 mdscli_ctx->path_scope_len = strlen(path_scope);
259 if (mdscli_ctx->path_scope_len < 1 ||
260 mdscli_ctx->path_scope_len > UINT16_MAX)
262 DBG_ERR("Bad path_scope: %s\n", path_scope);
263 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
266 mdscli_ctx->path_scope = talloc_strdup(mdscli_ctx, path_scope);
267 if (tevent_req_nomem(mdscli_ctx->path_scope, req)) {
271 if (mdscli_ctx->path_scope[mdscli_ctx->path_scope_len-1] == '/') {
272 mdscli_ctx->path_scope[mdscli_ctx->path_scope_len-1] = '\0';
273 mdscli_ctx->path_scope_len--;
276 tevent_req_done(req);
279 NTSTATUS mdscli_connect_recv(struct tevent_req *req,
281 struct mdscli_ctx **mdscli_ctx)
283 struct mdscli_connect_state *state = tevent_req_data(
284 req, struct mdscli_connect_state);
287 if (tevent_req_is_nterror(req, &status)) {
288 tevent_req_received(req);
292 *mdscli_ctx = talloc_move(mem_ctx, &state->mdscli_ctx);
293 tevent_req_received(req);
297 NTSTATUS mdscli_connect(TALLOC_CTX *mem_ctx,
298 struct dcerpc_binding_handle *bh,
299 const char *share_name,
300 const char *mount_path,
301 struct mdscli_ctx **mdscli_ctx)
303 TALLOC_CTX *frame = talloc_stackframe();
304 struct tevent_req *req = NULL;
305 struct tevent_context *ev = NULL;
306 NTSTATUS status = NT_STATUS_NO_MEMORY;
308 ev = samba_tevent_context_init(frame);
313 req = mdscli_connect_send(frame,
321 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
325 status = mdscli_connect_recv(req, mem_ctx, mdscli_ctx);
331 struct mdscli_search_state {
332 struct mdscli_search_ctx *search;
333 struct mdssvc_blob request_blob;
334 struct mdssvc_blob response_blob;
337 static void mdscli_search_cmd_done(struct tevent_req *subreq);
339 struct tevent_req *mdscli_search_send(TALLOC_CTX *mem_ctx,
340 struct tevent_context *ev,
341 struct mdscli_ctx *mdscli_ctx,
342 const char *mds_query,
343 const char *path_scope_in,
346 struct tevent_req *req = NULL;
347 struct mdscli_search_state *state = NULL;
348 struct tevent_req *subreq = NULL;
349 struct mdscli_search_ctx *search = NULL;
350 char *path_scope = NULL;
353 req = tevent_req_create(req, &state, struct mdscli_search_state);
358 search = talloc_zero(state, struct mdscli_search_ctx);
359 if (tevent_req_nomem(search, req)) {
360 return tevent_req_post(req, ev);
363 if (path_scope_in[0] == '/') {
364 path_scope = talloc_strdup(search, path_scope_in);
366 path_scope = talloc_asprintf(search,
368 mdscli_ctx->mdscmd_open.share_path,
371 if (tevent_req_nomem(path_scope, req)) {
372 return tevent_req_post(req, ev);
375 *search = (struct mdscli_search_ctx) {
376 .mdscli_ctx = mdscli_ctx,
377 .ctx_id = mdscli_new_ctx_id(mdscli_ctx),
378 .unique_id = generate_random_u64(),
380 .path_scope = path_scope,
381 .mds_query = talloc_strdup(search, mds_query),
383 if (tevent_req_nomem(search->mds_query, req)) {
384 return tevent_req_post(req, ev);
387 *state = (struct mdscli_search_state) {
391 status = mdscli_blob_search(state,
393 &state->request_blob);
394 if (tevent_req_nterror(req, status)) {
395 return tevent_req_post(req, ev);
398 subreq = dcerpc_mdssvc_cmd_send(state,
404 mdscli_ctx->mdscmd_open.unkn2,
409 mdscli_ctx->max_fragment_size,
411 mdscli_ctx->max_fragment_size,
414 &mdscli_ctx->mdscmd_cmd.fragment,
415 &state->response_blob,
416 &mdscli_ctx->mdscmd_cmd.unkn9);
417 if (tevent_req_nomem(subreq, req)) {
418 return tevent_req_post(req, ev);
420 tevent_req_set_callback(subreq, mdscli_search_cmd_done, req);
421 mdscli_ctx->async_pending++;
425 static void mdscli_search_cmd_done(struct tevent_req *subreq)
427 struct tevent_req *req = tevent_req_callback_data(
428 subreq, struct tevent_req);
429 struct mdscli_search_state *state = tevent_req_data(
430 req, struct mdscli_search_state);
431 DALLOC_CTX *d = NULL;
432 uint64_t *uint64p = NULL;
436 status = dcerpc_mdssvc_cmd_recv(subreq, state);
438 state->search->mdscli_ctx->async_pending--;
439 if (tevent_req_nterror(req, status)) {
443 d = dalloc_new(state);
444 if (tevent_req_nomem(d, req)) {
449 (char *)state->response_blob.spotlight_blob,
450 state->response_blob.length);
452 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
456 uint64p = dalloc_get(d,
459 if (uint64p == NULL) {
460 DBG_DEBUG("Unexpected mds response: %s", dalloc_dump(d, 0));
461 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
466 DBG_DEBUG("Unexpected mds result: 0x%" PRIx64 "\n", *uint64p);
467 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
471 tevent_req_done(req);
475 NTSTATUS mdscli_search_recv(struct tevent_req *req,
477 struct mdscli_search_ctx **search)
479 struct mdscli_search_state *state = tevent_req_data(
480 req, struct mdscli_search_state);
483 if (tevent_req_is_nterror(req, &status)) {
484 tevent_req_received(req);
488 *search = talloc_move(mem_ctx, &state->search);
489 tevent_req_received(req);
493 NTSTATUS mdscli_search(TALLOC_CTX *mem_ctx,
494 struct mdscli_ctx *mdscli_ctx,
495 const char *mds_query,
496 const char *path_scope,
498 struct mdscli_search_ctx **search)
500 TALLOC_CTX *frame = talloc_stackframe();
501 struct tevent_req *req = NULL;
502 struct tevent_context *ev = NULL;
503 NTSTATUS status = NT_STATUS_NO_MEMORY;
505 if (mdscli_ctx->async_pending != 0) {
506 status = NT_STATUS_INVALID_PARAMETER;
510 ev = samba_tevent_context_init(frame);
515 req = mdscli_search_send(frame,
524 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
528 status = mdscli_search_recv(req, mem_ctx, search);
534 struct mdscli_get_results_state {
535 struct tevent_context *ev;
536 struct mdscli_search_ctx *search;
537 struct mdssvc_blob request_blob;
538 struct mdssvc_blob response_fragment;
539 DATA_BLOB response_data;
544 static void mdscli_get_results_cmd_done(struct tevent_req *subreq);
546 struct tevent_req *mdscli_get_results_send(
548 struct tevent_context *ev,
549 struct mdscli_search_ctx *search)
551 struct tevent_req *req = NULL;
552 struct mdscli_get_results_state *state = NULL;
553 struct tevent_req *subreq = NULL;
554 struct mdscli_ctx *mdscli_ctx = search->mdscli_ctx;
557 req = tevent_req_create(req, &state, struct mdscli_get_results_state);
562 *state = (struct mdscli_get_results_state) {
567 status = mdscli_blob_get_results(state,
569 &state->request_blob);
570 if (tevent_req_nterror(req, status)) {
571 return tevent_req_post(req, ev);
574 subreq = dcerpc_mdssvc_cmd_send(state,
580 mdscli_ctx->mdscmd_open.unkn2,
585 mdscli_ctx->max_fragment_size,
587 mdscli_ctx->max_fragment_size,
591 &state->response_fragment,
592 &mdscli_ctx->mdscmd_cmd.unkn9);
593 if (tevent_req_nomem(subreq, req)) {
594 return tevent_req_post(req, ev);
596 tevent_req_set_callback(subreq, mdscli_get_results_cmd_done, req);
597 mdscli_ctx->async_pending++;
601 static void mdscli_get_results_cmd_done(struct tevent_req *subreq)
603 struct tevent_req *req = tevent_req_callback_data(
604 subreq, struct tevent_req);
605 struct mdscli_get_results_state *state = tevent_req_data(
606 req, struct mdscli_get_results_state);
607 struct mdscli_ctx *mdscli_ctx = state->search->mdscli_ctx;
608 size_t oldsize, newsize;
609 DALLOC_CTX *d = NULL;
610 uint64_t *uint64p = NULL;
611 bool search_in_progress = false;
612 sl_cnids_t *cnids = NULL;
618 status = dcerpc_mdssvc_cmd_recv(subreq, state);
620 state->search->mdscli_ctx->async_pending--;
621 if (tevent_req_nterror(req, status)) {
625 oldsize = state->response_data.length;
626 newsize = oldsize + state->response_fragment.length;
627 if (newsize < oldsize) {
628 tevent_req_nterror(req, NT_STATUS_INTEGER_OVERFLOW);
632 ok = data_blob_realloc(state, &state->response_data, newsize);
634 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
637 (void)memcpy(state->response_data.data + oldsize,
638 state->response_fragment.spotlight_blob,
639 state->response_fragment.length);
641 TALLOC_FREE(state->response_fragment.spotlight_blob);
642 state->response_fragment.length = 0;
643 state->response_fragment.size = 0;
645 if (state->fragment != 0) {
646 subreq = dcerpc_mdssvc_cmd_send(
653 mdscli_ctx->mdscmd_open.unkn2,
658 mdscli_ctx->max_fragment_size,
660 mdscli_ctx->max_fragment_size,
664 &state->response_fragment,
665 &mdscli_ctx->mdscmd_cmd.unkn9);
666 if (tevent_req_nomem(subreq, req)) {
667 tevent_req_post(req, state->ev);
670 tevent_req_set_callback(subreq,
671 mdscli_get_results_cmd_done,
673 mdscli_ctx->async_pending++;
677 d = dalloc_new(state);
678 if (tevent_req_nomem(d, req)) {
683 (char *)state->response_data.data,
684 state->response_data.length);
686 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
690 uint64p = dalloc_get(d,
693 if (uint64p == NULL) {
694 DBG_DEBUG("Unexpected mds response: %s", dalloc_dump(d, 0));
695 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
699 if (*uint64p == 35) {
700 DBG_DEBUG("Search in progress\n");
701 search_in_progress = true;
704 cnids = dalloc_get(d, "DALLOC_CTX", 0, "sl_cnids_t", 1);
706 DBG_DEBUG("cnids error: %s", dalloc_dump(d, 0));
707 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
711 ncnids = dalloc_size(cnids->ca_cnids);
712 if (ncnids == 0 && !search_in_progress) {
713 tevent_req_nterror(req, NT_STATUS_NO_MORE_MATCHES);
717 if (cnids->ca_unkn1 != 0xadd) {
719 * Whatever 0xadd means... but it seems to be the standard value
720 * macOS mdssvc returns here.
722 DBG_DEBUG("unexpected ca_unkn1: %s", dalloc_dump(d, 0));
723 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
727 if (cnids->ca_context != state->search->ctx_id.connection ) {
728 DBG_DEBUG("unexpected ca_context: %s", dalloc_dump(d, 0));
729 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
733 state->cnids = talloc_zero_array(state, uint64_t, ncnids);
734 if (tevent_req_nomem(state->cnids, req)) {
738 for (i = 0; i < ncnids; i++) {
739 uint64_t *cnid = NULL;
741 cnid = dalloc_get(cnids->ca_cnids, "uint64_t", i);
743 DBG_DEBUG("cnids error: %s", dalloc_dump(d, 0));
744 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
747 state->cnids[i] = *cnid;
750 tevent_req_done(req);
754 NTSTATUS mdscli_get_results_recv(struct tevent_req *req,
758 struct mdscli_get_results_state *state = tevent_req_data(
759 req, struct mdscli_get_results_state);
762 if (tevent_req_is_nterror(req, &status)) {
763 tevent_req_received(req);
767 *cnids = talloc_move(mem_ctx, &state->cnids);
769 tevent_req_received(req);
773 NTSTATUS mdscli_get_results(TALLOC_CTX *mem_ctx,
774 struct mdscli_search_ctx *search,
777 TALLOC_CTX *frame = talloc_stackframe();
778 struct tevent_req *req = NULL;
779 struct tevent_context *ev = NULL;
780 NTSTATUS status = NT_STATUS_NO_MEMORY;
782 if (search->mdscli_ctx->async_pending != 0) {
783 status = NT_STATUS_INVALID_PARAMETER;
787 ev = samba_tevent_context_init(frame);
792 req = mdscli_get_results_send(frame,
798 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
802 status = mdscli_get_results_recv(req, mem_ctx, _cnids);
808 struct mdscli_get_path_state {
809 struct mdscli_ctx *mdscli_ctx;
810 struct mdssvc_blob request_blob;
811 struct mdssvc_blob response_blob;
815 static void mdscli_get_path_done(struct tevent_req *subreq);
817 struct tevent_req *mdscli_get_path_send(TALLOC_CTX *mem_ctx,
818 struct tevent_context *ev,
819 struct mdscli_ctx *mdscli_ctx,
822 struct tevent_req *req = NULL;
823 struct mdscli_get_path_state *state = NULL;
824 struct tevent_req *subreq = NULL;
827 req = tevent_req_create(req, &state, struct mdscli_get_path_state);
831 *state = (struct mdscli_get_path_state) {
832 .mdscli_ctx = mdscli_ctx,
835 status = mdscli_blob_get_path(state,
838 &state->request_blob);
839 if (tevent_req_nterror(req, status)) {
840 return tevent_req_post(req, ev);
843 subreq = dcerpc_mdssvc_cmd_send(state,
849 mdscli_ctx->mdscmd_open.unkn2,
854 mdscli_ctx->max_fragment_size,
856 mdscli_ctx->max_fragment_size,
859 &mdscli_ctx->mdscmd_cmd.fragment,
860 &state->response_blob,
861 &mdscli_ctx->mdscmd_cmd.unkn9);
862 if (tevent_req_nomem(subreq, req)) {
863 return tevent_req_post(req, ev);
865 tevent_req_set_callback(subreq, mdscli_get_path_done, req);
866 mdscli_ctx->async_pending++;
870 static void mdscli_get_path_done(struct tevent_req *subreq)
872 struct tevent_req *req = tevent_req_callback_data(
873 subreq, struct tevent_req);
874 struct mdscli_get_path_state *state = tevent_req_data(
875 req, struct mdscli_get_path_state);
876 DALLOC_CTX *d = NULL;
880 const char *p = NULL;
884 status = dcerpc_mdssvc_cmd_recv(subreq, state);
886 state->mdscli_ctx->async_pending--;
887 if (tevent_req_nterror(req, status)) {
891 d = dalloc_new(state);
892 if (tevent_req_nomem(d, req)) {
897 (char *)state->response_blob.spotlight_blob,
898 state->response_blob.length);
900 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
911 DBG_DEBUG("No path in mds response: %s", dalloc_dump(d, 0));
912 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
916 /* Path is prefixed by /PATHSCOPE/SHARENAME/, strip it */
917 pathlen = strlen(path);
920 * path_scope_len and share_path_len are already checked to be smaller
921 * then UINT16_MAX so this can't overflow
923 prefixlen = state->mdscli_ctx->path_scope_len
924 + state->mdscli_ctx->mdscmd_open.share_path_len;
926 if (pathlen < prefixlen) {
927 DBG_DEBUG("Bad path: %s\n", path);
928 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
932 p = path + prefixlen;
937 DBG_DEBUG("Bad path: %s\n", path);
938 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
942 state->path = talloc_strdup(state, p);
943 if (state->path == NULL) {
944 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
947 DBG_DEBUG("path: %s\n", state->path);
949 tevent_req_done(req);
953 NTSTATUS mdscli_get_path_recv(struct tevent_req *req,
957 struct mdscli_get_path_state *state = tevent_req_data(
958 req, struct mdscli_get_path_state);
961 if (tevent_req_is_nterror(req, &status)) {
962 tevent_req_received(req);
966 *path = talloc_move(mem_ctx, &state->path);
967 tevent_req_received(req);
971 NTSTATUS mdscli_get_path(TALLOC_CTX *mem_ctx,
972 struct mdscli_ctx *mdscli_ctx,
976 TALLOC_CTX *frame = talloc_stackframe();
977 struct tevent_req *req = NULL;
978 struct tevent_context *ev = NULL;
979 NTSTATUS status = NT_STATUS_NO_MEMORY;
981 if (mdscli_ctx->async_pending != 0) {
982 status = NT_STATUS_INVALID_PARAMETER;
986 ev = samba_tevent_context_init(frame);
991 req = mdscli_get_path_send(frame, ev, mdscli_ctx, cnid);
995 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
999 status = mdscli_get_path_recv(req, mem_ctx, path);
1005 struct mdscli_close_search_state {
1006 struct mdscli_search_ctx *search;
1007 struct mdssvc_blob request_blob;
1008 struct mdssvc_blob response_blob;
1011 static void mdscli_close_search_done(struct tevent_req *subreq);
1013 struct tevent_req *mdscli_close_search_send(TALLOC_CTX *mem_ctx,
1014 struct tevent_context *ev,
1015 struct mdscli_search_ctx **search)
1017 struct mdscli_ctx *mdscli_ctx = NULL;
1018 struct tevent_req *req = NULL;
1019 struct mdscli_close_search_state *state = NULL;
1020 struct tevent_req *subreq = NULL;
1023 req = tevent_req_create(req, &state, struct mdscli_close_search_state);
1027 *state = (struct mdscli_close_search_state) {
1028 .search = talloc_move(state, search),
1030 mdscli_ctx = state->search->mdscli_ctx;
1032 status = mdscli_blob_close_search(state,
1034 &state->request_blob);
1035 if (tevent_req_nterror(req, status)) {
1036 return tevent_req_post(req, ev);
1039 subreq = dcerpc_mdssvc_cmd_send(state,
1045 mdscli_ctx->mdscmd_open.unkn2,
1048 state->request_blob,
1050 mdscli_ctx->max_fragment_size,
1052 mdscli_ctx->max_fragment_size,
1055 &mdscli_ctx->mdscmd_cmd.fragment,
1056 &state->response_blob,
1057 &mdscli_ctx->mdscmd_cmd.unkn9);
1058 if (tevent_req_nomem(subreq, req)) {
1059 return tevent_req_post(req, ev);
1061 tevent_req_set_callback(subreq, mdscli_close_search_done, req);
1062 mdscli_ctx->async_pending++;
1066 static void mdscli_close_search_done(struct tevent_req *subreq)
1068 struct tevent_req *req = tevent_req_callback_data(
1069 subreq, struct tevent_req);
1070 struct mdscli_close_search_state *state = tevent_req_data(
1071 req, struct mdscli_close_search_state);
1074 status = dcerpc_mdssvc_cmd_recv(subreq, state);
1075 TALLOC_FREE(subreq);
1076 state->search->mdscli_ctx->async_pending--;
1077 if (tevent_req_nterror(req, status)) {
1081 tevent_req_done(req);
1085 NTSTATUS mdscli_close_search_recv(struct tevent_req *req)
1087 return tevent_req_simple_recv_ntstatus(req);
1090 NTSTATUS mdscli_close_search(struct mdscli_search_ctx **search)
1092 TALLOC_CTX *frame = talloc_stackframe();
1093 struct tevent_req *req = NULL;
1094 struct tevent_context *ev = NULL;
1095 NTSTATUS status = NT_STATUS_NO_MEMORY;
1097 if ((*search)->mdscli_ctx->async_pending != 0) {
1098 status = NT_STATUS_INVALID_PARAMETER;
1102 ev = samba_tevent_context_init(frame);
1107 req = mdscli_close_search_send(frame, ev, search);
1111 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1115 status = mdscli_close_search_recv(req);
1121 struct mdscli_disconnect_state {
1122 struct mdscli_ctx *mdscli_ctx;
1125 static void mdscli_disconnect_done(struct tevent_req *subreq);
1127 struct tevent_req *mdscli_disconnect_send(TALLOC_CTX *mem_ctx,
1128 struct tevent_context *ev,
1129 struct mdscli_ctx *mdscli_ctx)
1131 struct tevent_req *req = NULL;
1132 struct mdscli_disconnect_state *state = NULL;
1133 struct tevent_req *subreq = NULL;
1135 req = tevent_req_create(req, &state, struct mdscli_disconnect_state);
1139 *state = (struct mdscli_disconnect_state) {
1140 .mdscli_ctx = mdscli_ctx,
1143 subreq = dcerpc_mdssvc_close_send(state,
1149 mdscli_ctx->mdscmd_open.unkn2,
1152 &mdscli_ctx->mdscmd_close.status);
1153 if (tevent_req_nomem(subreq, req)) {
1154 return tevent_req_post(req, ev);
1156 tevent_req_set_callback(subreq, mdscli_disconnect_done, req);
1157 mdscli_ctx->async_pending++;
1161 static void mdscli_disconnect_done(struct tevent_req *subreq)
1163 struct tevent_req *req = tevent_req_callback_data(
1164 subreq, struct tevent_req);
1165 struct mdscli_disconnect_state *state = tevent_req_data(
1166 req, struct mdscli_disconnect_state);
1169 status = dcerpc_mdssvc_close_recv(subreq, state);
1170 TALLOC_FREE(subreq);
1171 state->mdscli_ctx->async_pending--;
1172 if (tevent_req_nterror(req, status)) {
1176 tevent_req_done(req);
1180 NTSTATUS mdscli_disconnect_recv(struct tevent_req *req)
1182 return tevent_req_simple_recv_ntstatus(req);
1185 NTSTATUS mdscli_disconnect(struct mdscli_ctx *mdscli_ctx)
1187 TALLOC_CTX *frame = talloc_stackframe();
1188 struct tevent_req *req = NULL;
1189 struct tevent_context *ev = NULL;
1190 NTSTATUS status = NT_STATUS_NO_MEMORY;
1192 if (mdscli_ctx->async_pending != 0) {
1193 status = NT_STATUS_INVALID_PARAMETER;
1197 ev = samba_tevent_context_init(frame);
1202 req = mdscli_disconnect_send(frame, ev, mdscli_ctx);
1206 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1210 status = mdscli_disconnect_recv(req);