LCOV - code coverage report
Current view: top level - libcli/smb - tstream_smbXcli_np.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 453 557 81.3 %
Date: 2021-09-23 10:06:22 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       17326 : static int tstream_smbXcli_np_destructor(struct tstream_smbXcli_np *cli_nps)
      80             : {
      81             :         NTSTATUS status;
      82             : 
      83       17326 :         if (cli_nps->conn_ref != NULL) {
      84       16839 :                 cli_nps->conn_ref->cli_nps = NULL;
      85       16839 :                 TALLOC_FREE(cli_nps->conn_ref);
      86             :         }
      87             : 
      88       17326 :         if (cli_nps->session_ref != NULL) {
      89       16839 :                 cli_nps->session_ref->cli_nps = NULL;
      90       16839 :                 TALLOC_FREE(cli_nps->session_ref);
      91             :         }
      92             : 
      93       17326 :         if (cli_nps->tcon_ref != NULL) {
      94       16839 :                 cli_nps->tcon_ref->cli_nps = NULL;
      95       16839 :                 TALLOC_FREE(cli_nps->tcon_ref);
      96             :         }
      97             : 
      98       17326 :         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
      99        7039 :                 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        9661 :         cli_nps->timeout = MIN(cli_nps->timeout, 1000);
     118             : 
     119        9661 :         if (cli_nps->is_smb1) {
     120         271 :                 status = smb1cli_close(cli_nps->conn,
     121             :                                        cli_nps->timeout,
     122         136 :                                        cli_nps->pid,
     123             :                                        cli_nps->tcon,
     124             :                                        cli_nps->session,
     125         136 :                                        cli_nps->fnum, UINT32_MAX);
     126             :         } else {
     127        9525 :                 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        9661 :         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        9661 :         return 0;
     144             : }
     145             : 
     146       51978 : static int tstream_smbXcli_np_ref_destructor(struct tstream_smbXcli_np_ref *ref)
     147             : {
     148       51978 :         if (ref->cli_nps == NULL) {
     149       48945 :                 return 0;
     150             :         }
     151             : 
     152        1461 :         if (ref->cli_nps->conn == NULL) {
     153         770 :                 return 0;
     154             :         }
     155             : 
     156         487 :         ref->cli_nps->conn = NULL;
     157         487 :         ref->cli_nps->session = NULL;
     158         487 :         ref->cli_nps->tcon = NULL;
     159             : 
     160         487 :         TALLOC_FREE(ref->cli_nps->conn_ref);
     161         487 :         TALLOC_FREE(ref->cli_nps->session_ref);
     162         487 :         TALLOC_FREE(ref->cli_nps->tcon_ref);
     163             : 
     164         385 :         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       17515 : 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       17515 :         req = tevent_req_create(mem_ctx, &state,
     203             :                                 struct tstream_smbXcli_np_open_state);
     204       17515 :         if (!req) {
     205           0 :                 return NULL;
     206             :         }
     207       17515 :         state->conn = conn;
     208       17515 :         state->tcon = tcon;
     209       17515 :         state->session = session;
     210       17515 :         state->pid = pid;
     211       17515 :         state->timeout = timeout;
     212             : 
     213       17515 :         state->npipe = talloc_strdup(state, npipe);
     214       17515 :         if (tevent_req_nomem(state->npipe, req)) {
     215           0 :                 return tevent_req_post(req, ev);
     216             :         }
     217             : 
     218       17515 :         if (smbXcli_conn_protocol(conn) < PROTOCOL_SMB2_02) {
     219         355 :                 state->is_smb1 = true;
     220             :         }
     221             : 
     222       17515 :         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         355 :                 smb1_npipe = talloc_asprintf(state, "\\%s", state->npipe);
     231         355 :                 if (tevent_req_nomem(smb1_npipe, req)) {
     232           0 :                         return tevent_req_post(req, ev);
     233             :                 }
     234        1288 :                 subreq = smb1cli_ntcreatex_send(state, ev, state->conn,
     235         355 :                                                 state->timeout,
     236         355 :                                                 state->pid,
     237         355 :                                                 state->tcon,
     238         355 :                                                 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       45938 :                 subreq = smb2cli_create_send(state, ev, state->conn,
     252       30923 :                                              state->timeout, state->session,
     253       16534 :                                              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       17515 :         if (tevent_req_nomem(subreq, req)) {
     265           0 :                 return tevent_req_post(req, ev);
     266             :         }
     267       17515 :         tevent_req_set_callback(subreq, tstream_smbXcli_np_open_done, req);
     268             : 
     269       17515 :         return req;
     270             : }
     271             : 
     272       17515 : static void tstream_smbXcli_np_open_done(struct tevent_req *subreq)
     273             : {
     274       15326 :         struct tevent_req *req =
     275       17515 :                 tevent_req_callback_data(subreq, struct tevent_req);
     276       15326 :         struct tstream_smbXcli_np_open_state *state =
     277       17515 :                 tevent_req_data(req, struct tstream_smbXcli_np_open_state);
     278             :         NTSTATUS status;
     279             : 
     280       17515 :         if (state->is_smb1) {
     281         355 :                 status = smb1cli_ntcreatex_recv(subreq, &state->fnum);
     282             :         } else {
     283       17160 :                 status = smb2cli_create_recv(subreq,
     284             :                                              &state->fid_persistent,
     285             :                                              &state->fid_volatile,
     286             :                                              NULL, NULL, NULL);
     287             :         }
     288       17515 :         TALLOC_FREE(subreq);
     289       17515 :         if (!NT_STATUS_IS_OK(status)) {
     290         167 :                 tevent_req_nterror(req, status);
     291         167 :                 return;
     292             :         }
     293             : 
     294       17348 :         tevent_req_done(req);
     295             : }
     296             : 
     297       17515 : NTSTATUS _tstream_smbXcli_np_open_recv(struct tevent_req *req,
     298             :                                        TALLOC_CTX *mem_ctx,
     299             :                                        struct tstream_context **_stream,
     300             :                                        const char *location)
     301             : {
     302       15326 :         struct tstream_smbXcli_np_open_state *state =
     303       17515 :                 tevent_req_data(req, struct tstream_smbXcli_np_open_state);
     304             :         struct tstream_context *stream;
     305             :         struct tstream_smbXcli_np *cli_nps;
     306             :         NTSTATUS status;
     307             : 
     308       17515 :         if (tevent_req_is_nterror(req, &status)) {
     309         167 :                 tevent_req_received(req);
     310         167 :                 return status;
     311             :         }
     312             : 
     313       17348 :         stream = tstream_context_create(mem_ctx,
     314             :                                         &tstream_smbXcli_np_ops,
     315             :                                         &cli_nps,
     316             :                                         struct tstream_smbXcli_np,
     317             :                                         location);
     318       17348 :         if (!stream) {
     319           0 :                 tevent_req_received(req);
     320           0 :                 return NT_STATUS_NO_MEMORY;
     321             :         }
     322       17348 :         ZERO_STRUCTP(cli_nps);
     323             : 
     324       17348 :         cli_nps->conn_ref = talloc_zero(state->conn,
     325             :                                         struct tstream_smbXcli_np_ref);
     326       17348 :         if (cli_nps->conn_ref == NULL) {
     327           0 :                 TALLOC_FREE(cli_nps);
     328           0 :                 tevent_req_received(req);
     329           0 :                 return NT_STATUS_NO_MEMORY;
     330             :         }
     331       17348 :         cli_nps->conn_ref->cli_nps = cli_nps;
     332             : 
     333       17348 :         cli_nps->session_ref = talloc_zero(state->session,
     334             :                                         struct tstream_smbXcli_np_ref);
     335       17348 :         if (cli_nps->session_ref == NULL) {
     336           0 :                 TALLOC_FREE(cli_nps);
     337           0 :                 tevent_req_received(req);
     338           0 :                 return NT_STATUS_NO_MEMORY;
     339             :         }
     340       17348 :         cli_nps->session_ref->cli_nps = cli_nps;
     341             : 
     342       17348 :         cli_nps->tcon_ref = talloc_zero(state->tcon,
     343             :                                         struct tstream_smbXcli_np_ref);
     344       17348 :         if (cli_nps->tcon_ref == NULL) {
     345           0 :                 TALLOC_FREE(cli_nps);
     346           0 :                 tevent_req_received(req);
     347           0 :                 return NT_STATUS_NO_MEMORY;
     348             :         }
     349       17348 :         cli_nps->tcon_ref->cli_nps = cli_nps;
     350             : 
     351       17348 :         cli_nps->conn = state->conn;
     352       17348 :         cli_nps->session = state->session;
     353       17348 :         cli_nps->tcon = state->tcon;
     354       17348 :         cli_nps->pid  = state->pid;
     355       17348 :         cli_nps->timeout = state->timeout;
     356       17348 :         cli_nps->npipe = talloc_move(cli_nps, &state->npipe);
     357       17348 :         cli_nps->is_smb1 = state->is_smb1;
     358       17348 :         cli_nps->fnum = state->fnum;
     359       17348 :         cli_nps->fid_persistent = state->fid_persistent;
     360       17348 :         cli_nps->fid_volatile = state->fid_volatile;
     361             : 
     362       17348 :         talloc_set_destructor(cli_nps, tstream_smbXcli_np_destructor);
     363       17348 :         talloc_set_destructor(cli_nps->conn_ref,
     364             :                               tstream_smbXcli_np_ref_destructor);
     365       17348 :         talloc_set_destructor(cli_nps->session_ref,
     366             :                               tstream_smbXcli_np_ref_destructor);
     367       17348 :         talloc_set_destructor(cli_nps->tcon_ref,
     368             :                               tstream_smbXcli_np_ref_destructor);
     369             : 
     370       17348 :         cli_nps->trans.active = false;
     371       17348 :         cli_nps->trans.read_req = NULL;
     372       17348 :         cli_nps->trans.write_req = NULL;
     373       17348 :         SSVAL(cli_nps->trans.setup+0, 0, TRANSACT_DCERPCCMD);
     374       17348 :         SSVAL(cli_nps->trans.setup+1, 0, cli_nps->fnum);
     375             : 
     376       17348 :         *_stream = stream;
     377       17348 :         tevent_req_received(req);
     378       17348 :         return NT_STATUS_OK;
     379             : }
     380             : 
     381      327120 : static ssize_t tstream_smbXcli_np_pending_bytes(struct tstream_context *stream)
     382             : {
     383      327120 :         struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
     384             :                                          struct tstream_smbXcli_np);
     385             : 
     386      327120 :         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
     387           0 :                 errno = ENOTCONN;
     388           0 :                 return -1;
     389             :         }
     390             : 
     391      327120 :         return cli_nps->read.left;
     392             : }
     393             : 
     394      991736 : bool tstream_is_smbXcli_np(struct tstream_context *stream)
     395             : {
     396      918719 :         struct tstream_smbXcli_np *cli_nps =
     397      991736 :                 talloc_get_type(_tstream_context_data(stream),
     398             :                 struct tstream_smbXcli_np);
     399             : 
     400      991736 :         if (!cli_nps) {
     401      307024 :                 return false;
     402             :         }
     403             : 
     404      683831 :         return true;
     405             : }
     406             : 
     407      338476 : NTSTATUS tstream_smbXcli_np_use_trans(struct tstream_context *stream)
     408             : {
     409      338476 :         struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
     410             :                                          struct tstream_smbXcli_np);
     411             : 
     412      338476 :         if (cli_nps->trans.read_req) {
     413           0 :                 return NT_STATUS_PIPE_BUSY;
     414             :         }
     415             : 
     416      338476 :         if (cli_nps->trans.write_req) {
     417           0 :                 return NT_STATUS_PIPE_BUSY;
     418             :         }
     419             : 
     420      338476 :         if (cli_nps->trans.active) {
     421           0 :                 return NT_STATUS_PIPE_BUSY;
     422             :         }
     423             : 
     424      338476 :         cli_nps->trans.active = true;
     425             : 
     426      338476 :         return NT_STATUS_OK;
     427             : }
     428             : 
     429         456 : unsigned int tstream_smbXcli_np_set_timeout(struct tstream_context *stream,
     430             :                                             unsigned int timeout)
     431             : {
     432         456 :         struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
     433             :                                          struct tstream_smbXcli_np);
     434         456 :         unsigned int old_timeout = cli_nps->timeout;
     435             : 
     436         456 :         cli_nps->timeout = timeout;
     437         456 :         return old_timeout;
     438             : }
     439             : 
     440             : struct tstream_smbXcli_np_writev_state {
     441             :         struct tstream_context *stream;
     442             :         struct tevent_context *ev;
     443             : 
     444             :         struct iovec *vector;
     445             :         size_t count;
     446             : 
     447             :         int ret;
     448             : 
     449             :         struct {
     450             :                 int val;
     451             :                 const char *location;
     452             :         } error;
     453             : };
     454             : 
     455      346625 : static int tstream_smbXcli_np_writev_state_destructor(struct tstream_smbXcli_np_writev_state *state)
     456             : {
     457      287957 :         struct tstream_smbXcli_np *cli_nps =
     458      346625 :                 tstream_context_data(state->stream,
     459             :                 struct tstream_smbXcli_np);
     460             : 
     461      346625 :         cli_nps->trans.write_req = NULL;
     462             : 
     463      346625 :         return 0;
     464             : }
     465             : 
     466             : static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req);
     467             : 
     468      346625 : static struct tevent_req *tstream_smbXcli_np_writev_send(TALLOC_CTX *mem_ctx,
     469             :                                         struct tevent_context *ev,
     470             :                                         struct tstream_context *stream,
     471             :                                         const struct iovec *vector,
     472             :                                         size_t count)
     473             : {
     474             :         struct tevent_req *req;
     475             :         struct tstream_smbXcli_np_writev_state *state;
     476      346625 :         struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
     477             :                                          struct tstream_smbXcli_np);
     478             : 
     479      346625 :         req = tevent_req_create(mem_ctx, &state,
     480             :                                 struct tstream_smbXcli_np_writev_state);
     481      346625 :         if (!req) {
     482           0 :                 return NULL;
     483             :         }
     484      346625 :         state->stream = stream;
     485      346625 :         state->ev = ev;
     486      346625 :         state->ret = 0;
     487             : 
     488      346625 :         talloc_set_destructor(state, tstream_smbXcli_np_writev_state_destructor);
     489             : 
     490      346625 :         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
     491           0 :                 tevent_req_error(req, ENOTCONN);
     492           0 :                 return tevent_req_post(req, ev);
     493             :         }
     494             : 
     495             :         /*
     496             :          * we make a copy of the vector so we can change the structure
     497             :          */
     498      346625 :         state->vector = talloc_array(state, struct iovec, count);
     499      346625 :         if (tevent_req_nomem(state->vector, req)) {
     500           0 :                 return tevent_req_post(req, ev);
     501             :         }
     502      353301 :         memcpy(state->vector, vector, sizeof(struct iovec) * count);
     503      346625 :         state->count = count;
     504             : 
     505      346625 :         tstream_smbXcli_np_writev_write_next(req);
     506      346625 :         if (!tevent_req_is_in_progress(req)) {
     507           0 :                 return tevent_req_post(req, ev);
     508             :         }
     509             : 
     510      339949 :         return req;
     511             : }
     512             : 
     513             : static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req);
     514             : static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq);
     515             : 
     516      354774 : static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req)
     517             : {
     518      293446 :         struct tstream_smbXcli_np_writev_state *state =
     519      354774 :                 tevent_req_data(req,
     520             :                 struct tstream_smbXcli_np_writev_state);
     521      293446 :         struct tstream_smbXcli_np *cli_nps =
     522      354774 :                 tstream_context_data(state->stream,
     523             :                 struct tstream_smbXcli_np);
     524             :         struct tevent_req *subreq;
     525             :         size_t i;
     526      354774 :         size_t left = 0;
     527             : 
     528      701399 :         for (i=0; i < state->count; i++) {
     529      346625 :                 left += state->vector[i].iov_len;
     530             :         }
     531             : 
     532      354774 :         if (left == 0) {
     533        8149 :                 TALLOC_FREE(cli_nps->write.buf);
     534        8149 :                 tevent_req_done(req);
     535        8149 :                 return;
     536             :         }
     537             : 
     538      346625 :         cli_nps->write.ofs = 0;
     539      346625 :         cli_nps->write.left = MIN(left, TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
     540      346625 :         cli_nps->write.buf = talloc_realloc(cli_nps, cli_nps->write.buf,
     541             :                                             uint8_t, cli_nps->write.left);
     542      346625 :         if (tevent_req_nomem(cli_nps->write.buf, req)) {
     543           0 :                 return;
     544             :         }
     545             : 
     546             :         /*
     547             :          * copy the pending buffer first
     548             :          */
     549      974531 :         while (cli_nps->write.left > 0 && state->count > 0) {
     550      346625 :                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
     551      346625 :                 size_t len = MIN(cli_nps->write.left, state->vector[0].iov_len);
     552             : 
     553      353301 :                 memcpy(cli_nps->write.buf + cli_nps->write.ofs, base, len);
     554             : 
     555      346625 :                 base += len;
     556      346625 :                 state->vector[0].iov_base = base;
     557      346625 :                 state->vector[0].iov_len -= len;
     558             : 
     559      346625 :                 cli_nps->write.ofs += len;
     560      346625 :                 cli_nps->write.left -= len;
     561             : 
     562      346625 :                 if (state->vector[0].iov_len == 0) {
     563      346625 :                         state->vector += 1;
     564      346625 :                         state->count -= 1;
     565             :                 }
     566             : 
     567      346625 :                 state->ret += len;
     568             :         }
     569             : 
     570      346625 :         if (cli_nps->trans.active && state->count == 0) {
     571      111932 :                 cli_nps->trans.active = false;
     572      111932 :                 cli_nps->trans.write_req = req;
     573      111932 :                 return;
     574             :         }
     575             : 
     576      234693 :         if (cli_nps->trans.read_req && state->count == 0) {
     577      226544 :                 cli_nps->trans.write_req = req;
     578      226544 :                 tstream_smbXcli_np_readv_trans_start(cli_nps->trans.read_req);
     579      226544 :                 return;
     580             :         }
     581             : 
     582        8149 :         if (cli_nps->is_smb1) {
     583          20 :                 subreq = smb1cli_writex_send(state, state->ev,
     584             :                                              cli_nps->conn,
     585             :                                              cli_nps->timeout,
     586           8 :                                              cli_nps->pid,
     587             :                                              cli_nps->tcon,
     588             :                                              cli_nps->session,
     589           8 :                                              cli_nps->fnum,
     590             :                                              8, /* 8 means message mode. */
     591           8 :                                              cli_nps->write.buf,
     592             :                                              0, /* offset */
     593           8 :                                              cli_nps->write.ofs); /* size */
     594             :         } else {
     595       13624 :                 subreq = smb2cli_write_send(state, state->ev,
     596             :                                             cli_nps->conn,
     597             :                                             cli_nps->timeout,
     598             :                                             cli_nps->session,
     599             :                                             cli_nps->tcon,
     600        8141 :                                             cli_nps->write.ofs, /* length */
     601             :                                             0, /* offset */
     602             :                                             cli_nps->fid_persistent,
     603             :                                             cli_nps->fid_volatile,
     604             :                                             0, /* remaining_bytes */
     605             :                                             0, /* flags */
     606        8141 :                                             cli_nps->write.buf);
     607             :         }
     608        8149 :         if (tevent_req_nomem(subreq, req)) {
     609           0 :                 return;
     610             :         }
     611        8149 :         tevent_req_set_callback(subreq,
     612             :                                 tstream_smbXcli_np_writev_write_done,
     613             :                                 req);
     614             : }
     615             : 
     616             : static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req,
     617             :                                                  int error,
     618             :                                                  const char *location);
     619             : 
     620        8149 : static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq)
     621             : {
     622        5489 :         struct tevent_req *req =
     623        8149 :                 tevent_req_callback_data(subreq, struct tevent_req);
     624        5489 :         struct tstream_smbXcli_np_writev_state *state =
     625        8149 :                 tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
     626        5489 :         struct tstream_smbXcli_np *cli_nps =
     627        8149 :                 tstream_context_data(state->stream,
     628             :                 struct tstream_smbXcli_np);
     629             :         uint32_t written;
     630             :         NTSTATUS status;
     631             : 
     632        8149 :         if (cli_nps->is_smb1) {
     633           8 :                 status = smb1cli_writex_recv(subreq, &written, NULL);
     634             :         } else {
     635        8141 :                 status = smb2cli_write_recv(subreq, &written);
     636             :         }
     637        8149 :         TALLOC_FREE(subreq);
     638        8149 :         if (!NT_STATUS_IS_OK(status)) {
     639           0 :                 tstream_smbXcli_np_writev_disconnect_now(req, EPIPE, __location__);
     640           0 :                 return;
     641             :         }
     642             : 
     643        8149 :         if (written != cli_nps->write.ofs) {
     644           0 :                 tstream_smbXcli_np_writev_disconnect_now(req, EIO, __location__);
     645           0 :                 return;
     646             :         }
     647             : 
     648        8149 :         tstream_smbXcli_np_writev_write_next(req);
     649             : }
     650             : 
     651             : static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq);
     652             : 
     653           0 : static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req,
     654             :                                                  int error,
     655             :                                                  const char *location)
     656             : {
     657           0 :         struct tstream_smbXcli_np_writev_state *state =
     658           0 :                 tevent_req_data(req,
     659             :                 struct tstream_smbXcli_np_writev_state);
     660           0 :         struct tstream_smbXcli_np *cli_nps =
     661           0 :                 tstream_context_data(state->stream,
     662             :                 struct tstream_smbXcli_np);
     663             :         struct tevent_req *subreq;
     664             : 
     665           0 :         state->error.val = error;
     666           0 :         state->error.location = location;
     667             : 
     668           0 :         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
     669             :                 /* return the original error */
     670           0 :                 _tevent_req_error(req, state->error.val, state->error.location);
     671           0 :                 return;
     672             :         }
     673             : 
     674           0 :         subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
     675             :                                                     state->stream);
     676           0 :         if (subreq == NULL) {
     677             :                 /* return the original error */
     678           0 :                 _tevent_req_error(req, state->error.val, state->error.location);
     679           0 :                 return;
     680             :         }
     681           0 :         tevent_req_set_callback(subreq,
     682             :                                 tstream_smbXcli_np_writev_disconnect_done,
     683             :                                 req);
     684             : }
     685             : 
     686           0 : static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq)
     687             : {
     688           0 :         struct tevent_req *req =
     689           0 :                 tevent_req_callback_data(subreq, struct tevent_req);
     690           0 :         struct tstream_smbXcli_np_writev_state *state =
     691           0 :                 tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
     692             :         int error;
     693             : 
     694           0 :         tstream_smbXcli_np_disconnect_recv(subreq, &error);
     695           0 :         TALLOC_FREE(subreq);
     696             : 
     697             :         /* return the original error */
     698           0 :         _tevent_req_error(req, state->error.val, state->error.location);
     699           0 : }
     700             : 
     701      346625 : static int tstream_smbXcli_np_writev_recv(struct tevent_req *req,
     702             :                                       int *perrno)
     703             : {
     704      287957 :         struct tstream_smbXcli_np_writev_state *state =
     705      346625 :                 tevent_req_data(req,
     706             :                 struct tstream_smbXcli_np_writev_state);
     707             :         int ret;
     708             : 
     709      346625 :         ret = tsocket_simple_int_recv(req, perrno);
     710      346625 :         if (ret == 0) {
     711      346594 :                 ret = state->ret;
     712             :         }
     713             : 
     714      346625 :         tevent_req_received(req);
     715      346625 :         return ret;
     716             : }
     717             : 
     718             : struct tstream_smbXcli_np_readv_state {
     719             :         struct tstream_context *stream;
     720             :         struct tevent_context *ev;
     721             : 
     722             :         struct iovec *vector;
     723             :         size_t count;
     724             : 
     725             :         int ret;
     726             : 
     727             :         struct {
     728             :                 struct tevent_immediate *im;
     729             :         } trans;
     730             : 
     731             :         struct {
     732             :                 int val;
     733             :                 const char *location;
     734             :         } error;
     735             : };
     736             : 
     737      693513 : static int tstream_smbXcli_np_readv_state_destructor(struct tstream_smbXcli_np_readv_state *state)
     738             : {
     739      576222 :         struct tstream_smbXcli_np *cli_nps =
     740      693513 :                 tstream_context_data(state->stream,
     741             :                 struct tstream_smbXcli_np);
     742             : 
     743      693513 :         cli_nps->trans.read_req = NULL;
     744             : 
     745      693513 :         return 0;
     746             : }
     747             : 
     748             : static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req);
     749             : 
     750      693513 : static struct tevent_req *tstream_smbXcli_np_readv_send(TALLOC_CTX *mem_ctx,
     751             :                                         struct tevent_context *ev,
     752             :                                         struct tstream_context *stream,
     753             :                                         struct iovec *vector,
     754             :                                         size_t count)
     755             : {
     756             :         struct tevent_req *req;
     757             :         struct tstream_smbXcli_np_readv_state *state;
     758      576222 :         struct tstream_smbXcli_np *cli_nps =
     759      693513 :                 tstream_context_data(stream, struct tstream_smbXcli_np);
     760             : 
     761      693513 :         req = tevent_req_create(mem_ctx, &state,
     762             :                                 struct tstream_smbXcli_np_readv_state);
     763      693513 :         if (!req) {
     764           0 :                 return NULL;
     765             :         }
     766      693513 :         state->stream = stream;
     767      693513 :         state->ev = ev;
     768      693513 :         state->ret = 0;
     769             : 
     770      693513 :         talloc_set_destructor(state, tstream_smbXcli_np_readv_state_destructor);
     771             : 
     772      693513 :         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
     773           0 :                 tevent_req_error(req, ENOTCONN);
     774           0 :                 return tevent_req_post(req, ev);
     775             :         }
     776             : 
     777             :         /*
     778             :          * we make a copy of the vector so we can change the structure
     779             :          */
     780      693513 :         state->vector = talloc_array(state, struct iovec, count);
     781      693513 :         if (tevent_req_nomem(state->vector, req)) {
     782           0 :                 return tevent_req_post(req, ev);
     783             :         }
     784      706862 :         memcpy(state->vector, vector, sizeof(struct iovec) * count);
     785      693513 :         state->count = count;
     786             : 
     787      693513 :         tstream_smbXcli_np_readv_read_next(req);
     788      693513 :         if (!tevent_req_is_in_progress(req)) {
     789      346741 :                 return tevent_req_post(req, ev);
     790             :         }
     791             : 
     792      340096 :         return req;
     793             : }
     794             : 
     795             : static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq);
     796             : 
     797     1040254 : static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req)
     798             : {
     799      864321 :         struct tstream_smbXcli_np_readv_state *state =
     800     1040254 :                 tevent_req_data(req,
     801             :                 struct tstream_smbXcli_np_readv_state);
     802      864321 :         struct tstream_smbXcli_np *cli_nps =
     803     1040254 :                 tstream_context_data(state->stream,
     804             :                 struct tstream_smbXcli_np);
     805             :         struct tevent_req *subreq;
     806             : 
     807             :         /*
     808             :          * copy the pending buffer first
     809             :          */
     810     2598057 :         while (cli_nps->read.left > 0 && state->count > 0) {
     811      693482 :                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
     812      693482 :                 size_t len = MIN(cli_nps->read.left, state->vector[0].iov_len);
     813             : 
     814      706828 :                 memcpy(base, cli_nps->read.buf + cli_nps->read.ofs, len);
     815             : 
     816      693482 :                 base += len;
     817      693482 :                 state->vector[0].iov_base = base;
     818      693482 :                 state->vector[0].iov_len -= len;
     819             : 
     820      693482 :                 cli_nps->read.ofs += len;
     821      693482 :                 cli_nps->read.left -= len;
     822             : 
     823      693482 :                 if (state->vector[0].iov_len == 0) {
     824      693482 :                         state->vector += 1;
     825      693482 :                         state->count -= 1;
     826             :                 }
     827             : 
     828      693482 :                 state->ret += len;
     829             :         }
     830             : 
     831     1040254 :         if (cli_nps->read.left == 0) {
     832      693513 :                 TALLOC_FREE(cli_nps->read.buf);
     833             :         }
     834             : 
     835     1040254 :         if (state->count == 0) {
     836      693482 :                 tevent_req_done(req);
     837      693482 :                 return;
     838             :         }
     839             : 
     840      346772 :         if (cli_nps->trans.active) {
     841      226544 :                 cli_nps->trans.active = false;
     842      226544 :                 cli_nps->trans.read_req = req;
     843      226544 :                 return;
     844             :         }
     845             : 
     846      120228 :         if (cli_nps->trans.write_req) {
     847      111932 :                 cli_nps->trans.read_req = req;
     848      111932 :                 tstream_smbXcli_np_readv_trans_start(req);
     849      111932 :                 return;
     850             :         }
     851             : 
     852        8296 :         if (cli_nps->is_smb1) {
     853          56 :                 subreq = smb1cli_readx_send(state, state->ev,
     854             :                                             cli_nps->conn,
     855             :                                             cli_nps->timeout,
     856          28 :                                             cli_nps->pid,
     857             :                                             cli_nps->tcon,
     858             :                                             cli_nps->session,
     859          28 :                                             cli_nps->fnum,
     860             :                                             0, /* offset */
     861             :                                             TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
     862             :         } else {
     863        8268 :                 subreq = smb2cli_read_send(state, state->ev,
     864             :                                            cli_nps->conn,
     865             :                                            cli_nps->timeout,
     866             :                                            cli_nps->session,
     867             :                                            cli_nps->tcon,
     868             :                                            TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE, /* length */
     869             :                                            0, /* offset */
     870             :                                            cli_nps->fid_persistent,
     871             :                                            cli_nps->fid_volatile,
     872             :                                            0, /* minimum_count */
     873             :                                            0); /* remaining_bytes */
     874             :         }
     875        8296 :         if (tevent_req_nomem(subreq, req)) {
     876           0 :                 return;
     877             :         }
     878        8296 :         tevent_req_set_callback(subreq,
     879             :                                 tstream_smbXcli_np_readv_read_done,
     880             :                                 req);
     881             : }
     882             : 
     883             : static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq);
     884             : 
     885      338476 : static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req)
     886             : {
     887      282468 :         struct tstream_smbXcli_np_readv_state *state =
     888      338476 :                 tevent_req_data(req,
     889             :                 struct tstream_smbXcli_np_readv_state);
     890      282468 :         struct tstream_smbXcli_np *cli_nps =
     891      338476 :                 tstream_context_data(state->stream,
     892             :                 struct tstream_smbXcli_np);
     893             :         struct tevent_req *subreq;
     894             : 
     895      338476 :         state->trans.im = tevent_create_immediate(state);
     896      338476 :         if (tevent_req_nomem(state->trans.im, req)) {
     897           0 :                 return;
     898             :         }
     899             : 
     900      338476 :         if (cli_nps->is_smb1) {
     901        3934 :                 subreq = smb1cli_trans_send(state, state->ev,
     902             :                                             cli_nps->conn, SMBtrans,
     903             :                                             0, 0, /* *_flags */
     904             :                                             0, 0, /* *_flags2 */
     905             :                                             cli_nps->timeout,
     906        1456 :                                             cli_nps->pid,
     907             :                                             cli_nps->tcon,
     908             :                                             cli_nps->session,
     909             :                                             "\\PIPE\\",
     910             :                                             0, 0, 0,
     911        1456 :                                             cli_nps->trans.setup, 2,
     912             :                                             0,
     913             :                                             NULL, 0, 0,
     914             :                                             cli_nps->write.buf,
     915        1456 :                                             cli_nps->write.ofs,
     916             :                                             TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
     917             :         } else {
     918      337020 :                 DATA_BLOB in_input_buffer = data_blob_null;
     919      337020 :                 DATA_BLOB in_output_buffer = data_blob_null;
     920             : 
     921      337020 :                 in_input_buffer = data_blob_const(cli_nps->write.buf,
     922      337020 :                                                   cli_nps->write.ofs);
     923             : 
     924      337020 :                 subreq = smb2cli_ioctl_send(state, state->ev,
     925             :                                             cli_nps->conn,
     926             :                                             cli_nps->timeout,
     927             :                                             cli_nps->session,
     928             :                                             cli_nps->tcon,
     929             :                                             cli_nps->fid_persistent,
     930             :                                             cli_nps->fid_volatile,
     931             :                                             FSCTL_NAMED_PIPE_READ_WRITE,
     932             :                                             0, /* in_max_input_length */
     933             :                                             &in_input_buffer,
     934             :                                             /* in_max_output_length */
     935             :                                             TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE,
     936             :                                             &in_output_buffer,
     937             :                                             SMB2_IOCTL_FLAG_IS_FSCTL);
     938             :         }
     939      338476 :         if (tevent_req_nomem(subreq, req)) {
     940           0 :                 return;
     941             :         }
     942      338476 :         tevent_req_set_callback(subreq,
     943             :                                 tstream_smbXcli_np_readv_trans_done,
     944             :                                 req);
     945             : }
     946             : 
     947             : static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
     948             :                                                 int error,
     949             :                                                 const char *location);
     950             : static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
     951             :                                                 struct tevent_immediate *im,
     952             :                                                 void *private_data);
     953             : 
     954      338476 : static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq)
     955             : {
     956      282468 :         struct tevent_req *req =
     957      338476 :                 tevent_req_callback_data(subreq, struct tevent_req);
     958      282468 :         struct tstream_smbXcli_np_readv_state *state =
     959      338476 :                 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
     960      282468 :         struct tstream_smbXcli_np *cli_nps =
     961      338476 :                 tstream_context_data(state->stream, struct tstream_smbXcli_np);
     962             :         uint8_t *rcvbuf;
     963             :         uint32_t received;
     964             :         NTSTATUS status;
     965             : 
     966      338476 :         if (cli_nps->is_smb1) {
     967        1456 :                 status = smb1cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
     968             :                                             NULL, 0, NULL,
     969             :                                             &rcvbuf, 0, &received);
     970             :         } else {
     971      337020 :                 DATA_BLOB out_input_buffer = data_blob_null;
     972      337020 :                 DATA_BLOB out_output_buffer = data_blob_null;
     973             : 
     974      337020 :                 status = smb2cli_ioctl_recv(subreq, state,
     975             :                                             &out_input_buffer,
     976             :                                             &out_output_buffer);
     977             : 
     978             :                 /* Note that rcvbuf is not a talloc pointer here */
     979      337020 :                 rcvbuf = out_output_buffer.data;
     980      337020 :                 received = out_output_buffer.length;
     981             :         }
     982      338476 :         TALLOC_FREE(subreq);
     983      338476 :         if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
     984             :                 /*
     985             :                  * STATUS_BUFFER_OVERFLOW means that there's
     986             :                  * more data to read when the named pipe is used
     987             :                  * in message mode (which is the case here).
     988             :                  *
     989             :                  * But we hide this from the caller.
     990             :                  */
     991           0 :                 status = NT_STATUS_OK;
     992             :         }
     993      338476 :         if (!NT_STATUS_IS_OK(status)) {
     994          31 :                 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
     995          31 :                 return;
     996             :         }
     997             : 
     998      338445 :         if (received > TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE) {
     999           0 :                 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
    1000           0 :                 return;
    1001             :         }
    1002             : 
    1003      338445 :         if (received == 0) {
    1004           0 :                 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
    1005           0 :                 return;
    1006             :         }
    1007             : 
    1008      338445 :         cli_nps->read.ofs = 0;
    1009      338445 :         cli_nps->read.left = received;
    1010      338445 :         cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
    1011      338445 :         if (cli_nps->read.buf == NULL) {
    1012           0 :                 TALLOC_FREE(subreq);
    1013           0 :                 tevent_req_oom(req);
    1014           0 :                 return;
    1015             :         }
    1016      345071 :         memcpy(cli_nps->read.buf, rcvbuf, received);
    1017             : 
    1018      338445 :         if (cli_nps->trans.write_req == NULL) {
    1019           0 :                 tstream_smbXcli_np_readv_read_next(req);
    1020           0 :                 return;
    1021             :         }
    1022             : 
    1023      338445 :         tevent_schedule_immediate(state->trans.im, state->ev,
    1024             :                                   tstream_smbXcli_np_readv_trans_next, req);
    1025             : 
    1026      338445 :         tevent_req_done(cli_nps->trans.write_req);
    1027             : }
    1028             : 
    1029      338445 : static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
    1030             :                                             struct tevent_immediate *im,
    1031             :                                             void *private_data)
    1032             : {
    1033      282444 :         struct tevent_req *req =
    1034       56001 :                 talloc_get_type_abort(private_data,
    1035             :                 struct tevent_req);
    1036             : 
    1037      338445 :         tstream_smbXcli_np_readv_read_next(req);
    1038      338445 : }
    1039             : 
    1040        8296 : static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq)
    1041             : {
    1042        5655 :         struct tevent_req *req =
    1043        8296 :                 tevent_req_callback_data(subreq, struct tevent_req);
    1044        5655 :         struct tstream_smbXcli_np_readv_state *state =
    1045        8296 :                 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
    1046        5655 :         struct tstream_smbXcli_np *cli_nps =
    1047        8296 :                 tstream_context_data(state->stream, struct tstream_smbXcli_np);
    1048             :         uint8_t *rcvbuf;
    1049             :         uint32_t received;
    1050             :         NTSTATUS status;
    1051             : 
    1052             :         /*
    1053             :          * We must free subreq in this function as there is
    1054             :          * a timer event attached to it.
    1055             :          */
    1056             : 
    1057        8296 :         if (cli_nps->is_smb1) {
    1058          28 :                 status = smb1cli_readx_recv(subreq, &received, &rcvbuf);
    1059             :         } else {
    1060        8268 :                 status = smb2cli_read_recv(subreq, state, &rcvbuf, &received);
    1061             :         }
    1062             :         /*
    1063             :          * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
    1064             :          * child of that.
    1065             :          */
    1066        8296 :         if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
    1067             :                 /*
    1068             :                  * STATUS_BUFFER_OVERFLOW means that there's
    1069             :                  * more data to read when the named pipe is used
    1070             :                  * in message mode (which is the case here).
    1071             :                  *
    1072             :                  * But we hide this from the caller.
    1073             :                  */
    1074           0 :                 status = NT_STATUS_OK;
    1075             :         }
    1076        8296 :         if (!NT_STATUS_IS_OK(status)) {
    1077           0 :                 TALLOC_FREE(subreq);
    1078           0 :                 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
    1079           0 :                 return;
    1080             :         }
    1081             : 
    1082        8296 :         if (received > TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE) {
    1083           0 :                 TALLOC_FREE(subreq);
    1084           0 :                 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
    1085           0 :                 return;
    1086             :         }
    1087             : 
    1088        8296 :         if (received == 0) {
    1089           0 :                 TALLOC_FREE(subreq);
    1090           0 :                 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
    1091           0 :                 return;
    1092             :         }
    1093             : 
    1094        8296 :         cli_nps->read.ofs = 0;
    1095        8296 :         cli_nps->read.left = received;
    1096        8296 :         cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
    1097        8296 :         if (cli_nps->read.buf == NULL) {
    1098           0 :                 TALLOC_FREE(subreq);
    1099           0 :                 tevent_req_oom(req);
    1100           0 :                 return;
    1101             :         }
    1102        8343 :         memcpy(cli_nps->read.buf, rcvbuf, received);
    1103        8296 :         TALLOC_FREE(subreq);
    1104             : 
    1105        8296 :         tstream_smbXcli_np_readv_read_next(req);
    1106             : }
    1107             : 
    1108             : static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq);
    1109             : 
    1110             : static void tstream_smbXcli_np_readv_error(struct tevent_req *req);
    1111             : 
    1112          31 : static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
    1113             :                                                 int error,
    1114             :                                                 const char *location)
    1115             : {
    1116          24 :         struct tstream_smbXcli_np_readv_state *state =
    1117          31 :                 tevent_req_data(req,
    1118             :                 struct tstream_smbXcli_np_readv_state);
    1119          24 :         struct tstream_smbXcli_np *cli_nps =
    1120          31 :                 tstream_context_data(state->stream,
    1121             :                 struct tstream_smbXcli_np);
    1122             :         struct tevent_req *subreq;
    1123             : 
    1124          31 :         state->error.val = error;
    1125          31 :         state->error.location = location;
    1126             : 
    1127          31 :         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
    1128             :                 /* return the original error */
    1129           0 :                 tstream_smbXcli_np_readv_error(req);
    1130           0 :                 return;
    1131             :         }
    1132             : 
    1133          31 :         subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
    1134             :                                                     state->stream);
    1135          31 :         if (subreq == NULL) {
    1136             :                 /* return the original error */
    1137           0 :                 tstream_smbXcli_np_readv_error(req);
    1138           0 :                 return;
    1139             :         }
    1140          31 :         tevent_req_set_callback(subreq,
    1141             :                                 tstream_smbXcli_np_readv_disconnect_done,
    1142             :                                 req);
    1143             : }
    1144             : 
    1145          31 : static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq)
    1146             : {
    1147          24 :         struct tevent_req *req =
    1148          31 :                 tevent_req_callback_data(subreq, struct tevent_req);
    1149             :         int error;
    1150             : 
    1151          31 :         tstream_smbXcli_np_disconnect_recv(subreq, &error);
    1152          31 :         TALLOC_FREE(subreq);
    1153             : 
    1154          31 :         tstream_smbXcli_np_readv_error(req);
    1155          31 : }
    1156             : 
    1157             : static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context *ctx,
    1158             :                                                    struct tevent_immediate *im,
    1159             :                                                    void *private_data);
    1160             : 
    1161          31 : static void tstream_smbXcli_np_readv_error(struct tevent_req *req)
    1162             : {
    1163          24 :         struct tstream_smbXcli_np_readv_state *state =
    1164          31 :                 tevent_req_data(req,
    1165             :                 struct tstream_smbXcli_np_readv_state);
    1166          24 :         struct tstream_smbXcli_np *cli_nps =
    1167          31 :                 tstream_context_data(state->stream,
    1168             :                 struct tstream_smbXcli_np);
    1169             : 
    1170          31 :         if (cli_nps->trans.write_req == NULL) {
    1171             :                 /* return the original error */
    1172           0 :                 _tevent_req_error(req, state->error.val, state->error.location);
    1173           0 :                 return;
    1174             :         }
    1175             : 
    1176          31 :         if (state->trans.im == NULL) {
    1177             :                 /* return the original error */
    1178           0 :                 _tevent_req_error(req, state->error.val, state->error.location);
    1179           0 :                 return;
    1180             :         }
    1181             : 
    1182          31 :         tevent_schedule_immediate(state->trans.im, state->ev,
    1183             :                                   tstream_smbXcli_np_readv_error_trigger, req);
    1184             : 
    1185             :         /* return the original error for writev */
    1186          55 :         _tevent_req_error(cli_nps->trans.write_req,
    1187          31 :                           state->error.val, state->error.location);
    1188             : }
    1189             : 
    1190           0 : static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context *ctx,
    1191             :                                                    struct tevent_immediate *im,
    1192             :                                                    void *private_data)
    1193             : {
    1194           0 :         struct tevent_req *req =
    1195           0 :                 talloc_get_type_abort(private_data,
    1196             :                 struct tevent_req);
    1197           0 :         struct tstream_smbXcli_np_readv_state *state =
    1198           0 :                 tevent_req_data(req,
    1199             :                 struct tstream_smbXcli_np_readv_state);
    1200             : 
    1201             :         /* return the original error */
    1202           0 :         _tevent_req_error(req, state->error.val, state->error.location);
    1203           0 : }
    1204             : 
    1205      693482 : static int tstream_smbXcli_np_readv_recv(struct tevent_req *req,
    1206             :                                          int *perrno)
    1207             : {
    1208      576198 :         struct tstream_smbXcli_np_readv_state *state =
    1209      693482 :                 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
    1210             :         int ret;
    1211             : 
    1212      693482 :         ret = tsocket_simple_int_recv(req, perrno);
    1213      693482 :         if (ret == 0) {
    1214      693482 :                 ret = state->ret;
    1215             :         }
    1216             : 
    1217      693482 :         tevent_req_received(req);
    1218      693482 :         return ret;
    1219             : }
    1220             : 
    1221             : struct tstream_smbXcli_np_disconnect_state {
    1222             :         struct tstream_context *stream;
    1223             :         struct tevent_req *subreq;
    1224             : };
    1225             : 
    1226             : static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq);
    1227             : static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req,
    1228             :                                         enum tevent_req_state req_state);
    1229             : 
    1230        7665 : static struct tevent_req *tstream_smbXcli_np_disconnect_send(TALLOC_CTX *mem_ctx,
    1231             :                                                 struct tevent_context *ev,
    1232             :                                                 struct tstream_context *stream)
    1233             : {
    1234        7665 :         struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
    1235             :                                          struct tstream_smbXcli_np);
    1236             :         struct tevent_req *req;
    1237             :         struct tstream_smbXcli_np_disconnect_state *state;
    1238             :         struct tevent_req *subreq;
    1239             : 
    1240        7665 :         req = tevent_req_create(mem_ctx, &state,
    1241             :                                 struct tstream_smbXcli_np_disconnect_state);
    1242        7665 :         if (req == NULL) {
    1243           0 :                 return NULL;
    1244             :         }
    1245             : 
    1246        7665 :         state->stream = stream;
    1247             : 
    1248        7665 :         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
    1249         487 :                 tevent_req_error(req, ENOTCONN);
    1250         487 :                 return tevent_req_post(req, ev);
    1251             :         }
    1252             : 
    1253        7178 :         if (cli_nps->is_smb1) {
    1254         342 :                 subreq = smb1cli_close_send(state, ev, cli_nps->conn,
    1255             :                                             cli_nps->timeout,
    1256         189 :                                             cli_nps->pid,
    1257             :                                             cli_nps->tcon,
    1258             :                                             cli_nps->session,
    1259         189 :                                             cli_nps->fnum, UINT32_MAX);
    1260             :         } else {
    1261        6989 :                 subreq = smb2cli_close_send(state, ev, cli_nps->conn,
    1262             :                                             cli_nps->timeout,
    1263             :                                             cli_nps->session,
    1264             :                                             cli_nps->tcon,
    1265             :                                             0, /* flags */
    1266             :                                             cli_nps->fid_persistent,
    1267             :                                             cli_nps->fid_volatile);
    1268             :         }
    1269        7178 :         if (tevent_req_nomem(subreq, req)) {
    1270           0 :                 return tevent_req_post(req, ev);
    1271             :         }
    1272        7178 :         tevent_req_set_callback(subreq, tstream_smbXcli_np_disconnect_done, req);
    1273        7178 :         state->subreq = subreq;
    1274             : 
    1275        7178 :         tevent_req_set_cleanup_fn(req, tstream_smbXcli_np_disconnect_cleanup);
    1276             : 
    1277             :         /*
    1278             :          * Make sure we don't send any requests anymore.
    1279             :          */
    1280        7178 :         cli_nps->conn = NULL;
    1281             : 
    1282        7178 :         return req;
    1283             : }
    1284             : 
    1285          37 : static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq)
    1286             : {
    1287          37 :         struct tevent_req *req = tevent_req_callback_data(subreq,
    1288             :                                                           struct tevent_req);
    1289          30 :         struct tstream_smbXcli_np_disconnect_state *state =
    1290          37 :                 tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
    1291          30 :         struct tstream_smbXcli_np *cli_nps =
    1292          37 :                 tstream_context_data(state->stream, struct tstream_smbXcli_np);
    1293             :         NTSTATUS status;
    1294             : 
    1295          37 :         state->subreq = NULL;
    1296             : 
    1297          37 :         if (cli_nps->is_smb1) {
    1298          19 :                 status = smb1cli_close_recv(subreq);
    1299             :         } else {
    1300          18 :                 status = smb2cli_close_recv(subreq);
    1301             :         }
    1302          37 :         TALLOC_FREE(subreq);
    1303          37 :         if (!NT_STATUS_IS_OK(status)) {
    1304          19 :                 tevent_req_error(req, EPIPE);
    1305          19 :                 return;
    1306             :         }
    1307             : 
    1308          18 :         cli_nps->conn = NULL;
    1309          18 :         cli_nps->session = NULL;
    1310          18 :         cli_nps->tcon = NULL;
    1311             : 
    1312          18 :         tevent_req_done(req);
    1313             : }
    1314             : 
    1315             : static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq);
    1316             : 
    1317        7215 : static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req,
    1318             :                                         enum tevent_req_state req_state)
    1319             : {
    1320        5508 :         struct tstream_smbXcli_np_disconnect_state *state =
    1321        7215 :                 tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
    1322        7215 :         struct tstream_smbXcli_np *cli_nps = NULL;
    1323             : 
    1324        7215 :         if (state->subreq == NULL) {
    1325          68 :                 return;
    1326             :         }
    1327             : 
    1328        7141 :         cli_nps = tstream_context_data(state->stream, struct tstream_smbXcli_np);
    1329             : 
    1330        7141 :         if (cli_nps->tcon == NULL) {
    1331           0 :                 return;
    1332             :         }
    1333             : 
    1334             :         /*
    1335             :          * We're no longer interested in the result
    1336             :          * any more, but need to make sure that the close
    1337             :          * request arrives at the server if the smb connection,
    1338             :          * session and tcon are still alive.
    1339             :          *
    1340             :          * We move the low level request to the tcon,
    1341             :          * which means that it stays as long as the tcon
    1342             :          * is available.
    1343             :          */
    1344        7141 :         talloc_steal(cli_nps->tcon, state->subreq);
    1345        7141 :         tevent_req_set_callback(state->subreq,
    1346             :                                 tstream_smbXcli_np_disconnect_free,
    1347             :                                 NULL);
    1348        7141 :         state->subreq = NULL;
    1349             : 
    1350        7141 :         cli_nps->conn = NULL;
    1351        7141 :         cli_nps->session = NULL;
    1352        7141 :         cli_nps->tcon = NULL;
    1353             : }
    1354             : 
    1355         351 : static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq)
    1356             : {
    1357         351 :         TALLOC_FREE(subreq);
    1358         351 : }
    1359             : 
    1360          34 : static int tstream_smbXcli_np_disconnect_recv(struct tevent_req *req,
    1361             :                                               int *perrno)
    1362             : {
    1363             :         int ret;
    1364             : 
    1365          37 :         ret = tsocket_simple_int_recv(req, perrno);
    1366             : 
    1367          37 :         tevent_req_received(req);
    1368          34 :         return ret;
    1369             : }
    1370             : 
    1371             : static const struct tstream_context_ops tstream_smbXcli_np_ops = {
    1372             :         .name                   = "smbXcli_np",
    1373             : 
    1374             :         .pending_bytes          = tstream_smbXcli_np_pending_bytes,
    1375             : 
    1376             :         .readv_send             = tstream_smbXcli_np_readv_send,
    1377             :         .readv_recv             = tstream_smbXcli_np_readv_recv,
    1378             : 
    1379             :         .writev_send            = tstream_smbXcli_np_writev_send,
    1380             :         .writev_recv            = tstream_smbXcli_np_writev_recv,
    1381             : 
    1382             :         .disconnect_send        = tstream_smbXcli_np_disconnect_send,
    1383             :         .disconnect_recv        = tstream_smbXcli_np_disconnect_recv,
    1384             : };

Generated by: LCOV version 1.13