2004-07-14 01:04:56 +04:00
/*
Unix SMB / CIFS implementation .
SERVER SERVICE code
Copyright ( C ) Andrew Tridgell 2003
Copyright ( C ) Stefan ( metze ) Metzmacher 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"
2004-11-02 15:15:17 +03:00
# include "events.h"
2004-11-02 03:24:21 +03:00
# include "system/dir.h"
2004-11-02 09:42:15 +03:00
# include "dlinklist.h"
2004-11-02 10:18:24 +03:00
# include "process_model.h"
2004-07-14 01:04:56 +04:00
2005-01-14 04:32:56 +03:00
struct server_context * server_service_startup ( const char * model , const char * * server_services )
2004-07-14 01:04:56 +04:00
{
int i ;
2005-01-14 04:32:56 +03:00
struct server_context * server ;
2004-07-14 01:04:56 +04:00
if ( ! server_services ) {
2005-01-14 04:32:56 +03:00
DEBUG ( 0 , ( " server_service_startup: no endpoint servers configured \n " ) ) ;
2004-07-14 01:04:56 +04:00
return NULL ;
}
2005-01-14 04:32:56 +03:00
server = talloc_zero ( NULL , struct server_context ) ;
if ( ! server ) {
2004-07-14 01:04:56 +04:00
return NULL ;
}
2005-01-14 04:32:56 +03:00
server - > model . ops = process_model_startup ( server , model ) ;
if ( ! server - > model . ops ) {
DEBUG ( 0 , ( " process_model_startup('%s') failed \n " , model ) ) ;
return NULL ;
}
2004-07-14 01:04:56 +04:00
2005-01-14 04:32:56 +03:00
server - > event . ctx = event_context_init ( server ) ;
if ( ! server - > event . ctx ) {
2004-07-14 01:04:56 +04:00
DEBUG ( 0 , ( " event_context_init() failed \n " ) ) ;
2005-01-14 04:32:56 +03:00
return NULL ;
2004-07-14 01:04:56 +04:00
}
for ( i = 0 ; server_services [ i ] ; i + + ) {
const struct server_service_ops * service_ops ;
struct server_service * service ;
service_ops = server_service_byname ( server_services [ i ] ) ;
if ( ! service_ops ) {
DEBUG ( 0 , ( " process_model_startup: failed to find server service = '%s' \n " , server_services [ i ] ) ) ;
return NULL ;
}
2005-01-14 04:32:56 +03:00
service = talloc_zero ( server , struct server_service ) ;
2004-07-14 01:04:56 +04:00
if ( ! service ) {
return NULL ;
}
2005-01-14 04:32:56 +03:00
service - > service . ops = service_ops ;
service - > server = server ;
2004-07-14 01:04:56 +04:00
/* TODO: service_init() should return a result */
2005-01-14 04:32:56 +03:00
service - > service . ops - > service_init ( service ) ;
2004-10-29 11:00:14 +04:00
2005-01-14 04:32:56 +03:00
DLIST_ADD ( server - > service_list , service ) ;
2004-07-14 01:04:56 +04:00
}
2005-01-14 04:32:56 +03:00
return server ;
}
void server_service_shutdown ( struct server_context * server , const char * reason )
{
server - > model . ops - > model_exit ( server , reason ) ;
2004-07-14 01:04:56 +04:00
}
/*
2004-09-20 16:31:07 +04:00
setup a listen stream socket
if you pass * port = = 0 , then a port > 1024 is used
2004-07-14 01:04:56 +04:00
*/
2005-01-14 04:32:56 +03:00
struct server_stream_socket * service_setup_stream_socket ( struct server_service * service ,
const struct server_stream_ops * stream_ops ,
const char * family ,
const char * sock_addr ,
uint16_t * port )
2004-07-14 01:04:56 +04:00
{
2004-09-20 16:31:07 +04:00
NTSTATUS status ;
2005-01-14 04:32:56 +03:00
struct server_stream_socket * stream_socket ;
struct socket_context * sock ;
2004-07-14 01:04:56 +04:00
struct fd_event fde ;
int i ;
2005-01-14 04:32:56 +03:00
status = socket_create ( family , SOCKET_TYPE_STREAM , & sock , 0 ) ;
2004-09-20 16:31:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-07-14 01:04:56 +04:00
DEBUG ( 0 , ( " Failed to open socket on %s:%u - %s \n " ,
2004-09-20 16:31:07 +04:00
sock_addr , * port , nt_errstr ( status ) ) ) ;
2004-07-14 01:04:56 +04:00
return NULL ;
}
/* ready to listen */
2005-01-14 04:32:56 +03:00
status = socket_set_option ( sock , " SO_KEEPALIVE SO_REUSEADDR=1 " , NULL ) ;
2004-09-20 16:31:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " socket_set_option(socket_ctx, SO_KEEPALIVE, NULL): %s \n " ,
nt_errstr ( status ) ) ) ;
2005-01-14 04:32:56 +03:00
socket_destroy ( sock ) ;
2004-09-20 16:31:07 +04:00
return NULL ;
}
2005-01-14 04:32:56 +03:00
status = socket_set_option ( sock , lp_socket_options ( ) , NULL ) ;
2004-09-20 16:31:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " socket_set_option(socket_ctx, lp_socket_options(), NULL): %s \n " ,
nt_errstr ( status ) ) ) ;
2005-01-14 04:32:56 +03:00
socket_destroy ( sock ) ;
2004-09-20 16:31:07 +04:00
return NULL ;
}
/* TODO: set socket ACL's here when they're implemented */
2004-10-10 02:34:18 +04:00
if ( * port = = 0 ) {
for ( i = SERVER_TCP_LOW_PORT ; i < = SERVER_TCP_HIGH_PORT ; i + + ) {
2005-01-14 04:32:56 +03:00
status = socket_listen ( sock , sock_addr , i , SERVER_LISTEN_BACKLOG , 0 ) ;
2004-10-10 02:34:18 +04:00
if ( NT_STATUS_IS_OK ( status ) ) {
* port = i ;
break ;
}
}
} else {
2005-01-14 04:32:56 +03:00
status = socket_listen ( sock , sock_addr , * port , SERVER_LISTEN_BACKLOG , 0 ) ;
2004-10-10 02:34:18 +04:00
}
2004-09-20 16:31:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-07-14 01:04:56 +04:00
DEBUG ( 0 , ( " Failed to listen on %s:%u - %s \n " ,
2004-09-20 16:31:07 +04:00
sock_addr , * port , nt_errstr ( status ) ) ) ;
2005-01-14 04:32:56 +03:00
socket_destroy ( sock ) ;
2004-09-20 16:31:07 +04:00
return NULL ;
}
2005-01-14 04:32:56 +03:00
stream_socket = talloc_zero ( service , struct server_stream_socket ) ;
if ( ! stream_socket ) {
2005-01-27 10:08:20 +03:00
DEBUG ( 0 , ( " talloc(mem_ctx, struct server_stream_socket) failed \n " ) ) ;
2005-01-14 04:32:56 +03:00
socket_destroy ( sock ) ;
2004-07-14 01:04:56 +04:00
return NULL ;
}
/* we are only interested in read events on the listen socket */
2005-01-14 04:32:56 +03:00
fde . fd = socket_get_fd ( sock ) ;
2004-09-20 16:31:07 +04:00
fde . flags = EVENT_FD_READ ;
2005-01-14 04:32:56 +03:00
fde . private = stream_socket ;
fde . handler = server_accept_handler ;
stream_socket - > stream . ops = stream_ops ;
stream_socket - > service = service ;
stream_socket - > socket = sock ;
stream_socket - > event . ctx = service - > server - > event . ctx ;
2005-01-23 15:17:45 +03:00
stream_socket - > event . fde = event_add_fd ( stream_socket - > event . ctx ,
& fde , stream_socket ) ;
2005-01-14 04:32:56 +03:00
if ( ! stream_socket - > event . fde ) {
socket_destroy ( sock ) ;
2004-07-14 01:04:56 +04:00
return NULL ;
}
2005-01-14 04:32:56 +03:00
talloc_steal ( stream_socket , sock ) ;
2004-07-14 01:04:56 +04:00
2005-01-14 04:32:56 +03:00
if ( stream_socket - > stream . ops - > socket_init ) {
stream_socket - > stream . ops - > socket_init ( stream_socket ) ;
}
return stream_socket ;
2004-07-14 01:04:56 +04:00
}
2004-09-26 07:50:24 +04:00
/*
destructor that handles necessary event context changes
*/
2005-01-14 04:32:56 +03:00
static int server_connection_destructor ( void * ptr )
2004-09-26 07:50:24 +04:00
{
struct server_connection * conn = ptr ;
2005-01-14 04:32:56 +03:00
if ( conn - > stream_socket & &
conn - > stream_socket - > stream . ops - > close_connection ) {
/* don't remove this! the stream service needs to free it's data
* before we destroy the server_connection
*/
conn - > stream_socket - > stream . ops - > close_connection ( conn , " shutdown " ) ;
}
2004-09-26 07:50:24 +04:00
return 0 ;
}
2004-09-25 15:48:30 +04:00
struct server_connection * server_setup_connection ( struct event_context * ev ,
2005-01-14 04:32:56 +03:00
struct server_stream_socket * stream_socket ,
2004-09-25 15:48:30 +04:00
struct socket_context * sock ,
2004-11-03 13:09:48 +03:00
struct timeval t ,
2004-10-17 06:55:47 +04:00
servid_t server_id )
2004-07-15 12:59:07 +04:00
{
struct fd_event fde ;
struct timed_event idle ;
struct server_connection * srv_conn ;
2005-01-27 10:08:20 +03:00
srv_conn = talloc ( stream_socket , struct server_connection ) ;
2004-07-15 12:59:07 +04:00
if ( ! srv_conn ) {
2005-01-27 10:08:20 +03:00
DEBUG ( 0 , ( " talloc(mem_ctx, struct server_connection) failed \n " ) ) ;
2004-07-15 12:59:07 +04:00
return NULL ;
}
ZERO_STRUCTP ( srv_conn ) ;
fde . private = srv_conn ;
2004-09-20 16:31:07 +04:00
fde . fd = socket_get_fd ( sock ) ;
2004-07-15 12:59:07 +04:00
fde . flags = EVENT_FD_READ ;
fde . handler = server_io_handler ;
idle . private = srv_conn ;
2004-11-03 13:09:48 +03:00
idle . next_event = timeval_add ( & t , SERVER_DEFAULT_IDLE_TIME , 0 ) ;
2004-07-15 12:59:07 +04:00
idle . handler = server_idle_handler ;
srv_conn - > event . ctx = ev ;
srv_conn - > event . fde = & fde ;
srv_conn - > event . idle = & idle ;
2004-11-03 13:09:48 +03:00
srv_conn - > event . idle_time = timeval_set ( SERVER_DEFAULT_IDLE_TIME , 0 ) ;
2004-07-15 12:59:07 +04:00
2005-01-14 04:32:56 +03:00
srv_conn - > stream_socket = stream_socket ;
2004-09-20 16:31:07 +04:00
srv_conn - > socket = sock ;
2005-01-14 04:32:56 +03:00
srv_conn - > connection . id = server_id ;
2004-07-15 12:59:07 +04:00
2005-01-09 04:14:26 +03:00
/* create a server context and add it to out event
2004-07-15 12:59:07 +04:00
handling */
2005-01-14 04:32:56 +03:00
stream_socket - > stream . ops - > accept_connection ( srv_conn ) ;
2004-07-15 12:59:07 +04:00
/* accpect_connection() of the service may changed idle.next_event */
2005-01-23 15:17:45 +03:00
srv_conn - > event . fde = event_add_fd ( ev , & fde , srv_conn ) ;
srv_conn - > event . idle = event_add_timed ( ev , & idle , srv_conn ) ;
2005-01-23 14:49:15 +03:00
2005-01-14 04:32:56 +03:00
talloc_set_destructor ( srv_conn , server_connection_destructor ) ;
2004-09-26 07:50:24 +04:00
2004-09-24 07:34:55 +04:00
if ( ! socket_check_access ( sock , " smbd " , lp_hostsallow ( - 1 ) , lp_hostsdeny ( - 1 ) ) ) {
server_terminate_connection ( srv_conn , " denied by access rules " ) ;
return NULL ;
}
2004-10-17 14:04:49 +04:00
/* setup to receive internal messages on this connection */
2005-01-14 04:32:56 +03:00
srv_conn - > messaging . ctx = messaging_init ( srv_conn , srv_conn - > connection . id , ev ) ;
if ( ! srv_conn - > messaging . ctx ) {
server_terminate_connection ( srv_conn , " messaging_init() failed " ) ;
return NULL ;
}
2004-10-17 14:04:49 +04:00
2004-07-15 12:59:07 +04:00
return srv_conn ;
}
2004-07-14 01:04:56 +04:00
/*
close the socket and shutdown a server_context
*/
void server_terminate_connection ( struct server_connection * srv_conn , const char * reason )
{
2004-09-24 10:52:19 +04:00
DEBUG ( 2 , ( " server_terminate_connection \n " ) ) ;
2005-01-14 04:32:56 +03:00
srv_conn - > stream_socket - > service - > server - > model . ops - > terminate_connection ( srv_conn , reason ) ;
}
void server_accept_handler ( struct event_context * ev , struct fd_event * fde ,
struct timeval t , uint16_t flags )
{
2005-01-23 12:03:05 +03:00
struct server_stream_socket * stream_socket = talloc_get_type ( fde - > private ,
struct server_stream_socket ) ;
2005-01-14 04:32:56 +03:00
stream_socket - > service - > server - > model . ops - > accept_connection ( ev , fde , t , flags ) ;
2004-07-14 01:04:56 +04:00
}
2004-11-03 13:09:48 +03:00
void server_io_handler ( struct event_context * ev , struct fd_event * fde ,
struct timeval t , uint16_t flags )
2004-07-14 01:04:56 +04:00
{
2005-01-23 12:03:05 +03:00
struct server_connection * conn = talloc_get_type ( fde - > private ,
struct server_connection ) ;
2004-07-14 01:04:56 +04:00
2004-11-03 13:09:48 +03:00
conn - > event . idle - > next_event = timeval_sum ( & t , & conn - > event . idle_time ) ;
2004-07-15 11:44:46 +04:00
2004-07-14 01:04:56 +04:00
if ( flags & EVENT_FD_WRITE ) {
2005-01-14 04:32:56 +03:00
conn - > stream_socket - > stream . ops - > send_handler ( conn , t , flags ) ;
2004-07-15 14:16:40 +04:00
return ;
2004-07-14 01:04:56 +04:00
}
if ( flags & EVENT_FD_READ ) {
2005-01-14 04:32:56 +03:00
conn - > stream_socket - > stream . ops - > recv_handler ( conn , t , flags ) ;
2004-07-14 01:04:56 +04:00
}
}
2004-11-03 13:09:48 +03:00
void server_idle_handler ( struct event_context * ev , struct timed_event * idle ,
struct timeval t )
2004-07-14 01:04:56 +04:00
{
2005-01-23 12:03:05 +03:00
struct server_connection * conn = talloc_get_type ( idle - > private ,
struct server_connection ) ;
2004-07-14 01:04:56 +04:00
2005-01-11 05:18:42 +03:00
/* Not all services provide an idle handler */
2005-01-14 04:32:56 +03:00
if ( conn - > stream_socket - > stream . ops - > idle_handler ) {
conn - > event . idle - > next_event = timeval_sum ( & t , & conn - > event . idle_time ) ;
conn - > stream_socket - > stream . ops - > idle_handler ( conn , t ) ;
2005-01-11 05:18:42 +03:00
}
2004-07-14 01:04:56 +04:00
}
2005-01-14 04:32:56 +03:00
void server_terminate_task ( struct server_task * task , const char * reason )
{
task - > service - > server - > model . ops - > terminate_task ( task , reason ) ;
return ;
}
void server_run_task ( struct server_service * service , const struct server_task_ops * ops )
{
struct server_task * task ;
task = talloc_zero ( service , struct server_task ) ;
if ( ! task ) {
return ;
}
task - > service = service ;
task - > task . ops = ops ;
service - > server - > model . ops - > create_task ( task ) ;
return ;
}
2004-07-14 01:04:56 +04:00
/*
return the operations structure for a named backend of the specified type
*/
const struct server_service_ops * server_service_byname ( const char * name )
{
if ( strcmp ( " smb " , name ) = = 0 ) {
return smbsrv_get_ops ( ) ;
}
if ( strcmp ( " rpc " , name ) = = 0 ) {
return dcesrv_get_ops ( ) ;
}
2004-09-13 14:36:59 +04:00
if ( strcmp ( " ldap " , name ) = = 0 ) {
return ldapsrv_get_ops ( ) ;
}
2005-01-14 05:01:19 +03:00
if ( strcmp ( " winbind " , name ) = = 0 ) {
return winbind_get_ops ( ) ;
}
if ( strcmp ( " winbind_task " , name ) = = 0 ) {
return winbind_task_get_ops ( ) ;
}
2004-07-14 01:04:56 +04:00
return NULL ;
}
2004-11-15 01:23:23 +03:00
NTSTATUS register_server_service_ops ( const void * _ops )
2004-07-14 01:04:56 +04:00
{
return NT_STATUS_NOT_IMPLEMENTED ;
}
2004-10-29 11:29:26 +04:00
/*
cleanup temporary files . This is the new alternative to
TDB_CLEAR_IF_FIRST . Unfortunately TDB_CLEAR_IF_FIRST is not
efficient on unix systems due to the lack of scaling of the byte
range locking system . So instead of putting the burden on tdb to
2004-10-29 12:38:59 +04:00
cleanup tmp files , this function deletes them .
2004-10-29 11:29:26 +04:00
*/
void service_cleanup_tmp_files ( void )
{
2004-10-29 12:38:59 +04:00
char * path ;
DIR * dir ;
struct dirent * de ;
TALLOC_CTX * mem_ctx = talloc_init ( " service_cleanup_tmp_files " ) ;
path = smbd_tmp_path ( mem_ctx , NULL ) ;
dir = opendir ( path ) ;
if ( ! dir ) {
talloc_free ( mem_ctx ) ;
return ;
}
for ( de = readdir ( dir ) ; de ; de = readdir ( dir ) ) {
char * fname = talloc_asprintf ( mem_ctx , " %s/%s " , path , de - > d_name ) ;
int ret = unlink ( fname ) ;
if ( ret = = - 1 & &
2004-10-29 11:29:26 +04:00
errno ! = ENOENT & &
2004-10-29 12:38:59 +04:00
errno ! = EISDIR & &
errno ! = EISDIR ) {
DEBUG ( 0 , ( " Unabled to delete '%s' - %s \n " ,
fname , strerror ( errno ) ) ) ;
smb_panic ( " unable to cleanup tmp files " ) ;
2004-10-29 11:29:26 +04:00
}
2004-10-29 12:38:59 +04:00
talloc_free ( fname ) ;
2004-10-29 11:29:26 +04:00
}
2004-10-29 12:38:59 +04:00
closedir ( dir ) ;
talloc_free ( mem_ctx ) ;
2004-10-29 11:29:26 +04:00
}