2004-02-03 08:47:36 +03:00
/*
Unix SMB / CIFS implementation .
process incoming packets - main loop
2005-11-17 11:00:48 +03:00
Copyright ( C ) Andrew Tridgell 2004 - 2005
Copyright ( C ) Stefan Metzmacher 2004 - 2005
2004-02-03 08:47:36 +03:00
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-02-03 08:47:36 +03: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-02-03 08:47:36 +03:00
*/
# include "includes.h"
2006-03-09 23:36:01 +03:00
# include "smbd/service_task.h"
2005-01-30 03:54:57 +03:00
# include "smbd/service_stream.h"
2006-03-07 16:22:00 +03:00
# include "smbd/service.h"
2004-11-02 10:18:24 +03:00
# include "smb_server/smb_server.h"
2006-04-28 05:55:17 +04:00
# include "smb_server/service_smb_proto.h"
2005-07-10 05:08:10 +04:00
# include "lib/messaging/irpc.h"
2005-11-09 13:51:26 +03:00
# include "lib/stream/packet.h"
2005-11-18 17:13:49 +03:00
# include "libcli/smb2/smb2.h"
2005-12-28 18:38:36 +03:00
# include "smb_server/smb2/smb2_server.h"
2006-03-07 14:07:23 +03:00
# include "system/network.h"
2006-08-17 17:37:04 +04:00
# include "lib/socket/netif.h"
2006-07-23 22:43:07 +04:00
# include "param/share.h"
2007-07-04 09:16:19 +04:00
# include "dsdb/samdb/samdb.h"
2004-02-03 08:47:36 +03:00
2005-11-18 11:44:36 +03:00
static NTSTATUS smbsrv_recv_generic_request ( void * private , DATA_BLOB blob )
{
NTSTATUS status ;
struct smbsrv_connection * smb_conn = talloc_get_type ( private , struct smbsrv_connection ) ;
uint32_t protocol_version ;
/* see if its a special NBT packet */
if ( CVAL ( blob . data , 0 ) ! = 0 ) {
status = smbsrv_init_smb_connection ( smb_conn ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
packet_set_callback ( smb_conn - > packet , smbsrv_recv_smb_request ) ;
return smbsrv_recv_smb_request ( smb_conn , blob ) ;
}
if ( blob . length < ( NBT_HDR_SIZE + MIN_SMB_SIZE ) ) {
2005-11-30 05:08:15 +03:00
DEBUG ( 2 , ( " Invalid SMB packet length count %ld \n " , ( long ) blob . length ) ) ;
2005-11-18 11:44:36 +03:00
smbsrv_terminate_connection ( smb_conn , " Invalid SMB packet " ) ;
return NT_STATUS_OK ;
}
protocol_version = IVAL ( blob . data , NBT_HDR_SIZE ) ;
switch ( protocol_version ) {
case SMB_MAGIC :
status = smbsrv_init_smb_connection ( smb_conn ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
packet_set_callback ( smb_conn - > packet , smbsrv_recv_smb_request ) ;
return smbsrv_recv_smb_request ( smb_conn , blob ) ;
2005-11-18 17:13:49 +03:00
case SMB2_MAGIC :
2006-06-22 21:06:36 +04:00
if ( lp_srv_maxprotocol ( ) < PROTOCOL_SMB2 ) break ;
2005-11-18 17:13:49 +03:00
status = smbsrv_init_smb2_connection ( smb_conn ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
packet_set_callback ( smb_conn - > packet , smbsrv_recv_smb2_request ) ;
return smbsrv_recv_smb2_request ( smb_conn , blob ) ;
2005-11-18 11:44:36 +03:00
}
2006-03-06 17:19:11 +03:00
DEBUG ( 2 , ( " Invalid SMB packet: protocol prefix: 0x%08X \n " , protocol_version ) ) ;
2005-11-18 11:44:36 +03:00
smbsrv_terminate_connection ( smb_conn , " NON-SMB packet " ) ;
return NT_STATUS_OK ;
}
2004-02-03 08:47:36 +03:00
/*
close the socket and shutdown a server_context
*/
2004-07-14 01:04:56 +04:00
void smbsrv_terminate_connection ( struct smbsrv_connection * smb_conn , const char * reason )
2004-02-03 08:47:36 +03:00
{
2005-12-08 13:23:56 +03:00
stream_terminate_connection ( smb_conn - > connection , reason ) ;
2004-06-24 03:44:50 +04:00
}
2004-02-03 08:47:36 +03:00
/*
called when a SMB socket becomes readable
*/
2005-02-03 14:25:52 +03:00
static void smbsrv_recv ( struct stream_connection * conn , uint16_t flags )
2004-02-03 08:47:36 +03:00
{
2005-12-08 13:23:56 +03:00
struct smbsrv_connection * smb_conn = talloc_get_type ( conn - > private ,
struct smbsrv_connection ) ;
2004-07-14 01:04:56 +04:00
DEBUG ( 10 , ( " smbsrv_recv \n " ) ) ;
2005-11-09 13:51:26 +03:00
packet_recv ( smb_conn - > packet ) ;
2004-02-03 08:47:36 +03:00
/* free up temporary memory */
lp_talloc_free ( ) ;
2004-07-14 01:04:56 +04:00
}
/*
called when a SMB socket becomes writable
*/
2005-02-03 14:25:52 +03:00
static void smbsrv_send ( struct stream_connection * conn , uint16_t flags )
2004-07-14 01:04:56 +04:00
{
2005-11-09 16:42:56 +03:00
struct smbsrv_connection * smb_conn = talloc_get_type ( conn - > private ,
struct smbsrv_connection ) ;
packet_queue_run ( smb_conn - > packet ) ;
2004-07-14 01:04:56 +04:00
}
2005-11-09 13:51:26 +03:00
/*
handle socket recv errors
*/
static void smbsrv_recv_error ( void * private , NTSTATUS status )
{
struct smbsrv_connection * smb_conn = talloc_get_type ( private , struct smbsrv_connection ) ;
smbsrv_terminate_connection ( smb_conn , nt_errstr ( status ) ) ;
}
2004-02-03 08:47:36 +03:00
/*
initialise a server_context from a open socket and register a event handler
for reading from that socket
*/
2005-01-30 03:54:57 +03:00
static void smbsrv_accept ( struct stream_connection * conn )
2004-02-03 08:47:36 +03:00
{
2004-06-29 11:40:14 +04:00
struct smbsrv_connection * smb_conn ;
2004-02-03 08:47:36 +03:00
2004-07-14 01:04:56 +04:00
DEBUG ( 5 , ( " smbsrv_accept \n " ) ) ;
2004-02-03 08:47:36 +03:00
2005-01-27 10:08:20 +03:00
smb_conn = talloc_zero ( conn , struct smbsrv_connection ) ;
2005-12-08 13:23:56 +03:00
if ( ! smb_conn ) {
stream_terminate_connection ( conn , " out of memory " ) ;
return ;
}
2004-02-03 08:47:36 +03:00
2005-11-09 13:51:26 +03:00
smb_conn - > packet = packet_init ( smb_conn ) ;
2005-12-08 13:23:56 +03:00
if ( ! smb_conn - > packet ) {
smbsrv_terminate_connection ( smb_conn , " out of memory " ) ;
2005-11-10 03:36:53 +03:00
return ;
}
2005-11-09 13:51:26 +03:00
packet_set_private ( smb_conn - > packet , smb_conn ) ;
packet_set_socket ( smb_conn - > packet , conn - > socket ) ;
2005-11-18 11:44:36 +03:00
packet_set_callback ( smb_conn - > packet , smbsrv_recv_generic_request ) ;
2005-11-09 13:51:26 +03:00
packet_set_full_request ( smb_conn - > packet , packet_full_request_nbt ) ;
packet_set_error_handler ( smb_conn - > packet , smbsrv_recv_error ) ;
packet_set_event_context ( smb_conn - > packet , conn - > event . ctx ) ;
2005-11-14 06:45:57 +03:00
packet_set_fde ( smb_conn - > packet , conn - > event . fde ) ;
packet_set_serialise ( smb_conn - > packet ) ;
2005-11-09 13:51:26 +03:00
2004-07-14 01:04:56 +04:00
smb_conn - > connection = conn ;
2005-01-30 03:54:57 +03:00
conn - > private = smb_conn ;
2005-07-10 05:08:10 +04:00
irpc_add_name ( conn - > msg_ctx , " smb_server " ) ;
2005-07-19 07:58:44 +04:00
2006-03-26 15:32:27 +04:00
smb_conn - > statistics . connect_time = timeval_current ( ) ;
2005-07-19 07:58:44 +04:00
smbsrv_management_init ( smb_conn ) ;
2006-07-23 22:43:07 +04:00
if ( ! NT_STATUS_IS_OK ( share_get_context ( smb_conn , & ( smb_conn - > share_context ) ) ) ) {
smbsrv_terminate_connection ( smb_conn , " share_init failed! " ) ;
return ;
}
2004-07-14 01:04:56 +04:00
}
2005-01-30 03:54:57 +03:00
static const struct stream_server_ops smb_stream_ops = {
2006-03-09 20:48:41 +03:00
. name = " smbsrv " ,
2004-07-14 01:04:56 +04:00
. accept_connection = smbsrv_accept ,
. recv_handler = smbsrv_recv ,
. send_handler = smbsrv_send ,
2005-01-14 04:32:56 +03:00
} ;
2005-01-30 03:54:57 +03:00
/*
setup a listening socket on all the SMB ports for a particular address
*/
static NTSTATUS smb_add_socket ( struct event_context * event_context ,
const struct model_ops * model_ops ,
const char * address )
2005-01-14 04:32:56 +03:00
{
2005-01-30 03:54:57 +03:00
const char * * ports = lp_smb_ports ( ) ;
int i ;
NTSTATUS status ;
for ( i = 0 ; ports [ i ] ; i + + ) {
uint16_t port = atoi ( ports [ i ] ) ;
if ( port = = 0 ) continue ;
status = stream_setup_socket ( event_context , model_ops , & smb_stream_ops ,
" ipv4 " , address , & port , NULL ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
}
return NT_STATUS_OK ;
2005-01-14 04:32:56 +03:00
}
2007-07-04 09:16:19 +04:00
/*
pre - open some of our ldb databases , to prevent an explosion of memory usage
when we fork
*/
static void smbsrv_preopen_ldb ( struct task_server * task )
{
/* yes, this looks strange. It is a hack to preload the
schema . I ' d like to share most of the ldb context with the
child too . That will come later */
talloc_free ( samdb_connect ( task , NULL ) ) ;
}
2005-01-30 03:54:57 +03:00
/*
2006-03-09 23:36:01 +03:00
open the smb server sockets
2005-01-30 03:54:57 +03:00
*/
2006-03-09 23:36:01 +03:00
static void smbsrv_task_init ( struct task_server * task )
2005-01-30 03:54:57 +03:00
{
NTSTATUS status ;
2004-07-14 01:04:56 +04:00
2006-03-09 23:36:01 +03:00
task_server_set_title ( task , " task[smbsrv] " ) ;
2005-01-30 03:54:57 +03:00
if ( lp_interfaces ( ) & & lp_bind_interfaces_only ( ) ) {
int num_interfaces = iface_count ( ) ;
int i ;
/* We have been given an interfaces line, and been
told to only bind to those interfaces . Create a
socket per interface and bind to only these .
*/
for ( i = 0 ; i < num_interfaces ; i + + ) {
2005-02-10 06:22:47 +03:00
const char * address = iface_n_ip ( i ) ;
2006-03-09 23:36:01 +03:00
status = smb_add_socket ( task - > event_ctx , task - > model_ops , address ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) goto failed ;
2005-01-30 03:54:57 +03:00
}
} else {
/* Just bind to lp_socket_address() (usually 0.0.0.0) */
2006-03-09 23:36:01 +03:00
status = smb_add_socket ( task - > event_ctx , task - > model_ops , lp_socket_address ( ) ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) goto failed ;
2005-01-30 03:54:57 +03:00
}
2007-07-04 09:16:19 +04:00
smbsrv_preopen_ldb ( task ) ;
2006-03-09 23:36:01 +03:00
return ;
failed :
task_server_terminate ( task , " Failed to startup smb server task " ) ;
}
/*
called on startup of the smb server service It ' s job is to start
listening on all configured sockets
*/
static NTSTATUS smbsrv_init ( struct event_context * event_context ,
const struct model_ops * model_ops )
{
return task_server_startup ( event_context , model_ops , smbsrv_task_init ) ;
2004-07-14 01:04:56 +04:00
}
2005-01-30 03:54:57 +03:00
/* called at smbd startup - register ourselves as a server service */
2004-07-14 01:04:56 +04:00
NTSTATUS server_service_smb_init ( void )
{
2005-01-30 03:54:57 +03:00
return register_server_service ( " smb " , smbsrv_init ) ;
2004-02-03 08:47:36 +03:00
}