2004-10-24 19:48:19 +04:00
/*
Unix SMB / CIFS implementation .
server side dcerpc using various kinds of sockets ( tcp , unix domain )
Copyright ( C ) Andrew Tridgell 2003
2005-01-11 19:53:02 +03:00
Copyright ( C ) Stefan ( metze ) Metzmacher 2004 - 2005
2004-10-24 19:48:19 +04:00
Copyright ( C ) Jelmer Vernooij 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
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"
2005-02-03 14:56:03 +03:00
# include "lib/events/events.h"
2004-11-02 10:42:47 +03:00
# include "rpc_server/dcerpc_server.h"
2005-01-30 03:54:57 +03:00
# include "smbd/service_stream.h"
2004-10-24 19:48:19 +04:00
struct dcesrv_socket_context {
const struct dcesrv_endpoint * endpoint ;
struct dcesrv_context * dcesrv_ctx ;
} ;
/*
write_fn callback for dcesrv_output ( )
*/
static ssize_t dcerpc_write_fn ( void * private , DATA_BLOB * out )
{
NTSTATUS status ;
struct socket_context * sock = private ;
size_t sendlen ;
2004-10-28 08:00:43 +04:00
status = socket_send ( sock , out , & sendlen , 0 ) ;
2004-10-28 15:59:03 +04:00
if ( NT_STATUS_IS_ERR ( status ) ) {
2004-10-24 19:48:19 +04:00
return - 1 ;
}
return sendlen ;
}
2005-01-11 19:53:02 +03:00
static void dcesrv_terminate_connection ( struct dcesrv_connection * dce_conn , const char * reason )
2004-10-24 19:48:19 +04:00
{
2005-01-30 03:54:57 +03:00
stream_terminate_connection ( dce_conn - > srv_conn , reason ) ;
2004-10-24 19:48:19 +04:00
}
2005-01-30 03:54:57 +03:00
void dcesrv_sock_accept ( struct stream_connection * srv_conn )
2004-10-24 19:48:19 +04:00
{
2005-01-30 03:54:57 +03:00
NTSTATUS status ;
struct dcesrv_socket_context * dcesrv_sock =
talloc_get_type ( srv_conn - > private , struct dcesrv_socket_context ) ;
struct dcesrv_connection * dcesrv_conn = NULL ;
status = dcesrv_endpoint_connect ( dcesrv_sock - > dcesrv_ctx ,
srv_conn ,
dcesrv_sock - > endpoint ,
srv_conn ,
& dcesrv_conn ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s \n " ,
nt_errstr ( status ) ) ) ;
return ;
}
srv_conn - > private = dcesrv_conn ;
return ;
}
2005-02-03 14:25:52 +03:00
void dcesrv_sock_recv ( struct stream_connection * conn , uint16_t flags )
2005-01-30 03:54:57 +03:00
{
NTSTATUS status ;
struct dcesrv_connection * dce_conn = talloc_get_type ( conn - > private , struct dcesrv_connection ) ;
DATA_BLOB tmp_blob ;
size_t nread ;
tmp_blob = data_blob_talloc ( conn - > socket , NULL , 0x1000 ) ;
if ( tmp_blob . data = = NULL ) {
dcesrv_terminate_connection ( dce_conn , " out of memory " ) ;
return ;
}
status = socket_recv ( conn - > socket , tmp_blob . data , tmp_blob . length , & nread , 0 ) ;
if ( NT_STATUS_IS_ERR ( status ) ) {
dcesrv_terminate_connection ( dce_conn , nt_errstr ( status ) ) ;
return ;
}
if ( nread = = 0 ) {
talloc_free ( tmp_blob . data ) ;
return ;
}
tmp_blob . length = nread ;
status = dcesrv_input ( dce_conn , & tmp_blob ) ;
talloc_free ( tmp_blob . data ) ;
2004-10-24 19:48:19 +04:00
2005-01-30 03:54:57 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
dcesrv_terminate_connection ( dce_conn , nt_errstr ( status ) ) ;
2004-10-24 19:48:19 +04:00
return ;
}
2005-01-30 03:54:57 +03:00
if ( dce_conn - > call_list & & dce_conn - > call_list - > replies ) {
2005-02-03 05:35:52 +03:00
EVENT_FD_WRITEABLE ( conn - > event . fde ) ;
2005-01-30 03:54:57 +03:00
}
}
2005-02-03 14:25:52 +03:00
void dcesrv_sock_send ( struct stream_connection * conn , uint16_t flags )
2005-01-30 03:54:57 +03:00
{
struct dcesrv_connection * dce_conn = talloc_get_type ( conn - > private , struct dcesrv_connection ) ;
NTSTATUS status ;
status = dcesrv_output ( dce_conn , conn - > socket , dcerpc_write_fn ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
dcesrv_terminate_connection ( dce_conn , " eof on socket " ) ;
2004-10-24 19:48:19 +04:00
return ;
}
2005-01-30 03:54:57 +03:00
if ( ! dce_conn - > call_list | | ! dce_conn - > call_list - > replies ) {
2005-02-03 05:35:52 +03:00
EVENT_FD_NOT_WRITEABLE ( conn - > event . fde ) ;
2005-01-30 03:54:57 +03:00
}
}
static const struct stream_server_ops dcesrv_stream_ops = {
. name = " rpc " ,
. accept_connection = dcesrv_sock_accept ,
. recv_handler = dcesrv_sock_recv ,
. send_handler = dcesrv_sock_send ,
} ;
static NTSTATUS add_socket_rpc_unix ( struct dcesrv_context * dce_ctx , struct dcesrv_endpoint * e ,
struct event_context * event_ctx , const struct model_ops * model_ops )
{
struct dcesrv_socket_context * dcesrv_sock ;
uint16_t port = 1 ;
NTSTATUS status ;
dcesrv_sock = talloc ( dce_ctx , struct dcesrv_socket_context ) ;
NT_STATUS_HAVE_NO_MEMORY ( dcesrv_sock ) ;
2004-10-24 19:48:19 +04:00
/* remember the endpoint of this socket */
dcesrv_sock - > endpoint = e ;
2005-01-30 03:54:57 +03:00
dcesrv_sock - > dcesrv_ctx = talloc_reference ( dcesrv_sock , dce_ctx ) ;
status = stream_setup_socket ( event_ctx , model_ops , & dcesrv_stream_ops ,
" unix " , e - > ep_description . endpoint , & port ,
dcesrv_sock ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " service_setup_stream_socket(path=%s) failed - %s \n " ,
e - > ep_description . endpoint , nt_errstr ( status ) ) ) ;
}
2004-10-24 19:48:19 +04:00
2005-01-30 03:54:57 +03:00
return status ;
2004-10-24 19:48:19 +04:00
}
2005-01-30 03:54:57 +03:00
static NTSTATUS add_socket_rpc_ncalrpc ( struct dcesrv_context * dce_ctx , struct dcesrv_endpoint * e ,
struct event_context * event_ctx , const struct model_ops * model_ops )
2004-10-24 19:48:19 +04:00
{
struct dcesrv_socket_context * dcesrv_sock ;
uint16_t port = 1 ;
char * full_path ;
2005-01-30 03:54:57 +03:00
NTSTATUS status ;
2004-10-24 19:48:19 +04:00
2004-10-25 02:46:47 +04:00
if ( ! e - > ep_description . endpoint ) {
2004-10-25 14:21:41 +04:00
/* No identifier specified: use DEFAULT.
* DO NOT hardcode this value anywhere else . Rather , specify
* no endpoint and let the epmapper worry about it . */
e - > ep_description . endpoint = talloc_strdup ( dce_ctx , " DEFAULT " ) ;
2004-10-24 19:48:19 +04:00
}
2004-10-25 02:46:47 +04:00
full_path = talloc_asprintf ( dce_ctx , " %s/%s " , lp_ncalrpc_dir ( ) , e - > ep_description . endpoint ) ;
2004-10-24 19:48:19 +04:00
2005-01-30 03:54:57 +03:00
dcesrv_sock = talloc ( dce_ctx , struct dcesrv_socket_context ) ;
NT_STATUS_HAVE_NO_MEMORY ( dcesrv_sock ) ;
2004-10-24 19:48:19 +04:00
/* remember the endpoint of this socket */
dcesrv_sock - > endpoint = e ;
dcesrv_sock - > dcesrv_ctx = dce_ctx ;
2005-01-30 03:54:57 +03:00
status = stream_setup_socket ( event_ctx , model_ops , & dcesrv_stream_ops ,
" unix " , full_path , & port , dcesrv_sock ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " service_setup_stream_socket(identifier=%s,path=%s) failed - %s \n " ,
e - > ep_description . endpoint , full_path , nt_errstr ( status ) ) ) ;
}
return status ;
2004-10-24 19:48:19 +04:00
}
/*
add a socket address to the list of events , one event per dcerpc endpoint
*/
2005-01-30 03:54:57 +03:00
static NTSTATUS add_socket_rpc_tcp_iface ( struct dcesrv_context * dce_ctx , struct dcesrv_endpoint * e ,
struct event_context * event_ctx , const struct model_ops * model_ops ,
const char * address )
2004-10-24 19:48:19 +04:00
{
struct dcesrv_socket_context * dcesrv_sock ;
uint16_t port = 0 ;
2005-01-30 03:54:57 +03:00
NTSTATUS status ;
2004-10-24 19:48:19 +04:00
2005-01-30 03:54:57 +03:00
if ( e - > ep_description . endpoint ) {
2004-10-25 02:46:47 +04:00
port = atoi ( e - > ep_description . endpoint ) ;
2004-10-24 19:48:19 +04:00
}
2005-01-30 03:54:57 +03:00
dcesrv_sock = talloc ( dce_ctx , struct dcesrv_socket_context ) ;
NT_STATUS_HAVE_NO_MEMORY ( dcesrv_sock ) ;
2004-10-24 19:48:19 +04:00
/* remember the endpoint of this socket */
dcesrv_sock - > endpoint = e ;
dcesrv_sock - > dcesrv_ctx = dce_ctx ;
2005-01-30 03:54:57 +03:00
status = stream_setup_socket ( event_ctx , model_ops , & dcesrv_stream_ops ,
" ipv4 " , address , & port , dcesrv_sock ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " service_setup_stream_socket(address=%s,port=%u) failed - %s \n " ,
address , port , nt_errstr ( status ) ) ) ;
}
2004-10-24 19:48:19 +04:00
2005-01-30 03:54:57 +03:00
if ( e - > ep_description . endpoint = = NULL ) {
e - > ep_description . endpoint = talloc_asprintf ( dce_ctx , " %d " , port ) ;
}
2004-10-24 19:48:19 +04:00
2005-01-30 03:54:57 +03:00
return status ;
2004-10-24 19:48:19 +04:00
}
2005-01-30 03:54:57 +03:00
static NTSTATUS add_socket_rpc_tcp ( struct dcesrv_context * dce_ctx , struct dcesrv_endpoint * e ,
struct event_context * event_ctx , const struct model_ops * model_ops )
2004-10-24 19:48:19 +04:00
{
2005-01-30 03:54:57 +03:00
NTSTATUS status ;
2004-10-24 19:48:19 +04:00
/* Add TCP/IP sockets */
if ( lp_interfaces ( ) & & lp_bind_interfaces_only ( ) ) {
int num_interfaces = iface_count ( ) ;
int i ;
for ( i = 0 ; i < num_interfaces ; i + + ) {
2005-02-10 06:22:47 +03:00
const char * address = iface_n_ip ( i ) ;
2005-01-30 03:54:57 +03:00
status = add_socket_rpc_tcp_iface ( dce_ctx , e , event_ctx , model_ops , address ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
2004-10-24 19:48:19 +04:00
}
} else {
2005-01-30 03:54:57 +03:00
status = add_socket_rpc_tcp_iface ( dce_ctx , e , event_ctx , model_ops , lp_socket_address ( ) ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
2004-10-24 19:48:19 +04:00
}
2005-01-30 03:54:57 +03:00
return NT_STATUS_OK ;
2004-10-24 19:48:19 +04:00
}
/****************************************************************************
Open the listening sockets for RPC over NCACN_IP_TCP / NCALRPC / NCACN_UNIX_STREAM
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-01-30 03:54:57 +03:00
NTSTATUS dcesrv_sock_init ( struct dcesrv_context * dce_ctx ,
struct event_context * event_ctx , const struct model_ops * model_ops )
2004-10-24 19:48:19 +04:00
{
struct dcesrv_endpoint * e ;
2005-01-30 03:54:57 +03:00
NTSTATUS status ;
2004-10-24 19:48:19 +04:00
2004-10-25 11:55:08 +04:00
/* Make sure the directory for NCALRPC exists */
if ( ! directory_exist ( lp_ncalrpc_dir ( ) , NULL ) ) {
2005-01-01 01:38:00 +03:00
mkdir ( lp_ncalrpc_dir ( ) , 0755 ) ;
2004-10-25 11:55:08 +04:00
}
2004-10-24 19:48:19 +04:00
for ( e = dce_ctx - > endpoint_list ; e ; e = e - > next ) {
switch ( e - > ep_description . transport ) {
case NCACN_UNIX_STREAM :
2005-01-30 03:54:57 +03:00
status = add_socket_rpc_unix ( dce_ctx , e , event_ctx , model_ops ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
2004-10-24 19:48:19 +04:00
break ;
case NCALRPC :
2005-01-30 03:54:57 +03:00
status = add_socket_rpc_ncalrpc ( dce_ctx , e , event_ctx , model_ops ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
2004-10-24 19:48:19 +04:00
break ;
case NCACN_IP_TCP :
2005-01-30 03:54:57 +03:00
status = add_socket_rpc_tcp ( dce_ctx , e , event_ctx , model_ops ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
2004-10-24 19:48:19 +04:00
break ;
default :
break ;
}
}
2005-01-30 03:54:57 +03:00
return NT_STATUS_OK ;
2004-10-24 19:48:19 +04:00
}