util:datablob: data_blob_pad checks its alignment assumption
[samba.git] / source3 / rpc_client / cli_mdssvc.c
blob8678b4bbcb0e664ae0f9e96a92d4d6aa0e99800e
1 /*
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/>.
21 #include "includes.h"
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);
65 if (req == NULL) {
66 return NULL;
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) {
75 .ev = ev,
76 .mdscli_ctx = ctx,
79 *ctx = (struct mdscli_ctx) {
80 .bh = bh,
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
85 * tcon.
87 .ctx_id.connection = UINT64_C(0x6b000060),
90 subreq = dcerpc_mdssvc_open_send(state,
91 state->ev,
92 ctx->bh,
93 &ctx->dev,
94 &ctx->mdscmd_open.unkn2,
95 &ctx->mdscmd_open.unkn3,
96 mount_path,
97 share_name,
98 ctx->mdscmd_open.share_path,
99 &ctx->ph);
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++;
106 return req;
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;
117 NTSTATUS status;
119 status = dcerpc_mdssvc_open_recv(subreq, state);
120 TALLOC_FREE(subreq);
121 state->mdscli_ctx->async_pending--;
122 if (tevent_req_nterror(req, status)) {
123 return;
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);
131 return;
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(
141 state,
142 state->ev,
143 mdscli_ctx->bh,
144 &mdscli_ctx->ph,
146 mdscli_ctx->dev,
147 mdscli_ctx->mdscmd_open.unkn2,
149 geteuid(),
150 getegid(),
151 &mdscli_ctx->mdscmd_unknown1.status,
152 &mdscli_ctx->flags,
153 &mdscli_ctx->mdscmd_unknown1.unkn7);
154 if (tevent_req_nomem(subreq, req)) {
155 return;
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;
168 NTSTATUS status;
170 status = dcerpc_mdssvc_unknown1_recv(subreq, state);
171 TALLOC_FREE(subreq);
172 if (tevent_req_nterror(req, status)) {
173 return;
176 status = mdscli_blob_fetch_props(state,
177 state->mdscli_ctx,
178 &request_blob);
179 if (tevent_req_nterror(req, status)) {
180 return;
183 subreq = dcerpc_mdssvc_cmd_send(state,
184 state->ev,
185 mdscli_ctx->bh,
186 &mdscli_ctx->ph,
188 mdscli_ctx->dev,
189 mdscli_ctx->mdscmd_open.unkn2,
191 mdscli_ctx->flags,
192 request_blob,
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)) {
203 return;
205 tevent_req_set_callback(subreq, mdscli_connect_fetch_props_done, req);
206 mdscli_ctx->async_pending++;
207 return;
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;
220 NTSTATUS status;
221 bool ok;
223 status = dcerpc_mdssvc_cmd_recv(subreq, state);
224 TALLOC_FREE(subreq);
225 state->mdscli_ctx->async_pending--;
226 if (tevent_req_nterror(req, status)) {
227 return;
230 d = dalloc_new(state);
231 if (tevent_req_nomem(d, req)) {
232 return;
235 ok = sl_unpack(d,
236 (char *)state->response_blob.spotlight_blob,
237 state->response_blob.length);
238 if (!ok) {
239 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
240 return;
243 path_scope_array = dalloc_value_for_key(d,
244 "DALLOC_CTX", 0,
245 "kMDSStorePathScopes",
246 "sl_array_t");
247 if (path_scope_array == NULL) {
248 DBG_ERR("Missing kMDSStorePathScopes\n");
249 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
250 return;
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);
257 return;
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);
266 return;
268 mdscli_ctx->path_scope = talloc_strdup(mdscli_ctx, path_scope);
269 if (tevent_req_nomem(mdscli_ctx->path_scope, req)) {
270 return;
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,
282 TALLOC_CTX *mem_ctx,
283 struct mdscli_ctx **mdscli_ctx)
285 struct mdscli_connect_state *state = tevent_req_data(
286 req, struct mdscli_connect_state);
287 NTSTATUS status;
289 if (tevent_req_is_nterror(req, &status)) {
290 tevent_req_received(req);
291 return status;
294 *mdscli_ctx = talloc_move(mem_ctx, &state->mdscli_ctx);
295 tevent_req_received(req);
296 return NT_STATUS_OK;
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);
311 if (ev == NULL) {
312 goto fail;
315 req = mdscli_connect_send(frame,
318 share_name,
319 mount_path);
320 if (req == NULL) {
321 goto fail;
323 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
324 goto fail;
327 status = mdscli_connect_recv(req, mem_ctx, mdscli_ctx);
328 fail:
329 TALLOC_FREE(frame);
330 return status;
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,
346 bool live)
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;
353 NTSTATUS status;
355 req = tevent_req_create(req, &state, struct mdscli_search_state);
356 if (req == NULL) {
357 return NULL;
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);
367 } else {
368 path_scope = talloc_asprintf(search,
369 "%s/%s",
370 mdscli_ctx->mdscmd_open.share_path,
371 path_scope_in);
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(),
381 .live = live,
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) {
390 .search = search,
393 status = mdscli_blob_search(state,
394 search,
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,
402 mdscli_ctx->bh,
403 &mdscli_ctx->ph,
405 mdscli_ctx->dev,
406 mdscli_ctx->mdscmd_open.unkn2,
408 mdscli_ctx->flags,
409 state->request_blob,
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++;
424 return req;
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;
435 NTSTATUS status;
436 bool ok;
438 status = dcerpc_mdssvc_cmd_recv(subreq, state);
439 TALLOC_FREE(subreq);
440 state->search->mdscli_ctx->async_pending--;
441 if (tevent_req_nterror(req, status)) {
442 return;
445 d = dalloc_new(state);
446 if (tevent_req_nomem(d, req)) {
447 return;
450 ok = sl_unpack(d,
451 (char *)state->response_blob.spotlight_blob,
452 state->response_blob.length);
453 if (!ok) {
454 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
455 return;
458 uint64p = dalloc_get(d,
459 "DALLOC_CTX", 0,
460 "uint64_t", 0);
461 if (uint64p == NULL) {
462 DBG_DEBUG("Unexpected mds response: %s", dalloc_dump(d, 0));
463 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
464 return;
467 if (*uint64p != 0) {
468 DBG_DEBUG("Unexpected mds result: 0x%" PRIx64 "\n", *uint64p);
469 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
470 return;
473 tevent_req_done(req);
474 return;
477 NTSTATUS mdscli_search_recv(struct tevent_req *req,
478 TALLOC_CTX *mem_ctx,
479 struct mdscli_search_ctx **search)
481 struct mdscli_search_state *state = tevent_req_data(
482 req, struct mdscli_search_state);
483 NTSTATUS status;
485 if (tevent_req_is_nterror(req, &status)) {
486 tevent_req_received(req);
487 return status;
490 *search = talloc_move(mem_ctx, &state->search);
491 tevent_req_received(req);
492 return NT_STATUS_OK;
495 NTSTATUS mdscli_search(TALLOC_CTX *mem_ctx,
496 struct mdscli_ctx *mdscli_ctx,
497 const char *mds_query,
498 const char *path_scope,
499 bool live,
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;
509 goto fail;
512 ev = samba_tevent_context_init(frame);
513 if (ev == NULL) {
514 goto fail;
517 req = mdscli_search_send(frame,
519 mdscli_ctx,
520 mds_query,
521 path_scope,
522 live);
523 if (req == NULL) {
524 goto fail;
526 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
527 goto fail;
530 status = mdscli_search_recv(req, mem_ctx, search);
531 fail:
532 TALLOC_FREE(frame);
533 return status;
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;
542 uint64_t *cnids;
543 uint32_t fragment;
546 static void mdscli_get_results_cmd_done(struct tevent_req *subreq);
548 struct tevent_req *mdscli_get_results_send(
549 TALLOC_CTX *mem_ctx,
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;
557 NTSTATUS status;
559 req = tevent_req_create(req, &state, struct mdscli_get_results_state);
560 if (req == NULL) {
561 return NULL;
564 *state = (struct mdscli_get_results_state) {
565 .ev = ev,
566 .search = search,
569 status = mdscli_blob_get_results(state,
570 search,
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,
578 mdscli_ctx->bh,
579 &mdscli_ctx->ph,
581 mdscli_ctx->dev,
582 mdscli_ctx->mdscmd_open.unkn2,
584 mdscli_ctx->flags,
585 state->request_blob,
587 mdscli_ctx->max_fragment_size,
589 mdscli_ctx->max_fragment_size,
592 &state->fragment,
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++;
600 return req;
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;
615 size_t ncnids;
616 size_t i;
617 NTSTATUS status;
618 bool ok;
620 status = dcerpc_mdssvc_cmd_recv(subreq, state);
621 TALLOC_FREE(subreq);
622 state->search->mdscli_ctx->async_pending--;
623 if (tevent_req_nterror(req, status)) {
624 return;
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);
631 return;
634 ok = data_blob_realloc(state, &state->response_data, newsize);
635 if (!ok) {
636 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
637 return;
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(
649 state,
650 state->ev,
651 mdscli_ctx->bh,
652 &mdscli_ctx->ph,
654 mdscli_ctx->dev,
655 mdscli_ctx->mdscmd_open.unkn2,
657 mdscli_ctx->flags,
658 state->request_blob,
660 mdscli_ctx->max_fragment_size,
662 mdscli_ctx->max_fragment_size,
665 &state->fragment,
666 &state->response_fragment,
667 &mdscli_ctx->mdscmd_cmd.unkn9);
668 if (tevent_req_nomem(subreq, req)) {
669 tevent_req_post(req, state->ev);
670 return;
672 tevent_req_set_callback(subreq,
673 mdscli_get_results_cmd_done,
674 req);
675 mdscli_ctx->async_pending++;
676 return;
679 d = dalloc_new(state);
680 if (tevent_req_nomem(d, req)) {
681 return;
684 ok = sl_unpack(d,
685 (char *)state->response_data.data,
686 state->response_data.length);
687 if (!ok) {
688 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
689 return;
692 uint64p = dalloc_get(d,
693 "DALLOC_CTX", 0,
694 "uint64_t", 0);
695 if (uint64p == NULL) {
696 DBG_DEBUG("Unexpected mds response: %s", dalloc_dump(d, 0));
697 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
698 return;
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);
707 if (cnids == NULL) {
708 DBG_DEBUG("cnids error: %s", dalloc_dump(d, 0));
709 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
710 return;
713 ncnids = dalloc_size(cnids->ca_cnids);
714 if (ncnids == 0 && !search_in_progress) {
715 tevent_req_nterror(req, NT_STATUS_NO_MORE_MATCHES);
716 return;
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);
726 return;
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);
732 return;
735 state->cnids = talloc_zero_array(state, uint64_t, ncnids);
736 if (tevent_req_nomem(state->cnids, req)) {
737 return;
740 for (i = 0; i < ncnids; i++) {
741 uint64_t *cnid = NULL;
743 cnid = dalloc_get(cnids->ca_cnids, "uint64_t", i);
744 if (cnid == NULL) {
745 DBG_DEBUG("cnids error: %s", dalloc_dump(d, 0));
746 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
747 return;
749 state->cnids[i] = *cnid;
752 tevent_req_done(req);
753 return;
756 NTSTATUS mdscli_get_results_recv(struct tevent_req *req,
757 TALLOC_CTX *mem_ctx,
758 uint64_t **cnids)
760 struct mdscli_get_results_state *state = tevent_req_data(
761 req, struct mdscli_get_results_state);
762 NTSTATUS status;
764 if (tevent_req_is_nterror(req, &status)) {
765 tevent_req_received(req);
766 return status;
769 *cnids = talloc_move(mem_ctx, &state->cnids);
771 tevent_req_received(req);
772 return NT_STATUS_OK;
775 NTSTATUS mdscli_get_results(TALLOC_CTX *mem_ctx,
776 struct mdscli_search_ctx *search,
777 uint64_t **_cnids)
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;
786 goto fail;
789 ev = samba_tevent_context_init(frame);
790 if (ev == NULL) {
791 goto fail;
794 req = mdscli_get_results_send(frame,
796 search);
797 if (req == NULL) {
798 goto fail;
800 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
801 goto fail;
804 status = mdscli_get_results_recv(req, mem_ctx, _cnids);
805 fail:
806 TALLOC_FREE(frame);
807 return status;
810 struct mdscli_get_path_state {
811 struct mdscli_ctx *mdscli_ctx;
812 struct mdssvc_blob request_blob;
813 struct mdssvc_blob response_blob;
814 char *path;
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,
822 uint64_t cnid)
824 struct tevent_req *req = NULL;
825 struct mdscli_get_path_state *state = NULL;
826 struct tevent_req *subreq = NULL;
827 NTSTATUS status;
829 req = tevent_req_create(req, &state, struct mdscli_get_path_state);
830 if (req == NULL) {
831 return NULL;
833 *state = (struct mdscli_get_path_state) {
834 .mdscli_ctx = mdscli_ctx,
837 status = mdscli_blob_get_path(state,
838 mdscli_ctx,
839 cnid,
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,
847 mdscli_ctx->bh,
848 &mdscli_ctx->ph,
850 mdscli_ctx->dev,
851 mdscli_ctx->mdscmd_open.unkn2,
853 mdscli_ctx->flags,
854 state->request_blob,
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++;
869 return req;
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;
879 size_t pathlen;
880 size_t prefixlen;
881 char *path = NULL;
882 const char *p = NULL;
883 NTSTATUS status;
884 bool ok;
886 status = dcerpc_mdssvc_cmd_recv(subreq, state);
887 TALLOC_FREE(subreq);
888 state->mdscli_ctx->async_pending--;
889 if (tevent_req_nterror(req, status)) {
890 return;
893 d = dalloc_new(state);
894 if (tevent_req_nomem(d, req)) {
895 return;
898 ok = sl_unpack(d,
899 (char *)state->response_blob.spotlight_blob,
900 state->response_blob.length);
901 if (!ok) {
902 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
903 return;
906 path = dalloc_get(d,
907 "DALLOC_CTX", 0,
908 "DALLOC_CTX", 2,
909 "DALLOC_CTX", 0,
910 "DALLOC_CTX", 1,
911 "char *", 0);
912 if (path == NULL) {
913 DBG_DEBUG("No path in mds response: %s", dalloc_dump(d, 0));
914 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
915 return;
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);
931 return;
934 p = path + prefixlen;
935 while (*p == '/') {
936 p++;
938 if (*p == '\0') {
939 DBG_DEBUG("Bad path: %s\n", path);
940 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
941 return;
944 state->path = talloc_strdup(state, p);
945 if (state->path == NULL) {
946 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
947 return;
949 DBG_DEBUG("path: %s\n", state->path);
951 tevent_req_done(req);
952 return;
955 NTSTATUS mdscli_get_path_recv(struct tevent_req *req,
956 TALLOC_CTX *mem_ctx,
957 char **path)
959 struct mdscli_get_path_state *state = tevent_req_data(
960 req, struct mdscli_get_path_state);
961 NTSTATUS status;
963 if (tevent_req_is_nterror(req, &status)) {
964 tevent_req_received(req);
965 return status;
968 *path = talloc_move(mem_ctx, &state->path);
969 tevent_req_received(req);
970 return NT_STATUS_OK;
973 NTSTATUS mdscli_get_path(TALLOC_CTX *mem_ctx,
974 struct mdscli_ctx *mdscli_ctx,
975 uint64_t cnid,
976 char **path)
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;
985 goto fail;
988 ev = samba_tevent_context_init(frame);
989 if (ev == NULL) {
990 goto fail;
993 req = mdscli_get_path_send(frame, ev, mdscli_ctx, cnid);
994 if (req == NULL) {
995 goto fail;
997 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
998 goto fail;
1001 status = mdscli_get_path_recv(req, mem_ctx, path);
1002 fail:
1003 TALLOC_FREE(frame);
1004 return status;
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;
1023 NTSTATUS status;
1025 req = tevent_req_create(req, &state, struct mdscli_close_search_state);
1026 if (req == NULL) {
1027 return NULL;
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,
1035 state->search,
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,
1043 mdscli_ctx->bh,
1044 &mdscli_ctx->ph,
1046 mdscli_ctx->dev,
1047 mdscli_ctx->mdscmd_open.unkn2,
1049 mdscli_ctx->flags,
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++;
1065 return req;
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);
1074 NTSTATUS status;
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)) {
1080 return;
1083 tevent_req_done(req);
1084 return;
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;
1101 goto fail;
1104 ev = samba_tevent_context_init(frame);
1105 if (ev == NULL) {
1106 goto fail;
1109 req = mdscli_close_search_send(frame, ev, search);
1110 if (req == NULL) {
1111 goto fail;
1113 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1114 goto fail;
1117 status = mdscli_close_search_recv(req);
1118 fail:
1119 TALLOC_FREE(frame);
1120 return status;
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);
1138 if (req == NULL) {
1139 return NULL;
1141 *state = (struct mdscli_disconnect_state) {
1142 .mdscli_ctx = mdscli_ctx,
1145 subreq = dcerpc_mdssvc_close_send(state,
1147 mdscli_ctx->bh,
1148 &mdscli_ctx->ph,
1150 mdscli_ctx->dev,
1151 mdscli_ctx->mdscmd_open.unkn2,
1153 &mdscli_ctx->ph,
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++;
1160 return req;
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);
1169 NTSTATUS status;
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)) {
1175 return;
1178 tevent_req_done(req);
1179 return;
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;
1196 goto fail;
1199 ev = samba_tevent_context_init(frame);
1200 if (ev == NULL) {
1201 goto fail;
1204 req = mdscli_disconnect_send(frame, ev, mdscli_ctx);
1205 if (req == NULL) {
1206 goto fail;
1208 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1209 goto fail;
1212 status = mdscli_disconnect_recv(req);
1213 fail:
1214 TALLOC_FREE(frame);
1215 return status;