LCOV - code coverage report
Current view: top level - source3/rpc_client - cli_mdssvc.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 427 568 75.2 %
Date: 2024-04-21 15:09:00 Functions: 28 28 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           6 : char *mdscli_get_basepath(TALLOC_CTX *mem_ctx,
      38             :                           struct mdscli_ctx *mdscli_ctx)
      39             : {
      40           6 :         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             :         struct mdssvc_blob response_blob;
      47             : };
      48             : 
      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);
      52             : 
      53          10 : 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)
      58             : {
      59          10 :         struct tevent_req *req = NULL;
      60          10 :         struct mdscli_connect_state *state = NULL;
      61          10 :         struct tevent_req *subreq = NULL;
      62          10 :         struct mdscli_ctx *ctx = NULL;
      63             : 
      64          10 :         req = tevent_req_create(req, &state, struct mdscli_connect_state);
      65          10 :         if (req == NULL) {
      66           0 :                 return NULL;
      67             :         }
      68             : 
      69          10 :         ctx = talloc_zero(state, struct mdscli_ctx);
      70          10 :         if (tevent_req_nomem(ctx, req)) {
      71           0 :                 return tevent_req_post(req, ev);
      72             :         }
      73             : 
      74          10 :         *state = (struct mdscli_connect_state) {
      75             :                 .ev = ev,
      76             :                 .mdscli_ctx = ctx,
      77             :         };
      78             : 
      79          10 :         *ctx = (struct mdscli_ctx) {
      80             :                 .bh = bh,
      81             :                 .max_fragment_size = 64 * 1024,
      82             :                 /*
      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.
      86             :                  */
      87             :                 .ctx_id.connection = UINT64_C(0x6b000060),
      88             :         };
      89             : 
      90          10 :         subreq = dcerpc_mdssvc_open_send(state,
      91          10 :                                          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          10 :                                          ctx->mdscmd_open.share_path,
      99             :                                          &ctx->ph);
     100          10 :         if (tevent_req_nomem(subreq, req)) {
     101           0 :                 return tevent_req_post(req, state->ev);
     102             :         }
     103          10 :         tevent_req_set_callback(subreq, mdscli_connect_open_done, req);
     104          10 :         ctx->async_pending++;
     105             : 
     106          10 :         return req;
     107             : }
     108             : 
     109          10 : static void mdscli_connect_open_done(struct tevent_req *subreq)
     110             : {
     111          10 :         struct tevent_req *req = tevent_req_callback_data(
     112             :                 subreq, struct tevent_req);
     113          10 :         struct mdscli_connect_state *state = tevent_req_data(
     114             :                 req, struct mdscli_connect_state);
     115          10 :         struct mdscli_ctx *mdscli_ctx = state->mdscli_ctx;
     116             :         size_t share_path_len;
     117             :         NTSTATUS status;
     118             : 
     119          10 :         status = dcerpc_mdssvc_open_recv(subreq, state);
     120          10 :         TALLOC_FREE(subreq);
     121          10 :         state->mdscli_ctx->async_pending--;
     122          10 :         if (tevent_req_nterror(req, status)) {
     123           0 :                 return;
     124             :         }
     125             : 
     126          10 :         share_path_len = strlen(mdscli_ctx->mdscmd_open.share_path);
     127          10 :         if (share_path_len < 1 || share_path_len > UINT16_MAX) {
     128           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     129           0 :                 return;
     130             :         }
     131          10 :         mdscli_ctx->mdscmd_open.share_path_len = share_path_len;
     132             : 
     133          10 :         if (mdscli_ctx->mdscmd_open.share_path[share_path_len-1] == '/') {
     134           0 :                 mdscli_ctx->mdscmd_open.share_path[share_path_len-1] = '\0';
     135           0 :                 mdscli_ctx->mdscmd_open.share_path_len--;
     136             :         }
     137             : 
     138          10 :         subreq = dcerpc_mdssvc_unknown1_send(
     139             :                         state,
     140             :                         state->ev,
     141             :                         mdscli_ctx->bh,
     142             :                         &mdscli_ctx->ph,
     143             :                         0,
     144             :                         mdscli_ctx->dev,
     145             :                         mdscli_ctx->mdscmd_open.unkn2,
     146             :                         0,
     147             :                         geteuid(),
     148             :                         getegid(),
     149             :                         &mdscli_ctx->mdscmd_unknown1.status,
     150             :                         &mdscli_ctx->flags,
     151             :                         &mdscli_ctx->mdscmd_unknown1.unkn7);
     152          10 :         if (tevent_req_nomem(subreq, req)) {
     153           0 :                 return;
     154             :         }
     155          10 :         tevent_req_set_callback(subreq, mdscli_connect_unknown1_done, req);
     156             : }
     157             : 
     158          10 : static void mdscli_connect_unknown1_done(struct tevent_req *subreq)
     159             : {
     160          10 :         struct tevent_req *req = tevent_req_callback_data(
     161             :                 subreq, struct tevent_req);
     162          10 :         struct mdscli_connect_state *state = tevent_req_data(
     163             :                 req, struct mdscli_connect_state);
     164          10 :         struct mdscli_ctx *mdscli_ctx = state->mdscli_ctx;
     165             :         struct mdssvc_blob request_blob;
     166             :         NTSTATUS status;
     167             : 
     168          10 :         status = dcerpc_mdssvc_unknown1_recv(subreq, state);
     169          10 :         TALLOC_FREE(subreq);
     170          10 :         if (tevent_req_nterror(req, status)) {
     171           0 :                 return;
     172             :         }
     173             : 
     174          10 :         status = mdscli_blob_fetch_props(state,
     175             :                                          state->mdscli_ctx,
     176             :                                          &request_blob);
     177          10 :         if (tevent_req_nterror(req, status)) {
     178           0 :                 return;
     179             :         }
     180             : 
     181          10 :         subreq = dcerpc_mdssvc_cmd_send(state,
     182             :                                         state->ev,
     183             :                                         mdscli_ctx->bh,
     184             :                                         &mdscli_ctx->ph,
     185             :                                         0,
     186             :                                         mdscli_ctx->dev,
     187             :                                         mdscli_ctx->mdscmd_open.unkn2,
     188             :                                         0,
     189             :                                         mdscli_ctx->flags,
     190             :                                         request_blob,
     191             :                                         0,
     192          10 :                                         mdscli_ctx->max_fragment_size,
     193             :                                         1,
     194          10 :                                         mdscli_ctx->max_fragment_size,
     195             :                                         0,
     196             :                                         0,
     197             :                                         &mdscli_ctx->mdscmd_cmd.fragment,
     198             :                                         &state->response_blob,
     199             :                                         &mdscli_ctx->mdscmd_cmd.unkn9);
     200          10 :         if (tevent_req_nomem(subreq, req)) {
     201           0 :                 return;
     202             :         }
     203          10 :         tevent_req_set_callback(subreq, mdscli_connect_fetch_props_done, req);
     204          10 :         mdscli_ctx->async_pending++;
     205          10 :         return;
     206             : }
     207             : 
     208          10 : static void mdscli_connect_fetch_props_done(struct tevent_req *subreq)
     209             : {
     210          10 :         struct tevent_req *req = tevent_req_callback_data(
     211             :                 subreq, struct tevent_req);
     212          10 :         struct mdscli_connect_state *state = tevent_req_data(
     213             :                 req, struct mdscli_connect_state);
     214          10 :         struct mdscli_ctx *mdscli_ctx = state->mdscli_ctx;
     215          10 :         DALLOC_CTX *d = NULL;
     216          10 :         sl_array_t *path_scope_array = NULL;
     217          10 :         char *path_scope = NULL;
     218             :         NTSTATUS status;
     219             :         bool ok;
     220             : 
     221          10 :         status = dcerpc_mdssvc_cmd_recv(subreq, state);
     222          10 :         TALLOC_FREE(subreq);
     223          10 :         state->mdscli_ctx->async_pending--;
     224          10 :         if (tevent_req_nterror(req, status)) {
     225           0 :                 return;
     226             :         }
     227             : 
     228          10 :         d = dalloc_new(state);
     229          10 :         if (tevent_req_nomem(d, req)) {
     230           0 :                 return;
     231             :         }
     232             : 
     233          10 :         ok = sl_unpack(d,
     234          10 :                        (char *)state->response_blob.spotlight_blob,
     235          10 :                        state->response_blob.length);
     236          10 :         if (!ok) {
     237           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     238           0 :                 return;
     239             :         }
     240             : 
     241          10 :         path_scope_array = dalloc_value_for_key(d,
     242             :                                                 "DALLOC_CTX", 0,
     243             :                                                 "kMDSStorePathScopes",
     244             :                                                 "sl_array_t");
     245          10 :         if (path_scope_array == NULL) {
     246           0 :                 DBG_ERR("Missing kMDSStorePathScopes\n");
     247           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     248           0 :                 return;
     249             :         }
     250             : 
     251          10 :         path_scope = dalloc_get(path_scope_array, "char *", 0);
     252          10 :         if (path_scope == NULL) {
     253           0 :                 DBG_ERR("Missing path in kMDSStorePathScopes\n");
     254           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     255           0 :                 return;
     256             :         }
     257             : 
     258          10 :         mdscli_ctx->path_scope_len = strlen(path_scope);
     259          10 :         if (mdscli_ctx->path_scope_len < 1 ||
     260          10 :             mdscli_ctx->path_scope_len > UINT16_MAX)
     261             :         {
     262           0 :                 DBG_ERR("Bad path_scope: %s\n", path_scope);
     263           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     264           0 :                 return;
     265             :         }
     266          10 :         mdscli_ctx->path_scope = talloc_strdup(mdscli_ctx, path_scope);
     267          10 :         if (tevent_req_nomem(mdscli_ctx->path_scope, req)) {
     268           0 :                 return;
     269             :         }
     270             : 
     271          10 :         if (mdscli_ctx->path_scope[mdscli_ctx->path_scope_len-1] == '/') {
     272          10 :                 mdscli_ctx->path_scope[mdscli_ctx->path_scope_len-1] = '\0';
     273          10 :                 mdscli_ctx->path_scope_len--;
     274             :         }
     275             : 
     276          10 :         tevent_req_done(req);
     277             : }
     278             : 
     279          10 : NTSTATUS mdscli_connect_recv(struct tevent_req *req,
     280             :                              TALLOC_CTX *mem_ctx,
     281             :                              struct mdscli_ctx **mdscli_ctx)
     282             : {
     283          10 :         struct mdscli_connect_state *state = tevent_req_data(
     284             :                 req, struct mdscli_connect_state);
     285             :         NTSTATUS status;
     286             : 
     287          10 :         if (tevent_req_is_nterror(req, &status)) {
     288           0 :                 tevent_req_received(req);
     289           0 :                 return status;
     290             :         }
     291             : 
     292          10 :         *mdscli_ctx = talloc_move(mem_ctx, &state->mdscli_ctx);
     293          10 :         tevent_req_received(req);
     294          10 :         return NT_STATUS_OK;
     295             : }
     296             : 
     297           2 : NTSTATUS mdscli_connect(TALLOC_CTX *mem_ctx,
     298             :                         struct dcerpc_binding_handle *bh,
     299             :                         const char *share_name,
     300             :                         const char *mount_path,
     301             :                         struct mdscli_ctx **mdscli_ctx)
     302             : {
     303           2 :         TALLOC_CTX *frame = talloc_stackframe();
     304           2 :         struct tevent_req *req = NULL;
     305           2 :         struct tevent_context *ev = NULL;
     306           2 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     307             : 
     308           2 :         ev = samba_tevent_context_init(frame);
     309           2 :         if (ev == NULL) {
     310           0 :                 goto fail;
     311             :         }
     312             : 
     313           2 :         req = mdscli_connect_send(frame,
     314             :                                   ev,
     315             :                                   bh,
     316             :                                   share_name,
     317             :                                   mount_path);
     318           2 :         if (req == NULL) {
     319           0 :                 goto fail;
     320             :         }
     321           2 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     322           0 :                 goto fail;
     323             :         }
     324             : 
     325           2 :         status = mdscli_connect_recv(req, mem_ctx, mdscli_ctx);
     326           2 : fail:
     327           2 :         TALLOC_FREE(frame);
     328           2 :         return status;
     329             : }
     330             : 
     331             : struct mdscli_search_state {
     332             :         struct mdscli_search_ctx *search;
     333             :         struct mdssvc_blob request_blob;
     334             :         struct mdssvc_blob response_blob;
     335             : };
     336             : 
     337             : static void mdscli_search_cmd_done(struct tevent_req *subreq);
     338             : 
     339           6 : struct tevent_req *mdscli_search_send(TALLOC_CTX *mem_ctx,
     340             :                                       struct tevent_context *ev,
     341             :                                       struct mdscli_ctx *mdscli_ctx,
     342             :                                       const char *mds_query,
     343             :                                       const char *path_scope_in,
     344             :                                       bool live)
     345             : {
     346           6 :         struct tevent_req *req = NULL;
     347           6 :         struct mdscli_search_state *state = NULL;
     348           6 :         struct tevent_req *subreq = NULL;
     349           6 :         struct mdscli_search_ctx *search = NULL;
     350           6 :         char *path_scope = NULL;
     351             :         NTSTATUS status;
     352             : 
     353           6 :         req = tevent_req_create(req, &state, struct mdscli_search_state);
     354           6 :         if (req == NULL) {
     355           0 :                 return NULL;
     356             :         }
     357             : 
     358           6 :         search = talloc_zero(state, struct mdscli_search_ctx);
     359           6 :         if (tevent_req_nomem(search, req)) {
     360           0 :                 return tevent_req_post(req, ev);
     361             :         }
     362             : 
     363           6 :         if (path_scope_in[0] == '/') {
     364           6 :                 path_scope = talloc_strdup(search, path_scope_in);
     365             :         } else {
     366           0 :                 path_scope = talloc_asprintf(search,
     367             :                                              "%s/%s",
     368           0 :                                              mdscli_ctx->mdscmd_open.share_path,
     369             :                                              path_scope_in);
     370             :         }
     371           6 :         if (tevent_req_nomem(path_scope, req)) {
     372           0 :                 return tevent_req_post(req, ev);
     373             :         }
     374             : 
     375           6 :         *search = (struct mdscli_search_ctx) {
     376             :                 .mdscli_ctx = mdscli_ctx,
     377           6 :                 .ctx_id = mdscli_new_ctx_id(mdscli_ctx),
     378           6 :                 .unique_id = generate_random_u64(),
     379             :                 .live = live,
     380             :                 .path_scope = path_scope,
     381           6 :                 .mds_query = talloc_strdup(search, mds_query),
     382             :         };
     383           6 :         if (tevent_req_nomem(search->mds_query, req)) {
     384           0 :                 return tevent_req_post(req, ev);
     385             :         }
     386             : 
     387           6 :         *state = (struct mdscli_search_state) {
     388             :                 .search = search,
     389             :         };
     390             : 
     391           6 :         status = mdscli_blob_search(state,
     392             :                                     search,
     393           6 :                                     &state->request_blob);
     394           6 :         if (tevent_req_nterror(req, status)) {
     395           0 :                 return tevent_req_post(req, ev);
     396             :         }
     397             : 
     398           6 :         subreq = dcerpc_mdssvc_cmd_send(state,
     399             :                                         ev,
     400             :                                         mdscli_ctx->bh,
     401             :                                         &mdscli_ctx->ph,
     402             :                                         0,
     403             :                                         mdscli_ctx->dev,
     404             :                                         mdscli_ctx->mdscmd_open.unkn2,
     405             :                                         0,
     406             :                                         mdscli_ctx->flags,
     407           6 :                                         state->request_blob,
     408             :                                         0,
     409           6 :                                         mdscli_ctx->max_fragment_size,
     410             :                                         1,
     411           6 :                                         mdscli_ctx->max_fragment_size,
     412             :                                         0,
     413             :                                         0,
     414             :                                         &mdscli_ctx->mdscmd_cmd.fragment,
     415           6 :                                         &state->response_blob,
     416             :                                         &mdscli_ctx->mdscmd_cmd.unkn9);
     417           6 :         if (tevent_req_nomem(subreq, req)) {
     418           0 :                 return tevent_req_post(req, ev);
     419             :         }
     420           6 :         tevent_req_set_callback(subreq, mdscli_search_cmd_done, req);
     421           6 :         mdscli_ctx->async_pending++;
     422           6 :         return req;
     423             : }
     424             : 
     425           6 : static void mdscli_search_cmd_done(struct tevent_req *subreq)
     426             : {
     427           6 :         struct tevent_req *req = tevent_req_callback_data(
     428             :                 subreq, struct tevent_req);
     429           6 :         struct mdscli_search_state *state = tevent_req_data(
     430             :                 req, struct mdscli_search_state);
     431           6 :         DALLOC_CTX *d = NULL;
     432           6 :         uint64_t *uint64p = NULL;
     433             :         NTSTATUS status;
     434             :         bool ok;
     435             : 
     436           6 :         status = dcerpc_mdssvc_cmd_recv(subreq, state);
     437           6 :         TALLOC_FREE(subreq);
     438           6 :         state->search->mdscli_ctx->async_pending--;
     439           6 :         if (tevent_req_nterror(req, status)) {
     440           0 :                 return;
     441             :         }
     442             : 
     443           6 :         d = dalloc_new(state);
     444           6 :         if (tevent_req_nomem(d, req)) {
     445           0 :                 return;
     446             :         }
     447             : 
     448           6 :         ok = sl_unpack(d,
     449           6 :                        (char *)state->response_blob.spotlight_blob,
     450           6 :                        state->response_blob.length);
     451           6 :         if (!ok) {
     452           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     453           0 :                 return;
     454             :         }
     455             : 
     456           6 :         uint64p = dalloc_get(d,
     457             :                              "DALLOC_CTX", 0,
     458             :                              "uint64_t", 0);
     459           6 :         if (uint64p == NULL) {
     460           0 :                 DBG_DEBUG("Unexpected mds response: %s", dalloc_dump(d, 0));
     461           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     462           0 :                 return;
     463             :         }
     464             : 
     465           6 :         if (*uint64p != 0) {
     466           0 :                 DBG_DEBUG("Unexpected mds result: 0x%" PRIx64 "\n", *uint64p);
     467           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     468           0 :                 return;
     469             :         }
     470             : 
     471           6 :         tevent_req_done(req);
     472           6 :         return;
     473             : }
     474             : 
     475           6 : NTSTATUS mdscli_search_recv(struct tevent_req *req,
     476             :                             TALLOC_CTX *mem_ctx,
     477             :                             struct mdscli_search_ctx **search)
     478             : {
     479           6 :         struct mdscli_search_state *state = tevent_req_data(
     480             :                 req, struct mdscli_search_state);
     481             :         NTSTATUS status;
     482             : 
     483           6 :         if (tevent_req_is_nterror(req, &status)) {
     484           0 :                 tevent_req_received(req);
     485           0 :                 return status;
     486             :         }
     487             : 
     488           6 :         *search = talloc_move(mem_ctx, &state->search);
     489           6 :         tevent_req_received(req);
     490           6 :         return NT_STATUS_OK;
     491             : }
     492             : 
     493           2 : NTSTATUS mdscli_search(TALLOC_CTX *mem_ctx,
     494             :                        struct mdscli_ctx *mdscli_ctx,
     495             :                        const char *mds_query,
     496             :                        const char *path_scope,
     497             :                        bool live,
     498             :                        struct mdscli_search_ctx **search)
     499             : {
     500           2 :         TALLOC_CTX *frame = talloc_stackframe();
     501           2 :         struct tevent_req *req = NULL;
     502           2 :         struct tevent_context *ev = NULL;
     503           2 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     504             : 
     505           2 :         if (mdscli_ctx->async_pending != 0) {
     506           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     507           0 :                 goto fail;
     508             :         }
     509             : 
     510           2 :         ev = samba_tevent_context_init(frame);
     511           2 :         if (ev == NULL) {
     512           0 :                 goto fail;
     513             :         }
     514             : 
     515           2 :         req = mdscli_search_send(frame,
     516             :                                  ev,
     517             :                                  mdscli_ctx,
     518             :                                  mds_query,
     519             :                                  path_scope,
     520             :                                  live);
     521           2 :         if (req == NULL) {
     522           0 :                 goto fail;
     523             :         }
     524           2 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     525           0 :                 goto fail;
     526             :         }
     527             : 
     528           2 :         status = mdscli_search_recv(req, mem_ctx, search);
     529           2 : fail:
     530           2 :         TALLOC_FREE(frame);
     531           2 :         return status;
     532             : }
     533             : 
     534             : struct mdscli_get_results_state {
     535             :         struct tevent_context *ev;
     536             :         struct mdscli_search_ctx *search;
     537             :         struct mdssvc_blob request_blob;
     538             :         struct mdssvc_blob response_fragment;
     539             :         DATA_BLOB response_data;
     540             :         uint64_t *cnids;
     541             :         uint32_t fragment;
     542             : };
     543             : 
     544             : static void mdscli_get_results_cmd_done(struct tevent_req *subreq);
     545             : 
     546           8 : struct tevent_req *mdscli_get_results_send(
     547             :                         TALLOC_CTX *mem_ctx,
     548             :                         struct tevent_context *ev,
     549             :                         struct mdscli_search_ctx *search)
     550             : {
     551           8 :         struct tevent_req *req = NULL;
     552           8 :         struct mdscli_get_results_state *state = NULL;
     553           8 :         struct tevent_req *subreq = NULL;
     554           8 :         struct mdscli_ctx *mdscli_ctx = search->mdscli_ctx;
     555             :         NTSTATUS status;
     556             : 
     557           8 :         req = tevent_req_create(req, &state, struct mdscli_get_results_state);
     558           8 :         if (req == NULL) {
     559           0 :                 return NULL;
     560             :         }
     561             : 
     562           8 :         *state = (struct mdscli_get_results_state) {
     563             :                 .ev = ev,
     564             :                 .search = search,
     565             :         };
     566             : 
     567           8 :         status = mdscli_blob_get_results(state,
     568             :                                          search,
     569           8 :                                          &state->request_blob);
     570           8 :         if (tevent_req_nterror(req, status)) {
     571           0 :                 return tevent_req_post(req, ev);
     572             :         }
     573             : 
     574           8 :         subreq = dcerpc_mdssvc_cmd_send(state,
     575             :                                         ev,
     576             :                                         mdscli_ctx->bh,
     577             :                                         &mdscli_ctx->ph,
     578             :                                         0,
     579             :                                         mdscli_ctx->dev,
     580             :                                         mdscli_ctx->mdscmd_open.unkn2,
     581             :                                         0,
     582             :                                         mdscli_ctx->flags,
     583           8 :                                         state->request_blob,
     584             :                                         0,
     585           8 :                                         mdscli_ctx->max_fragment_size,
     586             :                                         1,
     587           8 :                                         mdscli_ctx->max_fragment_size,
     588             :                                         0,
     589             :                                         0,
     590           8 :                                         &state->fragment,
     591           8 :                                         &state->response_fragment,
     592             :                                         &mdscli_ctx->mdscmd_cmd.unkn9);
     593           8 :         if (tevent_req_nomem(subreq, req)) {
     594           0 :                 return tevent_req_post(req, ev);
     595             :         }
     596           8 :         tevent_req_set_callback(subreq, mdscli_get_results_cmd_done, req);
     597           8 :         mdscli_ctx->async_pending++;
     598           8 :         return req;
     599             : }
     600             : 
     601           8 : static void mdscli_get_results_cmd_done(struct tevent_req *subreq)
     602             : {
     603           8 :         struct tevent_req *req = tevent_req_callback_data(
     604             :                 subreq, struct tevent_req);
     605           8 :         struct mdscli_get_results_state *state = tevent_req_data(
     606             :                 req, struct mdscli_get_results_state);
     607           8 :         struct mdscli_ctx *mdscli_ctx = state->search->mdscli_ctx;
     608             :         size_t oldsize, newsize;
     609           8 :         DALLOC_CTX *d = NULL;
     610           8 :         uint64_t *uint64p = NULL;
     611           8 :         bool search_in_progress = false;
     612           8 :         sl_cnids_t *cnids = NULL;
     613             :         size_t ncnids;
     614             :         size_t i;
     615             :         NTSTATUS status;
     616             :         bool ok;
     617             : 
     618           8 :         status = dcerpc_mdssvc_cmd_recv(subreq, state);
     619           8 :         TALLOC_FREE(subreq);
     620           8 :         state->search->mdscli_ctx->async_pending--;
     621           8 :         if (tevent_req_nterror(req, status)) {
     622           0 :                 return;
     623             :         }
     624             : 
     625           8 :         oldsize = state->response_data.length;
     626           8 :         newsize = oldsize + state->response_fragment.length;
     627           8 :         if (newsize < oldsize) {
     628           0 :                 tevent_req_nterror(req, NT_STATUS_INTEGER_OVERFLOW);
     629           0 :                 return;
     630             :         }
     631             : 
     632           8 :         ok = data_blob_realloc(state, &state->response_data, newsize);
     633           8 :         if (!ok) {
     634           0 :                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
     635           0 :                 return;
     636             :         }
     637           8 :         (void)memcpy(state->response_data.data + oldsize,
     638           8 :                      state->response_fragment.spotlight_blob,
     639           8 :                      state->response_fragment.length);
     640             : 
     641           8 :         TALLOC_FREE(state->response_fragment.spotlight_blob);
     642           8 :         state->response_fragment.length = 0;
     643           8 :         state->response_fragment.size = 0;
     644             : 
     645           8 :         if (state->fragment != 0) {
     646           0 :                 subreq = dcerpc_mdssvc_cmd_send(
     647             :                                 state,
     648             :                                 state->ev,
     649             :                                 mdscli_ctx->bh,
     650             :                                 &mdscli_ctx->ph,
     651             :                                 0,
     652             :                                 mdscli_ctx->dev,
     653             :                                 mdscli_ctx->mdscmd_open.unkn2,
     654             :                                 1,
     655             :                                 mdscli_ctx->flags,
     656             :                                 state->request_blob,
     657             :                                 0,
     658           0 :                                 mdscli_ctx->max_fragment_size,
     659             :                                 1,
     660           0 :                                 mdscli_ctx->max_fragment_size,
     661             :                                 0,
     662             :                                 0,
     663             :                                 &state->fragment,
     664             :                                 &state->response_fragment,
     665             :                                 &mdscli_ctx->mdscmd_cmd.unkn9);
     666           0 :                 if (tevent_req_nomem(subreq, req)) {
     667           0 :                         tevent_req_post(req, state->ev);
     668           0 :                         return;
     669             :                 }
     670           0 :                 tevent_req_set_callback(subreq,
     671             :                                         mdscli_get_results_cmd_done,
     672             :                                         req);
     673           0 :                 mdscli_ctx->async_pending++;
     674           0 :                 return;
     675             :         }
     676             : 
     677           8 :         d = dalloc_new(state);
     678           8 :         if (tevent_req_nomem(d, req)) {
     679           0 :                 return;
     680             :         }
     681             : 
     682           8 :         ok = sl_unpack(d,
     683           8 :                        (char *)state->response_data.data,
     684             :                        state->response_data.length);
     685           8 :         if (!ok) {
     686           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     687           0 :                 return;
     688             :         }
     689             : 
     690           8 :         uint64p = dalloc_get(d,
     691             :                              "DALLOC_CTX", 0,
     692             :                              "uint64_t", 0);
     693           8 :         if (uint64p == NULL) {
     694           0 :                 DBG_DEBUG("Unexpected mds response: %s", dalloc_dump(d, 0));
     695           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     696           0 :                 return;
     697             :         }
     698             : 
     699           8 :         if (*uint64p == 35) {
     700           0 :                 DBG_DEBUG("Search in progress\n");
     701           0 :                 search_in_progress = true;
     702             :         }
     703             : 
     704           8 :         cnids = dalloc_get(d, "DALLOC_CTX", 0, "sl_cnids_t", 1);
     705           8 :         if (cnids == NULL) {
     706           0 :                 DBG_DEBUG("cnids error: %s", dalloc_dump(d, 0));
     707           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     708           0 :                 return;
     709             :         }
     710             : 
     711           8 :         ncnids = dalloc_size(cnids->ca_cnids);
     712           8 :         if (ncnids == 0 && !search_in_progress) {
     713           2 :                 tevent_req_nterror(req, NT_STATUS_NO_MORE_MATCHES);
     714           2 :                 return;
     715             :         }
     716             : 
     717           6 :         if (cnids->ca_unkn1 != 0xadd) {
     718             :                 /*
     719             :                  * Whatever 0xadd means... but it seems to be the standard value
     720             :                  * macOS mdssvc returns here.
     721             :                  */
     722           0 :                 DBG_DEBUG("unexpected ca_unkn1: %s", dalloc_dump(d, 0));
     723           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     724           0 :                 return;
     725             :         }
     726             : 
     727           6 :         if (cnids->ca_context != state->search->ctx_id.connection ) {
     728           0 :                 DBG_DEBUG("unexpected ca_context: %s", dalloc_dump(d, 0));
     729           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     730           0 :                 return;
     731             :         }
     732             : 
     733           6 :         state->cnids = talloc_zero_array(state, uint64_t, ncnids);
     734           6 :         if (tevent_req_nomem(state->cnids, req)) {
     735           0 :                 return;
     736             :         }
     737             : 
     738          32 :         for (i = 0; i < ncnids; i++) {
     739          26 :                 uint64_t *cnid = NULL;
     740             : 
     741          26 :                 cnid = dalloc_get(cnids->ca_cnids, "uint64_t", i);
     742          26 :                 if (cnid == NULL) {
     743           0 :                         DBG_DEBUG("cnids error: %s", dalloc_dump(d, 0));
     744           0 :                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     745           0 :                         return;
     746             :                 }
     747          26 :                 state->cnids[i] = *cnid;
     748             :         }
     749             : 
     750           6 :         tevent_req_done(req);
     751           6 :         return;
     752             : }
     753             : 
     754           8 : NTSTATUS mdscli_get_results_recv(struct tevent_req *req,
     755             :                                  TALLOC_CTX *mem_ctx,
     756             :                                  uint64_t **cnids)
     757             : {
     758           8 :         struct mdscli_get_results_state *state = tevent_req_data(
     759             :                 req, struct mdscli_get_results_state);
     760             :         NTSTATUS status;
     761             : 
     762           8 :         if (tevent_req_is_nterror(req, &status)) {
     763           2 :                 tevent_req_received(req);
     764           2 :                 return status;
     765             :         }
     766             : 
     767           6 :         *cnids = talloc_move(mem_ctx, &state->cnids);
     768             : 
     769           6 :         tevent_req_received(req);
     770           6 :         return NT_STATUS_OK;
     771             : }
     772             : 
     773           4 : NTSTATUS mdscli_get_results(TALLOC_CTX *mem_ctx,
     774             :                             struct mdscli_search_ctx *search,
     775             :                             uint64_t **_cnids)
     776             : {
     777           4 :         TALLOC_CTX *frame = talloc_stackframe();
     778           4 :         struct tevent_req *req = NULL;
     779           4 :         struct tevent_context *ev = NULL;
     780           4 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     781             : 
     782           4 :         if (search->mdscli_ctx->async_pending != 0) {
     783           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     784           0 :                 goto fail;
     785             :         }
     786             : 
     787           4 :         ev = samba_tevent_context_init(frame);
     788           4 :         if (ev == NULL) {
     789           0 :                 goto fail;
     790             :         }
     791             : 
     792           4 :         req = mdscli_get_results_send(frame,
     793             :                                       ev,
     794             :                                       search);
     795           4 :         if (req == NULL) {
     796           0 :                 goto fail;
     797             :         }
     798           4 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     799           0 :                 goto fail;
     800             :         }
     801             : 
     802           4 :         status = mdscli_get_results_recv(req, mem_ctx, _cnids);
     803           4 : fail:
     804           4 :         TALLOC_FREE(frame);
     805           4 :         return status;
     806             : }
     807             : 
     808             : struct mdscli_get_path_state {
     809             :         struct mdscli_ctx *mdscli_ctx;
     810             :         struct mdssvc_blob request_blob;
     811             :         struct mdssvc_blob response_blob;
     812             :         char *path;
     813             : };
     814             : 
     815             : static void mdscli_get_path_done(struct tevent_req *subreq);
     816             : 
     817          26 : struct tevent_req *mdscli_get_path_send(TALLOC_CTX *mem_ctx,
     818             :                                         struct tevent_context *ev,
     819             :                                         struct mdscli_ctx *mdscli_ctx,
     820             :                                         uint64_t cnid)
     821             : {
     822          26 :         struct tevent_req *req = NULL;
     823          26 :         struct mdscli_get_path_state *state = NULL;
     824          26 :         struct tevent_req *subreq = NULL;
     825             :         NTSTATUS status;
     826             : 
     827          26 :         req = tevent_req_create(req, &state, struct mdscli_get_path_state);
     828          26 :         if (req == NULL) {
     829           0 :                 return NULL;
     830             :         }
     831          26 :         *state = (struct mdscli_get_path_state) {
     832             :                 .mdscli_ctx = mdscli_ctx,
     833             :         };
     834             : 
     835          26 :         status = mdscli_blob_get_path(state,
     836             :                                       mdscli_ctx,
     837             :                                       cnid,
     838          26 :                                       &state->request_blob);
     839          26 :         if (tevent_req_nterror(req, status)) {
     840           0 :                 return tevent_req_post(req, ev);
     841             :         }
     842             : 
     843          26 :         subreq = dcerpc_mdssvc_cmd_send(state,
     844             :                                         ev,
     845             :                                         mdscli_ctx->bh,
     846             :                                         &mdscli_ctx->ph,
     847             :                                         0,
     848             :                                         mdscli_ctx->dev,
     849             :                                         mdscli_ctx->mdscmd_open.unkn2,
     850             :                                         0,
     851             :                                         mdscli_ctx->flags,
     852          26 :                                         state->request_blob,
     853             :                                         0,
     854          26 :                                         mdscli_ctx->max_fragment_size,
     855             :                                         1,
     856          26 :                                         mdscli_ctx->max_fragment_size,
     857             :                                         0,
     858             :                                         0,
     859             :                                         &mdscli_ctx->mdscmd_cmd.fragment,
     860          26 :                                         &state->response_blob,
     861             :                                         &mdscli_ctx->mdscmd_cmd.unkn9);
     862          26 :         if (tevent_req_nomem(subreq, req)) {
     863           0 :                 return tevent_req_post(req, ev);
     864             :         }
     865          26 :         tevent_req_set_callback(subreq, mdscli_get_path_done, req);
     866          26 :         mdscli_ctx->async_pending++;
     867          26 :         return req;
     868             : }
     869             : 
     870          26 : static void mdscli_get_path_done(struct tevent_req *subreq)
     871             : {
     872          26 :         struct tevent_req *req = tevent_req_callback_data(
     873             :                 subreq, struct tevent_req);
     874          26 :         struct mdscli_get_path_state *state = tevent_req_data(
     875             :                 req, struct mdscli_get_path_state);
     876          26 :         DALLOC_CTX *d = NULL;
     877             :         size_t pathlen;
     878             :         size_t prefixlen;
     879          26 :         char *path = NULL;
     880          26 :         const char *p = NULL;
     881             :         NTSTATUS status;
     882             :         bool ok;
     883             : 
     884          26 :         status = dcerpc_mdssvc_cmd_recv(subreq, state);
     885          26 :         TALLOC_FREE(subreq);
     886          26 :         state->mdscli_ctx->async_pending--;
     887          26 :         if (tevent_req_nterror(req, status)) {
     888           0 :                 return;
     889             :         }
     890             : 
     891          26 :         d = dalloc_new(state);
     892          26 :         if (tevent_req_nomem(d, req)) {
     893           0 :                 return;
     894             :         }
     895             : 
     896          26 :         ok = sl_unpack(d,
     897          26 :                        (char *)state->response_blob.spotlight_blob,
     898          26 :                        state->response_blob.length);
     899          26 :         if (!ok) {
     900           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     901           0 :                 return;
     902             :         }
     903             : 
     904          26 :         path = dalloc_get(d,
     905             :                           "DALLOC_CTX", 0,
     906             :                           "DALLOC_CTX", 2,
     907             :                           "DALLOC_CTX", 0,
     908             :                           "DALLOC_CTX", 1,
     909             :                           "char *", 0);
     910          26 :         if (path == NULL) {
     911           0 :                 DBG_DEBUG("No path in mds response: %s", dalloc_dump(d, 0));
     912           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     913           0 :                 return;
     914             :         }
     915             : 
     916             :         /* Path is prefixed by /PATHSCOPE/SHARENAME/, strip it */
     917          26 :         pathlen = strlen(path);
     918             : 
     919             :         /*
     920             :          * path_scope_len and share_path_len are already checked to be smaller
     921             :          * then UINT16_MAX so this can't overflow
     922             :          */
     923          26 :         prefixlen = state->mdscli_ctx->path_scope_len
     924          26 :                 + state->mdscli_ctx->mdscmd_open.share_path_len;
     925             : 
     926          26 :         if (pathlen < prefixlen) {
     927           0 :                 DBG_DEBUG("Bad path: %s\n", path);
     928           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
     929           0 :                 return;
     930             :         }
     931             : 
     932          26 :         p = path + prefixlen;
     933          52 :         while (*p == '/') {
     934          26 :                 p++;
     935             :         }
     936          26 :         if (*p == '\0') {
     937           0 :                 DBG_DEBUG("Bad path: %s\n", path);
     938           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
     939           0 :                 return;
     940             :         }
     941             : 
     942          26 :         state->path = talloc_strdup(state, p);
     943          26 :         if (state->path == NULL) {
     944           0 :                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
     945           0 :                 return;
     946             :         }
     947          26 :         DBG_DEBUG("path: %s\n", state->path);
     948             : 
     949          26 :         tevent_req_done(req);
     950          26 :         return;
     951             : }
     952             : 
     953          26 : NTSTATUS mdscli_get_path_recv(struct tevent_req *req,
     954             :                               TALLOC_CTX *mem_ctx,
     955             :                               char **path)
     956             : {
     957          26 :         struct mdscli_get_path_state *state = tevent_req_data(
     958             :                 req, struct mdscli_get_path_state);
     959             :         NTSTATUS status;
     960             : 
     961          26 :         if (tevent_req_is_nterror(req, &status)) {
     962           0 :                 tevent_req_received(req);
     963           0 :                 return status;
     964             :         }
     965             : 
     966          26 :         *path = talloc_move(mem_ctx, &state->path);
     967          26 :         tevent_req_received(req);
     968          26 :         return NT_STATUS_OK;
     969             : }
     970             : 
     971           4 : NTSTATUS mdscli_get_path(TALLOC_CTX *mem_ctx,
     972             :                          struct mdscli_ctx *mdscli_ctx,
     973             :                          uint64_t cnid,
     974             :                          char **path)
     975             : {
     976           4 :         TALLOC_CTX *frame = talloc_stackframe();
     977           4 :         struct tevent_req *req = NULL;
     978           4 :         struct tevent_context *ev = NULL;
     979           4 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     980             : 
     981           4 :         if (mdscli_ctx->async_pending != 0) {
     982           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     983           0 :                 goto fail;
     984             :         }
     985             : 
     986           4 :         ev = samba_tevent_context_init(frame);
     987           4 :         if (ev == NULL) {
     988           0 :                 goto fail;
     989             :         }
     990             : 
     991           4 :         req = mdscli_get_path_send(frame, ev, mdscli_ctx, cnid);
     992           4 :         if (req == NULL) {
     993           0 :                 goto fail;
     994             :         }
     995           4 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     996           0 :                 goto fail;
     997             :         }
     998             : 
     999           4 :         status = mdscli_get_path_recv(req, mem_ctx, path);
    1000           4 : fail:
    1001           4 :         TALLOC_FREE(frame);
    1002           4 :         return status;
    1003             : }
    1004             : 
    1005             : struct mdscli_close_search_state {
    1006             :         struct mdscli_search_ctx *search;
    1007             :         struct mdssvc_blob request_blob;
    1008             :         struct mdssvc_blob response_blob;
    1009             : };
    1010             : 
    1011             : static void mdscli_close_search_done(struct tevent_req *subreq);
    1012             : 
    1013           6 : struct tevent_req *mdscli_close_search_send(TALLOC_CTX *mem_ctx,
    1014             :                                             struct tevent_context *ev,
    1015             :                                             struct mdscli_search_ctx **search)
    1016             : {
    1017           6 :         struct mdscli_ctx *mdscli_ctx = NULL;
    1018           6 :         struct tevent_req *req = NULL;
    1019           6 :         struct mdscli_close_search_state *state = NULL;
    1020           6 :         struct tevent_req *subreq = NULL;
    1021             :         NTSTATUS status;
    1022             : 
    1023           6 :         req = tevent_req_create(req, &state, struct mdscli_close_search_state);
    1024           6 :         if (req == NULL) {
    1025           0 :                 return NULL;
    1026             :         }
    1027          12 :         *state = (struct mdscli_close_search_state) {
    1028           6 :                 .search = talloc_move(state, search),
    1029             :         };
    1030           6 :         mdscli_ctx = state->search->mdscli_ctx;
    1031             : 
    1032           6 :         status = mdscli_blob_close_search(state,
    1033           6 :                                           state->search,
    1034           6 :                                           &state->request_blob);
    1035           6 :         if (tevent_req_nterror(req, status)) {
    1036           0 :                 return tevent_req_post(req, ev);
    1037             :         }
    1038             : 
    1039           6 :         subreq = dcerpc_mdssvc_cmd_send(state,
    1040             :                                         ev,
    1041             :                                         mdscli_ctx->bh,
    1042             :                                         &mdscli_ctx->ph,
    1043             :                                         0,
    1044             :                                         mdscli_ctx->dev,
    1045             :                                         mdscli_ctx->mdscmd_open.unkn2,
    1046             :                                         0,
    1047             :                                         mdscli_ctx->flags,
    1048           6 :                                         state->request_blob,
    1049             :                                         0,
    1050           6 :                                         mdscli_ctx->max_fragment_size,
    1051             :                                         1,
    1052           6 :                                         mdscli_ctx->max_fragment_size,
    1053             :                                         0,
    1054             :                                         0,
    1055             :                                         &mdscli_ctx->mdscmd_cmd.fragment,
    1056           6 :                                         &state->response_blob,
    1057             :                                         &mdscli_ctx->mdscmd_cmd.unkn9);
    1058           6 :         if (tevent_req_nomem(subreq, req)) {
    1059           0 :                 return tevent_req_post(req, ev);
    1060             :         }
    1061           6 :         tevent_req_set_callback(subreq, mdscli_close_search_done, req);
    1062           6 :         mdscli_ctx->async_pending++;
    1063           6 :         return req;
    1064             : }
    1065             : 
    1066           6 : static void mdscli_close_search_done(struct tevent_req *subreq)
    1067             : {
    1068           6 :         struct tevent_req *req = tevent_req_callback_data(
    1069             :                 subreq, struct tevent_req);
    1070           6 :         struct mdscli_close_search_state *state = tevent_req_data(
    1071             :                 req, struct mdscli_close_search_state);
    1072             :         NTSTATUS status;
    1073             : 
    1074           6 :         status = dcerpc_mdssvc_cmd_recv(subreq, state);
    1075           6 :         TALLOC_FREE(subreq);
    1076           6 :         state->search->mdscli_ctx->async_pending--;
    1077           6 :         if (tevent_req_nterror(req, status)) {
    1078           0 :                 return;
    1079             :         }
    1080             : 
    1081           6 :         tevent_req_done(req);
    1082           6 :         return;
    1083             : }
    1084             : 
    1085           6 : NTSTATUS mdscli_close_search_recv(struct tevent_req *req)
    1086             : {
    1087           6 :         return tevent_req_simple_recv_ntstatus(req);
    1088             : }
    1089             : 
    1090           2 : NTSTATUS mdscli_close_search(struct mdscli_search_ctx **search)
    1091             : {
    1092           2 :         TALLOC_CTX *frame = talloc_stackframe();
    1093           2 :         struct tevent_req *req = NULL;
    1094           2 :         struct tevent_context *ev = NULL;
    1095           2 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    1096             : 
    1097           2 :         if ((*search)->mdscli_ctx->async_pending != 0) {
    1098           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    1099           0 :                 goto fail;
    1100             :         }
    1101             : 
    1102           2 :         ev = samba_tevent_context_init(frame);
    1103           2 :         if (ev == NULL) {
    1104           0 :                 goto fail;
    1105             :         }
    1106             : 
    1107           2 :         req = mdscli_close_search_send(frame, ev, search);
    1108           2 :         if (req == NULL) {
    1109           0 :                 goto fail;
    1110             :         }
    1111           2 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    1112           0 :                 goto fail;
    1113             :         }
    1114             : 
    1115           2 :         status = mdscli_close_search_recv(req);
    1116           2 : fail:
    1117           2 :         TALLOC_FREE(frame);
    1118           2 :         return status;
    1119             : }
    1120             : 
    1121             : struct mdscli_disconnect_state {
    1122             :         struct mdscli_ctx *mdscli_ctx;
    1123             : };
    1124             : 
    1125             : static void mdscli_disconnect_done(struct tevent_req *subreq);
    1126             : 
    1127          10 : struct tevent_req *mdscli_disconnect_send(TALLOC_CTX *mem_ctx,
    1128             :                                           struct tevent_context *ev,
    1129             :                                           struct mdscli_ctx *mdscli_ctx)
    1130             : {
    1131          10 :         struct tevent_req *req = NULL;
    1132          10 :         struct mdscli_disconnect_state *state = NULL;
    1133          10 :         struct tevent_req *subreq = NULL;
    1134             : 
    1135          10 :         req = tevent_req_create(req, &state, struct mdscli_disconnect_state);
    1136          10 :         if (req == NULL) {
    1137           0 :                 return NULL;
    1138             :         }
    1139          10 :         *state = (struct mdscli_disconnect_state) {
    1140             :                 .mdscli_ctx = mdscli_ctx,
    1141             :         };
    1142             : 
    1143          10 :         subreq = dcerpc_mdssvc_close_send(state,
    1144             :                                           ev,
    1145             :                                           mdscli_ctx->bh,
    1146             :                                           &mdscli_ctx->ph,
    1147             :                                           0,
    1148             :                                           mdscli_ctx->dev,
    1149             :                                           mdscli_ctx->mdscmd_open.unkn2,
    1150             :                                           0,
    1151             :                                           &mdscli_ctx->ph,
    1152             :                                           &mdscli_ctx->mdscmd_close.status);
    1153          10 :         if (tevent_req_nomem(subreq, req)) {
    1154           0 :                 return tevent_req_post(req, ev);
    1155             :         }
    1156          10 :         tevent_req_set_callback(subreq, mdscli_disconnect_done, req);
    1157          10 :         mdscli_ctx->async_pending++;
    1158          10 :         return req;
    1159             : }
    1160             : 
    1161          10 : static void mdscli_disconnect_done(struct tevent_req *subreq)
    1162             : {
    1163          10 :         struct tevent_req *req = tevent_req_callback_data(
    1164             :                 subreq, struct tevent_req);
    1165          10 :         struct mdscli_disconnect_state *state = tevent_req_data(
    1166             :                 req, struct mdscli_disconnect_state);
    1167             :         NTSTATUS status;
    1168             : 
    1169          10 :         status = dcerpc_mdssvc_close_recv(subreq, state);
    1170          10 :         TALLOC_FREE(subreq);
    1171          10 :         state->mdscli_ctx->async_pending--;
    1172          10 :         if (tevent_req_nterror(req, status)) {
    1173           0 :                 return;
    1174             :         }
    1175             : 
    1176          10 :         tevent_req_done(req);
    1177          10 :         return;
    1178             : }
    1179             : 
    1180          10 : NTSTATUS mdscli_disconnect_recv(struct tevent_req *req)
    1181             : {
    1182          10 :         return tevent_req_simple_recv_ntstatus(req);
    1183             : }
    1184             : 
    1185           2 : NTSTATUS mdscli_disconnect(struct mdscli_ctx *mdscli_ctx)
    1186             : {
    1187           2 :         TALLOC_CTX *frame = talloc_stackframe();
    1188           2 :         struct tevent_req *req = NULL;
    1189           2 :         struct tevent_context *ev = NULL;
    1190           2 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    1191             : 
    1192           2 :         if (mdscli_ctx->async_pending != 0) {
    1193           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    1194           0 :                 goto fail;
    1195             :         }
    1196             : 
    1197           2 :         ev = samba_tevent_context_init(frame);
    1198           2 :         if (ev == NULL) {
    1199           0 :                 goto fail;
    1200             :         }
    1201             : 
    1202           2 :         req = mdscli_disconnect_send(frame, ev, mdscli_ctx);
    1203           2 :         if (req == NULL) {
    1204           0 :                 goto fail;
    1205             :         }
    1206           2 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    1207           0 :                 goto fail;
    1208             :         }
    1209             : 
    1210           2 :         status = mdscli_disconnect_recv(req);
    1211           2 : fail:
    1212           2 :         TALLOC_FREE(frame);
    1213           2 :         return status;
    1214             : }

Generated by: LCOV version 1.14