2004-07-12 20:35:48 +04:00
/*
Unix SMB / CIFS implementation .
RAP handlers
Copyright ( C ) Volker Lendecke 2004
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
2004-07-12 20:35:48 +04: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/>.
2004-07-12 20:35:48 +04:00
*/
# include "includes.h"
2006-08-30 15:29:34 +04:00
# include "libcli/raw/interfaces.h"
2006-02-23 14:29:01 +03:00
# include "libcli/rap/rap.h"
2008-04-17 14:23:44 +04:00
# include "events/events.h"
2006-03-07 02:28:18 +03:00
# include "ntvfs/ipc/proto.h"
2006-03-18 18:42:57 +03:00
# include "librpc/ndr/libndr.h"
2007-12-14 00:46:23 +03:00
# include "param/param.h"
2004-07-12 20:35:48 +04:00
2007-11-09 21:24:51 +03:00
# define NDR_RETURN(call) do { \
enum ndr_err_code _ndr_err ; \
_ndr_err = call ; \
if ( ! NDR_ERR_CODE_IS_SUCCESS ( _ndr_err ) ) { \
return ndr_map_error2ntstatus ( _ndr_err ) ; \
} \
} while ( 0 )
# define RAP_GOTO(call) do { \
result = call ; \
if ( NT_STATUS_EQUAL ( result , NT_STATUS_BUFFER_TOO_SMALL ) ) { \
goto buffer_overflow ; \
} \
if ( ! NT_STATUS_IS_OK ( result ) ) { \
goto done ; \
} \
} while ( 0 )
# define NDR_GOTO(call) do { \
enum ndr_err_code _ndr_err ; \
_ndr_err = call ; \
if ( ! NDR_ERR_CODE_IS_SUCCESS ( _ndr_err ) ) { \
RAP_GOTO ( ndr_map_error2ntstatus ( _ndr_err ) ) ; \
} \
} while ( 0 )
2004-07-12 20:35:48 +04:00
# define NERR_notsupported 50
struct rap_string_heap {
TALLOC_CTX * mem_ctx ;
int offset ;
int num_strings ;
const char * * strings ;
} ;
struct rap_heap_save {
int offset , num_strings ;
} ;
static void rap_heap_save ( struct rap_string_heap * heap ,
struct rap_heap_save * save )
{
save - > offset = heap - > offset ;
save - > num_strings = heap - > num_strings ;
}
static void rap_heap_restore ( struct rap_string_heap * heap ,
struct rap_heap_save * save )
{
heap - > offset = save - > offset ;
heap - > num_strings = save - > num_strings ;
}
struct rap_call {
2008-01-06 04:03:43 +03:00
struct loadparm_context * lp_ctx ;
2004-07-12 20:35:48 +04:00
TALLOC_CTX * mem_ctx ;
2005-02-10 08:09:35 +03:00
uint16_t callno ;
2004-07-12 20:35:48 +04:00
const char * paramdesc ;
const char * datadesc ;
2005-02-10 08:09:35 +03:00
uint16_t status ;
uint16_t convert ;
2004-07-12 20:35:48 +04:00
2005-02-10 08:09:35 +03:00
uint16_t rcv_paramlen , rcv_datalen ;
2004-07-12 20:35:48 +04:00
struct ndr_push * ndr_push_param ;
struct ndr_push * ndr_push_data ;
struct rap_string_heap * heap ;
struct ndr_pull * ndr_pull_param ;
struct ndr_pull * ndr_pull_data ;
2008-04-17 14:23:44 +04:00
2008-12-29 22:24:57 +03:00
struct tevent_context * event_ctx ;
2004-07-12 20:35:48 +04:00
} ;
# define RAPNDR_FLAGS (LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
static struct rap_call * new_rap_srv_call ( TALLOC_CTX * mem_ctx ,
2008-12-29 22:24:57 +03:00
struct tevent_context * ev_ctx ,
2008-01-06 04:03:43 +03:00
struct loadparm_context * lp_ctx ,
2004-07-12 20:35:48 +04:00
struct smb_trans2 * trans )
{
struct rap_call * call ;
2005-01-27 10:08:20 +03:00
call = talloc ( mem_ctx , struct rap_call ) ;
2004-07-12 20:35:48 +04:00
if ( call = = NULL )
return NULL ;
ZERO_STRUCTP ( call ) ;
2008-01-06 04:03:43 +03:00
call - > lp_ctx = talloc_reference ( call , lp_ctx ) ;
2008-04-17 14:23:44 +04:00
call - > event_ctx = ev_ctx ;
2008-01-06 04:03:43 +03:00
2004-07-12 20:35:48 +04:00
call - > mem_ctx = mem_ctx ;
2008-01-06 04:03:43 +03:00
call - > ndr_pull_param = ndr_pull_init_blob ( & trans - > in . params , mem_ctx , lp_iconv_convenience ( lp_ctx ) ) ;
2004-07-12 20:35:48 +04:00
call - > ndr_pull_param - > flags = RAPNDR_FLAGS ;
2008-01-06 04:03:43 +03:00
call - > ndr_pull_data = ndr_pull_init_blob ( & trans - > in . data , mem_ctx , lp_iconv_convenience ( lp_ctx ) ) ;
2004-07-12 20:35:48 +04:00
call - > ndr_pull_data - > flags = RAPNDR_FLAGS ;
2005-01-27 10:08:20 +03:00
call - > heap = talloc ( mem_ctx , struct rap_string_heap ) ;
2004-07-12 20:35:48 +04:00
if ( call - > heap = = NULL )
return NULL ;
ZERO_STRUCTP ( call - > heap ) ;
call - > heap - > mem_ctx = mem_ctx ;
return call ;
}
2005-02-10 08:09:35 +03:00
static NTSTATUS rap_srv_pull_word ( struct rap_call * call , uint16_t * result )
2004-07-12 20:35:48 +04:00
{
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2004-07-12 20:35:48 +04:00
if ( * call - > paramdesc + + ! = ' W ' )
return NT_STATUS_INVALID_PARAMETER ;
2007-11-09 21:24:51 +03:00
ndr_err = ndr_pull_uint16 ( call - > ndr_pull_param , NDR_SCALARS , result ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return ndr_map_error2ntstatus ( ndr_err ) ;
}
return NT_STATUS_OK ;
2004-07-12 20:35:48 +04:00
}
2005-02-10 08:09:35 +03:00
static NTSTATUS rap_srv_pull_dword ( struct rap_call * call , uint32_t * result )
2004-07-12 20:35:48 +04:00
{
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2004-07-12 20:35:48 +04:00
if ( * call - > paramdesc + + ! = ' D ' )
return NT_STATUS_INVALID_PARAMETER ;
2007-11-09 21:24:51 +03:00
ndr_err = ndr_pull_uint32 ( call - > ndr_pull_param , NDR_SCALARS , result ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return ndr_map_error2ntstatus ( ndr_err ) ;
}
return NT_STATUS_OK ;
2004-07-12 20:35:48 +04:00
}
static NTSTATUS rap_srv_pull_string ( struct rap_call * call , const char * * result )
{
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2004-07-12 20:35:48 +04:00
char paramdesc = * call - > paramdesc + + ;
if ( paramdesc = = ' O ' ) {
* result = NULL ;
return NT_STATUS_OK ;
}
if ( paramdesc ! = ' z ' )
return NT_STATUS_INVALID_PARAMETER ;
2007-11-09 21:24:51 +03:00
ndr_err = ndr_pull_string ( call - > ndr_pull_param , NDR_SCALARS , result ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return ndr_map_error2ntstatus ( ndr_err ) ;
}
return NT_STATUS_OK ;
2004-07-12 20:35:48 +04:00
}
2005-02-10 08:09:35 +03:00
static NTSTATUS rap_srv_pull_bufsize ( struct rap_call * call , uint16_t * bufsize )
2004-07-12 20:35:48 +04:00
{
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2004-07-12 20:35:48 +04:00
if ( ( * call - > paramdesc + + ! = ' r ' ) | | ( * call - > paramdesc + + ! = ' L ' ) )
return NT_STATUS_INVALID_PARAMETER ;
2007-11-09 21:24:51 +03:00
ndr_err = ndr_pull_uint16 ( call - > ndr_pull_param , NDR_SCALARS , bufsize ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return ndr_map_error2ntstatus ( ndr_err ) ;
}
2004-07-12 20:35:48 +04:00
call - > heap - > offset = * bufsize ;
return NT_STATUS_OK ;
}
static NTSTATUS rap_srv_pull_expect_multiple ( struct rap_call * call )
{
if ( ( * call - > paramdesc + + ! = ' e ' ) | | ( * call - > paramdesc + + ! = ' h ' ) )
return NT_STATUS_INVALID_PARAMETER ;
return NT_STATUS_OK ;
}
static NTSTATUS rap_push_string ( struct ndr_push * data_push ,
struct rap_string_heap * heap ,
const char * str )
{
size_t space ;
if ( str = = NULL )
str = " " ;
space = strlen ( str ) + 1 ;
if ( heap - > offset < space )
return NT_STATUS_BUFFER_TOO_SMALL ;
heap - > offset - = space ;
2007-11-09 21:24:51 +03:00
NDR_RETURN ( ndr_push_uint16 ( data_push , NDR_SCALARS , heap - > offset ) ) ;
NDR_RETURN ( ndr_push_uint16 ( data_push , NDR_SCALARS , 0 ) ) ;
2004-07-12 20:35:48 +04:00
2005-01-27 10:08:20 +03:00
heap - > strings = talloc_realloc ( heap - > mem_ctx ,
2004-09-27 05:36:19 +04:00
heap - > strings ,
const char * ,
heap - > num_strings + 1 ) ;
2004-07-12 20:35:48 +04:00
if ( heap - > strings = = NULL )
return NT_STATUS_NO_MEMORY ;
heap - > strings [ heap - > num_strings ] = str ;
heap - > num_strings + = 1 ;
return NT_STATUS_OK ;
}
2006-03-10 17:31:17 +03:00
static NTSTATUS _rap_netshareenum ( struct rap_call * call )
2004-07-12 20:35:48 +04:00
{
struct rap_NetShareEnum r ;
NTSTATUS result ;
2007-11-09 21:24:51 +03:00
RAP_GOTO ( rap_srv_pull_word ( call , & r . in . level ) ) ;
RAP_GOTO ( rap_srv_pull_bufsize ( call , & r . in . bufsize ) ) ;
RAP_GOTO ( rap_srv_pull_expect_multiple ( call ) ) ;
2004-07-12 20:35:48 +04:00
switch ( r . in . level ) {
case 0 :
if ( strcmp ( call - > datadesc , " B13 " ) ! = 0 )
return NT_STATUS_INVALID_PARAMETER ;
break ;
case 1 :
if ( strcmp ( call - > datadesc , " B13BWz " ) ! = 0 )
return NT_STATUS_INVALID_PARAMETER ;
break ;
default :
return NT_STATUS_INVALID_PARAMETER ;
break ;
}
2008-04-17 14:23:44 +04:00
result = rap_netshareenum ( call , call - > event_ctx , call - > lp_ctx , & r ) ;
2004-07-12 20:35:48 +04:00
if ( ! NT_STATUS_IS_OK ( result ) )
return result ;
for ( r . out . count = 0 ; r . out . count < r . out . available ; r . out . count + + ) {
int i = r . out . count ;
2007-11-20 13:08:24 +03:00
uint32_t offset_save ;
2004-07-12 20:35:48 +04:00
struct rap_heap_save heap_save ;
2007-11-20 13:08:24 +03:00
offset_save = call - > ndr_push_data - > offset ;
2004-07-12 20:35:48 +04:00
rap_heap_save ( call - > heap , & heap_save ) ;
switch ( r . in . level ) {
case 0 :
2007-11-09 21:24:51 +03:00
NDR_GOTO ( ndr_push_bytes ( call - > ndr_push_data ,
2004-11-25 21:25:22 +03:00
( const uint8_t * ) r . out . info [ i ] . info0 . name ,
2004-07-12 20:35:48 +04:00
sizeof ( r . out . info [ i ] . info0 . name ) ) ) ;
break ;
case 1 :
2007-11-09 21:24:51 +03:00
NDR_GOTO ( ndr_push_bytes ( call - > ndr_push_data ,
2004-11-25 21:25:22 +03:00
( const uint8_t * ) r . out . info [ i ] . info1 . name ,
2004-07-12 20:35:48 +04:00
sizeof ( r . out . info [ i ] . info1 . name ) ) ) ;
2007-11-09 21:24:51 +03:00
NDR_GOTO ( ndr_push_uint8 ( call - > ndr_push_data ,
2005-02-10 00:10:23 +03:00
NDR_SCALARS , r . out . info [ i ] . info1 . pad ) ) ;
2007-11-09 21:24:51 +03:00
NDR_GOTO ( ndr_push_uint16 ( call - > ndr_push_data ,
2005-02-10 00:10:23 +03:00
NDR_SCALARS , r . out . info [ i ] . info1 . type ) ) ;
2004-07-12 20:35:48 +04:00
2007-11-09 21:24:51 +03:00
RAP_GOTO ( rap_push_string ( call - > ndr_push_data ,
2004-07-12 20:35:48 +04:00
call - > heap ,
r . out . info [ i ] . info1 . comment ) ) ;
break ;
}
if ( call - > ndr_push_data - > offset > call - > heap - > offset ) {
buffer_overflow :
2007-11-20 13:08:24 +03:00
call - > ndr_push_data - > offset = offset_save ;
2004-07-12 20:35:48 +04:00
rap_heap_restore ( call - > heap , & heap_save ) ;
break ;
}
}
call - > status = r . out . status ;
2007-11-09 21:24:51 +03:00
NDR_RETURN ( ndr_push_uint16 ( call - > ndr_push_param , NDR_SCALARS , r . out . count ) ) ;
NDR_RETURN ( ndr_push_uint16 ( call - > ndr_push_param , NDR_SCALARS , r . out . available ) ) ;
2004-07-12 20:35:48 +04:00
result = NT_STATUS_OK ;
done :
return result ;
}
2006-03-10 17:31:17 +03:00
static NTSTATUS _rap_netserverenum2 ( struct rap_call * call )
2004-07-12 20:35:48 +04:00
{
struct rap_NetServerEnum2 r ;
NTSTATUS result ;
2007-11-09 21:24:51 +03:00
RAP_GOTO ( rap_srv_pull_word ( call , & r . in . level ) ) ;
RAP_GOTO ( rap_srv_pull_bufsize ( call , & r . in . bufsize ) ) ;
RAP_GOTO ( rap_srv_pull_expect_multiple ( call ) ) ;
RAP_GOTO ( rap_srv_pull_dword ( call , & r . in . servertype ) ) ;
RAP_GOTO ( rap_srv_pull_string ( call , & r . in . domain ) ) ;
2004-07-12 20:35:48 +04:00
switch ( r . in . level ) {
case 0 :
if ( strcmp ( call - > datadesc , " B16 " ) ! = 0 )
return NT_STATUS_INVALID_PARAMETER ;
break ;
case 1 :
if ( strcmp ( call - > datadesc , " B16BBDz " ) ! = 0 )
return NT_STATUS_INVALID_PARAMETER ;
break ;
default :
return NT_STATUS_INVALID_PARAMETER ;
break ;
}
2008-01-06 04:03:43 +03:00
result = rap_netserverenum2 ( call , call - > lp_ctx , & r ) ;
2004-07-12 20:35:48 +04:00
if ( ! NT_STATUS_IS_OK ( result ) )
return result ;
for ( r . out . count = 0 ; r . out . count < r . out . available ; r . out . count + + ) {
int i = r . out . count ;
2007-11-20 13:08:24 +03:00
uint32_t offset_save ;
2004-07-12 20:35:48 +04:00
struct rap_heap_save heap_save ;
2007-11-20 13:08:24 +03:00
offset_save = call - > ndr_push_data - > offset ;
2004-07-12 20:35:48 +04:00
rap_heap_save ( call - > heap , & heap_save ) ;
switch ( r . in . level ) {
case 0 :
2007-11-09 21:24:51 +03:00
NDR_GOTO ( ndr_push_bytes ( call - > ndr_push_data ,
2004-11-25 21:25:22 +03:00
( const uint8_t * ) r . out . info [ i ] . info0 . name ,
2004-07-12 20:35:48 +04:00
sizeof ( r . out . info [ i ] . info0 . name ) ) ) ;
break ;
case 1 :
2007-11-09 21:24:51 +03:00
NDR_GOTO ( ndr_push_bytes ( call - > ndr_push_data ,
2004-11-25 21:25:22 +03:00
( const uint8_t * ) r . out . info [ i ] . info1 . name ,
2004-07-12 20:35:48 +04:00
sizeof ( r . out . info [ i ] . info1 . name ) ) ) ;
2007-11-09 21:24:51 +03:00
NDR_GOTO ( ndr_push_uint8 ( call - > ndr_push_data ,
2005-02-10 00:10:23 +03:00
NDR_SCALARS , r . out . info [ i ] . info1 . version_major ) ) ;
2007-11-09 21:24:51 +03:00
NDR_GOTO ( ndr_push_uint8 ( call - > ndr_push_data ,
2005-02-10 00:10:23 +03:00
NDR_SCALARS , r . out . info [ i ] . info1 . version_minor ) ) ;
2007-11-09 21:24:51 +03:00
NDR_GOTO ( ndr_push_uint32 ( call - > ndr_push_data ,
2005-02-10 00:10:23 +03:00
NDR_SCALARS , r . out . info [ i ] . info1 . servertype ) ) ;
2004-07-12 20:35:48 +04:00
2007-11-09 21:24:51 +03:00
RAP_GOTO ( rap_push_string ( call - > ndr_push_data ,
2004-07-12 20:35:48 +04:00
call - > heap ,
r . out . info [ i ] . info1 . comment ) ) ;
break ;
}
if ( call - > ndr_push_data - > offset > call - > heap - > offset ) {
buffer_overflow :
2007-11-20 13:08:24 +03:00
call - > ndr_push_data - > offset = offset_save ;
2004-07-12 20:35:48 +04:00
rap_heap_restore ( call - > heap , & heap_save ) ;
break ;
}
}
call - > status = r . out . status ;
2007-11-09 21:24:51 +03:00
NDR_RETURN ( ndr_push_uint16 ( call - > ndr_push_param , NDR_SCALARS , r . out . count ) ) ;
NDR_RETURN ( ndr_push_uint16 ( call - > ndr_push_param , NDR_SCALARS , r . out . available ) ) ;
2004-07-12 20:35:48 +04:00
result = NT_STATUS_OK ;
done :
return result ;
}
2006-03-10 17:31:17 +03:00
static NTSTATUS api_Unsupported ( struct rap_call * call )
2004-07-12 20:35:48 +04:00
{
call - > status = NERR_notsupported ;
call - > convert = 0 ;
return NT_STATUS_OK ;
}
static const struct
{
const char * name ;
int id ;
2006-03-10 17:31:17 +03:00
NTSTATUS ( * fn ) ( struct rap_call * call ) ;
2004-07-12 20:35:48 +04:00
} api_commands [ ] = {
2005-01-25 13:03:57 +03:00
{ " NetShareEnum " , RAP_WshareEnum , _rap_netshareenum } ,
2004-07-12 20:35:48 +04:00
{ " NetServerEnum2 " , RAP_NetServerEnum2 , _rap_netserverenum2 } ,
{ NULL , - 1 , api_Unsupported }
} ;
2008-12-29 22:24:57 +03:00
NTSTATUS ipc_rap_call ( TALLOC_CTX * mem_ctx , struct tevent_context * event_ctx , struct loadparm_context * lp_ctx ,
2008-01-06 04:03:43 +03:00
struct smb_trans2 * trans )
2004-07-12 20:35:48 +04:00
{
int i ;
NTSTATUS result ;
struct rap_call * call ;
DATA_BLOB result_param , result_data ;
struct ndr_push * final_param ;
struct ndr_push * final_data ;
2008-04-17 14:23:44 +04:00
call = new_rap_srv_call ( mem_ctx , event_ctx , lp_ctx , trans ) ;
2004-07-12 20:35:48 +04:00
if ( call = = NULL )
return NT_STATUS_NO_MEMORY ;
2007-11-09 21:24:51 +03:00
NDR_RETURN ( ndr_pull_uint16 ( call - > ndr_pull_param , NDR_SCALARS , & call - > callno ) ) ;
NDR_RETURN ( ndr_pull_string ( call - > ndr_pull_param , NDR_SCALARS ,
2004-07-12 20:35:48 +04:00
& call - > paramdesc ) ) ;
2007-11-09 21:24:51 +03:00
NDR_RETURN ( ndr_pull_string ( call - > ndr_pull_param , NDR_SCALARS ,
2004-07-12 20:35:48 +04:00
& call - > datadesc ) ) ;
2008-01-06 04:03:43 +03:00
call - > ndr_push_param = ndr_push_init_ctx ( call , lp_iconv_convenience ( lp_ctx ) ) ;
call - > ndr_push_data = ndr_push_init_ctx ( call , lp_iconv_convenience ( lp_ctx ) ) ;
2004-07-12 20:35:48 +04:00
if ( ( call - > ndr_push_param = = NULL ) | | ( call - > ndr_push_data = = NULL ) )
return NT_STATUS_NO_MEMORY ;
call - > ndr_push_param - > flags = RAPNDR_FLAGS ;
call - > ndr_push_data - > flags = RAPNDR_FLAGS ;
2005-01-25 12:46:00 +03:00
result = NT_STATUS_INVALID_SYSTEM_SERVICE ;
2004-07-12 20:35:48 +04:00
for ( i = 0 ; api_commands [ i ] . name ! = NULL ; i + + ) {
if ( api_commands [ i ] . id = = call - > callno ) {
DEBUG ( 5 , ( " Running RAP call %s \n " ,
api_commands [ i ] . name ) ) ;
2006-03-10 17:31:17 +03:00
result = api_commands [ i ] . fn ( call ) ;
2004-07-12 20:35:48 +04:00
break ;
}
}
if ( ! NT_STATUS_IS_OK ( result ) )
return result ;
result_param = ndr_push_blob ( call - > ndr_push_param ) ;
result_data = ndr_push_blob ( call - > ndr_push_data ) ;
2008-01-06 04:03:43 +03:00
final_param = ndr_push_init_ctx ( call , lp_iconv_convenience ( lp_ctx ) ) ;
final_data = ndr_push_init_ctx ( call , lp_iconv_convenience ( lp_ctx ) ) ;
2004-07-12 20:35:48 +04:00
if ( ( final_param = = NULL ) | | ( final_data = = NULL ) )
return NT_STATUS_NO_MEMORY ;
final_param - > flags = RAPNDR_FLAGS ;
final_data - > flags = RAPNDR_FLAGS ;
2007-11-09 21:24:51 +03:00
NDR_RETURN ( ndr_push_uint16 ( final_param , NDR_SCALARS , call - > status ) ) ;
NDR_RETURN ( ndr_push_uint16 ( final_param ,
2005-02-10 00:10:23 +03:00
NDR_SCALARS , call - > heap - > offset - result_data . length ) ) ;
2007-11-09 21:24:51 +03:00
NDR_RETURN ( ndr_push_bytes ( final_param , result_param . data ,
2004-07-12 20:35:48 +04:00
result_param . length ) ) ;
2007-11-09 21:24:51 +03:00
NDR_RETURN ( ndr_push_bytes ( final_data , result_data . data ,
2004-07-12 20:35:48 +04:00
result_data . length ) ) ;
for ( i = call - > heap - > num_strings - 1 ; i > = 0 ; i - - )
2007-11-09 21:24:51 +03:00
NDR_RETURN ( ndr_push_string ( final_data , NDR_SCALARS ,
2004-07-12 20:35:48 +04:00
call - > heap - > strings [ i ] ) ) ;
trans - > out . setup_count = 0 ;
trans - > out . setup = NULL ;
trans - > out . params = ndr_push_blob ( final_param ) ;
trans - > out . data = ndr_push_blob ( final_data ) ;
return result ;
}