root/source4/libcli/raw/rawreadwrite.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. smb_raw_read_send
  2. smb_raw_read_recv
  3. smb_raw_read
  4. smb_raw_write_send
  5. smb_raw_write_recv
  6. smb_raw_write

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

/* [<][>][^][v][top][bottom][index][help] */