2003-08-13 01:53:07 +00:00
/*
Unix SMB / CIFS implementation .
Copyright ( C ) Andrew Tridgell 2003
Copyright ( C ) James Myers 2003 < myersjj @ samba . org >
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
the Free Software Foundation ; either version 2 of the License , or
( 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
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
/*
2004-08-04 13:23:35 +00:00
this file implements functions for manipulating the ' struct smbcli_request ' structure in libsmb
2003-08-13 01:53:07 +00:00
*/
# include "includes.h"
/* we over allocate the data buffer to prevent too many realloc calls */
# define REQ_OVER_ALLOCATION 256
/* assume that a character will not consume more than 3 bytes per char */
# define MAX_BYTES_PER_CHAR 3
/* destroy a request structure and return final status */
2004-08-04 13:23:35 +00:00
NTSTATUS smbcli_request_destroy ( struct smbcli_request * req )
2003-08-13 01:53:07 +00:00
{
NTSTATUS status ;
/* this is the error code we give the application for when a
_send ( ) call fails completely */
if ( ! req ) return NT_STATUS_UNSUCCESSFUL ;
2004-04-23 04:21:22 +00:00
if ( req - > transport ) {
/* remove it from the list of pending requests (a null op if
its not in the list ) */
2004-07-23 06:40:49 +00:00
DLIST_REMOVE ( req - > transport - > pending_recv , req ) ;
2004-04-23 04:21:22 +00:00
}
2003-08-13 01:53:07 +00:00
/* ahh, its so nice to destroy a complex structure in such a
simple way ! */
status = req - > status ;
2004-08-21 02:07:12 +00:00
talloc_free ( req ) ;
2003-08-13 01:53:07 +00:00
return status ;
}
/*
low - level function to setup a request buffer for a non - SMB packet
at the transport level
*/
2004-08-04 13:23:35 +00:00
struct smbcli_request * smbcli_request_setup_nonsmb ( struct smbcli_transport * transport , uint_t size )
2003-08-13 01:53:07 +00:00
{
2004-08-04 13:23:35 +00:00
struct smbcli_request * req ;
2003-08-13 01:53:07 +00:00
2004-08-21 02:07:12 +00:00
req = talloc_named ( NULL , sizeof ( struct smbcli_request ) , " smcli_request " ) ;
2003-08-13 01:53:07 +00:00
if ( ! req ) {
return NULL ;
}
ZERO_STRUCTP ( req ) ;
/* setup the request context */
2004-08-04 13:23:35 +00:00
req - > state = SMBCLI_REQUEST_INIT ;
2003-08-13 01:53:07 +00:00
req - > transport = transport ;
req - > session = NULL ;
req - > tree = NULL ;
req - > out . size = size ;
/* over allocate by a small amount */
req - > out . allocated = req - > out . size + REQ_OVER_ALLOCATION ;
2004-08-21 02:07:12 +00:00
req - > out . buffer = talloc ( req , req - > out . allocated ) ;
2003-08-13 01:53:07 +00:00
if ( ! req - > out . buffer ) {
return NULL ;
}
SIVAL ( req - > out . buffer , 0 , 0 ) ;
return req ;
}
/*
setup a SMB packet at transport level
*/
2004-08-04 13:23:35 +00:00
struct smbcli_request * smbcli_request_setup_transport ( struct smbcli_transport * transport ,
2004-06-01 10:12:52 +00:00
uint8_t command , uint_t wct , uint_t buflen )
2003-08-13 01:53:07 +00:00
{
2004-08-04 13:23:35 +00:00
struct smbcli_request * req ;
2003-08-13 01:53:07 +00:00
2004-08-04 13:23:35 +00:00
req = smbcli_request_setup_nonsmb ( transport , NBT_HDR_SIZE + MIN_SMB_SIZE + wct * 2 + buflen ) ;
2003-08-13 01:53:07 +00:00
if ( ! req ) return NULL ;
req - > out . hdr = req - > out . buffer + NBT_HDR_SIZE ;
req - > out . vwv = req - > out . hdr + HDR_VWV ;
req - > out . wct = wct ;
req - > out . data = req - > out . vwv + VWV ( wct ) + 2 ;
req - > out . data_size = buflen ;
req - > out . ptr = req - > out . data ;
SCVAL ( req - > out . hdr , HDR_WCT , wct ) ;
SSVAL ( req - > out . vwv , VWV ( wct ) , buflen ) ;
memcpy ( req - > out . hdr , " \377 SMB " , 4 ) ;
SCVAL ( req - > out . hdr , HDR_COM , command ) ;
SCVAL ( req - > out . hdr , HDR_FLG , FLAG_CASELESS_PATHNAMES ) ;
SSVAL ( req - > out . hdr , HDR_FLG2 , 0 ) ;
/* assign a mid */
2004-08-04 13:23:35 +00:00
req - > mid = smbcli_transport_next_mid ( transport ) ;
2003-08-13 01:53:07 +00:00
/* copy the pid, uid and mid to the request */
SSVAL ( req - > out . hdr , HDR_PID , 0 ) ;
SSVAL ( req - > out . hdr , HDR_UID , 0 ) ;
SSVAL ( req - > out . hdr , HDR_MID , req - > mid ) ;
SSVAL ( req - > out . hdr , HDR_TID , 0 ) ;
SSVAL ( req - > out . hdr , HDR_PIDHIGH , 0 ) ;
SIVAL ( req - > out . hdr , HDR_RCLS , 0 ) ;
memset ( req - > out . hdr + HDR_SS_FIELD , 0 , 10 ) ;
return req ;
}
/*
setup a reply in req - > out with the given word count and initial data
buffer size . the caller will then fill in the command words and
2004-08-04 13:23:35 +00:00
data before calling smbcli_request_send ( ) to send the reply on its
2003-08-13 01:53:07 +00:00
way . This interface is used before a session is setup .
*/
2004-08-04 13:23:35 +00:00
struct smbcli_request * smbcli_request_setup_session ( struct smbcli_session * session ,
2004-06-01 10:12:52 +00:00
uint8_t command , uint_t wct , uint_t buflen )
2003-08-13 01:53:07 +00:00
{
2004-08-04 13:23:35 +00:00
struct smbcli_request * req ;
2004-05-25 17:24:24 +00:00
uint16_t flags2 ;
2004-05-25 16:24:13 +00:00
uint32_t capabilities ;
2003-08-13 01:53:07 +00:00
2004-08-04 13:23:35 +00:00
req = smbcli_request_setup_transport ( session - > transport , command , wct , buflen ) ;
2003-08-13 01:53:07 +00:00
if ( ! req ) return NULL ;
req - > session = session ;
flags2 = FLAGS2_LONG_PATH_COMPONENTS ;
capabilities = session - > transport - > negotiate . capabilities ;
if ( capabilities & CAP_UNICODE ) {
flags2 | = FLAGS2_UNICODE_STRINGS ;
}
if ( capabilities & CAP_STATUS32 ) {
flags2 | = FLAGS2_32_BIT_ERROR_CODES ;
}
if ( capabilities & CAP_EXTENDED_SECURITY ) {
flags2 | = FLAGS2_EXTENDED_SECURITY ;
}
if ( session - > transport - > negotiate . sign_info . doing_signing ) {
flags2 | = FLAGS2_SMB_SECURITY_SIGNATURES ;
}
SSVAL ( req - > out . hdr , HDR_FLG2 , flags2 ) ;
2003-08-13 02:02:17 +00:00
SSVAL ( req - > out . hdr , HDR_PID , session - > pid & 0xFFFF ) ;
SSVAL ( req - > out . hdr , HDR_PIDHIGH , session - > pid > > 16 ) ;
2003-08-13 01:53:07 +00:00
SSVAL ( req - > out . hdr , HDR_UID , session - > vuid ) ;
return req ;
}
/*
setup a request for tree based commands
*/
2004-08-04 13:23:35 +00:00
struct smbcli_request * smbcli_request_setup ( struct smbcli_tree * tree ,
2004-05-25 17:50:17 +00:00
uint8_t command ,
2004-06-01 10:12:52 +00:00
uint_t wct , uint_t buflen )
2003-08-13 01:53:07 +00:00
{
2004-08-04 13:23:35 +00:00
struct smbcli_request * req ;
2003-08-13 01:53:07 +00:00
2004-08-04 13:23:35 +00:00
req = smbcli_request_setup_session ( tree - > session , command , wct , buflen ) ;
2003-08-13 01:53:07 +00:00
if ( req ) {
req - > tree = tree ;
SSVAL ( req - > out . hdr , HDR_TID , tree - > tid ) ;
}
return req ;
}
/*
grow the allocation of the data buffer portion of a reply
packet . Note that as this can reallocate the packet buffer this
invalidates any local pointers into the packet .
To cope with this req - > out . ptr is supplied . This will be updated to
point at the same offset into the packet as before this call
*/
2004-08-04 13:23:35 +00:00
static void smbcli_req_grow_allocation ( struct smbcli_request * req , uint_t new_size )
2003-08-13 01:53:07 +00:00
{
int delta ;
char * buf2 ;
delta = new_size - req - > out . data_size ;
if ( delta + req - > out . size < = req - > out . allocated ) {
/* it fits in the preallocation */
return ;
}
/* we need to realloc */
req - > out . allocated = req - > out . size + delta + REQ_OVER_ALLOCATION ;
2004-08-21 01:54:46 +00:00
buf2 = talloc_realloc ( req - > out . buffer , req - > out . allocated ) ;
2003-08-13 01:53:07 +00:00
if ( buf2 = = NULL ) {
smb_panic ( " out of memory in req_grow_allocation " ) ;
}
if ( buf2 = = req - > out . buffer ) {
/* the malloc library gave us the same pointer */
return ;
}
/* update the pointers into the packet */
req - > out . data = buf2 + PTR_DIFF ( req - > out . data , req - > out . buffer ) ;
req - > out . ptr = buf2 + PTR_DIFF ( req - > out . ptr , req - > out . buffer ) ;
req - > out . vwv = buf2 + PTR_DIFF ( req - > out . vwv , req - > out . buffer ) ;
req - > out . hdr = buf2 + PTR_DIFF ( req - > out . hdr , req - > out . buffer ) ;
req - > out . buffer = buf2 ;
}
/*
grow the data buffer portion of a reply packet . Note that as this
can reallocate the packet buffer this invalidates any local pointers
into the packet .
To cope with this req - > out . ptr is supplied . This will be updated to
point at the same offset into the packet as before this call
*/
2004-08-14 18:24:33 +00:00
void smbcli_req_grow_data ( struct smbcli_request * req , uint_t new_size )
2003-08-13 01:53:07 +00:00
{
int delta ;
2004-08-04 13:23:35 +00:00
smbcli_req_grow_allocation ( req , new_size ) ;
2003-08-13 01:53:07 +00:00
delta = new_size - req - > out . data_size ;
req - > out . size + = delta ;
req - > out . data_size + = delta ;
/* set the BCC to the new data size */
SSVAL ( req - > out . vwv , VWV ( req - > out . wct ) , new_size ) ;
}
2004-07-23 06:40:49 +00:00
2003-08-13 01:53:07 +00:00
/*
send a message
*/
2004-08-04 13:23:35 +00:00
BOOL smbcli_request_send ( struct smbcli_request * req )
2003-08-13 01:53:07 +00:00
{
if ( IVAL ( req - > out . buffer , 0 ) = = 0 ) {
_smb_setlen ( req - > out . buffer , req - > out . size - NBT_HDR_SIZE ) ;
}
2004-08-04 13:23:35 +00:00
smbcli_request_calculate_sign_mac ( req ) ;
2003-08-13 01:53:07 +00:00
2004-08-04 13:23:35 +00:00
smbcli_transport_send ( req ) ;
2003-11-20 00:36:10 +00:00
2003-08-13 01:53:07 +00:00
return True ;
}
/*
receive a response to a packet
*/
2004-08-04 13:23:35 +00:00
BOOL smbcli_request_receive ( struct smbcli_request * req )
2003-08-13 01:53:07 +00:00
{
/* req can be NULL when a send has failed. This eliminates lots of NULL
checks in each module */
if ( ! req ) return False ;
/* keep receiving packets until this one is replied to */
2004-08-04 13:23:35 +00:00
while ( req - > state < = SMBCLI_REQUEST_RECV ) {
2004-07-23 06:40:49 +00:00
event_loop_once ( req - > transport - > event . ctx ) ;
2003-08-13 01:53:07 +00:00
}
2004-08-14 18:24:33 +00:00
return req - > state = = SMBCLI_REQUEST_DONE ;
2003-08-13 01:53:07 +00:00
}
2004-08-02 05:51:42 +00:00
/*
receive another reply to a request - this is used for requests that
have multi - part replies ( such as SMBtrans2 )
*/
2004-08-04 13:23:35 +00:00
BOOL smbcli_request_receive_more ( struct smbcli_request * req )
2004-08-02 05:51:42 +00:00
{
2004-08-04 13:23:35 +00:00
req - > state = SMBCLI_REQUEST_RECV ;
2004-08-02 05:51:42 +00:00
DLIST_ADD ( req - > transport - > pending_recv , req ) ;
2004-08-04 13:23:35 +00:00
return smbcli_request_receive ( req ) ;
2004-08-02 05:51:42 +00:00
}
2003-08-13 01:53:07 +00:00
/*
handle oplock break requests from the server - return True if the request was
an oplock break
*/
2004-08-04 13:23:35 +00:00
BOOL handle_oplock_break ( struct smbcli_transport * transport , uint_t len , const char * hdr , const char * vwv )
2003-08-13 01:53:07 +00:00
{
/* we must be very fussy about what we consider an oplock break to avoid
matching readbraw replies */
2004-08-03 06:52:06 +00:00
if ( len ! = MIN_SMB_SIZE + VWV ( 8 ) + NBT_HDR_SIZE | |
2003-08-13 01:53:07 +00:00
( CVAL ( hdr , HDR_FLG ) & FLAG_REPLY ) | |
CVAL ( hdr , HDR_COM ) ! = SMBlockingX | |
SVAL ( hdr , HDR_MID ) ! = 0xFFFF | |
SVAL ( vwv , VWV ( 6 ) ) ! = 0 | |
SVAL ( vwv , VWV ( 7 ) ) ! = 0 ) {
return False ;
}
if ( transport - > oplock . handler ) {
2004-05-25 17:24:24 +00:00
uint16_t tid = SVAL ( hdr , HDR_TID ) ;
uint16_t fnum = SVAL ( vwv , VWV ( 2 ) ) ;
2004-05-25 17:50:17 +00:00
uint8_t level = CVAL ( vwv , VWV ( 3 ) + 1 ) ;
2003-08-13 01:53:07 +00:00
transport - > oplock . handler ( transport , tid , fnum , level , transport - > oplock . private ) ;
}
return True ;
}
/*
wait for a reply to be received for a packet that just returns an error
code and nothing more
*/
2004-08-04 13:23:35 +00:00
NTSTATUS smbcli_request_simple_recv ( struct smbcli_request * req )
2003-08-13 01:53:07 +00:00
{
2004-08-04 13:23:35 +00:00
smbcli_request_receive ( req ) ;
return smbcli_request_destroy ( req ) ;
2003-08-13 01:53:07 +00:00
}
/* Return true if the last packet was in error */
2004-08-04 13:23:35 +00:00
BOOL smbcli_request_is_error ( struct smbcli_request * req )
2003-08-13 01:53:07 +00:00
{
return NT_STATUS_IS_ERR ( req - > status ) ;
}
/*
append a string into the data portion of the request packet
return the number of bytes added to the packet
*/
2004-08-04 13:23:35 +00:00
size_t smbcli_req_append_string ( struct smbcli_request * req , const char * str , uint_t flags )
2003-08-13 01:53:07 +00:00
{
size_t len ;
/* determine string type to use */
if ( ! ( flags & ( STR_ASCII | STR_UNICODE ) ) ) {
flags | = ( req - > transport - > negotiate . capabilities & CAP_UNICODE ) ? STR_UNICODE : STR_ASCII ;
}
len = ( strlen ( str ) + 2 ) * MAX_BYTES_PER_CHAR ;
2004-08-04 13:23:35 +00:00
smbcli_req_grow_allocation ( req , len + req - > out . data_size ) ;
2003-08-13 01:53:07 +00:00
len = push_string ( NULL , req - > out . data + req - > out . data_size , str , len , flags ) ;
2004-08-04 13:23:35 +00:00
smbcli_req_grow_data ( req , len + req - > out . data_size ) ;
2003-08-13 01:53:07 +00:00
return len ;
}
/*
2004-08-04 13:23:35 +00:00
this is like smbcli_req_append_string but it also return the
2003-08-13 01:53:07 +00:00
non - terminated string byte length , which can be less than the number
of bytes consumed in the packet for 2 reasons :
1 ) the string in the packet may be null terminated
2 ) the string in the packet may need a 1 byte UCS2 alignment
this is used in places where the non - terminated string byte length is
placed in the packet as a separate field
*/
2004-08-04 13:23:35 +00:00
size_t smbcli_req_append_string_len ( struct smbcli_request * req , const char * str , uint_t flags , int * len )
2003-08-13 01:53:07 +00:00
{
int diff = 0 ;
size_t ret ;
/* determine string type to use */
if ( ! ( flags & ( STR_ASCII | STR_UNICODE ) ) ) {
flags | = ( req - > transport - > negotiate . capabilities & CAP_UNICODE ) ? STR_UNICODE : STR_ASCII ;
}
/* see if an alignment byte will be used */
if ( ( flags & STR_UNICODE ) & & ! ( flags & STR_NOALIGN ) ) {
diff = ucs2_align ( NULL , req - > out . data + req - > out . data_size , flags ) ;
}
/* do the hard work */
2004-08-04 13:23:35 +00:00
ret = smbcli_req_append_string ( req , str , flags ) ;
2003-08-13 01:53:07 +00:00
/* see if we need to subtract the termination */
if ( flags & STR_TERMINATE ) {
diff + = ( flags & STR_UNICODE ) ? 2 : 1 ;
}
if ( ret > = diff ) {
( * len ) = ret - diff ;
} else {
( * len ) = ret ;
}
return ret ;
}
/*
push a string into the data portion of the request packet , growing it if necessary
this gets quite tricky - please be very careful to cover all cases when modifying this
if dest is NULL , then put the string at the end of the data portion of the packet
if dest_len is - 1 then no limit applies
*/
2004-08-04 13:23:35 +00:00
size_t smbcli_req_append_ascii4 ( struct smbcli_request * req , const char * str , uint_t flags )
2003-08-13 01:53:07 +00:00
{
size_t size ;
2004-08-04 13:23:35 +00:00
smbcli_req_append_bytes ( req , ( const uint8_t * ) " \4 " , 1 ) ;
size = smbcli_req_append_string ( req , str , flags ) ;
2003-08-13 01:53:07 +00:00
return size + 1 ;
}
/*
push a blob into the data portion of the request packet , growing it if necessary
this gets quite tricky - please be very careful to cover all cases when modifying this
if dest is NULL , then put the blob at the end of the data portion of the packet
*/
2004-08-04 13:23:35 +00:00
size_t smbcli_req_append_blob ( struct smbcli_request * req , const DATA_BLOB * blob )
2003-08-13 01:53:07 +00:00
{
2004-08-04 13:23:35 +00:00
smbcli_req_grow_allocation ( req , req - > out . data_size + blob - > length ) ;
2003-08-13 01:53:07 +00:00
memcpy ( req - > out . data + req - > out . data_size , blob - > data , blob - > length ) ;
2004-08-04 13:23:35 +00:00
smbcli_req_grow_data ( req , req - > out . data_size + blob - > length ) ;
2003-08-13 01:53:07 +00:00
return blob - > length ;
}
/*
append raw bytes into the data portion of the request packet
return the number of bytes added
*/
2004-08-04 13:23:35 +00:00
size_t smbcli_req_append_bytes ( struct smbcli_request * req , const uint8_t * bytes , size_t byte_len )
2003-08-13 01:53:07 +00:00
{
2004-08-04 13:23:35 +00:00
smbcli_req_grow_allocation ( req , byte_len + req - > out . data_size ) ;
2003-08-13 01:53:07 +00:00
memcpy ( req - > out . data + req - > out . data_size , bytes , byte_len ) ;
2004-08-04 13:23:35 +00:00
smbcli_req_grow_data ( req , byte_len + req - > out . data_size ) ;
2003-08-13 01:53:07 +00:00
return byte_len ;
}
/*
append variable block ( type 5 buffer ) into the data portion of the request packet
return the number of bytes added
*/
2004-08-04 13:23:35 +00:00
size_t smbcli_req_append_var_block ( struct smbcli_request * req , const uint8_t * bytes , uint16_t byte_len )
2003-08-13 01:53:07 +00:00
{
2004-08-04 13:23:35 +00:00
smbcli_req_grow_allocation ( req , byte_len + 3 + req - > out . data_size ) ;
2003-08-13 01:53:07 +00:00
SCVAL ( req - > out . data + req - > out . data_size , 0 , 5 ) ;
SSVAL ( req - > out . data + req - > out . data_size , 1 , byte_len ) ; /* add field length */
if ( byte_len > 0 ) {
memcpy ( req - > out . data + req - > out . data_size + 3 , bytes , byte_len ) ;
}
2004-08-04 13:23:35 +00:00
smbcli_req_grow_data ( req , byte_len + 3 + req - > out . data_size ) ;
2003-08-13 01:53:07 +00:00
return byte_len + 3 ;
}
/*
pull a UCS2 string from a request packet , returning a talloced unix string
the string length is limited by the 3 things :
- the data size in the request ( end of packet )
- the passed ' byte_len ' if it is not - 1
- the end of string ( null termination )
Note that ' byte_len ' is the number of bytes in the packet
on failure zero is returned and * dest is set to NULL , otherwise the number
of bytes consumed in the packet is returned
*/
2004-08-04 13:23:35 +00:00
static size_t smbcli_req_pull_ucs2 ( struct smbcli_request * req , TALLOC_CTX * mem_ctx ,
2004-06-01 10:12:52 +00:00
char * * dest , const char * src , int byte_len , uint_t flags )
2003-08-13 01:53:07 +00:00
{
int src_len , src_len2 , alignment = 0 ;
ssize_t ret ;
if ( ! ( flags & STR_NOALIGN ) & & ucs2_align ( req - > in . buffer , src , flags ) ) {
src + + ;
alignment = 1 ;
if ( byte_len ! = - 1 ) {
byte_len - - ;
}
}
src_len = req - > in . data_size - PTR_DIFF ( src , req - > in . data ) ;
if ( src_len < 0 ) {
* dest = NULL ;
return 0 ;
}
if ( byte_len ! = - 1 & & src_len > byte_len ) {
src_len = byte_len ;
}
src_len2 = strnlen_w ( ( const smb_ucs2_t * ) src , src_len / 2 ) * 2 ;
if ( src_len2 < src_len - 2 ) {
/* include the termination if we didn't reach the end of the packet */
src_len2 + = 2 ;
}
/* ucs2 strings must be at least 2 bytes long */
if ( src_len2 < 2 ) {
* dest = NULL ;
return 0 ;
}
ret = convert_string_talloc ( mem_ctx , CH_UCS2 , CH_UNIX , src , src_len2 , ( const void * * ) dest ) ;
if ( ret = = - 1 ) {
* dest = NULL ;
return 0 ;
}
return src_len2 + alignment ;
}
/*
pull a ascii string from a request packet , returning a talloced string
the string length is limited by the 3 things :
- the data size in the request ( end of packet )
- the passed ' byte_len ' if it is not - 1
- the end of string ( null termination )
Note that ' byte_len ' is the number of bytes in the packet
on failure zero is returned and * dest is set to NULL , otherwise the number
of bytes consumed in the packet is returned
*/
2004-08-04 13:23:35 +00:00
size_t smbcli_req_pull_ascii ( struct smbcli_request * req , TALLOC_CTX * mem_ctx ,
2004-06-01 10:12:52 +00:00
char * * dest , const char * src , int byte_len , uint_t flags )
2003-08-13 01:53:07 +00:00
{
int src_len , src_len2 ;
ssize_t ret ;
src_len = req - > in . data_size - PTR_DIFF ( src , req - > in . data ) ;
if ( src_len < 0 ) {
* dest = NULL ;
return 0 ;
}
if ( byte_len ! = - 1 & & src_len > byte_len ) {
src_len = byte_len ;
}
src_len2 = strnlen ( src , src_len ) ;
if ( src_len2 < src_len - 1 ) {
/* include the termination if we didn't reach the end of the packet */
src_len2 + + ;
}
ret = convert_string_talloc ( mem_ctx , CH_DOS , CH_UNIX , src , src_len2 , ( const void * * ) dest ) ;
if ( ret = = - 1 ) {
* dest = NULL ;
return 0 ;
}
return ret ;
}
/*
pull a string from a request packet , returning a talloced string
the string length is limited by the 3 things :
- the data size in the request ( end of packet )
- the passed ' byte_len ' if it is not - 1
- the end of string ( null termination )
Note that ' byte_len ' is the number of bytes in the packet
on failure zero is returned and * dest is set to NULL , otherwise the number
of bytes consumed in the packet is returned
*/
2004-08-04 13:23:35 +00:00
size_t smbcli_req_pull_string ( struct smbcli_request * req , TALLOC_CTX * mem_ctx ,
2004-06-01 10:12:52 +00:00
char * * dest , const char * src , int byte_len , uint_t flags )
2003-08-13 01:53:07 +00:00
{
if ( ! ( flags & STR_ASCII ) & &
2003-08-15 16:19:48 +00:00
( ( ( flags & STR_UNICODE ) | | ( req - > flags2 & FLAGS2_UNICODE_STRINGS ) ) ) ) {
2004-08-04 13:23:35 +00:00
return smbcli_req_pull_ucs2 ( req , mem_ctx , dest , src , byte_len , flags ) ;
2003-08-13 01:53:07 +00:00
}
2004-08-04 13:23:35 +00:00
return smbcli_req_pull_ascii ( req , mem_ctx , dest , src , byte_len , flags ) ;
2003-08-13 01:53:07 +00:00
}
/*
pull a DATA_BLOB from a reply packet , returning a talloced blob
make sure we don ' t go past end of packet
if byte_len is - 1 then limit the blob only by packet size
*/
2004-08-04 13:23:35 +00:00
DATA_BLOB smbcli_req_pull_blob ( struct smbcli_request * req , TALLOC_CTX * mem_ctx , const char * src , int byte_len )
2003-08-13 01:53:07 +00:00
{
int src_len ;
src_len = req - > in . data_size - PTR_DIFF ( src , req - > in . data ) ;
if ( src_len < 0 ) {
return data_blob ( NULL , 0 ) ;
}
if ( byte_len ! = - 1 & & src_len > byte_len ) {
src_len = byte_len ;
}
return data_blob_talloc ( mem_ctx , src , src_len ) ;
}
/* check that a lump of data in a request is within the bounds of the data section of
the packet */
2004-08-04 13:23:35 +00:00
static BOOL smbcli_req_data_oob ( struct smbcli_request * req , const char * ptr , uint32_t count )
2003-08-13 01:53:07 +00:00
{
/* be careful with wraparound! */
if ( ptr < req - > in . data | |
ptr > = req - > in . data + req - > in . data_size | |
count > req - > in . data_size | |
ptr + count > req - > in . data + req - > in . data_size ) {
return True ;
}
return False ;
}
/*
pull a lump of data from a request packet
return False if any part is outside the data portion of the packet
*/
2004-08-04 13:23:35 +00:00
BOOL smbcli_raw_pull_data ( struct smbcli_request * req , const char * src , int len , char * dest )
2003-08-13 01:53:07 +00:00
{
if ( len = = 0 ) return True ;
2004-08-04 13:23:35 +00:00
if ( smbcli_req_data_oob ( req , src , len ) ) {
2003-08-13 01:53:07 +00:00
return False ;
}
memcpy ( dest , src , len ) ;
return True ;
}
/*
put a NTTIME into a packet
*/
2004-08-04 13:23:35 +00:00
void smbcli_push_nttime ( void * base , uint16_t offset , NTTIME t )
2003-08-13 01:53:07 +00:00
{
2004-05-25 13:57:39 +00:00
SBVAL ( base , offset , t ) ;
2003-08-13 01:53:07 +00:00
}
/*
pull a NTTIME from a packet
*/
2004-08-04 13:23:35 +00:00
NTTIME smbcli_pull_nttime ( void * base , uint16_t offset )
2003-08-13 01:53:07 +00:00
{
2004-05-25 13:57:39 +00:00
NTTIME ret = BVAL ( base , offset ) ;
2003-08-13 01:53:07 +00:00
return ret ;
}
/*
pull a UCS2 string from a blob , returning a talloced unix string
the string length is limited by the 3 things :
- the data size in the blob
- the passed ' byte_len ' if it is not - 1
- the end of string ( null termination )
Note that ' byte_len ' is the number of bytes in the packet
on failure zero is returned and * dest is set to NULL , otherwise the number
of bytes consumed in the blob is returned
*/
2004-08-04 13:23:35 +00:00
static size_t smbcli_blob_pull_ucs2 ( TALLOC_CTX * mem_ctx ,
2003-08-13 01:53:07 +00:00
DATA_BLOB * blob , const char * * dest ,
2004-06-01 10:12:52 +00:00
const char * src , int byte_len , uint_t flags )
2003-08-13 01:53:07 +00:00
{
int src_len , src_len2 , alignment = 0 ;
ssize_t ret ;
if ( src < ( const char * ) blob - > data | |
src > = ( const char * ) ( blob - > data + blob - > length ) ) {
* dest = NULL ;
return 0 ;
}
src_len = blob - > length - PTR_DIFF ( src , blob - > data ) ;
if ( byte_len ! = - 1 & & src_len > byte_len ) {
src_len = byte_len ;
}
if ( ! ( flags & STR_NOALIGN ) & & ucs2_align ( blob - > data , src , flags ) ) {
src + + ;
alignment = 1 ;
src_len - - ;
}
if ( src_len < 2 ) {
* dest = NULL ;
return 0 ;
}
src_len2 = strnlen_w ( ( const smb_ucs2_t * ) src , src_len / 2 ) * 2 ;
if ( src_len2 < src_len - 2 ) {
/* include the termination if we didn't reach the end of the packet */
src_len2 + = 2 ;
}
ret = convert_string_talloc ( mem_ctx , CH_UCS2 , CH_UNIX , src , src_len2 , ( const void * * ) dest ) ;
if ( ret = = - 1 ) {
* dest = NULL ;
return 0 ;
}
return src_len2 + alignment ;
}
/*
pull a ascii string from a blob , returning a talloced string
the string length is limited by the 3 things :
- the data size in the blob
- the passed ' byte_len ' if it is not - 1
- the end of string ( null termination )
Note that ' byte_len ' is the number of bytes in the blob
on failure zero is returned and * dest is set to NULL , otherwise the number
of bytes consumed in the blob is returned
*/
2004-08-04 13:23:35 +00:00
static size_t smbcli_blob_pull_ascii ( TALLOC_CTX * mem_ctx ,
2003-08-13 01:53:07 +00:00
DATA_BLOB * blob , const char * * dest ,
2004-06-01 10:12:52 +00:00
const char * src , int byte_len , uint_t flags )
2003-08-13 01:53:07 +00:00
{
int src_len , src_len2 ;
ssize_t ret ;
src_len = blob - > length - PTR_DIFF ( src , blob - > data ) ;
if ( src_len < 0 ) {
* dest = NULL ;
return 0 ;
}
if ( byte_len ! = - 1 & & src_len > byte_len ) {
src_len = byte_len ;
}
src_len2 = strnlen ( src , src_len ) ;
if ( src_len2 < src_len - 1 ) {
/* include the termination if we didn't reach the end of the packet */
src_len2 + + ;
}
ret = convert_string_talloc ( mem_ctx , CH_DOS , CH_UNIX , src , src_len2 , ( const void * * ) dest ) ;
if ( ret = = - 1 ) {
* dest = NULL ;
return 0 ;
}
return ret ;
}
/*
pull a string from a blob , returning a talloced WIRE_STRING
the string length is limited by the 3 things :
- the data size in the blob
- length field on the wire
- the end of string ( null termination )
if STR_LEN8BIT is set in the flags then assume the length field is
8 bits , instead of 32
on failure zero is returned and dest - > s is set to NULL , otherwise the number
of bytes consumed in the blob is returned
*/
2004-08-04 13:23:35 +00:00
size_t smbcli_blob_pull_string ( struct smbcli_session * session ,
2003-08-13 01:53:07 +00:00
TALLOC_CTX * mem_ctx ,
DATA_BLOB * blob ,
WIRE_STRING * dest ,
2004-05-25 17:24:24 +00:00
uint16_t len_offset , uint16_t str_offset ,
2004-06-01 10:12:52 +00:00
uint_t flags )
2003-08-13 01:53:07 +00:00
{
2003-08-31 03:16:52 +00:00
int extra ;
2003-08-13 01:53:07 +00:00
dest - > s = NULL ;
2003-08-31 03:16:52 +00:00
2003-08-13 01:53:07 +00:00
if ( flags & STR_LEN8BIT ) {
2004-08-09 20:47:31 +00:00
if ( len_offset > blob - > length - 1 ) {
return 0 ;
}
2003-08-13 01:53:07 +00:00
dest - > private_length = CVAL ( blob - > data , len_offset ) ;
} else {
2004-08-09 20:47:31 +00:00
if ( len_offset > blob - > length - 4 ) {
return 0 ;
}
2003-08-13 01:53:07 +00:00
dest - > private_length = IVAL ( blob - > data , len_offset ) ;
}
2003-08-31 03:16:52 +00:00
extra = 0 ;
2003-08-13 01:53:07 +00:00
dest - > s = NULL ;
if ( ! ( flags & STR_ASCII ) & &
( ( flags & STR_UNICODE ) | |
( session - > transport - > negotiate . capabilities & CAP_UNICODE ) ) ) {
2003-08-31 03:16:52 +00:00
int align = 0 ;
2003-08-13 01:53:07 +00:00
if ( ( str_offset & 1 ) & & ! ( flags & STR_NOALIGN ) ) {
2003-08-31 03:16:52 +00:00
align = 1 ;
}
if ( flags & STR_LEN_NOTERM ) {
extra = 2 ;
2003-08-13 01:53:07 +00:00
}
2004-08-04 13:23:35 +00:00
return align + extra + smbcli_blob_pull_ucs2 ( mem_ctx , blob , & dest - > s ,
2003-08-31 03:16:52 +00:00
blob - > data + str_offset + align ,
dest - > private_length , flags ) ;
}
if ( flags & STR_LEN_NOTERM ) {
extra = 1 ;
2003-08-13 01:53:07 +00:00
}
2004-08-04 13:23:35 +00:00
return extra + smbcli_blob_pull_ascii ( mem_ctx , blob , & dest - > s ,
2003-08-31 03:16:52 +00:00
blob - > data + str_offset , dest - > private_length , flags ) ;
2003-08-13 01:53:07 +00:00
}
2004-04-14 01:09:41 +00:00
/*
pull a string from a blob , returning a talloced char *
Currently only used by the UNIX search info level .
the string length is limited by 2 things :
- the data size in the blob
- the end of string ( null termination )
on failure zero is returned and dest - > s is set to NULL , otherwise the number
of bytes consumed in the blob is returned
*/
2004-08-04 13:23:35 +00:00
size_t smbcli_blob_pull_unix_string ( struct smbcli_session * session ,
2004-04-14 01:09:41 +00:00
TALLOC_CTX * mem_ctx ,
DATA_BLOB * blob ,
const char * * dest ,
2004-05-25 17:24:24 +00:00
uint16_t str_offset ,
2004-06-01 10:12:52 +00:00
uint_t flags )
2004-04-14 01:09:41 +00:00
{
int extra = 0 ;
* dest = NULL ;
if ( ! ( flags & STR_ASCII ) & &
( ( flags & STR_UNICODE ) | |
( session - > transport - > negotiate . capabilities & CAP_UNICODE ) ) ) {
int align = 0 ;
if ( ( str_offset & 1 ) & & ! ( flags & STR_NOALIGN ) ) {
align = 1 ;
}
if ( flags & STR_LEN_NOTERM ) {
extra = 2 ;
}
2004-08-04 13:23:35 +00:00
return align + extra + smbcli_blob_pull_ucs2 ( mem_ctx , blob , dest ,
2004-04-14 01:09:41 +00:00
blob - > data + str_offset + align ,
- 1 , flags ) ;
}
if ( flags & STR_LEN_NOTERM ) {
extra = 1 ;
}
2004-08-04 13:23:35 +00:00
return extra + smbcli_blob_pull_ascii ( mem_ctx , blob , dest ,
2004-04-14 01:09:41 +00:00
blob - > data + str_offset , - 1 , flags ) ;
}
2003-08-13 01:53:07 +00:00
/*
append a string into a blob
*/
2004-08-04 13:23:35 +00:00
size_t smbcli_blob_append_string ( struct smbcli_session * session ,
2003-08-13 01:53:07 +00:00
TALLOC_CTX * mem_ctx , DATA_BLOB * blob ,
2004-06-01 10:12:52 +00:00
const char * str , uint_t flags )
2003-08-13 01:53:07 +00:00
{
size_t max_len ;
int len ;
if ( ! str ) return 0 ;
/* determine string type to use */
if ( ! ( flags & ( STR_ASCII | STR_UNICODE ) ) ) {
flags | = ( session - > transport - > negotiate . capabilities & CAP_UNICODE ) ? STR_UNICODE : STR_ASCII ;
}
max_len = ( strlen ( str ) + 2 ) * MAX_BYTES_PER_CHAR ;
2004-08-21 01:54:46 +00:00
blob - > data = talloc_realloc ( blob - > data , blob - > length + max_len ) ;
2003-08-13 01:53:07 +00:00
if ( ! blob - > data ) {
return 0 ;
}
len = push_string ( NULL , blob - > data + blob - > length , str , max_len , flags ) ;
blob - > length + = len ;
return len ;
}