LCOV - code coverage report
Current view: top level - libcli/smb - tstream_smbXcli_np.c (source / functions) Hit Total Coverage
Test: coverage report for recycleplus df22b230 Lines: 407 518 78.6 %
Date: 2024-02-14 10:14:15 Functions: 30 33 90.9 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Copyright (C) Stefan Metzmacher 2010
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include "system/network.h"
      22             : #include "../lib/util/tevent_ntstatus.h"
      23             : #include "../lib/tsocket/tsocket.h"
      24             : #include "../lib/tsocket/tsocket_internal.h"
      25             : #include "smb_common.h"
      26             : #include "smbXcli_base.h"
      27             : #include "tstream_smbXcli_np.h"
      28             : #include "libcli/security/security.h"
      29             : 
      30             : static const struct tstream_context_ops tstream_smbXcli_np_ops;
      31             : 
      32             : #define TSTREAM_SMBXCLI_NP_DESIRED_ACCESS ( \
      33             :         SEC_STD_READ_CONTROL | \
      34             :         SEC_FILE_READ_DATA | \
      35             :         SEC_FILE_WRITE_DATA | \
      36             :         SEC_FILE_APPEND_DATA | \
      37             :         SEC_FILE_READ_EA | \
      38             :         SEC_FILE_WRITE_EA | \
      39             :         SEC_FILE_READ_ATTRIBUTE | \
      40             :         SEC_FILE_WRITE_ATTRIBUTE | \
      41             : 0)
      42             : 
      43             : struct tstream_smbXcli_np_ref;
      44             : 
      45             : struct tstream_smbXcli_np {
      46             :         struct smbXcli_conn *conn;
      47             :         struct tstream_smbXcli_np_ref *conn_ref;
      48             :         struct smbXcli_session *session;
      49             :         struct tstream_smbXcli_np_ref *session_ref;
      50             :         struct smbXcli_tcon *tcon;
      51             :         struct tstream_smbXcli_np_ref *tcon_ref;
      52             :         uint16_t pid;
      53             :         unsigned int timeout;
      54             : 
      55             :         const char *npipe;
      56             :         bool is_smb1;
      57             :         uint16_t fnum;
      58             :         uint64_t fid_persistent;
      59             :         uint64_t fid_volatile;
      60             : 
      61             :         struct {
      62             :                 bool active;
      63             :                 struct tevent_req *read_req;
      64             :                 struct tevent_req *write_req;
      65             :                 uint16_t setup[2];
      66             :         } trans;
      67             : 
      68             :         struct {
      69             :                 off_t ofs;
      70             :                 size_t left;
      71             :                 uint8_t *buf;
      72             :         } read, write;
      73             : };
      74             : 
      75             : struct tstream_smbXcli_np_ref {
      76             :         struct tstream_smbXcli_np *cli_nps;
      77             : };
      78             : 
      79        4579 : static int tstream_smbXcli_np_destructor(struct tstream_smbXcli_np *cli_nps)
      80             : {
      81             :         NTSTATUS status;
      82             : 
      83        4579 :         if (cli_nps->conn_ref != NULL) {
      84        4496 :                 cli_nps->conn_ref->cli_nps = NULL;
      85        4496 :                 TALLOC_FREE(cli_nps->conn_ref);
      86             :         }
      87             : 
      88        4579 :         if (cli_nps->session_ref != NULL) {
      89        4496 :                 cli_nps->session_ref->cli_nps = NULL;
      90        4496 :                 TALLOC_FREE(cli_nps->session_ref);
      91             :         }
      92             : 
      93        4579 :         if (cli_nps->tcon_ref != NULL) {
      94        4496 :                 cli_nps->tcon_ref->cli_nps = NULL;
      95        4496 :                 TALLOC_FREE(cli_nps->tcon_ref);
      96             :         }
      97             : 
      98        4579 :         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
      99        3821 :                 return 0;
     100             :         }
     101             : 
     102             :         /*
     103             :          * TODO: do not use a sync call with a destructor!!!
     104             :          *
     105             :          * This only happens, if a caller does talloc_free(),
     106             :          * while the everything was still ok.
     107             :          *
     108             :          * If we get an unexpected failure within a normal
     109             :          * operation, we already do an async cli_close_send()/_recv().
     110             :          *
     111             :          * Once we've fixed all callers to call
     112             :          * tstream_disconnect_send()/_recv(), this will
     113             :          * never be called.
     114             :          *
     115             :          * We use a maximun timeout of 1 second == 1000 msec.
     116             :          */
     117         758 :         cli_nps->timeout = MIN(cli_nps->timeout, 1000);
     118             : 
     119         758 :         if (cli_nps->is_smb1) {
     120           0 :                 status = smb1cli_close(cli_nps->conn,
     121             :                                        cli_nps->timeout,
     122           0 :                                        cli_nps->pid,
     123             :                                        cli_nps->tcon,
     124             :                                        cli_nps->session,
     125           0 :                                        cli_nps->fnum, UINT32_MAX);
     126             :         } else {
     127         758 :                 status = smb2cli_close(cli_nps->conn,
     128             :                                        cli_nps->timeout,
     129             :                                        cli_nps->session,
     130             :                                        cli_nps->tcon,
     131             :                                        0, /* flags */
     132             :                                        cli_nps->fid_persistent,
     133             :                                        cli_nps->fid_volatile);
     134             :         }
     135         758 :         if (!NT_STATUS_IS_OK(status)) {
     136           0 :                 DEBUG(1, ("tstream_smbXcli_np_destructor: cli_close "
     137             :                           "failed on pipe %s. Error was %s\n",
     138             :                           cli_nps->npipe, nt_errstr(status)));
     139             :         }
     140             :         /*
     141             :          * We can't do much on failure
     142             :          */
     143         758 :         return 0;
     144             : }
     145             : 
     146       13737 : static int tstream_smbXcli_np_ref_destructor(struct tstream_smbXcli_np_ref *ref)
     147             : {
     148       13737 :         if (ref->cli_nps == NULL) {
     149       13488 :                 return 0;
     150             :         }
     151             : 
     152         249 :         if (ref->cli_nps->conn == NULL) {
     153         166 :                 return 0;
     154             :         }
     155             : 
     156          83 :         ref->cli_nps->conn = NULL;
     157          83 :         ref->cli_nps->session = NULL;
     158          83 :         ref->cli_nps->tcon = NULL;
     159             : 
     160          83 :         TALLOC_FREE(ref->cli_nps->conn_ref);
     161          83 :         TALLOC_FREE(ref->cli_nps->session_ref);
     162          83 :         TALLOC_FREE(ref->cli_nps->tcon_ref);
     163             : 
     164          83 :         return 0;
     165             : };
     166             : 
     167             : static struct tevent_req *tstream_smbXcli_np_disconnect_send(TALLOC_CTX *mem_ctx,
     168             :                                                 struct tevent_context *ev,
     169             :                                                 struct tstream_context *stream);
     170             : static int tstream_smbXcli_np_disconnect_recv(struct tevent_req *req,
     171             :                                               int *perrno);
     172             : 
     173             : struct tstream_smbXcli_np_open_state {
     174             :         struct smbXcli_conn *conn;
     175             :         struct smbXcli_session *session;
     176             :         struct smbXcli_tcon *tcon;
     177             :         uint16_t pid;
     178             :         unsigned int timeout;
     179             : 
     180             :         bool is_smb1;
     181             :         uint16_t fnum;
     182             :         uint64_t fid_persistent;
     183             :         uint64_t fid_volatile;
     184             :         const char *npipe;
     185             : };
     186             : 
     187             : static void tstream_smbXcli_np_open_done(struct tevent_req *subreq);
     188             : 
     189        4737 : struct tevent_req *tstream_smbXcli_np_open_send(TALLOC_CTX *mem_ctx,
     190             :                                                 struct tevent_context *ev,
     191             :                                                 struct smbXcli_conn *conn,
     192             :                                                 struct smbXcli_session *session,
     193             :                                                 struct smbXcli_tcon *tcon,
     194             :                                                 uint16_t pid,
     195             :                                                 unsigned int timeout,
     196             :                                                 const char *npipe)
     197             : {
     198             :         struct tevent_req *req;
     199             :         struct tstream_smbXcli_np_open_state *state;
     200             :         struct tevent_req *subreq;
     201             : 
     202        4737 :         req = tevent_req_create(mem_ctx, &state,
     203             :                                 struct tstream_smbXcli_np_open_state);
     204        4737 :         if (!req) {
     205           0 :                 return NULL;
     206             :         }
     207        4737 :         state->conn = conn;
     208        4737 :         state->tcon = tcon;
     209        4737 :         state->session = session;
     210        4737 :         state->pid = pid;
     211        4737 :         state->timeout = timeout;
     212             : 
     213        4737 :         state->npipe = talloc_strdup(state, npipe);
     214        4737 :         if (tevent_req_nomem(state->npipe, req)) {
     215           0 :                 return tevent_req_post(req, ev);
     216             :         }
     217             : 
     218        4737 :         if (smbXcli_conn_protocol(conn) < PROTOCOL_SMB2_02) {
     219          11 :                 state->is_smb1 = true;
     220             :         }
     221             : 
     222        4737 :         if (state->is_smb1) {
     223             :                 const char *smb1_npipe;
     224             : 
     225             :                 /*
     226             :                  * Windows and newer Samba versions allow
     227             :                  * the pipe name without leading backslash,
     228             :                  * but we should better behave like windows clients
     229             :                  */
     230          11 :                 smb1_npipe = talloc_asprintf(state, "\\%s", state->npipe);
     231          11 :                 if (tevent_req_nomem(smb1_npipe, req)) {
     232           0 :                         return tevent_req_post(req, ev);
     233             :                 }
     234          11 :                 subreq = smb1cli_ntcreatex_send(state, ev, state->conn,
     235          11 :                                                 state->timeout,
     236          11 :                                                 state->pid,
     237          11 :                                                 state->tcon,
     238          11 :                                                 state->session,
     239             :                                                 smb1_npipe,
     240             :                                                 0, /* CreatFlags */
     241             :                                                 0, /* RootDirectoryFid */
     242             :                                                 TSTREAM_SMBXCLI_NP_DESIRED_ACCESS,
     243             :                                                 0, /* AllocationSize */
     244             :                                                 0, /* FileAttributes */
     245             :                                                 FILE_SHARE_READ|FILE_SHARE_WRITE,
     246             :                                                 FILE_OPEN, /* CreateDisposition */
     247             :                                                 0, /* CreateOptions */
     248             :                                                 2, /* NTCREATEX_IMPERSONATION_IMPERSONATION */
     249             :                                                 0); /* SecurityFlags */
     250             :         } else {
     251        4726 :                 subreq = smb2cli_create_send(state, ev, state->conn,
     252        4726 :                                              state->timeout, state->session,
     253        4726 :                                              state->tcon,
     254             :                                              npipe,
     255             :                                              SMB2_OPLOCK_LEVEL_NONE,
     256             :                                              SMB2_IMPERSONATION_IMPERSONATION,
     257             :                                              TSTREAM_SMBXCLI_NP_DESIRED_ACCESS,
     258             :                                              0, /* file_attributes */
     259             :                                              FILE_SHARE_READ|FILE_SHARE_WRITE,
     260             :                                              FILE_OPEN,
     261             :                                              0, /* create_options */
     262             :                                              NULL); /* blobs */
     263             :         }
     264        4737 :         if (tevent_req_nomem(subreq, req)) {
     265           0 :                 return tevent_req_post(req, ev);
     266             :         }
     267        4737 :         tevent_req_set_callback(subreq, tstream_smbXcli_np_open_done, req);
     268             : 
     269        4737 :         return req;
     270             : }
     271             : 
     272        4737 : static void tstream_smbXcli_np_open_done(struct tevent_req *subreq)
     273             : {
     274             :         struct tevent_req *req =
     275        4737 :                 tevent_req_callback_data(subreq, struct tevent_req);
     276             :         struct tstream_smbXcli_np_open_state *state =
     277        4737 :                 tevent_req_data(req, struct tstream_smbXcli_np_open_state);
     278             :         NTSTATUS status;
     279             : 
     280        4737 :         if (state->is_smb1) {
     281          11 :                 status = smb1cli_ntcreatex_recv(subreq, &state->fnum);
     282             :         } else {
     283        4726 :                 status = smb2cli_create_recv(
     284             :                         subreq,
     285             :                         &state->fid_persistent,
     286             :                         &state->fid_volatile,
     287             :                         NULL,
     288             :                         NULL,
     289             :                         NULL,
     290             :                         NULL);
     291             :         }
     292        4737 :         TALLOC_FREE(subreq);
     293        4737 :         if (!NT_STATUS_IS_OK(status)) {
     294         158 :                 tevent_req_nterror(req, status);
     295         158 :                 return;
     296             :         }
     297             : 
     298        4579 :         tevent_req_done(req);
     299             : }
     300             : 
     301        4737 : NTSTATUS _tstream_smbXcli_np_open_recv(struct tevent_req *req,
     302             :                                        TALLOC_CTX *mem_ctx,
     303             :                                        struct tstream_context **_stream,
     304             :                                        const char *location)
     305             : {
     306             :         struct tstream_smbXcli_np_open_state *state =
     307        4737 :                 tevent_req_data(req, struct tstream_smbXcli_np_open_state);
     308             :         struct tstream_context *stream;
     309             :         struct tstream_smbXcli_np *cli_nps;
     310             :         NTSTATUS status;
     311             : 
     312        4737 :         if (tevent_req_is_nterror(req, &status)) {
     313         158 :                 tevent_req_received(req);
     314         158 :                 return status;
     315             :         }
     316             : 
     317        4579 :         stream = tstream_context_create(mem_ctx,
     318             :                                         &tstream_smbXcli_np_ops,
     319             :                                         &cli_nps,
     320             :                                         struct tstream_smbXcli_np,
     321             :                                         location);
     322        4579 :         if (!stream) {
     323           0 :                 tevent_req_received(req);
     324           0 :                 return NT_STATUS_NO_MEMORY;
     325             :         }
     326        4579 :         ZERO_STRUCTP(cli_nps);
     327             : 
     328        4579 :         cli_nps->conn_ref = talloc_zero(state->conn,
     329             :                                         struct tstream_smbXcli_np_ref);
     330        4579 :         if (cli_nps->conn_ref == NULL) {
     331           0 :                 TALLOC_FREE(cli_nps);
     332           0 :                 tevent_req_received(req);
     333           0 :                 return NT_STATUS_NO_MEMORY;
     334             :         }
     335        4579 :         cli_nps->conn_ref->cli_nps = cli_nps;
     336             : 
     337        4579 :         cli_nps->session_ref = talloc_zero(state->session,
     338             :                                         struct tstream_smbXcli_np_ref);
     339        4579 :         if (cli_nps->session_ref == NULL) {
     340           0 :                 TALLOC_FREE(cli_nps);
     341           0 :                 tevent_req_received(req);
     342           0 :                 return NT_STATUS_NO_MEMORY;
     343             :         }
     344        4579 :         cli_nps->session_ref->cli_nps = cli_nps;
     345             : 
     346        4579 :         cli_nps->tcon_ref = talloc_zero(state->tcon,
     347             :                                         struct tstream_smbXcli_np_ref);
     348        4579 :         if (cli_nps->tcon_ref == NULL) {
     349           0 :                 TALLOC_FREE(cli_nps);
     350           0 :                 tevent_req_received(req);
     351           0 :                 return NT_STATUS_NO_MEMORY;
     352             :         }
     353        4579 :         cli_nps->tcon_ref->cli_nps = cli_nps;
     354             : 
     355        4579 :         cli_nps->conn = state->conn;
     356        4579 :         cli_nps->session = state->session;
     357        4579 :         cli_nps->tcon = state->tcon;
     358        4579 :         cli_nps->pid  = state->pid;
     359        4579 :         cli_nps->timeout = state->timeout;
     360        4579 :         cli_nps->npipe = talloc_move(cli_nps, &state->npipe);
     361        4579 :         cli_nps->is_smb1 = state->is_smb1;
     362        4579 :         cli_nps->fnum = state->fnum;
     363        4579 :         cli_nps->fid_persistent = state->fid_persistent;
     364        4579 :         cli_nps->fid_volatile = state->fid_volatile;
     365             : 
     366        4579 :         talloc_set_destructor(cli_nps, tstream_smbXcli_np_destructor);
     367        4579 :         talloc_set_destructor(cli_nps->conn_ref,
     368             :                               tstream_smbXcli_np_ref_destructor);
     369        4579 :         talloc_set_destructor(cli_nps->session_ref,
     370             :                               tstream_smbXcli_np_ref_destructor);
     371        4579 :         talloc_set_destructor(cli_nps->tcon_ref,
     372             :                               tstream_smbXcli_np_ref_destructor);
     373             : 
     374        4579 :         cli_nps->trans.active = false;
     375        4579 :         cli_nps->trans.read_req = NULL;
     376        4579 :         cli_nps->trans.write_req = NULL;
     377        4579 :         SSVAL(cli_nps->trans.setup+0, 0, TRANSACT_DCERPCCMD);
     378        4579 :         SSVAL(cli_nps->trans.setup+1, 0, cli_nps->fnum);
     379             : 
     380        4579 :         *_stream = stream;
     381        4579 :         tevent_req_received(req);
     382        4579 :         return NT_STATUS_OK;
     383             : }
     384             : 
     385       13784 : static ssize_t tstream_smbXcli_np_pending_bytes(struct tstream_context *stream)
     386             : {
     387       13784 :         struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
     388             :                                          struct tstream_smbXcli_np);
     389             : 
     390       13784 :         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
     391           0 :                 errno = ENOTCONN;
     392           0 :                 return -1;
     393             :         }
     394             : 
     395       13784 :         return cli_nps->read.left;
     396             : }
     397             : 
     398      221917 : bool tstream_is_smbXcli_np(struct tstream_context *stream)
     399             : {
     400             :         struct tstream_smbXcli_np *cli_nps =
     401      221917 :                 talloc_get_type(_tstream_context_data(stream),
     402             :                 struct tstream_smbXcli_np);
     403             : 
     404      221917 :         if (!cli_nps) {
     405       77034 :                 return false;
     406             :         }
     407             : 
     408      144883 :         return true;
     409             : }
     410             : 
     411      123360 : NTSTATUS tstream_smbXcli_np_use_trans(struct tstream_context *stream)
     412             : {
     413      123360 :         struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
     414             :                                          struct tstream_smbXcli_np);
     415             : 
     416      123360 :         if (cli_nps->trans.read_req) {
     417           0 :                 return NT_STATUS_PIPE_BUSY;
     418             :         }
     419             : 
     420      123360 :         if (cli_nps->trans.write_req) {
     421           0 :                 return NT_STATUS_PIPE_BUSY;
     422             :         }
     423             : 
     424      123360 :         if (cli_nps->trans.active) {
     425           0 :                 return NT_STATUS_PIPE_BUSY;
     426             :         }
     427             : 
     428      123360 :         cli_nps->trans.active = true;
     429             : 
     430      123360 :         return NT_STATUS_OK;
     431             : }
     432             : 
     433         204 : unsigned int tstream_smbXcli_np_set_timeout(struct tstream_context *stream,
     434             :                                             unsigned int timeout)
     435             : {
     436         204 :         struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
     437             :                                          struct tstream_smbXcli_np);
     438         204 :         unsigned int old_timeout = cli_nps->timeout;
     439             : 
     440         204 :         cli_nps->timeout = timeout;
     441         204 :         return old_timeout;
     442             : }
     443             : 
     444             : struct tstream_smbXcli_np_writev_state {
     445             :         struct tstream_context *stream;
     446             :         struct tevent_context *ev;
     447             : 
     448             :         struct iovec *vector;
     449             :         size_t count;
     450             : 
     451             :         int ret;
     452             : 
     453             :         struct {
     454             :                 int val;
     455             :                 const char *location;
     456             :         } error;
     457             : };
     458             : 
     459      130148 : static int tstream_smbXcli_np_writev_state_destructor(struct tstream_smbXcli_np_writev_state *state)
     460             : {
     461             :         struct tstream_smbXcli_np *cli_nps =
     462      130148 :                 tstream_context_data(state->stream,
     463             :                 struct tstream_smbXcli_np);
     464             : 
     465      130148 :         cli_nps->trans.write_req = NULL;
     466             : 
     467      130148 :         return 0;
     468             : }
     469             : 
     470             : static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req);
     471             : 
     472      130148 : static struct tevent_req *tstream_smbXcli_np_writev_send(TALLOC_CTX *mem_ctx,
     473             :                                         struct tevent_context *ev,
     474             :                                         struct tstream_context *stream,
     475             :                                         const struct iovec *vector,
     476             :                                         size_t count)
     477             : {
     478             :         struct tevent_req *req;
     479             :         struct tstream_smbXcli_np_writev_state *state;
     480      130148 :         struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
     481             :                                          struct tstream_smbXcli_np);
     482             : 
     483      130148 :         req = tevent_req_create(mem_ctx, &state,
     484             :                                 struct tstream_smbXcli_np_writev_state);
     485      130148 :         if (!req) {
     486           0 :                 return NULL;
     487             :         }
     488      130148 :         state->stream = stream;
     489      130148 :         state->ev = ev;
     490      130148 :         state->ret = 0;
     491             : 
     492      130148 :         talloc_set_destructor(state, tstream_smbXcli_np_writev_state_destructor);
     493             : 
     494      130148 :         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
     495           0 :                 tevent_req_error(req, ENOTCONN);
     496           0 :                 return tevent_req_post(req, ev);
     497             :         }
     498             : 
     499             :         /*
     500             :          * we make a copy of the vector so we can change the structure
     501             :          */
     502      130148 :         state->vector = talloc_array(state, struct iovec, count);
     503      130148 :         if (tevent_req_nomem(state->vector, req)) {
     504           0 :                 return tevent_req_post(req, ev);
     505             :         }
     506      130148 :         memcpy(state->vector, vector, sizeof(struct iovec) * count);
     507      130148 :         state->count = count;
     508             : 
     509      130148 :         tstream_smbXcli_np_writev_write_next(req);
     510      130148 :         if (!tevent_req_is_in_progress(req)) {
     511           0 :                 return tevent_req_post(req, ev);
     512             :         }
     513             : 
     514      130148 :         return req;
     515             : }
     516             : 
     517             : static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req);
     518             : static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq);
     519             : 
     520      136936 : static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req)
     521             : {
     522             :         struct tstream_smbXcli_np_writev_state *state =
     523      136936 :                 tevent_req_data(req,
     524             :                 struct tstream_smbXcli_np_writev_state);
     525             :         struct tstream_smbXcli_np *cli_nps =
     526      136936 :                 tstream_context_data(state->stream,
     527             :                 struct tstream_smbXcli_np);
     528             :         struct tevent_req *subreq;
     529             :         size_t i;
     530      136936 :         size_t left = 0;
     531             : 
     532      267084 :         for (i=0; i < state->count; i++) {
     533      130148 :                 left += state->vector[i].iov_len;
     534             :         }
     535             : 
     536      136936 :         if (left == 0) {
     537        6788 :                 TALLOC_FREE(cli_nps->write.buf);
     538        6788 :                 tevent_req_done(req);
     539        6788 :                 return;
     540             :         }
     541             : 
     542      130148 :         cli_nps->write.ofs = 0;
     543      130148 :         cli_nps->write.left = MIN(left, TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
     544      130148 :         cli_nps->write.buf = talloc_realloc(cli_nps, cli_nps->write.buf,
     545             :                                             uint8_t, cli_nps->write.left);
     546      130148 :         if (tevent_req_nomem(cli_nps->write.buf, req)) {
     547           0 :                 return;
     548             :         }
     549             : 
     550             :         /*
     551             :          * copy the pending buffer first
     552             :          */
     553      260296 :         while (cli_nps->write.left > 0 && state->count > 0) {
     554      130148 :                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
     555      130148 :                 size_t len = MIN(cli_nps->write.left, state->vector[0].iov_len);
     556             : 
     557      130148 :                 memcpy(cli_nps->write.buf + cli_nps->write.ofs, base, len);
     558             : 
     559      130148 :                 base += len;
     560      130148 :                 state->vector[0].iov_base = base;
     561      130148 :                 state->vector[0].iov_len -= len;
     562             : 
     563      130148 :                 cli_nps->write.ofs += len;
     564      130148 :                 cli_nps->write.left -= len;
     565             : 
     566      130148 :                 if (state->vector[0].iov_len == 0) {
     567      130148 :                         state->vector += 1;
     568      130148 :                         state->count -= 1;
     569             :                 }
     570             : 
     571      130148 :                 state->ret += len;
     572             :         }
     573             : 
     574      130148 :         if (cli_nps->trans.active && state->count == 0) {
     575        4690 :                 cli_nps->trans.active = false;
     576        4690 :                 cli_nps->trans.write_req = req;
     577        4690 :                 return;
     578             :         }
     579             : 
     580      125458 :         if (cli_nps->trans.read_req && state->count == 0) {
     581      118670 :                 cli_nps->trans.write_req = req;
     582      118670 :                 tstream_smbXcli_np_readv_trans_start(cli_nps->trans.read_req);
     583      118670 :                 return;
     584             :         }
     585             : 
     586        6788 :         if (cli_nps->is_smb1) {
     587           0 :                 subreq = smb1cli_writex_send(state, state->ev,
     588             :                                              cli_nps->conn,
     589             :                                              cli_nps->timeout,
     590           0 :                                              cli_nps->pid,
     591             :                                              cli_nps->tcon,
     592             :                                              cli_nps->session,
     593           0 :                                              cli_nps->fnum,
     594             :                                              8, /* 8 means message mode. */
     595           0 :                                              cli_nps->write.buf,
     596             :                                              0, /* offset */
     597           0 :                                              cli_nps->write.ofs); /* size */
     598             :         } else {
     599        6788 :                 subreq = smb2cli_write_send(state, state->ev,
     600             :                                             cli_nps->conn,
     601             :                                             cli_nps->timeout,
     602             :                                             cli_nps->session,
     603             :                                             cli_nps->tcon,
     604        6788 :                                             cli_nps->write.ofs, /* length */
     605             :                                             0, /* offset */
     606             :                                             cli_nps->fid_persistent,
     607             :                                             cli_nps->fid_volatile,
     608             :                                             0, /* remaining_bytes */
     609             :                                             0, /* flags */
     610        6788 :                                             cli_nps->write.buf);
     611             :         }
     612        6788 :         if (tevent_req_nomem(subreq, req)) {
     613           0 :                 return;
     614             :         }
     615        6788 :         tevent_req_set_callback(subreq,
     616             :                                 tstream_smbXcli_np_writev_write_done,
     617             :                                 req);
     618             : }
     619             : 
     620             : static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req,
     621             :                                                  int error,
     622             :                                                  const char *location);
     623             : 
     624        6788 : static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq)
     625             : {
     626             :         struct tevent_req *req =
     627        6788 :                 tevent_req_callback_data(subreq, struct tevent_req);
     628             :         struct tstream_smbXcli_np_writev_state *state =
     629        6788 :                 tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
     630             :         struct tstream_smbXcli_np *cli_nps =
     631        6788 :                 tstream_context_data(state->stream,
     632             :                 struct tstream_smbXcli_np);
     633             :         uint32_t written;
     634             :         NTSTATUS status;
     635             : 
     636        6788 :         if (cli_nps->is_smb1) {
     637           0 :                 status = smb1cli_writex_recv(subreq, &written, NULL);
     638             :         } else {
     639        6788 :                 status = smb2cli_write_recv(subreq, &written);
     640             :         }
     641        6788 :         TALLOC_FREE(subreq);
     642        6788 :         if (!NT_STATUS_IS_OK(status)) {
     643           0 :                 tstream_smbXcli_np_writev_disconnect_now(req, EPIPE, __location__);
     644           0 :                 return;
     645             :         }
     646             : 
     647        6788 :         if (written != cli_nps->write.ofs) {
     648           0 :                 tstream_smbXcli_np_writev_disconnect_now(req, EIO, __location__);
     649           0 :                 return;
     650             :         }
     651             : 
     652        6788 :         tstream_smbXcli_np_writev_write_next(req);
     653             : }
     654             : 
     655             : static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq);
     656             : 
     657           0 : static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req,
     658             :                                                  int error,
     659             :                                                  const char *location)
     660             : {
     661             :         struct tstream_smbXcli_np_writev_state *state =
     662           0 :                 tevent_req_data(req,
     663             :                 struct tstream_smbXcli_np_writev_state);
     664             :         struct tstream_smbXcli_np *cli_nps =
     665           0 :                 tstream_context_data(state->stream,
     666             :                 struct tstream_smbXcli_np);
     667             :         struct tevent_req *subreq;
     668             : 
     669           0 :         state->error.val = error;
     670           0 :         state->error.location = location;
     671             : 
     672           0 :         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
     673             :                 /* return the original error */
     674           0 :                 _tevent_req_error(req, state->error.val, state->error.location);
     675           0 :                 return;
     676             :         }
     677             : 
     678           0 :         subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
     679             :                                                     state->stream);
     680           0 :         if (subreq == NULL) {
     681             :                 /* return the original error */
     682           0 :                 _tevent_req_error(req, state->error.val, state->error.location);
     683           0 :                 return;
     684             :         }
     685           0 :         tevent_req_set_callback(subreq,
     686             :                                 tstream_smbXcli_np_writev_disconnect_done,
     687             :                                 req);
     688             : }
     689             : 
     690           0 : static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq)
     691             : {
     692             :         struct tevent_req *req =
     693           0 :                 tevent_req_callback_data(subreq, struct tevent_req);
     694             :         struct tstream_smbXcli_np_writev_state *state =
     695           0 :                 tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
     696             :         int error;
     697             : 
     698           0 :         tstream_smbXcli_np_disconnect_recv(subreq, &error);
     699           0 :         TALLOC_FREE(subreq);
     700             : 
     701             :         /* return the original error */
     702           0 :         _tevent_req_error(req, state->error.val, state->error.location);
     703           0 : }
     704             : 
     705      130148 : static int tstream_smbXcli_np_writev_recv(struct tevent_req *req,
     706             :                                       int *perrno)
     707             : {
     708             :         struct tstream_smbXcli_np_writev_state *state =
     709      130148 :                 tevent_req_data(req,
     710             :                 struct tstream_smbXcli_np_writev_state);
     711             :         int ret;
     712             : 
     713      130148 :         ret = tsocket_simple_int_recv(req, perrno);
     714      130148 :         if (ret == 0) {
     715      130136 :                 ret = state->ret;
     716             :         }
     717             : 
     718      130148 :         tevent_req_received(req);
     719      130148 :         return ret;
     720             : }
     721             : 
     722             : struct tstream_smbXcli_np_readv_state {
     723             :         struct tstream_context *stream;
     724             :         struct tevent_context *ev;
     725             : 
     726             :         struct iovec *vector;
     727             :         size_t count;
     728             : 
     729             :         int ret;
     730             : 
     731             :         struct {
     732             :                 struct tevent_immediate *im;
     733             :         } trans;
     734             : 
     735             :         struct {
     736             :                 int val;
     737             :                 const char *location;
     738             :         } error;
     739             : };
     740             : 
     741      260360 : static int tstream_smbXcli_np_readv_state_destructor(struct tstream_smbXcli_np_readv_state *state)
     742             : {
     743             :         struct tstream_smbXcli_np *cli_nps =
     744      260360 :                 tstream_context_data(state->stream,
     745             :                 struct tstream_smbXcli_np);
     746             : 
     747      260360 :         cli_nps->trans.read_req = NULL;
     748             : 
     749      260360 :         return 0;
     750             : }
     751             : 
     752             : static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req);
     753             : 
     754      260360 : static struct tevent_req *tstream_smbXcli_np_readv_send(TALLOC_CTX *mem_ctx,
     755             :                                         struct tevent_context *ev,
     756             :                                         struct tstream_context *stream,
     757             :                                         struct iovec *vector,
     758             :                                         size_t count)
     759             : {
     760             :         struct tevent_req *req;
     761             :         struct tstream_smbXcli_np_readv_state *state;
     762             :         struct tstream_smbXcli_np *cli_nps =
     763      260360 :                 tstream_context_data(stream, struct tstream_smbXcli_np);
     764             : 
     765      260360 :         req = tevent_req_create(mem_ctx, &state,
     766             :                                 struct tstream_smbXcli_np_readv_state);
     767      260360 :         if (!req) {
     768           0 :                 return NULL;
     769             :         }
     770      260360 :         state->stream = stream;
     771      260360 :         state->ev = ev;
     772      260360 :         state->ret = 0;
     773             : 
     774      260360 :         talloc_set_destructor(state, tstream_smbXcli_np_readv_state_destructor);
     775             : 
     776      260360 :         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
     777           0 :                 tevent_req_error(req, ENOTCONN);
     778           0 :                 return tevent_req_post(req, ev);
     779             :         }
     780             : 
     781             :         /*
     782             :          * we make a copy of the vector so we can change the structure
     783             :          */
     784      260360 :         state->vector = talloc_array(state, struct iovec, count);
     785      260360 :         if (tevent_req_nomem(state->vector, req)) {
     786           0 :                 return tevent_req_post(req, ev);
     787             :         }
     788      260360 :         memcpy(state->vector, vector, sizeof(struct iovec) * count);
     789      260360 :         state->count = count;
     790             : 
     791      260360 :         tstream_smbXcli_np_readv_read_next(req);
     792      260360 :         if (!tevent_req_is_in_progress(req)) {
     793      130174 :                 return tevent_req_post(req, ev);
     794             :         }
     795             : 
     796      130186 :         return req;
     797             : }
     798             : 
     799             : static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq);
     800             : 
     801      390534 : static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req)
     802             : {
     803             :         struct tstream_smbXcli_np_readv_state *state =
     804      390534 :                 tevent_req_data(req,
     805             :                 struct tstream_smbXcli_np_readv_state);
     806             :         struct tstream_smbXcli_np *cli_nps =
     807      390534 :                 tstream_context_data(state->stream,
     808             :                 struct tstream_smbXcli_np);
     809             :         struct tevent_req *subreq;
     810             : 
     811             :         /*
     812             :          * copy the pending buffer first
     813             :          */
     814      650882 :         while (cli_nps->read.left > 0 && state->count > 0) {
     815      260348 :                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
     816      260348 :                 size_t len = MIN(cli_nps->read.left, state->vector[0].iov_len);
     817             : 
     818      260348 :                 memcpy(base, cli_nps->read.buf + cli_nps->read.ofs, len);
     819             : 
     820      260348 :                 base += len;
     821      260348 :                 state->vector[0].iov_base = base;
     822      260348 :                 state->vector[0].iov_len -= len;
     823             : 
     824      260348 :                 cli_nps->read.ofs += len;
     825      260348 :                 cli_nps->read.left -= len;
     826             : 
     827      260348 :                 if (state->vector[0].iov_len == 0) {
     828      260348 :                         state->vector += 1;
     829      260348 :                         state->count -= 1;
     830             :                 }
     831             : 
     832      260348 :                 state->ret += len;
     833             :         }
     834             : 
     835      390534 :         if (cli_nps->read.left == 0) {
     836      260360 :                 TALLOC_FREE(cli_nps->read.buf);
     837             :         }
     838             : 
     839      390534 :         if (state->count == 0) {
     840      260348 :                 tevent_req_done(req);
     841      260348 :                 return;
     842             :         }
     843             : 
     844      130186 :         if (cli_nps->trans.active) {
     845      118670 :                 cli_nps->trans.active = false;
     846      118670 :                 cli_nps->trans.read_req = req;
     847      118670 :                 return;
     848             :         }
     849             : 
     850       11516 :         if (cli_nps->trans.write_req) {
     851        4690 :                 cli_nps->trans.read_req = req;
     852        4690 :                 tstream_smbXcli_np_readv_trans_start(req);
     853        4690 :                 return;
     854             :         }
     855             : 
     856        6826 :         if (cli_nps->is_smb1) {
     857           0 :                 subreq = smb1cli_readx_send(state, state->ev,
     858             :                                             cli_nps->conn,
     859             :                                             cli_nps->timeout,
     860           0 :                                             cli_nps->pid,
     861             :                                             cli_nps->tcon,
     862             :                                             cli_nps->session,
     863           0 :                                             cli_nps->fnum,
     864             :                                             0, /* offset */
     865             :                                             TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
     866             :         } else {
     867        6826 :                 subreq = smb2cli_read_send(state, state->ev,
     868             :                                            cli_nps->conn,
     869             :                                            cli_nps->timeout,
     870             :                                            cli_nps->session,
     871             :                                            cli_nps->tcon,
     872             :                                            TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE, /* length */
     873             :                                            0, /* offset */
     874             :                                            cli_nps->fid_persistent,
     875             :                                            cli_nps->fid_volatile,
     876             :                                            0, /* minimum_count */
     877             :                                            0); /* remaining_bytes */
     878             :         }
     879        6826 :         if (tevent_req_nomem(subreq, req)) {
     880           0 :                 return;
     881             :         }
     882        6826 :         tevent_req_set_callback(subreq,
     883             :                                 tstream_smbXcli_np_readv_read_done,
     884             :                                 req);
     885             : }
     886             : 
     887             : static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq);
     888             : 
     889      123360 : static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req)
     890             : {
     891             :         struct tstream_smbXcli_np_readv_state *state =
     892      123360 :                 tevent_req_data(req,
     893             :                 struct tstream_smbXcli_np_readv_state);
     894             :         struct tstream_smbXcli_np *cli_nps =
     895      123360 :                 tstream_context_data(state->stream,
     896             :                 struct tstream_smbXcli_np);
     897             :         struct tevent_req *subreq;
     898             : 
     899      123360 :         state->trans.im = tevent_create_immediate(state);
     900      123360 :         if (tevent_req_nomem(state->trans.im, req)) {
     901           0 :                 return;
     902             :         }
     903             : 
     904      123360 :         if (cli_nps->is_smb1) {
     905          42 :                 subreq = smb1cli_trans_send(state, state->ev,
     906             :                                             cli_nps->conn, SMBtrans,
     907             :                                             0, 0, /* *_flags */
     908             :                                             0, 0, /* *_flags2 */
     909             :                                             cli_nps->timeout,
     910          42 :                                             cli_nps->pid,
     911             :                                             cli_nps->tcon,
     912             :                                             cli_nps->session,
     913             :                                             "\\PIPE\\",
     914             :                                             0, 0, 0,
     915          42 :                                             cli_nps->trans.setup, 2,
     916             :                                             0,
     917             :                                             NULL, 0, 0,
     918             :                                             cli_nps->write.buf,
     919          42 :                                             cli_nps->write.ofs,
     920             :                                             TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
     921             :         } else {
     922      123318 :                 DATA_BLOB in_input_buffer = data_blob_null;
     923      123318 :                 DATA_BLOB in_output_buffer = data_blob_null;
     924             : 
     925      123318 :                 in_input_buffer = data_blob_const(cli_nps->write.buf,
     926      123318 :                                                   cli_nps->write.ofs);
     927             : 
     928      123318 :                 subreq = smb2cli_ioctl_send(state, state->ev,
     929             :                                             cli_nps->conn,
     930             :                                             cli_nps->timeout,
     931             :                                             cli_nps->session,
     932             :                                             cli_nps->tcon,
     933             :                                             cli_nps->fid_persistent,
     934             :                                             cli_nps->fid_volatile,
     935             :                                             FSCTL_NAMED_PIPE_READ_WRITE,
     936             :                                             0, /* in_max_input_length */
     937             :                                             &in_input_buffer,
     938             :                                             /* in_max_output_length */
     939             :                                             TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE,
     940             :                                             &in_output_buffer,
     941             :                                             SMB2_IOCTL_FLAG_IS_FSCTL);
     942             :         }
     943      123360 :         if (tevent_req_nomem(subreq, req)) {
     944           0 :                 return;
     945             :         }
     946      123360 :         tevent_req_set_callback(subreq,
     947             :                                 tstream_smbXcli_np_readv_trans_done,
     948             :                                 req);
     949             : }
     950             : 
     951             : static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
     952             :                                                 int error,
     953             :                                                 const char *location);
     954             : static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
     955             :                                                 struct tevent_immediate *im,
     956             :                                                 void *private_data);
     957             : 
     958      123360 : static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq)
     959             : {
     960             :         struct tevent_req *req =
     961      123360 :                 tevent_req_callback_data(subreq, struct tevent_req);
     962             :         struct tstream_smbXcli_np_readv_state *state =
     963      123360 :                 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
     964             :         struct tstream_smbXcli_np *cli_nps =
     965      123360 :                 tstream_context_data(state->stream, struct tstream_smbXcli_np);
     966             :         uint8_t *rcvbuf;
     967             :         uint32_t received;
     968             :         NTSTATUS status;
     969             : 
     970      123360 :         if (cli_nps->is_smb1) {
     971          42 :                 status = smb1cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
     972             :                                             NULL, 0, NULL,
     973             :                                             &rcvbuf, 0, &received);
     974             :         } else {
     975      123318 :                 DATA_BLOB out_input_buffer = data_blob_null;
     976      123318 :                 DATA_BLOB out_output_buffer = data_blob_null;
     977             : 
     978      123318 :                 status = smb2cli_ioctl_recv(subreq, state,
     979             :                                             &out_input_buffer,
     980             :                                             &out_output_buffer);
     981             : 
     982             :                 /* Note that rcvbuf is not a talloc pointer here */
     983      123318 :                 rcvbuf = out_output_buffer.data;
     984      123318 :                 received = out_output_buffer.length;
     985             :         }
     986      123360 :         TALLOC_FREE(subreq);
     987      123360 :         if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
     988             :                 /*
     989             :                  * STATUS_BUFFER_OVERFLOW means that there's
     990             :                  * more data to read when the named pipe is used
     991             :                  * in message mode (which is the case here).
     992             :                  *
     993             :                  * But we hide this from the caller.
     994             :                  */
     995           0 :                 status = NT_STATUS_OK;
     996             :         }
     997      123360 :         if (!NT_STATUS_IS_OK(status)) {
     998          12 :                 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
     999          12 :                 return;
    1000             :         }
    1001             : 
    1002      123348 :         if (received > TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE) {
    1003           0 :                 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
    1004           0 :                 return;
    1005             :         }
    1006             : 
    1007      123348 :         if (received == 0) {
    1008           0 :                 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
    1009           0 :                 return;
    1010             :         }
    1011             : 
    1012      123348 :         cli_nps->read.ofs = 0;
    1013      123348 :         cli_nps->read.left = received;
    1014      123348 :         cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
    1015      123348 :         if (cli_nps->read.buf == NULL) {
    1016           0 :                 TALLOC_FREE(subreq);
    1017           0 :                 tevent_req_oom(req);
    1018           0 :                 return;
    1019             :         }
    1020      123348 :         memcpy(cli_nps->read.buf, rcvbuf, received);
    1021             : 
    1022      123348 :         if (cli_nps->trans.write_req == NULL) {
    1023           0 :                 tstream_smbXcli_np_readv_read_next(req);
    1024           0 :                 return;
    1025             :         }
    1026             : 
    1027      123348 :         tevent_schedule_immediate(state->trans.im, state->ev,
    1028             :                                   tstream_smbXcli_np_readv_trans_next, req);
    1029             : 
    1030      123348 :         tevent_req_done(cli_nps->trans.write_req);
    1031             : }
    1032             : 
    1033      123348 : static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
    1034             :                                             struct tevent_immediate *im,
    1035             :                                             void *private_data)
    1036             : {
    1037             :         struct tevent_req *req =
    1038      123348 :                 talloc_get_type_abort(private_data,
    1039             :                 struct tevent_req);
    1040             : 
    1041      123348 :         tstream_smbXcli_np_readv_read_next(req);
    1042      123348 : }
    1043             : 
    1044        6826 : static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq)
    1045             : {
    1046             :         struct tevent_req *req =
    1047        6826 :                 tevent_req_callback_data(subreq, struct tevent_req);
    1048             :         struct tstream_smbXcli_np_readv_state *state =
    1049        6826 :                 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
    1050             :         struct tstream_smbXcli_np *cli_nps =
    1051        6826 :                 tstream_context_data(state->stream, struct tstream_smbXcli_np);
    1052             :         uint8_t *rcvbuf;
    1053             :         uint32_t received;
    1054             :         NTSTATUS status;
    1055             : 
    1056             :         /*
    1057             :          * We must free subreq in this function as there is
    1058             :          * a timer event attached to it.
    1059             :          */
    1060             : 
    1061        6826 :         if (cli_nps->is_smb1) {
    1062           0 :                 status = smb1cli_readx_recv(subreq, &received, &rcvbuf);
    1063             :         } else {
    1064        6826 :                 status = smb2cli_read_recv(subreq, state, &rcvbuf, &received);
    1065             :         }
    1066             :         /*
    1067             :          * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
    1068             :          * child of that.
    1069             :          */
    1070        6826 :         if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
    1071             :                 /*
    1072             :                  * STATUS_BUFFER_OVERFLOW means that there's
    1073             :                  * more data to read when the named pipe is used
    1074             :                  * in message mode (which is the case here).
    1075             :                  *
    1076             :                  * But we hide this from the caller.
    1077             :                  */
    1078           0 :                 status = NT_STATUS_OK;
    1079             :         }
    1080        6826 :         if (!NT_STATUS_IS_OK(status)) {
    1081           0 :                 TALLOC_FREE(subreq);
    1082           0 :                 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
    1083           0 :                 return;
    1084             :         }
    1085             : 
    1086        6826 :         if (received > TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE) {
    1087           0 :                 TALLOC_FREE(subreq);
    1088           0 :                 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
    1089           0 :                 return;
    1090             :         }
    1091             : 
    1092        6826 :         if (received == 0) {
    1093           0 :                 TALLOC_FREE(subreq);
    1094           0 :                 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
    1095           0 :                 return;
    1096             :         }
    1097             : 
    1098        6826 :         cli_nps->read.ofs = 0;
    1099        6826 :         cli_nps->read.left = received;
    1100        6826 :         cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
    1101        6826 :         if (cli_nps->read.buf == NULL) {
    1102           0 :                 TALLOC_FREE(subreq);
    1103           0 :                 tevent_req_oom(req);
    1104           0 :                 return;
    1105             :         }
    1106        6826 :         memcpy(cli_nps->read.buf, rcvbuf, received);
    1107        6826 :         TALLOC_FREE(subreq);
    1108             : 
    1109        6826 :         tstream_smbXcli_np_readv_read_next(req);
    1110             : }
    1111             : 
    1112             : static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq);
    1113             : 
    1114             : static void tstream_smbXcli_np_readv_error(struct tevent_req *req);
    1115             : 
    1116          12 : static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
    1117             :                                                 int error,
    1118             :                                                 const char *location)
    1119             : {
    1120             :         struct tstream_smbXcli_np_readv_state *state =
    1121          12 :                 tevent_req_data(req,
    1122             :                 struct tstream_smbXcli_np_readv_state);
    1123             :         struct tstream_smbXcli_np *cli_nps =
    1124          12 :                 tstream_context_data(state->stream,
    1125             :                 struct tstream_smbXcli_np);
    1126             :         struct tevent_req *subreq;
    1127             : 
    1128          12 :         state->error.val = error;
    1129          12 :         state->error.location = location;
    1130             : 
    1131          12 :         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
    1132             :                 /* return the original error */
    1133           0 :                 tstream_smbXcli_np_readv_error(req);
    1134           0 :                 return;
    1135             :         }
    1136             : 
    1137          12 :         subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
    1138             :                                                     state->stream);
    1139          12 :         if (subreq == NULL) {
    1140             :                 /* return the original error */
    1141           0 :                 tstream_smbXcli_np_readv_error(req);
    1142           0 :                 return;
    1143             :         }
    1144          12 :         tevent_req_set_callback(subreq,
    1145             :                                 tstream_smbXcli_np_readv_disconnect_done,
    1146             :                                 req);
    1147             : }
    1148             : 
    1149          12 : static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq)
    1150             : {
    1151             :         struct tevent_req *req =
    1152          12 :                 tevent_req_callback_data(subreq, struct tevent_req);
    1153             :         int error;
    1154             : 
    1155          12 :         tstream_smbXcli_np_disconnect_recv(subreq, &error);
    1156          12 :         TALLOC_FREE(subreq);
    1157             : 
    1158          12 :         tstream_smbXcli_np_readv_error(req);
    1159          12 : }
    1160             : 
    1161             : static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context *ctx,
    1162             :                                                    struct tevent_immediate *im,
    1163             :                                                    void *private_data);
    1164             : 
    1165          12 : static void tstream_smbXcli_np_readv_error(struct tevent_req *req)
    1166             : {
    1167             :         struct tstream_smbXcli_np_readv_state *state =
    1168          12 :                 tevent_req_data(req,
    1169             :                 struct tstream_smbXcli_np_readv_state);
    1170             :         struct tstream_smbXcli_np *cli_nps =
    1171          12 :                 tstream_context_data(state->stream,
    1172             :                 struct tstream_smbXcli_np);
    1173             : 
    1174          12 :         if (cli_nps->trans.write_req == NULL) {
    1175             :                 /* return the original error */
    1176           0 :                 _tevent_req_error(req, state->error.val, state->error.location);
    1177           0 :                 return;
    1178             :         }
    1179             : 
    1180          12 :         if (state->trans.im == NULL) {
    1181             :                 /* return the original error */
    1182           0 :                 _tevent_req_error(req, state->error.val, state->error.location);
    1183           0 :                 return;
    1184             :         }
    1185             : 
    1186          12 :         tevent_schedule_immediate(state->trans.im, state->ev,
    1187             :                                   tstream_smbXcli_np_readv_error_trigger, req);
    1188             : 
    1189             :         /* return the original error for writev */
    1190          12 :         _tevent_req_error(cli_nps->trans.write_req,
    1191          12 :                           state->error.val, state->error.location);
    1192             : }
    1193             : 
    1194           0 : static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context *ctx,
    1195             :                                                    struct tevent_immediate *im,
    1196             :                                                    void *private_data)
    1197             : {
    1198             :         struct tevent_req *req =
    1199           0 :                 talloc_get_type_abort(private_data,
    1200             :                 struct tevent_req);
    1201             :         struct tstream_smbXcli_np_readv_state *state =
    1202           0 :                 tevent_req_data(req,
    1203             :                 struct tstream_smbXcli_np_readv_state);
    1204             : 
    1205             :         /* return the original error */
    1206           0 :         _tevent_req_error(req, state->error.val, state->error.location);
    1207           0 : }
    1208             : 
    1209      260348 : static int tstream_smbXcli_np_readv_recv(struct tevent_req *req,
    1210             :                                          int *perrno)
    1211             : {
    1212             :         struct tstream_smbXcli_np_readv_state *state =
    1213      260348 :                 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
    1214             :         int ret;
    1215             : 
    1216      260348 :         ret = tsocket_simple_int_recv(req, perrno);
    1217      260348 :         if (ret == 0) {
    1218      260348 :                 ret = state->ret;
    1219             :         }
    1220             : 
    1221      260348 :         tevent_req_received(req);
    1222      260348 :         return ret;
    1223             : }
    1224             : 
    1225             : struct tstream_smbXcli_np_disconnect_state {
    1226             :         struct tstream_context *stream;
    1227             :         struct tevent_req *subreq;
    1228             : };
    1229             : 
    1230             : static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq);
    1231             : static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req,
    1232             :                                         enum tevent_req_state req_state);
    1233             : 
    1234        3821 : static struct tevent_req *tstream_smbXcli_np_disconnect_send(TALLOC_CTX *mem_ctx,
    1235             :                                                 struct tevent_context *ev,
    1236             :                                                 struct tstream_context *stream)
    1237             : {
    1238        3821 :         struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
    1239             :                                          struct tstream_smbXcli_np);
    1240             :         struct tevent_req *req;
    1241             :         struct tstream_smbXcli_np_disconnect_state *state;
    1242             :         struct tevent_req *subreq;
    1243             : 
    1244        3821 :         req = tevent_req_create(mem_ctx, &state,
    1245             :                                 struct tstream_smbXcli_np_disconnect_state);
    1246        3821 :         if (req == NULL) {
    1247           0 :                 return NULL;
    1248             :         }
    1249             : 
    1250        3821 :         state->stream = stream;
    1251             : 
    1252        3821 :         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
    1253          83 :                 tevent_req_error(req, ENOTCONN);
    1254          83 :                 return tevent_req_post(req, ev);
    1255             :         }
    1256             : 
    1257        3738 :         if (cli_nps->is_smb1) {
    1258          11 :                 subreq = smb1cli_close_send(state, ev, cli_nps->conn,
    1259             :                                             cli_nps->timeout,
    1260          11 :                                             cli_nps->pid,
    1261             :                                             cli_nps->tcon,
    1262             :                                             cli_nps->session,
    1263          11 :                                             cli_nps->fnum, UINT32_MAX);
    1264             :         } else {
    1265        3727 :                 subreq = smb2cli_close_send(state, ev, cli_nps->conn,
    1266             :                                             cli_nps->timeout,
    1267             :                                             cli_nps->session,
    1268             :                                             cli_nps->tcon,
    1269             :                                             0, /* flags */
    1270             :                                             cli_nps->fid_persistent,
    1271             :                                             cli_nps->fid_volatile);
    1272             :         }
    1273        3738 :         if (tevent_req_nomem(subreq, req)) {
    1274           0 :                 return tevent_req_post(req, ev);
    1275             :         }
    1276        3738 :         tevent_req_set_callback(subreq, tstream_smbXcli_np_disconnect_done, req);
    1277        3738 :         state->subreq = subreq;
    1278             : 
    1279        3738 :         tevent_req_set_cleanup_fn(req, tstream_smbXcli_np_disconnect_cleanup);
    1280             : 
    1281             :         /*
    1282             :          * Make sure we don't send any requests anymore.
    1283             :          */
    1284        3738 :         cli_nps->conn = NULL;
    1285             : 
    1286        3738 :         return req;
    1287             : }
    1288             : 
    1289          12 : static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq)
    1290             : {
    1291          12 :         struct tevent_req *req = tevent_req_callback_data(subreq,
    1292             :                                                           struct tevent_req);
    1293             :         struct tstream_smbXcli_np_disconnect_state *state =
    1294          12 :                 tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
    1295             :         struct tstream_smbXcli_np *cli_nps =
    1296          12 :                 tstream_context_data(state->stream, struct tstream_smbXcli_np);
    1297             :         NTSTATUS status;
    1298             : 
    1299          12 :         state->subreq = NULL;
    1300             : 
    1301          12 :         if (cli_nps->is_smb1) {
    1302           9 :                 status = smb1cli_close_recv(subreq);
    1303             :         } else {
    1304           3 :                 status = smb2cli_close_recv(subreq);
    1305             :         }
    1306          12 :         TALLOC_FREE(subreq);
    1307          12 :         if (!NT_STATUS_IS_OK(status)) {
    1308           9 :                 tevent_req_error(req, EPIPE);
    1309           9 :                 return;
    1310             :         }
    1311             : 
    1312           3 :         cli_nps->conn = NULL;
    1313           3 :         cli_nps->session = NULL;
    1314           3 :         cli_nps->tcon = NULL;
    1315             : 
    1316           3 :         tevent_req_done(req);
    1317             : }
    1318             : 
    1319             : static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq);
    1320             : 
    1321        3750 : static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req,
    1322             :                                         enum tevent_req_state req_state)
    1323             : {
    1324             :         struct tstream_smbXcli_np_disconnect_state *state =
    1325        3750 :                 tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
    1326        3750 :         struct tstream_smbXcli_np *cli_nps = NULL;
    1327             : 
    1328        3750 :         if (state->subreq == NULL) {
    1329          24 :                 return;
    1330             :         }
    1331             : 
    1332        3726 :         cli_nps = tstream_context_data(state->stream, struct tstream_smbXcli_np);
    1333             : 
    1334        3726 :         if (cli_nps->tcon == NULL) {
    1335           0 :                 return;
    1336             :         }
    1337             : 
    1338             :         /*
    1339             :          * We're no longer interested in the result
    1340             :          * any more, but need to make sure that the close
    1341             :          * request arrives at the server if the smb connection,
    1342             :          * session and tcon are still alive.
    1343             :          *
    1344             :          * We move the low level request to the tcon,
    1345             :          * which means that it stays as long as the tcon
    1346             :          * is available.
    1347             :          */
    1348        3726 :         talloc_steal(cli_nps->tcon, state->subreq);
    1349        3726 :         tevent_req_set_callback(state->subreq,
    1350             :                                 tstream_smbXcli_np_disconnect_free,
    1351             :                                 NULL);
    1352        3726 :         state->subreq = NULL;
    1353             : 
    1354        3726 :         cli_nps->conn = NULL;
    1355        3726 :         cli_nps->session = NULL;
    1356        3726 :         cli_nps->tcon = NULL;
    1357             : }
    1358             : 
    1359          52 : static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq)
    1360             : {
    1361          52 :         TALLOC_FREE(subreq);
    1362          52 : }
    1363             : 
    1364          12 : static int tstream_smbXcli_np_disconnect_recv(struct tevent_req *req,
    1365             :                                               int *perrno)
    1366             : {
    1367             :         int ret;
    1368             : 
    1369          12 :         ret = tsocket_simple_int_recv(req, perrno);
    1370             : 
    1371          12 :         tevent_req_received(req);
    1372          12 :         return ret;
    1373             : }
    1374             : 
    1375             : static const struct tstream_context_ops tstream_smbXcli_np_ops = {
    1376             :         .name                   = "smbXcli_np",
    1377             : 
    1378             :         .pending_bytes          = tstream_smbXcli_np_pending_bytes,
    1379             : 
    1380             :         .readv_send             = tstream_smbXcli_np_readv_send,
    1381             :         .readv_recv             = tstream_smbXcli_np_readv_recv,
    1382             : 
    1383             :         .writev_send            = tstream_smbXcli_np_writev_send,
    1384             :         .writev_recv            = tstream_smbXcli_np_writev_recv,
    1385             : 
    1386             :         .disconnect_send        = tstream_smbXcli_np_disconnect_send,
    1387             :         .disconnect_recv        = tstream_smbXcli_np_disconnect_recv,
    1388             : };

Generated by: LCOV version 1.14