LCOV - code coverage report
Current view: top level - source3/rpc_client - cli_mdssvc.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 372 477 78.0 %
Date: 2021-09-23 10:06:22 Functions: 27 27 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Main metadata server / Spotlight client functions
       4             : 
       5             :    Copyright (C) Ralph Boehme 2019
       6             : 
       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.
      11             : 
      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.
      16             : 
      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/>.
      19             : */
      20             : 
      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"
      30             : 
      31          32 : struct mdsctx_id mdscli_new_ctx_id(struct mdscli_ctx *mdscli_ctx)
      32             : {
      33          32 :         mdscli_ctx->ctx_id.id++;
      34          32 :         return mdscli_ctx->ctx_id;
      35             : }
      36             : 
      37           8 : char *mdscli_get_basepath(TALLOC_CTX *mem_ctx,
      38             :                           struct mdscli_ctx *mdscli_ctx)
      39             : {
      40           8 :         return talloc_strdup(mem_ctx, mdscli_ctx->mdscmd_open.share_path);
      41             : }
      42             : 
      43             : struct mdscli_connect_state {
      44             :         struct tevent_context *ev;
      45             :         struct mdscli_ctx *mdscli_ctx;
      46             : };
      47             : 
      48             : static void mdscli_connect_open_done(struct tevent_req *subreq);
      49             : static void mdscli_connect_unknown1_done(struct tevent_req *subreq);
      50             : 
      51          12 : struct tevent_req *mdscli_connect_send(TALLOC_CTX *mem_ctx,
      52             :                                        struct tevent_context *ev,
      53             :                                        struct dcerpc_binding_handle *bh,
      54             :                                        const char *share_name,
      55             :                                        const char *mount_path)
      56             : {
      57          12 :         struct tevent_req *req = NULL;
      58          12 :         struct mdscli_connect_state *state = NULL;
      59          12 :         struct tevent_req *subreq = NULL;
      60          12 :         struct mdscli_ctx *ctx = NULL;
      61             : 
      62          12 :         req = tevent_req_create(req, &state, struct mdscli_connect_state);
      63          12 :         if (req == NULL) {
      64           0 :                 return NULL;
      65             :         }
      66             : 
      67          12 :         ctx = talloc_zero(state, struct mdscli_ctx);
      68          12 :         if (tevent_req_nomem(ctx, req)) {
      69           0 :                 return tevent_req_post(req, ev);
      70             :         }
      71             : 
      72          12 :         *state = (struct mdscli_connect_state) {
      73             :                 .ev = ev,
      74             :                 .mdscli_ctx = ctx,
      75             :         };
      76             : 
      77          12 :         *ctx = (struct mdscli_ctx) {
      78             :                 .bh = bh,
      79             :                 .max_fragment_size = 64 * 1024,
      80             :                 /*
      81             :                  * The connection id is a per tcon value sent by the client,
      82             :                  * 0x6b000060 is a value used most of the times for the first
      83             :                  * tcon.
      84             :                  */
      85             :                 .ctx_id.connection = UINT64_C(0x6b000060),
      86             :         };
      87             : 
      88          36 :         subreq = dcerpc_mdssvc_open_send(state,
      89          12 :                                          state->ev,
      90             :                                          ctx->bh,
      91             :                                          &ctx->dev,
      92             :                                          &ctx->mdscmd_open.unkn2,
      93             :                                          &ctx->mdscmd_open.unkn3,
      94             :                                          mount_path,
      95             :                                          share_name,
      96          12 :                                          ctx->mdscmd_open.share_path,
      97             :                                          &ctx->ph);
      98          12 :         if (tevent_req_nomem(subreq, req)) {
      99           0 :                 return tevent_req_post(req, state->ev);
     100             :         }
     101          12 :         tevent_req_set_callback(subreq, mdscli_connect_open_done, req);
     102          12 :         ctx->async_pending++;
     103             : 
     104          12 :         return req;
     105             : }
     106             : 
     107          12 : static void mdscli_connect_open_done(struct tevent_req *subreq)
     108             : {
     109          12 :         struct tevent_req *req = tevent_req_callback_data(
     110             :                 subreq, struct tevent_req);
     111          12 :         struct mdscli_connect_state *state = tevent_req_data(
     112             :                 req, struct mdscli_connect_state);
     113          12 :         struct mdscli_ctx *mdscli_ctx = state->mdscli_ctx;
     114             :         NTSTATUS status;
     115             : 
     116          12 :         status = dcerpc_mdssvc_open_recv(subreq, state);
     117          12 :         TALLOC_FREE(subreq);
     118          12 :         state->mdscli_ctx->async_pending--;
     119          12 :         if (tevent_req_nterror(req, status)) {
     120           0 :                 return;
     121             :         }
     122             : 
     123          12 :         subreq = dcerpc_mdssvc_unknown1_send(
     124             :                         state,
     125             :                         state->ev,
     126             :                         mdscli_ctx->bh,
     127             :                         &mdscli_ctx->ph,
     128             :                         0,
     129             :                         mdscli_ctx->dev,
     130             :                         mdscli_ctx->mdscmd_open.unkn2,
     131             :                         0,
     132             :                         geteuid(),
     133             :                         getegid(),
     134             :                         &mdscli_ctx->mdscmd_unknown1.status,
     135             :                         &mdscli_ctx->flags,
     136             :                         &mdscli_ctx->mdscmd_unknown1.unkn7);
     137          12 :         if (tevent_req_nomem(subreq, req)) {
     138           0 :                 return;
     139             :         }
     140          12 :         tevent_req_set_callback(subreq, mdscli_connect_unknown1_done, req);
     141             : }
     142             : 
     143          12 : static void mdscli_connect_unknown1_done(struct tevent_req *subreq)
     144             : {
     145          12 :         struct tevent_req *req = tevent_req_callback_data(
     146             :                 subreq, struct tevent_req);
     147          12 :         struct mdscli_connect_state *state = tevent_req_data(
     148             :                 req, struct mdscli_connect_state);
     149             :         NTSTATUS status;
     150             : 
     151          12 :         status = dcerpc_mdssvc_unknown1_recv(subreq, state);
     152          12 :         TALLOC_FREE(subreq);
     153          12 :         if (tevent_req_nterror(req, status)) {
     154           0 :                 return;
     155             :         }
     156             : 
     157          12 :         tevent_req_done(req);
     158             : }
     159             : 
     160          12 : NTSTATUS mdscli_connect_recv(struct tevent_req *req,
     161             :                              TALLOC_CTX *mem_ctx,
     162             :                              struct mdscli_ctx **mdscli_ctx)
     163             : {
     164          12 :         struct mdscli_connect_state *state = tevent_req_data(
     165             :                 req, struct mdscli_connect_state);
     166             :         NTSTATUS status;
     167             : 
     168          12 :         if (tevent_req_is_nterror(req, &status)) {
     169           0 :                 tevent_req_received(req);
     170           0 :                 return status;
     171             :         }
     172             : 
     173          12 :         *mdscli_ctx = talloc_move(mem_ctx, &state->mdscli_ctx);
     174          12 :         tevent_req_received(req);
     175          12 :         return NT_STATUS_OK;
     176             : }
     177             : 
     178           2 : NTSTATUS mdscli_connect(TALLOC_CTX *mem_ctx,
     179             :                         struct dcerpc_binding_handle *bh,
     180             :                         const char *share_name,
     181             :                         const char *mount_path,
     182             :                         struct mdscli_ctx **mdscli_ctx)
     183             : {
     184           2 :         TALLOC_CTX *frame = talloc_stackframe();
     185           2 :         struct tevent_req *req = NULL;
     186           2 :         struct tevent_context *ev = NULL;
     187           2 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     188             : 
     189           2 :         ev = samba_tevent_context_init(frame);
     190           2 :         if (ev == NULL) {
     191           0 :                 goto fail;
     192             :         }
     193             : 
     194           2 :         req = mdscli_connect_send(frame,
     195             :                                   ev,
     196             :                                   bh,
     197             :                                   share_name,
     198             :                                   mount_path);
     199           2 :         if (req == NULL) {
     200           0 :                 goto fail;
     201             :         }
     202           2 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     203           0 :                 goto fail;
     204             :         }
     205             : 
     206           2 :         status = mdscli_connect_recv(req, mem_ctx, mdscli_ctx);
     207           2 : fail:
     208           2 :         TALLOC_FREE(frame);
     209           2 :         return status;
     210             : }
     211             : 
     212             : struct mdscli_search_state {
     213             :         struct mdscli_search_ctx *search;
     214             :         struct mdssvc_blob request_blob;
     215             :         struct mdssvc_blob response_blob;
     216             : };
     217             : 
     218             : static void mdscli_search_cmd_done(struct tevent_req *subreq);
     219             : 
     220           6 : struct tevent_req *mdscli_search_send(TALLOC_CTX *mem_ctx,
     221             :                                       struct tevent_context *ev,
     222             :                                       struct mdscli_ctx *mdscli_ctx,
     223             :                                       const char *mds_query,
     224             :                                       const char *path_scope_in,
     225             :                                       bool live)
     226             : {
     227           6 :         struct tevent_req *req = NULL;
     228           6 :         struct mdscli_search_state *state = NULL;
     229           6 :         struct tevent_req *subreq = NULL;
     230           6 :         struct mdscli_search_ctx *search = NULL;
     231           6 :         char *path_scope = NULL;
     232             :         NTSTATUS status;
     233             : 
     234           6 :         req = tevent_req_create(req, &state, struct mdscli_search_state);
     235           6 :         if (req == NULL) {
     236           0 :                 return NULL;
     237             :         }
     238             : 
     239           6 :         search = talloc_zero(state, struct mdscli_search_ctx);
     240           6 :         if (tevent_req_nomem(search, req)) {
     241           0 :                 return tevent_req_post(req, ev);
     242             :         }
     243             : 
     244           6 :         if (path_scope_in[0] == '/') {
     245           6 :                 path_scope = talloc_strdup(search, path_scope_in);
     246             :         } else {
     247           0 :                 path_scope = talloc_asprintf(search,
     248             :                                              "%s/%s",
     249           0 :                                              mdscli_ctx->mdscmd_open.share_path,
     250             :                                              path_scope_in);
     251             :         }
     252           6 :         if (tevent_req_nomem(path_scope, req)) {
     253           0 :                 return tevent_req_post(req, ev);
     254             :         }
     255             : 
     256           6 :         *search = (struct mdscli_search_ctx) {
     257             :                 .mdscli_ctx = mdscli_ctx,
     258           6 :                 .ctx_id = mdscli_new_ctx_id(mdscli_ctx),
     259           6 :                 .unique_id = generate_random_u64(),
     260             :                 .live = live,
     261             :                 .path_scope = path_scope,
     262           6 :                 .mds_query = talloc_strdup(search, mds_query),
     263             :         };
     264           6 :         if (tevent_req_nomem(search->mds_query, req)) {
     265           0 :                 return tevent_req_post(req, ev);
     266             :         }
     267             : 
     268           6 :         *state = (struct mdscli_search_state) {
     269             :                 .search = search,
     270             :         };
     271             : 
     272           6 :         status = mdscli_blob_search(state,
     273             :                                     search,
     274           6 :                                     &state->request_blob);
     275           6 :         if (tevent_req_nterror(req, status)) {
     276           0 :                 return tevent_req_post(req, ev);
     277             :         }
     278             : 
     279           6 :         state->response_blob.spotlight_blob = talloc_array(
     280             :                 state,
     281             :                 uint8_t,
     282             :                 mdscli_ctx->max_fragment_size);
     283           6 :         if (tevent_req_nomem(state->response_blob.spotlight_blob, req)) {
     284           0 :                 return tevent_req_post(req, ev);
     285             :         }
     286           6 :         state->response_blob.size = mdscli_ctx->max_fragment_size;
     287             : 
     288          30 :         subreq = dcerpc_mdssvc_cmd_send(state,
     289             :                                         ev,
     290             :                                         mdscli_ctx->bh,
     291             :                                         &mdscli_ctx->ph,
     292             :                                         0,
     293             :                                         mdscli_ctx->dev,
     294             :                                         mdscli_ctx->mdscmd_open.unkn2,
     295             :                                         0,
     296             :                                         mdscli_ctx->flags,
     297           6 :                                         state->request_blob,
     298             :                                         0,
     299           6 :                                         mdscli_ctx->max_fragment_size,
     300             :                                         1,
     301           6 :                                         mdscli_ctx->max_fragment_size,
     302             :                                         0,
     303             :                                         0,
     304             :                                         &mdscli_ctx->mdscmd_cmd.fragment,
     305           6 :                                         &state->response_blob,
     306             :                                         &mdscli_ctx->mdscmd_cmd.unkn9);
     307           6 :         if (tevent_req_nomem(subreq, req)) {
     308           0 :                 return tevent_req_post(req, ev);
     309             :         }
     310           6 :         tevent_req_set_callback(subreq, mdscli_search_cmd_done, req);
     311           6 :         mdscli_ctx->async_pending++;
     312           6 :         return req;
     313             : }
     314             : 
     315           6 : static void mdscli_search_cmd_done(struct tevent_req *subreq)
     316             : {
     317           6 :         struct tevent_req *req = tevent_req_callback_data(
     318             :                 subreq, struct tevent_req);
     319           6 :         struct mdscli_search_state *state = tevent_req_data(
     320             :                 req, struct mdscli_search_state);
     321           6 :         DALLOC_CTX *d = NULL;
     322           6 :         uint64_t *uint64p = NULL;
     323             :         NTSTATUS status;
     324             :         bool ok;
     325             : 
     326           6 :         status = dcerpc_mdssvc_cmd_recv(subreq, state);
     327           6 :         TALLOC_FREE(subreq);
     328           6 :         state->search->mdscli_ctx->async_pending--;
     329           6 :         if (tevent_req_nterror(req, status)) {
     330           0 :                 return;
     331             :         }
     332             : 
     333           6 :         d = dalloc_new(state);
     334           6 :         if (tevent_req_nomem(d, req)) {
     335           0 :                 return;
     336             :         }
     337             : 
     338          12 :         ok = sl_unpack(d,
     339           6 :                        (char *)state->response_blob.spotlight_blob,
     340           6 :                        state->response_blob.length);
     341           6 :         if (!ok) {
     342           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     343           0 :                 return;
     344             :         }
     345             : 
     346           6 :         uint64p = dalloc_get(d,
     347             :                              "DALLOC_CTX", 0,
     348             :                              "uint64_t", 0);
     349           6 :         if (uint64p == NULL) {
     350           0 :                 DBG_DEBUG("Unexpected mds reponse: %s", dalloc_dump(d, 0));
     351           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     352           0 :                 return;
     353             :         }
     354             : 
     355           6 :         if (*uint64p != 0) {
     356           0 :                 DBG_DEBUG("Unexpected mds result: 0x%" PRIx64, *uint64p);
     357           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     358           0 :                 return;
     359             :         }
     360             : 
     361           6 :         tevent_req_done(req);
     362           6 :         return;
     363             : }
     364             : 
     365           6 : NTSTATUS mdscli_search_recv(struct tevent_req *req,
     366             :                             TALLOC_CTX *mem_ctx,
     367             :                             struct mdscli_search_ctx **search)
     368             : {
     369           6 :         struct mdscli_search_state *state = tevent_req_data(
     370             :                 req, struct mdscli_search_state);
     371             :         NTSTATUS status;
     372             : 
     373           6 :         if (tevent_req_is_nterror(req, &status)) {
     374           0 :                 tevent_req_received(req);
     375           0 :                 return status;
     376             :         }
     377             : 
     378           6 :         *search = talloc_move(mem_ctx, &state->search);
     379           6 :         tevent_req_received(req);
     380           6 :         return NT_STATUS_OK;
     381             : }
     382             : 
     383           2 : NTSTATUS mdscli_search(TALLOC_CTX *mem_ctx,
     384             :                        struct mdscli_ctx *mdscli_ctx,
     385             :                        const char *mds_query,
     386             :                        const char *path_scope,
     387             :                        bool live,
     388             :                        struct mdscli_search_ctx **search)
     389             : {
     390           2 :         TALLOC_CTX *frame = talloc_stackframe();
     391           2 :         struct tevent_req *req = NULL;
     392           2 :         struct tevent_context *ev = NULL;
     393           2 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     394             : 
     395           2 :         if (mdscli_ctx->async_pending != 0) {
     396           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     397           0 :                 goto fail;
     398             :         }
     399             : 
     400           2 :         ev = samba_tevent_context_init(frame);
     401           2 :         if (ev == NULL) {
     402           0 :                 goto fail;
     403             :         }
     404             : 
     405           2 :         req = mdscli_search_send(frame,
     406             :                                  ev,
     407             :                                  mdscli_ctx,
     408             :                                  mds_query,
     409             :                                  path_scope,
     410             :                                  live);
     411           2 :         if (req == NULL) {
     412           0 :                 goto fail;
     413             :         }
     414           2 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     415           0 :                 goto fail;
     416             :         }
     417             : 
     418           2 :         status = mdscli_search_recv(req, mem_ctx, search);
     419           2 : fail:
     420           2 :         TALLOC_FREE(frame);
     421           2 :         return status;
     422             : }
     423             : 
     424             : struct mdscli_get_results_state {
     425             :         struct mdscli_search_ctx *search;
     426             :         struct mdssvc_blob request_blob;
     427             :         struct mdssvc_blob response_blob;
     428             :         uint64_t *cnids;
     429             : };
     430             : 
     431             : static void mdscli_get_results_cmd_done(struct tevent_req *subreq);
     432             : 
     433           8 : struct tevent_req *mdscli_get_results_send(
     434             :                         TALLOC_CTX *mem_ctx,
     435             :                         struct tevent_context *ev,
     436             :                         struct mdscli_search_ctx *search)
     437             : {
     438           8 :         struct tevent_req *req = NULL;
     439           8 :         struct mdscli_get_results_state *state = NULL;
     440           8 :         struct tevent_req *subreq = NULL;
     441           8 :         struct mdscli_ctx *mdscli_ctx = search->mdscli_ctx;
     442             :         NTSTATUS status;
     443             : 
     444           8 :         req = tevent_req_create(req, &state, struct mdscli_get_results_state);
     445           8 :         if (req == NULL) {
     446           0 :                 return NULL;
     447             :         }
     448             : 
     449           8 :         *state = (struct mdscli_get_results_state) {
     450             :                 .search = search,
     451             :         };
     452             : 
     453           8 :         status = mdscli_blob_get_results(state,
     454             :                                          search,
     455           8 :                                          &state->request_blob);
     456           8 :         if (tevent_req_nterror(req, status)) {
     457           0 :                 return tevent_req_post(req, ev);
     458             :         }
     459             : 
     460           8 :         state->response_blob.spotlight_blob = talloc_array(
     461             :                 state,
     462             :                 uint8_t,
     463             :                 mdscli_ctx->max_fragment_size);
     464           8 :         if (tevent_req_nomem(state->response_blob.spotlight_blob, req)) {
     465           0 :                 return tevent_req_post(req, ev);
     466             :         }
     467           8 :         state->response_blob.size = mdscli_ctx->max_fragment_size;
     468             : 
     469          40 :         subreq = dcerpc_mdssvc_cmd_send(state,
     470             :                                         ev,
     471             :                                         mdscli_ctx->bh,
     472             :                                         &mdscli_ctx->ph,
     473             :                                         0,
     474             :                                         mdscli_ctx->dev,
     475             :                                         mdscli_ctx->mdscmd_open.unkn2,
     476             :                                         0,
     477             :                                         mdscli_ctx->flags,
     478           8 :                                         state->request_blob,
     479             :                                         0,
     480           8 :                                         mdscli_ctx->max_fragment_size,
     481             :                                         1,
     482           8 :                                         mdscli_ctx->max_fragment_size,
     483             :                                         0,
     484             :                                         0,
     485             :                                         &mdscli_ctx->mdscmd_cmd.fragment,
     486           8 :                                         &state->response_blob,
     487             :                                         &mdscli_ctx->mdscmd_cmd.unkn9);
     488           8 :         if (tevent_req_nomem(subreq, req)) {
     489           0 :                 return tevent_req_post(req, ev);
     490             :         }
     491           8 :         tevent_req_set_callback(subreq, mdscli_get_results_cmd_done, req);
     492           8 :         mdscli_ctx->async_pending++;
     493           8 :         return req;
     494             : }
     495             : 
     496           8 : static void mdscli_get_results_cmd_done(struct tevent_req *subreq)
     497             : {
     498           8 :         struct tevent_req *req = tevent_req_callback_data(
     499             :                 subreq, struct tevent_req);
     500           8 :         struct mdscli_get_results_state *state = tevent_req_data(
     501             :                 req, struct mdscli_get_results_state);
     502           8 :         DALLOC_CTX *d = NULL;
     503           8 :         uint64_t *uint64p = NULL;
     504           8 :         sl_cnids_t *cnids = NULL;
     505             :         size_t ncnids;
     506             :         size_t i;
     507             :         NTSTATUS status;
     508             :         bool ok;
     509             : 
     510           8 :         status = dcerpc_mdssvc_cmd_recv(subreq, state);
     511           8 :         TALLOC_FREE(subreq);
     512           8 :         state->search->mdscli_ctx->async_pending--;
     513           8 :         if (tevent_req_nterror(req, status)) {
     514           0 :                 return;
     515             :         }
     516             : 
     517           8 :         d = dalloc_new(state);
     518           8 :         if (tevent_req_nomem(d, req)) {
     519           0 :                 return;
     520             :         }
     521             : 
     522          16 :         ok = sl_unpack(d,
     523           8 :                        (char *)state->response_blob.spotlight_blob,
     524           8 :                        state->response_blob.length);
     525           8 :         if (!ok) {
     526           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     527           0 :                 return;
     528             :         }
     529             : 
     530           8 :         uint64p = dalloc_get(d,
     531             :                              "DALLOC_CTX", 0,
     532             :                              "uint64_t", 0);
     533           8 :         if (uint64p == NULL) {
     534           0 :                 DBG_DEBUG("Unexpected mds reponse: %s", dalloc_dump(d, 0));
     535           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     536           0 :                 return;
     537             :         }
     538             : 
     539           8 :         if (*uint64p == 35) {
     540           0 :                 DBG_DEBUG("search done: %s", dalloc_dump(d, 0));
     541           0 :                 tevent_req_done(req);
     542           0 :                 return;
     543             :         }
     544             : 
     545           8 :         cnids = dalloc_get(d, "DALLOC_CTX", 0, "sl_cnids_t", 1);
     546           8 :         if (cnids == NULL) {
     547           0 :                 DBG_DEBUG("cnids error: %s", dalloc_dump(d, 0));
     548           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     549           0 :                 return;
     550             :         }
     551             : 
     552           8 :         ncnids = dalloc_size(cnids->ca_cnids);
     553           8 :         if (ncnids == 0) {
     554           2 :                 tevent_req_nterror(req, NT_STATUS_NO_MORE_MATCHES);
     555           2 :                 return;
     556             :         }
     557             : 
     558           6 :         if (cnids->ca_unkn1 != 0xadd) {
     559             :                 /*
     560             :                  * Whatever 0xadd means... but it seems to be the standard value
     561             :                  * macOS mdssvc returns here.
     562             :                  */
     563           0 :                 DBG_DEBUG("unexpected ca_unkn1: %s", dalloc_dump(d, 0));
     564           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     565           0 :                 return;
     566             :         }
     567             : 
     568           6 :         if (cnids->ca_context != state->search->ctx_id.connection ) {
     569           0 :                 DBG_DEBUG("unexpected ca_context: %s", dalloc_dump(d, 0));
     570           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     571           0 :                 return;
     572             :         }
     573             : 
     574           6 :         state->cnids = talloc_zero_array(state, uint64_t, ncnids);
     575           6 :         if (tevent_req_nomem(state->cnids, req)) {
     576           0 :                 return;
     577             :         }
     578             : 
     579          32 :         for (i = 0; i < ncnids; i++) {
     580          26 :                 uint64_t *cnid = NULL;
     581             : 
     582          26 :                 cnid = dalloc_get(cnids->ca_cnids, "uint64_t", i);
     583          26 :                 if (cnid == NULL) {
     584           0 :                         DBG_DEBUG("cnids error: %s", dalloc_dump(d, 0));
     585           0 :                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     586           0 :                         return;
     587             :                 }
     588          26 :                 state->cnids[i] = *cnid;
     589             :         }
     590             : 
     591           6 :         tevent_req_done(req);
     592           6 :         return;
     593             : }
     594             : 
     595           8 : NTSTATUS mdscli_get_results_recv(struct tevent_req *req,
     596             :                                  TALLOC_CTX *mem_ctx,
     597             :                                  uint64_t **cnids)
     598             : {
     599           8 :         struct mdscli_get_results_state *state = tevent_req_data(
     600             :                 req, struct mdscli_get_results_state);
     601             :         NTSTATUS status;
     602             : 
     603           8 :         if (tevent_req_is_nterror(req, &status)) {
     604           2 :                 tevent_req_received(req);
     605           2 :                 return status;
     606             :         }
     607             : 
     608           6 :         *cnids = talloc_move(mem_ctx, &state->cnids);
     609             : 
     610           6 :         tevent_req_received(req);
     611           6 :         return NT_STATUS_OK;
     612             : }
     613             : 
     614           4 : NTSTATUS mdscli_get_results(TALLOC_CTX *mem_ctx,
     615             :                             struct mdscli_search_ctx *search,
     616             :                             uint64_t **_cnids)
     617             : {
     618           4 :         TALLOC_CTX *frame = talloc_stackframe();
     619           4 :         struct tevent_req *req = NULL;
     620           4 :         struct tevent_context *ev = NULL;
     621           4 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     622             : 
     623           4 :         if (search->mdscli_ctx->async_pending != 0) {
     624           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     625           0 :                 goto fail;
     626             :         }
     627             : 
     628           4 :         ev = samba_tevent_context_init(frame);
     629           4 :         if (ev == NULL) {
     630           0 :                 goto fail;
     631             :         }
     632             : 
     633           4 :         req = mdscli_get_results_send(frame,
     634             :                                       ev,
     635             :                                       search);
     636           4 :         if (req == NULL) {
     637           0 :                 goto fail;
     638             :         }
     639           4 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     640           0 :                 goto fail;
     641             :         }
     642             : 
     643           4 :         status = mdscli_get_results_recv(req, mem_ctx, _cnids);
     644           4 : fail:
     645           4 :         TALLOC_FREE(frame);
     646           4 :         return status;
     647             : }
     648             : 
     649             : struct mdscli_get_path_state {
     650             :         struct mdscli_ctx *mdscli_ctx;
     651             :         struct mdssvc_blob request_blob;
     652             :         struct mdssvc_blob response_blob;
     653             :         char *path;
     654             : };
     655             : 
     656             : static void mdscli_get_path_done(struct tevent_req *subreq);
     657             : 
     658          26 : struct tevent_req *mdscli_get_path_send(TALLOC_CTX *mem_ctx,
     659             :                                         struct tevent_context *ev,
     660             :                                         struct mdscli_ctx *mdscli_ctx,
     661             :                                         uint64_t cnid)
     662             : {
     663          26 :         struct tevent_req *req = NULL;
     664          26 :         struct mdscli_get_path_state *state = NULL;
     665          26 :         struct tevent_req *subreq = NULL;
     666             :         NTSTATUS status;
     667             : 
     668          26 :         req = tevent_req_create(req, &state, struct mdscli_get_path_state);
     669          26 :         if (req == NULL) {
     670           0 :                 return NULL;
     671             :         }
     672          26 :         *state = (struct mdscli_get_path_state) {
     673             :                 .mdscli_ctx = mdscli_ctx,
     674             :         };
     675             : 
     676          26 :         status = mdscli_blob_get_path(state,
     677             :                                       mdscli_ctx,
     678             :                                       cnid,
     679          26 :                                       &state->request_blob);
     680          26 :         if (tevent_req_nterror(req, status)) {
     681           0 :                 return tevent_req_post(req, ev);
     682             :         }
     683             : 
     684          26 :         state->response_blob.spotlight_blob = talloc_array(
     685             :                 state,
     686             :                 uint8_t,
     687             :                 mdscli_ctx->max_fragment_size);
     688          26 :         if (tevent_req_nomem(state->response_blob.spotlight_blob, req)) {
     689           0 :                 return tevent_req_post(req, ev);
     690             :         }
     691          26 :         state->response_blob.size = mdscli_ctx->max_fragment_size;
     692             : 
     693         130 :         subreq = dcerpc_mdssvc_cmd_send(state,
     694             :                                         ev,
     695             :                                         mdscli_ctx->bh,
     696             :                                         &mdscli_ctx->ph,
     697             :                                         0,
     698             :                                         mdscli_ctx->dev,
     699             :                                         mdscli_ctx->mdscmd_open.unkn2,
     700             :                                         0,
     701             :                                         mdscli_ctx->flags,
     702          26 :                                         state->request_blob,
     703             :                                         0,
     704          26 :                                         mdscli_ctx->max_fragment_size,
     705             :                                         1,
     706          26 :                                         mdscli_ctx->max_fragment_size,
     707             :                                         0,
     708             :                                         0,
     709             :                                         &mdscli_ctx->mdscmd_cmd.fragment,
     710          26 :                                         &state->response_blob,
     711             :                                         &mdscli_ctx->mdscmd_cmd.unkn9);
     712          26 :         if (tevent_req_nomem(subreq, req)) {
     713           0 :                 return tevent_req_post(req, ev);
     714             :         }
     715          26 :         tevent_req_set_callback(subreq, mdscli_get_path_done, req);
     716          26 :         mdscli_ctx->async_pending++;
     717          26 :         return req;
     718             : }
     719             : 
     720          26 : static void mdscli_get_path_done(struct tevent_req *subreq)
     721             : {
     722          26 :         struct tevent_req *req = tevent_req_callback_data(
     723             :                 subreq, struct tevent_req);
     724          26 :         struct mdscli_get_path_state *state = tevent_req_data(
     725             :                 req, struct mdscli_get_path_state);
     726          26 :         DALLOC_CTX *d = NULL;
     727          26 :         char *path = NULL;
     728             :         NTSTATUS status;
     729             :         bool ok;
     730             : 
     731          26 :         status = dcerpc_mdssvc_cmd_recv(subreq, state);
     732          26 :         TALLOC_FREE(subreq);
     733          26 :         state->mdscli_ctx->async_pending--;
     734          26 :         if (tevent_req_nterror(req, status)) {
     735           0 :                 return;
     736             :         }
     737             : 
     738          26 :         d = dalloc_new(state);
     739          26 :         if (tevent_req_nomem(d, req)) {
     740           0 :                 return;
     741             :         }
     742             : 
     743          52 :         ok = sl_unpack(d,
     744          26 :                        (char *)state->response_blob.spotlight_blob,
     745          26 :                        state->response_blob.length);
     746          26 :         if (!ok) {
     747           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     748           0 :                 return;
     749             :         }
     750             : 
     751          26 :         path = dalloc_get(d,
     752             :                           "DALLOC_CTX", 0,
     753             :                           "DALLOC_CTX", 2,
     754             :                           "DALLOC_CTX", 0,
     755             :                           "DALLOC_CTX", 1,
     756             :                           "char *", 0);
     757          26 :         if (path == NULL) {
     758           0 :                 DBG_DEBUG("No path in mds reponse: %s", dalloc_dump(d, 0));
     759           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     760           0 :                 return;
     761             :         }
     762          26 :         state->path = talloc_move(state, &path);
     763          26 :         DBG_DEBUG("path: %s\n", state->path);
     764             : 
     765          26 :         tevent_req_done(req);
     766          26 :         return;
     767             : }
     768             : 
     769          26 : NTSTATUS mdscli_get_path_recv(struct tevent_req *req,
     770             :                               TALLOC_CTX *mem_ctx,
     771             :                               char **path)
     772             : {
     773          26 :         struct mdscli_get_path_state *state = tevent_req_data(
     774             :                 req, struct mdscli_get_path_state);
     775             :         NTSTATUS status;
     776             : 
     777          26 :         if (tevent_req_is_nterror(req, &status)) {
     778           0 :                 tevent_req_received(req);
     779           0 :                 return status;
     780             :         }
     781             : 
     782          26 :         *path = talloc_move(mem_ctx, &state->path);
     783          26 :         tevent_req_received(req);
     784          26 :         return NT_STATUS_OK;
     785             : }
     786             : 
     787           4 : NTSTATUS mdscli_get_path(TALLOC_CTX *mem_ctx,
     788             :                          struct mdscli_ctx *mdscli_ctx,
     789             :                          uint64_t cnid,
     790             :                          char **path)
     791             : {
     792           4 :         TALLOC_CTX *frame = talloc_stackframe();
     793           4 :         struct tevent_req *req = NULL;
     794           4 :         struct tevent_context *ev = NULL;
     795           4 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     796             : 
     797           4 :         if (mdscli_ctx->async_pending != 0) {
     798           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     799           0 :                 goto fail;
     800             :         }
     801             : 
     802           4 :         ev = samba_tevent_context_init(frame);
     803           4 :         if (ev == NULL) {
     804           0 :                 goto fail;
     805             :         }
     806             : 
     807           4 :         req = mdscli_get_path_send(frame, ev, mdscli_ctx, cnid);
     808           4 :         if (req == NULL) {
     809           0 :                 goto fail;
     810             :         }
     811           4 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     812           0 :                 goto fail;
     813             :         }
     814             : 
     815           4 :         status = mdscli_get_path_recv(req, mem_ctx, path);
     816           4 : fail:
     817           4 :         TALLOC_FREE(frame);
     818           4 :         return status;
     819             : }
     820             : 
     821             : struct mdscli_close_search_state {
     822             :         struct mdscli_search_ctx *search;
     823             :         struct mdssvc_blob request_blob;
     824             :         struct mdssvc_blob response_blob;
     825             : };
     826             : 
     827             : static void mdscli_close_search_done(struct tevent_req *subreq);
     828             : 
     829           6 : struct tevent_req *mdscli_close_search_send(TALLOC_CTX *mem_ctx,
     830             :                                             struct tevent_context *ev,
     831             :                                             struct mdscli_search_ctx **search)
     832             : {
     833           6 :         struct mdscli_ctx *mdscli_ctx = NULL;
     834           6 :         struct tevent_req *req = NULL;
     835           6 :         struct mdscli_close_search_state *state = NULL;
     836           6 :         struct tevent_req *subreq = NULL;
     837             :         NTSTATUS status;
     838             : 
     839           6 :         req = tevent_req_create(req, &state, struct mdscli_close_search_state);
     840           6 :         if (req == NULL) {
     841           0 :                 return NULL;
     842             :         }
     843          12 :         *state = (struct mdscli_close_search_state) {
     844           6 :                 .search = talloc_move(state, search),
     845             :         };
     846           6 :         mdscli_ctx = state->search->mdscli_ctx;
     847             : 
     848          12 :         status = mdscli_blob_close_search(state,
     849           6 :                                           state->search,
     850           6 :                                           &state->request_blob);
     851           6 :         if (tevent_req_nterror(req, status)) {
     852           0 :                 return tevent_req_post(req, ev);
     853             :         }
     854             : 
     855           6 :         state->response_blob.spotlight_blob = talloc_array(
     856             :                 state,
     857             :                 uint8_t,
     858             :                 mdscli_ctx->max_fragment_size);
     859           6 :         if (tevent_req_nomem(state->response_blob.spotlight_blob, req)) {
     860           0 :                 return tevent_req_post(req, ev);
     861             :         }
     862           6 :         state->response_blob.size = mdscli_ctx->max_fragment_size;
     863             : 
     864          30 :         subreq = dcerpc_mdssvc_cmd_send(state,
     865             :                                         ev,
     866             :                                         mdscli_ctx->bh,
     867             :                                         &mdscli_ctx->ph,
     868             :                                         0,
     869             :                                         mdscli_ctx->dev,
     870             :                                         mdscli_ctx->mdscmd_open.unkn2,
     871             :                                         0,
     872             :                                         mdscli_ctx->flags,
     873           6 :                                         state->request_blob,
     874             :                                         0,
     875           6 :                                         mdscli_ctx->max_fragment_size,
     876             :                                         1,
     877           6 :                                         mdscli_ctx->max_fragment_size,
     878             :                                         0,
     879             :                                         0,
     880             :                                         &mdscli_ctx->mdscmd_cmd.fragment,
     881           6 :                                         &state->response_blob,
     882             :                                         &mdscli_ctx->mdscmd_cmd.unkn9);
     883           6 :         if (tevent_req_nomem(subreq, req)) {
     884           0 :                 return tevent_req_post(req, ev);
     885             :         }
     886           6 :         tevent_req_set_callback(subreq, mdscli_close_search_done, req);
     887           6 :         mdscli_ctx->async_pending++;
     888           6 :         return req;
     889             : }
     890             : 
     891           6 : static void mdscli_close_search_done(struct tevent_req *subreq)
     892             : {
     893           6 :         struct tevent_req *req = tevent_req_callback_data(
     894             :                 subreq, struct tevent_req);
     895           6 :         struct mdscli_close_search_state *state = tevent_req_data(
     896             :                 req, struct mdscli_close_search_state);
     897             :         NTSTATUS status;
     898             : 
     899           6 :         status = dcerpc_mdssvc_cmd_recv(subreq, state);
     900           6 :         TALLOC_FREE(subreq);
     901           6 :         state->search->mdscli_ctx->async_pending--;
     902           6 :         if (tevent_req_nterror(req, status)) {
     903           0 :                 return;
     904             :         }
     905             : 
     906           6 :         tevent_req_done(req);
     907           6 :         return;
     908             : }
     909             : 
     910           6 : NTSTATUS mdscli_close_search_recv(struct tevent_req *req)
     911             : {
     912           6 :         return tevent_req_simple_recv_ntstatus(req);
     913             : }
     914             : 
     915           2 : NTSTATUS mdscli_close_search(struct mdscli_search_ctx **search)
     916             : {
     917           2 :         TALLOC_CTX *frame = talloc_stackframe();
     918           2 :         struct tevent_req *req = NULL;
     919           2 :         struct tevent_context *ev = NULL;
     920           2 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     921             : 
     922           2 :         if ((*search)->mdscli_ctx->async_pending != 0) {
     923           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     924           0 :                 goto fail;
     925             :         }
     926             : 
     927           2 :         ev = samba_tevent_context_init(frame);
     928           2 :         if (ev == NULL) {
     929           0 :                 goto fail;
     930             :         }
     931             : 
     932           2 :         req = mdscli_close_search_send(frame, ev, search);
     933           2 :         if (req == NULL) {
     934           0 :                 goto fail;
     935             :         }
     936           2 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     937           0 :                 goto fail;
     938             :         }
     939             : 
     940           2 :         status = mdscli_close_search_recv(req);
     941           2 : fail:
     942           2 :         TALLOC_FREE(frame);
     943           2 :         return status;
     944             : }
     945             : 
     946             : struct mdscli_disconnect_state {
     947             :         struct mdscli_ctx *mdscli_ctx;
     948             : };
     949             : 
     950             : static void mdscli_disconnect_done(struct tevent_req *subreq);
     951             : 
     952          12 : struct tevent_req *mdscli_disconnect_send(TALLOC_CTX *mem_ctx,
     953             :                                           struct tevent_context *ev,
     954             :                                           struct mdscli_ctx *mdscli_ctx)
     955             : {
     956          12 :         struct tevent_req *req = NULL;
     957          12 :         struct mdscli_disconnect_state *state = NULL;
     958          12 :         struct tevent_req *subreq = NULL;
     959             : 
     960          12 :         req = tevent_req_create(req, &state, struct mdscli_disconnect_state);
     961          12 :         if (req == NULL) {
     962           0 :                 return NULL;
     963             :         }
     964          12 :         *state = (struct mdscli_disconnect_state) {
     965             :                 .mdscli_ctx = mdscli_ctx,
     966             :         };
     967             : 
     968          12 :         subreq = dcerpc_mdssvc_close_send(state,
     969             :                                           ev,
     970             :                                           mdscli_ctx->bh,
     971             :                                           &mdscli_ctx->ph,
     972             :                                           0,
     973             :                                           mdscli_ctx->dev,
     974             :                                           mdscli_ctx->mdscmd_open.unkn2,
     975             :                                           0,
     976             :                                           &mdscli_ctx->ph,
     977             :                                           &mdscli_ctx->mdscmd_close.status);
     978          12 :         if (tevent_req_nomem(subreq, req)) {
     979           0 :                 return tevent_req_post(req, ev);
     980             :         }
     981          12 :         tevent_req_set_callback(subreq, mdscli_disconnect_done, req);
     982          12 :         mdscli_ctx->async_pending++;
     983          12 :         return req;
     984             : }
     985             : 
     986          12 : static void mdscli_disconnect_done(struct tevent_req *subreq)
     987             : {
     988          12 :         struct tevent_req *req = tevent_req_callback_data(
     989             :                 subreq, struct tevent_req);
     990          12 :         struct mdscli_disconnect_state *state = tevent_req_data(
     991             :                 req, struct mdscli_disconnect_state);
     992             :         NTSTATUS status;
     993             : 
     994          12 :         status = dcerpc_mdssvc_close_recv(subreq, state);
     995          12 :         TALLOC_FREE(subreq);
     996          12 :         state->mdscli_ctx->async_pending--;
     997          12 :         if (tevent_req_nterror(req, status)) {
     998           0 :                 return;
     999             :         }
    1000             : 
    1001          12 :         tevent_req_done(req);
    1002          12 :         return;
    1003             : }
    1004             : 
    1005          12 : NTSTATUS mdscli_disconnect_recv(struct tevent_req *req)
    1006             : {
    1007          12 :         return tevent_req_simple_recv_ntstatus(req);
    1008             : }
    1009             : 
    1010           2 : NTSTATUS mdscli_disconnect(struct mdscli_ctx *mdscli_ctx)
    1011             : {
    1012           2 :         TALLOC_CTX *frame = talloc_stackframe();
    1013           2 :         struct tevent_req *req = NULL;
    1014           2 :         struct tevent_context *ev = NULL;
    1015           2 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    1016             : 
    1017           2 :         if (mdscli_ctx->async_pending != 0) {
    1018           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    1019           0 :                 goto fail;
    1020             :         }
    1021             : 
    1022           2 :         ev = samba_tevent_context_init(frame);
    1023           2 :         if (ev == NULL) {
    1024           0 :                 goto fail;
    1025             :         }
    1026             : 
    1027           2 :         req = mdscli_disconnect_send(frame, ev, mdscli_ctx);
    1028           2 :         if (req == NULL) {
    1029           0 :                 goto fail;
    1030             :         }
    1031           2 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    1032           0 :                 goto fail;
    1033             :         }
    1034             : 
    1035           2 :         status = mdscli_disconnect_recv(req);
    1036           2 : fail:
    1037           2 :         TALLOC_FREE(frame);
    1038           2 :         return status;
    1039             : }

Generated by: LCOV version 1.13