2010-10-04 17:56:49 +04:00
/*
Unix SMB / CIFS implementation .
Endpoint server for the epmapper pipe
Copyright ( C ) 2010 Andreas Schneider < asn @ 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 3 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 , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
# include "librpc/gen_ndr/ndr_epmapper.h"
# include "librpc/gen_ndr/srv_epmapper.h"
typedef uint32_t error_status_t ;
2010-10-04 19:58:33 +04:00
/* An endpoint combined with an interface description */
struct dcesrv_ep_iface {
const char * name ;
struct epm_tower ep ;
} ;
2010-09-16 12:50:25 +04:00
/* A rpc service interface like samr, lsarpc or netlogon */
struct dcesrv_iface {
const char * name ;
struct ndr_syntax_id syntax_id ;
} ;
struct dcesrv_iface_list {
struct dcesrv_iface_list * next , * prev ;
struct dcesrv_iface * iface ;
} ;
2010-10-04 17:56:49 +04:00
/*
2010-09-16 12:50:25 +04:00
* An endpoint can serve multiple rpc services interfaces .
* For example \ \ pipe \ netlogon can be used by lsarpc and netlogon .
*/
struct dcesrv_endpoint {
struct dcesrv_endpoint * next , * prev ;
/* The type and the location of the endpoint */
struct dcerpc_binding * ep_description ;
/* A list of rpc services able to connect to the endpoint */
struct dcesrv_iface_list * iface_list ;
} ;
struct dcesrv_endpoint * endpoint_table ;
/*
* Check if the UUID and if_version match to an interface .
*/
static bool interface_match ( const struct dcesrv_iface * if1 ,
const struct dcesrv_iface * if2 )
{
return GUID_equal ( & if1 - > syntax_id . uuid , & if2 - > syntax_id . uuid ) ;
}
/*
* Find the interface operations on an endpoint .
*/
static const struct dcesrv_iface * find_interface ( const struct dcesrv_endpoint * endpoint ,
const struct dcesrv_iface * iface )
{
struct dcesrv_iface_list * iflist ;
for ( iflist = endpoint - > iface_list ; iflist ; iflist = iflist - > next ) {
if ( interface_match ( iflist - > iface , iface ) ) {
return iflist - > iface ;
}
}
return NULL ;
}
2010-10-11 19:22:22 +04:00
/*
* See if a uuid and if_version match to an interface
*/
static bool interface_match_by_uuid ( const struct dcesrv_iface * iface ,
const struct GUID * uuid )
{
return GUID_equal ( & iface - > syntax_id . uuid , uuid ) ;
}
2010-10-05 13:45:41 +04:00
static struct dcesrv_iface_list * find_interface_list ( const struct dcesrv_endpoint * endpoint ,
const struct dcesrv_iface * iface )
{
struct dcesrv_iface_list * iflist ;
for ( iflist = endpoint - > iface_list ; iflist ; iflist = iflist - > next ) {
if ( interface_match ( iflist - > iface , iface ) ) {
return iflist ;
}
}
return NULL ;
}
2010-09-16 12:50:25 +04:00
/*
* Check if two endpoints match .
*/
static bool endpoints_match ( const struct dcerpc_binding * ep1 ,
const struct dcerpc_binding * ep2 )
{
if ( ep1 - > transport ! = ep2 - > transport ) {
return false ;
}
if ( ! ep1 - > endpoint | | ! ep2 - > endpoint ) {
return ep1 - > endpoint = = ep2 - > endpoint ;
}
if ( ! strequal ( ep1 - > endpoint , ep2 - > endpoint ) ) {
return false ;
}
return true ;
}
static struct dcesrv_endpoint * find_endpoint ( struct dcesrv_endpoint * endpoint_list ,
struct dcerpc_binding * ep_description ) {
struct dcesrv_endpoint * ep ;
for ( ep = endpoint_list ; ep ! = NULL ; ep = ep - > next ) {
if ( endpoints_match ( ep - > ep_description , ep_description ) ) {
return ep ;
}
}
return NULL ;
}
/*
* Build a list of all interfaces handled by all endpoint servers .
*/
static uint32_t build_ep_list ( TALLOC_CTX * mem_ctx ,
struct dcesrv_endpoint * endpoint_list ,
2010-10-11 19:22:22 +04:00
const struct GUID * uuid ,
2010-09-16 12:50:25 +04:00
struct dcesrv_ep_iface * * peps )
{
2010-10-04 19:58:33 +04:00
struct dcesrv_ep_iface * eps = NULL ;
2010-09-16 12:50:25 +04:00
struct dcesrv_endpoint * d ;
uint32_t total = 0 ;
NTSTATUS status ;
* peps = NULL ;
for ( d = endpoint_list ; d ! = NULL ; d = d - > next ) {
struct dcesrv_iface_list * iface ;
struct dcerpc_binding * description ;
for ( iface = d - > iface_list ; iface ! = NULL ; iface = iface - > next ) {
2010-10-11 19:22:22 +04:00
if ( uuid ! = NULL & &
! interface_match_by_uuid ( iface - > iface , uuid ) ) {
continue ;
}
2010-09-16 12:50:25 +04:00
eps = talloc_realloc ( mem_ctx ,
eps ,
struct dcesrv_ep_iface ,
total + 1 ) ;
if ( eps = = NULL ) {
return 0 ;
}
eps [ total ] . name = iface - > iface - > name ;
description = d - > ep_description ;
description - > object = iface - > iface - > syntax_id ;
status = dcerpc_binding_build_tower ( eps ,
description ,
& eps [ total ] . ep ) ;
if ( NT_STATUS_IS_ERR ( status ) ) {
DEBUG ( 1 , ( " Unable to build tower for %s \n " ,
iface - > iface - > name ) ) ;
continue ;
}
total + + ;
}
}
* peps = eps ;
return total ;
}
/*
* epm_Insert
*
* Add the specified entries to an endpoint map .
*/
2010-10-04 17:56:49 +04:00
error_status_t _epm_Insert ( struct pipes_struct * p ,
struct epm_Insert * r )
{
2010-09-16 12:50:25 +04:00
TALLOC_CTX * tmp_ctx ;
error_status_t rc ;
NTSTATUS status ;
uint32_t i ;
2010-10-04 17:56:49 +04:00
2010-09-16 12:50:25 +04:00
tmp_ctx = talloc_stackframe ( ) ;
if ( tmp_ctx = = NULL ) {
return EPMAPPER_STATUS_NO_MEMORY ;
}
2010-10-04 17:56:49 +04:00
2010-09-16 12:50:25 +04:00
DEBUG ( 3 , ( " _epm_Insert: Trying to add %u new entries. \n " ,
r - > in . num_ents ) ) ;
2010-10-04 17:56:49 +04:00
2010-09-16 12:50:25 +04:00
/* TODO Check if we have a priviledged pipe/handle */
2010-10-04 17:56:49 +04:00
2010-09-16 12:50:25 +04:00
for ( i = 0 ; i < r - > in . num_ents ; i + + ) {
struct dcerpc_binding * b = NULL ;
struct dcesrv_endpoint * ep ;
struct dcesrv_iface_list * iflist ;
struct dcesrv_iface * iface ;
bool add_ep = false ;
status = dcerpc_binding_from_tower ( tmp_ctx ,
& r - > in . entries [ i ] . tower - > tower ,
& b ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
rc = EPMAPPER_STATUS_NO_MEMORY ;
goto done ;
}
DEBUG ( 3 , ( " _epm_Insert: Adding transport %s for %s \n " ,
derpc_transport_string_by_transport ( b - > transport ) ,
r - > in . entries [ i ] . annotation ) ) ;
/* Check if the entry already exits */
ep = find_endpoint ( endpoint_table , b ) ;
if ( ep = = NULL ) {
/* No entry found, create it */
ep = talloc_zero ( NULL , struct dcesrv_endpoint ) ;
if ( ep = = NULL ) {
rc = EPMAPPER_STATUS_CANT_PERFORM_OP ;
goto done ;
}
add_ep = true ;
ep - > ep_description = talloc_steal ( ep , b ) ;
}
/* TODO Replace the entry if the replace flag is set */
/* Create an interface */
iface = talloc ( tmp_ctx , struct dcesrv_iface ) ;
if ( iface = = NULL ) {
rc = EPMAPPER_STATUS_NO_MEMORY ;
goto done ;
}
iface - > name = talloc_strdup ( iface , r - > in . entries [ i ] . annotation ) ;
if ( iface - > name = = NULL ) {
rc = EPMAPPER_STATUS_NO_MEMORY ;
goto done ;
}
iface - > syntax_id = b - > object ;
/*
* Check if the rpc service is alrady registered on the
* endpoint .
*/
if ( find_interface ( ep , iface ) ! = NULL ) {
DEBUG ( 0 , ( " dcesrv_interface_register: interface '%s' "
" already registered on endpoint \n " ,
iface - > name ) ) ;
/* FIXME wrong error code? */
rc = EPMAPPER_STATUS_OK ;
goto done ;
}
/* Create an entry for the interface */
iflist = talloc ( ep , struct dcesrv_iface_list ) ;
if ( iflist = = NULL ) {
rc = EPMAPPER_STATUS_NO_MEMORY ;
goto done ;
}
iflist - > iface = talloc_move ( iflist , & iface ) ;
/* Finally add the interface on the endpoint */
DLIST_ADD ( ep - > iface_list , iflist ) ;
/* If it's a new endpoint add it to the endpoint_table */
if ( add_ep ) {
DLIST_ADD ( endpoint_table , ep ) ;
}
}
rc = EPMAPPER_STATUS_OK ;
done :
talloc_free ( tmp_ctx ) ;
return rc ;
2010-10-04 17:56:49 +04:00
}
/*
2010-10-05 13:45:41 +04:00
* epm_Delete
*
* Delete the specified entries from an endpoint map .
*/
2010-10-04 17:56:49 +04:00
error_status_t _epm_Delete ( struct pipes_struct * p ,
2010-10-05 13:45:41 +04:00
struct epm_Delete * r )
2010-10-04 17:56:49 +04:00
{
2010-10-05 13:45:41 +04:00
TALLOC_CTX * tmp_ctx ;
error_status_t rc ;
NTSTATUS status ;
uint32_t i ;
2010-10-04 17:56:49 +04:00
2010-10-05 13:45:41 +04:00
DEBUG ( 3 , ( " _epm_Delete: Trying to delete %u entries. \n " ,
r - > in . num_ents ) ) ;
2010-10-04 17:56:49 +04:00
2010-10-05 13:45:41 +04:00
tmp_ctx = talloc_stackframe ( ) ;
if ( tmp_ctx = = NULL ) {
return EPMAPPER_STATUS_NO_MEMORY ;
}
/* TODO Check if we have a priviledged pipe/handle */
for ( i = 0 ; i < r - > in . num_ents ; i + + ) {
struct dcerpc_binding * b = NULL ;
struct dcesrv_endpoint * ep ;
struct dcesrv_iface iface ;
struct dcesrv_iface_list * iflist ;
status = dcerpc_binding_from_tower ( tmp_ctx ,
& r - > in . entries [ i ] . tower - > tower ,
& b ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
rc = EPMAPPER_STATUS_NO_MEMORY ;
goto done ;
}
DEBUG ( 3 , ( " _epm_Delete: Deleting transport '%s' for '%s' \n " ,
derpc_transport_string_by_transport ( b - > transport ) ,
r - > in . entries [ i ] . annotation ) ) ;
ep = find_endpoint ( endpoint_table , b ) ;
if ( ep = = NULL ) {
rc = EPMAPPER_STATUS_OK ;
goto done ;
}
iface . name = r - > in . entries [ i ] . annotation ;
iface . syntax_id = b - > object ;
iflist = find_interface_list ( ep , & iface ) ;
if ( iflist = = NULL ) {
DEBUG ( 0 , ( " _epm_Delete: No interfaces left, delete endpoint \n " ) ) ;
DLIST_REMOVE ( endpoint_table , ep ) ;
talloc_free ( ep ) ;
rc = EPMAPPER_STATUS_OK ;
goto done ;
}
DLIST_REMOVE ( ep - > iface_list , iflist ) ;
if ( ep - > iface_list = = NULL ) {
DEBUG ( 0 , ( " _epm_Delete: No interfaces left, delete endpoint \n " ) ) ;
DLIST_REMOVE ( endpoint_table , ep ) ;
talloc_free ( ep ) ;
rc = EPMAPPER_STATUS_OK ;
goto done ;
}
}
rc = EPMAPPER_STATUS_OK ;
done :
talloc_free ( tmp_ctx ) ;
return rc ;
2010-10-04 17:56:49 +04:00
}
/*
epm_Lookup
*/
error_status_t _epm_Lookup ( struct pipes_struct * p ,
struct epm_Lookup * r )
{
p - > rng_fault_state = true ;
return EPMAPPER_STATUS_CANT_PERFORM_OP ;
}
/*
2010-10-04 19:58:33 +04:00
* epm_Map
*
2010-10-04 17:56:49 +04:00
* Apply some algorithm ( using the fields in the map_tower ) to an endpoint map
* to produce a list of protocol towers .
*/
error_status_t _epm_Map ( struct pipes_struct * p ,
struct epm_Map * r )
{
2010-10-04 19:58:33 +04:00
enum dcerpc_transport_t transport ;
struct ndr_syntax_id ndr_syntax ;
struct dcesrv_ep_iface * eps ;
struct epm_floor * floors ;
uint32_t count , i ;
2010-10-11 19:22:22 +04:00
count = build_ep_list ( p - > mem_ctx , endpoint_table , NULL , & eps ) ;
2010-10-04 19:58:33 +04:00
ZERO_STRUCT ( * r - > out . entry_handle ) ;
r - > out . num_towers = talloc ( p - > mem_ctx , uint32_t ) ;
if ( r - > out . num_towers = = NULL ) {
return EPMAPPER_STATUS_NO_MEMORY ;
}
* r - > out . num_towers = 1 ;
r - > out . towers = talloc ( p - > mem_ctx , struct epm_twr_p_t ) ;
if ( r - > out . towers = = NULL ) {
return EPMAPPER_STATUS_NO_MEMORY ;
}
r - > out . towers - > twr = talloc ( p - > mem_ctx , struct epm_twr_t ) ;
if ( r - > out . towers - > twr = = NULL ) {
return EPMAPPER_STATUS_NO_MEMORY ;
}
if ( r - > in . map_tower = = NULL | | r - > in . max_towers = = 0 | |
r - > in . map_tower - > tower . num_floors < 3 ) {
goto failed ;
}
floors = r - > in . map_tower - > tower . floors ;
dcerpc_floor_get_lhs_data ( & r - > in . map_tower - > tower . floors [ 1 ] , & ndr_syntax ) ;
if ( floors [ 1 ] . lhs . protocol ! = EPM_PROTOCOL_UUID | |
! GUID_equal ( & ndr_syntax . uuid , & ndr_transfer_syntax . uuid ) | |
ndr_syntax . if_version ! = ndr_transfer_syntax . if_version ) {
goto failed ;
}
transport = dcerpc_transport_by_tower ( & r - > in . map_tower - > tower ) ;
if ( transport = = - 1 ) {
DEBUG ( 2 , ( " epm_Insert: Client requested unknown transport with levels: " ) ) ;
for ( i = 2 ; i < r - > in . map_tower - > tower . num_floors ; i + + ) {
DEBUG ( 2 , ( " %d, " , r - > in . map_tower - > tower . floors [ i ] . lhs . protocol ) ) ;
}
DEBUG ( 2 , ( " \n " ) ) ;
goto failed ;
}
for ( i = 0 ; i < count ; i + + ) {
if ( data_blob_cmp ( & r - > in . map_tower - > tower . floors [ 0 ] . lhs . lhs_data ,
& eps [ i ] . ep . floors [ 0 ] . lhs . lhs_data ) ! = 0 | |
transport ! = dcerpc_transport_by_tower ( & eps [ i ] . ep ) ) {
continue ;
}
r - > out . towers - > twr - > tower = eps [ i ] . ep ;
r - > out . towers - > twr - > tower_length = 0 ;
return EPMAPPER_STATUS_OK ;
}
failed :
* r - > out . num_towers = 0 ;
r - > out . towers - > twr = NULL ;
return EPMAPPER_STATUS_NO_MORE_ENTRIES ;
2010-10-04 17:56:49 +04:00
}
/*
epm_LookupHandleFree
*/
error_status_t _epm_LookupHandleFree ( struct pipes_struct * p ,
struct epm_LookupHandleFree * r )
{
p - > rng_fault_state = true ;
return EPMAPPER_STATUS_CANT_PERFORM_OP ;
}
/*
epm_InqObject
*/
error_status_t _epm_InqObject ( struct pipes_struct * p ,
struct epm_InqObject * r )
{
p - > rng_fault_state = true ;
return EPMAPPER_STATUS_CANT_PERFORM_OP ;
}
/*
epm_MgmtDelete
*/
error_status_t _epm_MgmtDelete ( struct pipes_struct * p ,
struct epm_MgmtDelete * r )
{
p - > rng_fault_state = true ;
return EPMAPPER_STATUS_CANT_PERFORM_OP ;
}
/*
epm_MapAuth
*/
error_status_t _epm_MapAuth ( struct pipes_struct * p ,
struct epm_MapAuth * r )
{
p - > rng_fault_state = true ;
return EPMAPPER_STATUS_CANT_PERFORM_OP ;
}
/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */