2003-10-30 11:32:26 +03:00
/*
Unix SMB / CIFS implementation .
routines for marshalling / unmarshalling basic types
Copyright ( C ) Andrew Tridgell 2003
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 .
*/
# include "includes.h"
2003-11-03 09:22:45 +03:00
# define NDR_PULL_NEED_BYTES(ndr, n) do { \
2003-10-30 11:32:26 +03:00
if ( ( n ) > ndr - > data_size | | ndr - > offset + ( n ) > ndr - > data_size ) { \
return NT_STATUS_BUFFER_TOO_SMALL ; \
} \
} while ( 0 )
2003-11-03 09:22:45 +03:00
# define NDR_PULL_ALIGN(ndr, n) do { \
2003-10-30 11:32:26 +03:00
ndr - > offset = ( ndr - > offset + ( n - 1 ) ) & ~ ( n - 1 ) ; \
if ( ndr - > offset > = ndr - > data_size ) { \
return NT_STATUS_BUFFER_TOO_SMALL ; \
} \
} while ( 0 )
/*
2003-11-06 15:34:04 +03:00
parse a uint8
2003-10-30 11:32:26 +03:00
*/
2003-11-06 15:34:04 +03:00
NTSTATUS ndr_pull_uint8 ( struct ndr_pull * ndr , uint8 * v )
2003-10-30 11:32:26 +03:00
{
2003-11-03 09:22:45 +03:00
NDR_PULL_NEED_BYTES ( ndr , 1 ) ;
2003-10-30 11:32:26 +03:00
* v = CVAL ( ndr - > data , ndr - > offset ) ;
ndr - > offset + = 1 ;
return NT_STATUS_OK ;
}
/*
2003-11-06 15:34:04 +03:00
parse a uint16
2003-10-30 11:32:26 +03:00
*/
2003-11-06 15:34:04 +03:00
NTSTATUS ndr_pull_uint16 ( struct ndr_pull * ndr , uint16 * v )
2003-10-30 11:32:26 +03:00
{
2003-11-03 09:22:45 +03:00
NDR_PULL_ALIGN ( ndr , 2 ) ;
NDR_PULL_NEED_BYTES ( ndr , 2 ) ;
2003-10-30 11:32:26 +03:00
if ( ndr - > flags & LIBNDR_FLAG_BIGENDIAN ) {
* v = RSVAL ( ndr - > data , ndr - > offset ) ;
} else {
* v = SVAL ( ndr - > data , ndr - > offset ) ;
}
ndr - > offset + = 2 ;
return NT_STATUS_OK ;
}
/*
2003-11-06 15:34:04 +03:00
parse a uint32
2003-10-30 11:32:26 +03:00
*/
2003-11-06 15:34:04 +03:00
NTSTATUS ndr_pull_uint32 ( struct ndr_pull * ndr , uint32 * v )
2003-10-30 11:32:26 +03:00
{
2003-11-03 09:22:45 +03:00
NDR_PULL_ALIGN ( ndr , 4 ) ;
NDR_PULL_NEED_BYTES ( ndr , 4 ) ;
2003-10-30 11:32:26 +03:00
if ( ndr - > flags & LIBNDR_FLAG_BIGENDIAN ) {
* v = RIVAL ( ndr - > data , ndr - > offset ) ;
} else {
* v = IVAL ( ndr - > data , ndr - > offset ) ;
}
2003-11-03 12:18:38 +03:00
ndr - > offset + = 4 ;
return NT_STATUS_OK ;
}
2003-11-04 12:10:31 +03:00
/*
pull a NTSTATUS
*/
NTSTATUS ndr_pull_status ( struct ndr_pull * ndr , NTSTATUS * status )
{
uint32 v ;
2003-11-06 15:34:04 +03:00
NDR_CHECK ( ndr_pull_uint32 ( ndr , & v ) ) ;
2003-11-04 12:10:31 +03:00
* status = NT_STATUS ( v ) ;
return NT_STATUS_OK ;
}
2003-11-03 12:18:38 +03:00
/*
parse a set of bytes
*/
2003-11-04 12:10:31 +03:00
NTSTATUS ndr_pull_bytes ( struct ndr_pull * ndr , char * data , uint32 n )
2003-11-03 12:18:38 +03:00
{
NDR_PULL_NEED_BYTES ( ndr , n ) ;
2003-11-04 12:10:31 +03:00
memcpy ( data , ndr - > data + ndr - > offset , n ) ;
2003-11-03 12:18:38 +03:00
ndr - > offset + = n ;
2003-10-30 11:32:26 +03:00
return NT_STATUS_OK ;
}
2003-11-04 12:10:31 +03:00
/*
parse a GUID
*/
NTSTATUS ndr_pull_guid ( struct ndr_pull * ndr , GUID * guid )
{
int i ;
NDR_PULL_NEED_BYTES ( ndr , GUID_SIZE ) ;
for ( i = 0 ; i < GUID_SIZE ; i + + ) {
guid - > info [ i ] = CVAL ( ndr - > data , ndr - > offset + i ) ;
}
ndr - > offset + = i ;
return NT_STATUS_OK ;
}
2003-11-03 09:22:45 +03:00
# define NDR_PUSH_NEED_BYTES(ndr, n) NDR_CHECK(ndr_push_expand(ndr, ndr->offset+(n)))
# define NDR_PUSH_ALIGN(ndr, n) do { \
2003-11-05 01:42:00 +03:00
uint32 _pad = ( ndr - > offset & ( n - 1 ) ) ; \
2003-11-06 15:34:04 +03:00
while ( _pad - - ) NDR_CHECK ( ndr_push_uint8 ( ndr , 0 ) ) ; \
2003-11-03 09:22:45 +03:00
} while ( 0 )
/*
2003-11-06 15:34:04 +03:00
push a uint8
2003-11-03 09:22:45 +03:00
*/
2003-11-06 15:34:04 +03:00
NTSTATUS ndr_push_uint8 ( struct ndr_push * ndr , uint8 v )
2003-11-03 09:22:45 +03:00
{
NDR_PUSH_NEED_BYTES ( ndr , 1 ) ;
SCVAL ( ndr - > data , ndr - > offset , v ) ;
ndr - > offset + = 1 ;
return NT_STATUS_OK ;
}
/*
2003-11-06 15:34:04 +03:00
push a uint16
2003-11-03 09:22:45 +03:00
*/
2003-11-06 15:34:04 +03:00
NTSTATUS ndr_push_uint16 ( struct ndr_push * ndr , uint16 v )
2003-11-03 09:22:45 +03:00
{
NDR_PUSH_ALIGN ( ndr , 2 ) ;
NDR_PUSH_NEED_BYTES ( ndr , 2 ) ;
SSVAL ( ndr - > data , ndr - > offset , v ) ;
ndr - > offset + = 2 ;
return NT_STATUS_OK ;
}
/*
2003-11-06 15:34:04 +03:00
push a uint32
2003-11-03 09:22:45 +03:00
*/
2003-11-06 15:34:04 +03:00
NTSTATUS ndr_push_uint32 ( struct ndr_push * ndr , uint32 v )
2003-11-03 09:22:45 +03:00
{
NDR_PUSH_ALIGN ( ndr , 4 ) ;
NDR_PUSH_NEED_BYTES ( ndr , 4 ) ;
SIVAL ( ndr - > data , ndr - > offset , v ) ;
ndr - > offset + = 4 ;
return NT_STATUS_OK ;
}
2003-11-03 12:18:38 +03:00
2003-11-06 15:34:04 +03:00
/*
align to a uint32
*/
NTSTATUS ndr_push_align_uint32 ( struct ndr_push * ndr )
{
NDR_PUSH_ALIGN ( ndr , 4 ) ;
return NT_STATUS_OK ;
}
2003-11-03 12:18:38 +03:00
/*
push some bytes
*/
NTSTATUS ndr_push_bytes ( struct ndr_push * ndr , const char * data , uint32 n )
{
NDR_PUSH_NEED_BYTES ( ndr , n ) ;
memcpy ( ndr - > data + ndr - > offset , data , n ) ;
ndr - > offset + = n ;
return NT_STATUS_OK ;
}
2003-11-04 12:10:31 +03:00
2003-11-05 03:49:42 +03:00
/*
save the current position
*/
void ndr_push_save ( struct ndr_push * ndr , struct ndr_push_save * save )
{
save - > offset = ndr - > offset ;
}
/*
restore the position
*/
void ndr_push_restore ( struct ndr_push * ndr , struct ndr_push_save * save )
{
ndr - > offset = save - > offset ;
}
2003-11-04 12:10:31 +03:00
/*
this is used when a packet has a 4 byte length field . We remember the start position
and come back to it later to fill in the size
*/
NTSTATUS ndr_push_length4_start ( struct ndr_push * ndr , struct ndr_push_save * save )
{
2003-11-04 12:48:33 +03:00
NDR_PUSH_ALIGN ( ndr , 4 ) ;
2003-11-05 03:49:42 +03:00
ndr_push_save ( ndr , save ) ;
2003-11-06 15:34:04 +03:00
return ndr_push_uint32 ( ndr , 0 ) ;
2003-11-04 12:10:31 +03:00
}
NTSTATUS ndr_push_length4_end ( struct ndr_push * ndr , struct ndr_push_save * save )
{
2003-11-05 03:49:42 +03:00
struct ndr_push_save save2 ;
ndr_push_save ( ndr , & save2 ) ;
ndr_push_restore ( ndr , save ) ;
2003-11-06 15:34:04 +03:00
NDR_CHECK ( ndr_push_uint32 ( ndr , save2 . offset - ndr - > offset ) ) ;
2003-11-05 03:49:42 +03:00
ndr_push_restore ( ndr , & save2 ) ;
2003-11-04 12:10:31 +03:00
return NT_STATUS_OK ;
}
/*
push a 1 if a pointer is non - NULL , otherwise 0
*/
NTSTATUS ndr_push_ptr ( struct ndr_push * ndr , const void * p )
{
2003-11-06 15:34:04 +03:00
return ndr_push_uint32 ( ndr , p ? 1 : 0 ) ;
2003-11-04 12:10:31 +03:00
}
/*
push a comformant , variable ucs2 string onto the wire from a C string
*/
NTSTATUS ndr_push_unistr ( struct ndr_push * ndr , const char * s )
{
2003-11-04 12:48:33 +03:00
char * ws ;
2003-11-04 12:10:31 +03:00
ssize_t len ;
2003-11-04 12:48:33 +03:00
len = push_ucs2_talloc ( ndr - > mem_ctx , ( smb_ucs2_t * * ) & ws , s ) ;
2003-11-04 12:10:31 +03:00
if ( len = = - 1 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2003-11-06 15:34:04 +03:00
NDR_CHECK ( ndr_push_uint32 ( ndr , len / 2 ) ) ;
NDR_CHECK ( ndr_push_uint32 ( ndr , 0 ) ) ;
NDR_CHECK ( ndr_push_uint32 ( ndr , len / 2 ) ) ;
2003-11-04 12:48:33 +03:00
NDR_CHECK ( ndr_push_bytes ( ndr , ws , len ) ) ;
2003-11-04 12:10:31 +03:00
return NT_STATUS_OK ;
}
2003-11-05 03:49:42 +03:00
/*
push a 4 byte offset pointer , remembering where we are so we can later fill
in the correct value
*/
NTSTATUS ndr_push_offset ( struct ndr_push * ndr , struct ndr_push_save * ofs )
{
NDR_PUSH_ALIGN ( ndr , 4 ) ;
ndr_push_save ( ndr , ofs ) ;
2003-11-06 15:34:04 +03:00
return ndr_push_uint32 ( ndr , 0 ) ;
2003-11-05 03:49:42 +03:00
}
/*
fill in the correct offset in a saved offset pointer
the offset is taken relative to ' save '
*/
NTSTATUS ndr_push_offset_ptr ( struct ndr_push * ndr ,
struct ndr_push_save * ofs ,
struct ndr_push_save * save )
{
struct ndr_push_save save2 ;
ndr_push_save ( ndr , & save2 ) ;
ndr_push_restore ( ndr , ofs ) ;
2003-11-06 15:34:04 +03:00
NDR_CHECK ( ndr_push_uint32 ( ndr , save2 . offset - save - > offset ) ) ;
2003-11-05 03:49:42 +03:00
ndr_push_restore ( ndr , & save2 ) ;
return NT_STATUS_OK ;
}
/*
push a GUID
*/
NTSTATUS ndr_push_guid ( struct ndr_push * ndr , GUID * guid )
{
return ndr_push_bytes ( ndr , guid - > info , GUID_SIZE ) ;
}