LCOV - code coverage report
Current view: top level - source3/smbd - smb2_read.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 185 303 61.1 %
Date: 2024-04-21 15:09:00 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        7939 :                 in_flags                = CVAL(inbody, 0x03);
      72             :         } else {
      73        4732 :                 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 :         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           0 :         ssize_t nread;
     215           0 :         ssize_t ret;
     216           0 :         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         767 : static NTSTATUS schedule_smb2_sendfile_read(struct smbd_smb2_request *smb2req,
     346             :                                         struct smbd_smb2_read_state *state)
     347             : {
     348         767 :         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             :          * 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         767 :         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_is_alternate_stream(fsp) ||
     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         767 :                 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        4971 : NTSTATUS smb2_read_complete(struct tevent_req *req, ssize_t nread, int err)
     393             : {
     394        4971 :         struct smbd_smb2_read_state *state = tevent_req_data(req,
     395             :                                         struct smbd_smb2_read_state);
     396        4971 :         files_struct *fsp = state->fsp;
     397             : 
     398        4971 :         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        4971 :         if (nread == 0 && state->in_length != 0) {
     411         362 :                 DEBUG(5,("smb2_read_complete: read_file[%s] end of file\n",
     412             :                         fsp_str_dbg(fsp)));
     413         362 :                 return NT_STATUS_END_OF_FILE;
     414             :         }
     415             : 
     416        4609 :         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        4589 :         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        4589 :         state->out_data.length = nread;
     433        4589 :         state->out_remaining = 0;
     434             : 
     435        4589 :         return NT_STATUS_OK;
     436             : }
     437             : 
     438           2 : static bool smbd_smb2_read_cancel(struct tevent_req *req)
     439             : {
     440           0 :         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       12671 : 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          48 :         NTSTATUS status;
     458       12671 :         struct tevent_req *req = NULL;
     459       12671 :         struct smbd_smb2_read_state *state = NULL;
     460       12671 :         struct smb_request *smbreq = NULL;
     461       12671 :         connection_struct *conn = smb2req->tcon->compat;
     462       12671 :         ssize_t nread = -1;
     463          48 :         struct lock_struct lock;
     464          48 :         int saved_errno;
     465             : 
     466       12671 :         req = tevent_req_create(mem_ctx, &state,
     467             :                                 struct smbd_smb2_read_state);
     468       12671 :         if (req == NULL) {
     469           0 :                 return NULL;
     470             :         }
     471       12671 :         state->smb2req = smb2req;
     472       12671 :         state->in_flags = in_flags;
     473       12671 :         state->in_length = in_length;
     474       12671 :         state->in_offset = in_offset;
     475       12671 :         state->in_minimum = in_minimum;
     476       12671 :         state->out_data = data_blob_null;
     477       12671 :         state->out_remaining = 0;
     478             : 
     479       12671 :         DEBUG(10,("smbd_smb2_read: %s - %s\n",
     480             :                   fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
     481             : 
     482       12671 :         smbreq = smbd_smb2_fake_smb_request(smb2req, fsp);
     483       12671 :         if (tevent_req_nomem(smbreq, req)) {
     484           0 :                 return tevent_req_post(req, ev);
     485             :         }
     486       12671 :         state->smbreq = smbreq;
     487             : 
     488       12671 :         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       12655 :         state->fsp = fsp;
     494             : 
     495       12655 :         if (IS_IPC(smbreq->conn)) {
     496        7480 :                 struct tevent_req *subreq = NULL;
     497          48 :                 bool ok;
     498             : 
     499        7480 :                 state->out_data = data_blob_talloc(state, NULL, in_length);
     500        7480 :                 if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) {
     501           0 :                         return tevent_req_post(req, ev);
     502             :                 }
     503             : 
     504        7480 :                 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        7528 :                 subreq = np_read_send(state, ev,
     510             :                                       fsp->fake_file_handle,
     511        7432 :                                       state->out_data.data,
     512        7480 :                                       state->out_data.length);
     513        7480 :                 if (tevent_req_nomem(subreq, req)) {
     514           0 :                         return tevent_req_post(req, ev);
     515             :                 }
     516        7480 :                 tevent_req_set_callback(subreq,
     517             :                                         smbd_smb2_read_pipe_done,
     518             :                                         req);
     519             : 
     520             :                 /*
     521             :                  * Make sure we mark the fsp as having outstanding async
     522             :                  * activity so we don't crash on shutdown close.
     523             :                  */
     524             : 
     525        7480 :                 ok = aio_add_req_to_fsp(fsp, req);
     526        7480 :                 if (!ok) {
     527           0 :                         tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
     528           0 :                         return tevent_req_post(req, ev);
     529             :                 }
     530             : 
     531        7432 :                 return req;
     532             :         }
     533             : 
     534        5175 :         if (!CHECK_READ_SMB2(fsp)) {
     535         164 :                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
     536         164 :                 return tevent_req_post(req, ev);
     537             :         }
     538             : 
     539        5011 :         status = schedule_smb2_aio_read(fsp->conn,
     540             :                                 smbreq,
     541             :                                 fsp,
     542             :                                 state,
     543        5011 :                                 &state->out_data,
     544             :                                 (off_t)in_offset,
     545             :                                 (size_t)in_length);
     546             : 
     547        5011 :         if (NT_STATUS_IS_OK(status)) {
     548             :                 /*
     549             :                  * Doing an async read, allow this
     550             :                  * request to be canceled
     551             :                  */
     552        4204 :                 tevent_req_set_cancel_fn(req, smbd_smb2_read_cancel);
     553        4204 :                 return req;
     554             :         }
     555             : 
     556         807 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
     557             :                 /* Real error in setting up aio. Fail. */
     558          40 :                 tevent_req_nterror(req, status);
     559          40 :                 return tevent_req_post(req, ev);
     560             :         }
     561             : 
     562             :         /* Fallback to synchronous. */
     563             : 
     564         767 :         init_strict_lock_struct(fsp,
     565         767 :                                 fsp->op->global->open_persistent_id,
     566             :                                 in_offset,
     567             :                                 in_length,
     568             :                                 READ_LOCK,
     569             :                                 lp_posix_cifsu_locktype(fsp),
     570             :                                 &lock);
     571             : 
     572         767 :         if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
     573           0 :                 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
     574           0 :                 return tevent_req_post(req, ev);
     575             :         }
     576             : 
     577             :         /* Try sendfile in preference. */
     578         767 :         status = schedule_smb2_sendfile_read(smb2req, state);
     579         767 :         if (NT_STATUS_IS_OK(status)) {
     580           0 :                 tevent_req_done(req);
     581           0 :                 return tevent_req_post(req, ev);
     582             :         } else {
     583         767 :                 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
     584           0 :                         tevent_req_nterror(req, status);
     585           0 :                         return tevent_req_post(req, ev);
     586             :                 }
     587             :         }
     588             : 
     589             :         /* Ok, read into memory. Allocate the out buffer. */
     590         767 :         state->out_data = data_blob_talloc(state, NULL, in_length);
     591         767 :         if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) {
     592           0 :                 return tevent_req_post(req, ev);
     593             :         }
     594             : 
     595         767 :         nread = read_file(fsp,
     596         767 :                           (char *)state->out_data.data,
     597             :                           in_offset,
     598             :                           in_length);
     599             : 
     600         767 :         saved_errno = errno;
     601             : 
     602         767 :         DEBUG(10,("smbd_smb2_read: file %s, %s, offset=%llu "
     603             :                 "len=%llu returned %lld\n",
     604             :                 fsp_str_dbg(fsp),
     605             :                 fsp_fnum_dbg(fsp),
     606             :                 (unsigned long long)in_offset,
     607             :                 (unsigned long long)in_length,
     608             :                 (long long)nread));
     609             : 
     610         767 :         status = smb2_read_complete(req, nread, saved_errno);
     611         767 :         if (!NT_STATUS_IS_OK(status)) {
     612          20 :                 tevent_req_nterror(req, status);
     613             :         } else {
     614             :                 /* Success. */
     615         747 :                 tevent_req_done(req);
     616             :         }
     617         767 :         return tevent_req_post(req, ev);
     618             : }
     619             : 
     620        7480 : static void smbd_smb2_read_pipe_done(struct tevent_req *subreq)
     621             : {
     622        7480 :         struct tevent_req *req = tevent_req_callback_data(subreq,
     623             :                                  struct tevent_req);
     624        7480 :         struct smbd_smb2_read_state *state = tevent_req_data(req,
     625             :                                              struct smbd_smb2_read_state);
     626          48 :         NTSTATUS status;
     627        7480 :         ssize_t nread = -1;
     628          48 :         bool is_data_outstanding;
     629             : 
     630        7480 :         status = np_read_recv(subreq, &nread, &is_data_outstanding);
     631        7480 :         TALLOC_FREE(subreq);
     632        7480 :         if (!NT_STATUS_IS_OK(status)) {
     633           3 :                 NTSTATUS old = status;
     634           3 :                 status = nt_status_np_pipe(old);
     635           3 :                 tevent_req_nterror(req, status);
     636           3 :                 return;
     637             :         }
     638             : 
     639        7477 :         if (nread == 0 && state->out_data.length != 0) {
     640           0 :                 tevent_req_nterror(req, NT_STATUS_END_OF_FILE);
     641           0 :                 return;
     642             :         }
     643             : 
     644        7477 :         state->out_data.length = nread;
     645        7477 :         state->out_remaining = 0;
     646             : 
     647             :         /*
     648             :          * TODO: add STATUS_BUFFER_OVERFLOW handling, once we also
     649             :          * handle it in SMB1 pipe_read_andx_done().
     650             :          */
     651             : 
     652        7477 :         tevent_req_done(req);
     653             : }
     654             : 
     655       12671 : static NTSTATUS smbd_smb2_read_recv(struct tevent_req *req,
     656             :                                     TALLOC_CTX *mem_ctx,
     657             :                                     DATA_BLOB *out_data,
     658             :                                     uint32_t *out_remaining)
     659             : {
     660          48 :         NTSTATUS status;
     661       12671 :         struct smbd_smb2_read_state *state = tevent_req_data(req,
     662             :                                              struct smbd_smb2_read_state);
     663             : 
     664       12671 :         if (tevent_req_is_nterror(req, &status)) {
     665         605 :                 tevent_req_received(req);
     666         605 :                 return status;
     667             :         }
     668             : 
     669       12066 :         *out_data = state->out_data;
     670       12066 :         talloc_steal(mem_ctx, out_data->data);
     671       12066 :         *out_remaining = state->out_remaining;
     672             : 
     673       12066 :         if (state->out_headers.length > 0) {
     674           0 :                 talloc_steal(mem_ctx, state);
     675           0 :                 talloc_set_destructor(state, smb2_smb2_read_state_deny_destructor);
     676           0 :                 tevent_req_received(req);
     677           0 :                 state->smb2req->queue_entry.sendfile_header = &state->out_headers;
     678           0 :                 state->smb2req->queue_entry.sendfile_body_size = state->in_length;
     679           0 :                 talloc_set_destructor(state, smb2_sendfile_send_data);
     680             :         } else {
     681       12066 :                 tevent_req_received(req);
     682             :         }
     683             : 
     684       12066 :         return NT_STATUS_OK;
     685             : }

Generated by: LCOV version 1.14