LCOV - code coverage report
Current view: top level - source4/libcli/smb2 - request.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 306 372 82.3 %
Date: 2024-02-28 12:06:22 Functions: 24 25 96.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    SMB2 client request handling
       5             : 
       6             :    Copyright (C) Andrew Tridgell        2005
       7             :    Copyright (C) Stefan Metzmacher      2005
       8             :    
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             :    
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             :    
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include "libcli/raw/libcliraw.h"
      25             : #include "libcli/smb2/smb2.h"
      26             : #include "../lib/util/dlinklist.h"
      27             : #include "lib/events/events.h"
      28             : #include "libcli/smb2/smb2_calls.h"
      29             : 
      30             : /* fill in the bufinfo */
      31     1210749 : void smb2_setup_bufinfo(struct smb2_request *req)
      32             : {
      33     1210749 :         req->in.bufinfo.mem_ctx    = req;
      34     1210749 :         req->in.bufinfo.flags      = BUFINFO_FLAG_UNICODE | BUFINFO_FLAG_SMB2;
      35     1210749 :         req->in.bufinfo.align_base = req->in.buffer;
      36     1210749 :         if (req->in.dynamic) {
      37     1210749 :                 req->in.bufinfo.data       = req->in.dynamic;
      38     1210749 :                 req->in.bufinfo.data_size  = req->in.body_size - req->in.body_fixed;
      39             :         } else {
      40           0 :                 req->in.bufinfo.data       = NULL;
      41           0 :                 req->in.bufinfo.data_size  = 0;
      42             :         }
      43     1210749 : }
      44             : 
      45             : /*
      46             :   initialise a smb2 request
      47             : */
      48     1210899 : struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_t opcode,
      49             :                                        uint16_t body_fixed_size, bool body_dynamic_present,
      50             :                                        uint32_t body_dynamic_size)
      51             : {
      52         898 :         struct smb2_request *req;
      53         898 :         uint32_t hdr_offset;
      54     1210899 :         bool compound = false;
      55             : 
      56     1210899 :         if (body_dynamic_present) {
      57      732590 :                 if (body_dynamic_size == 0) {
      58      661010 :                         body_dynamic_size = 1;
      59             :                 }
      60             :         } else {
      61      478112 :                 body_dynamic_size = 0;
      62             :         }
      63             : 
      64     1210899 :         req = talloc_zero(transport, struct smb2_request);
      65     1210899 :         if (req == NULL) return NULL;
      66             : 
      67     1210899 :         req->state     = SMB2_REQUEST_INIT;
      68     1210899 :         req->transport = transport;
      69             : 
      70     1210899 :         hdr_offset = NBT_HDR_SIZE;
      71             : 
      72     1210899 :         req->out.size      = hdr_offset + SMB2_HDR_BODY + body_fixed_size;
      73     1210899 :         req->out.allocated = req->out.size + body_dynamic_size;
      74             : 
      75     1210899 :         req->out.buffer = talloc_realloc(req, req->out.buffer,
      76             :                                          uint8_t, req->out.allocated);
      77     1210899 :         if (req->out.buffer == NULL) {
      78           0 :                 talloc_free(req);
      79           0 :                 return NULL;
      80             :         }
      81             : 
      82     1210899 :         req->out.hdr       = req->out.buffer + hdr_offset;
      83     1210899 :         req->out.body      = req->out.hdr + SMB2_HDR_BODY;
      84     1210899 :         req->out.body_fixed= body_fixed_size;
      85     1210899 :         req->out.body_size = body_fixed_size;
      86     1210899 :         req->out.dynamic   = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
      87             : 
      88     1210899 :         SIVAL(req->out.hdr, 0,                               SMB2_MAGIC);
      89     1210899 :         SSVAL(req->out.hdr, SMB2_HDR_LENGTH,         SMB2_HDR_BODY);
      90     1210899 :         SSVAL(req->out.hdr, SMB2_HDR_CREDIT_CHARGE,  0);
      91     1210899 :         SIVAL(req->out.hdr, SMB2_HDR_STATUS,         0);
      92     1210899 :         SSVAL(req->out.hdr, SMB2_HDR_OPCODE,         opcode);
      93     1210899 :         SSVAL(req->out.hdr, SMB2_HDR_CREDIT,         0);
      94     1210899 :         SIVAL(req->out.hdr, SMB2_HDR_FLAGS,          0);
      95     1210899 :         SIVAL(req->out.hdr, SMB2_HDR_NEXT_COMMAND,   0);
      96     1210899 :         SBVAL(req->out.hdr, SMB2_HDR_MESSAGE_ID,     0);
      97     1210899 :         SIVAL(req->out.hdr, SMB2_HDR_PID,            0);
      98     1210899 :         SIVAL(req->out.hdr, SMB2_HDR_TID,            0);
      99     1210899 :         SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID,             0);
     100     1210899 :         memset(req->out.hdr+SMB2_HDR_SIGNATURE, 0, 16);
     101             : 
     102             :         /* set the length of the fixed body part and +1 if there's a dynamic part also */
     103     1211096 :         SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0));
     104             : 
     105             :         /* 
     106             :          * if we have a dynamic part, make sure the first byte
     107             :          * which is always be part of the packet is initialized
     108             :          */
     109     1210899 :         if (body_dynamic_size && !compound) {
     110      732590 :                 req->out.size += 1;
     111      732590 :                 SCVAL(req->out.dynamic, 0, 0);
     112             :         }
     113             : 
     114     1210001 :         return req;
     115             : }
     116             : 
     117             : /*
     118             :     initialise a smb2 request for tree operations
     119             : */
     120     1209835 : struct smb2_request *smb2_request_init_tree(struct smb2_tree *tree, uint16_t opcode,
     121             :                                             uint16_t body_fixed_size, bool body_dynamic_present,
     122             :                                             uint32_t body_dynamic_size)
     123             : {
     124     1209835 :         struct smb2_request *req = smb2_request_init(tree->session->transport, opcode, 
     125             :                                                      body_fixed_size, body_dynamic_present,
     126             :                                                      body_dynamic_size);
     127     1209835 :         if (req == NULL) return NULL;
     128             : 
     129     1209835 :         req->session = tree->session;
     130     1209835 :         req->tree = tree;
     131             : 
     132     1209835 :         return req;     
     133             : }
     134             : 
     135             : /* destroy a request structure and return final status */
     136     1210793 : NTSTATUS smb2_request_destroy(struct smb2_request *req)
     137             : {
     138         898 :         NTSTATUS status;
     139             : 
     140             :         /* this is the error code we give the application for when a
     141             :            _send() call fails completely */
     142     1210793 :         if (!req) return NT_STATUS_UNSUCCESSFUL;
     143             : 
     144     1210793 :         if (req->state == SMB2_REQUEST_ERROR &&
     145          58 :             NT_STATUS_IS_OK(req->status)) {
     146           0 :                 status = NT_STATUS_INTERNAL_ERROR;
     147             :         } else {
     148     1210793 :                 status = req->status;
     149             :         }
     150             : 
     151     1210793 :         talloc_free(req);
     152     1210793 :         return status;
     153             : }
     154             : 
     155             : /*
     156             :   receive a response to a packet
     157             : */
     158     1210836 : bool smb2_request_receive(struct smb2_request *req)
     159             : {
     160             :         /* req can be NULL when a send has failed. This eliminates lots of NULL
     161             :            checks in each module */
     162     1210836 :         if (!req) return false;
     163             : 
     164             :         /* keep receiving packets until this one is replied to */
     165     3576967 :         while (req->state <= SMB2_REQUEST_RECV) {
     166     2366131 :                 if (tevent_loop_once(req->transport->ev) != 0) {
     167           0 :                         return false;
     168             :                 }
     169             :         }
     170             : 
     171     1210836 :         return req->state == SMB2_REQUEST_DONE;
     172             : }
     173             : 
     174             : /* Return true if the last packet was in error */
     175       20768 : bool smb2_request_is_error(struct smb2_request *req)
     176             : {
     177       20768 :         return NT_STATUS_IS_ERR(req->status);
     178             : }
     179             : 
     180             : /* Return true if the last packet was OK */
     181     1188165 : bool smb2_request_is_ok(struct smb2_request *req)
     182             : {
     183     1188165 :         return NT_STATUS_IS_OK(req->status);
     184             : }
     185             : 
     186             : /*
     187             :   check if a range in the reply body is out of bounds
     188             : */
     189     3239161 : bool smb2_oob(struct smb2_request_buffer *buf, const uint8_t *ptr, size_t size)
     190             : {
     191     3239161 :         if (size == 0) {
     192             :                 /* zero bytes is never out of range */
     193       56912 :                 return false;
     194             :         }
     195             :         /* be careful with wraparound! */
     196     3182249 :         if ((uintptr_t)ptr < (uintptr_t)buf->body ||
     197     3182249 :             (uintptr_t)ptr >= (uintptr_t)buf->body + buf->body_size ||
     198     3182249 :             size > buf->body_size ||
     199     3182249 :             (uintptr_t)ptr + size > (uintptr_t)buf->body + buf->body_size) {
     200           0 :                 return true;
     201             :         }
     202     3180396 :         return false;
     203             : }
     204             : 
     205      772590 : size_t smb2_padding_size(uint32_t offset, size_t n)
     206             : {
     207      772590 :         if ((offset & (n-1)) == 0) return 0;
     208        2134 :         return n - (offset & (n-1));
     209             : }
     210             : 
     211      772590 : static size_t smb2_padding_fix(struct smb2_request_buffer *buf)
     212             : {
     213      772590 :         if (buf->dynamic == (buf->body + buf->body_fixed)) {
     214      769756 :                 if (buf->dynamic != (buf->buffer + buf->size)) {
     215      769610 :                         return 1;
     216             :                 }
     217             :         }
     218        2980 :         return 0;
     219             : }
     220             : 
     221             : /*
     222             :   grow a SMB2 buffer by the specified amount
     223             : */
     224      803868 : NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t increase)
     225             : {
     226         391 :         size_t hdr_ofs;
     227         391 :         size_t dynamic_ofs;
     228         391 :         uint8_t *buffer_ptr;
     229      803868 :         uint32_t newsize = buf->size + increase;
     230             : 
     231             :         /* a packet size should be limited a bit */
     232      803868 :         if (newsize >= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW;
     233             : 
     234      803868 :         if (newsize <= buf->allocated) return NT_STATUS_OK;
     235             : 
     236      663872 :         hdr_ofs = buf->hdr - buf->buffer;
     237      663872 :         dynamic_ofs = buf->dynamic - buf->buffer;
     238             : 
     239      663872 :         buffer_ptr = talloc_realloc(buf, buf->buffer, uint8_t, newsize);
     240      663872 :         NT_STATUS_HAVE_NO_MEMORY(buffer_ptr);
     241             : 
     242      663872 :         buf->buffer  = buffer_ptr;
     243      663872 :         buf->hdr     = buf->buffer + hdr_ofs;
     244      663872 :         buf->body    = buf->hdr    + SMB2_HDR_BODY;
     245      663872 :         buf->dynamic = buf->buffer + dynamic_ofs;
     246      663872 :         buf->allocated       = newsize;
     247             : 
     248      663872 :         return NT_STATUS_OK;
     249             : }
     250             : 
     251             : /*
     252             :   pull a uint16_t ofs/ uint16_t length/blob triple from a data blob
     253             :   the ptr points to the start of the offset/length pair
     254             : */
     255      226181 : NTSTATUS smb2_pull_o16s16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
     256             : {
     257         306 :         uint16_t ofs, size;
     258      226181 :         if (smb2_oob(buf, ptr, 4)) {
     259           0 :                 return NT_STATUS_INVALID_PARAMETER;
     260             :         }
     261      226181 :         ofs  = SVAL(ptr, 0);
     262      226181 :         size = SVAL(ptr, 2);
     263      226181 :         if (ofs == 0) {
     264          25 :                 *blob = data_blob(NULL, 0);
     265          25 :                 return NT_STATUS_OK;
     266             :         }
     267      226156 :         if (smb2_oob(buf, buf->hdr + ofs, size)) {
     268           0 :                 return NT_STATUS_INVALID_PARAMETER;
     269             :         }
     270      226156 :         *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
     271      226156 :         NT_STATUS_HAVE_NO_MEMORY(blob->data);
     272      226156 :         return NT_STATUS_OK;
     273             : }
     274             : 
     275             : /*
     276             :   push a uint16_t ofs/ uint16_t length/blob triple into a data blob
     277             :   the ofs points to the start of the offset/length pair, and is relative
     278             :   to the body start
     279             : */
     280      648477 : NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf, 
     281             :                                uint16_t ofs, DATA_BLOB blob)
     282             : {
     283         367 :         NTSTATUS status;
     284         367 :         size_t offset;
     285         367 :         size_t padding_length;
     286         367 :         size_t padding_fix;
     287      648477 :         uint8_t *ptr = buf->body+ofs;
     288             : 
     289      648477 :         if (buf->dynamic == NULL) {
     290           0 :                 return NT_STATUS_INVALID_PARAMETER;
     291             :         }
     292             : 
     293             :         /* we have only 16 bit for the size */
     294      648477 :         if (blob.length > 0xFFFF) {
     295           0 :                 return NT_STATUS_INVALID_PARAMETER;
     296             :         }
     297             : 
     298             :         /* check if there're enough room for ofs and size */
     299      648477 :         if (smb2_oob(buf, ptr, 4)) {
     300           0 :                 return NT_STATUS_INVALID_PARAMETER;
     301             :         }
     302             : 
     303      648477 :         if (blob.data == NULL) {
     304           0 :                 if (blob.length != 0) {
     305           0 :                         return NT_STATUS_INTERNAL_ERROR;
     306             :                 }
     307           0 :                 SSVAL(ptr, 0, 0);
     308           0 :                 SSVAL(ptr, 2, 0);
     309           0 :                 return NT_STATUS_OK;
     310             :         }
     311             : 
     312      648477 :         offset = buf->dynamic - buf->hdr;
     313      648477 :         padding_length = smb2_padding_size(offset, 2);
     314      648477 :         offset += padding_length;
     315      648477 :         padding_fix = smb2_padding_fix(buf);
     316             : 
     317      648477 :         SSVAL(ptr, 0, offset);
     318      648477 :         SSVAL(ptr, 2, blob.length);
     319             : 
     320      648477 :         status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
     321      648477 :         NT_STATUS_NOT_OK_RETURN(status);
     322             : 
     323      648477 :         memset(buf->dynamic, 0, padding_length);
     324      648477 :         buf->dynamic += padding_length;
     325             : 
     326      648477 :         memcpy(buf->dynamic, blob.data, blob.length);
     327      648477 :         buf->dynamic += blob.length;
     328             : 
     329      648477 :         buf->size += blob.length + padding_length - padding_fix;
     330      648477 :         buf->body_size += blob.length + padding_length;
     331             : 
     332      648477 :         return NT_STATUS_OK;
     333             : }
     334             : 
     335             : 
     336             : /*
     337             :   push a uint16_t ofs/ uint32_t length/blob triple into a data blob
     338             :   the ofs points to the start of the offset/length pair, and is relative
     339             :   to the body start
     340             : */
     341       65795 : NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf, 
     342             :                                uint16_t ofs, DATA_BLOB blob)
     343             : {
     344           2 :         NTSTATUS status;
     345           2 :         size_t offset;
     346           2 :         size_t padding_length;
     347           2 :         size_t padding_fix;
     348       65795 :         uint8_t *ptr = buf->body+ofs;
     349             : 
     350       65795 :         if (buf->dynamic == NULL) {
     351           0 :                 return NT_STATUS_INVALID_PARAMETER;
     352             :         }
     353             : 
     354             :         /* check if there're enough room for ofs and size */
     355       65795 :         if (smb2_oob(buf, ptr, 6)) {
     356           0 :                 return NT_STATUS_INVALID_PARAMETER;
     357             :         }
     358             : 
     359       65795 :         if (blob.data == NULL) {
     360           5 :                 if (blob.length != 0) {
     361           0 :                         return NT_STATUS_INTERNAL_ERROR;
     362             :                 }
     363           5 :                 SSVAL(ptr, 0, 0);
     364           5 :                 SIVAL(ptr, 2, 0);
     365           5 :                 return NT_STATUS_OK;
     366             :         }
     367             : 
     368       65790 :         offset = buf->dynamic - buf->hdr;
     369       65790 :         padding_length = smb2_padding_size(offset, 2);
     370       65790 :         offset += padding_length;
     371       65790 :         padding_fix = smb2_padding_fix(buf);
     372             : 
     373       65790 :         SSVAL(ptr, 0, offset);
     374       65790 :         SIVAL(ptr, 2, blob.length);
     375             : 
     376       65790 :         status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
     377       65790 :         NT_STATUS_NOT_OK_RETURN(status);
     378             : 
     379       65790 :         memset(buf->dynamic, 0, padding_length);
     380       65790 :         buf->dynamic += padding_length;
     381             : 
     382       65790 :         memcpy(buf->dynamic, blob.data, blob.length);
     383       65790 :         buf->dynamic += blob.length;
     384             : 
     385       65790 :         buf->size += blob.length + padding_length - padding_fix;
     386       65790 :         buf->body_size += blob.length + padding_length;
     387             : 
     388       65790 :         return NT_STATUS_OK;
     389             : }
     390             : 
     391             : 
     392             : /*
     393             :   push a uint32_t ofs/ uint32_t length/blob triple into a data blob
     394             :   the ofs points to the start of the offset/length pair, and is relative
     395             :   to the body start
     396             : */
     397      895216 : NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf, 
     398             :                                uint32_t ofs, DATA_BLOB blob)
     399             : {
     400         691 :         NTSTATUS status;
     401         691 :         size_t offset;
     402         691 :         size_t padding_length;
     403         691 :         size_t padding_fix;
     404      895216 :         uint8_t *ptr = buf->body+ofs;
     405             : 
     406      895216 :         if (buf->dynamic == NULL) {
     407           0 :                 return NT_STATUS_INVALID_PARAMETER;
     408             :         }
     409             : 
     410             :         /* check if there're enough room for ofs and size */
     411      895216 :         if (smb2_oob(buf, ptr, 8)) {
     412           0 :                 return NT_STATUS_INVALID_PARAMETER;
     413             :         }
     414             : 
     415      895216 :         if (blob.data == NULL) {
     416      843500 :                 if (blob.length != 0) {
     417           0 :                         return NT_STATUS_INTERNAL_ERROR;
     418             :                 }
     419      843500 :                 SIVAL(ptr, 0, 0);
     420      843500 :                 SIVAL(ptr, 4, 0);
     421      843500 :                 return NT_STATUS_OK;
     422             :         }
     423             : 
     424       51716 :         offset = buf->dynamic - buf->hdr;
     425       51716 :         padding_length = smb2_padding_size(offset, 8);
     426       51716 :         offset += padding_length;
     427       51716 :         padding_fix = smb2_padding_fix(buf);
     428             : 
     429       51716 :         SIVAL(ptr, 0, offset);
     430       51716 :         SIVAL(ptr, 4, blob.length);
     431             : 
     432       51716 :         status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
     433       51716 :         NT_STATUS_NOT_OK_RETURN(status);
     434             : 
     435       51716 :         memset(buf->dynamic, 0, padding_length);
     436       51716 :         buf->dynamic += padding_length;
     437             : 
     438       51716 :         memcpy(buf->dynamic, blob.data, blob.length);
     439       51716 :         buf->dynamic += blob.length;
     440             : 
     441       51716 :         buf->size += blob.length + padding_length - padding_fix;
     442       51716 :         buf->body_size += blob.length + padding_length;
     443             : 
     444       51716 :         return NT_STATUS_OK;
     445             : }
     446             : 
     447             : 
     448             : /*
     449             :   push a uint32_t length/ uint32_t ofs/blob triple into a data blob
     450             :   the ofs points to the start of the length/offset pair, and is relative
     451             :   to the body start
     452             : */
     453        6607 : NTSTATUS smb2_push_s32o32_blob(struct smb2_request_buffer *buf, 
     454             :                                uint32_t ofs, DATA_BLOB blob)
     455             : {
     456           4 :         NTSTATUS status;
     457           4 :         size_t offset;
     458           4 :         size_t padding_length;
     459           4 :         size_t padding_fix;
     460        6607 :         uint8_t *ptr = buf->body+ofs;
     461             : 
     462        6607 :         if (buf->dynamic == NULL) {
     463           0 :                 return NT_STATUS_INVALID_PARAMETER;
     464             :         }
     465             : 
     466             :         /* check if there're enough room for ofs and size */
     467        6607 :         if (smb2_oob(buf, ptr, 8)) {
     468           0 :                 return NT_STATUS_INVALID_PARAMETER;
     469             :         }
     470             : 
     471        6607 :         if (blob.data == NULL) {
     472           0 :                 if (blob.length != 0) {
     473           0 :                         return NT_STATUS_INTERNAL_ERROR;
     474             :                 }
     475           0 :                 SIVAL(ptr, 0, 0);
     476           0 :                 SIVAL(ptr, 4, 0);
     477           0 :                 return NT_STATUS_OK;
     478             :         }
     479             : 
     480        6607 :         offset = buf->dynamic - buf->hdr;
     481        6607 :         padding_length = smb2_padding_size(offset, 8);
     482        6607 :         offset += padding_length;
     483        6607 :         padding_fix = smb2_padding_fix(buf);
     484             : 
     485        6607 :         SIVAL(ptr, 0, blob.length);
     486        6607 :         SIVAL(ptr, 4, offset);
     487             : 
     488        6607 :         status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
     489        6607 :         NT_STATUS_NOT_OK_RETURN(status);
     490             : 
     491        6607 :         memset(buf->dynamic, 0, padding_length);
     492        6607 :         buf->dynamic += padding_length;
     493             : 
     494        6607 :         memcpy(buf->dynamic, blob.data, blob.length);
     495        6607 :         buf->dynamic += blob.length;
     496             : 
     497        6607 :         buf->size += blob.length + padding_length - padding_fix;
     498        6607 :         buf->body_size += blob.length + padding_length;
     499             : 
     500        6607 :         return NT_STATUS_OK;
     501             : }
     502             : 
     503             : /*
     504             :   pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
     505             :   the ptr points to the start of the offset/length pair
     506             : */
     507        8620 : NTSTATUS smb2_pull_o16s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
     508             : {
     509           2 :         uint16_t ofs;
     510           2 :         uint32_t size;
     511             : 
     512        8620 :         if (smb2_oob(buf, ptr, 6)) {
     513           0 :                 return NT_STATUS_INVALID_PARAMETER;
     514             :         }
     515        8620 :         ofs  = SVAL(ptr, 0);
     516        8620 :         size = IVAL(ptr, 2);
     517        8620 :         if (ofs == 0) {
     518        1284 :                 *blob = data_blob(NULL, 0);
     519        1284 :                 return NT_STATUS_OK;
     520             :         }
     521        7336 :         if (smb2_oob(buf, buf->hdr + ofs, size)) {
     522           0 :                 return NT_STATUS_INVALID_PARAMETER;
     523             :         }
     524        7336 :         *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
     525        7336 :         NT_STATUS_HAVE_NO_MEMORY(blob->data);
     526        7336 :         return NT_STATUS_OK;
     527             : }
     528             : 
     529             : /*
     530             :   pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
     531             :   the ptr points to the start of the offset/length pair
     532             : */
     533      781504 : NTSTATUS smb2_pull_o32s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
     534             : {
     535         173 :         uint32_t ofs, size;
     536      781504 :         if (smb2_oob(buf, ptr, 8)) {
     537           0 :                 return NT_STATUS_INVALID_PARAMETER;
     538             :         }
     539      781504 :         ofs  = IVAL(ptr, 0);
     540      781504 :         size = IVAL(ptr, 4);
     541      781504 :         if (ofs == 0) {
     542      678624 :                 *blob = data_blob(NULL, 0);
     543      678624 :                 return NT_STATUS_OK;
     544             :         }
     545      102880 :         if (smb2_oob(buf, buf->hdr + ofs, size)) {
     546           0 :                 return NT_STATUS_INVALID_PARAMETER;
     547             :         }
     548      102880 :         *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
     549      102880 :         NT_STATUS_HAVE_NO_MEMORY(blob->data);
     550      102880 :         return NT_STATUS_OK;
     551             : }
     552             : 
     553             : /*
     554             :   pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
     555             :   the ptr points to the start of the offset/length pair
     556             :   
     557             :   In this variant the uint16_t is padded by an extra 2 bytes, making
     558             :   the size aligned on 4 byte boundary
     559             : */
     560         981 : NTSTATUS smb2_pull_o16As32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
     561             : {
     562           0 :         uint32_t ofs, size;
     563         981 :         if (smb2_oob(buf, ptr, 8)) {
     564           0 :                 return NT_STATUS_INVALID_PARAMETER;
     565             :         }
     566         981 :         ofs  = SVAL(ptr, 0);
     567         981 :         size = IVAL(ptr, 4);
     568         981 :         if (ofs == 0) {
     569         980 :                 *blob = data_blob(NULL, 0);
     570         980 :                 return NT_STATUS_OK;
     571             :         }
     572           1 :         if (smb2_oob(buf, buf->hdr + ofs, size)) {
     573           0 :                 return NT_STATUS_INVALID_PARAMETER;
     574             :         }
     575           1 :         *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
     576           1 :         NT_STATUS_HAVE_NO_MEMORY(blob->data);
     577           1 :         return NT_STATUS_OK;
     578             : }
     579             : 
     580             : /*
     581             :   pull a uint32_t length/ uint32_t ofs/blob triple from a data blob
     582             :   the ptr points to the start of the offset/length pair
     583             : */
     584           0 : NTSTATUS smb2_pull_s32o32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
     585             : {
     586           0 :         uint32_t ofs, size;
     587           0 :         if (smb2_oob(buf, ptr, 8)) {
     588           0 :                 return NT_STATUS_INVALID_PARAMETER;
     589             :         }
     590           0 :         size = IVAL(ptr, 0);
     591           0 :         ofs  = IVAL(ptr, 4);
     592           0 :         if (ofs == 0) {
     593           0 :                 *blob = data_blob(NULL, 0);
     594           0 :                 return NT_STATUS_OK;
     595             :         }
     596           0 :         if (smb2_oob(buf, buf->hdr + ofs, size)) {
     597           0 :                 return NT_STATUS_INVALID_PARAMETER;
     598             :         }
     599           0 :         *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
     600           0 :         NT_STATUS_HAVE_NO_MEMORY(blob->data);
     601           0 :         return NT_STATUS_OK;
     602             : }
     603             : 
     604             : /*
     605             :   pull a uint32_t length/ uint16_t ofs/blob triple from a data blob
     606             :   the ptr points to the start of the offset/length pair
     607             : */
     608         458 : NTSTATUS smb2_pull_s32o16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
     609             : {
     610           0 :         uint32_t ofs, size;
     611         458 :         if (smb2_oob(buf, ptr, 8)) {
     612           0 :                 return NT_STATUS_INVALID_PARAMETER;
     613             :         }
     614         458 :         size = IVAL(ptr, 0);
     615         458 :         ofs  = SVAL(ptr, 4);
     616         458 :         if (ofs == 0) {
     617           0 :                 *blob = data_blob(NULL, 0);
     618           0 :                 return NT_STATUS_OK;
     619             :         }
     620         458 :         if (smb2_oob(buf, buf->hdr + ofs, size)) {
     621           0 :                 return NT_STATUS_INVALID_PARAMETER;
     622             :         }
     623         458 :         *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
     624         458 :         NT_STATUS_HAVE_NO_MEMORY(blob->data);
     625         458 :         return NT_STATUS_OK;
     626             : }
     627             : 
     628             : /*
     629             :   pull a string in a uint16_t ofs/ uint16_t length/blob format
     630             :   UTF-16 without termination
     631             : */
     632      212154 : NTSTATUS smb2_pull_o16s16_string(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx,
     633             :                                  uint8_t *ptr, const char **str)
     634             : {
     635           0 :         DATA_BLOB blob;
     636           0 :         NTSTATUS status;
     637           0 :         void *vstr;
     638      212154 :         size_t converted_size = 0;
     639           0 :         bool ret;
     640             : 
     641      212154 :         status = smb2_pull_o16s16_blob(buf, mem_ctx, ptr, &blob);
     642      212154 :         NT_STATUS_NOT_OK_RETURN(status);
     643             : 
     644      212154 :         if (blob.data == NULL) {
     645           0 :                 *str = NULL;
     646           0 :                 return NT_STATUS_OK;
     647             :         }
     648             : 
     649      212154 :         if (blob.length == 0) {
     650           0 :                 char *s;
     651        5647 :                 s = talloc_strdup(mem_ctx, "");
     652        5647 :                 NT_STATUS_HAVE_NO_MEMORY(s);
     653        5647 :                 *str = s;
     654        5647 :                 return NT_STATUS_OK;
     655             :         }
     656             : 
     657      206507 :         ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, 
     658      206507 :                                      blob.data, blob.length, &vstr, &converted_size);
     659      206507 :         data_blob_free(&blob);
     660      206507 :         (*str) = (char *)vstr;
     661      206507 :         if (!ret) {
     662           0 :                 return NT_STATUS_ILLEGAL_CHARACTER;
     663             :         }
     664      206507 :         return NT_STATUS_OK;
     665             : }
     666             : 
     667             : /*
     668             :   push a string in a uint16_t ofs/ uint16_t length/blob format
     669             :   UTF-16 without termination
     670             : */
     671      644828 : NTSTATUS smb2_push_o16s16_string(struct smb2_request_buffer *buf,
     672             :                                  uint16_t ofs, const char *str)
     673             : {
     674         367 :         DATA_BLOB blob;
     675         367 :         NTSTATUS status;
     676         367 :         bool ret;
     677      644828 :         void *ptr = NULL;
     678             : 
     679      644828 :         if (str == NULL) {
     680           0 :                 return smb2_push_o16s16_blob(buf, ofs, data_blob(NULL, 0));
     681             :         }
     682             : 
     683      644828 :         if (*str == 0) {
     684       31424 :                 blob.data = discard_const_p(uint8_t, str);
     685       31424 :                 blob.length = 0;
     686       31424 :                 return smb2_push_o16s16_blob(buf, ofs, blob);
     687             :         }
     688             : 
     689      613404 :         ret = convert_string_talloc(buf->buffer, CH_UNIX, CH_UTF16, 
     690             :                                     str, strlen(str), &ptr, &blob.length);
     691      613404 :         if (!ret) {
     692           0 :                 return NT_STATUS_ILLEGAL_CHARACTER;
     693             :         }
     694      613404 :         blob.data = (uint8_t *)ptr;
     695             : 
     696      613404 :         status = smb2_push_o16s16_blob(buf, ofs, blob);
     697      613404 :         data_blob_free(&blob);
     698      613404 :         return status;
     699             : }
     700             : 
     701             : /*
     702             :   push a file handle into a buffer
     703             : */
     704      569730 : void smb2_push_handle(uint8_t *data, struct smb2_handle *h)
     705             : {
     706      569730 :         SBVAL(data, 0, h->data[0]);
     707      569730 :         SBVAL(data, 8, h->data[1]);
     708      569730 : }
     709             : 
     710             : /*
     711             :   pull a file handle from a buffer
     712             : */
     713      521802 : void smb2_pull_handle(uint8_t *ptr, struct smb2_handle *h)
     714             : {
     715      521802 :         h->data[0] = BVAL(ptr, 0);
     716      521802 :         h->data[1] = BVAL(ptr, 8);
     717      521802 : }

Generated by: LCOV version 1.14