LCOV - code coverage report
Current view: top level - source3/smbd - smb2_read.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 123 271 45.4 %
Date: 2024-06-13 04:01:37 Functions: 6 10 60.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Core SMB2 server
       4             : 
       5             :    Copyright (C) Stefan Metzmacher 2009
       6             : 
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include "includes.h"
      22             : #include "system/filesys.h"
      23             : #include "smbd/smbd.h"
      24             : #include "smbd/globals.h"
      25             : #include "../libcli/smb/smb_common.h"
      26             : #include "libcli/security/security.h"
      27             : #include "../lib/util/tevent_ntstatus.h"
      28             : #include "rpc_server/srv_pipe_hnd.h"
      29             : #include "lib/util/sys_rw_data.h"
      30             : 
      31             : #undef DBGC_CLASS
      32             : #define DBGC_CLASS DBGC_SMB2
      33             : 
      34             : static struct tevent_req *smbd_smb2_read_send(TALLOC_CTX *mem_ctx,
      35             :                                               struct tevent_context *ev,
      36             :                                               struct smbd_smb2_request *smb2req,
      37             :                                               struct files_struct *in_fsp,
      38             :                                               uint8_t in_flags,
      39             :                                               uint32_t in_length,
      40             :                                               uint64_t in_offset,
      41             :                                               uint32_t in_minimum,
      42             :                                               uint32_t in_remaining);
      43             : static NTSTATUS smbd_smb2_read_recv(struct tevent_req *req,
      44             :                                     TALLOC_CTX *mem_ctx,
      45             :                                     DATA_BLOB *out_data,
      46             :                                     uint32_t *out_remaining);
      47             : 
      48             : static void smbd_smb2_request_read_done(struct tevent_req *subreq);
      49        6358 : NTSTATUS smbd_smb2_request_process_read(struct smbd_smb2_request *req)
      50             : {
      51        6358 :         struct smbXsrv_connection *xconn = req->xconn;
      52             :         NTSTATUS status;
      53             :         const uint8_t *inbody;
      54             :         uint8_t in_flags;
      55             :         uint32_t in_length;
      56             :         uint64_t in_offset;
      57             :         uint64_t in_file_id_persistent;
      58             :         uint64_t in_file_id_volatile;
      59             :         struct files_struct *in_fsp;
      60             :         uint32_t in_minimum_count;
      61             :         uint32_t in_remaining_bytes;
      62             :         struct tevent_req *subreq;
      63             : 
      64        6358 :         status = smbd_smb2_request_verify_sizes(req, 0x31);
      65        6358 :         if (!NT_STATUS_IS_OK(status)) {
      66           0 :                 return smbd_smb2_request_error(req, status);
      67             :         }
      68        6358 :         inbody = SMBD_SMB2_IN_BODY_PTR(req);
      69             : 
      70        6358 :         if (xconn->protocol >= PROTOCOL_SMB3_02) {
      71        1792 :                 in_flags                = CVAL(inbody, 0x03);
      72             :         } else {
      73        4566 :                 in_flags                = 0;
      74             :         }
      75        6358 :         in_length               = IVAL(inbody, 0x04);
      76        6358 :         in_offset               = BVAL(inbody, 0x08);
      77        6358 :         in_file_id_persistent   = BVAL(inbody, 0x10);
      78        6358 :         in_file_id_volatile     = BVAL(inbody, 0x18);
      79        6358 :         in_minimum_count        = IVAL(inbody, 0x20);
      80        6358 :         in_remaining_bytes      = IVAL(inbody, 0x28);
      81             : 
      82             :         /* check the max read size */
      83        6358 :         if (in_length > xconn->smb2.server.max_read) {
      84           0 :                 DEBUG(2,("smbd_smb2_request_process_read: "
      85             :                          "client ignored max read: %s: 0x%08X: 0x%08X\n",
      86             :                         __location__, in_length, xconn->smb2.server.max_read));
      87           0 :                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
      88             :         }
      89             : 
      90        6358 :         status = smbd_smb2_request_verify_creditcharge(req, in_length);
      91        6358 :         if (!NT_STATUS_IS_OK(status)) {
      92           0 :                 return smbd_smb2_request_error(req, status);
      93             :         }
      94             : 
      95        6358 :         in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
      96        6358 :         if (in_fsp == NULL) {
      97           0 :                 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
      98             :         }
      99             : 
     100        6358 :         subreq = smbd_smb2_read_send(req, req->sconn->ev_ctx,
     101             :                                      req, in_fsp,
     102             :                                      in_flags,
     103             :                                      in_length,
     104             :                                      in_offset,
     105             :                                      in_minimum_count,
     106             :                                      in_remaining_bytes);
     107        6358 :         if (subreq == NULL) {
     108           0 :                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
     109             :         }
     110        6358 :         tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
     111             : 
     112        6358 :         return smbd_smb2_request_pending_queue(req, subreq, 500);
     113             : }
     114             : 
     115        6358 : static void smbd_smb2_request_read_done(struct tevent_req *subreq)
     116             : {
     117        6358 :         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
     118             :                                         struct smbd_smb2_request);
     119             :         uint16_t body_size;
     120        6358 :         uint8_t body_padding = req->xconn->smb2.smbtorture.read_body_padding;
     121             :         DATA_BLOB outbody;
     122             :         DATA_BLOB outdyn;
     123             :         uint8_t out_data_offset;
     124        6358 :         DATA_BLOB out_data_buffer = data_blob_null;
     125        6358 :         uint32_t out_data_remaining = 0;
     126             :         NTSTATUS status;
     127             :         NTSTATUS error; /* transport error */
     128             : 
     129        6358 :         status = smbd_smb2_read_recv(subreq,
     130             :                                      req,
     131             :                                      &out_data_buffer,
     132             :                                      &out_data_remaining);
     133        6358 :         TALLOC_FREE(subreq);
     134        6358 :         if (!NT_STATUS_IS_OK(status)) {
     135           3 :                 error = smbd_smb2_request_error(req, status);
     136           3 :                 if (!NT_STATUS_IS_OK(error)) {
     137           0 :                         smbd_server_connection_terminate(req->xconn,
     138             :                                                          nt_errstr(error));
     139           1 :                         return;
     140             :                 }
     141           3 :                 return;
     142             :         }
     143             : 
     144             :         /*
     145             :          * Only FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8
     146             :          * sets body_padding to a value different from 0.
     147             :          */
     148        6355 :         body_size = 0x10 + body_padding;
     149        6355 :         out_data_offset = SMB2_HDR_BODY + body_size;
     150             : 
     151        6355 :         outbody = smbd_smb2_generate_outbody(req, body_size);
     152        6355 :         if (outbody.data == NULL) {
     153           0 :                 error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
     154           0 :                 if (!NT_STATUS_IS_OK(error)) {
     155           0 :                         smbd_server_connection_terminate(req->xconn,
     156             :                                                          nt_errstr(error));
     157           0 :                         return;
     158             :                 }
     159           0 :                 return;
     160             :         }
     161             : 
     162        6355 :         SSVAL(outbody.data, 0x00, 0x10 + 1);    /* struct size */
     163        6355 :         SCVAL(outbody.data, 0x02,
     164             :               out_data_offset);                 /* data offset */
     165        6355 :         SCVAL(outbody.data, 0x03, 0);           /* reserved */
     166        6355 :         SIVAL(outbody.data, 0x04,
     167             :               out_data_buffer.length);          /* data length */
     168        6355 :         SIVAL(outbody.data, 0x08,
     169             :               out_data_remaining);              /* data remaining */
     170        6355 :         SIVAL(outbody.data, 0x0C, 0);           /* reserved */
     171        6355 :         if (body_padding != 0) {
     172           0 :                 memset(outbody.data + 0x10, 0, body_padding);
     173             :         }
     174             : 
     175        6355 :         outdyn = out_data_buffer;
     176             : 
     177        6355 :         error = smbd_smb2_request_done(req, outbody, &outdyn);
     178        6355 :         if (!NT_STATUS_IS_OK(error)) {
     179           0 :                 smbd_server_connection_terminate(req->xconn,
     180             :                                                  nt_errstr(error));
     181           0 :                 return;
     182             :         }
     183             : }
     184             : 
     185             : struct smbd_smb2_read_state {
     186             :         struct smbd_smb2_request *smb2req;
     187             :         struct smb_request *smbreq;
     188             :         files_struct *fsp;
     189             :         uint8_t in_flags;
     190             :         uint32_t in_length;
     191             :         uint64_t in_offset;
     192             :         uint32_t in_minimum;
     193             :         DATA_BLOB out_headers;
     194             :         uint8_t _out_hdr_buf[NBT_HDR_SIZE + SMB2_HDR_BODY + 0x10];
     195             :         DATA_BLOB out_data;
     196             :         uint32_t out_remaining;
     197             : };
     198             : 
     199           0 : static int smb2_smb2_read_state_deny_destructor(struct smbd_smb2_read_state *state)
     200             : {
     201           0 :         return -1;
     202             : }
     203             : 
     204             : /* struct smbd_smb2_read_state destructor. Send the SMB2_READ data. */
     205           0 : static int smb2_sendfile_send_data(struct smbd_smb2_read_state *state)
     206             : {
     207             :         struct lock_struct lock;
     208           0 :         uint32_t in_length = state->in_length;
     209           0 :         uint64_t in_offset = state->in_offset;
     210           0 :         files_struct *fsp = state->fsp;
     211           0 :         const DATA_BLOB *hdr = state->smb2req->queue_entry.sendfile_header;
     212           0 :         NTSTATUS *pstatus = state->smb2req->queue_entry.sendfile_status;
     213           0 :         struct smbXsrv_connection *xconn = state->smb2req->xconn;
     214             :         ssize_t nread;
     215             :         ssize_t ret;
     216             :         int saved_errno;
     217             : 
     218           0 :         nread = SMB_VFS_SENDFILE(xconn->transport.sock,
     219             :                                  fsp,
     220             :                                  hdr,
     221             :                                  in_offset,
     222             :                                  in_length);
     223           0 :         DEBUG(10,("smb2_sendfile_send_data: SMB_VFS_SENDFILE returned %d on file %s\n",
     224             :                 (int)nread,
     225             :                 fsp_str_dbg(fsp) ));
     226             : 
     227           0 :         if (nread == -1) {
     228           0 :                 saved_errno = errno;
     229             : 
     230             :                 /*
     231             :                  * Returning ENOSYS means no data at all was sent.
     232             :                    Do this as a normal read. */
     233           0 :                 if (errno == ENOSYS) {
     234           0 :                         goto normal_read;
     235             :                 }
     236             : 
     237           0 :                 if (errno == ENOTSUP) {
     238           0 :                         set_use_sendfile(SNUM(fsp->conn), false);
     239           0 :                         DBG_WARNING("Disabling sendfile use as sendfile is "
     240             :                                     "not supported by the system\n");
     241           0 :                         goto normal_read;
     242             :                 }
     243             : 
     244           0 :                 if (errno == EINTR) {
     245             :                         /*
     246             :                          * Special hack for broken Linux with no working sendfile. If we
     247             :                          * return EINTR we sent the header but not the rest of the data.
     248             :                          * Fake this up by doing read/write calls.
     249             :                          */
     250           0 :                         set_use_sendfile(SNUM(fsp->conn), false);
     251           0 :                         nread = fake_sendfile(xconn, fsp, in_offset, in_length);
     252           0 :                         if (nread == -1) {
     253           0 :                                 saved_errno = errno;
     254           0 :                                 DEBUG(0,("smb2_sendfile_send_data: fake_sendfile "
     255             :                                          "failed for file %s (%s) for client %s. "
     256             :                                          "Terminating\n",
     257             :                                          fsp_str_dbg(fsp), strerror(saved_errno),
     258             :                                          smbXsrv_connection_dbg(xconn)));
     259           0 :                                 *pstatus = map_nt_error_from_unix_common(saved_errno);
     260           0 :                                 return 0;
     261             :                         }
     262           0 :                         goto out;
     263             :                 }
     264             : 
     265           0 :                 DEBUG(0,("smb2_sendfile_send_data: sendfile failed for file "
     266             :                          "%s (%s) for client %s. Terminating\n",
     267             :                          fsp_str_dbg(fsp), strerror(saved_errno),
     268             :                          smbXsrv_connection_dbg(xconn)));
     269           0 :                 *pstatus = map_nt_error_from_unix_common(saved_errno);
     270           0 :                 return 0;
     271           0 :         } else if (nread == 0) {
     272             :                 /*
     273             :                  * Some sendfile implementations return 0 to indicate
     274             :                  * that there was a short read, but nothing was
     275             :                  * actually written to the socket.  In this case,
     276             :                  * fallback to the normal read path so the header gets
     277             :                  * the correct byte count.
     278             :                  */
     279           0 :                 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
     280             :                         "falling back to the normal read: %s\n",
     281             :                         fsp_str_dbg(fsp)));
     282           0 :                 goto normal_read;
     283             :         }
     284             : 
     285             :         /*
     286             :          * We got a short read
     287             :          */
     288           0 :         goto out;
     289             : 
     290           0 : normal_read:
     291             :         /* Send out the header. */
     292           0 :         ret = write_data(xconn->transport.sock,
     293           0 :                          (const char *)hdr->data, hdr->length);
     294           0 :         if (ret != hdr->length) {
     295           0 :                 saved_errno = errno;
     296           0 :                 DEBUG(0,("smb2_sendfile_send_data: write_data failed for file "
     297             :                          "%s (%s) for client %s. Terminating\n",
     298             :                          fsp_str_dbg(fsp), strerror(saved_errno),
     299             :                          smbXsrv_connection_dbg(xconn)));
     300           0 :                 *pstatus = map_nt_error_from_unix_common(saved_errno);
     301           0 :                 return 0;
     302             :         }
     303           0 :         nread = fake_sendfile(xconn, fsp, in_offset, in_length);
     304           0 :         if (nread == -1) {
     305           0 :                 saved_errno = errno;
     306           0 :                 DEBUG(0,("smb2_sendfile_send_data: fake_sendfile "
     307             :                          "failed for file %s (%s) for client %s. "
     308             :                          "Terminating\n",
     309             :                          fsp_str_dbg(fsp), strerror(saved_errno),
     310             :                          smbXsrv_connection_dbg(xconn)));
     311           0 :                 *pstatus = map_nt_error_from_unix_common(saved_errno);
     312           0 :                 return 0;
     313             :         }
     314             : 
     315           0 :   out:
     316             : 
     317           0 :         if (nread < in_length) {
     318           0 :                 ret = sendfile_short_send(xconn, fsp, nread,
     319           0 :                                           hdr->length, in_length);
     320           0 :                 if (ret == -1) {
     321           0 :                         saved_errno = errno;
     322           0 :                         DEBUG(0,("%s: sendfile_short_send "
     323             :                                  "failed for file %s (%s) for client %s. "
     324             :                                  "Terminating\n",
     325             :                                  __func__,
     326             :                                  fsp_str_dbg(fsp), strerror(saved_errno),
     327             :                                  smbXsrv_connection_dbg(xconn)));
     328           0 :                         *pstatus = map_nt_error_from_unix_common(saved_errno);
     329           0 :                         return 0;
     330             :                 }
     331             :         }
     332             : 
     333           0 :         init_strict_lock_struct(fsp,
     334           0 :                                 fsp->op->global->open_persistent_id,
     335             :                                 in_offset,
     336             :                                 in_length,
     337             :                                 READ_LOCK,
     338             :                                 lp_posix_cifsu_locktype(fsp),
     339             :                                 &lock);
     340             : 
     341           0 :         *pstatus = NT_STATUS_OK;
     342           0 :         return 0;
     343             : }
     344             : 
     345           0 : static NTSTATUS schedule_smb2_sendfile_read(struct smbd_smb2_request *smb2req,
     346             :                                         struct smbd_smb2_read_state *state)
     347             : {
     348           0 :         files_struct *fsp = state->fsp;
     349             : 
     350             :         /*
     351             :          * We cannot use sendfile if...
     352             :          * We were not configured to do so OR
     353             :          * Signing is active OR
     354             :          * This is a compound SMB2 operation OR
     355             :          * fsp is a STREAM file OR
     356             :          * We're using a write cache OR
     357             :          * It's not a regular file OR
     358             :          * Requested offset is greater than file size OR
     359             :          * there's not enough data in the file.
     360             :          * Phew :-). Luckily this means most
     361             :          * reads on most normal files. JRA.
     362             :         */
     363             : 
     364           0 :         if (!lp__use_sendfile(SNUM(fsp->conn)) ||
     365           0 :             smb2req->do_signing ||
     366           0 :             smb2req->do_encryption ||
     367           0 :             smbd_smb2_is_compound(smb2req) ||
     368           0 :             fsp_is_alternate_stream(fsp) ||
     369           0 :             (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) ||
     370           0 :             (state->in_offset >= fsp->fsp_name->st.st_ex_size) ||
     371           0 :             (fsp->fsp_name->st.st_ex_size < state->in_offset + state->in_length))
     372             :         {
     373           0 :                 return NT_STATUS_RETRY;
     374             :         }
     375             : 
     376             :         /* We've already checked there's this amount of data
     377             :            to read. */
     378           0 :         state->out_data.length = state->in_length;
     379           0 :         state->out_remaining = 0;
     380             : 
     381           0 :         state->out_headers = data_blob_const(state->_out_hdr_buf,
     382             :                                              sizeof(state->_out_hdr_buf));
     383           0 :         return NT_STATUS_OK;
     384             : }
     385             : 
     386             : static void smbd_smb2_read_pipe_done(struct tevent_req *subreq);
     387             : 
     388             : /*******************************************************************
     389             :  Common read complete processing function for both synchronous and
     390             :  asynchronous reads.
     391             : *******************************************************************/
     392             : 
     393         349 : NTSTATUS smb2_read_complete(struct tevent_req *req, ssize_t nread, int err)
     394             : {
     395         349 :         struct smbd_smb2_read_state *state = tevent_req_data(req,
     396             :                                         struct smbd_smb2_read_state);
     397         349 :         files_struct *fsp = state->fsp;
     398             : 
     399         349 :         if (nread < 0) {
     400           0 :                 NTSTATUS status = map_nt_error_from_unix(err);
     401             : 
     402           0 :                 DEBUG( 3,( "smb2_read_complete: file %s nread = %d. "
     403             :                         "Error = %s (NTSTATUS %s)\n",
     404             :                         fsp_str_dbg(fsp),
     405             :                         (int)nread,
     406             :                         strerror(err),
     407             :                         nt_errstr(status)));
     408             : 
     409           0 :                 return status;
     410             :         }
     411         349 :         if (nread == 0 && state->in_length != 0) {
     412           0 :                 DEBUG(5,("smb2_read_complete: read_file[%s] end of file\n",
     413             :                         fsp_str_dbg(fsp)));
     414           0 :                 return NT_STATUS_END_OF_FILE;
     415             :         }
     416             : 
     417         349 :         if (nread < state->in_minimum) {
     418           0 :                 DEBUG(5,("smb2_read_complete: read_file[%s] read less %d than "
     419             :                         "minimum requested %u. Returning end of file\n",
     420             :                         fsp_str_dbg(fsp),
     421             :                         (int)nread,
     422             :                         (unsigned int)state->in_minimum));
     423           0 :                 return NT_STATUS_END_OF_FILE;
     424             :         }
     425             : 
     426         349 :         DEBUG(3,("smbd_smb2_read: %s, file %s, length=%lu offset=%lu read=%lu\n",
     427             :                 fsp_fnum_dbg(fsp),
     428             :                 fsp_str_dbg(fsp),
     429             :                 (unsigned long)state->in_length,
     430             :                 (unsigned long)state->in_offset,
     431             :                 (unsigned long)nread));
     432             : 
     433         349 :         state->out_data.length = nread;
     434         349 :         state->out_remaining = 0;
     435             : 
     436         349 :         return NT_STATUS_OK;
     437             : }
     438             : 
     439           0 : static bool smbd_smb2_read_cancel(struct tevent_req *req)
     440             : {
     441           0 :         struct smbd_smb2_read_state *state =
     442           0 :                 tevent_req_data(req,
     443             :                 struct smbd_smb2_read_state);
     444             : 
     445           0 :         return cancel_smb2_aio(state->smbreq);
     446             : }
     447             : 
     448        6358 : static struct tevent_req *smbd_smb2_read_send(TALLOC_CTX *mem_ctx,
     449             :                                               struct tevent_context *ev,
     450             :                                               struct smbd_smb2_request *smb2req,
     451             :                                               struct files_struct *fsp,
     452             :                                               uint8_t in_flags,
     453             :                                               uint32_t in_length,
     454             :                                               uint64_t in_offset,
     455             :                                               uint32_t in_minimum,
     456             :                                               uint32_t in_remaining)
     457             : {
     458             :         NTSTATUS status;
     459        6358 :         struct tevent_req *req = NULL;
     460        6358 :         struct smbd_smb2_read_state *state = NULL;
     461        6358 :         struct smb_request *smbreq = NULL;
     462        6358 :         connection_struct *conn = smb2req->tcon->compat;
     463        6358 :         ssize_t nread = -1;
     464             :         struct lock_struct lock;
     465             :         int saved_errno;
     466             : 
     467        6358 :         req = tevent_req_create(mem_ctx, &state,
     468             :                                 struct smbd_smb2_read_state);
     469        6358 :         if (req == NULL) {
     470           0 :                 return NULL;
     471             :         }
     472        6358 :         state->smb2req = smb2req;
     473        6358 :         state->in_flags = in_flags;
     474        6358 :         state->in_length = in_length;
     475        6358 :         state->in_offset = in_offset;
     476        6358 :         state->in_minimum = in_minimum;
     477        6358 :         state->out_data = data_blob_null;
     478        6358 :         state->out_remaining = 0;
     479             : 
     480        6358 :         DEBUG(10,("smbd_smb2_read: %s - %s\n",
     481             :                   fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
     482             : 
     483        6358 :         smbreq = smbd_smb2_fake_smb_request(smb2req);
     484        6358 :         if (tevent_req_nomem(smbreq, req)) {
     485           0 :                 return tevent_req_post(req, ev);
     486             :         }
     487        6358 :         state->smbreq = smbreq;
     488             : 
     489        6358 :         if (fsp->fsp_flags.is_directory) {
     490           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
     491           0 :                 return tevent_req_post(req, ev);
     492             :         }
     493             : 
     494        6358 :         state->fsp = fsp;
     495             : 
     496        6358 :         if (IS_IPC(smbreq->conn)) {
     497        6009 :                 struct tevent_req *subreq = NULL;
     498             : 
     499        6009 :                 state->out_data = data_blob_talloc(state, NULL, in_length);
     500        6009 :                 if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) {
     501           0 :                         return tevent_req_post(req, ev);
     502             :                 }
     503             : 
     504        6009 :                 if (!fsp_is_np(fsp)) {
     505           0 :                         tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
     506           0 :                         return tevent_req_post(req, ev);
     507             :                 }
     508             : 
     509       10188 :                 subreq = np_read_send(state, ev,
     510             :                                       fsp->fake_file_handle,
     511        6009 :                                       state->out_data.data,
     512        6009 :                                       state->out_data.length);
     513        6009 :                 if (tevent_req_nomem(subreq, req)) {
     514           0 :                         return tevent_req_post(req, ev);
     515             :                 }
     516        6009 :                 tevent_req_set_callback(subreq,
     517             :                                         smbd_smb2_read_pipe_done,
     518             :                                         req);
     519        6009 :                 return req;
     520             :         }
     521             : 
     522         349 :         if (!CHECK_READ_SMB2(fsp)) {
     523           0 :                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
     524           0 :                 return tevent_req_post(req, ev);
     525             :         }
     526             : 
     527         690 :         status = schedule_smb2_aio_read(fsp->conn,
     528             :                                 smbreq,
     529             :                                 fsp,
     530             :                                 state,
     531         349 :                                 &state->out_data,
     532             :                                 (off_t)in_offset,
     533             :                                 (size_t)in_length);
     534             : 
     535         349 :         if (NT_STATUS_IS_OK(status)) {
     536             :                 /*
     537             :                  * Doing an async read, allow this
     538             :                  * request to be canceled
     539             :                  */
     540         349 :                 tevent_req_set_cancel_fn(req, smbd_smb2_read_cancel);
     541         349 :                 return req;
     542             :         }
     543             : 
     544           0 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
     545             :                 /* Real error in setting up aio. Fail. */
     546           0 :                 tevent_req_nterror(req, status);
     547           0 :                 return tevent_req_post(req, ev);
     548             :         }
     549             : 
     550             :         /* Fallback to synchronous. */
     551             : 
     552           0 :         init_strict_lock_struct(fsp,
     553           0 :                                 fsp->op->global->open_persistent_id,
     554             :                                 in_offset,
     555             :                                 in_length,
     556             :                                 READ_LOCK,
     557             :                                 lp_posix_cifsu_locktype(fsp),
     558             :                                 &lock);
     559             : 
     560           0 :         if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
     561           0 :                 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
     562           0 :                 return tevent_req_post(req, ev);
     563             :         }
     564             : 
     565             :         /* Try sendfile in preference. */
     566           0 :         status = schedule_smb2_sendfile_read(smb2req, state);
     567           0 :         if (NT_STATUS_IS_OK(status)) {
     568           0 :                 tevent_req_done(req);
     569           0 :                 return tevent_req_post(req, ev);
     570             :         } else {
     571           0 :                 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
     572           0 :                         tevent_req_nterror(req, status);
     573           0 :                         return tevent_req_post(req, ev);
     574             :                 }
     575             :         }
     576             : 
     577             :         /* Ok, read into memory. Allocate the out buffer. */
     578           0 :         state->out_data = data_blob_talloc(state, NULL, in_length);
     579           0 :         if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) {
     580           0 :                 return tevent_req_post(req, ev);
     581             :         }
     582             : 
     583           0 :         nread = read_file(fsp,
     584           0 :                           (char *)state->out_data.data,
     585             :                           in_offset,
     586             :                           in_length);
     587             : 
     588           0 :         saved_errno = errno;
     589             : 
     590           0 :         DEBUG(10,("smbd_smb2_read: file %s, %s, offset=%llu "
     591             :                 "len=%llu returned %lld\n",
     592             :                 fsp_str_dbg(fsp),
     593             :                 fsp_fnum_dbg(fsp),
     594             :                 (unsigned long long)in_offset,
     595             :                 (unsigned long long)in_length,
     596             :                 (long long)nread));
     597             : 
     598           0 :         status = smb2_read_complete(req, nread, saved_errno);
     599           0 :         if (!NT_STATUS_IS_OK(status)) {
     600           0 :                 tevent_req_nterror(req, status);
     601             :         } else {
     602             :                 /* Success. */
     603           0 :                 tevent_req_done(req);
     604             :         }
     605           0 :         return tevent_req_post(req, ev);
     606             : }
     607             : 
     608        6009 : static void smbd_smb2_read_pipe_done(struct tevent_req *subreq)
     609             : {
     610        6009 :         struct tevent_req *req = tevent_req_callback_data(subreq,
     611             :                                  struct tevent_req);
     612        6009 :         struct smbd_smb2_read_state *state = tevent_req_data(req,
     613             :                                              struct smbd_smb2_read_state);
     614             :         NTSTATUS status;
     615        6009 :         ssize_t nread = -1;
     616             :         bool is_data_outstanding;
     617             : 
     618        6009 :         status = np_read_recv(subreq, &nread, &is_data_outstanding);
     619        6009 :         TALLOC_FREE(subreq);
     620        6009 :         if (!NT_STATUS_IS_OK(status)) {
     621           3 :                 NTSTATUS old = status;
     622           3 :                 status = nt_status_np_pipe(old);
     623           3 :                 tevent_req_nterror(req, status);
     624           3 :                 return;
     625             :         }
     626             : 
     627        6006 :         if (nread == 0 && state->out_data.length != 0) {
     628           0 :                 tevent_req_nterror(req, NT_STATUS_END_OF_FILE);
     629           0 :                 return;
     630             :         }
     631             : 
     632        6006 :         state->out_data.length = nread;
     633        6006 :         state->out_remaining = 0;
     634             : 
     635             :         /*
     636             :          * TODO: add STATUS_BUFFER_OVERFLOW handling, once we also
     637             :          * handle it in SMB1 pipe_read_andx_done().
     638             :          */
     639             : 
     640        6006 :         tevent_req_done(req);
     641             : }
     642             : 
     643        6358 : static NTSTATUS smbd_smb2_read_recv(struct tevent_req *req,
     644             :                                     TALLOC_CTX *mem_ctx,
     645             :                                     DATA_BLOB *out_data,
     646             :                                     uint32_t *out_remaining)
     647             : {
     648             :         NTSTATUS status;
     649        6358 :         struct smbd_smb2_read_state *state = tevent_req_data(req,
     650             :                                              struct smbd_smb2_read_state);
     651             : 
     652        6358 :         if (tevent_req_is_nterror(req, &status)) {
     653           3 :                 tevent_req_received(req);
     654           3 :                 return status;
     655             :         }
     656             : 
     657        6355 :         *out_data = state->out_data;
     658        6355 :         talloc_steal(mem_ctx, out_data->data);
     659        6355 :         *out_remaining = state->out_remaining;
     660             : 
     661        6355 :         if (state->out_headers.length > 0) {
     662           0 :                 talloc_steal(mem_ctx, state);
     663           0 :                 talloc_set_destructor(state, smb2_smb2_read_state_deny_destructor);
     664           0 :                 tevent_req_received(req);
     665           0 :                 state->smb2req->queue_entry.sendfile_header = &state->out_headers;
     666           0 :                 state->smb2req->queue_entry.sendfile_body_size = state->in_length;
     667           0 :                 talloc_set_destructor(state, smb2_sendfile_send_data);
     668             :         } else {
     669        6355 :                 tevent_req_received(req);
     670             :         }
     671             : 
     672        6355 :         return NT_STATUS_OK;
     673             : }

Generated by: LCOV version 1.13