LCOV - code coverage report
Current view: top level - libcli/smb - tstream_smbXcli_np.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 489 600 81.5 %
Date: 2024-02-28 12:06:22 Functions: 30 34 88.2 %

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

Generated by: LCOV version 1.14