LCOV - code coverage report
Current view: top level - source4/libcli/raw - rawreadwrite.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 189 216 87.5 %
Date: 2024-04-21 15:09:00 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    client file read/write routines
       4             :    Copyright (C) Andrew Tridgell 1994-1998
       5             :    Copyright (C) James Myers 2003
       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 "libcli/raw/libcliraw.h"
      23             : #include "libcli/raw/raw_proto.h"
      24             : 
      25             : #define SETUP_REQUEST(cmd, wct, buflen) do { \
      26             :         req = smbcli_request_setup(tree, cmd, wct, buflen); \
      27             :         if (!req) return NULL; \
      28             : } while (0)
      29             : 
      30             : /****************************************************************************
      31             :  low level read operation (async send)
      32             : ****************************************************************************/
      33       54338 : _PUBLIC_ struct smbcli_request *smb_raw_read_send(struct smbcli_tree *tree, union smb_read *parms)
      34             : {
      35       54338 :         bool bigoffset = false;
      36       54338 :         struct smbcli_request *req = NULL;
      37             : 
      38       54338 :         switch (parms->generic.level) {
      39          60 :         case RAW_READ_READBRAW:
      40          60 :                 if (tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES) {
      41          60 :                         bigoffset = true;
      42             :                 }
      43          60 :                 SETUP_REQUEST(SMBreadbraw, bigoffset? 10:8, 0);
      44          60 :                 SSVAL(req->out.vwv, VWV(0), parms->readbraw.in.file.fnum);
      45          60 :                 SIVAL(req->out.vwv, VWV(1), parms->readbraw.in.offset);
      46          60 :                 SSVAL(req->out.vwv, VWV(3), parms->readbraw.in.maxcnt);
      47          60 :                 SSVAL(req->out.vwv, VWV(4), parms->readbraw.in.mincnt);
      48          60 :                 SIVAL(req->out.vwv, VWV(5), parms->readbraw.in.timeout);
      49          60 :                 SSVAL(req->out.vwv, VWV(7), 0); /* reserved */
      50          60 :                 if (bigoffset) {
      51          60 :                         SIVAL(req->out.vwv, VWV(8),parms->readbraw.in.offset>>32);
      52             :                 }
      53          60 :                 break;
      54             : 
      55         104 :         case RAW_READ_LOCKREAD:
      56         104 :                 SETUP_REQUEST(SMBlockread, 5, 0);
      57         104 :                 SSVAL(req->out.vwv, VWV(0), parms->lockread.in.file.fnum);
      58         104 :                 SSVAL(req->out.vwv, VWV(1), parms->lockread.in.count);
      59         104 :                 SIVAL(req->out.vwv, VWV(2), parms->lockread.in.offset);
      60         104 :                 SSVAL(req->out.vwv, VWV(4), parms->lockread.in.remaining);
      61         104 :                 break;
      62             : 
      63          64 :         case RAW_READ_READ:
      64          64 :                 SETUP_REQUEST(SMBread, 5, 0);
      65          64 :                 SSVAL(req->out.vwv, VWV(0), parms->read.in.file.fnum);
      66          64 :                 SSVAL(req->out.vwv, VWV(1), parms->read.in.count);
      67          64 :                 SIVAL(req->out.vwv, VWV(2), parms->read.in.offset);
      68          64 :                 SSVAL(req->out.vwv, VWV(4), parms->read.in.remaining);
      69          64 :                 break;
      70             : 
      71       54110 :         case RAW_READ_READX:
      72       54110 :                 if (tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES) {
      73       54063 :                         bigoffset = true;
      74             :                 }
      75       54110 :                 SETUP_REQUEST(SMBreadX, bigoffset ? 12 : 10, 0);
      76       54110 :                 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
      77       54110 :                 SSVAL(req->out.vwv, VWV(1), 0);
      78       54110 :                 SSVAL(req->out.vwv, VWV(2), parms->readx.in.file.fnum);
      79       54110 :                 SIVAL(req->out.vwv, VWV(3), parms->readx.in.offset);
      80       54110 :                 SSVAL(req->out.vwv, VWV(5), parms->readx.in.maxcnt & 0xFFFF);
      81       54110 :                 SSVAL(req->out.vwv, VWV(6), parms->readx.in.mincnt);
      82       54110 :                 SIVAL(req->out.vwv, VWV(7), parms->readx.in.maxcnt >> 16);
      83       54110 :                 SSVAL(req->out.vwv, VWV(9), parms->readx.in.remaining);
      84             :                 /*
      85             :                  * TODO: give an error when the offset is 64 bit
      86             :                  *       and the server doesn't support it
      87             :                  */
      88       54110 :                 if (bigoffset) {
      89       54110 :                         SIVAL(req->out.vwv, VWV(10),parms->readx.in.offset>>32);
      90             :                 }
      91       54110 :                 if (parms->readx.in.read_for_execute) {
      92       25283 :                         uint16_t flags2 = SVAL(req->out.hdr, HDR_FLG2);
      93       25283 :                         flags2 |= FLAGS2_READ_PERMIT_EXECUTE;
      94       25283 :                         SSVAL(req->out.hdr, HDR_FLG2, flags2);
      95             :                 }
      96       54063 :                 break;
      97             : 
      98           0 :         case RAW_READ_SMB2:
      99           0 :                 return NULL;
     100             :         }
     101             : 
     102       54338 :         if (!smbcli_request_send(req)) {
     103           0 :                 smbcli_request_destroy(req);
     104           0 :                 return NULL;
     105             :         }
     106             : 
     107       54270 :         return req;
     108             : }
     109             : 
     110             : /****************************************************************************
     111             :  low level read operation (async recv)
     112             : ****************************************************************************/
     113       54330 : _PUBLIC_ NTSTATUS smb_raw_read_recv(struct smbcli_request *req, union smb_read *parms)
     114             : {
     115      108660 :         if (!smbcli_request_receive(req) ||
     116       54330 :             smbcli_request_is_error(req)) {
     117       19335 :                 goto failed;
     118             :         }
     119             : 
     120       34995 :         switch (parms->generic.level) {
     121          60 :         case RAW_READ_READBRAW:
     122          60 :                 parms->readbraw.out.nread = req->in.size - NBT_HDR_SIZE;
     123          60 :                 if (parms->readbraw.out.nread >
     124          60 :                     MAX(parms->readx.in.mincnt, parms->readx.in.maxcnt)) {
     125           0 :                         req->status = NT_STATUS_BUFFER_TOO_SMALL;
     126           0 :                         goto failed;
     127             :                 }
     128          60 :                 memcpy(parms->readbraw.out.data, req->in.buffer + NBT_HDR_SIZE, parms->readbraw.out.nread);
     129       34941 :                 break;
     130             : 
     131          48 :         case RAW_READ_LOCKREAD:
     132          48 :                 SMBCLI_CHECK_WCT(req, 5);
     133          48 :                 parms->lockread.out.nread = SVAL(req->in.vwv, VWV(0));
     134          54 :                 if (parms->lockread.out.nread > parms->lockread.in.count ||
     135          48 :                     !smbcli_raw_pull_data(&req->in.bufinfo, req->in.data+3,
     136          42 :                                        parms->lockread.out.nread, parms->lockread.out.data)) {
     137           0 :                         req->status = NT_STATUS_BUFFER_TOO_SMALL;
     138             :                 }
     139          42 :                 break;
     140             : 
     141          48 :         case RAW_READ_READ:
     142             :                 /* there are 4 reserved words in the reply */
     143          48 :                 SMBCLI_CHECK_WCT(req, 5);
     144          48 :                 parms->read.out.nread = SVAL(req->in.vwv, VWV(0));
     145          54 :                 if (parms->read.out.nread > parms->read.in.count ||
     146          48 :                     !smbcli_raw_pull_data(&req->in.bufinfo, req->in.data+3,
     147          42 :                                        parms->read.out.nread, parms->read.out.data)) {
     148           0 :                         req->status = NT_STATUS_BUFFER_TOO_SMALL;
     149             :                 }
     150          42 :                 break;
     151             : 
     152       34839 :         case RAW_READ_READX:
     153             :                 /* there are 5 reserved words in the reply */
     154       34839 :                 SMBCLI_CHECK_WCT(req, 12);
     155       34839 :                 parms->readx.out.remaining       = SVAL(req->in.vwv, VWV(2));
     156       34839 :                 parms->readx.out.compaction_mode = SVAL(req->in.vwv, VWV(3));
     157       34839 :                 parms->readx.out.nread = SVAL(req->in.vwv, VWV(5));
     158       34839 :                 parms->readx.out.flags2 = req->flags2;
     159       34839 :                 parms->readx.out.data_offset = SVAL(req->in.vwv, VWV(6));
     160             : 
     161             :                 /* handle oversize replies for non-chained readx replies with
     162             :                    CAP_LARGE_READX. The snia spec has must to answer for. */
     163       34839 :                 if ((req->tree->session->transport->negotiate.capabilities & CAP_LARGE_READX)
     164       34839 :                     && CVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE &&
     165       34839 :                     req->in.size >= 0x10000) {
     166          36 :                         parms->readx.out.nread += (SVAL(req->in.vwv, VWV(7)) << 16);
     167          36 :                         if (req->in.hdr + SVAL(req->in.vwv, VWV(6)) +
     168          36 :                             parms->readx.out.nread <=
     169          36 :                             req->in.buffer + req->in.size) {
     170          36 :                                 req->in.data_size += (SVAL(req->in.vwv, VWV(7)) << 16);
     171             : 
     172             :                                 /* update the bufinfo with the new size */
     173          36 :                                 smb_setup_bufinfo(req);
     174             :                         }
     175             :                 }
     176             : 
     177       34881 :                 if (parms->readx.out.nread > MAX(parms->readx.in.mincnt, parms->readx.in.maxcnt) ||
     178       34839 :                     !smbcli_raw_pull_data(&req->in.bufinfo, req->in.hdr + SVAL(req->in.vwv, VWV(6)),
     179       34797 :                                        parms->readx.out.nread,
     180             :                                        parms->readx.out.data)) {
     181           0 :                         req->status = NT_STATUS_BUFFER_TOO_SMALL;
     182             :                 }
     183       34797 :                 break;
     184             : 
     185           0 :         case RAW_READ_SMB2:
     186           0 :                 req->status = NT_STATUS_INTERNAL_ERROR;
     187           0 :                 break;
     188             :         }
     189             : 
     190       54330 : failed:
     191       54330 :         return smbcli_request_destroy(req);
     192             : }
     193             : 
     194             : /****************************************************************************
     195             :  low level read operation (sync interface)
     196             : ****************************************************************************/
     197       36772 : _PUBLIC_ NTSTATUS smb_raw_read(struct smbcli_tree *tree, union smb_read *parms)
     198             : {
     199       36772 :         struct smbcli_request *req = smb_raw_read_send(tree, parms);
     200       36772 :         return smb_raw_read_recv(req, parms);
     201             : }
     202             : 
     203             : 
     204             : /****************************************************************************
     205             :  raw write interface (async send)
     206             : ****************************************************************************/
     207       29654 : _PUBLIC_ struct smbcli_request *smb_raw_write_send(struct smbcli_tree *tree, union smb_write *parms)
     208             : {
     209       29654 :         bool bigoffset = false;
     210       29654 :         struct smbcli_request *req = NULL;
     211             : 
     212       29654 :         switch (parms->generic.level) {
     213          42 :         case RAW_WRITE_WRITEUNLOCK:
     214          42 :                 SETUP_REQUEST(SMBwriteunlock, 5, 3 + parms->writeunlock.in.count);
     215          42 :                 SSVAL(req->out.vwv, VWV(0), parms->writeunlock.in.file.fnum);
     216          42 :                 SSVAL(req->out.vwv, VWV(1), parms->writeunlock.in.count);
     217          42 :                 SIVAL(req->out.vwv, VWV(2), parms->writeunlock.in.offset);
     218          42 :                 SSVAL(req->out.vwv, VWV(4), parms->writeunlock.in.remaining);
     219          42 :                 SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
     220          42 :                 SSVAL(req->out.data, 1, parms->writeunlock.in.count);
     221          42 :                 if (parms->writeunlock.in.count > 0) {
     222          36 :                         memcpy(req->out.data+3, parms->writeunlock.in.data,
     223          30 :                                parms->writeunlock.in.count);
     224             :                 }
     225          35 :                 break;
     226             : 
     227         103 :         case RAW_WRITE_WRITE:
     228         103 :                 SETUP_REQUEST(SMBwrite, 5,  3 + parms->write.in.count);
     229         103 :                 SSVAL(req->out.vwv, VWV(0), parms->write.in.file.fnum);
     230         103 :                 SSVAL(req->out.vwv, VWV(1), parms->write.in.count);
     231         103 :                 SIVAL(req->out.vwv, VWV(2), parms->write.in.offset);
     232         103 :                 SSVAL(req->out.vwv, VWV(4), parms->write.in.remaining);
     233         103 :                 SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
     234         103 :                 SSVAL(req->out.data, 1, parms->write.in.count);
     235         103 :                 if (parms->write.in.count > 0) {
     236          45 :                         memcpy(req->out.data+3, parms->write.in.data, parms->write.in.count);
     237             :                 }
     238          98 :                 break;
     239             : 
     240          54 :         case RAW_WRITE_WRITECLOSE:
     241          54 :                 SETUP_REQUEST(SMBwriteclose, 6, 1 + parms->writeclose.in.count);
     242          54 :                 SSVAL(req->out.vwv, VWV(0), parms->writeclose.in.file.fnum);
     243          54 :                 SSVAL(req->out.vwv, VWV(1), parms->writeclose.in.count);
     244          54 :                 SIVAL(req->out.vwv, VWV(2), parms->writeclose.in.offset);
     245          54 :                 raw_push_dos_date3(tree->session->transport,
     246             :                                   req->out.vwv, VWV(4), parms->writeclose.in.mtime);
     247          54 :                 SCVAL(req->out.data, 0, 0);
     248          54 :                 if (parms->writeclose.in.count > 0) {
     249          42 :                         memcpy(req->out.data+1, parms->writeclose.in.data,
     250          35 :                                parms->writeclose.in.count);
     251             :                 }
     252          45 :                 break;
     253             : 
     254       29455 :         case RAW_WRITE_WRITEX:
     255       29455 :                 if (tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES) {
     256       29455 :                         bigoffset = true;
     257             :                 }
     258       29455 :                 SETUP_REQUEST(SMBwriteX, bigoffset ? 14 : 12, parms->writex.in.count);
     259       29455 :                 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
     260       29455 :                 SSVAL(req->out.vwv, VWV(1), 0);
     261       29455 :                 SSVAL(req->out.vwv, VWV(2), parms->writex.in.file.fnum);
     262       29455 :                 SIVAL(req->out.vwv, VWV(3), parms->writex.in.offset);
     263       29455 :                 SIVAL(req->out.vwv, VWV(5), 0); /* reserved */
     264       29455 :                 SSVAL(req->out.vwv, VWV(7), parms->writex.in.wmode);
     265       29455 :                 SSVAL(req->out.vwv, VWV(8), parms->writex.in.remaining);
     266       29455 :                 SSVAL(req->out.vwv, VWV(9), parms->writex.in.count>>16);
     267       29455 :                 SSVAL(req->out.vwv, VWV(10), parms->writex.in.count);
     268       29455 :                 SSVAL(req->out.vwv, VWV(11), PTR_DIFF(req->out.data, req->out.hdr));
     269       29455 :                 if (bigoffset) {
     270       29455 :                         SIVAL(req->out.vwv,VWV(12),parms->writex.in.offset>>32);
     271             :                 }
     272       29455 :                 if (parms->writex.in.count > 0) {
     273       29447 :                         memcpy(req->out.data, parms->writex.in.data, parms->writex.in.count);
     274             :                 }
     275       29394 :                 break;
     276             : 
     277           0 :         case RAW_WRITE_SPLWRITE:
     278           0 :                 SETUP_REQUEST(SMBsplwr, 1, parms->splwrite.in.count);
     279           0 :                 SSVAL(req->out.vwv, VWV(0), parms->splwrite.in.file.fnum);
     280           0 :                 if (parms->splwrite.in.count > 0) {
     281           0 :                         memcpy(req->out.data, parms->splwrite.in.data, parms->splwrite.in.count);
     282             :                 }
     283           0 :                 break;
     284             : 
     285           0 :         case RAW_WRITE_SMB2:
     286           0 :                 return NULL;
     287             :         }
     288             : 
     289       29654 :         if (!smbcli_request_send(req)) {
     290           0 :                 smbcli_request_destroy(req);
     291           0 :                 return NULL;
     292             :         }
     293             : 
     294       29572 :         return req;
     295             : }
     296             : 
     297             : 
     298             : /****************************************************************************
     299             :  raw write interface (async recv)
     300             : ****************************************************************************/
     301       29654 : _PUBLIC_ NTSTATUS smb_raw_write_recv(struct smbcli_request *req, union smb_write *parms)
     302             : {
     303       29654 :         if (!smbcli_request_receive(req) ||
     304       29654 :             !NT_STATUS_IS_OK(req->status)) {
     305       13065 :                 goto failed;
     306             :         }
     307             : 
     308       16589 :         switch (parms->generic.level) {
     309          24 :         case RAW_WRITE_WRITEUNLOCK:
     310          24 :                 SMBCLI_CHECK_WCT(req, 1);
     311          24 :                 parms->writeunlock.out.nwritten = SVAL(req->in.vwv, VWV(0));
     312       16526 :                 break;
     313          97 :         case RAW_WRITE_WRITE:
     314          97 :                 SMBCLI_CHECK_WCT(req, 1);
     315          97 :                 parms->write.out.nwritten = SVAL(req->in.vwv, VWV(0));
     316          97 :                 break;
     317          36 :         case RAW_WRITE_WRITECLOSE:
     318          36 :                 SMBCLI_CHECK_WCT(req, 1);
     319          36 :                 parms->writeclose.out.nwritten = SVAL(req->in.vwv, VWV(0));
     320          36 :                 break;
     321       16432 :         case RAW_WRITE_WRITEX:
     322       16432 :                 SMBCLI_CHECK_WCT(req, 6);
     323       16432 :                 parms->writex.out.nwritten  = SVAL(req->in.vwv, VWV(2));
     324       16432 :                 parms->writex.out.nwritten += (CVAL(req->in.vwv, VWV(4)) << 16);
     325       16432 :                 parms->writex.out.remaining = SVAL(req->in.vwv, VWV(3));
     326       16432 :                 break;
     327           0 :         case RAW_WRITE_SPLWRITE:
     328           0 :                 break;
     329           0 :         case RAW_WRITE_SMB2:
     330           0 :                 req->status = NT_STATUS_INTERNAL_ERROR;
     331           0 :                 break;
     332             :         }
     333             : 
     334       29654 : failed:
     335       29654 :         return smbcli_request_destroy(req);
     336             : }
     337             : 
     338             : /****************************************************************************
     339             :  raw write interface (sync interface)
     340             : ****************************************************************************/
     341       20976 : _PUBLIC_ NTSTATUS smb_raw_write(struct smbcli_tree *tree, union smb_write *parms)
     342             : {
     343       20976 :         struct smbcli_request *req = smb_raw_write_send(tree, parms);
     344       20976 :         return smb_raw_write_recv(req, parms);
     345             : }

Generated by: LCOV version 1.14