LCOV - code coverage report
Current view: top level - source3/smbd - smb2_read.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 185 300 61.7 %
Date: 2024-05-31 13:13:24 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       12671 : NTSTATUS smbd_smb2_request_process_read(struct smbd_smb2_request *req)
      50             : {
      51       12671 :         struct smbXsrv_connection *xconn = req->xconn;
      52          48 :         NTSTATUS status;
      53          48 :         const uint8_t *inbody;
      54          48 :         uint8_t in_flags;
      55          48 :         uint32_t in_length;
      56          48 :         uint64_t in_offset;
      57          48 :         uint64_t in_file_id_persistent;
      58          48 :         uint64_t in_file_id_volatile;
      59          48 :         struct files_struct *in_fsp;
      60          48 :         uint32_t in_minimum_count;
      61          48 :         uint32_t in_remaining_bytes;
      62          48 :         struct tevent_req *subreq;
      63             : 
      64       12671 :         status = smbd_smb2_request_verify_sizes(req, 0x31);
      65       12671 :         if (!NT_STATUS_IS_OK(status)) {
      66           0 :                 return smbd_smb2_request_error(req, status);
      67             :         }
      68       12671 :         inbody = SMBD_SMB2_IN_BODY_PTR(req);
      69             : 
      70       12671 :         if (xconn->protocol >= PROTOCOL_SMB3_02) {
      71        7952 :                 in_flags                = CVAL(inbody, 0x03);
      72             :         } else {
      73        4719 :                 in_flags                = 0;
      74             :         }
      75       12671 :         in_length               = IVAL(inbody, 0x04);
      76       12671 :         in_offset               = BVAL(inbody, 0x08);
      77       12671 :         in_file_id_persistent   = BVAL(inbody, 0x10);
      78       12671 :         in_file_id_volatile     = BVAL(inbody, 0x18);
      79       12671 :         in_minimum_count        = IVAL(inbody, 0x20);
      80       12671 :         in_remaining_bytes      = IVAL(inbody, 0x28);
      81             : 
      82             :         /* check the max read size */
      83       12671 :         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       12671 :         status = smbd_smb2_request_verify_creditcharge(req, in_length);
      91       12671 :         if (!NT_STATUS_IS_OK(status)) {
      92           0 :                 return smbd_smb2_request_error(req, status);
      93             :         }
      94             : 
      95       12671 :         in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
      96       12671 :         if (in_fsp == NULL) {
      97           0 :                 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
      98             :         }
      99             : 
     100       12671 :         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       12671 :         if (subreq == NULL) {
     108           0 :                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
     109             :         }
     110       12671 :         tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
     111             : 
     112       12671 :         return smbd_smb2_request_pending_queue(req, subreq, 500);
     113             : }
     114             : 
     115       12671 : static void smbd_smb2_request_read_done(struct tevent_req *subreq)
     116             : {
     117       12671 :         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
     118             :                                         struct smbd_smb2_request);
     119          48 :         uint16_t body_size;
     120       12671 :         uint8_t body_padding = req->xconn->smb2.smbtorture.read_body_padding;
     121          48 :         DATA_BLOB outbody;
     122          48 :         DATA_BLOB outdyn;
     123          48 :         uint8_t out_data_offset;
     124       12671 :         DATA_BLOB out_data_buffer = data_blob_null;
     125       12671 :         uint32_t out_data_remaining = 0;
     126          48 :         NTSTATUS status;
     127          48 :         NTSTATUS error; /* transport error */
     128             : 
     129       12671 :         status = smbd_smb2_read_recv(subreq,
     130             :                                      req,
     131             :                                      &out_data_buffer,
     132             :                                      &out_data_remaining);
     133       12671 :         TALLOC_FREE(subreq);
     134       12671 :         if (!NT_STATUS_IS_OK(status)) {
     135         605 :                 error = smbd_smb2_request_error(req, status);
     136         605 :                 if (!NT_STATUS_IS_OK(error)) {
     137           0 :                         smbd_server_connection_terminate(req->xconn,
     138             :                                                          nt_errstr(error));
     139         605 :                         return;
     140             :                 }
     141         605 :                 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       12066 :         body_size = 0x10 + body_padding;
     149       12066 :         out_data_offset = SMB2_HDR_BODY + body_size;
     150             : 
     151       12066 :         outbody = smbd_smb2_generate_outbody(req, body_size);
     152       12066 :         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       12066 :         SSVAL(outbody.data, 0x00, 0x10 + 1);    /* struct size */
     163       12066 :         SCVAL(outbody.data, 0x02,
     164             :               out_data_offset);                 /* data offset */
     165       12066 :         SCVAL(outbody.data, 0x03, 0);           /* reserved */
     166       12066 :         SIVAL(outbody.data, 0x04,
     167             :               out_data_buffer.length);          /* data length */
     168       12066 :         SIVAL(outbody.data, 0x08,
     169             :               out_data_remaining);              /* data remaining */
     170       12066 :         SIVAL(outbody.data, 0x0C, 0);           /* reserved */
     171       12066 :         if (body_padding != 0) {
     172           8 :                 memset(outbody.data + 0x10, 0, body_padding);
     173             :         }
     174             : 
     175       12066 :         outdyn = out_data_buffer;
     176             : 
     177       12066 :         error = smbd_smb2_request_done(req, outbody, &outdyn);
     178       12066 :         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           0 :         uint32_t in_length = state->in_length;
     208           0 :         uint64_t in_offset = state->in_offset;
     209           0 :         files_struct *fsp = state->fsp;
     210           0 :         const DATA_BLOB *hdr = state->smb2req->queue_entry.sendfile_header;
     211           0 :         NTSTATUS *pstatus = state->smb2req->queue_entry.sendfile_status;
     212           0 :         struct smbXsrv_connection *xconn = state->smb2req->xconn;
     213           0 :         ssize_t nread;
     214           0 :         ssize_t ret;
     215           0 :         int saved_errno;
     216             : 
     217           0 :         nread = SMB_VFS_SENDFILE(xconn->transport.sock,
     218             :                                  fsp,
     219             :                                  hdr,
     220             :                                  in_offset,
     221             :                                  in_length);
     222           0 :         DBG_DEBUG("SMB_VFS_SENDFILE returned %zd on file %s\n",
     223             :                   nread,
     224             :                   fsp_str_dbg(fsp));
     225             : 
     226           0 :         if (nread == -1) {
     227           0 :                 saved_errno = errno;
     228             : 
     229             :                 /*
     230             :                  * Returning ENOSYS means no data at all was sent.
     231             :                    Do this as a normal read. */
     232           0 :                 if (errno == ENOSYS) {
     233           0 :                         goto normal_read;
     234             :                 }
     235             : 
     236           0 :                 if (errno == ENOTSUP) {
     237           0 :                         set_use_sendfile(SNUM(fsp->conn), false);
     238           0 :                         DBG_WARNING("Disabling sendfile use as sendfile is "
     239             :                                     "not supported by the system\n");
     240           0 :                         goto normal_read;
     241             :                 }
     242             : 
     243           0 :                 if (errno == EINTR) {
     244             :                         /*
     245             :                          * Special hack for broken Linux with no working sendfile. If we
     246             :                          * return EINTR we sent the header but not the rest of the data.
     247             :                          * Fake this up by doing read/write calls.
     248             :                          */
     249           0 :                         set_use_sendfile(SNUM(fsp->conn), false);
     250           0 :                         nread = fake_sendfile(xconn, fsp, in_offset, in_length);
     251           0 :                         if (nread == -1) {
     252           0 :                                 saved_errno = errno;
     253           0 :                                 DBG_ERR("fake_sendfile failed for file %s "
     254             :                                         "(%s) for client %s. Terminating\n",
     255             :                                         fsp_str_dbg(fsp),
     256             :                                         strerror(saved_errno),
     257             :                                         smbXsrv_connection_dbg(xconn));
     258           0 :                                 *pstatus = map_nt_error_from_unix_common(saved_errno);
     259           0 :                                 return 0;
     260             :                         }
     261           0 :                         goto out;
     262             :                 }
     263             : 
     264           0 :                 DBG_ERR("sendfile failed for file "
     265             :                         "%s (%s) for client %s. Terminating\n",
     266             :                         fsp_str_dbg(fsp),
     267             :                         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 :                 DBG_NOTICE("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 :                 DBG_ERR("write_data failed for file "
     297             :                         "%s (%s) for client %s. Terminating\n",
     298             :                         fsp_str_dbg(fsp),
     299             :                         strerror(saved_errno),
     300             :                         smbXsrv_connection_dbg(xconn));
     301           0 :                 *pstatus = map_nt_error_from_unix_common(saved_errno);
     302           0 :                 return 0;
     303             :         }
     304           0 :         nread = fake_sendfile(xconn, fsp, in_offset, in_length);
     305           0 :         if (nread == -1) {
     306           0 :                 saved_errno = errno;
     307           0 :                 DBG_ERR("fake_sendfile failed for file %s (%s) for client %s. "
     308             :                         "Terminating\n",
     309             :                         fsp_str_dbg(fsp),
     310             :                         strerror(saved_errno),
     311             :                         smbXsrv_connection_dbg(xconn));
     312           0 :                 *pstatus = map_nt_error_from_unix_common(saved_errno);
     313           0 :                 return 0;
     314             :         }
     315             : 
     316           0 :   out:
     317             : 
     318           0 :         if (nread < in_length) {
     319           0 :                 ret = sendfile_short_send(xconn, fsp, nread,
     320           0 :                                           hdr->length, in_length);
     321           0 :                 if (ret == -1) {
     322           0 :                         saved_errno = errno;
     323           0 :                         DBG_ERR("sendfile_short_send "
     324             :                                 "failed for file %s (%s) for client %s. "
     325             :                                 "Terminating\n",
     326             :                                 fsp_str_dbg(fsp),
     327             :                                 strerror(saved_errno),
     328             :                                 smbXsrv_connection_dbg(xconn));
     329           0 :                         *pstatus = map_nt_error_from_unix_common(saved_errno);
     330           0 :                         return 0;
     331             :                 }
     332             :         }
     333             : 
     334           0 :         *pstatus = NT_STATUS_OK;
     335           0 :         return 0;
     336             : }
     337             : 
     338         767 : static NTSTATUS schedule_smb2_sendfile_read(struct smbd_smb2_request *smb2req,
     339             :                                         struct smbd_smb2_read_state *state)
     340             : {
     341         767 :         files_struct *fsp = state->fsp;
     342             : 
     343             :         /*
     344             :          * We cannot use sendfile if...
     345             :          * We were not configured to do so OR
     346             :          * Signing is active OR
     347             :          * This is a compound SMB2 operation OR
     348             :          * fsp is a STREAM file OR
     349             :          * It's not a regular file OR
     350             :          * Requested offset is greater than file size OR
     351             :          * there's not enough data in the file.
     352             :          * Phew :-). Luckily this means most
     353             :          * reads on most normal files. JRA.
     354             :         */
     355             : 
     356         767 :         if (!lp__use_sendfile(SNUM(fsp->conn)) ||
     357           0 :             smb2req->do_signing ||
     358           0 :             smb2req->do_encryption ||
     359           0 :             smbd_smb2_is_compound(smb2req) ||
     360           0 :             fsp_is_alternate_stream(fsp) ||
     361           0 :             (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) ||
     362           0 :             (state->in_offset >= fsp->fsp_name->st.st_ex_size) ||
     363           0 :             (fsp->fsp_name->st.st_ex_size < state->in_offset + state->in_length))
     364             :         {
     365         767 :                 return NT_STATUS_RETRY;
     366             :         }
     367             : 
     368             :         /* We've already checked there's this amount of data
     369             :            to read. */
     370           0 :         state->out_data.length = state->in_length;
     371           0 :         state->out_remaining = 0;
     372             : 
     373           0 :         state->out_headers = data_blob_const(state->_out_hdr_buf,
     374             :                                              sizeof(state->_out_hdr_buf));
     375           0 :         return NT_STATUS_OK;
     376             : }
     377             : 
     378             : static void smbd_smb2_read_pipe_done(struct tevent_req *subreq);
     379             : 
     380             : /*******************************************************************
     381             :  Common read complete processing function for both synchronous and
     382             :  asynchronous reads.
     383             : *******************************************************************/
     384             : 
     385        4973 : NTSTATUS smb2_read_complete(struct tevent_req *req, ssize_t nread, int err)
     386             : {
     387        4973 :         struct smbd_smb2_read_state *state = tevent_req_data(req,
     388             :                                         struct smbd_smb2_read_state);
     389        4973 :         files_struct *fsp = state->fsp;
     390             : 
     391        4973 :         if (nread < 0) {
     392           0 :                 NTSTATUS status = map_nt_error_from_unix(err);
     393             : 
     394           0 :                 DEBUG( 3,( "smb2_read_complete: file %s nread = %d. "
     395             :                         "Error = %s (NTSTATUS %s)\n",
     396             :                         fsp_str_dbg(fsp),
     397             :                         (int)nread,
     398             :                         strerror(err),
     399             :                         nt_errstr(status)));
     400             : 
     401           0 :                 return status;
     402             :         }
     403        4973 :         if (nread == 0 && state->in_length != 0) {
     404         362 :                 DEBUG(5,("smb2_read_complete: read_file[%s] end of file\n",
     405             :                         fsp_str_dbg(fsp)));
     406         362 :                 return NT_STATUS_END_OF_FILE;
     407             :         }
     408             : 
     409        4611 :         if (nread < state->in_minimum) {
     410          20 :                 DEBUG(5,("smb2_read_complete: read_file[%s] read less %d than "
     411             :                         "minimum requested %u. Returning end of file\n",
     412             :                         fsp_str_dbg(fsp),
     413             :                         (int)nread,
     414             :                         (unsigned int)state->in_minimum));
     415          20 :                 return NT_STATUS_END_OF_FILE;
     416             :         }
     417             : 
     418        4591 :         DEBUG(3,("smbd_smb2_read: %s, file %s, length=%lu offset=%lu read=%lu\n",
     419             :                 fsp_fnum_dbg(fsp),
     420             :                 fsp_str_dbg(fsp),
     421             :                 (unsigned long)state->in_length,
     422             :                 (unsigned long)state->in_offset,
     423             :                 (unsigned long)nread));
     424             : 
     425        4591 :         state->out_data.length = nread;
     426        4591 :         state->out_remaining = 0;
     427             : 
     428        4591 :         return NT_STATUS_OK;
     429             : }
     430             : 
     431           2 : static bool smbd_smb2_read_cancel(struct tevent_req *req)
     432             : {
     433           0 :         struct smbd_smb2_read_state *state =
     434           2 :                 tevent_req_data(req,
     435             :                 struct smbd_smb2_read_state);
     436             : 
     437           2 :         return cancel_smb2_aio(state->smbreq);
     438             : }
     439             : 
     440       12671 : static struct tevent_req *smbd_smb2_read_send(TALLOC_CTX *mem_ctx,
     441             :                                               struct tevent_context *ev,
     442             :                                               struct smbd_smb2_request *smb2req,
     443             :                                               struct files_struct *fsp,
     444             :                                               uint8_t in_flags,
     445             :                                               uint32_t in_length,
     446             :                                               uint64_t in_offset,
     447             :                                               uint32_t in_minimum,
     448             :                                               uint32_t in_remaining)
     449             : {
     450          48 :         NTSTATUS status;
     451       12671 :         struct tevent_req *req = NULL;
     452       12671 :         struct smbd_smb2_read_state *state = NULL;
     453       12671 :         struct smb_request *smbreq = NULL;
     454       12671 :         connection_struct *conn = smb2req->tcon->compat;
     455       12671 :         ssize_t nread = -1;
     456          48 :         struct lock_struct lock;
     457          48 :         int saved_errno;
     458             : 
     459       12671 :         req = tevent_req_create(mem_ctx, &state,
     460             :                                 struct smbd_smb2_read_state);
     461       12671 :         if (req == NULL) {
     462           0 :                 return NULL;
     463             :         }
     464       12671 :         state->smb2req = smb2req;
     465       12671 :         state->in_flags = in_flags;
     466       12671 :         state->in_length = in_length;
     467       12671 :         state->in_offset = in_offset;
     468       12671 :         state->in_minimum = in_minimum;
     469       12671 :         state->out_data = data_blob_null;
     470       12671 :         state->out_remaining = 0;
     471             : 
     472       12671 :         DEBUG(10,("smbd_smb2_read: %s - %s\n",
     473             :                   fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
     474             : 
     475       12671 :         smbreq = smbd_smb2_fake_smb_request(smb2req, fsp);
     476       12671 :         if (tevent_req_nomem(smbreq, req)) {
     477           0 :                 return tevent_req_post(req, ev);
     478             :         }
     479       12671 :         state->smbreq = smbreq;
     480             : 
     481       12671 :         if (fsp->fsp_flags.is_directory) {
     482          16 :                 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
     483          16 :                 return tevent_req_post(req, ev);
     484             :         }
     485             : 
     486       12655 :         state->fsp = fsp;
     487             : 
     488       12655 :         if (IS_IPC(smbreq->conn)) {
     489        7478 :                 struct tevent_req *subreq = NULL;
     490          48 :                 bool ok;
     491             : 
     492        7478 :                 state->out_data = data_blob_talloc(state, NULL, in_length);
     493        7478 :                 if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) {
     494           0 :                         return tevent_req_post(req, ev);
     495             :                 }
     496             : 
     497        7478 :                 if (!fsp_is_np(fsp)) {
     498           0 :                         tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
     499           0 :                         return tevent_req_post(req, ev);
     500             :                 }
     501             : 
     502        7526 :                 subreq = np_read_send(state, ev,
     503             :                                       fsp->fake_file_handle,
     504        7430 :                                       state->out_data.data,
     505        7478 :                                       state->out_data.length);
     506        7478 :                 if (tevent_req_nomem(subreq, req)) {
     507           0 :                         return tevent_req_post(req, ev);
     508             :                 }
     509        7478 :                 tevent_req_set_callback(subreq,
     510             :                                         smbd_smb2_read_pipe_done,
     511             :                                         req);
     512             : 
     513             :                 /*
     514             :                  * Make sure we mark the fsp as having outstanding async
     515             :                  * activity so we don't crash on shutdown close.
     516             :                  */
     517             : 
     518        7478 :                 ok = aio_add_req_to_fsp(fsp, req);
     519        7478 :                 if (!ok) {
     520           0 :                         tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
     521           0 :                         return tevent_req_post(req, ev);
     522             :                 }
     523             : 
     524        7430 :                 return req;
     525             :         }
     526             : 
     527        5177 :         if (!CHECK_READ_SMB2(fsp)) {
     528         164 :                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
     529         164 :                 return tevent_req_post(req, ev);
     530             :         }
     531             : 
     532        5013 :         status = schedule_smb2_aio_read(fsp->conn,
     533             :                                 smbreq,
     534             :                                 fsp,
     535             :                                 state,
     536        5013 :                                 &state->out_data,
     537             :                                 (off_t)in_offset,
     538             :                                 (size_t)in_length);
     539             : 
     540        5013 :         if (NT_STATUS_IS_OK(status)) {
     541             :                 /*
     542             :                  * Doing an async read, allow this
     543             :                  * request to be canceled
     544             :                  */
     545        4206 :                 tevent_req_set_cancel_fn(req, smbd_smb2_read_cancel);
     546        4206 :                 return req;
     547             :         }
     548             : 
     549         807 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
     550             :                 /* Real error in setting up aio. Fail. */
     551          40 :                 tevent_req_nterror(req, status);
     552          40 :                 return tevent_req_post(req, ev);
     553             :         }
     554             : 
     555             :         /* Fallback to synchronous. */
     556             : 
     557         767 :         init_strict_lock_struct(fsp,
     558         767 :                                 fsp->op->global->open_persistent_id,
     559             :                                 in_offset,
     560             :                                 in_length,
     561             :                                 READ_LOCK,
     562             :                                 lp_posix_cifsu_locktype(fsp),
     563             :                                 &lock);
     564             : 
     565         767 :         if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
     566           0 :                 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
     567           0 :                 return tevent_req_post(req, ev);
     568             :         }
     569             : 
     570             :         /* Try sendfile in preference. */
     571         767 :         status = schedule_smb2_sendfile_read(smb2req, state);
     572         767 :         if (NT_STATUS_IS_OK(status)) {
     573           0 :                 tevent_req_done(req);
     574           0 :                 return tevent_req_post(req, ev);
     575             :         }
     576         767 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
     577           0 :                 tevent_req_nterror(req, status);
     578           0 :                 return tevent_req_post(req, ev);
     579             :         }
     580             : 
     581             :         /* Ok, read into memory. Allocate the out buffer. */
     582         767 :         state->out_data = data_blob_talloc(state, NULL, in_length);
     583         767 :         if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) {
     584           0 :                 return tevent_req_post(req, ev);
     585             :         }
     586             : 
     587         767 :         nread = read_file(fsp,
     588         767 :                           (char *)state->out_data.data,
     589             :                           in_offset,
     590             :                           in_length);
     591             : 
     592         767 :         saved_errno = errno;
     593             : 
     594         767 :         DEBUG(10,("smbd_smb2_read: file %s, %s, offset=%llu "
     595             :                 "len=%llu returned %lld\n",
     596             :                 fsp_str_dbg(fsp),
     597             :                 fsp_fnum_dbg(fsp),
     598             :                 (unsigned long long)in_offset,
     599             :                 (unsigned long long)in_length,
     600             :                 (long long)nread));
     601             : 
     602         767 :         status = smb2_read_complete(req, nread, saved_errno);
     603         767 :         if (!NT_STATUS_IS_OK(status)) {
     604          20 :                 tevent_req_nterror(req, status);
     605             :         } else {
     606             :                 /* Success. */
     607         747 :                 tevent_req_done(req);
     608             :         }
     609         767 :         return tevent_req_post(req, ev);
     610             : }
     611             : 
     612        7478 : static void smbd_smb2_read_pipe_done(struct tevent_req *subreq)
     613             : {
     614        7478 :         struct tevent_req *req = tevent_req_callback_data(subreq,
     615             :                                  struct tevent_req);
     616        7478 :         struct smbd_smb2_read_state *state = tevent_req_data(req,
     617             :                                              struct smbd_smb2_read_state);
     618          48 :         NTSTATUS status;
     619        7478 :         ssize_t nread = -1;
     620          48 :         bool is_data_outstanding;
     621             : 
     622        7478 :         status = np_read_recv(subreq, &nread, &is_data_outstanding);
     623        7478 :         TALLOC_FREE(subreq);
     624        7478 :         if (!NT_STATUS_IS_OK(status)) {
     625           3 :                 NTSTATUS old = status;
     626           3 :                 status = nt_status_np_pipe(old);
     627           3 :                 tevent_req_nterror(req, status);
     628           3 :                 return;
     629             :         }
     630             : 
     631        7475 :         if (nread == 0 && state->out_data.length != 0) {
     632           0 :                 tevent_req_nterror(req, NT_STATUS_END_OF_FILE);
     633           0 :                 return;
     634             :         }
     635             : 
     636        7475 :         state->out_data.length = nread;
     637        7475 :         state->out_remaining = 0;
     638             : 
     639             :         /*
     640             :          * TODO: add STATUS_BUFFER_OVERFLOW handling, once we also
     641             :          * handle it in SMB1 pipe_read_andx_done().
     642             :          */
     643             : 
     644        7475 :         tevent_req_done(req);
     645             : }
     646             : 
     647       12671 : static NTSTATUS smbd_smb2_read_recv(struct tevent_req *req,
     648             :                                     TALLOC_CTX *mem_ctx,
     649             :                                     DATA_BLOB *out_data,
     650             :                                     uint32_t *out_remaining)
     651             : {
     652          48 :         NTSTATUS status;
     653       12671 :         struct smbd_smb2_read_state *state = tevent_req_data(req,
     654             :                                              struct smbd_smb2_read_state);
     655             : 
     656       12671 :         if (tevent_req_is_nterror(req, &status)) {
     657         605 :                 tevent_req_received(req);
     658         605 :                 return status;
     659             :         }
     660             : 
     661       12066 :         *out_data = state->out_data;
     662       12066 :         talloc_steal(mem_ctx, out_data->data);
     663       12066 :         *out_remaining = state->out_remaining;
     664             : 
     665       12066 :         if (state->out_headers.length > 0) {
     666           0 :                 talloc_steal(mem_ctx, state);
     667           0 :                 talloc_set_destructor(state, smb2_smb2_read_state_deny_destructor);
     668           0 :                 tevent_req_received(req);
     669           0 :                 state->smb2req->queue_entry.sendfile_header = &state->out_headers;
     670           0 :                 state->smb2req->queue_entry.sendfile_body_size = state->in_length;
     671           0 :                 talloc_set_destructor(state, smb2_sendfile_send_data);
     672             :         } else {
     673       12066 :                 tevent_req_received(req);
     674             :         }
     675             : 
     676       12066 :         return NT_STATUS_OK;
     677             : }

Generated by: LCOV version 1.14