LCOV - code coverage report
Current view: top level - source3/smbd - smb2_read.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 159 270 58.9 %
Date: 2021-08-25 13:27:56 Functions: 8 10 80.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       12092 : NTSTATUS smbd_smb2_request_process_read(struct smbd_smb2_request *req)
      50             : {
      51       12092 :         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       12092 :         status = smbd_smb2_request_verify_sizes(req, 0x31);
      65       12092 :         if (!NT_STATUS_IS_OK(status)) {
      66           0 :                 return smbd_smb2_request_error(req, status);
      67             :         }
      68       12092 :         inbody = SMBD_SMB2_IN_BODY_PTR(req);
      69             : 
      70       12092 :         if (xconn->protocol >= PROTOCOL_SMB3_02) {
      71        6973 :                 in_flags                = CVAL(inbody, 0x03);
      72             :         } else {
      73        5119 :                 in_flags                = 0;
      74             :         }
      75       12092 :         in_length               = IVAL(inbody, 0x04);
      76       12092 :         in_offset               = BVAL(inbody, 0x08);
      77       12092 :         in_file_id_persistent   = BVAL(inbody, 0x10);
      78       12092 :         in_file_id_volatile     = BVAL(inbody, 0x18);
      79       12092 :         in_minimum_count        = IVAL(inbody, 0x20);
      80       12092 :         in_remaining_bytes      = IVAL(inbody, 0x28);
      81             : 
      82             :         /* check the max read size */
      83       12092 :         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       12092 :         status = smbd_smb2_request_verify_creditcharge(req, in_length);
      91       12092 :         if (!NT_STATUS_IS_OK(status)) {
      92           0 :                 return smbd_smb2_request_error(req, status);
      93             :         }
      94             : 
      95       12092 :         in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
      96       12092 :         if (in_fsp == NULL) {
      97           0 :                 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
      98             :         }
      99             : 
     100       12092 :         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       12092 :         if (subreq == NULL) {
     108           0 :                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
     109             :         }
     110       12092 :         tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
     111             : 
     112       12092 :         return smbd_smb2_request_pending_queue(req, subreq, 500);
     113             : }
     114             : 
     115       12092 : static void smbd_smb2_request_read_done(struct tevent_req *subreq)
     116             : {
     117       12092 :         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
     118             :                                         struct smbd_smb2_request);
     119             :         uint16_t body_size;
     120       12092 :         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       12092 :         DATA_BLOB out_data_buffer = data_blob_null;
     125       12092 :         uint32_t out_data_remaining = 0;
     126             :         NTSTATUS status;
     127             :         NTSTATUS error; /* transport error */
     128             : 
     129       12092 :         status = smbd_smb2_read_recv(subreq,
     130             :                                      req,
     131             :                                      &out_data_buffer,
     132             :                                      &out_data_remaining);
     133       12092 :         TALLOC_FREE(subreq);
     134       12092 :         if (!NT_STATUS_IS_OK(status)) {
     135         570 :                 error = smbd_smb2_request_error(req, status);
     136         570 :                 if (!NT_STATUS_IS_OK(error)) {
     137           0 :                         smbd_server_connection_terminate(req->xconn,
     138             :                                                          nt_errstr(error));
     139           0 :                         return;
     140             :                 }
     141         570 :                 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       11522 :         body_size = 0x10 + body_padding;
     149       11522 :         out_data_offset = SMB2_HDR_BODY + body_size;
     150             : 
     151       11522 :         outbody = smbd_smb2_generate_outbody(req, body_size);
     152       11522 :         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       11522 :         SSVAL(outbody.data, 0x00, 0x10 + 1);    /* struct size */
     163       11522 :         SCVAL(outbody.data, 0x02,
     164             :               out_data_offset);                 /* data offset */
     165       11522 :         SCVAL(outbody.data, 0x03, 0);           /* reserved */
     166       11522 :         SIVAL(outbody.data, 0x04,
     167             :               out_data_buffer.length);          /* data length */
     168       11522 :         SIVAL(outbody.data, 0x08,
     169             :               out_data_remaining);              /* data remaining */
     170       11522 :         SIVAL(outbody.data, 0x0C, 0);           /* reserved */
     171       11522 :         if (body_padding != 0) {
     172           8 :                 memset(outbody.data + 0x10, 0, body_padding);
     173             :         }
     174             : 
     175       11522 :         outdyn = out_data_buffer;
     176             : 
     177       11522 :         error = smbd_smb2_request_done(req, outbody, &outdyn);
     178       11522 :         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             :                                           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             :                                 &lock);
     339             : 
     340           0 :         *pstatus = NT_STATUS_OK;
     341           0 :         return 0;
     342             : }
     343             : 
     344         750 : static NTSTATUS schedule_smb2_sendfile_read(struct smbd_smb2_request *smb2req,
     345             :                                         struct smbd_smb2_read_state *state)
     346             : {
     347         750 :         files_struct *fsp = state->fsp;
     348             : 
     349             :         /*
     350             :          * We cannot use sendfile if...
     351             :          * We were not configured to do so OR
     352             :          * Signing is active OR
     353             :          * This is a compound SMB2 operation OR
     354             :          * fsp is a STREAM file OR
     355             :          * We're using a write cache OR
     356             :          * It's not a regular file OR
     357             :          * Requested offset is greater than file size OR
     358             :          * there's not enough data in the file.
     359             :          * Phew :-). Luckily this means most
     360             :          * reads on most normal files. JRA.
     361             :         */
     362             : 
     363         750 :         if (!lp__use_sendfile(SNUM(fsp->conn)) ||
     364           0 :             smb2req->do_signing ||
     365           0 :             smb2req->do_encryption ||
     366           0 :             smbd_smb2_is_compound(smb2req) ||
     367           0 :             (fsp->base_fsp != NULL) ||
     368           0 :             (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) ||
     369           0 :             (state->in_offset >= fsp->fsp_name->st.st_ex_size) ||
     370           0 :             (fsp->fsp_name->st.st_ex_size < state->in_offset + state->in_length))
     371             :         {
     372         750 :                 return NT_STATUS_RETRY;
     373             :         }
     374             : 
     375             :         /* We've already checked there's this amount of data
     376             :            to read. */
     377           0 :         state->out_data.length = state->in_length;
     378           0 :         state->out_remaining = 0;
     379             : 
     380           0 :         state->out_headers = data_blob_const(state->_out_hdr_buf,
     381             :                                              sizeof(state->_out_hdr_buf));
     382           0 :         return NT_STATUS_OK;
     383             : }
     384             : 
     385             : static void smbd_smb2_read_pipe_done(struct tevent_req *subreq);
     386             : 
     387             : /*******************************************************************
     388             :  Common read complete processing function for both synchronous and
     389             :  asynchronous reads.
     390             : *******************************************************************/
     391             : 
     392        3894 : NTSTATUS smb2_read_complete(struct tevent_req *req, ssize_t nread, int err)
     393             : {
     394        3894 :         struct smbd_smb2_read_state *state = tevent_req_data(req,
     395             :                                         struct smbd_smb2_read_state);
     396        3894 :         files_struct *fsp = state->fsp;
     397             : 
     398        3894 :         if (nread < 0) {
     399           0 :                 NTSTATUS status = map_nt_error_from_unix(err);
     400             : 
     401           0 :                 DEBUG( 3,( "smb2_read_complete: file %s nread = %d. "
     402             :                         "Error = %s (NTSTATUS %s)\n",
     403             :                         fsp_str_dbg(fsp),
     404             :                         (int)nread,
     405             :                         strerror(err),
     406             :                         nt_errstr(status)));
     407             : 
     408           0 :                 return status;
     409             :         }
     410        3894 :         if (nread == 0 && state->in_length != 0) {
     411         341 :                 DEBUG(5,("smb2_read_complete: read_file[%s] end of file\n",
     412             :                         fsp_str_dbg(fsp)));
     413         341 :                 return NT_STATUS_END_OF_FILE;
     414             :         }
     415             : 
     416        3553 :         if (nread < state->in_minimum) {
     417          20 :                 DEBUG(5,("smb2_read_complete: read_file[%s] read less %d than "
     418             :                         "minimum requested %u. Returning end of file\n",
     419             :                         fsp_str_dbg(fsp),
     420             :                         (int)nread,
     421             :                         (unsigned int)state->in_minimum));
     422          20 :                 return NT_STATUS_END_OF_FILE;
     423             :         }
     424             : 
     425        3533 :         DEBUG(3,("smbd_smb2_read: %s, file %s, length=%lu offset=%lu read=%lu\n",
     426             :                 fsp_fnum_dbg(fsp),
     427             :                 fsp_str_dbg(fsp),
     428             :                 (unsigned long)state->in_length,
     429             :                 (unsigned long)state->in_offset,
     430             :                 (unsigned long)nread));
     431             : 
     432        3533 :         state->out_data.length = nread;
     433        3533 :         state->out_remaining = 0;
     434             : 
     435        3533 :         return NT_STATUS_OK;
     436             : }
     437             : 
     438           2 : static bool smbd_smb2_read_cancel(struct tevent_req *req)
     439             : {
     440           2 :         struct smbd_smb2_read_state *state =
     441           2 :                 tevent_req_data(req,
     442             :                 struct smbd_smb2_read_state);
     443             : 
     444           2 :         return cancel_smb2_aio(state->smbreq);
     445             : }
     446             : 
     447       12092 : static struct tevent_req *smbd_smb2_read_send(TALLOC_CTX *mem_ctx,
     448             :                                               struct tevent_context *ev,
     449             :                                               struct smbd_smb2_request *smb2req,
     450             :                                               struct files_struct *fsp,
     451             :                                               uint8_t in_flags,
     452             :                                               uint32_t in_length,
     453             :                                               uint64_t in_offset,
     454             :                                               uint32_t in_minimum,
     455             :                                               uint32_t in_remaining)
     456             : {
     457             :         NTSTATUS status;
     458       12092 :         struct tevent_req *req = NULL;
     459       12092 :         struct smbd_smb2_read_state *state = NULL;
     460       12092 :         struct smb_request *smbreq = NULL;
     461       12092 :         connection_struct *conn = smb2req->tcon->compat;
     462       12092 :         ssize_t nread = -1;
     463             :         struct lock_struct lock;
     464             :         int saved_errno;
     465             : 
     466       12092 :         req = tevent_req_create(mem_ctx, &state,
     467             :                                 struct smbd_smb2_read_state);
     468       12092 :         if (req == NULL) {
     469           0 :                 return NULL;
     470             :         }
     471       12092 :         state->smb2req = smb2req;
     472       12092 :         state->in_flags = in_flags;
     473       12092 :         state->in_length = in_length;
     474       12092 :         state->in_offset = in_offset;
     475       12092 :         state->in_minimum = in_minimum;
     476       12092 :         state->out_data = data_blob_null;
     477       12092 :         state->out_remaining = 0;
     478             : 
     479       12092 :         DEBUG(10,("smbd_smb2_read: %s - %s\n",
     480             :                   fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
     481             : 
     482       12092 :         smbreq = smbd_smb2_fake_smb_request(smb2req);
     483       12092 :         if (tevent_req_nomem(smbreq, req)) {
     484           0 :                 return tevent_req_post(req, ev);
     485             :         }
     486       12092 :         state->smbreq = smbreq;
     487             : 
     488       12092 :         if (fsp->fsp_flags.is_directory) {
     489          16 :                 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
     490          16 :                 return tevent_req_post(req, ev);
     491             :         }
     492             : 
     493       12076 :         state->fsp = fsp;
     494             : 
     495       12076 :         if (IS_IPC(smbreq->conn)) {
     496        7990 :                 struct tevent_req *subreq = NULL;
     497             : 
     498        7990 :                 state->out_data = data_blob_talloc(state, NULL, in_length);
     499        7990 :                 if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) {
     500           0 :                         return tevent_req_post(req, ev);
     501             :                 }
     502             : 
     503        7990 :                 if (!fsp_is_np(fsp)) {
     504           0 :                         tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
     505           0 :                         return tevent_req_post(req, ev);
     506             :                 }
     507             : 
     508       15932 :                 subreq = np_read_send(state, ev,
     509             :                                       fsp->fake_file_handle,
     510        7942 :                                       state->out_data.data,
     511        7990 :                                       state->out_data.length);
     512        7990 :                 if (tevent_req_nomem(subreq, req)) {
     513           0 :                         return tevent_req_post(req, ev);
     514             :                 }
     515        7990 :                 tevent_req_set_callback(subreq,
     516             :                                         smbd_smb2_read_pipe_done,
     517             :                                         req);
     518        7990 :                 return req;
     519             :         }
     520             : 
     521        4086 :         if (!CHECK_READ_SMB2(fsp)) {
     522         164 :                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
     523         164 :                 return tevent_req_post(req, ev);
     524             :         }
     525             : 
     526        7844 :         status = schedule_smb2_aio_read(fsp->conn,
     527             :                                 smbreq,
     528             :                                 fsp,
     529             :                                 state,
     530        3922 :                                 &state->out_data,
     531             :                                 (off_t)in_offset,
     532             :                                 (size_t)in_length);
     533             : 
     534        3922 :         if (NT_STATUS_IS_OK(status)) {
     535             :                 /*
     536             :                  * Doing an async read, allow this
     537             :                  * request to be canceled
     538             :                  */
     539        3144 :                 tevent_req_set_cancel_fn(req, smbd_smb2_read_cancel);
     540        3144 :                 return req;
     541             :         }
     542             : 
     543         778 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
     544             :                 /* Real error in setting up aio. Fail. */
     545          28 :                 tevent_req_nterror(req, status);
     546          28 :                 return tevent_req_post(req, ev);
     547             :         }
     548             : 
     549             :         /* Fallback to synchronous. */
     550             : 
     551        1500 :         init_strict_lock_struct(fsp,
     552         750 :                                 fsp->op->global->open_persistent_id,
     553             :                                 in_offset,
     554             :                                 in_length,
     555             :                                 READ_LOCK,
     556             :                                 &lock);
     557             : 
     558         750 :         if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
     559           0 :                 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
     560           0 :                 return tevent_req_post(req, ev);
     561             :         }
     562             : 
     563             :         /* Try sendfile in preference. */
     564         750 :         status = schedule_smb2_sendfile_read(smb2req, state);
     565         750 :         if (NT_STATUS_IS_OK(status)) {
     566           0 :                 tevent_req_done(req);
     567           0 :                 return tevent_req_post(req, ev);
     568             :         } else {
     569         750 :                 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
     570           0 :                         tevent_req_nterror(req, status);
     571           0 :                         return tevent_req_post(req, ev);
     572             :                 }
     573             :         }
     574             : 
     575             :         /* Ok, read into memory. Allocate the out buffer. */
     576         750 :         state->out_data = data_blob_talloc(state, NULL, in_length);
     577         750 :         if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) {
     578           0 :                 return tevent_req_post(req, ev);
     579             :         }
     580             : 
     581        1500 :         nread = read_file(fsp,
     582         750 :                           (char *)state->out_data.data,
     583             :                           in_offset,
     584             :                           in_length);
     585             : 
     586         750 :         saved_errno = errno;
     587             : 
     588         750 :         DEBUG(10,("smbd_smb2_read: file %s, %s, offset=%llu "
     589             :                 "len=%llu returned %lld\n",
     590             :                 fsp_str_dbg(fsp),
     591             :                 fsp_fnum_dbg(fsp),
     592             :                 (unsigned long long)in_offset,
     593             :                 (unsigned long long)in_length,
     594             :                 (long long)nread));
     595             : 
     596         750 :         status = smb2_read_complete(req, nread, saved_errno);
     597         750 :         if (!NT_STATUS_IS_OK(status)) {
     598          20 :                 tevent_req_nterror(req, status);
     599             :         } else {
     600             :                 /* Success. */
     601         730 :                 tevent_req_done(req);
     602             :         }
     603         750 :         return tevent_req_post(req, ev);
     604             : }
     605             : 
     606        7990 : static void smbd_smb2_read_pipe_done(struct tevent_req *subreq)
     607             : {
     608        7990 :         struct tevent_req *req = tevent_req_callback_data(subreq,
     609             :                                  struct tevent_req);
     610        7990 :         struct smbd_smb2_read_state *state = tevent_req_data(req,
     611             :                                              struct smbd_smb2_read_state);
     612             :         NTSTATUS status;
     613        7990 :         ssize_t nread = -1;
     614             :         bool is_data_outstanding;
     615             : 
     616        7990 :         status = np_read_recv(subreq, &nread, &is_data_outstanding);
     617        7990 :         TALLOC_FREE(subreq);
     618        7990 :         if (!NT_STATUS_IS_OK(status)) {
     619           1 :                 NTSTATUS old = status;
     620           1 :                 status = nt_status_np_pipe(old);
     621           1 :                 tevent_req_nterror(req, status);
     622           1 :                 return;
     623             :         }
     624             : 
     625        7989 :         if (nread == 0 && state->out_data.length != 0) {
     626           0 :                 tevent_req_nterror(req, NT_STATUS_END_OF_FILE);
     627           0 :                 return;
     628             :         }
     629             : 
     630        7989 :         state->out_data.length = nread;
     631        7989 :         state->out_remaining = 0;
     632             : 
     633             :         /*
     634             :          * TODO: add STATUS_BUFFER_OVERFLOW handling, once we also
     635             :          * handle it in SMB1 pipe_read_andx_done().
     636             :          */
     637             : 
     638        7989 :         tevent_req_done(req);
     639             : }
     640             : 
     641       12092 : static NTSTATUS smbd_smb2_read_recv(struct tevent_req *req,
     642             :                                     TALLOC_CTX *mem_ctx,
     643             :                                     DATA_BLOB *out_data,
     644             :                                     uint32_t *out_remaining)
     645             : {
     646             :         NTSTATUS status;
     647       12092 :         struct smbd_smb2_read_state *state = tevent_req_data(req,
     648             :                                              struct smbd_smb2_read_state);
     649             : 
     650       12092 :         if (tevent_req_is_nterror(req, &status)) {
     651         570 :                 tevent_req_received(req);
     652         570 :                 return status;
     653             :         }
     654             : 
     655       11522 :         *out_data = state->out_data;
     656       11522 :         talloc_steal(mem_ctx, out_data->data);
     657       11522 :         *out_remaining = state->out_remaining;
     658             : 
     659       11522 :         if (state->out_headers.length > 0) {
     660           0 :                 talloc_steal(mem_ctx, state);
     661           0 :                 talloc_set_destructor(state, smb2_smb2_read_state_deny_destructor);
     662           0 :                 tevent_req_received(req);
     663           0 :                 state->smb2req->queue_entry.sendfile_header = &state->out_headers;
     664           0 :                 state->smb2req->queue_entry.sendfile_body_size = state->in_length;
     665           0 :                 talloc_set_destructor(state, smb2_sendfile_send_data);
     666             :         } else {
     667       11522 :                 tevent_req_received(req);
     668             :         }
     669             : 
     670       11522 :         return NT_STATUS_OK;
     671             : }

Generated by: LCOV version 1.13