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"
2007-09-08 16:42:09 +04:00
# include "param/param.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 ) {
2007-12-03 23:25:17 +03:00
status = smbsrv_init_smb_connection ( smb_conn , smb_conn - > lp_ctx ) ;
2005-11-18 11:44:36 +03:00
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 :
2007-12-03 23:25:17 +03:00
status = smbsrv_init_smb_connection ( smb_conn , smb_conn - > lp_ctx ) ;
2005-11-18 11:44:36 +03:00
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 :
2007-12-03 23:25:17 +03:00
if ( lp_srv_maxprotocol ( smb_conn - > lp_ctx ) < 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-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
2008-02-21 20:09:47 +03:00
smb_conn - > lp_ctx = conn - > lp_ctx ;
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
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
2008-05-26 07:12:31 +04:00
irpc_add_name ( conn - > msg_ctx , " smb_server " ) ;
2007-12-10 20:41:55 +03:00
if ( ! NT_STATUS_IS_OK ( share_get_context_by_name ( smb_conn , lp_share_backend ( smb_conn - > lp_ctx ) ,
2008-04-17 14:23:44 +04:00
smb_conn - > connection - > event . ctx ,
2007-12-14 00:46:55 +03:00
smb_conn - > lp_ctx , & ( smb_conn - > share_context ) ) ) ) {
2006-07-23 22:43:07 +04:00
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
*/
2008-12-29 22:24:57 +03:00
_PUBLIC_ NTSTATUS smbsrv_add_socket ( struct tevent_context * event_context ,
2007-12-03 02:28:22 +03:00
struct loadparm_context * lp_ctx ,
2005-01-30 03:54:57 +03:00
const struct model_ops * model_ops ,
const char * address )
2005-01-14 04:32:56 +03:00
{
2007-12-03 02:28:22 +03:00
const char * * ports = lp_smb_ports ( lp_ctx ) ;
2005-01-30 03:54:57 +03:00
int i ;
NTSTATUS status ;
for ( i = 0 ; ports [ i ] ; i + + ) {
uint16_t port = atoi ( ports [ i ] ) ;
if ( port = = 0 ) continue ;
2008-01-06 04:03:43 +03:00
status = stream_setup_socket ( event_context , lp_ctx ,
model_ops , & smb_stream_ops ,
2007-12-06 18:54:34 +03:00
" ipv4 " , address , & port ,
lp_socket_options ( lp_ctx ) ,
NULL ) ;
2005-01-30 03:54:57 +03:00
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 */
2008-04-17 14:23:44 +04:00
talloc_free ( samdb_connect ( task , task - > event_ctx , task - > lp_ctx , NULL ) ) ;
2007-07-04 09:16:19 +04:00
}
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] " ) ;
2007-12-03 02:28:22 +03:00
if ( lp_interfaces ( task - > lp_ctx ) & & lp_bind_interfaces_only ( task - > lp_ctx ) ) {
2007-12-12 00:23:14 +03:00
int num_interfaces ;
2005-01-30 03:54:57 +03:00
int i ;
2007-12-12 00:23:14 +03:00
struct interface * ifaces ;
2007-12-12 00:23:20 +03:00
load_interfaces ( task , lp_interfaces ( task - > lp_ctx ) , & ifaces ) ;
2007-12-12 00:23:14 +03:00
num_interfaces = iface_count ( ifaces ) ;
2005-01-30 03:54:57 +03:00
/* 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 + + ) {
2007-12-12 00:23:14 +03:00
const char * address = iface_n_ip ( ifaces , i ) ;
2007-12-03 02:28:22 +03:00
status = smbsrv_add_socket ( task - > event_ctx , task - > lp_ctx , task - > model_ops , address ) ;
2006-03-09 23:36:01 +03:00
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) */
2007-12-03 02:28:22 +03:00
status = smbsrv_add_socket ( task - > event_ctx , task - > lp_ctx , task - > model_ops ,
lp_socket_address ( task - > lp_ctx ) ) ;
2006-03-09 23:36:01 +03:00
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 " ) ;
}
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 )
{
2008-02-21 18:21:32 +03:00
share_init ( ) ;
2008-02-04 13:58:29 +03:00
return register_server_service ( " smb " , smbsrv_task_init ) ;
2004-02-03 08:47:36 +03:00
}