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 ||
128 share_path_len
>= sizeof(mdscli_ctx
->mdscmd_open
.share_path
))
130 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
133 mdscli_ctx
->mdscmd_open
.share_path_len
= share_path_len
;
135 if (mdscli_ctx
->mdscmd_open
.share_path
[share_path_len
-1] == '/') {
136 mdscli_ctx
->mdscmd_open
.share_path
[share_path_len
-1] = '\0';
137 mdscli_ctx
->mdscmd_open
.share_path_len
--;
140 subreq
= dcerpc_mdssvc_unknown1_send(
147 mdscli_ctx
->mdscmd_open
.unkn2
,
151 &mdscli_ctx
->mdscmd_unknown1
.status
,
153 &mdscli_ctx
->mdscmd_unknown1
.unkn7
);
154 if (tevent_req_nomem(subreq
, req
)) {
157 tevent_req_set_callback(subreq
, mdscli_connect_unknown1_done
, req
);
160 static void mdscli_connect_unknown1_done(struct tevent_req
*subreq
)
162 struct tevent_req
*req
= tevent_req_callback_data(
163 subreq
, struct tevent_req
);
164 struct mdscli_connect_state
*state
= tevent_req_data(
165 req
, struct mdscli_connect_state
);
166 struct mdscli_ctx
*mdscli_ctx
= state
->mdscli_ctx
;
167 struct mdssvc_blob request_blob
;
170 status
= dcerpc_mdssvc_unknown1_recv(subreq
, state
);
172 if (tevent_req_nterror(req
, status
)) {
176 status
= mdscli_blob_fetch_props(state
,
179 if (tevent_req_nterror(req
, status
)) {
183 subreq
= dcerpc_mdssvc_cmd_send(state
,
189 mdscli_ctx
->mdscmd_open
.unkn2
,
194 mdscli_ctx
->max_fragment_size
,
196 mdscli_ctx
->max_fragment_size
,
199 &mdscli_ctx
->mdscmd_cmd
.fragment
,
200 &state
->response_blob
,
201 &mdscli_ctx
->mdscmd_cmd
.unkn9
);
202 if (tevent_req_nomem(subreq
, req
)) {
205 tevent_req_set_callback(subreq
, mdscli_connect_fetch_props_done
, req
);
206 mdscli_ctx
->async_pending
++;
210 static void mdscli_connect_fetch_props_done(struct tevent_req
*subreq
)
212 struct tevent_req
*req
= tevent_req_callback_data(
213 subreq
, struct tevent_req
);
214 struct mdscli_connect_state
*state
= tevent_req_data(
215 req
, struct mdscli_connect_state
);
216 struct mdscli_ctx
*mdscli_ctx
= state
->mdscli_ctx
;
217 DALLOC_CTX
*d
= NULL
;
218 sl_array_t
*path_scope_array
= NULL
;
219 char *path_scope
= NULL
;
223 status
= dcerpc_mdssvc_cmd_recv(subreq
, state
);
225 state
->mdscli_ctx
->async_pending
--;
226 if (tevent_req_nterror(req
, status
)) {
230 d
= dalloc_new(state
);
231 if (tevent_req_nomem(d
, req
)) {
236 (char *)state
->response_blob
.spotlight_blob
,
237 state
->response_blob
.length
);
239 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
243 path_scope_array
= dalloc_value_for_key(d
,
245 "kMDSStorePathScopes",
247 if (path_scope_array
== NULL
) {
248 DBG_ERR("Missing kMDSStorePathScopes\n");
249 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
253 path_scope
= dalloc_get(path_scope_array
, "char *", 0);
254 if (path_scope
== NULL
) {
255 DBG_ERR("Missing path in kMDSStorePathScopes\n");
256 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
260 mdscli_ctx
->path_scope_len
= strlen(path_scope
);
261 if (mdscli_ctx
->path_scope_len
< 1 ||
262 mdscli_ctx
->path_scope_len
> UINT16_MAX
)
264 DBG_ERR("Bad path_scope: %s\n", path_scope
);
265 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
268 mdscli_ctx
->path_scope
= talloc_strdup(mdscli_ctx
, path_scope
);
269 if (tevent_req_nomem(mdscli_ctx
->path_scope
, req
)) {
273 if (mdscli_ctx
->path_scope
[mdscli_ctx
->path_scope_len
-1] == '/') {
274 mdscli_ctx
->path_scope
[mdscli_ctx
->path_scope_len
-1] = '\0';
275 mdscli_ctx
->path_scope_len
--;
278 tevent_req_done(req
);
281 NTSTATUS
mdscli_connect_recv(struct tevent_req
*req
,
283 struct mdscli_ctx
**mdscli_ctx
)
285 struct mdscli_connect_state
*state
= tevent_req_data(
286 req
, struct mdscli_connect_state
);
289 if (tevent_req_is_nterror(req
, &status
)) {
290 tevent_req_received(req
);
294 *mdscli_ctx
= talloc_move(mem_ctx
, &state
->mdscli_ctx
);
295 tevent_req_received(req
);
299 NTSTATUS
mdscli_connect(TALLOC_CTX
*mem_ctx
,
300 struct dcerpc_binding_handle
*bh
,
301 const char *share_name
,
302 const char *mount_path
,
303 struct mdscli_ctx
**mdscli_ctx
)
305 TALLOC_CTX
*frame
= talloc_stackframe();
306 struct tevent_req
*req
= NULL
;
307 struct tevent_context
*ev
= NULL
;
308 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
310 ev
= samba_tevent_context_init(frame
);
315 req
= mdscli_connect_send(frame
,
323 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
327 status
= mdscli_connect_recv(req
, mem_ctx
, mdscli_ctx
);
333 struct mdscli_search_state
{
334 struct mdscli_search_ctx
*search
;
335 struct mdssvc_blob request_blob
;
336 struct mdssvc_blob response_blob
;
339 static void mdscli_search_cmd_done(struct tevent_req
*subreq
);
341 struct tevent_req
*mdscli_search_send(TALLOC_CTX
*mem_ctx
,
342 struct tevent_context
*ev
,
343 struct mdscli_ctx
*mdscli_ctx
,
344 const char *mds_query
,
345 const char *path_scope_in
,
348 struct tevent_req
*req
= NULL
;
349 struct mdscli_search_state
*state
= NULL
;
350 struct tevent_req
*subreq
= NULL
;
351 struct mdscli_search_ctx
*search
= NULL
;
352 char *path_scope
= NULL
;
355 req
= tevent_req_create(req
, &state
, struct mdscli_search_state
);
360 search
= talloc_zero(state
, struct mdscli_search_ctx
);
361 if (tevent_req_nomem(search
, req
)) {
362 return tevent_req_post(req
, ev
);
365 if (path_scope_in
[0] == '/') {
366 path_scope
= talloc_strdup(search
, path_scope_in
);
368 path_scope
= talloc_asprintf(search
,
370 mdscli_ctx
->mdscmd_open
.share_path
,
373 if (tevent_req_nomem(path_scope
, req
)) {
374 return tevent_req_post(req
, ev
);
377 *search
= (struct mdscli_search_ctx
) {
378 .mdscli_ctx
= mdscli_ctx
,
379 .ctx_id
= mdscli_new_ctx_id(mdscli_ctx
),
380 .unique_id
= generate_random_u64(),
382 .path_scope
= path_scope
,
383 .mds_query
= talloc_strdup(search
, mds_query
),
385 if (tevent_req_nomem(search
->mds_query
, req
)) {
386 return tevent_req_post(req
, ev
);
389 *state
= (struct mdscli_search_state
) {
393 status
= mdscli_blob_search(state
,
395 &state
->request_blob
);
396 if (tevent_req_nterror(req
, status
)) {
397 return tevent_req_post(req
, ev
);
400 subreq
= dcerpc_mdssvc_cmd_send(state
,
406 mdscli_ctx
->mdscmd_open
.unkn2
,
411 mdscli_ctx
->max_fragment_size
,
413 mdscli_ctx
->max_fragment_size
,
416 &mdscli_ctx
->mdscmd_cmd
.fragment
,
417 &state
->response_blob
,
418 &mdscli_ctx
->mdscmd_cmd
.unkn9
);
419 if (tevent_req_nomem(subreq
, req
)) {
420 return tevent_req_post(req
, ev
);
422 tevent_req_set_callback(subreq
, mdscli_search_cmd_done
, req
);
423 mdscli_ctx
->async_pending
++;
427 static void mdscli_search_cmd_done(struct tevent_req
*subreq
)
429 struct tevent_req
*req
= tevent_req_callback_data(
430 subreq
, struct tevent_req
);
431 struct mdscli_search_state
*state
= tevent_req_data(
432 req
, struct mdscli_search_state
);
433 DALLOC_CTX
*d
= NULL
;
434 uint64_t *uint64p
= NULL
;
438 status
= dcerpc_mdssvc_cmd_recv(subreq
, state
);
440 state
->search
->mdscli_ctx
->async_pending
--;
441 if (tevent_req_nterror(req
, status
)) {
445 d
= dalloc_new(state
);
446 if (tevent_req_nomem(d
, req
)) {
451 (char *)state
->response_blob
.spotlight_blob
,
452 state
->response_blob
.length
);
454 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
458 uint64p
= dalloc_get(d
,
461 if (uint64p
== NULL
) {
462 DBG_DEBUG("Unexpected mds response: %s", dalloc_dump(d
, 0));
463 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
468 DBG_DEBUG("Unexpected mds result: 0x%" PRIx64
"\n", *uint64p
);
469 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
473 tevent_req_done(req
);
477 NTSTATUS
mdscli_search_recv(struct tevent_req
*req
,
479 struct mdscli_search_ctx
**search
)
481 struct mdscli_search_state
*state
= tevent_req_data(
482 req
, struct mdscli_search_state
);
485 if (tevent_req_is_nterror(req
, &status
)) {
486 tevent_req_received(req
);
490 *search
= talloc_move(mem_ctx
, &state
->search
);
491 tevent_req_received(req
);
495 NTSTATUS
mdscli_search(TALLOC_CTX
*mem_ctx
,
496 struct mdscli_ctx
*mdscli_ctx
,
497 const char *mds_query
,
498 const char *path_scope
,
500 struct mdscli_search_ctx
**search
)
502 TALLOC_CTX
*frame
= talloc_stackframe();
503 struct tevent_req
*req
= NULL
;
504 struct tevent_context
*ev
= NULL
;
505 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
507 if (mdscli_ctx
->async_pending
!= 0) {
508 status
= NT_STATUS_INVALID_PARAMETER
;
512 ev
= samba_tevent_context_init(frame
);
517 req
= mdscli_search_send(frame
,
526 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
530 status
= mdscli_search_recv(req
, mem_ctx
, search
);
536 struct mdscli_get_results_state
{
537 struct tevent_context
*ev
;
538 struct mdscli_search_ctx
*search
;
539 struct mdssvc_blob request_blob
;
540 struct mdssvc_blob response_fragment
;
541 DATA_BLOB response_data
;
546 static void mdscli_get_results_cmd_done(struct tevent_req
*subreq
);
548 struct tevent_req
*mdscli_get_results_send(
550 struct tevent_context
*ev
,
551 struct mdscli_search_ctx
*search
)
553 struct tevent_req
*req
= NULL
;
554 struct mdscli_get_results_state
*state
= NULL
;
555 struct tevent_req
*subreq
= NULL
;
556 struct mdscli_ctx
*mdscli_ctx
= search
->mdscli_ctx
;
559 req
= tevent_req_create(req
, &state
, struct mdscli_get_results_state
);
564 *state
= (struct mdscli_get_results_state
) {
569 status
= mdscli_blob_get_results(state
,
571 &state
->request_blob
);
572 if (tevent_req_nterror(req
, status
)) {
573 return tevent_req_post(req
, ev
);
576 subreq
= dcerpc_mdssvc_cmd_send(state
,
582 mdscli_ctx
->mdscmd_open
.unkn2
,
587 mdscli_ctx
->max_fragment_size
,
589 mdscli_ctx
->max_fragment_size
,
593 &state
->response_fragment
,
594 &mdscli_ctx
->mdscmd_cmd
.unkn9
);
595 if (tevent_req_nomem(subreq
, req
)) {
596 return tevent_req_post(req
, ev
);
598 tevent_req_set_callback(subreq
, mdscli_get_results_cmd_done
, req
);
599 mdscli_ctx
->async_pending
++;
603 static void mdscli_get_results_cmd_done(struct tevent_req
*subreq
)
605 struct tevent_req
*req
= tevent_req_callback_data(
606 subreq
, struct tevent_req
);
607 struct mdscli_get_results_state
*state
= tevent_req_data(
608 req
, struct mdscli_get_results_state
);
609 struct mdscli_ctx
*mdscli_ctx
= state
->search
->mdscli_ctx
;
610 size_t oldsize
, newsize
;
611 DALLOC_CTX
*d
= NULL
;
612 uint64_t *uint64p
= NULL
;
613 bool search_in_progress
= false;
614 sl_cnids_t
*cnids
= NULL
;
620 status
= dcerpc_mdssvc_cmd_recv(subreq
, state
);
622 state
->search
->mdscli_ctx
->async_pending
--;
623 if (tevent_req_nterror(req
, status
)) {
627 oldsize
= state
->response_data
.length
;
628 newsize
= oldsize
+ state
->response_fragment
.length
;
629 if (newsize
< oldsize
) {
630 tevent_req_nterror(req
, NT_STATUS_INTEGER_OVERFLOW
);
634 ok
= data_blob_realloc(state
, &state
->response_data
, newsize
);
636 tevent_req_nterror(req
, NT_STATUS_NO_MEMORY
);
639 (void)memcpy(state
->response_data
.data
+ oldsize
,
640 state
->response_fragment
.spotlight_blob
,
641 state
->response_fragment
.length
);
643 TALLOC_FREE(state
->response_fragment
.spotlight_blob
);
644 state
->response_fragment
.length
= 0;
645 state
->response_fragment
.size
= 0;
647 if (state
->fragment
!= 0) {
648 subreq
= dcerpc_mdssvc_cmd_send(
655 mdscli_ctx
->mdscmd_open
.unkn2
,
660 mdscli_ctx
->max_fragment_size
,
662 mdscli_ctx
->max_fragment_size
,
666 &state
->response_fragment
,
667 &mdscli_ctx
->mdscmd_cmd
.unkn9
);
668 if (tevent_req_nomem(subreq
, req
)) {
669 tevent_req_post(req
, state
->ev
);
672 tevent_req_set_callback(subreq
,
673 mdscli_get_results_cmd_done
,
675 mdscli_ctx
->async_pending
++;
679 d
= dalloc_new(state
);
680 if (tevent_req_nomem(d
, req
)) {
685 (char *)state
->response_data
.data
,
686 state
->response_data
.length
);
688 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
692 uint64p
= dalloc_get(d
,
695 if (uint64p
== NULL
) {
696 DBG_DEBUG("Unexpected mds response: %s", dalloc_dump(d
, 0));
697 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
701 if (*uint64p
== 35) {
702 DBG_DEBUG("Search in progress\n");
703 search_in_progress
= true;
706 cnids
= dalloc_get(d
, "DALLOC_CTX", 0, "sl_cnids_t", 1);
708 DBG_DEBUG("cnids error: %s", dalloc_dump(d
, 0));
709 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
713 ncnids
= dalloc_size(cnids
->ca_cnids
);
714 if (ncnids
== 0 && !search_in_progress
) {
715 tevent_req_nterror(req
, NT_STATUS_NO_MORE_MATCHES
);
719 if (cnids
->ca_unkn1
!= 0xadd) {
721 * Whatever 0xadd means... but it seems to be the standard value
722 * macOS mdssvc returns here.
724 DBG_DEBUG("unexpected ca_unkn1: %s", dalloc_dump(d
, 0));
725 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
729 if (cnids
->ca_context
!= state
->search
->ctx_id
.connection
) {
730 DBG_DEBUG("unexpected ca_context: %s", dalloc_dump(d
, 0));
731 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
735 state
->cnids
= talloc_zero_array(state
, uint64_t, ncnids
);
736 if (tevent_req_nomem(state
->cnids
, req
)) {
740 for (i
= 0; i
< ncnids
; i
++) {
741 uint64_t *cnid
= NULL
;
743 cnid
= dalloc_get(cnids
->ca_cnids
, "uint64_t", i
);
745 DBG_DEBUG("cnids error: %s", dalloc_dump(d
, 0));
746 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
749 state
->cnids
[i
] = *cnid
;
752 tevent_req_done(req
);
756 NTSTATUS
mdscli_get_results_recv(struct tevent_req
*req
,
760 struct mdscli_get_results_state
*state
= tevent_req_data(
761 req
, struct mdscli_get_results_state
);
764 if (tevent_req_is_nterror(req
, &status
)) {
765 tevent_req_received(req
);
769 *cnids
= talloc_move(mem_ctx
, &state
->cnids
);
771 tevent_req_received(req
);
775 NTSTATUS
mdscli_get_results(TALLOC_CTX
*mem_ctx
,
776 struct mdscli_search_ctx
*search
,
779 TALLOC_CTX
*frame
= talloc_stackframe();
780 struct tevent_req
*req
= NULL
;
781 struct tevent_context
*ev
= NULL
;
782 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
784 if (search
->mdscli_ctx
->async_pending
!= 0) {
785 status
= NT_STATUS_INVALID_PARAMETER
;
789 ev
= samba_tevent_context_init(frame
);
794 req
= mdscli_get_results_send(frame
,
800 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
804 status
= mdscli_get_results_recv(req
, mem_ctx
, _cnids
);
810 struct mdscli_get_path_state
{
811 struct mdscli_ctx
*mdscli_ctx
;
812 struct mdssvc_blob request_blob
;
813 struct mdssvc_blob response_blob
;
817 static void mdscli_get_path_done(struct tevent_req
*subreq
);
819 struct tevent_req
*mdscli_get_path_send(TALLOC_CTX
*mem_ctx
,
820 struct tevent_context
*ev
,
821 struct mdscli_ctx
*mdscli_ctx
,
824 struct tevent_req
*req
= NULL
;
825 struct mdscli_get_path_state
*state
= NULL
;
826 struct tevent_req
*subreq
= NULL
;
829 req
= tevent_req_create(req
, &state
, struct mdscli_get_path_state
);
833 *state
= (struct mdscli_get_path_state
) {
834 .mdscli_ctx
= mdscli_ctx
,
837 status
= mdscli_blob_get_path(state
,
840 &state
->request_blob
);
841 if (tevent_req_nterror(req
, status
)) {
842 return tevent_req_post(req
, ev
);
845 subreq
= dcerpc_mdssvc_cmd_send(state
,
851 mdscli_ctx
->mdscmd_open
.unkn2
,
856 mdscli_ctx
->max_fragment_size
,
858 mdscli_ctx
->max_fragment_size
,
861 &mdscli_ctx
->mdscmd_cmd
.fragment
,
862 &state
->response_blob
,
863 &mdscli_ctx
->mdscmd_cmd
.unkn9
);
864 if (tevent_req_nomem(subreq
, req
)) {
865 return tevent_req_post(req
, ev
);
867 tevent_req_set_callback(subreq
, mdscli_get_path_done
, req
);
868 mdscli_ctx
->async_pending
++;
872 static void mdscli_get_path_done(struct tevent_req
*subreq
)
874 struct tevent_req
*req
= tevent_req_callback_data(
875 subreq
, struct tevent_req
);
876 struct mdscli_get_path_state
*state
= tevent_req_data(
877 req
, struct mdscli_get_path_state
);
878 DALLOC_CTX
*d
= NULL
;
882 const char *p
= NULL
;
886 status
= dcerpc_mdssvc_cmd_recv(subreq
, state
);
888 state
->mdscli_ctx
->async_pending
--;
889 if (tevent_req_nterror(req
, status
)) {
893 d
= dalloc_new(state
);
894 if (tevent_req_nomem(d
, req
)) {
899 (char *)state
->response_blob
.spotlight_blob
,
900 state
->response_blob
.length
);
902 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
913 DBG_DEBUG("No path in mds response: %s", dalloc_dump(d
, 0));
914 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
918 /* Path is prefixed by /PATHSCOPE/SHARENAME/, strip it */
919 pathlen
= strlen(path
);
922 * path_scope_len and share_path_len are already checked to be smaller
923 * then UINT16_MAX so this can't overflow
925 prefixlen
= state
->mdscli_ctx
->path_scope_len
926 + state
->mdscli_ctx
->mdscmd_open
.share_path_len
;
928 if (pathlen
< prefixlen
) {
929 DBG_DEBUG("Bad path: %s\n", path
);
930 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
934 p
= path
+ prefixlen
;
939 DBG_DEBUG("Bad path: %s\n", path
);
940 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
944 state
->path
= talloc_strdup(state
, p
);
945 if (state
->path
== NULL
) {
946 tevent_req_nterror(req
, NT_STATUS_NO_MEMORY
);
949 DBG_DEBUG("path: %s\n", state
->path
);
951 tevent_req_done(req
);
955 NTSTATUS
mdscli_get_path_recv(struct tevent_req
*req
,
959 struct mdscli_get_path_state
*state
= tevent_req_data(
960 req
, struct mdscli_get_path_state
);
963 if (tevent_req_is_nterror(req
, &status
)) {
964 tevent_req_received(req
);
968 *path
= talloc_move(mem_ctx
, &state
->path
);
969 tevent_req_received(req
);
973 NTSTATUS
mdscli_get_path(TALLOC_CTX
*mem_ctx
,
974 struct mdscli_ctx
*mdscli_ctx
,
978 TALLOC_CTX
*frame
= talloc_stackframe();
979 struct tevent_req
*req
= NULL
;
980 struct tevent_context
*ev
= NULL
;
981 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
983 if (mdscli_ctx
->async_pending
!= 0) {
984 status
= NT_STATUS_INVALID_PARAMETER
;
988 ev
= samba_tevent_context_init(frame
);
993 req
= mdscli_get_path_send(frame
, ev
, mdscli_ctx
, cnid
);
997 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1001 status
= mdscli_get_path_recv(req
, mem_ctx
, path
);
1007 struct mdscli_close_search_state
{
1008 struct mdscli_search_ctx
*search
;
1009 struct mdssvc_blob request_blob
;
1010 struct mdssvc_blob response_blob
;
1013 static void mdscli_close_search_done(struct tevent_req
*subreq
);
1015 struct tevent_req
*mdscli_close_search_send(TALLOC_CTX
*mem_ctx
,
1016 struct tevent_context
*ev
,
1017 struct mdscli_search_ctx
**search
)
1019 struct mdscli_ctx
*mdscli_ctx
= NULL
;
1020 struct tevent_req
*req
= NULL
;
1021 struct mdscli_close_search_state
*state
= NULL
;
1022 struct tevent_req
*subreq
= NULL
;
1025 req
= tevent_req_create(req
, &state
, struct mdscli_close_search_state
);
1029 *state
= (struct mdscli_close_search_state
) {
1030 .search
= talloc_move(state
, search
),
1032 mdscli_ctx
= state
->search
->mdscli_ctx
;
1034 status
= mdscli_blob_close_search(state
,
1036 &state
->request_blob
);
1037 if (tevent_req_nterror(req
, status
)) {
1038 return tevent_req_post(req
, ev
);
1041 subreq
= dcerpc_mdssvc_cmd_send(state
,
1047 mdscli_ctx
->mdscmd_open
.unkn2
,
1050 state
->request_blob
,
1052 mdscli_ctx
->max_fragment_size
,
1054 mdscli_ctx
->max_fragment_size
,
1057 &mdscli_ctx
->mdscmd_cmd
.fragment
,
1058 &state
->response_blob
,
1059 &mdscli_ctx
->mdscmd_cmd
.unkn9
);
1060 if (tevent_req_nomem(subreq
, req
)) {
1061 return tevent_req_post(req
, ev
);
1063 tevent_req_set_callback(subreq
, mdscli_close_search_done
, req
);
1064 mdscli_ctx
->async_pending
++;
1068 static void mdscli_close_search_done(struct tevent_req
*subreq
)
1070 struct tevent_req
*req
= tevent_req_callback_data(
1071 subreq
, struct tevent_req
);
1072 struct mdscli_close_search_state
*state
= tevent_req_data(
1073 req
, struct mdscli_close_search_state
);
1076 status
= dcerpc_mdssvc_cmd_recv(subreq
, state
);
1077 TALLOC_FREE(subreq
);
1078 state
->search
->mdscli_ctx
->async_pending
--;
1079 if (tevent_req_nterror(req
, status
)) {
1083 tevent_req_done(req
);
1087 NTSTATUS
mdscli_close_search_recv(struct tevent_req
*req
)
1089 return tevent_req_simple_recv_ntstatus(req
);
1092 NTSTATUS
mdscli_close_search(struct mdscli_search_ctx
**search
)
1094 TALLOC_CTX
*frame
= talloc_stackframe();
1095 struct tevent_req
*req
= NULL
;
1096 struct tevent_context
*ev
= NULL
;
1097 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1099 if ((*search
)->mdscli_ctx
->async_pending
!= 0) {
1100 status
= NT_STATUS_INVALID_PARAMETER
;
1104 ev
= samba_tevent_context_init(frame
);
1109 req
= mdscli_close_search_send(frame
, ev
, search
);
1113 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1117 status
= mdscli_close_search_recv(req
);
1123 struct mdscli_disconnect_state
{
1124 struct mdscli_ctx
*mdscli_ctx
;
1127 static void mdscli_disconnect_done(struct tevent_req
*subreq
);
1129 struct tevent_req
*mdscli_disconnect_send(TALLOC_CTX
*mem_ctx
,
1130 struct tevent_context
*ev
,
1131 struct mdscli_ctx
*mdscli_ctx
)
1133 struct tevent_req
*req
= NULL
;
1134 struct mdscli_disconnect_state
*state
= NULL
;
1135 struct tevent_req
*subreq
= NULL
;
1137 req
= tevent_req_create(req
, &state
, struct mdscli_disconnect_state
);
1141 *state
= (struct mdscli_disconnect_state
) {
1142 .mdscli_ctx
= mdscli_ctx
,
1145 subreq
= dcerpc_mdssvc_close_send(state
,
1151 mdscli_ctx
->mdscmd_open
.unkn2
,
1154 &mdscli_ctx
->mdscmd_close
.status
);
1155 if (tevent_req_nomem(subreq
, req
)) {
1156 return tevent_req_post(req
, ev
);
1158 tevent_req_set_callback(subreq
, mdscli_disconnect_done
, req
);
1159 mdscli_ctx
->async_pending
++;
1163 static void mdscli_disconnect_done(struct tevent_req
*subreq
)
1165 struct tevent_req
*req
= tevent_req_callback_data(
1166 subreq
, struct tevent_req
);
1167 struct mdscli_disconnect_state
*state
= tevent_req_data(
1168 req
, struct mdscli_disconnect_state
);
1171 status
= dcerpc_mdssvc_close_recv(subreq
, state
);
1172 TALLOC_FREE(subreq
);
1173 state
->mdscli_ctx
->async_pending
--;
1174 if (tevent_req_nterror(req
, status
)) {
1178 tevent_req_done(req
);
1182 NTSTATUS
mdscli_disconnect_recv(struct tevent_req
*req
)
1184 return tevent_req_simple_recv_ntstatus(req
);
1187 NTSTATUS
mdscli_disconnect(struct mdscli_ctx
*mdscli_ctx
)
1189 TALLOC_CTX
*frame
= talloc_stackframe();
1190 struct tevent_req
*req
= NULL
;
1191 struct tevent_context
*ev
= NULL
;
1192 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1194 if (mdscli_ctx
->async_pending
!= 0) {
1195 status
= NT_STATUS_INVALID_PARAMETER
;
1199 ev
= samba_tevent_context_init(frame
);
1204 req
= mdscli_disconnect_send(frame
, ev
, mdscli_ctx
);
1208 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1212 status
= mdscli_disconnect_recv(req
);