2003-10-30 11:32:26 +03:00
/*
Unix SMB / CIFS implementation .
2003-11-03 09:22:45 +03:00
2003-10-30 11:32:26 +03:00
libndr interface
2003-11-03 09:22:45 +03:00
2003-10-30 11:32:26 +03: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 09:22:45 +03: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 11:32:26 +03:00
*/
# include "includes.h"
2004-11-02 09:42:15 +03:00
# include "dlinklist.h"
2003-10-30 11:32:26 +03:00
2003-11-05 02:12:44 +03:00
# define NDR_BASE_MARSHALL_SIZE 1024
2003-11-23 09:28:12 +03:00
/*
work out the number of bytes needed to align on a n byte boundary
*/
2004-05-25 20:24:13 +04:00
size_t ndr_align_size ( uint32_t offset , size_t n )
2003-11-23 09:28:12 +03:00
{
if ( ( offset & ( n - 1 ) ) = = 0 ) return 0 ;
return n - ( offset & ( n - 1 ) ) ;
}
2003-10-30 11:32:26 +03:00
/*
initialise a ndr parse structure from a data blob
*/
2003-12-12 06:59:09 +03:00
struct ndr_pull * ndr_pull_init_blob ( const DATA_BLOB * blob , TALLOC_CTX * mem_ctx )
2003-10-30 11:32:26 +03:00
{
2003-11-03 09:22:45 +03:00
struct ndr_pull * ndr ;
2003-10-30 11:32:26 +03:00
2004-12-09 10:05:00 +03:00
ndr = talloc_zero_p ( mem_ctx , struct ndr_pull ) ;
2003-10-30 11:32:26 +03:00
if ( ! ndr ) return NULL ;
ndr - > data = blob - > data ;
ndr - > data_size = blob - > length ;
return ndr ;
}
2003-11-15 07:42:48 +03:00
/*
create an ndr sub - context based on an existing context . The new context starts
at the current offset , with the given size limit
*/
2004-05-25 20:24:13 +04:00
NTSTATUS ndr_pull_subcontext ( struct ndr_pull * ndr , struct ndr_pull * ndr2 , uint32_t size )
2003-11-15 07:42:48 +03:00
{
NDR_PULL_NEED_BYTES ( ndr , size ) ;
* ndr2 = * ndr ;
ndr2 - > data + = ndr2 - > offset ;
ndr2 - > offset = 0 ;
ndr2 - > data_size = size ;
2003-11-21 16:14:17 +03:00
ndr2 - > flags = ndr - > flags ;
2003-11-15 07:42:48 +03:00
return NT_STATUS_OK ;
}
2003-10-30 11:32:26 +03:00
/*
advance by ' size ' bytes
*/
2004-05-25 20:24:13 +04:00
NTSTATUS ndr_pull_advance ( struct ndr_pull * ndr , uint32_t size )
2003-10-30 11:32:26 +03:00
{
ndr - > offset + = size ;
if ( ndr - > offset > ndr - > data_size ) {
2003-11-22 11:11:32 +03:00
return ndr_pull_error ( ndr , NDR_ERR_BUFSIZE ,
" ndr_pull_advance by %u failed " ,
size ) ;
2003-10-30 11:32:26 +03:00
}
return NT_STATUS_OK ;
}
/*
set the parse offset to ' ofs '
*/
2004-05-25 20:24:13 +04:00
NTSTATUS ndr_pull_set_offset ( struct ndr_pull * ndr , uint32_t ofs )
2003-10-30 11:32:26 +03:00
{
ndr - > offset = ofs ;
if ( ndr - > offset > ndr - > data_size ) {
2003-11-22 11:11:32 +03:00
return ndr_pull_error ( ndr , NDR_ERR_BUFSIZE ,
" ndr_pull_set_offset %u failed " ,
ofs ) ;
2003-10-30 11:32:26 +03:00
}
return NT_STATUS_OK ;
}
/* save the offset/size of the current ndr state */
2003-11-03 09:22:45 +03:00
void ndr_pull_save ( struct ndr_pull * ndr , struct ndr_pull_save * save )
2003-10-30 11:32:26 +03:00
{
save - > offset = ndr - > offset ;
save - > data_size = ndr - > data_size ;
}
/* restore the size/offset of a ndr structure */
2003-11-03 09:22:45 +03:00
void ndr_pull_restore ( struct ndr_pull * ndr , struct ndr_pull_save * save )
2003-10-30 11:32:26 +03:00
{
ndr - > offset = save - > offset ;
ndr - > data_size = save - > data_size ;
}
2003-11-03 09:22:45 +03:00
/* create a ndr_push structure, ready for some marshalling */
2003-11-22 11:11:32 +03:00
struct ndr_push * ndr_push_init_ctx ( TALLOC_CTX * mem_ctx )
2003-11-03 09:22:45 +03:00
{
struct ndr_push * ndr ;
2004-12-09 10:05:00 +03:00
ndr = talloc_zero_p ( mem_ctx , struct ndr_push ) ;
2003-11-03 09:22:45 +03:00
if ( ! ndr ) {
return NULL ;
}
ndr - > flags = 0 ;
ndr - > alloc_size = NDR_BASE_MARSHALL_SIZE ;
2004-08-21 11:43:29 +04:00
ndr - > data = talloc ( ndr , ndr - > alloc_size ) ;
2003-11-03 09:22:45 +03:00
if ( ! ndr - > data ) {
return NULL ;
}
2004-08-12 09:15:41 +04:00
2003-11-03 09:22:45 +03:00
return ndr ;
}
2003-11-22 11:11:32 +03:00
/* create a ndr_push structure, ready for some marshalling */
struct ndr_push * ndr_push_init ( void )
{
2004-08-30 07:10:43 +04:00
return ndr_push_init_ctx ( NULL ) ;
2003-11-22 11:11:32 +03:00
}
2003-11-03 09:22:45 +03:00
/* free a ndr_push structure */
void ndr_push_free ( struct ndr_push * ndr )
{
2004-09-08 04:00:56 +04:00
talloc_free ( ndr ) ;
2003-11-03 09:22:45 +03:00
}
/* 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 '
*/
2004-05-25 20:24:13 +04:00
NTSTATUS ndr_push_expand ( struct ndr_push * ndr , uint32_t size )
2003-11-03 09:22:45 +03:00
{
if ( ndr - > alloc_size > = size ) {
return NT_STATUS_OK ;
}
2003-11-12 08:34:21 +03:00
ndr - > alloc_size + = NDR_BASE_MARSHALL_SIZE ;
if ( size > ndr - > alloc_size ) {
ndr - > alloc_size = size ;
}
2004-09-27 05:36:19 +04:00
ndr - > data = talloc_realloc ( ndr , ndr - > data , ndr - > alloc_size ) ;
2003-11-03 09:22:45 +03:00
if ( ! ndr - > data ) {
2003-11-22 11:11:32 +03:00
return ndr_push_error ( ndr , NDR_ERR_ALLOC , " Failed to push_expand to %u " ,
ndr - > alloc_size ) ;
2003-11-03 09:22:45 +03:00
}
return NT_STATUS_OK ;
}
/*
set the push offset to ' ofs '
*/
2004-05-25 20:24:13 +04:00
NTSTATUS ndr_push_set_offset ( struct ndr_push * ndr , uint32_t ofs )
2003-11-03 09:22:45 +03:00
{
NDR_CHECK ( ndr_push_expand ( ndr , ofs ) ) ;
ndr - > offset = ofs ;
return NT_STATUS_OK ;
}
2003-11-08 14:21:57 +03:00
/*
push a generic array
*/
2003-11-13 12:26:53 +03:00
NTSTATUS ndr_push_array ( struct ndr_push * ndr , int ndr_flags , void * base ,
2004-05-25 20:24:13 +04:00
size_t elsize , uint32_t count ,
2003-11-16 16:49:14 +03:00
NTSTATUS ( * push_fn ) ( struct ndr_push * , int , void * ) )
2003-11-08 14:21:57 +03:00
{
int i ;
char * p = base ;
2003-11-09 03:58:40 +03:00
if ( ! ( ndr_flags & NDR_SCALARS ) ) goto buffers ;
2003-11-08 14:21:57 +03:00
for ( i = 0 ; i < count ; i + + ) {
2003-11-09 03:58:40 +03:00
NDR_CHECK ( push_fn ( ndr , NDR_SCALARS , p ) ) ;
2003-11-08 14:21:57 +03:00
p + = elsize ;
}
2003-11-09 03:58:40 +03: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 14:21:57 +03:00
return NT_STATUS_OK ;
}
2003-11-12 08:34:21 +03:00
/*
pull a constant sized array
*/
2003-11-13 12:26:53 +03:00
NTSTATUS ndr_pull_array ( struct ndr_pull * ndr , int ndr_flags , void * base ,
2004-05-25 20:24:13 +04:00
size_t elsize , uint32_t count ,
2003-11-13 12:26:53 +03:00
NTSTATUS ( * pull_fn ) ( struct ndr_pull * , int , void * ) )
2003-11-08 14:21:57 +03:00
{
int i ;
char * p ;
2003-11-09 10:24:06 +03:00
p = base ;
2003-11-08 14:21:57 +03: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 10:24:06 +03:00
p = base ;
2003-11-08 14:21:57 +03: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 07:04:36 +03:00
2004-10-18 16:18:54 +04:00
/*
pull a constant size array of structures
*/
NTSTATUS ndr_pull_struct_array ( struct ndr_pull * ndr , uint32_t count ,
size_t elsize , void * * info ,
NTSTATUS ( * pull_fn ) ( struct ndr_pull * , int , void * ) )
{
int i ;
char * base ;
NDR_ALLOC_N_SIZE ( ndr , * info , count , elsize ) ;
base = ( char * ) * info ;
for ( i = 0 ; i < count ; i + + ) {
ndr - > data + = ndr - > offset ;
ndr - > offset = 0 ;
NDR_CHECK ( pull_fn ( ndr , NDR_SCALARS | NDR_BUFFERS , & base [ count * elsize ] ) ) ;
}
return NT_STATUS_OK ;
}
2003-11-11 07:04:36 +03:00
/*
print a generic array
*/
void ndr_print_array ( struct ndr_print * ndr , const char * name , void * base ,
2004-05-25 20:24:13 +04:00
size_t elsize , uint32_t count ,
2003-11-11 07:04:36 +03:00
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 - - ;
}
2004-08-25 11:15:21 +04:00
void ndr_print_debug_helper ( struct ndr_print * ndr , const char * format , . . . ) _PRINTF_ATTRIBUTE ( 2 , 3 )
2003-11-11 07:04:36 +03: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 05:50:40 +03:00
DEBUG ( 0 , ( " " ) ) ;
2003-11-11 07:04:36 +03:00
}
2003-11-21 05:50:40 +03:00
DEBUG ( 0 , ( " %s \n " , s ) ) ;
2003-11-11 07:04:36 +03:00
free ( s ) ;
}
/*
a useful helper function for printing idl structures via DEBUG ( )
*/
2004-11-05 10:29:02 +03:00
void ndr_print_debug ( ndr_print_fn_t fn , const char * name , void * ptr )
2003-11-11 07:04:36 +03:00
{
2004-08-21 11:43:29 +04:00
struct ndr_print * ndr ;
2003-11-11 07:04:36 +03:00
2004-08-21 11:43:29 +04:00
ndr = talloc_p ( NULL , struct ndr_print ) ;
if ( ! ndr ) return ;
ndr - > print = ndr_print_debug_helper ;
ndr - > depth = 1 ;
ndr - > flags = 0 ;
fn ( ndr , name , ptr ) ;
talloc_free ( ndr ) ;
2003-11-11 07:04:36 +03:00
}
2003-11-11 07:38:51 +03:00
2003-11-21 05:50:40 +03:00
2003-11-11 07:38:51 +03:00
/*
a useful helper function for printing idl unions via DEBUG ( )
*/
2004-11-05 10:29:02 +03:00
void ndr_print_union_debug ( ndr_print_union_fn_t fn , const char * name , uint32_t level , void * ptr )
2003-11-11 07:38:51 +03:00
{
2004-08-21 11:43:29 +04:00
struct ndr_print * ndr ;
2003-11-11 07:38:51 +03:00
2004-08-21 11:43:29 +04:00
ndr = talloc_p ( NULL , struct ndr_print ) ;
if ( ! ndr ) return ;
ndr - > print = ndr_print_debug_helper ;
ndr - > depth = 1 ;
ndr - > flags = 0 ;
fn ( ndr , name , level , ptr ) ;
talloc_free ( ndr ) ;
2003-11-11 07:38:51 +03:00
}
2003-11-13 12:26:53 +03:00
2003-11-17 14:55:56 +03:00
/*
a useful helper function for printing idl function calls via DEBUG ( )
*/
2004-11-05 10:29:02 +03:00
void ndr_print_function_debug ( ndr_print_function_t fn , const char * name , int flags , void * ptr )
2003-11-17 14:55:56 +03:00
{
2004-08-21 11:43:29 +04:00
struct ndr_print * ndr ;
2003-11-17 14:55:56 +03:00
2004-08-21 11:43:29 +04:00
ndr = talloc_p ( NULL , struct ndr_print ) ;
if ( ! ndr ) return ;
ndr - > print = ndr_print_debug_helper ;
ndr - > depth = 1 ;
ndr - > flags = 0 ;
fn ( ndr , name , flags , ptr ) ;
talloc_free ( ndr ) ;
2003-11-17 14:55:56 +03:00
}
2004-10-14 13:07:41 +04:00
void ndr_set_flags ( uint32_t * pflags , uint32_t new_flags )
{
/* the big/little endian flags are inter-dependent */
if ( new_flags & LIBNDR_FLAG_LITTLE_ENDIAN ) {
( * pflags ) & = ~ LIBNDR_FLAG_BIGENDIAN ;
}
if ( new_flags & LIBNDR_FLAG_BIGENDIAN ) {
( * pflags ) & = ~ LIBNDR_FLAG_LITTLE_ENDIAN ;
}
( * pflags ) | = new_flags ;
}
2003-11-22 11:11:32 +03:00
static NTSTATUS ndr_map_error ( enum ndr_err_code err )
{
switch ( err ) {
case NDR_ERR_BUFSIZE :
return NT_STATUS_BUFFER_TOO_SMALL ;
2004-12-09 10:05:00 +03:00
case NDR_ERR_TOKEN :
return NT_STATUS_INTERNAL_ERROR ;
2003-11-22 11:11:32 +03:00
case NDR_ERR_ALLOC :
return NT_STATUS_NO_MEMORY ;
2004-12-09 10:05:00 +03:00
case NDR_ERR_ARRAY_SIZE :
return NT_STATUS_ARRAY_BOUNDS_EXCEEDED ;
2004-10-28 16:46:59 +04:00
default :
break ;
2003-11-22 11:11:32 +03:00
}
/* we should all error codes to different status codes */
return NT_STATUS_INVALID_PARAMETER ;
}
2003-11-13 12:26:53 +03:00
/*
return and possibly log an NDR error
*/
2004-06-14 11:25:38 +04:00
NTSTATUS ndr_pull_error ( struct ndr_pull * ndr ,
enum ndr_err_code err , const char * format , . . . ) _PRINTF_ATTRIBUTE ( 3 , 4 )
2003-11-13 12:26:53 +03:00
{
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 11:11:32 +03:00
return ndr_map_error ( err ) ;
2003-11-13 12:26:53 +03:00
}
2003-11-14 10:20:46 +03:00
/*
return and possibly log an NDR error
*/
2004-08-25 11:15:21 +04:00
NTSTATUS ndr_push_error ( struct ndr_push * ndr , enum ndr_err_code err , const char * format , . . . ) _PRINTF_ATTRIBUTE ( 3 , 4 )
2003-11-14 10:20:46 +03:00
{
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 11:11:32 +03:00
return ndr_map_error ( err ) ;
2003-11-14 10:20:46 +03:00
}
2003-11-16 09:00:15 +03:00
2003-11-21 16:14:17 +03: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 : {
2004-05-25 20:24:13 +04:00
uint32_t size = ndr - > data_size - ndr - > offset ;
2003-11-21 16:14:17 +03:00
if ( size = = 0 ) return NT_STATUS_OK ;
NDR_CHECK ( ndr_pull_subcontext ( ndr , ndr2 , size ) ) ;
break ;
}
case 2 : {
2004-05-25 21:24:24 +04:00
uint16_t size ;
2003-11-21 16:14:17 +03:00
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 : {
2004-05-25 20:24:13 +04:00
uint32_t size ;
2003-11-21 16:14:17 +03:00
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 09:00:15 +03:00
/*
handle subcontext buffers , which in midl land are user - marshalled , but
we use magic in pidl to make them easier to cope with
*/
2004-11-05 10:29:02 +03:00
NTSTATUS ndr_pull_subcontext_fn ( struct ndr_pull * ndr , size_t sub_size ,
void * base , ndr_pull_fn_t fn )
2003-11-16 09:00:15 +03:00
{
2004-08-21 11:43:29 +04:00
struct ndr_pull * ndr2 ;
NDR_ALLOC ( ndr , ndr2 ) ;
NDR_CHECK ( ndr_pull_subcontext_header ( ndr , sub_size , ndr2 ) ) ;
NDR_CHECK ( fn ( ndr2 , base ) ) ;
2003-11-21 16:14:17 +03:00
if ( sub_size ) {
2004-08-21 11:43:29 +04:00
NDR_CHECK ( ndr_pull_advance ( ndr , ndr2 - > data_size ) ) ;
2003-11-21 16:14:17 +03:00
} else {
2004-08-21 11:43:29 +04:00
NDR_CHECK ( ndr_pull_advance ( ndr , ndr2 - > offset ) ) ;
2003-11-21 16:14:17 +03:00
}
2003-11-16 09:00:15 +03:00
return NT_STATUS_OK ;
}
2004-11-05 10:29:02 +03:00
NTSTATUS ndr_pull_subcontext_flags_fn ( struct ndr_pull * ndr , size_t sub_size ,
void * base , ndr_pull_flags_fn_t fn )
2003-11-16 09:00:15 +03:00
{
2004-08-21 11:43:29 +04:00
struct ndr_pull * ndr2 ;
NDR_ALLOC ( ndr , ndr2 ) ;
NDR_CHECK ( ndr_pull_subcontext_header ( ndr , sub_size , ndr2 ) ) ;
NDR_CHECK ( fn ( ndr2 , NDR_SCALARS | NDR_BUFFERS , base ) ) ;
2003-11-21 16:14:17 +03:00
if ( sub_size ) {
2004-08-21 11:43:29 +04:00
NDR_CHECK ( ndr_pull_advance ( ndr , ndr2 - > data_size ) ) ;
2003-11-21 16:14:17 +03:00
} else {
2004-08-21 11:43:29 +04:00
NDR_CHECK ( ndr_pull_advance ( ndr , ndr2 - > offset ) ) ;
2003-11-21 16:14:17 +03:00
}
2003-11-16 09:00:15 +03:00
return NT_STATUS_OK ;
}
2004-11-05 10:29:02 +03:00
NTSTATUS ndr_pull_subcontext_union_fn ( struct ndr_pull * ndr , size_t sub_size ,
uint32_t level , void * base , ndr_pull_union_fn_t fn )
2003-11-16 14:36:59 +03:00
{
2004-08-21 11:43:29 +04:00
struct ndr_pull * ndr2 ;
2003-11-16 14:36:59 +03:00
2004-08-21 11:43:29 +04:00
NDR_ALLOC ( ndr , ndr2 ) ;
NDR_CHECK ( ndr_pull_subcontext_header ( ndr , sub_size , ndr2 ) ) ;
NDR_CHECK ( fn ( ndr2 , NDR_SCALARS | NDR_BUFFERS , level , base ) ) ;
2003-11-21 16:14:17 +03:00
if ( sub_size ) {
2004-08-21 11:43:29 +04:00
NDR_CHECK ( ndr_pull_advance ( ndr , ndr2 - > data_size ) ) ;
2003-11-21 16:14:17 +03:00
} else {
2004-08-21 11:43:29 +04:00
NDR_CHECK ( ndr_pull_advance ( ndr , ndr2 - > offset ) ) ;
2003-11-21 16:14:17 +03:00
}
2003-11-16 14:36:59 +03:00
return NT_STATUS_OK ;
}
2003-11-16 16:49:14 +03:00
2003-11-22 11:11:32 +03: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
*/
2004-11-05 10:29:02 +03:00
NTSTATUS ndr_push_subcontext_fn ( struct ndr_push * ndr , size_t sub_size ,
void * base , ndr_push_fn_t fn )
2003-11-22 11:11:32 +03:00
{
struct ndr_push * ndr2 ;
2004-08-21 11:43:29 +04:00
ndr2 = ndr_push_init_ctx ( ndr ) ;
2003-11-22 11:11:32 +03:00
if ( ! ndr2 ) return NT_STATUS_NO_MEMORY ;
2003-11-22 12:32:35 +03:00
ndr2 - > flags = ndr - > flags ;
2003-11-22 11:11:32 +03: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
*/
2004-11-05 10:29:02 +03:00
NTSTATUS ndr_push_subcontext_flags_fn ( struct ndr_push * ndr , size_t sub_size ,
void * base , ndr_push_flags_fn_t fn )
2003-11-22 11:11:32 +03:00
{
struct ndr_push * ndr2 ;
2004-08-21 11:43:29 +04:00
ndr2 = ndr_push_init_ctx ( ndr ) ;
2003-11-22 11:11:32 +03:00
if ( ! ndr2 ) return NT_STATUS_NO_MEMORY ;
2003-11-22 12:32:35 +03:00
ndr2 - > flags = ndr - > flags ;
2003-11-22 11:11:32 +03: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
*/
2004-11-05 10:29:02 +03:00
NTSTATUS ndr_push_subcontext_union_fn ( struct ndr_push * ndr , size_t sub_size ,
uint32_t level , void * base , ndr_push_union_fn_t fn )
2003-11-22 11:11:32 +03:00
{
struct ndr_push * ndr2 ;
2004-08-21 11:43:29 +04:00
ndr2 = ndr_push_init_ctx ( ndr ) ;
2003-11-22 11:11:32 +03:00
if ( ! ndr2 ) return NT_STATUS_NO_MEMORY ;
2003-11-22 12:32:35 +03:00
ndr2 - > flags = ndr - > flags ;
2003-11-22 11:11:32 +03: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 05:18:11 +03:00
/*
mark the start of a structure
*/
NTSTATUS ndr_pull_struct_start ( struct ndr_pull * ndr )
{
return NT_STATUS_OK ;
}
/*
mark the end of a structure
*/
void ndr_pull_struct_end ( struct ndr_pull * ndr )
{
}
/*
mark the start of a structure
*/
NTSTATUS ndr_push_struct_start ( struct ndr_push * ndr )
{
return NT_STATUS_OK ;
}
/*
mark the end of a structure
*/
void ndr_push_struct_end ( struct ndr_push * ndr )
{
}
2004-08-12 09:15:41 +04:00
/*
store a token in the ndr context , for later retrieval
*/
static NTSTATUS ndr_token_store ( TALLOC_CTX * mem_ctx ,
struct ndr_token_list * * list ,
const void * key ,
uint32_t value )
{
struct ndr_token_list * tok ;
tok = talloc_p ( mem_ctx , struct ndr_token_list ) ;
if ( tok = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
tok - > key = key ;
tok - > value = value ;
DLIST_ADD ( ( * list ) , tok ) ;
return NT_STATUS_OK ;
}
2003-11-16 16:49:14 +03:00
/*
2004-08-12 09:15:41 +04:00
retrieve a token from a ndr context
2003-11-16 16:49:14 +03:00
*/
2004-12-09 10:05:00 +03:00
static NTSTATUS ndr_token_retrieve ( struct ndr_token_list * * list , const void * key , uint32_t * v )
2003-11-16 16:49:14 +03:00
{
2004-08-12 09:15:41 +04:00
struct ndr_token_list * tok ;
for ( tok = * list ; tok ; tok = tok - > next ) {
if ( tok - > key = = key ) {
DLIST_REMOVE ( ( * list ) , tok ) ;
2004-12-09 10:05:00 +03:00
* v = tok - > value ;
return NT_STATUS_OK ;
}
}
return ndr_map_error ( NDR_ERR_TOKEN ) ;
}
/*
peek at but don ' t removed a token from a ndr context
*/
static uint32_t ndr_token_peek ( struct ndr_token_list * * list , const void * key )
{
struct ndr_token_list * tok ;
for ( tok = * list ; tok ; tok = tok - > next ) {
if ( tok - > key = = key ) {
2004-08-12 09:15:41 +04:00
return tok - > value ;
2003-11-16 16:49:14 +03:00
}
}
2004-08-12 09:15:41 +04:00
return 0 ;
}
2004-12-09 10:05:00 +03:00
/*
pull an array size field and add it to the array_size_list token list
*/
NTSTATUS ndr_pull_array_size ( struct ndr_pull * ndr , const void * p )
{
uint32_t size ;
NDR_CHECK ( ndr_pull_uint32 ( ndr , & size ) ) ;
return ndr_token_store ( ndr , & ndr - > array_size_list , p , size ) ;
}
/*
get the stored array size field
*/
uint32_t ndr_get_array_size ( struct ndr_pull * ndr , const void * p )
{
return ndr_token_peek ( & ndr - > array_size_list , p ) ;
}
/*
check the stored array size field
*/
2004-12-11 01:36:46 +03:00
NTSTATUS ndr_check_array_size ( struct ndr_pull * ndr , void * p , uint32_t size )
2004-12-09 10:05:00 +03:00
{
2004-12-11 01:36:46 +03:00
uint32_t stored ;
2004-12-09 10:05:00 +03:00
NDR_CHECK ( ndr_token_retrieve ( & ndr - > array_size_list , p , & stored ) ) ;
if ( stored ! = size ) {
return ndr_pull_error ( ndr , NDR_ERR_ARRAY_SIZE ,
" Bad array size - got %u expected %u \n " ,
stored , size ) ;
}
return NT_STATUS_OK ;
}
/*
pull an array length field and add it to the array_length_list token list
*/
NTSTATUS ndr_pull_array_length ( struct ndr_pull * ndr , const void * p )
{
uint32_t length , offset ;
NDR_CHECK ( ndr_pull_uint32 ( ndr , & offset ) ) ;
if ( offset ! = 0 ) {
return ndr_pull_error ( ndr , NDR_ERR_ARRAY_SIZE ,
" non-zero array offset %u \n " , offset ) ;
}
NDR_CHECK ( ndr_pull_uint32 ( ndr , & length ) ) ;
return ndr_token_store ( ndr , & ndr - > array_length_list , p , length ) ;
}
/*
get the stored array length field
*/
uint32_t ndr_get_array_length ( struct ndr_pull * ndr , const void * p )
{
return ndr_token_peek ( & ndr - > array_length_list , p ) ;
}
/*
check the stored array length field
*/
NTSTATUS ndr_check_array_length ( struct ndr_pull * ndr , void * p , uint32_t length )
{
uint32_t stored ;
NDR_CHECK ( ndr_token_retrieve ( & ndr - > array_length_list , p , & stored ) ) ;
if ( stored ! = length ) {
return ndr_pull_error ( ndr , NDR_ERR_ARRAY_SIZE ,
" Bad array length - got %u expected %u \n " ,
stored , length ) ;
}
return NT_STATUS_OK ;
}
2004-08-12 09:15:41 +04:00
/*
pull a relative object - stage1
called during SCALARS processing
*/
NTSTATUS ndr_pull_relative1 ( struct ndr_pull * ndr , const void * p , uint32_t rel_offset )
{
2004-09-03 16:58:19 +04:00
if ( ndr - > flags & LIBNDR_FLAG_RELATIVE_CURRENT ) {
return ndr_token_store ( ndr , & ndr - > relative_list , p ,
2004-09-03 17:21:52 +04:00
rel_offset + ndr - > offset - 4 ) ;
2004-09-03 16:58:19 +04:00
} else {
return ndr_token_store ( ndr , & ndr - > relative_list , p , rel_offset ) ;
}
2004-08-12 09:15:41 +04:00
}
/*
pull a relative object - stage2
called during BUFFERS processing
*/
NTSTATUS ndr_pull_relative2 ( struct ndr_pull * ndr , const void * p )
{
uint32_t rel_offset ;
2004-12-09 10:05:00 +03:00
NDR_CHECK ( ndr_token_retrieve ( & ndr - > relative_list , p , & rel_offset ) ) ;
2004-08-12 09:15:41 +04:00
return ndr_pull_set_offset ( ndr , rel_offset ) ;
}
/*
push a relative object - stage1
this is called during SCALARS processing
*/
NTSTATUS ndr_push_relative1 ( struct ndr_push * ndr , const void * p )
{
if ( p = = NULL ) {
NDR_CHECK ( ndr_push_uint32 ( ndr , 0 ) ) ;
return NT_STATUS_OK ;
}
NDR_CHECK ( ndr_push_align ( ndr , 4 ) ) ;
2004-08-21 11:43:29 +04:00
NDR_CHECK ( ndr_token_store ( ndr , & ndr - > relative_list , p , ndr - > offset ) ) ;
2004-08-12 09:15:41 +04:00
return ndr_push_uint32 ( ndr , 0xFFFFFFFF ) ;
}
/*
push a relative object - stage2
this is called during buffers processing
*/
NTSTATUS ndr_push_relative2 ( struct ndr_push * ndr , const void * p )
{
struct ndr_push_save save ;
if ( p = = NULL ) {
return NT_STATUS_OK ;
}
NDR_CHECK ( ndr_push_align ( ndr , 4 ) ) ;
ndr_push_save ( ndr , & save ) ;
2004-12-09 10:05:00 +03:00
NDR_CHECK ( ndr_token_retrieve ( & ndr - > relative_list , p , & ndr - > offset ) ) ;
2004-09-03 16:10:34 +04:00
if ( ndr - > flags & LIBNDR_FLAG_RELATIVE_CURRENT ) {
NDR_CHECK ( ndr_push_uint32 ( ndr , save . offset - ndr - > offset ) ) ;
} else {
NDR_CHECK ( ndr_push_uint32 ( ndr , save . offset ) ) ;
}
2004-08-12 09:15:41 +04:00
ndr_push_restore ( ndr , & save ) ;
2003-11-16 16:49:14 +03:00
return NT_STATUS_OK ;
}
2003-11-17 07:56:59 +03:00
/*
pull a union from a blob using NDR
*/
2004-05-25 20:24:13 +04:00
NTSTATUS ndr_pull_union_blob ( DATA_BLOB * blob , TALLOC_CTX * mem_ctx , uint32_t level , void * p ,
2004-11-05 10:29:02 +03:00
ndr_pull_union_fn_t fn )
2003-11-17 07:56:59 +03:00
{
struct ndr_pull * ndr ;
ndr = ndr_pull_init_blob ( blob , mem_ctx ) ;
if ( ! ndr ) {
return NT_STATUS_NO_MEMORY ;
}
2003-11-20 01:10:20 +03:00
return fn ( ndr , NDR_SCALARS | NDR_BUFFERS , level , p ) ;
2003-11-17 07:56:59 +03:00
}
/*
pull a struct from a blob using NDR
*/
r1294: A nice, large, commit...
This implements gensec for Samba's server side, and brings gensec up
to the standards of a full subsystem.
This means that use of the subsystem is by gensec_* functions, not
function pointers in structures (this is internal). This causes
changes in all the existing gensec users.
Our RPC server no longer contains it's own generalised security
scheme, and now calls gensec directly.
Gensec has also taken over the role of auth/auth_ntlmssp.c
An important part of gensec, is the output of the 'session_info'
struct. This is now reference counted, so that we can correctly free
it when a pipe is closed, no matter if it was inherited, or created by
per-pipe authentication.
The schannel code is reworked, to be in the same file for client and
server.
ntlm_auth is reworked to use gensec.
The major problem with this code is the way it relies on subsystem
auto-initialisation. The primary reason for this commit now.is to
allow these problems to be looked at, and fixed.
There are problems with the new code:
- I've tested it with smbtorture, but currently don't have VMware and
valgrind working (this I'll fix soon).
- The SPNEGO code is client-only at this point.
- We still do not do kerberos.
Andrew Bartlett
(This used to be commit 07fd885fd488fd1051eacc905a2d4962f8a018ec)
2004-06-29 13:40:10 +04:00
NTSTATUS ndr_pull_struct_blob ( const DATA_BLOB * blob , TALLOC_CTX * mem_ctx , void * p ,
2004-11-05 10:29:02 +03:00
ndr_pull_flags_fn_t fn )
2003-11-17 07:56:59 +03: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 04:24:29 +03:00
2003-11-26 04:16:41 +03:00
/*
push a struct to a blob using NDR
*/
NTSTATUS ndr_push_struct_blob ( DATA_BLOB * blob , TALLOC_CTX * mem_ctx , void * p ,
2004-11-05 10:29:02 +03:00
ndr_push_flags_fn_t fn )
2003-11-26 04:16:41 +03:00
{
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 04:24:29 +03:00
2003-11-26 04:16:41 +03:00
* blob = ndr_push_blob ( ndr ) ;
return NT_STATUS_OK ;
}