LCOV - code coverage report
Current view: top level - libcli/smb - smb1cli_read.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 51 86 59.3 %
Date: 2024-02-28 12:06:22 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Copyright (C) Gregor Beck 2013
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include "system/network.h"
      22             : #include "lib/util/tevent_ntstatus.h"
      23             : #include "smb_common.h"
      24             : #include "smbXcli_base.h"
      25             : 
      26             : struct smb1cli_readx_state {
      27             :         uint32_t size;
      28             :         uint16_t vwv[12];
      29             :         uint32_t received;
      30             :         uint8_t *buf;
      31             :         bool out_valid;
      32             : };
      33             : 
      34             : static void smb1cli_readx_done(struct tevent_req *subreq);
      35             : 
      36             : /**
      37             :  * Send an asynchrounus SMB_COM_READ_ANDX request.
      38             :  * <a href="http://msdn.microsoft.com/en-us/library/ee441839.aspx">MS-CIFS 2.2.4.42.1</a>,
      39             :  * <a href="http://msdn.microsoft.com/en-us/library/ff470250.aspx">MS-SMB 2.2.4.2.1</a>
      40             :  * @see smb1cli_readx_recv()
      41             :  * @todo fix API (min/max size, timeout)
      42             :  *
      43             :  * @param[in] mem_ctx The memory context for the result.
      44             :  * @param[in] ev The event context to work on.
      45             :  * @param[in] conn The smb connection.
      46             :  * @param[in] timeout_msec If positive a timeout for the request.
      47             :  * @param[in] pid The process identifier
      48             :  * @param[in] tcon The smb tree connect.
      49             :  * @param[in] session The smb session.
      50             :  * @param[in] fnum The file id of the file the data should be read from.
      51             :  * @param[in] offset The offset in bytes from the begin of file where to start reading.
      52             :  * @param[in] size The number of bytes to read.
      53             :  *
      54             :  * @return a tevent_req or NULL
      55             :  */
      56          34 : struct tevent_req *smb1cli_readx_send(TALLOC_CTX *mem_ctx,
      57             :                                       struct tevent_context *ev,
      58             :                                       struct smbXcli_conn *conn,
      59             :                                       uint32_t timeout_msec,
      60             :                                       uint32_t pid,
      61             :                                       struct smbXcli_tcon *tcon,
      62             :                                       struct smbXcli_session *session,
      63             :                                       uint16_t fnum,
      64             :                                       uint64_t offset,
      65             :                                       uint32_t size)
      66             : {
      67           0 :         NTSTATUS status;
      68           0 :         struct tevent_req *req, *subreq;
      69           0 :         struct smb1cli_readx_state *state;
      70          34 :         uint8_t wct = 10;
      71             : 
      72          34 :         req = tevent_req_create(mem_ctx, &state, struct smb1cli_readx_state);
      73          34 :         if (req == NULL) {
      74           0 :                 return NULL;
      75             :         }
      76          34 :         state->size = size;
      77             : 
      78          34 :         SCVAL(state->vwv + 0, 0, 0xFF);
      79          34 :         SCVAL(state->vwv + 0, 1, 0);
      80          34 :         SSVAL(state->vwv + 1, 0, 0);
      81          34 :         SSVAL(state->vwv + 2, 0, fnum);
      82          34 :         SIVAL(state->vwv + 3, 0, offset);
      83          34 :         SSVAL(state->vwv + 5, 0, size);
      84          34 :         SSVAL(state->vwv + 6, 0, size);
      85          34 :         SSVAL(state->vwv + 7, 0, (size >> 16));
      86          34 :         SSVAL(state->vwv + 8, 0, 0);
      87          34 :         SSVAL(state->vwv + 9, 0, 0);
      88             : 
      89          34 :         if (smb1cli_conn_capabilities(conn) & CAP_LARGE_FILES) {
      90          34 :                 SIVAL(state->vwv + 10, 0,
      91             :                       (((uint64_t)offset)>>32) & 0xffffffff);
      92          34 :                 wct = 12;
      93             :         } else {
      94           0 :                 if ((((uint64_t)offset) & 0xffffffff00000000LL) != 0) {
      95           0 :                         DEBUG(10, ("smb1cli_readx_send got large offset where "
      96             :                                    "the server does not support it\n"));
      97           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
      98           0 :                         return tevent_req_post(req, ev);
      99             :                 }
     100             :         }
     101             : 
     102          68 :         subreq = smb1cli_req_create(state, ev, conn, SMBreadX,
     103             :                                     0, 0, /* *_flags */
     104             :                                     0, 0, /* *_flags2 */
     105             :                                     timeout_msec, pid, tcon, session,
     106          34 :                                     wct, state->vwv,
     107             :                                     0, NULL);
     108          34 :         if (tevent_req_nomem(subreq, req)) {
     109           0 :                 return tevent_req_post(req, ev);
     110             :         }
     111          34 :         tevent_req_set_callback(subreq, smb1cli_readx_done, req);
     112             : 
     113          34 :         status = smb1cli_req_chain_submit(&subreq, 1);
     114          34 :         if (tevent_req_nterror(req, status)) {
     115           0 :                 return tevent_req_post(req, ev);
     116             :         }
     117             : 
     118          34 :         return req;
     119             : }
     120             : 
     121          34 : static void smb1cli_readx_done(struct tevent_req *subreq)
     122             : {
     123          34 :         struct tevent_req *req = tevent_req_callback_data(
     124             :                 subreq, struct tevent_req);
     125          34 :         struct smb1cli_readx_state *state = tevent_req_data(
     126             :                 req, struct smb1cli_readx_state);
     127          34 :         struct iovec *recv_iov = NULL;
     128           0 :         uint8_t wct;
     129           0 :         uint16_t *vwv;
     130           0 :         uint32_t num_bytes;
     131           0 :         uint8_t *bytes;
     132           0 :         uint16_t data_offset;
     133           0 :         uint32_t bytes_offset;
     134           0 :         NTSTATUS status;
     135           0 :         static const struct smb1cli_req_expected_response expected[] = {
     136             :         {
     137             :                 .status = NT_STATUS_OK,
     138             :                 .wct = 0x0C
     139             :         },
     140             :         {
     141             :                 .status = STATUS_BUFFER_OVERFLOW,
     142             :                 .wct = 0x0C
     143             :         },
     144             :         };
     145             : 
     146          34 :         status = smb1cli_req_recv(subreq, state,
     147             :                                   &recv_iov,
     148             :                                   NULL, /* phdr */
     149             :                                   &wct,
     150             :                                   &vwv,
     151             :                                   NULL, /* pvwv_offset */
     152             :                                   &num_bytes,
     153             :                                   &bytes,
     154             :                                   &bytes_offset,
     155             :                                   NULL, /* inbuf */
     156             :                                   expected, ARRAY_SIZE(expected));
     157          34 :         TALLOC_FREE(subreq);
     158          34 :         if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
     159             :                 /* no error */
     160             :         } else {
     161          34 :                 if (tevent_req_nterror(req, status)) {
     162           0 :                         return;
     163             :                 }
     164             :         }
     165             : 
     166             :         /* size is the number of bytes the server returned.
     167             :          * Might be zero. */
     168          34 :         state->received = SVAL(vwv + 5, 0);
     169          34 :         state->received |= (((unsigned int)SVAL(vwv + 7, 0)) << 16);
     170             : 
     171          34 :         if (state->received > state->size) {
     172           0 :                 DEBUG(5,("server returned more than we wanted!\n"));
     173           0 :                 tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
     174           0 :                 return;
     175             :         }
     176             : 
     177             :         /*
     178             :          * bcc field must be valid for small reads, for large reads the 16-bit
     179             :          * bcc field can't be correct.
     180             :          */
     181          34 :         if ((state->received < 0xffff) && (state->received > num_bytes)) {
     182           0 :                 DEBUG(5, ("server announced more bytes than sent\n"));
     183           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
     184           0 :                 return;
     185             :         }
     186             : 
     187          34 :         data_offset = SVAL(vwv+6, 0);
     188          34 :         if (data_offset < bytes_offset) {
     189           0 :                 DEBUG(5, ("server returned invalid read&x data offset\n"));
     190           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
     191           0 :                 return;
     192             :         }
     193          34 :         if (smb_buffer_oob(num_bytes, data_offset - bytes_offset, state->received)) {
     194           0 :                 DEBUG(5, ("server returned invalid read&x data offset\n"));
     195           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
     196           0 :                 return;
     197             :         }
     198             : 
     199          34 :         state->buf = bytes + (data_offset - bytes_offset);
     200             : 
     201          34 :         state->out_valid = true;
     202             : 
     203          34 :         if (tevent_req_nterror(req, status)) {
     204           0 :                 return;
     205             :         }
     206             : 
     207          34 :         tevent_req_done(req);
     208             : }
     209             : 
     210             : /**
     211             :  * Receive the response to an asynchronous SMB_COM_READ_ANDX request.
     212             :  * <a href="http://msdn.microsoft.com/en-us/library/ee441872.aspx">MS-CIFS 2.2.4.42.2</a>,
     213             :  * <a href="http://msdn.microsoft.com/en-us/library/ff470017.aspx">MS-SMB 2.2.4.2.2</a>
     214             :  *
     215             :  * @warning rcvbuf is talloced from the request, so better make sure that you
     216             :  * copy it away before  you talloc_free(req). rcvbuf is NOT a talloc_ctx of its
     217             :  * own, so do not talloc_move it!
     218             :  *
     219             :  * @param[in] req A tevent request created with smb1cli_readx_send()
     220             :  * @param[out] received The number of bytes received.
     221             :  * @param[out] rcvbuf Pointer to the bytes received.
     222             :  *
     223             :  * @return NT_STATUS_OK or STATUS_BUFFER_OVERFLOW on success.
     224             :  */
     225          34 : NTSTATUS smb1cli_readx_recv(struct tevent_req *req,
     226             :                             uint32_t *received,
     227             :                             uint8_t **rcvbuf)
     228             : {
     229          34 :         struct smb1cli_readx_state *state = tevent_req_data(
     230             :                 req, struct smb1cli_readx_state);
     231          34 :         NTSTATUS status = NT_STATUS_OK;
     232             : 
     233          34 :         if (tevent_req_is_nterror(req, &status) && !state->out_valid) {
     234           0 :                 *received = 0;
     235           0 :                 *rcvbuf = NULL;
     236           0 :                 return status;
     237             :         }
     238          34 :         *received = state->received;
     239          34 :         *rcvbuf = state->buf;
     240          34 :         return status;
     241             : }

Generated by: LCOV version 1.14