LCOV - code coverage report
Current view: top level - libcli/smb - tstream_smbXcli_np.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 440 557 79.0 %
Date: 2024-06-13 04:01:37 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        4575 : static int tstream_smbXcli_np_destructor(struct tstream_smbXcli_np *cli_nps)
      80             : {
      81             :         NTSTATUS status;
      82             : 
      83        4575 :         if (cli_nps->conn_ref != NULL) {
      84        4492 :                 cli_nps->conn_ref->cli_nps = NULL;
      85        4492 :                 TALLOC_FREE(cli_nps->conn_ref);
      86             :         }
      87             : 
      88        4575 :         if (cli_nps->session_ref != NULL) {
      89        4492 :                 cli_nps->session_ref->cli_nps = NULL;
      90        4492 :                 TALLOC_FREE(cli_nps->session_ref);
      91             :         }
      92             : 
      93        4575 :         if (cli_nps->tcon_ref != NULL) {
      94        4492 :                 cli_nps->tcon_ref->cli_nps = NULL;
      95        4492 :                 TALLOC_FREE(cli_nps->tcon_ref);
      96             :         }
      97             : 
      98        4575 :         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         754 :         cli_nps->timeout = MIN(cli_nps->timeout, 1000);
     118             : 
     119         754 :         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         754 :                 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         754 :         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         754 :         return 0;
     144             : }
     145             : 
     146       13725 : static int tstream_smbXcli_np_ref_destructor(struct tstream_smbXcli_np_ref *ref)
     147             : {
     148       13725 :         if (ref->cli_nps == NULL) {
     149       13476 :                 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        4733 : 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        4733 :         req = tevent_req_create(mem_ctx, &state,
     203             :                                 struct tstream_smbXcli_np_open_state);
     204        4733 :         if (!req) {
     205           0 :                 return NULL;
     206             :         }
     207        4733 :         state->conn = conn;
     208        4733 :         state->tcon = tcon;
     209        4733 :         state->session = session;
     210        4733 :         state->pid = pid;
     211        4733 :         state->timeout = timeout;
     212             : 
     213        4733 :         state->npipe = talloc_strdup(state, npipe);
     214        4733 :         if (tevent_req_nomem(state->npipe, req)) {
     215           0 :                 return tevent_req_post(req, ev);
     216             :         }
     217             : 
     218        4733 :         if (smbXcli_conn_protocol(conn) < PROTOCOL_SMB2_02) {
     219          11 :                 state->is_smb1 = true;
     220             :         }
     221             : 
     222        4733 :         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          41 :                 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       11596 :                 subreq = smb2cli_create_send(state, ev, state->conn,
     252        8159 :                                              state->timeout, state->session,
     253        4722 :                                              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        4733 :         if (tevent_req_nomem(subreq, req)) {
     265           0 :                 return tevent_req_post(req, ev);
     266             :         }
     267        4733 :         tevent_req_set_callback(subreq, tstream_smbXcli_np_open_done, req);
     268             : 
     269        4733 :         return req;
     270             : }
     271             : 
     272        4733 : static void tstream_smbXcli_np_open_done(struct tevent_req *subreq)
     273             : {
     274        3447 :         struct tevent_req *req =
     275        4733 :                 tevent_req_callback_data(subreq, struct tevent_req);
     276        3447 :         struct tstream_smbXcli_np_open_state *state =
     277        4733 :                 tevent_req_data(req, struct tstream_smbXcli_np_open_state);
     278             :         NTSTATUS status;
     279             : 
     280        4733 :         if (state->is_smb1) {
     281          11 :                 status = smb1cli_ntcreatex_recv(subreq, &state->fnum);
     282             :         } else {
     283        4722 :                 status = smb2cli_create_recv(subreq,
     284             :                                              &state->fid_persistent,
     285             :                                              &state->fid_volatile,
     286             :                                              NULL, NULL, NULL);
     287             :         }
     288        4733 :         TALLOC_FREE(subreq);
     289        4733 :         if (!NT_STATUS_IS_OK(status)) {
     290         158 :                 tevent_req_nterror(req, status);
     291         158 :                 return;
     292             :         }
     293             : 
     294        4575 :         tevent_req_done(req);
     295             : }
     296             : 
     297        4733 : 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        3447 :         struct tstream_smbXcli_np_open_state *state =
     303        4733 :                 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        4733 :         if (tevent_req_is_nterror(req, &status)) {
     309         158 :                 tevent_req_received(req);
     310         158 :                 return status;
     311             :         }
     312             : 
     313        4575 :         stream = tstream_context_create(mem_ctx,
     314             :                                         &tstream_smbXcli_np_ops,
     315             :                                         &cli_nps,
     316             :                                         struct tstream_smbXcli_np,
     317             :                                         location);
     318        4575 :         if (!stream) {
     319           0 :                 tevent_req_received(req);
     320           0 :                 return NT_STATUS_NO_MEMORY;
     321             :         }
     322        4575 :         ZERO_STRUCTP(cli_nps);
     323             : 
     324        4575 :         cli_nps->conn_ref = talloc_zero(state->conn,
     325             :                                         struct tstream_smbXcli_np_ref);
     326        4575 :         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        4575 :         cli_nps->conn_ref->cli_nps = cli_nps;
     332             : 
     333        4575 :         cli_nps->session_ref = talloc_zero(state->session,
     334             :                                         struct tstream_smbXcli_np_ref);
     335        4575 :         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        4575 :         cli_nps->session_ref->cli_nps = cli_nps;
     341             : 
     342        4575 :         cli_nps->tcon_ref = talloc_zero(state->tcon,
     343             :                                         struct tstream_smbXcli_np_ref);
     344        4575 :         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        4575 :         cli_nps->tcon_ref->cli_nps = cli_nps;
     350             : 
     351        4575 :         cli_nps->conn = state->conn;
     352        4575 :         cli_nps->session = state->session;
     353        4575 :         cli_nps->tcon = state->tcon;
     354        4575 :         cli_nps->pid  = state->pid;
     355        4575 :         cli_nps->timeout = state->timeout;
     356        4575 :         cli_nps->npipe = talloc_move(cli_nps, &state->npipe);
     357        4575 :         cli_nps->is_smb1 = state->is_smb1;
     358        4575 :         cli_nps->fnum = state->fnum;
     359        4575 :         cli_nps->fid_persistent = state->fid_persistent;
     360        4575 :         cli_nps->fid_volatile = state->fid_volatile;
     361             : 
     362        4575 :         talloc_set_destructor(cli_nps, tstream_smbXcli_np_destructor);
     363        4575 :         talloc_set_destructor(cli_nps->conn_ref,
     364             :                               tstream_smbXcli_np_ref_destructor);
     365        4575 :         talloc_set_destructor(cli_nps->session_ref,
     366             :                               tstream_smbXcli_np_ref_destructor);
     367        4575 :         talloc_set_destructor(cli_nps->tcon_ref,
     368             :                               tstream_smbXcli_np_ref_destructor);
     369             : 
     370        4575 :         cli_nps->trans.active = false;
     371        4575 :         cli_nps->trans.read_req = NULL;
     372        4575 :         cli_nps->trans.write_req = NULL;
     373        4575 :         SSVAL(cli_nps->trans.setup+0, 0, TRANSACT_DCERPCCMD);
     374        4575 :         SSVAL(cli_nps->trans.setup+1, 0, cli_nps->fnum);
     375             : 
     376        4575 :         *_stream = stream;
     377        4575 :         tevent_req_received(req);
     378        4575 :         return NT_STATUS_OK;
     379             : }
     380             : 
     381       13756 : static ssize_t tstream_smbXcli_np_pending_bytes(struct tstream_context *stream)
     382             : {
     383       13756 :         struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
     384             :                                          struct tstream_smbXcli_np);
     385             : 
     386       13756 :         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
     387           0 :                 errno = ENOTCONN;
     388           0 :                 return -1;
     389             :         }
     390             : 
     391       13756 :         return cli_nps->read.left;
     392             : }
     393             : 
     394      222054 : bool tstream_is_smbXcli_np(struct tstream_context *stream)
     395             : {
     396      176421 :         struct tstream_smbXcli_np *cli_nps =
     397      222054 :                 talloc_get_type(_tstream_context_data(stream),
     398             :                 struct tstream_smbXcli_np);
     399             : 
     400      222054 :         if (!cli_nps) {
     401       77216 :                 return false;
     402             :         }
     403             : 
     404      144838 :         return true;
     405             : }
     406             : 
     407      123336 : NTSTATUS tstream_smbXcli_np_use_trans(struct tstream_context *stream)
     408             : {
     409      123336 :         struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
     410             :                                          struct tstream_smbXcli_np);
     411             : 
     412      123336 :         if (cli_nps->trans.read_req) {
     413           0 :                 return NT_STATUS_PIPE_BUSY;
     414             :         }
     415             : 
     416      123336 :         if (cli_nps->trans.write_req) {
     417           0 :                 return NT_STATUS_PIPE_BUSY;
     418             :         }
     419             : 
     420      123336 :         if (cli_nps->trans.active) {
     421           0 :                 return NT_STATUS_PIPE_BUSY;
     422             :         }
     423             : 
     424      123336 :         cli_nps->trans.active = true;
     425             : 
     426      123336 :         return NT_STATUS_OK;
     427             : }
     428             : 
     429         204 : unsigned int tstream_smbXcli_np_set_timeout(struct tstream_context *stream,
     430             :                                             unsigned int timeout)
     431             : {
     432         204 :         struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
     433             :                                          struct tstream_smbXcli_np);
     434         204 :         unsigned int old_timeout = cli_nps->timeout;
     435             : 
     436         204 :         cli_nps->timeout = timeout;
     437         204 :         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      130135 : static int tstream_smbXcli_np_writev_state_destructor(struct tstream_smbXcli_np_writev_state *state)
     456             : {
     457      100008 :         struct tstream_smbXcli_np *cli_nps =
     458      130135 :                 tstream_context_data(state->stream,
     459             :                 struct tstream_smbXcli_np);
     460             : 
     461      130135 :         cli_nps->trans.write_req = NULL;
     462             : 
     463      130135 :         return 0;
     464             : }
     465             : 
     466             : static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req);
     467             : 
     468      130135 : 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      130135 :         struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
     477             :                                          struct tstream_smbXcli_np);
     478             : 
     479      130135 :         req = tevent_req_create(mem_ctx, &state,
     480             :                                 struct tstream_smbXcli_np_writev_state);
     481      130135 :         if (!req) {
     482           0 :                 return NULL;
     483             :         }
     484      130135 :         state->stream = stream;
     485      130135 :         state->ev = ev;
     486      130135 :         state->ret = 0;
     487             : 
     488      130135 :         talloc_set_destructor(state, tstream_smbXcli_np_writev_state_destructor);
     489             : 
     490      130135 :         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      130135 :         state->vector = talloc_array(state, struct iovec, count);
     499      130135 :         if (tevent_req_nomem(state->vector, req)) {
     500           0 :                 return tevent_req_post(req, ev);
     501             :         }
     502      130135 :         memcpy(state->vector, vector, sizeof(struct iovec) * count);
     503      130135 :         state->count = count;
     504             : 
     505      130135 :         tstream_smbXcli_np_writev_write_next(req);
     506      130135 :         if (!tevent_req_is_in_progress(req)) {
     507           0 :                 return tevent_req_post(req, ev);
     508             :         }
     509             : 
     510      130135 :         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      136934 : static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req)
     517             : {
     518      104538 :         struct tstream_smbXcli_np_writev_state *state =
     519      136934 :                 tevent_req_data(req,
     520             :                 struct tstream_smbXcli_np_writev_state);
     521      104538 :         struct tstream_smbXcli_np *cli_nps =
     522      136934 :                 tstream_context_data(state->stream,
     523             :                 struct tstream_smbXcli_np);
     524             :         struct tevent_req *subreq;
     525             :         size_t i;
     526      136934 :         size_t left = 0;
     527             : 
     528      267069 :         for (i=0; i < state->count; i++) {
     529      130135 :                 left += state->vector[i].iov_len;
     530             :         }
     531             : 
     532      136934 :         if (left == 0) {
     533        6799 :                 TALLOC_FREE(cli_nps->write.buf);
     534        6799 :                 tevent_req_done(req);
     535        6799 :                 return;
     536             :         }
     537             : 
     538      130135 :         cli_nps->write.ofs = 0;
     539      130135 :         cli_nps->write.left = MIN(left, TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
     540      130135 :         cli_nps->write.buf = talloc_realloc(cli_nps, cli_nps->write.buf,
     541             :                                             uint8_t, cli_nps->write.left);
     542      130135 :         if (tevent_req_nomem(cli_nps->write.buf, req)) {
     543           0 :                 return;
     544             :         }
     545             : 
     546             :         /*
     547             :          * copy the pending buffer first
     548             :          */
     549      360278 :         while (cli_nps->write.left > 0 && state->count > 0) {
     550      130135 :                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
     551      130135 :                 size_t len = MIN(cli_nps->write.left, state->vector[0].iov_len);
     552             : 
     553      130135 :                 memcpy(cli_nps->write.buf + cli_nps->write.ofs, base, len);
     554             : 
     555      130135 :                 base += len;
     556      130135 :                 state->vector[0].iov_base = base;
     557      130135 :                 state->vector[0].iov_len -= len;
     558             : 
     559      130135 :                 cli_nps->write.ofs += len;
     560      130135 :                 cli_nps->write.left -= len;
     561             : 
     562      130135 :                 if (state->vector[0].iov_len == 0) {
     563      130135 :                         state->vector += 1;
     564      130135 :                         state->count -= 1;
     565             :                 }
     566             : 
     567      130135 :                 state->ret += len;
     568             :         }
     569             : 
     570      130135 :         if (cli_nps->trans.active && state->count == 0) {
     571        4680 :                 cli_nps->trans.active = false;
     572        4680 :                 cli_nps->trans.write_req = req;
     573        4680 :                 return;
     574             :         }
     575             : 
     576      125455 :         if (cli_nps->trans.read_req && state->count == 0) {
     577      118656 :                 cli_nps->trans.write_req = req;
     578      118656 :                 tstream_smbXcli_np_readv_trans_start(cli_nps->trans.read_req);
     579      118656 :                 return;
     580             :         }
     581             : 
     582        6799 :         if (cli_nps->is_smb1) {
     583           0 :                 subreq = smb1cli_writex_send(state, state->ev,
     584             :                                              cli_nps->conn,
     585             :                                              cli_nps->timeout,
     586           0 :                                              cli_nps->pid,
     587             :                                              cli_nps->tcon,
     588             :                                              cli_nps->session,
     589           0 :                                              cli_nps->fnum,
     590             :                                              8, /* 8 means message mode. */
     591           0 :                                              cli_nps->write.buf,
     592             :                                              0, /* offset */
     593           0 :                                              cli_nps->write.ofs); /* size */
     594             :         } else {
     595       11329 :                 subreq = smb2cli_write_send(state, state->ev,
     596             :                                             cli_nps->conn,
     597             :                                             cli_nps->timeout,
     598             :                                             cli_nps->session,
     599             :                                             cli_nps->tcon,
     600        6799 :                                             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        6799 :                                             cli_nps->write.buf);
     607             :         }
     608        6799 :         if (tevent_req_nomem(subreq, req)) {
     609           0 :                 return;
     610             :         }
     611        6799 :         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        6799 : static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq)
     621             : {
     622        4530 :         struct tevent_req *req =
     623        6799 :                 tevent_req_callback_data(subreq, struct tevent_req);
     624        4530 :         struct tstream_smbXcli_np_writev_state *state =
     625        6799 :                 tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
     626        4530 :         struct tstream_smbXcli_np *cli_nps =
     627        6799 :                 tstream_context_data(state->stream,
     628             :                 struct tstream_smbXcli_np);
     629             :         uint32_t written;
     630             :         NTSTATUS status;
     631             : 
     632        6799 :         if (cli_nps->is_smb1) {
     633           0 :                 status = smb1cli_writex_recv(subreq, &written, NULL);
     634             :         } else {
     635        6799 :                 status = smb2cli_write_recv(subreq, &written);
     636             :         }
     637        6799 :         TALLOC_FREE(subreq);
     638        6799 :         if (!NT_STATUS_IS_OK(status)) {
     639           0 :                 tstream_smbXcli_np_writev_disconnect_now(req, EPIPE, __location__);
     640           0 :                 return;
     641             :         }
     642             : 
     643        6799 :         if (written != cli_nps->write.ofs) {
     644           0 :                 tstream_smbXcli_np_writev_disconnect_now(req, EIO, __location__);
     645           0 :                 return;
     646             :         }
     647             : 
     648        6799 :         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      130135 : static int tstream_smbXcli_np_writev_recv(struct tevent_req *req,
     702             :                                       int *perrno)
     703             : {
     704      100008 :         struct tstream_smbXcli_np_writev_state *state =
     705      130135 :                 tevent_req_data(req,
     706             :                 struct tstream_smbXcli_np_writev_state);
     707             :         int ret;
     708             : 
     709      130135 :         ret = tsocket_simple_int_recv(req, perrno);
     710      130135 :         if (ret == 0) {
     711      130123 :                 ret = state->ret;
     712             :         }
     713             : 
     714      130135 :         tevent_req_received(req);
     715      130135 :         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      260308 : static int tstream_smbXcli_np_readv_state_destructor(struct tstream_smbXcli_np_readv_state *state)
     738             : {
     739      200000 :         struct tstream_smbXcli_np *cli_nps =
     740      260308 :                 tstream_context_data(state->stream,
     741             :                 struct tstream_smbXcli_np);
     742             : 
     743      260308 :         cli_nps->trans.read_req = NULL;
     744             : 
     745      260308 :         return 0;
     746             : }
     747             : 
     748             : static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req);
     749             : 
     750      260308 : 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      200000 :         struct tstream_smbXcli_np *cli_nps =
     759      260308 :                 tstream_context_data(stream, struct tstream_smbXcli_np);
     760             : 
     761      260308 :         req = tevent_req_create(mem_ctx, &state,
     762             :                                 struct tstream_smbXcli_np_readv_state);
     763      260308 :         if (!req) {
     764           0 :                 return NULL;
     765             :         }
     766      260308 :         state->stream = stream;
     767      260308 :         state->ev = ev;
     768      260308 :         state->ret = 0;
     769             : 
     770      260308 :         talloc_set_destructor(state, tstream_smbXcli_np_readv_state_destructor);
     771             : 
     772      260308 :         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      260308 :         state->vector = talloc_array(state, struct iovec, count);
     781      260308 :         if (tevent_req_nomem(state->vector, req)) {
     782           0 :                 return tevent_req_post(req, ev);
     783             :         }
     784      260308 :         memcpy(state->vector, vector, sizeof(struct iovec) * count);
     785      260308 :         state->count = count;
     786             : 
     787      260308 :         tstream_smbXcli_np_readv_read_next(req);
     788      260308 :         if (!tevent_req_is_in_progress(req)) {
     789      130148 :                 return tevent_req_post(req, ev);
     790             :         }
     791             : 
     792      130160 :         return req;
     793             : }
     794             : 
     795             : static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq);
     796             : 
     797      390456 : static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req)
     798             : {
     799      299994 :         struct tstream_smbXcli_np_readv_state *state =
     800      390456 :                 tevent_req_data(req,
     801             :                 struct tstream_smbXcli_np_readv_state);
     802      299994 :         struct tstream_smbXcli_np *cli_nps =
     803      390456 :                 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      950746 :         while (cli_nps->read.left > 0 && state->count > 0) {
     811      260296 :                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
     812      260296 :                 size_t len = MIN(cli_nps->read.left, state->vector[0].iov_len);
     813             : 
     814      260296 :                 memcpy(base, cli_nps->read.buf + cli_nps->read.ofs, len);
     815             : 
     816      260296 :                 base += len;
     817      260296 :                 state->vector[0].iov_base = base;
     818      260296 :                 state->vector[0].iov_len -= len;
     819             : 
     820      260296 :                 cli_nps->read.ofs += len;
     821      260296 :                 cli_nps->read.left -= len;
     822             : 
     823      260296 :                 if (state->vector[0].iov_len == 0) {
     824      260296 :                         state->vector += 1;
     825      260296 :                         state->count -= 1;
     826             :                 }
     827             : 
     828      260296 :                 state->ret += len;
     829             :         }
     830             : 
     831      390456 :         if (cli_nps->read.left == 0) {
     832      260308 :                 TALLOC_FREE(cli_nps->read.buf);
     833             :         }
     834             : 
     835      390456 :         if (state->count == 0) {
     836      260296 :                 tevent_req_done(req);
     837      260296 :                 return;
     838             :         }
     839             : 
     840      130160 :         if (cli_nps->trans.active) {
     841      118656 :                 cli_nps->trans.active = false;
     842      118656 :                 cli_nps->trans.read_req = req;
     843      118656 :                 return;
     844             :         }
     845             : 
     846       11504 :         if (cli_nps->trans.write_req) {
     847        4680 :                 cli_nps->trans.read_req = req;
     848        4680 :                 tstream_smbXcli_np_readv_trans_start(req);
     849        4680 :                 return;
     850             :         }
     851             : 
     852        6824 :         if (cli_nps->is_smb1) {
     853           0 :                 subreq = smb1cli_readx_send(state, state->ev,
     854             :                                             cli_nps->conn,
     855             :                                             cli_nps->timeout,
     856           0 :                                             cli_nps->pid,
     857             :                                             cli_nps->tcon,
     858             :                                             cli_nps->session,
     859           0 :                                             cli_nps->fnum,
     860             :                                             0, /* offset */
     861             :                                             TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
     862             :         } else {
     863        6824 :                 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        6824 :         if (tevent_req_nomem(subreq, req)) {
     876           0 :                 return;
     877             :         }
     878        6824 :         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      123336 : static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req)
     886             : {
     887       95478 :         struct tstream_smbXcli_np_readv_state *state =
     888      123336 :                 tevent_req_data(req,
     889             :                 struct tstream_smbXcli_np_readv_state);
     890       95478 :         struct tstream_smbXcli_np *cli_nps =
     891      123336 :                 tstream_context_data(state->stream,
     892             :                 struct tstream_smbXcli_np);
     893             :         struct tevent_req *subreq;
     894             : 
     895      123336 :         state->trans.im = tevent_create_immediate(state);
     896      123336 :         if (tevent_req_nomem(state->trans.im, req)) {
     897           0 :                 return;
     898             :         }
     899             : 
     900      123336 :         if (cli_nps->is_smb1) {
     901         120 :                 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          42 :                                             cli_nps->pid,
     907             :                                             cli_nps->tcon,
     908             :                                             cli_nps->session,
     909             :                                             "\\PIPE\\",
     910             :                                             0, 0, 0,
     911          42 :                                             cli_nps->trans.setup, 2,
     912             :                                             0,
     913             :                                             NULL, 0, 0,
     914             :                                             cli_nps->write.buf,
     915          42 :                                             cli_nps->write.ofs,
     916             :                                             TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
     917             :         } else {
     918      123294 :                 DATA_BLOB in_input_buffer = data_blob_null;
     919      123294 :                 DATA_BLOB in_output_buffer = data_blob_null;
     920             : 
     921      123294 :                 in_input_buffer = data_blob_const(cli_nps->write.buf,
     922      123294 :                                                   cli_nps->write.ofs);
     923             : 
     924      123294 :                 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      123336 :         if (tevent_req_nomem(subreq, req)) {
     940           0 :                 return;
     941             :         }
     942      123336 :         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      123336 : static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq)
     955             : {
     956       95478 :         struct tevent_req *req =
     957      123336 :                 tevent_req_callback_data(subreq, struct tevent_req);
     958       95478 :         struct tstream_smbXcli_np_readv_state *state =
     959      123336 :                 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
     960       95478 :         struct tstream_smbXcli_np *cli_nps =
     961      123336 :                 tstream_context_data(state->stream, struct tstream_smbXcli_np);
     962             :         uint8_t *rcvbuf;
     963             :         uint32_t received;
     964             :         NTSTATUS status;
     965             : 
     966      123336 :         if (cli_nps->is_smb1) {
     967          42 :                 status = smb1cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
     968             :                                             NULL, 0, NULL,
     969             :                                             &rcvbuf, 0, &received);
     970             :         } else {
     971      123294 :                 DATA_BLOB out_input_buffer = data_blob_null;
     972      123294 :                 DATA_BLOB out_output_buffer = data_blob_null;
     973             : 
     974      123294 :                 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      123294 :                 rcvbuf = out_output_buffer.data;
     980      123294 :                 received = out_output_buffer.length;
     981             :         }
     982      123336 :         TALLOC_FREE(subreq);
     983      123336 :         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      123336 :         if (!NT_STATUS_IS_OK(status)) {
     994          12 :                 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
     995          12 :                 return;
     996             :         }
     997             : 
     998      123324 :         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      123324 :         if (received == 0) {
    1004           0 :                 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
    1005           0 :                 return;
    1006             :         }
    1007             : 
    1008      123324 :         cli_nps->read.ofs = 0;
    1009      123324 :         cli_nps->read.left = received;
    1010      123324 :         cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
    1011      123324 :         if (cli_nps->read.buf == NULL) {
    1012           0 :                 TALLOC_FREE(subreq);
    1013           0 :                 tevent_req_oom(req);
    1014           0 :                 return;
    1015             :         }
    1016      123324 :         memcpy(cli_nps->read.buf, rcvbuf, received);
    1017             : 
    1018      123324 :         if (cli_nps->trans.write_req == NULL) {
    1019           0 :                 tstream_smbXcli_np_readv_read_next(req);
    1020           0 :                 return;
    1021             :         }
    1022             : 
    1023      123324 :         tevent_schedule_immediate(state->trans.im, state->ev,
    1024             :                                   tstream_smbXcli_np_readv_trans_next, req);
    1025             : 
    1026      123324 :         tevent_req_done(cli_nps->trans.write_req);
    1027             : }
    1028             : 
    1029      123324 : static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
    1030             :                                             struct tevent_immediate *im,
    1031             :                                             void *private_data)
    1032             : {
    1033       95466 :         struct tevent_req *req =
    1034       27858 :                 talloc_get_type_abort(private_data,
    1035             :                 struct tevent_req);
    1036             : 
    1037      123324 :         tstream_smbXcli_np_readv_read_next(req);
    1038      123324 : }
    1039             : 
    1040        6824 : static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq)
    1041             : {
    1042        4528 :         struct tevent_req *req =
    1043        6824 :                 tevent_req_callback_data(subreq, struct tevent_req);
    1044        4528 :         struct tstream_smbXcli_np_readv_state *state =
    1045        6824 :                 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
    1046        4528 :         struct tstream_smbXcli_np *cli_nps =
    1047        6824 :                 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        6824 :         if (cli_nps->is_smb1) {
    1058           0 :                 status = smb1cli_readx_recv(subreq, &received, &rcvbuf);
    1059             :         } else {
    1060        6824 :                 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        6824 :         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        6824 :         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        6824 :         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        6824 :         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        6824 :         cli_nps->read.ofs = 0;
    1095        6824 :         cli_nps->read.left = received;
    1096        6824 :         cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
    1097        6824 :         if (cli_nps->read.buf == NULL) {
    1098           0 :                 TALLOC_FREE(subreq);
    1099           0 :                 tevent_req_oom(req);
    1100           0 :                 return;
    1101             :         }
    1102        6824 :         memcpy(cli_nps->read.buf, rcvbuf, received);
    1103        6824 :         TALLOC_FREE(subreq);
    1104             : 
    1105        6824 :         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          12 : static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
    1113             :                                                 int error,
    1114             :                                                 const char *location)
    1115             : {
    1116          12 :         struct tstream_smbXcli_np_readv_state *state =
    1117          12 :                 tevent_req_data(req,
    1118             :                 struct tstream_smbXcli_np_readv_state);
    1119          12 :         struct tstream_smbXcli_np *cli_nps =
    1120          12 :                 tstream_context_data(state->stream,
    1121             :                 struct tstream_smbXcli_np);
    1122             :         struct tevent_req *subreq;
    1123             : 
    1124          12 :         state->error.val = error;
    1125          12 :         state->error.location = location;
    1126             : 
    1127          12 :         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          12 :         subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
    1134             :                                                     state->stream);
    1135          12 :         if (subreq == NULL) {
    1136             :                 /* return the original error */
    1137           0 :                 tstream_smbXcli_np_readv_error(req);
    1138           0 :                 return;
    1139             :         }
    1140          12 :         tevent_req_set_callback(subreq,
    1141             :                                 tstream_smbXcli_np_readv_disconnect_done,
    1142             :                                 req);
    1143             : }
    1144             : 
    1145          12 : static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq)
    1146             : {
    1147          12 :         struct tevent_req *req =
    1148          12 :                 tevent_req_callback_data(subreq, struct tevent_req);
    1149             :         int error;
    1150             : 
    1151          12 :         tstream_smbXcli_np_disconnect_recv(subreq, &error);
    1152          12 :         TALLOC_FREE(subreq);
    1153             : 
    1154          12 :         tstream_smbXcli_np_readv_error(req);
    1155          12 : }
    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          12 : static void tstream_smbXcli_np_readv_error(struct tevent_req *req)
    1162             : {
    1163          12 :         struct tstream_smbXcli_np_readv_state *state =
    1164          12 :                 tevent_req_data(req,
    1165             :                 struct tstream_smbXcli_np_readv_state);
    1166          12 :         struct tstream_smbXcli_np *cli_nps =
    1167          12 :                 tstream_context_data(state->stream,
    1168             :                 struct tstream_smbXcli_np);
    1169             : 
    1170          12 :         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          12 :         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          12 :         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          24 :         _tevent_req_error(cli_nps->trans.write_req,
    1187          12 :                           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      260296 : static int tstream_smbXcli_np_readv_recv(struct tevent_req *req,
    1206             :                                          int *perrno)
    1207             : {
    1208      199988 :         struct tstream_smbXcli_np_readv_state *state =
    1209      260296 :                 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
    1210             :         int ret;
    1211             : 
    1212      260296 :         ret = tsocket_simple_int_recv(req, perrno);
    1213      260296 :         if (ret == 0) {
    1214      260296 :                 ret = state->ret;
    1215             :         }
    1216             : 
    1217      260296 :         tevent_req_received(req);
    1218      260296 :         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        3821 : 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        3821 :         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        3821 :         req = tevent_req_create(mem_ctx, &state,
    1241             :                                 struct tstream_smbXcli_np_disconnect_state);
    1242        3821 :         if (req == NULL) {
    1243           0 :                 return NULL;
    1244             :         }
    1245             : 
    1246        3821 :         state->stream = stream;
    1247             : 
    1248        3821 :         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
    1249          83 :                 tevent_req_error(req, ENOTCONN);
    1250          83 :                 return tevent_req_post(req, ev);
    1251             :         }
    1252             : 
    1253        3738 :         if (cli_nps->is_smb1) {
    1254          21 :                 subreq = smb1cli_close_send(state, ev, cli_nps->conn,
    1255             :                                             cli_nps->timeout,
    1256          11 :                                             cli_nps->pid,
    1257             :                                             cli_nps->tcon,
    1258             :                                             cli_nps->session,
    1259          11 :                                             cli_nps->fnum, UINT32_MAX);
    1260             :         } else {
    1261        3727 :                 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        3738 :         if (tevent_req_nomem(subreq, req)) {
    1270           0 :                 return tevent_req_post(req, ev);
    1271             :         }
    1272        3738 :         tevent_req_set_callback(subreq, tstream_smbXcli_np_disconnect_done, req);
    1273        3738 :         state->subreq = subreq;
    1274             : 
    1275        3738 :         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        3738 :         cli_nps->conn = NULL;
    1281             : 
    1282        3738 :         return req;
    1283             : }
    1284             : 
    1285          12 : static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq)
    1286             : {
    1287          12 :         struct tevent_req *req = tevent_req_callback_data(subreq,
    1288             :                                                           struct tevent_req);
    1289          12 :         struct tstream_smbXcli_np_disconnect_state *state =
    1290          12 :                 tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
    1291          12 :         struct tstream_smbXcli_np *cli_nps =
    1292          12 :                 tstream_context_data(state->stream, struct tstream_smbXcli_np);
    1293             :         NTSTATUS status;
    1294             : 
    1295          12 :         state->subreq = NULL;
    1296             : 
    1297          12 :         if (cli_nps->is_smb1) {
    1298           9 :                 status = smb1cli_close_recv(subreq);
    1299             :         } else {
    1300           3 :                 status = smb2cli_close_recv(subreq);
    1301             :         }
    1302          12 :         TALLOC_FREE(subreq);
    1303          12 :         if (!NT_STATUS_IS_OK(status)) {
    1304           9 :                 tevent_req_error(req, EPIPE);
    1305           9 :                 return;
    1306             :         }
    1307             : 
    1308           3 :         cli_nps->conn = NULL;
    1309           3 :         cli_nps->session = NULL;
    1310           3 :         cli_nps->tcon = NULL;
    1311             : 
    1312           3 :         tevent_req_done(req);
    1313             : }
    1314             : 
    1315             : static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq);
    1316             : 
    1317        3750 : static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req,
    1318             :                                         enum tevent_req_state req_state)
    1319             : {
    1320        2808 :         struct tstream_smbXcli_np_disconnect_state *state =
    1321        3750 :                 tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
    1322        3750 :         struct tstream_smbXcli_np *cli_nps = NULL;
    1323             : 
    1324        3750 :         if (state->subreq == NULL) {
    1325          24 :                 return;
    1326             :         }
    1327             : 
    1328        3726 :         cli_nps = tstream_context_data(state->stream, struct tstream_smbXcli_np);
    1329             : 
    1330        3726 :         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        3726 :         talloc_steal(cli_nps->tcon, state->subreq);
    1345        3726 :         tevent_req_set_callback(state->subreq,
    1346             :                                 tstream_smbXcli_np_disconnect_free,
    1347             :                                 NULL);
    1348        3726 :         state->subreq = NULL;
    1349             : 
    1350        3726 :         cli_nps->conn = NULL;
    1351        3726 :         cli_nps->session = NULL;
    1352        3726 :         cli_nps->tcon = NULL;
    1353             : }
    1354             : 
    1355          52 : static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq)
    1356             : {
    1357          52 :         TALLOC_FREE(subreq);
    1358          52 : }
    1359             : 
    1360          12 : static int tstream_smbXcli_np_disconnect_recv(struct tevent_req *req,
    1361             :                                               int *perrno)
    1362             : {
    1363             :         int ret;
    1364             : 
    1365          12 :         ret = tsocket_simple_int_recv(req, perrno);
    1366             : 
    1367          12 :         tevent_req_received(req);
    1368          12 :         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