2003-10-30 08:32:26 +00:00
/*
Unix SMB / CIFS implementation .
2003-11-03 06:22:45 +00:00
2003-10-30 08:32:26 +00:00
libndr interface
2003-11-03 06:22:45 +00:00
2003-10-30 08:32:26 +00:00
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 .
*/
/*
2003-11-03 06:22:45 +00:00
this provides the core routines for NDR parsing functions
see http : //www.opengroup.org/onlinepubs/9629399/chap14.htm for details
of NDR encoding rules
2003-10-30 08:32:26 +00:00
*/
# include "includes.h"
2003-11-04 23:12:44 +00:00
# define NDR_BASE_MARSHALL_SIZE 1024
2003-11-23 06:28:12 +00:00
/*
work out the number of bytes needed to align on a n byte boundary
*/
size_t ndr_align_size ( uint32 offset , size_t n )
{
if ( ( offset & ( n - 1 ) ) = = 0 ) return 0 ;
return n - ( offset & ( n - 1 ) ) ;
}
2003-10-30 08:32:26 +00:00
/*
initialise a ndr parse structure from a data blob
*/
2003-12-12 03:59:09 +00:00
struct ndr_pull * ndr_pull_init_blob ( const DATA_BLOB * blob , TALLOC_CTX * mem_ctx )
2003-10-30 08:32:26 +00:00
{
2003-11-03 06:22:45 +00:00
struct ndr_pull * ndr ;
2003-10-30 08:32:26 +00:00
ndr = talloc ( mem_ctx , sizeof ( * ndr ) ) ;
if ( ! ndr ) return NULL ;
2003-11-04 22:42:00 +00:00
ndr - > flags = 0 ;
2003-10-30 08:32:26 +00:00
ndr - > data = blob - > data ;
ndr - > data_size = blob - > length ;
ndr - > offset = 0 ;
ndr - > mem_ctx = mem_ctx ;
return ndr ;
}
2003-11-15 04:42:48 +00:00
/*
create an ndr sub - context based on an existing context . The new context starts
at the current offset , with the given size limit
*/
NTSTATUS ndr_pull_subcontext ( struct ndr_pull * ndr , struct ndr_pull * ndr2 , uint32 size )
{
NDR_PULL_NEED_BYTES ( ndr , size ) ;
* ndr2 = * ndr ;
ndr2 - > data + = ndr2 - > offset ;
ndr2 - > offset = 0 ;
ndr2 - > data_size = size ;
2003-11-21 13:14:17 +00:00
ndr2 - > flags = ndr - > flags ;
2003-11-15 04:42:48 +00:00
return NT_STATUS_OK ;
}
2003-10-30 08:32:26 +00:00
/*
advance by ' size ' bytes
*/
2003-11-03 06:22:45 +00:00
NTSTATUS ndr_pull_advance ( struct ndr_pull * ndr , uint32 size )
2003-10-30 08:32:26 +00:00
{
ndr - > offset + = size ;
if ( ndr - > offset > ndr - > data_size ) {
2003-11-22 08:11:32 +00:00
return ndr_pull_error ( ndr , NDR_ERR_BUFSIZE ,
" ndr_pull_advance by %u failed " ,
size ) ;
2003-10-30 08:32:26 +00:00
}
return NT_STATUS_OK ;
}
/*
set the parse offset to ' ofs '
*/
2003-11-03 06:22:45 +00:00
NTSTATUS ndr_pull_set_offset ( struct ndr_pull * ndr , uint32 ofs )
2003-10-30 08:32:26 +00:00
{
ndr - > offset = ofs ;
if ( ndr - > offset > ndr - > data_size ) {
2003-11-22 08:11:32 +00:00
return ndr_pull_error ( ndr , NDR_ERR_BUFSIZE ,
" ndr_pull_set_offset %u failed " ,
ofs ) ;
2003-10-30 08:32:26 +00:00
}
return NT_STATUS_OK ;
}
/* save the offset/size of the current ndr state */
2003-11-03 06:22:45 +00:00
void ndr_pull_save ( struct ndr_pull * ndr , struct ndr_pull_save * save )
2003-10-30 08:32:26 +00:00
{
save - > offset = ndr - > offset ;
save - > data_size = ndr - > data_size ;
}
/* restore the size/offset of a ndr structure */
2003-11-03 06:22:45 +00:00
void ndr_pull_restore ( struct ndr_pull * ndr , struct ndr_pull_save * save )
2003-10-30 08:32:26 +00:00
{
ndr - > offset = save - > offset ;
ndr - > data_size = save - > data_size ;
}
2003-11-03 06:22:45 +00:00
/* create a ndr_push structure, ready for some marshalling */
2003-11-22 08:11:32 +00:00
struct ndr_push * ndr_push_init_ctx ( TALLOC_CTX * mem_ctx )
2003-11-03 06:22:45 +00:00
{
struct ndr_push * ndr ;
ndr = talloc ( mem_ctx , sizeof ( * ndr ) ) ;
if ( ! ndr ) {
return NULL ;
}
ndr - > mem_ctx = mem_ctx ;
ndr - > flags = 0 ;
ndr - > alloc_size = NDR_BASE_MARSHALL_SIZE ;
ndr - > data = talloc ( ndr - > mem_ctx , ndr - > alloc_size ) ;
if ( ! ndr - > data ) {
return NULL ;
}
ndr - > offset = 0 ;
2003-11-20 03:09:19 +00:00
ndr - > ptr_count = 0 ;
2003-11-22 08:11:32 +00:00
ndr - > relative_list = NULL ;
ndr - > relative_list_end = NULL ;
2003-11-03 06:22:45 +00:00
return ndr ;
}
2003-11-22 08:11:32 +00:00
/* create a ndr_push structure, ready for some marshalling */
struct ndr_push * ndr_push_init ( void )
{
struct ndr_push * ndr ;
TALLOC_CTX * mem_ctx = talloc_init ( " ndr_push_init " ) ;
if ( ! mem_ctx ) return NULL ;
ndr = ndr_push_init_ctx ( mem_ctx ) ;
if ( ! ndr ) {
talloc_destroy ( mem_ctx ) ;
}
return ndr ;
}
2003-11-03 06:22:45 +00:00
/* free a ndr_push structure */
void ndr_push_free ( struct ndr_push * ndr )
{
talloc_destroy ( ndr - > mem_ctx ) ;
}
/* return a DATA_BLOB structure for the current ndr_push marshalled data */
DATA_BLOB ndr_push_blob ( struct ndr_push * ndr )
{
DATA_BLOB blob ;
blob . data = ndr - > data ;
blob . length = ndr - > offset ;
return blob ;
}
/*
expand the available space in the buffer to ' size '
*/
NTSTATUS ndr_push_expand ( struct ndr_push * ndr , uint32 size )
{
if ( ndr - > alloc_size > = size ) {
return NT_STATUS_OK ;
}
2003-11-12 05:34:21 +00:00
ndr - > alloc_size + = NDR_BASE_MARSHALL_SIZE ;
if ( size > ndr - > alloc_size ) {
ndr - > alloc_size = size ;
}
2003-11-04 23:12:44 +00:00
ndr - > data = talloc_realloc ( ndr - > mem_ctx , ndr - > data , ndr - > alloc_size ) ;
2003-11-03 06:22:45 +00:00
if ( ! ndr - > data ) {
2003-11-22 08:11:32 +00:00
return ndr_push_error ( ndr , NDR_ERR_ALLOC , " Failed to push_expand to %u " ,
ndr - > alloc_size ) ;
2003-11-03 06:22:45 +00:00
}
return NT_STATUS_OK ;
}
/*
set the push offset to ' ofs '
*/
NTSTATUS ndr_push_set_offset ( struct ndr_push * ndr , uint32 ofs )
{
NDR_CHECK ( ndr_push_expand ( ndr , ofs ) ) ;
ndr - > offset = ofs ;
return NT_STATUS_OK ;
}
2003-11-08 11:21:57 +00:00
/*
push a generic array
*/
2003-11-13 09:26:53 +00:00
NTSTATUS ndr_push_array ( struct ndr_push * ndr , int ndr_flags , void * base ,
2003-11-16 13:49:14 +00:00
size_t elsize , uint32 count ,
NTSTATUS ( * push_fn ) ( struct ndr_push * , int , void * ) )
2003-11-08 11:21:57 +00:00
{
int i ;
char * p = base ;
2003-11-09 00:58:40 +00:00
if ( ! ( ndr_flags & NDR_SCALARS ) ) goto buffers ;
2003-11-08 11:21:57 +00:00
for ( i = 0 ; i < count ; i + + ) {
2003-11-09 00:58:40 +00:00
NDR_CHECK ( push_fn ( ndr , NDR_SCALARS , p ) ) ;
2003-11-08 11:21:57 +00:00
p + = elsize ;
}
2003-11-09 00:58:40 +00:00
if ( ! ( ndr_flags & NDR_BUFFERS ) ) goto done ;
buffers :
p = base ;
for ( i = 0 ; i < count ; i + + ) {
NDR_CHECK ( push_fn ( ndr , NDR_BUFFERS , p ) ) ;
p + = elsize ;
}
done :
2003-11-08 11:21:57 +00:00
return NT_STATUS_OK ;
}
2003-11-12 05:34:21 +00:00
/*
pull a constant sized array
*/
2003-11-13 09:26:53 +00:00
NTSTATUS ndr_pull_array ( struct ndr_pull * ndr , int ndr_flags , void * base ,
size_t elsize , uint32 count ,
NTSTATUS ( * pull_fn ) ( struct ndr_pull * , int , void * ) )
2003-11-08 11:21:57 +00:00
{
int i ;
char * p ;
2003-11-09 07:24:06 +00:00
p = base ;
2003-11-08 11:21:57 +00:00
if ( ! ( ndr_flags & NDR_SCALARS ) ) goto buffers ;
for ( i = 0 ; i < count ; i + + ) {
NDR_CHECK ( pull_fn ( ndr , NDR_SCALARS , p ) ) ;
p + = elsize ;
}
if ( ! ( ndr_flags & NDR_BUFFERS ) ) goto done ;
buffers :
2003-11-09 07:24:06 +00:00
p = base ;
2003-11-08 11:21:57 +00:00
for ( i = 0 ; i < count ; i + + ) {
NDR_CHECK ( pull_fn ( ndr , NDR_BUFFERS , p ) ) ;
p + = elsize ;
}
done :
return NT_STATUS_OK ;
}
2003-11-11 04:04:36 +00:00
/*
print a generic array
*/
void ndr_print_array ( struct ndr_print * ndr , const char * name , void * base ,
size_t elsize , uint32 count ,
void ( * print_fn ) ( struct ndr_print * , const char * , void * ) )
{
int i ;
char * p = base ;
ndr - > print ( ndr , " %s: ARRAY(%d) " , name , count ) ;
ndr - > depth + + ;
for ( i = 0 ; i < count ; i + + ) {
char * idx = NULL ;
asprintf ( & idx , " [%d] " , i ) ;
if ( idx ) {
print_fn ( ndr , idx , p ) ;
free ( idx ) ;
}
p + = elsize ;
}
ndr - > depth - - ;
}
2003-11-23 13:44:19 +00:00
void ndr_print_debug_helper ( struct ndr_print * ndr , const char * format , . . . )
2003-11-11 04:04:36 +00:00
{
va_list ap ;
char * s = NULL ;
int i ;
va_start ( ap , format ) ;
vasprintf ( & s , format , ap ) ;
va_end ( ap ) ;
for ( i = 0 ; i < ndr - > depth ; i + + ) {
2003-11-21 02:50:40 +00:00
DEBUG ( 0 , ( " " ) ) ;
2003-11-11 04:04:36 +00:00
}
2003-11-21 02:50:40 +00:00
DEBUG ( 0 , ( " %s \n " , s ) ) ;
2003-11-11 04:04:36 +00:00
free ( s ) ;
}
/*
a useful helper function for printing idl structures via DEBUG ( )
*/
void ndr_print_debug ( void ( * fn ) ( struct ndr_print * , const char * , void * ) ,
const char * name ,
void * ptr )
{
struct ndr_print ndr ;
ndr . mem_ctx = talloc_init ( " ndr_print_debug " ) ;
if ( ! ndr . mem_ctx ) return ;
ndr . print = ndr_print_debug_helper ;
2003-11-11 04:38:51 +00:00
ndr . depth = 1 ;
2003-11-11 04:04:36 +00:00
fn ( & ndr , name , ptr ) ;
talloc_destroy ( ndr . mem_ctx ) ;
}
2003-11-11 04:38:51 +00:00
2003-11-21 02:50:40 +00:00
2003-11-11 04:38:51 +00:00
/*
a useful helper function for printing idl unions via DEBUG ( )
*/
2003-11-19 22:10:20 +00:00
void ndr_print_union_debug ( void ( * fn ) ( struct ndr_print * , const char * , uint32 , void * ) ,
2003-11-11 04:38:51 +00:00
const char * name ,
2003-11-19 22:10:20 +00:00
uint32 level ,
2003-11-11 04:38:51 +00:00
void * ptr )
{
struct ndr_print ndr ;
2003-11-17 11:55:56 +00:00
ndr . mem_ctx = talloc_init ( " ndr_print_union " ) ;
2003-11-11 04:38:51 +00:00
if ( ! ndr . mem_ctx ) return ;
ndr . print = ndr_print_debug_helper ;
ndr . depth = 1 ;
fn ( & ndr , name , level , ptr ) ;
talloc_destroy ( ndr . mem_ctx ) ;
}
2003-11-13 09:26:53 +00:00
2003-11-17 11:55:56 +00:00
/*
a useful helper function for printing idl function calls via DEBUG ( )
*/
void ndr_print_function_debug ( void ( * fn ) ( struct ndr_print * , const char * , int , void * ) ,
const char * name ,
int flags ,
void * ptr )
{
struct ndr_print ndr ;
2003-11-21 02:50:40 +00:00
if ( ! DEBUGLVL ( 2 ) ) {
return ;
}
2003-11-17 11:55:56 +00:00
ndr . mem_ctx = talloc_init ( " ndr_print_function " ) ;
if ( ! ndr . mem_ctx ) return ;
ndr . print = ndr_print_debug_helper ;
ndr . depth = 1 ;
fn ( & ndr , name , flags , ptr ) ;
talloc_destroy ( ndr . mem_ctx ) ;
}
2003-11-22 08:11:32 +00:00
static NTSTATUS ndr_map_error ( enum ndr_err_code err )
{
switch ( err ) {
case NDR_ERR_BUFSIZE :
return NT_STATUS_BUFFER_TOO_SMALL ;
case NDR_ERR_ALLOC :
return NT_STATUS_NO_MEMORY ;
}
/* we should all error codes to different status codes */
return NT_STATUS_INVALID_PARAMETER ;
}
2003-11-13 09:26:53 +00:00
/*
return and possibly log an NDR error
*/
NTSTATUS ndr_pull_error ( struct ndr_pull * ndr , enum ndr_err_code err , const char * format , . . . )
{
char * s = NULL ;
va_list ap ;
va_start ( ap , format ) ;
vasprintf ( & s , format , ap ) ;
va_end ( ap ) ;
DEBUG ( 3 , ( " ndr_pull_error(%u): %s \n " , err , s ) ) ;
free ( s ) ;
2003-11-22 08:11:32 +00:00
return ndr_map_error ( err ) ;
2003-11-13 09:26:53 +00:00
}
2003-11-14 07:20:46 +00:00
/*
return and possibly log an NDR error
*/
NTSTATUS ndr_push_error ( struct ndr_push * ndr , enum ndr_err_code err , const char * format , . . . )
{
char * s = NULL ;
va_list ap ;
va_start ( ap , format ) ;
vasprintf ( & s , format , ap ) ;
va_end ( ap ) ;
DEBUG ( 3 , ( " ndr_push_error(%u): %s \n " , err , s ) ) ;
free ( s ) ;
2003-11-22 08:11:32 +00:00
return ndr_map_error ( err ) ;
2003-11-14 07:20:46 +00:00
}
2003-11-16 06:00:15 +00:00
2003-11-21 13:14:17 +00:00
/*
handle subcontext buffers , which in midl land are user - marshalled , but
we use magic in pidl to make them easier to cope with
*/
static NTSTATUS ndr_pull_subcontext_header ( struct ndr_pull * ndr ,
size_t sub_size ,
struct ndr_pull * ndr2 )
{
switch ( sub_size ) {
case 0 : {
uint32 size = ndr - > data_size - ndr - > offset ;
if ( size = = 0 ) return NT_STATUS_OK ;
NDR_CHECK ( ndr_pull_subcontext ( ndr , ndr2 , size ) ) ;
break ;
}
case 2 : {
uint16 size ;
NDR_CHECK ( ndr_pull_uint16 ( ndr , & size ) ) ;
if ( size = = 0 ) return NT_STATUS_OK ;
NDR_CHECK ( ndr_pull_subcontext ( ndr , ndr2 , size ) ) ;
break ;
}
case 4 : {
uint32 size ;
NDR_CHECK ( ndr_pull_uint32 ( ndr , & size ) ) ;
if ( size = = 0 ) return NT_STATUS_OK ;
NDR_CHECK ( ndr_pull_subcontext ( ndr , ndr2 , size ) ) ;
break ;
}
default :
return ndr_pull_error ( ndr , NDR_ERR_SUBCONTEXT , " Bad subcontext size %d " ,
sub_size ) ;
}
return NT_STATUS_OK ;
}
2003-11-16 06:00:15 +00:00
/*
handle subcontext buffers , which in midl land are user - marshalled , but
we use magic in pidl to make them easier to cope with
*/
NTSTATUS ndr_pull_subcontext_fn ( struct ndr_pull * ndr ,
2003-11-21 13:14:17 +00:00
size_t sub_size ,
2003-11-16 06:00:15 +00:00
void * base ,
NTSTATUS ( * fn ) ( struct ndr_pull * , void * ) )
{
struct ndr_pull ndr2 ;
2003-11-21 13:14:17 +00:00
NDR_CHECK ( ndr_pull_subcontext_header ( ndr , sub_size , & ndr2 ) ) ;
2003-11-16 06:00:15 +00:00
NDR_CHECK ( fn ( & ndr2 , base ) ) ;
2003-11-21 13:14:17 +00:00
if ( sub_size ) {
NDR_CHECK ( ndr_pull_advance ( ndr , ndr2 . data_size ) ) ;
} else {
NDR_CHECK ( ndr_pull_advance ( ndr , ndr2 . offset ) ) ;
}
2003-11-16 06:00:15 +00:00
return NT_STATUS_OK ;
}
NTSTATUS ndr_pull_subcontext_flags_fn ( struct ndr_pull * ndr ,
2003-11-21 13:14:17 +00:00
size_t sub_size ,
2003-11-16 06:00:15 +00:00
void * base ,
NTSTATUS ( * fn ) ( struct ndr_pull * , int , void * ) )
{
struct ndr_pull ndr2 ;
2003-11-21 13:14:17 +00:00
NDR_CHECK ( ndr_pull_subcontext_header ( ndr , sub_size , & ndr2 ) ) ;
2003-11-16 06:00:15 +00:00
NDR_CHECK ( fn ( & ndr2 , NDR_SCALARS | NDR_BUFFERS , base ) ) ;
2003-11-21 13:14:17 +00:00
if ( sub_size ) {
NDR_CHECK ( ndr_pull_advance ( ndr , ndr2 . data_size ) ) ;
} else {
NDR_CHECK ( ndr_pull_advance ( ndr , ndr2 . offset ) ) ;
}
2003-11-16 06:00:15 +00:00
return NT_STATUS_OK ;
}
2003-11-16 11:36:59 +00:00
NTSTATUS ndr_pull_subcontext_union_fn ( struct ndr_pull * ndr ,
2003-11-21 13:14:17 +00:00
size_t sub_size ,
2003-11-19 22:10:20 +00:00
uint32 level ,
2003-11-16 11:36:59 +00:00
void * base ,
2003-11-19 22:10:20 +00:00
NTSTATUS ( * fn ) ( struct ndr_pull * , int , uint32 , void * ) )
2003-11-16 11:36:59 +00:00
{
struct ndr_pull ndr2 ;
2003-11-21 13:14:17 +00:00
NDR_CHECK ( ndr_pull_subcontext_header ( ndr , sub_size , & ndr2 ) ) ;
2003-11-16 11:36:59 +00:00
NDR_CHECK ( fn ( & ndr2 , NDR_SCALARS | NDR_BUFFERS , level , base ) ) ;
2003-11-21 13:14:17 +00:00
if ( sub_size ) {
NDR_CHECK ( ndr_pull_advance ( ndr , ndr2 . data_size ) ) ;
} else {
NDR_CHECK ( ndr_pull_advance ( ndr , ndr2 . offset ) ) ;
}
2003-11-16 11:36:59 +00:00
return NT_STATUS_OK ;
}
2003-11-16 13:49:14 +00:00
2003-11-22 08:11:32 +00:00
/*
push a subcontext header
*/
static NTSTATUS ndr_push_subcontext_header ( struct ndr_push * ndr ,
size_t sub_size ,
struct ndr_push * ndr2 )
{
switch ( sub_size ) {
case 0 :
break ;
case 2 :
NDR_CHECK ( ndr_push_uint16 ( ndr , ndr2 - > offset ) ) ;
break ;
case 4 :
NDR_CHECK ( ndr_push_uint32 ( ndr , ndr2 - > offset ) ) ;
break ;
default :
return ndr_push_error ( ndr , NDR_ERR_SUBCONTEXT , " Bad subcontext size %d " ,
sub_size ) ;
}
return NT_STATUS_OK ;
}
/*
handle subcontext buffers , which in midl land are user - marshalled , but
we use magic in pidl to make them easier to cope with
*/
NTSTATUS ndr_push_subcontext_fn ( struct ndr_push * ndr ,
size_t sub_size ,
void * base ,
NTSTATUS ( * fn ) ( struct ndr_push * , void * ) )
{
struct ndr_push * ndr2 ;
ndr2 = ndr_push_init_ctx ( ndr - > mem_ctx ) ;
if ( ! ndr2 ) return NT_STATUS_NO_MEMORY ;
2003-11-22 09:32:35 +00:00
ndr2 - > flags = ndr - > flags ;
2003-11-22 08:11:32 +00:00
NDR_CHECK ( fn ( ndr2 , base ) ) ;
NDR_CHECK ( ndr_push_subcontext_header ( ndr , sub_size , ndr2 ) ) ;
NDR_CHECK ( ndr_push_bytes ( ndr , ndr2 - > data , ndr2 - > offset ) ) ;
return NT_STATUS_OK ;
}
/*
handle subcontext buffers for function that take a flags arg
*/
NTSTATUS ndr_push_subcontext_flags_fn ( struct ndr_push * ndr ,
size_t sub_size ,
void * base ,
NTSTATUS ( * fn ) ( struct ndr_push * , int , void * ) )
{
struct ndr_push * ndr2 ;
ndr2 = ndr_push_init_ctx ( ndr - > mem_ctx ) ;
if ( ! ndr2 ) return NT_STATUS_NO_MEMORY ;
2003-11-22 09:32:35 +00:00
ndr2 - > flags = ndr - > flags ;
2003-11-22 08:11:32 +00:00
NDR_CHECK ( fn ( ndr2 , NDR_SCALARS | NDR_BUFFERS , base ) ) ;
NDR_CHECK ( ndr_push_subcontext_header ( ndr , sub_size , ndr2 ) ) ;
NDR_CHECK ( ndr_push_bytes ( ndr , ndr2 - > data , ndr2 - > offset ) ) ;
return NT_STATUS_OK ;
}
/*
handle subcontext buffers for function that take a union
*/
NTSTATUS ndr_push_subcontext_union_fn ( struct ndr_push * ndr ,
size_t sub_size ,
uint32 level ,
void * base ,
NTSTATUS ( * fn ) ( struct ndr_push * , int , uint32 , void * ) )
{
struct ndr_push * ndr2 ;
ndr2 = ndr_push_init_ctx ( ndr - > mem_ctx ) ;
if ( ! ndr2 ) return NT_STATUS_NO_MEMORY ;
2003-11-22 09:32:35 +00:00
ndr2 - > flags = ndr - > flags ;
2003-11-22 08:11:32 +00:00
NDR_CHECK ( fn ( ndr2 , NDR_SCALARS | NDR_BUFFERS , level , base ) ) ;
NDR_CHECK ( ndr_push_subcontext_header ( ndr , sub_size , ndr2 ) ) ;
NDR_CHECK ( ndr_push_bytes ( ndr , ndr2 - > data , ndr2 - > offset ) ) ;
return NT_STATUS_OK ;
}
2003-11-17 02:18:11 +00:00
/*
mark the start of a structure
*/
NTSTATUS ndr_pull_struct_start ( struct ndr_pull * ndr )
{
struct ndr_ofs_list * ofs ;
NDR_ALLOC ( ndr , ofs ) ;
ofs - > offset = ndr - > offset ;
ofs - > next = ndr - > ofs_list ;
ndr - > ofs_list = ofs ;
return NT_STATUS_OK ;
}
/*
mark the end of a structure
*/
void ndr_pull_struct_end ( struct ndr_pull * ndr )
{
ndr - > ofs_list = ndr - > ofs_list - > next ;
}
/*
mark the start of a structure
*/
NTSTATUS ndr_push_struct_start ( struct ndr_push * ndr )
{
struct ndr_ofs_list * ofs ;
2003-11-22 08:11:32 +00:00
NDR_PUSH_ALLOC ( ndr , ofs ) ;
2003-11-17 02:18:11 +00:00
ofs - > offset = ndr - > offset ;
ofs - > next = ndr - > ofs_list ;
ndr - > ofs_list = ofs ;
return NT_STATUS_OK ;
}
/*
mark the end of a structure
*/
void ndr_push_struct_end ( struct ndr_push * ndr )
{
ndr - > ofs_list = ndr - > ofs_list - > next ;
}
2003-11-16 13:49:14 +00:00
/*
pull a relative structure
*/
NTSTATUS ndr_pull_relative ( struct ndr_pull * ndr , const void * * buf , size_t size ,
NTSTATUS ( * fn ) ( struct ndr_pull * , int ndr_flags , void * ) )
{
struct ndr_pull ndr2 ;
uint32 ofs ;
struct ndr_pull_save save ;
void * p ;
NDR_CHECK ( ndr_pull_uint32 ( ndr , & ofs ) ) ;
if ( ofs = = 0 ) {
( * buf ) = NULL ;
return NT_STATUS_OK ;
}
ndr_pull_save ( ndr , & save ) ;
2003-11-17 02:18:11 +00:00
NDR_CHECK ( ndr_pull_set_offset ( ndr , ofs + ndr - > ofs_list - > offset ) ) ;
2003-11-16 13:49:14 +00:00
NDR_CHECK ( ndr_pull_subcontext ( ndr , & ndr2 , ndr - > data_size - ndr - > offset ) ) ;
2003-11-21 22:00:00 +00:00
/* strings must be allocated by the backend functions */
if ( ndr - > flags & LIBNDR_STRING_FLAGS ) {
NDR_CHECK ( fn ( & ndr2 , NDR_SCALARS | NDR_BUFFERS , & p ) ) ;
2003-11-16 13:49:14 +00:00
} else {
NDR_ALLOC_SIZE ( ndr , p , size ) ;
NDR_CHECK ( fn ( & ndr2 , NDR_SCALARS | NDR_BUFFERS , p ) ) ;
}
( * buf ) = p ;
ndr_pull_restore ( ndr , & save ) ;
return NT_STATUS_OK ;
}
/*
push a relative structure
*/
NTSTATUS ndr_push_relative ( struct ndr_push * ndr , int ndr_flags , const void * p ,
NTSTATUS ( * fn ) ( struct ndr_push * , int , const void * ) )
{
2003-11-17 02:18:11 +00:00
struct ndr_ofs_list * ofs ;
2003-11-16 13:49:14 +00:00
if ( ndr_flags & NDR_SCALARS ) {
if ( ! p ) {
NDR_CHECK ( ndr_push_uint32 ( ndr , 0 ) ) ;
return NT_STATUS_OK ;
}
2003-11-22 08:11:32 +00:00
NDR_PUSH_ALLOC ( ndr , ofs ) ;
2003-11-16 13:49:14 +00:00
NDR_CHECK ( ndr_push_align ( ndr , 4 ) ) ;
2003-11-17 02:18:11 +00:00
ofs - > offset = ndr - > offset ;
2003-11-16 13:49:14 +00:00
NDR_CHECK ( ndr_push_uint32 ( ndr , 0xFFFFFFFF ) ) ;
2003-11-22 08:11:32 +00:00
ofs - > next = NULL ;
if ( ndr - > relative_list_end ) {
ndr - > relative_list_end - > next = ofs ;
} else {
ndr - > relative_list = ofs ;
}
ndr - > relative_list_end = ofs ;
2003-11-16 13:49:14 +00:00
}
if ( ndr_flags & NDR_BUFFERS ) {
2003-11-17 02:18:11 +00:00
struct ndr_push_save save ;
2003-11-16 13:49:14 +00:00
if ( ! p ) {
return NT_STATUS_OK ;
}
2003-11-17 02:18:11 +00:00
ofs = ndr - > relative_list ;
if ( ! ofs ) {
2003-11-16 13:49:14 +00:00
return ndr_push_error ( ndr , NDR_ERR_RELATIVE , " Empty relative stack " ) ;
}
2003-11-17 02:18:11 +00:00
ndr - > relative_list = ndr - > relative_list - > next ;
2003-11-22 08:11:32 +00:00
if ( ndr - > relative_list = = NULL ) {
ndr - > relative_list_end = NULL ;
}
2003-11-16 13:49:14 +00:00
NDR_CHECK ( ndr_push_align ( ndr , 8 ) ) ;
2003-11-17 02:18:11 +00:00
ndr_push_save ( ndr , & save ) ;
ndr - > offset = ofs - > offset ;
2003-11-22 11:49:22 +00:00
NDR_CHECK ( ndr_push_uint32 ( ndr , save . offset - ndr - > ofs_list - > offset ) ) ;
2003-11-17 02:18:11 +00:00
ndr_push_restore ( ndr , & save ) ;
2003-11-16 13:49:14 +00:00
NDR_CHECK ( fn ( ndr , NDR_SCALARS | NDR_BUFFERS , p ) ) ;
}
return NT_STATUS_OK ;
}
2003-11-17 04:56:59 +00:00
/*
pull a union from a blob using NDR
*/
2003-11-19 22:10:20 +00:00
NTSTATUS ndr_pull_union_blob ( DATA_BLOB * blob , TALLOC_CTX * mem_ctx , uint32 level , void * p ,
NTSTATUS ( * fn ) ( struct ndr_pull * , int ndr_flags , uint32 , void * ) )
2003-11-17 04:56:59 +00:00
{
struct ndr_pull * ndr ;
ndr = ndr_pull_init_blob ( blob , mem_ctx ) ;
if ( ! ndr ) {
return NT_STATUS_NO_MEMORY ;
}
2003-11-19 22:10:20 +00:00
return fn ( ndr , NDR_SCALARS | NDR_BUFFERS , level , p ) ;
2003-11-17 04:56:59 +00:00
}
/*
pull a struct from a blob using NDR
*/
NTSTATUS ndr_pull_struct_blob ( DATA_BLOB * blob , TALLOC_CTX * mem_ctx , void * p ,
2003-11-26 01:16:41 +00:00
NTSTATUS ( * fn ) ( struct ndr_pull * , int , void * ) )
2003-11-17 04:56:59 +00:00
{
struct ndr_pull * ndr ;
ndr = ndr_pull_init_blob ( blob , mem_ctx ) ;
if ( ! ndr ) {
return NT_STATUS_NO_MEMORY ;
}
return fn ( ndr , NDR_SCALARS | NDR_BUFFERS , p ) ;
}
2003-11-24 01:24:29 +00:00
2003-11-26 01:16:41 +00:00
/*
push a struct to a blob using NDR
*/
NTSTATUS ndr_push_struct_blob ( DATA_BLOB * blob , TALLOC_CTX * mem_ctx , void * p ,
NTSTATUS ( * fn ) ( struct ndr_push * , int , void * ) )
{
NTSTATUS status ;
struct ndr_push * ndr ;
ndr = ndr_push_init_ctx ( mem_ctx ) ;
if ( ! ndr ) {
return NT_STATUS_NO_MEMORY ;
}
status = fn ( ndr , NDR_SCALARS | NDR_BUFFERS , p ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2003-11-24 01:24:29 +00:00
2003-11-26 01:16:41 +00:00
* blob = ndr_push_blob ( ndr ) ;
return NT_STATUS_OK ;
}