2005-11-11 07:45:38 +03:00
/*
Unix SMB / CIFS implementation .
SMB2 client request handling
2005-11-16 14:01:15 +03:00
Copyright ( C ) Andrew Tridgell 2005
Copyright ( C ) Stefan Metzmacher 2005
2005-11-11 07:45:38 +03:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2005-11-11 07:45:38 +03:00
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-11-11 07:45:38 +03:00
*/
# include "includes.h"
# include "libcli/raw/libcliraw.h"
# include "libcli/smb2/smb2.h"
2008-10-11 23:31:42 +04:00
# include "../lib/util/dlinklist.h"
2005-11-11 07:45:38 +03:00
# include "lib/events/events.h"
2007-09-08 17:27:14 +04:00
# include "libcli/smb2/smb2_calls.h"
2005-11-11 07:45:38 +03:00
2008-02-14 02:12:33 +03:00
/* fill in the bufinfo */
void smb2_setup_bufinfo ( struct smb2_request * req )
{
req - > in . bufinfo . mem_ctx = req ;
2008-02-14 04:30:31 +03:00
req - > in . bufinfo . flags = BUFINFO_FLAG_UNICODE | BUFINFO_FLAG_SMB2 ;
2008-02-14 02:12:33 +03:00
req - > in . bufinfo . align_base = req - > in . buffer ;
if ( req - > in . dynamic ) {
req - > in . bufinfo . data = req - > in . dynamic ;
req - > in . bufinfo . data_size = req - > in . body_size - req - > in . body_fixed ;
} else {
req - > in . bufinfo . data = NULL ;
req - > in . bufinfo . data_size = 0 ;
}
}
2005-11-11 07:45:38 +03:00
/*
initialise a smb2 request
*/
2005-11-16 14:01:15 +03:00
struct smb2_request * smb2_request_init ( struct smb2_transport * transport , uint16_t opcode ,
2007-10-07 02:28:14 +04:00
uint16_t body_fixed_size , bool body_dynamic_present ,
2006-05-11 14:47:37 +04:00
uint32_t body_dynamic_size )
2005-11-11 07:45:38 +03:00
{
struct smb2_request * req ;
2009-06-08 18:24:27 +04:00
uint32_t hdr_offset ;
2009-06-09 17:04:53 +04:00
bool compound = false ;
2005-11-11 07:45:38 +03:00
2006-05-11 14:47:37 +04:00
if ( body_dynamic_present ) {
if ( body_dynamic_size = = 0 ) {
body_dynamic_size = 1 ;
}
} else {
body_dynamic_size = 0 ;
}
2011-09-24 11:36:58 +04:00
req = talloc_zero ( transport , struct smb2_request ) ;
2005-11-11 07:45:38 +03:00
if ( req = = NULL ) return NULL ;
req - > state = SMB2_REQUEST_INIT ;
req - > transport = transport ;
2011-09-24 11:36:58 +04:00
hdr_offset = NBT_HDR_SIZE ;
2009-06-08 18:24:27 +04:00
req - > out . size = hdr_offset + SMB2_HDR_BODY + body_fixed_size ;
2005-11-17 06:32:38 +03:00
req - > out . allocated = req - > out . size + body_dynamic_size ;
2009-06-08 18:24:27 +04:00
req - > out . buffer = talloc_realloc ( req , req - > out . buffer ,
uint8_t , req - > out . allocated ) ;
2005-11-11 07:45:38 +03:00
if ( req - > out . buffer = = NULL ) {
talloc_free ( req ) ;
return NULL ;
}
2009-06-08 18:24:27 +04:00
req - > out . hdr = req - > out . buffer + hdr_offset ;
2005-11-11 07:45:38 +03:00
req - > out . body = req - > out . hdr + SMB2_HDR_BODY ;
2006-06-30 03:11:07 +04:00
req - > out . body_fixed = body_fixed_size ;
2005-11-16 14:01:15 +03:00
req - > out . body_size = body_fixed_size ;
req - > out . dynamic = ( body_dynamic_size ? req - > out . body + body_fixed_size : NULL ) ;
2005-11-11 07:45:38 +03:00
2007-05-14 22:02:49 +04:00
SIVAL ( req - > out . hdr , 0 , SMB2_MAGIC ) ;
SSVAL ( req - > out . hdr , SMB2_HDR_LENGTH , SMB2_HDR_BODY ) ;
2011-09-20 22:59:45 +04:00
SSVAL ( req - > out . hdr , SMB2_HDR_CREDIT_CHARGE , 0 ) ;
2007-05-14 22:02:49 +04:00
SIVAL ( req - > out . hdr , SMB2_HDR_STATUS , 0 ) ;
SSVAL ( req - > out . hdr , SMB2_HDR_OPCODE , opcode ) ;
2011-09-20 22:59:45 +04:00
SSVAL ( req - > out . hdr , SMB2_HDR_CREDIT , 0 ) ;
SIVAL ( req - > out . hdr , SMB2_HDR_FLAGS , 0 ) ;
2008-02-12 09:00:35 +03:00
SIVAL ( req - > out . hdr , SMB2_HDR_NEXT_COMMAND , 0 ) ;
2011-09-20 22:59:45 +04:00
SBVAL ( req - > out . hdr , SMB2_HDR_MESSAGE_ID , 0 ) ;
2007-05-14 22:02:49 +04:00
SIVAL ( req - > out . hdr , SMB2_HDR_PID , 0 ) ;
SIVAL ( req - > out . hdr , SMB2_HDR_TID , 0 ) ;
2008-02-12 09:00:35 +03:00
SBVAL ( req - > out . hdr , SMB2_HDR_SESSION_ID , 0 ) ;
memset ( req - > out . hdr + SMB2_HDR_SIGNATURE , 0 , 16 ) ;
2005-11-11 07:45:38 +03:00
2005-11-16 14:01:15 +03:00
/* set the length of the fixed body part and +1 if there's a dynamic part also */
SSVAL ( req - > out . body , 0 , body_fixed_size + ( body_dynamic_size ? 1 : 0 ) ) ;
/*
* if we have a dynamic part , make sure the first byte
* which is always be part of the packet is initialized
*/
2009-06-09 17:04:53 +04:00
if ( body_dynamic_size & & ! compound ) {
2006-05-21 14:13:49 +04:00
req - > out . size + = 1 ;
2005-11-16 14:01:15 +03:00
SCVAL ( req - > out . dynamic , 0 , 0 ) ;
}
2005-11-11 07:45:38 +03:00
return req ;
}
2005-11-11 15:37:16 +03:00
/*
initialise a smb2 request for tree operations
*/
2005-11-16 14:01:15 +03:00
struct smb2_request * smb2_request_init_tree ( struct smb2_tree * tree , uint16_t opcode ,
2007-10-07 02:28:14 +04:00
uint16_t body_fixed_size , bool body_dynamic_present ,
2006-05-11 14:47:37 +04:00
uint32_t body_dynamic_size )
2005-11-11 15:37:16 +03:00
{
struct smb2_request * req = smb2_request_init ( tree - > session - > transport , opcode ,
2006-05-11 14:47:37 +04:00
body_fixed_size , body_dynamic_present ,
body_dynamic_size ) ;
2005-11-11 15:37:16 +03:00
if ( req = = NULL ) return NULL ;
2005-11-12 04:08:43 +03:00
req - > session = tree - > session ;
req - > tree = tree ;
2005-11-11 15:37:16 +03:00
return req ;
}
2005-11-11 07:45:38 +03:00
/* destroy a request structure and return final status */
NTSTATUS smb2_request_destroy ( struct smb2_request * req )
{
NTSTATUS status ;
/* this is the error code we give the application for when a
_send ( ) call fails completely */
if ( ! req ) return NT_STATUS_UNSUCCESSFUL ;
2006-03-15 08:52:45 +03:00
if ( req - > state = = SMB2_REQUEST_ERROR & &
2005-11-11 07:45:38 +03:00
NT_STATUS_IS_OK ( req - > status ) ) {
2008-05-16 09:03:58 +04:00
status = NT_STATUS_INTERNAL_ERROR ;
} else {
status = req - > status ;
2005-11-11 07:45:38 +03:00
}
talloc_free ( req ) ;
return status ;
}
/*
receive a response to a packet
*/
2007-10-07 02:28:14 +04:00
bool smb2_request_receive ( struct smb2_request * req )
2005-11-11 07:45:38 +03:00
{
/* req can be NULL when a send has failed. This eliminates lots of NULL
checks in each module */
2007-10-07 02:28:14 +04:00
if ( ! req ) return false ;
2005-11-11 07:45:38 +03:00
/* keep receiving packets until this one is replied to */
while ( req - > state < = SMB2_REQUEST_RECV ) {
2011-09-20 22:59:45 +04:00
if ( tevent_loop_once ( req - > transport - > ev ) ! = 0 ) {
2007-10-07 02:28:14 +04:00
return false ;
2005-11-11 07:45:38 +03:00
}
}
return req - > state = = SMB2_REQUEST_DONE ;
}
/* Return true if the last packet was in error */
2007-10-07 02:28:14 +04:00
bool smb2_request_is_error ( struct smb2_request * req )
2005-11-11 07:45:38 +03:00
{
return NT_STATUS_IS_ERR ( req - > status ) ;
}
2005-11-18 12:25:25 +03:00
/* Return true if the last packet was OK */
2007-10-07 02:28:14 +04:00
bool smb2_request_is_ok ( struct smb2_request * req )
2005-11-18 12:25:25 +03:00
{
return NT_STATUS_IS_OK ( req - > status ) ;
}
2005-11-11 07:45:38 +03:00
/*
check if a range in the reply body is out of bounds
*/
2007-10-07 02:28:14 +04:00
bool smb2_oob ( struct smb2_request_buffer * buf , const uint8_t * ptr , size_t size )
2005-11-11 07:45:38 +03:00
{
2008-02-15 23:25:38 +03:00
if ( size = = 0 ) {
/* zero bytes is never out of range */
return false ;
}
2005-11-11 07:45:38 +03:00
/* be careful with wraparound! */
2008-04-17 17:20:39 +04:00
if ( ( uintptr_t ) ptr < ( uintptr_t ) buf - > body | |
( uintptr_t ) ptr > = ( uintptr_t ) buf - > body + buf - > body_size | |
2005-11-14 15:31:02 +03:00
size > buf - > body_size | |
2008-04-17 17:20:39 +04:00
( uintptr_t ) ptr + size > ( uintptr_t ) buf - > body + buf - > body_size ) {
2007-10-07 02:28:14 +04:00
return true ;
2005-11-11 07:45:38 +03:00
}
2007-10-07 02:28:14 +04:00
return false ;
2005-11-11 07:45:38 +03:00
}
2005-11-18 14:45:24 +03:00
size_t smb2_padding_size ( uint32_t offset , size_t n )
2005-11-16 14:01:15 +03:00
{
if ( ( offset & ( n - 1 ) ) = = 0 ) return 0 ;
return n - ( offset & ( n - 1 ) ) ;
}
2006-06-30 03:11:07 +04:00
static size_t smb2_padding_fix ( struct smb2_request_buffer * buf )
{
if ( buf - > dynamic = = ( buf - > body + buf - > body_fixed ) ) {
2009-06-09 17:04:53 +04:00
if ( buf - > dynamic ! = ( buf - > buffer + buf - > size ) ) {
return 1 ;
}
2006-06-30 03:11:07 +04:00
}
return 0 ;
}
2005-11-17 06:32:38 +03:00
/*
grow a SMB2 buffer by the specified amount
*/
2009-06-08 18:24:27 +04:00
NTSTATUS smb2_grow_buffer ( struct smb2_request_buffer * buf , size_t increase )
2005-11-16 14:01:15 +03:00
{
2009-06-08 18:24:27 +04:00
size_t hdr_ofs ;
2005-11-16 14:01:15 +03:00
size_t dynamic_ofs ;
uint8_t * buffer_ptr ;
2005-11-17 06:32:38 +03:00
uint32_t newsize = buf - > size + increase ;
2005-11-16 14:01:15 +03:00
/* a packet size should be limited a bit */
2005-11-17 06:32:38 +03:00
if ( newsize > = 0x00FFFFFF ) return NT_STATUS_MARSHALL_OVERFLOW ;
2005-11-16 14:01:15 +03:00
2005-11-17 06:32:38 +03:00
if ( newsize < = buf - > allocated ) return NT_STATUS_OK ;
2005-11-16 14:01:15 +03:00
2009-06-08 18:24:27 +04:00
hdr_ofs = buf - > hdr - buf - > buffer ;
2005-11-16 14:01:15 +03:00
dynamic_ofs = buf - > dynamic - buf - > buffer ;
2007-09-07 17:31:15 +04:00
buffer_ptr = talloc_realloc ( buf , buf - > buffer , uint8_t , newsize ) ;
2005-11-16 14:01:15 +03:00
NT_STATUS_HAVE_NO_MEMORY ( buffer_ptr ) ;
buf - > buffer = buffer_ptr ;
2009-06-08 18:24:27 +04:00
buf - > hdr = buf - > buffer + hdr_ofs ;
2005-11-16 14:01:15 +03:00
buf - > body = buf - > hdr + SMB2_HDR_BODY ;
buf - > dynamic = buf - > buffer + dynamic_ofs ;
2005-11-17 06:32:38 +03:00
buf - > allocated = newsize ;
2005-11-16 14:01:15 +03:00
return NT_STATUS_OK ;
}
2005-11-11 10:23:45 +03:00
/*
2005-11-16 14:01:15 +03:00
pull a uint16_t ofs / uint16_t length / blob triple from a data blob
the ptr points to the start of the offset / length pair
2005-11-11 10:23:45 +03:00
*/
2005-11-16 14:01:15 +03:00
NTSTATUS smb2_pull_o16s16_blob ( struct smb2_request_buffer * buf , TALLOC_CTX * mem_ctx , uint8_t * ptr , DATA_BLOB * blob )
2005-11-11 10:23:45 +03:00
{
2005-11-16 14:01:15 +03:00
uint16_t ofs , size ;
if ( smb2_oob ( buf , ptr , 4 ) ) {
2008-09-25 04:28:58 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2005-11-16 14:01:15 +03:00
}
ofs = SVAL ( ptr , 0 ) ;
size = SVAL ( ptr , 2 ) ;
2008-02-15 23:25:38 +03:00
if ( ofs = = 0 ) {
2005-11-16 14:01:15 +03:00
* blob = data_blob ( NULL , 0 ) ;
return NT_STATUS_OK ;
}
if ( smb2_oob ( buf , buf - > hdr + ofs , size ) ) {
2008-09-25 04:28:58 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2005-11-11 10:23:45 +03:00
}
2005-11-16 14:01:15 +03:00
* blob = data_blob_talloc ( mem_ctx , buf - > hdr + ofs , size ) ;
NT_STATUS_HAVE_NO_MEMORY ( blob - > data ) ;
return NT_STATUS_OK ;
2005-11-11 10:23:45 +03:00
}
2005-11-11 07:45:38 +03:00
/*
2005-11-16 14:01:15 +03:00
push a uint16_t ofs / uint16_t length / blob triple into a data blob
2005-11-17 06:32:38 +03:00
the ofs points to the start of the offset / length pair , and is relative
to the body start
2005-11-11 07:45:38 +03:00
*/
2005-11-17 06:32:38 +03:00
NTSTATUS smb2_push_o16s16_blob ( struct smb2_request_buffer * buf ,
uint16_t ofs , DATA_BLOB blob )
2005-11-11 07:45:38 +03:00
{
2005-11-16 14:01:15 +03:00
NTSTATUS status ;
size_t offset ;
size_t padding_length ;
2006-06-30 03:11:07 +04:00
size_t padding_fix ;
2005-11-17 06:32:38 +03:00
uint8_t * ptr = buf - > body + ofs ;
2005-11-16 14:01:15 +03:00
2005-11-17 06:32:38 +03:00
if ( buf - > dynamic = = NULL ) {
2005-11-16 14:01:15 +03:00
return NT_STATUS_INVALID_PARAMETER ;
}
/* we have only 16 bit for the size */
if ( blob . length > 0xFFFF ) {
2008-09-25 04:28:58 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2005-11-11 07:45:38 +03:00
}
2005-11-16 14:01:15 +03:00
/* check if there're enough room for ofs and size */
if ( smb2_oob ( buf , ptr , 4 ) ) {
2008-09-25 04:28:58 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2005-11-16 14:01:15 +03:00
}
2008-02-15 23:25:38 +03:00
if ( blob . data = = NULL ) {
if ( blob . length ! = 0 ) {
return NT_STATUS_INTERNAL_ERROR ;
}
2005-11-16 16:34:56 +03:00
SSVAL ( ptr , 0 , 0 ) ;
2005-11-16 18:47:44 +03:00
SSVAL ( ptr , 2 , 0 ) ;
2005-11-16 16:34:56 +03:00
return NT_STATUS_OK ;
}
2005-11-16 14:01:15 +03:00
offset = buf - > dynamic - buf - > hdr ;
padding_length = smb2_padding_size ( offset , 2 ) ;
offset + = padding_length ;
2006-06-30 03:11:07 +04:00
padding_fix = smb2_padding_fix ( buf ) ;
2005-11-16 14:01:15 +03:00
SSVAL ( ptr , 0 , offset ) ;
SSVAL ( ptr , 2 , blob . length ) ;
2006-07-08 12:34:35 +04:00
status = smb2_grow_buffer ( buf , blob . length + padding_length - padding_fix ) ;
2005-11-16 14:01:15 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
memset ( buf - > dynamic , 0 , padding_length ) ;
buf - > dynamic + = padding_length ;
memcpy ( buf - > dynamic , blob . data , blob . length ) ;
buf - > dynamic + = blob . length ;
2006-06-30 03:11:07 +04:00
buf - > size + = blob . length + padding_length - padding_fix ;
2006-07-08 12:34:35 +04:00
buf - > body_size + = blob . length + padding_length ;
2005-11-16 14:01:15 +03:00
2005-11-14 15:31:02 +03:00
return NT_STATUS_OK ;
2005-11-11 07:45:38 +03:00
}
2005-11-11 10:23:45 +03:00
/*
2005-11-16 14:01:15 +03:00
push a uint16_t ofs / uint32_t length / blob triple into a data blob
2005-11-17 06:32:38 +03:00
the ofs points to the start of the offset / length pair , and is relative
to the body start
2005-11-16 14:01:15 +03:00
*/
2005-11-17 06:32:38 +03:00
NTSTATUS smb2_push_o16s32_blob ( struct smb2_request_buffer * buf ,
uint16_t ofs , DATA_BLOB blob )
2005-11-16 14:01:15 +03:00
{
NTSTATUS status ;
size_t offset ;
size_t padding_length ;
2006-06-30 03:11:07 +04:00
size_t padding_fix ;
2005-11-17 06:32:38 +03:00
uint8_t * ptr = buf - > body + ofs ;
2005-11-11 10:23:45 +03:00
2005-11-17 06:32:38 +03:00
if ( buf - > dynamic = = NULL ) {
2005-11-16 14:01:15 +03:00
return NT_STATUS_INVALID_PARAMETER ;
}
/* check if there're enough room for ofs and size */
if ( smb2_oob ( buf , ptr , 6 ) ) {
2008-09-25 04:28:58 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2005-11-16 14:01:15 +03:00
}
2008-02-15 23:25:38 +03:00
if ( blob . data = = NULL ) {
if ( blob . length ! = 0 ) {
return NT_STATUS_INTERNAL_ERROR ;
}
2005-11-16 16:34:56 +03:00
SSVAL ( ptr , 0 , 0 ) ;
2005-11-16 18:47:44 +03:00
SIVAL ( ptr , 2 , 0 ) ;
2005-11-16 16:34:56 +03:00
return NT_STATUS_OK ;
}
2005-11-16 14:01:15 +03:00
offset = buf - > dynamic - buf - > hdr ;
padding_length = smb2_padding_size ( offset , 2 ) ;
offset + = padding_length ;
2006-06-30 03:11:07 +04:00
padding_fix = smb2_padding_fix ( buf ) ;
2005-11-16 14:01:15 +03:00
SSVAL ( ptr , 0 , offset ) ;
SIVAL ( ptr , 2 , blob . length ) ;
2006-07-08 12:34:35 +04:00
status = smb2_grow_buffer ( buf , blob . length + padding_length - padding_fix ) ;
2005-11-16 14:01:15 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
memset ( buf - > dynamic , 0 , padding_length ) ;
buf - > dynamic + = padding_length ;
memcpy ( buf - > dynamic , blob . data , blob . length ) ;
buf - > dynamic + = blob . length ;
2006-06-30 03:11:07 +04:00
buf - > size + = blob . length + padding_length - padding_fix ;
2006-07-08 12:34:35 +04:00
buf - > body_size + = blob . length + padding_length ;
2005-11-16 14:01:15 +03:00
return NT_STATUS_OK ;
}
2005-11-11 12:11:51 +03:00
/*
2005-11-16 14:01:15 +03:00
push a uint32_t ofs / uint32_t length / blob triple into a data blob
2005-11-17 06:32:38 +03:00
the ofs points to the start of the offset / length pair , and is relative
to the body start
2005-11-11 12:11:51 +03:00
*/
2005-11-17 06:32:38 +03:00
NTSTATUS smb2_push_o32s32_blob ( struct smb2_request_buffer * buf ,
uint32_t ofs , DATA_BLOB blob )
2005-11-16 14:01:15 +03:00
{
NTSTATUS status ;
size_t offset ;
size_t padding_length ;
2006-06-30 03:11:07 +04:00
size_t padding_fix ;
2005-11-17 06:32:38 +03:00
uint8_t * ptr = buf - > body + ofs ;
2005-11-16 14:01:15 +03:00
2005-11-17 06:32:38 +03:00
if ( buf - > dynamic = = NULL ) {
2005-11-16 14:01:15 +03:00
return NT_STATUS_INVALID_PARAMETER ;
}
/* check if there're enough room for ofs and size */
if ( smb2_oob ( buf , ptr , 8 ) ) {
2008-09-25 04:28:58 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2005-11-16 14:01:15 +03:00
}
2008-02-15 23:25:38 +03:00
if ( blob . data = = NULL ) {
if ( blob . length ! = 0 ) {
return NT_STATUS_INTERNAL_ERROR ;
}
2005-11-16 16:34:56 +03:00
SIVAL ( ptr , 0 , 0 ) ;
SIVAL ( ptr , 4 , 0 ) ;
return NT_STATUS_OK ;
}
2005-11-16 14:01:15 +03:00
offset = buf - > dynamic - buf - > hdr ;
padding_length = smb2_padding_size ( offset , 8 ) ;
offset + = padding_length ;
2006-06-30 03:11:07 +04:00
padding_fix = smb2_padding_fix ( buf ) ;
2005-11-16 14:01:15 +03:00
SIVAL ( ptr , 0 , offset ) ;
SIVAL ( ptr , 4 , blob . length ) ;
2006-07-08 12:34:35 +04:00
status = smb2_grow_buffer ( buf , blob . length + padding_length - padding_fix ) ;
2005-11-16 14:01:15 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
memset ( buf - > dynamic , 0 , padding_length ) ;
buf - > dynamic + = padding_length ;
memcpy ( buf - > dynamic , blob . data , blob . length ) ;
buf - > dynamic + = blob . length ;
2005-11-18 09:28:15 +03:00
2006-06-30 03:11:07 +04:00
buf - > size + = blob . length + padding_length - padding_fix ;
2006-07-08 12:34:35 +04:00
buf - > body_size + = blob . length + padding_length ;
2005-11-18 09:28:15 +03:00
return NT_STATUS_OK ;
}
/*
push a uint32_t length / uint32_t ofs / blob triple into a data blob
the ofs points to the start of the length / offset pair , and is relative
to the body start
*/
NTSTATUS smb2_push_s32o32_blob ( struct smb2_request_buffer * buf ,
uint32_t ofs , DATA_BLOB blob )
{
NTSTATUS status ;
size_t offset ;
size_t padding_length ;
2006-06-30 03:11:07 +04:00
size_t padding_fix ;
2005-11-18 09:28:15 +03:00
uint8_t * ptr = buf - > body + ofs ;
if ( buf - > dynamic = = NULL ) {
return NT_STATUS_INVALID_PARAMETER ;
}
/* check if there're enough room for ofs and size */
if ( smb2_oob ( buf , ptr , 8 ) ) {
2008-09-25 04:28:58 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2005-11-18 09:28:15 +03:00
}
2008-02-15 23:25:38 +03:00
if ( blob . data = = NULL ) {
if ( blob . length ! = 0 ) {
return NT_STATUS_INTERNAL_ERROR ;
}
2005-11-18 09:28:15 +03:00
SIVAL ( ptr , 0 , 0 ) ;
SIVAL ( ptr , 4 , 0 ) ;
return NT_STATUS_OK ;
}
offset = buf - > dynamic - buf - > hdr ;
padding_length = smb2_padding_size ( offset , 8 ) ;
offset + = padding_length ;
2006-06-30 03:11:07 +04:00
padding_fix = smb2_padding_fix ( buf ) ;
2005-11-18 09:28:15 +03:00
SIVAL ( ptr , 0 , blob . length ) ;
SIVAL ( ptr , 4 , offset ) ;
2006-07-08 12:34:35 +04:00
status = smb2_grow_buffer ( buf , blob . length + padding_length - padding_fix ) ;
2005-11-18 09:28:15 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
memset ( buf - > dynamic , 0 , padding_length ) ;
buf - > dynamic + = padding_length ;
memcpy ( buf - > dynamic , blob . data , blob . length ) ;
buf - > dynamic + = blob . length ;
2005-11-16 14:01:15 +03:00
2006-06-30 03:11:07 +04:00
buf - > size + = blob . length + padding_length - padding_fix ;
2006-07-08 12:34:35 +04:00
buf - > body_size + = blob . length + padding_length ;
2005-11-17 06:32:38 +03:00
return NT_STATUS_OK ;
}
/*
pull a uint16_t ofs / uint32_t length / blob triple from a data blob
the ptr points to the start of the offset / length pair
*/
NTSTATUS smb2_pull_o16s32_blob ( struct smb2_request_buffer * buf , TALLOC_CTX * mem_ctx , uint8_t * ptr , DATA_BLOB * blob )
{
uint16_t ofs ;
uint32_t size ;
if ( smb2_oob ( buf , ptr , 6 ) ) {
2008-09-25 04:28:58 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2005-11-17 06:32:38 +03:00
}
ofs = SVAL ( ptr , 0 ) ;
size = IVAL ( ptr , 2 ) ;
2008-02-15 23:25:38 +03:00
if ( ofs = = 0 ) {
2005-11-17 06:32:38 +03:00
* blob = data_blob ( NULL , 0 ) ;
return NT_STATUS_OK ;
}
if ( smb2_oob ( buf , buf - > hdr + ofs , size ) ) {
2008-09-25 04:28:58 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2005-11-17 06:32:38 +03:00
}
* blob = data_blob_talloc ( mem_ctx , buf - > hdr + ofs , size ) ;
NT_STATUS_HAVE_NO_MEMORY ( blob - > data ) ;
return NT_STATUS_OK ;
}
2005-11-16 14:01:15 +03:00
2005-11-17 06:32:38 +03:00
/*
pull a uint32_t ofs / uint32_t length / blob triple from a data blob
the ptr points to the start of the offset / length pair
*/
NTSTATUS smb2_pull_o32s32_blob ( struct smb2_request_buffer * buf , TALLOC_CTX * mem_ctx , uint8_t * ptr , DATA_BLOB * blob )
{
uint32_t ofs , size ;
if ( smb2_oob ( buf , ptr , 8 ) ) {
2008-09-25 04:28:58 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2005-11-17 06:32:38 +03:00
}
ofs = IVAL ( ptr , 0 ) ;
size = IVAL ( ptr , 4 ) ;
2008-02-15 23:25:38 +03:00
if ( ofs = = 0 ) {
2005-11-17 06:32:38 +03:00
* blob = data_blob ( NULL , 0 ) ;
return NT_STATUS_OK ;
}
if ( smb2_oob ( buf , buf - > hdr + ofs , size ) ) {
2008-09-25 04:28:58 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2005-11-17 06:32:38 +03:00
}
* blob = data_blob_talloc ( mem_ctx , buf - > hdr + ofs , size ) ;
NT_STATUS_HAVE_NO_MEMORY ( blob - > data ) ;
2005-11-16 14:01:15 +03:00
return NT_STATUS_OK ;
}
2008-02-14 09:11:36 +03:00
/*
pull a uint16_t ofs / uint32_t length / blob triple from a data blob
the ptr points to the start of the offset / length pair
In this varient the uint16_t is padded by an extra 2 bytes , making
the size aligned on 4 byte boundary
*/
NTSTATUS smb2_pull_o16As32_blob ( struct smb2_request_buffer * buf , TALLOC_CTX * mem_ctx , uint8_t * ptr , DATA_BLOB * blob )
{
uint32_t ofs , size ;
if ( smb2_oob ( buf , ptr , 8 ) ) {
2008-09-25 04:28:58 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2008-02-14 09:11:36 +03:00
}
ofs = SVAL ( ptr , 0 ) ;
size = IVAL ( ptr , 4 ) ;
2008-02-15 23:25:38 +03:00
if ( ofs = = 0 ) {
2008-02-14 09:11:36 +03:00
* blob = data_blob ( NULL , 0 ) ;
return NT_STATUS_OK ;
}
if ( smb2_oob ( buf , buf - > hdr + ofs , size ) ) {
2008-09-25 04:28:58 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2008-02-14 09:11:36 +03:00
}
* blob = data_blob_talloc ( mem_ctx , buf - > hdr + ofs , size ) ;
NT_STATUS_HAVE_NO_MEMORY ( blob - > data ) ;
return NT_STATUS_OK ;
}
2006-06-27 21:16:14 +04:00
/*
pull a uint32_t length / uint32_t ofs / blob triple from a data blob
the ptr points to the start of the offset / length pair
*/
NTSTATUS smb2_pull_s32o32_blob ( struct smb2_request_buffer * buf , TALLOC_CTX * mem_ctx , uint8_t * ptr , DATA_BLOB * blob )
{
uint32_t ofs , size ;
if ( smb2_oob ( buf , ptr , 8 ) ) {
2008-09-25 04:28:58 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2006-06-27 21:16:14 +04:00
}
size = IVAL ( ptr , 0 ) ;
ofs = IVAL ( ptr , 4 ) ;
2008-02-15 23:25:38 +03:00
if ( ofs = = 0 ) {
2006-06-27 21:16:14 +04:00
* blob = data_blob ( NULL , 0 ) ;
return NT_STATUS_OK ;
}
if ( smb2_oob ( buf , buf - > hdr + ofs , size ) ) {
2008-09-25 04:28:58 +04:00
return NT_STATUS_INVALID_PARAMETER ;
}
* blob = data_blob_talloc ( mem_ctx , buf - > hdr + ofs , size ) ;
NT_STATUS_HAVE_NO_MEMORY ( blob - > data ) ;
return NT_STATUS_OK ;
}
/*
pull a uint32_t length / uint16_t ofs / blob triple from a data blob
the ptr points to the start of the offset / length pair
*/
NTSTATUS smb2_pull_s32o16_blob ( struct smb2_request_buffer * buf , TALLOC_CTX * mem_ctx , uint8_t * ptr , DATA_BLOB * blob )
{
uint32_t ofs , size ;
if ( smb2_oob ( buf , ptr , 8 ) ) {
return NT_STATUS_INVALID_PARAMETER ;
}
size = IVAL ( ptr , 0 ) ;
ofs = SVAL ( ptr , 4 ) ;
if ( ofs = = 0 ) {
* blob = data_blob ( NULL , 0 ) ;
return NT_STATUS_OK ;
}
if ( smb2_oob ( buf , buf - > hdr + ofs , size ) ) {
return NT_STATUS_INVALID_PARAMETER ;
2006-06-27 21:16:14 +04:00
}
* blob = data_blob_talloc ( mem_ctx , buf - > hdr + ofs , size ) ;
NT_STATUS_HAVE_NO_MEMORY ( blob - > data ) ;
return NT_STATUS_OK ;
}
2005-11-16 14:01:15 +03:00
/*
pull a string in a uint16_t ofs / uint16_t length / blob format
UTF - 16 without termination
*/
NTSTATUS smb2_pull_o16s16_string ( struct smb2_request_buffer * buf , TALLOC_CTX * mem_ctx ,
uint8_t * ptr , const char * * str )
2005-11-11 12:11:51 +03:00
{
DATA_BLOB blob ;
NTSTATUS status ;
void * vstr ;
2011-03-29 22:16:26 +04:00
size_t converted_size = 0 ;
2009-03-01 21:55:46 +03:00
bool ret ;
2005-11-16 14:01:15 +03:00
status = smb2_pull_o16s16_blob ( buf , mem_ctx , ptr , & blob ) ;
2005-11-11 12:11:51 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2005-11-16 14:01:15 +03:00
2008-02-15 23:25:38 +03:00
if ( blob . data = = NULL ) {
* str = NULL ;
return NT_STATUS_OK ;
}
2006-05-20 15:50:10 +04:00
if ( blob . length = = 0 ) {
char * s ;
s = talloc_strdup ( mem_ctx , " " ) ;
NT_STATUS_HAVE_NO_MEMORY ( s ) ;
* str = s ;
return NT_STATUS_OK ;
}
2009-03-01 21:55:46 +03:00
ret = convert_string_talloc ( mem_ctx , CH_UTF16 , CH_UNIX ,
2011-03-29 22:16:26 +04:00
blob . data , blob . length , & vstr , & converted_size ) ;
2005-11-11 12:11:51 +03:00
data_blob_free ( & blob ) ;
2007-09-08 20:46:30 +04:00
( * str ) = ( char * ) vstr ;
2009-03-01 21:55:46 +03:00
if ( ! ret ) {
2005-11-11 12:11:51 +03:00
return NT_STATUS_ILLEGAL_CHARACTER ;
}
return NT_STATUS_OK ;
}
/*
2005-11-16 14:01:15 +03:00
push a string in a uint16_t ofs / uint16_t length / blob format
UTF - 16 without termination
2005-11-11 12:11:51 +03:00
*/
2005-11-16 14:01:15 +03:00
NTSTATUS smb2_push_o16s16_string ( struct smb2_request_buffer * buf ,
2005-11-17 06:32:38 +03:00
uint16_t ofs , const char * str )
2005-11-11 12:11:51 +03:00
{
2005-11-16 14:01:15 +03:00
DATA_BLOB blob ;
NTSTATUS status ;
2009-03-01 21:55:46 +03:00
bool ret ;
2011-11-21 20:43:11 +04:00
void * ptr = NULL ;
2005-11-16 14:01:15 +03:00
2008-02-15 23:25:38 +03:00
if ( str = = NULL ) {
2005-11-17 06:32:38 +03:00
return smb2_push_o16s16_blob ( buf , ofs , data_blob ( NULL , 0 ) ) ;
2005-11-16 18:47:44 +03:00
}
2008-02-18 06:53:48 +03:00
if ( * str = = 0 ) {
2009-02-05 20:18:33 +03:00
blob . data = discard_const_p ( uint8_t , str ) ;
2008-02-18 06:53:48 +03:00
blob . length = 0 ;
return smb2_push_o16s16_blob ( buf , ofs , blob ) ;
}
2009-03-01 21:55:46 +03:00
ret = convert_string_talloc ( buf - > buffer , CH_UNIX , CH_UTF16 ,
2011-11-21 20:43:11 +04:00
str , strlen ( str ) , & ptr , & blob . length ) ;
2009-03-01 21:55:46 +03:00
if ( ! ret ) {
2005-11-11 12:11:51 +03:00
return NT_STATUS_ILLEGAL_CHARACTER ;
}
2011-11-21 20:43:11 +04:00
blob . data = ( uint8_t * ) ptr ;
2005-11-16 14:01:15 +03:00
2005-11-17 06:32:38 +03:00
status = smb2_push_o16s16_blob ( buf , ofs , blob ) ;
2005-11-16 14:01:15 +03:00
data_blob_free ( & blob ) ;
2005-11-17 06:32:38 +03:00
return status ;
2005-11-11 12:11:51 +03:00
}
2005-11-14 08:09:26 +03:00
/*
2005-11-16 14:01:15 +03:00
push a file handle into a buffer
2005-11-14 08:09:26 +03:00
*/
2005-11-16 14:01:15 +03:00
void smb2_push_handle ( uint8_t * data , struct smb2_handle * h )
2005-11-14 08:09:26 +03:00
{
2005-11-14 10:06:16 +03:00
SBVAL ( data , 0 , h - > data [ 0 ] ) ;
SBVAL ( data , 8 , h - > data [ 1 ] ) ;
2005-11-14 08:09:26 +03:00
}
2005-11-16 14:01:15 +03:00
/*
pull a file handle from a buffer
*/
void smb2_pull_handle ( uint8_t * ptr , struct smb2_handle * h )
{
h - > data [ 0 ] = BVAL ( ptr , 0 ) ;
h - > data [ 1 ] = BVAL ( ptr , 8 ) ;
}