0001-01-01 02:30:17 +02:30
# define OLD_NTDOMAIN 1
0001-01-01 02:30:17 +02:30
/*
Unix SMB / Netbios implementation .
Version 1.9 .
Main SMB server routines
0001-01-01 02:30:17 +02:30
Copyright ( C ) Andrew Tridgell 1992 - 1998
0001-01-01 02:30:17 +02:30
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"
pstring servicesf = CONFIGFILE ;
extern pstring debugf ;
0001-01-01 02:30:17 +02:30
extern fstring global_myworkgroup ;
0001-01-01 02:30:17 +02:30
extern pstring global_myname ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
int am_parent = 1 ;
0001-01-01 02:30:17 +02:30
/* the last message the was processed */
int last_message = - 1 ;
/* a useful macro to debug the last message processed */
# define LAST_MESSAGE() smb_fn_name(last_message)
extern int DEBUGLEVEL ;
extern pstring user_socket_options ;
0001-01-01 02:30:17 +02:30
# ifdef WITH_DFS
0001-01-01 02:30:17 +02:30
extern int dcelogin_atmost_once ;
0001-01-01 02:30:17 +02:30
# endif /* WITH_DFS */
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
extern fstring remote_machine ;
0001-01-01 02:30:17 +02:30
/* really we should have a top level context structure that has the
client file descriptor as an element . That would require a major rewrite : (
the following 2 functions are an alternative - they make the file
descriptor private to smbd
*/
0001-01-01 02:30:17 +02:30
static int server_fd = - 1 ;
0001-01-01 02:30:17 +02:30
int smbd_server_fd ( void )
{
return server_fd ;
}
void smbd_set_server_fd ( int fd )
{
server_fd = fd ;
client_setfd ( fd ) ;
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
when exiting , take the whole family
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
static void * dflt_sig ( void )
0001-01-01 02:30:17 +02:30
{
0001-01-01 02:30:17 +02:30
exit_server ( " caught signal " ) ;
return NULL ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
/****************************************************************************
Send a SIGTERM to our process group .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
static void killkids ( void )
0001-01-01 02:30:17 +02:30
{
0001-01-01 02:30:17 +02:30
if ( am_parent ) kill ( 0 , SIGTERM ) ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
/****************************************************************************
0001-01-01 02:30:17 +02:30
open the socket communication
0001-01-01 02:30:17 +02:30
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
static BOOL open_sockets_inetd ( void )
0001-01-01 02:30:17 +02:30
{
0001-01-01 02:30:17 +02:30
/* Started from inetd. fd 0 is the socket. */
/* We will abort gracefully when the client or remote system
goes away */
0001-01-01 02:30:17 +02:30
smbd_set_server_fd ( dup ( 0 ) ) ;
0001-01-01 02:30:17 +02:30
/* close our standard file descriptors */
close_low_fds ( ) ;
0001-01-01 02:30:17 +02:30
set_socket_options ( smbd_server_fd ( ) , " SO_KEEPALIVE " ) ;
set_socket_options ( smbd_server_fd ( ) , user_socket_options ) ;
0001-01-01 02:30:17 +02:30
return True ;
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
/****************************************************************************
open the socket communication
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
static BOOL open_sockets ( BOOL is_daemon , int port )
0001-01-01 02:30:17 +02:30
{
int num_interfaces = iface_count ( ) ;
int fd_listenset [ FD_SETSIZE ] ;
fd_set listen_set ;
int s ;
int i ;
if ( ! is_daemon ) {
return open_sockets_inetd ( ) ;
}
0001-01-01 02:30:17 +02:30
# ifdef HAVE_ATEXIT
0001-01-01 02:30:17 +02:30
{
static int atexit_set ;
if ( atexit_set = = 0 ) {
atexit_set = 1 ;
atexit ( killkids ) ;
}
}
0001-01-01 02:30:17 +02:30
# endif
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
/* Stop zombies */
CatchChild ( ) ;
FD_ZERO ( & listen_set ) ;
if ( lp_interfaces ( ) & & lp_bind_interfaces_only ( ) ) {
/* 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 .
*/
0001-01-01 02:30:17 +02:30
if ( num_interfaces > FD_SETSIZE ) {
0001-01-01 02:30:17 +02:30
DEBUG ( 0 , ( " open_sockets: Too many interfaces specified to bind to. Number was %d \
max can be % d \ n " ,
num_interfaces , FD_SETSIZE ) ) ;
return False ;
}
/* Now open a listen socket for each of the
interfaces . */
for ( i = 0 ; i < num_interfaces ; i + + ) {
struct in_addr * ifip = iface_n_ip ( i ) ;
if ( ifip = = NULL ) {
DEBUG ( 0 , ( " open_sockets: interface %d has NULL IP address ! \n " , i ) ) ;
continue ;
}
0001-01-01 02:30:17 +02:30
s = fd_listenset [ i ] = open_socket_in ( SOCK_STREAM , port , 0 , ifip - > s_addr , True ) ;
if ( s = = - 1 )
return False ;
/* ready to listen */
if ( listen ( s , 5 ) = = - 1 ) {
DEBUG ( 0 , ( " listen: %s \n " , strerror ( errno ) ) ) ;
close ( s ) ;
return False ;
}
0001-01-01 02:30:17 +02:30
FD_SET ( s , & listen_set ) ;
}
} else {
/* Just bind to 0.0.0.0 - accept connections
from anywhere . */
num_interfaces = 1 ;
/* open an incoming socket */
0001-01-01 02:30:17 +02:30
s = open_socket_in ( SOCK_STREAM , port , 0 ,
interpret_addr ( lp_socket_address ( ) ) , True ) ;
0001-01-01 02:30:17 +02:30
if ( s = = - 1 )
return ( False ) ;
0001-01-01 02:30:17 +02:30
/* ready to listen */
if ( listen ( s , 5 ) = = - 1 ) {
DEBUG ( 0 , ( " open_sockets: listen: %s \n " ,
strerror ( errno ) ) ) ;
close ( s ) ;
return False ;
}
0001-01-01 02:30:17 +02:30
fd_listenset [ 0 ] = s ;
FD_SET ( s , & listen_set ) ;
}
/* now accept incoming connections - forking a new process
for each incoming connection */
DEBUG ( 2 , ( " waiting for a connection \n " ) ) ;
while ( 1 ) {
fd_set lfds ;
int num ;
0001-01-01 02:30:17 +02:30
/* Free up temporary memory from the main smbd. */
lp_talloc_free ( ) ;
0001-01-01 02:30:17 +02:30
/* Ensure we respond to PING and DEBUG messages from the main smbd. */
message_dispatch ( ) ;
0001-01-01 02:30:17 +02:30
memcpy ( ( char * ) & lfds , ( char * ) & listen_set ,
sizeof ( listen_set ) ) ;
0001-01-01 02:30:17 +02:30
num = sys_select ( FD_SETSIZE , & lfds , NULL ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( num = = - 1 & & errno = = EINTR ) {
extern VOLATILE SIG_ATOMIC_T reload_after_sighup ;
/* check for sighup processing */
if ( reload_after_sighup ) {
unbecome_user ( ) ;
DEBUG ( 1 , ( " Reloading services after SIGHUP \n " ) ) ;
reload_services ( False ) ;
reload_after_sighup = False ;
}
0001-01-01 02:30:17 +02:30
continue ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
/* check if we need to reload services */
check_reload ( time ( NULL ) ) ;
0001-01-01 02:30:17 +02:30
/* Find the sockets that are read-ready -
accept on these . */
for ( ; num > 0 ; num - - ) {
struct sockaddr addr ;
int in_addrlen = sizeof ( addr ) ;
s = - 1 ;
for ( i = 0 ; i < num_interfaces ; i + + ) {
0001-01-01 02:30:17 +02:30
if ( FD_ISSET ( fd_listenset [ i ] , & lfds ) ) {
s = fd_listenset [ i ] ;
/* Clear this so we don't look
at it again . */
FD_CLR ( fd_listenset [ i ] , & lfds ) ;
0001-01-01 02:30:17 +02:30
break ;
}
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
smbd_set_server_fd ( accept ( s , & addr , & in_addrlen ) ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( smbd_server_fd ( ) = = - 1 & & errno = = EINTR )
0001-01-01 02:30:17 +02:30
continue ;
0001-01-01 02:30:17 +02:30
if ( smbd_server_fd ( ) = = - 1 ) {
0001-01-01 02:30:17 +02:30
DEBUG ( 0 , ( " open_sockets: accept: %s \n " ,
strerror ( errno ) ) ) ;
continue ;
}
0001-01-01 02:30:17 +02:30
if ( smbd_server_fd ( ) ! = - 1 & & sys_fork ( ) = = 0 ) {
0001-01-01 02:30:17 +02:30
/* Child code ... */
/* close the listening socket(s) */
for ( i = 0 ; i < num_interfaces ; i + + )
close ( fd_listenset [ i ] ) ;
/* close our standard file
descriptors */
close_low_fds ( ) ;
am_parent = 0 ;
0001-01-01 02:30:17 +02:30
set_socket_options ( smbd_server_fd ( ) , " SO_KEEPALIVE " ) ;
set_socket_options ( smbd_server_fd ( ) , user_socket_options ) ;
0001-01-01 02:30:17 +02:30
/* Reset global variables in util.c so
that client substitutions will be
done correctly in the process . */
reset_globals_after_fork ( ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
return True ;
}
/* The parent doesn't need this socket */
0001-01-01 02:30:17 +02:30
close ( smbd_server_fd ( ) ) ;
0001-01-01 02:30:17 +02:30
/* Force parent to check log size after
* spawning child . Fix from
* klausr @ ITAP . Physik . Uni - Stuttgart . De . The
* parent smbd will log to logserver . smb . It
* writes only two messages for each child
* started / finished . But each child writes ,
* say , 50 messages also in logserver . smb ,
* begining with the debug_count of the
* parent , before the child opens its own log
* file logserver . client . In a worst case
* scenario the size of logserver . smb would be
* checked after about 50 * 50 = 2500 messages
* ( ca . 100 kb ) .
* */
force_check_log_size ( ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
} /* end for num */
} /* end while 1 */
0001-01-01 02:30:17 +02:30
/* NOTREACHED return True; */
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
reload the services file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL reload_services ( BOOL test )
{
0001-01-01 02:30:17 +02:30
BOOL ret ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( lp_loaded ( ) ) {
pstring fname ;
pstrcpy ( fname , lp_configfile ( ) ) ;
0001-01-01 02:30:17 +02:30
if ( file_exist ( fname , NULL ) & & ! strcsequal ( fname , servicesf ) ) {
pstrcpy ( servicesf , fname ) ;
test = False ;
0001-01-01 02:30:17 +02:30
}
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
reopen_logs ( ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( test & & ! lp_file_list_changed ( ) )
return ( True ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
lp_killunused ( conn_snum_used ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
ret = lp_load ( servicesf , False , False , True ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
load_printers ( ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
/* perhaps the config filename is now set */
if ( ! test )
reload_services ( True ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
reopen_logs ( ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
load_interfaces ( ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
{
0001-01-01 02:30:17 +02:30
if ( smbd_server_fd ( ) ! = - 1 ) {
set_socket_options ( smbd_server_fd ( ) , " SO_KEEPALIVE " ) ;
set_socket_options ( smbd_server_fd ( ) , user_socket_options ) ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
reset_mangled_cache ( ) ;
0001-01-01 02:30:17 +02:30
reset_stat_cache ( ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
/* this forces service parameters to be flushed */
become_service ( NULL , True ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
return ( ret ) ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
0001-01-01 02:30:17 +02:30
Catch a sighup .
0001-01-01 02:30:17 +02:30
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
VOLATILE SIG_ATOMIC_T reload_after_sighup = False ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
static void sig_hup ( int sig )
{
0001-01-01 02:30:17 +02:30
BlockSignals ( True , SIGHUP ) ;
DEBUG ( 0 , ( " Got SIGHUP \n " ) ) ;
0001-01-01 02:30:17 +02:30
totally rewrote the async signal, notification and oplock notification
handling in Samba. This was needed due to several limitations and
races in the previous code - as a side effect the new code is much
cleaner :)
in summary:
- changed sys_select() to avoid a signal/select race condition. It is a
rare race but once we have signals doing notification and oplocks it
is important.
- changed our main processing loop to take advantage of the new
sys_select semantics
- split the notify code into implementaion dependent and general
parts. Added the following structure that defines an implementation:
struct cnotify_fns {
void * (*register_notify)(connection_struct *conn, char *path, uint32 flags);
BOOL (*check_notify)(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *data, time_t t);
void (*remove_notify)(void *data);
};
then I wrote two implementations, one using hash/poll (like our old
code) and the other using the new Linux kernel change notify. It
should be easy to add other change notify implementations by creating
a sructure of the above type.
- fixed a bug in change notify where we were returning the wrong error
code.
- rewrote the core change notify code to be much simpler
- moved to real-time signals for leases and change notify
Amazingly, it all seems to work. I was very surprised!
0001-01-01 02:30:17 +02:30
sys_select_signal ( ) ;
0001-01-01 02:30:17 +02:30
reload_after_sighup = True ;
BlockSignals ( False , SIGHUP ) ;
0001-01-01 02:30:17 +02:30
}
# if DUMP_CORE
/*******************************************************************
prepare to dump a core file - carefully !
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL dump_core ( void )
{
0001-01-01 02:30:17 +02:30
char * p ;
pstring dname ;
pstrcpy ( dname , debugf ) ;
if ( ( p = strrchr ( dname , ' / ' ) ) ) * p = 0 ;
pstrcat ( dname , " /corefiles " ) ;
mkdir ( dname , 0700 ) ;
sys_chown ( dname , getuid ( ) , getgid ( ) ) ;
chmod ( dname , 0700 ) ;
if ( chdir ( dname ) ) return ( False ) ;
umask ( ~ ( 0700 ) ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
# ifdef HAVE_GETRLIMIT
0001-01-01 02:30:17 +02:30
# ifdef RLIMIT_CORE
0001-01-01 02:30:17 +02:30
{
struct rlimit rlp ;
getrlimit ( RLIMIT_CORE , & rlp ) ;
rlp . rlim_cur = MAX ( 4 * 1024 * 1024 , rlp . rlim_cur ) ;
setrlimit ( RLIMIT_CORE , & rlp ) ;
getrlimit ( RLIMIT_CORE , & rlp ) ;
DEBUG ( 3 , ( " Core limits now %d %d \n " ,
( int ) rlp . rlim_cur , ( int ) rlp . rlim_max ) ) ;
}
0001-01-01 02:30:17 +02:30
# endif
# endif
0001-01-01 02:30:17 +02:30
DEBUG ( 0 , ( " Dumping core in %s \n " , dname ) ) ;
abort ( ) ;
return ( True ) ;
0001-01-01 02:30:17 +02:30
}
# endif
/****************************************************************************
exit the server
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void exit_server ( char * reason )
{
0001-01-01 02:30:17 +02:30
static int firsttime = 1 ;
extern char * last_inbuf ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( ! firsttime ) exit ( 0 ) ;
firsttime = 0 ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
unbecome_user ( ) ;
DEBUG ( 2 , ( " Closing connections \n " ) ) ;
conn_close_all ( ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
respond_to_all_remaining_local_messages ( ) ;
0001-01-01 02:30:17 +02:30
# ifdef WITH_DFS
0001-01-01 02:30:17 +02:30
if ( dcelogin_atmost_once ) {
dfs_unlogin ( ) ;
}
0001-01-01 02:30:17 +02:30
# endif
0001-01-01 02:30:17 +02:30
if ( ! reason ) {
int oldlevel = DEBUGLEVEL ;
DEBUGLEVEL = 10 ;
DEBUG ( 0 , ( " Last message was %s \n " , smb_fn_name ( last_message ) ) ) ;
if ( last_inbuf )
show_msg ( last_inbuf ) ;
DEBUGLEVEL = oldlevel ;
DEBUG ( 0 , ( " =============================================================== \n " ) ) ;
0001-01-01 02:30:17 +02:30
# if DUMP_CORE
0001-01-01 02:30:17 +02:30
if ( dump_core ( ) ) return ;
0001-01-01 02:30:17 +02:30
# endif
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
locking_end ( ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
DEBUG ( 3 , ( " Server exit (%s) \n " , ( reason ? reason : " " ) ) ) ;
exit ( 0 ) ;
0001-01-01 02:30:17 +02:30
}
/****************************************************************************
initialise connect , service and file structs
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
static void init_structs ( void )
0001-01-01 02:30:17 +02:30
{
0001-01-01 02:30:17 +02:30
/*
* Set the machine NETBIOS name if not already
* set from the config file .
*/
if ( ! * global_myname ) {
char * p ;
fstrcpy ( global_myname , myhostname ( ) ) ;
p = strchr ( global_myname , ' . ' ) ;
if ( p )
* p = 0 ;
}
strupper ( global_myname ) ;
0001-01-01 02:30:17 +02:30
conn_init ( ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
file_init ( ) ;
0001-01-01 02:30:17 +02:30
/* for RPC pipes */
init_rpc_pipe_hnd ( ) ;
/* for LSA handles */
init_lsa_policy_hnd ( ) ;
0001-01-01 02:30:17 +02:30
/* for SPOOLSS handles */
init_printer_hnd ( ) ;
0001-01-01 02:30:17 +02:30
init_dptrs ( ) ;
0001-01-01 02:30:17 +02:30
secrets_init ( ) ;
0001-01-01 02:30:17 +02:30
}
/****************************************************************************
usage on the program
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
static void usage ( char * pname )
0001-01-01 02:30:17 +02:30
{
0001-01-01 02:30:17 +02:30
printf ( " Usage: %s [-DaoPh?V] [-d debuglevel] [-l log basename] [-p port] \n " , pname ) ;
0001-01-01 02:30:17 +02:30
printf ( " [-O socket options] [-s services file] \n " ) ;
0001-01-01 02:30:17 +02:30
printf ( " \t -D Become a daemon \n " ) ;
printf ( " \t -a Append to log file (default) \n " ) ;
printf ( " \t -o Overwrite log file, don't append \n " ) ;
printf ( " \t -h Print usage \n " ) ;
printf ( " \t -? Print usage \n " ) ;
printf ( " \t -V Print version \n " ) ;
printf ( " \t -d debuglevel Set the debuglevel \n " ) ;
0001-01-01 02:30:17 +02:30
printf ( " \t -l log basename. Basename for log/debug files \n " ) ;
0001-01-01 02:30:17 +02:30
printf ( " \t -p port Listen on the specified port \n " ) ;
printf ( " \t -O socket options Socket options \n " ) ;
0001-01-01 02:30:17 +02:30
printf ( " \t -s services file. Filename of services file \n " ) ;
printf ( " \n " ) ;
0001-01-01 02:30:17 +02:30
}
/****************************************************************************
main program
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
int main ( int argc , char * argv [ ] )
0001-01-01 02:30:17 +02:30
{
0001-01-01 02:30:17 +02:30
extern BOOL append_log ;
/* shall I run as a daemon */
BOOL is_daemon = False ;
0001-01-01 02:30:17 +02:30
BOOL specified_logfile = False ;
0001-01-01 02:30:17 +02:30
int port = SMB_PORT ;
int opt ;
extern char * optarg ;
0001-01-01 02:30:17 +02:30
# ifdef HAVE_SET_AUTH_PARAMETERS
0001-01-01 02:30:17 +02:30
set_auth_parameters ( argc , argv ) ;
0001-01-01 02:30:17 +02:30
# endif
0001-01-01 02:30:17 +02:30
/* this is for people who can't start the program correctly */
while ( argc > 1 & & ( * argv [ 1 ] ! = ' - ' ) ) {
argv + + ;
argc - - ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
while ( EOF ! = ( opt = getopt ( argc , argv , " O:l:s:d:Dp:h?Vaof: " ) ) )
0001-01-01 02:30:17 +02:30
switch ( opt ) {
case ' O ' :
pstrcpy ( user_socket_options , optarg ) ;
break ;
case ' s ' :
pstrcpy ( servicesf , optarg ) ;
break ;
case ' l ' :
0001-01-01 02:30:17 +02:30
specified_logfile = True ;
0001-01-01 02:30:17 +02:30
pstrcpy ( debugf , optarg ) ;
break ;
case ' a ' :
0001-01-01 02:30:17 +02:30
append_log = True ;
break ;
case ' o ' :
append_log = False ;
0001-01-01 02:30:17 +02:30
break ;
case ' D ' :
is_daemon = True ;
break ;
case ' d ' :
if ( * optarg = = ' A ' )
DEBUGLEVEL = 10000 ;
else
DEBUGLEVEL = atoi ( optarg ) ;
break ;
case ' p ' :
port = atoi ( optarg ) ;
break ;
case ' h ' :
0001-01-01 02:30:17 +02:30
case ' ? ' :
0001-01-01 02:30:17 +02:30
usage ( argv [ 0 ] ) ;
exit ( 0 ) ;
break ;
0001-01-01 02:30:17 +02:30
case ' V ' :
printf ( " Version %s \n " , VERSION ) ;
exit ( 0 ) ;
break ;
0001-01-01 02:30:17 +02:30
default :
0001-01-01 02:30:17 +02:30
DEBUG ( 0 , ( " Incorrect program usage - are you sure the command line is correct? \n " ) ) ;
0001-01-01 02:30:17 +02:30
usage ( argv [ 0 ] ) ;
exit ( 1 ) ;
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
# ifdef HAVE_SETLUID
/* needed for SecureWare on SCO */
setluid ( 0 ) ;
# endif
/*
* gain_root_privilege uses an assert than will cause a core
* dump if euid ! = 0. Ensure this is the case .
*/
if ( geteuid ( ) ! = ( uid_t ) 0 ) {
fprintf ( stderr , " %s: Version %s : Must have effective user id of zero to run. \n " , argv [ 0 ] , VERSION ) ;
exit ( 1 ) ;
}
append_log = True ;
TimeInit ( ) ;
0001-01-01 02:30:17 +02:30
if ( ! specified_logfile ) {
slprintf ( debugf , sizeof ( debugf ) , " %s/log.smbd " , LOGFILEBASE ) ;
}
0001-01-01 02:30:17 +02:30
pstrcpy ( remote_machine , " smb " ) ;
setup_logging ( argv [ 0 ] , False ) ;
charset_initialise ( ) ;
/* we want to re-seed early to prevent time delays causing
client problems at a later date . ( tridge ) */
generate_random_buffer ( NULL , 0 , False ) ;
/* make absolutely sure we run as root - to handle cases where people
are crazy enough to have it setuid */
gain_root_privilege ( ) ;
gain_root_group_privilege ( ) ;
fault_setup ( ( void ( * ) ( void * ) ) exit_server ) ;
CatchSignal ( SIGTERM , SIGNAL_CAST dflt_sig ) ;
/* we are never interested in SIGPIPE */
BlockSignals ( True , SIGPIPE ) ;
# if defined(SIGFPE)
/* we are never interested in SIGFPE */
BlockSignals ( True , SIGFPE ) ;
# endif
0001-01-01 02:30:17 +02:30
# if defined(SIGUSR2)
/* We are no longer interested in USR2 */
BlockSignals ( True , SIGUSR2 ) ;
# endif
0001-01-01 02:30:17 +02:30
/* we want total control over the permissions on created files,
so set our umask to 0 */
umask ( 0 ) ;
0001-01-01 02:30:17 +02:30
init_sec_ctx ( ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
reopen_logs ( ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
DEBUG ( 1 , ( " smbd version %s started. \n " , VERSION ) ) ;
0001-01-01 02:30:17 +02:30
DEBUGADD ( 1 , ( " Copyright Andrew Tridgell 1992-1998 \n " ) ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
DEBUG ( 2 , ( " uid=%d gid=%d euid=%d egid=%d \n " ,
( int ) getuid ( ) , ( int ) getgid ( ) , ( int ) geteuid ( ) , ( int ) getegid ( ) ) ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( sizeof ( uint16 ) < 2 | | sizeof ( uint32 ) < 4 ) {
DEBUG ( 0 , ( " ERROR: Samba is not configured correctly for the word size on your machine \n " ) ) ;
exit ( 1 ) ;
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
/*
* Do this before reload_services .
*/
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( ! reload_services ( False ) )
return ( - 1 ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
init_structs ( ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
# ifdef WITH_PROFILE
if ( ! profile_setup ( False ) ) {
DEBUG ( 0 , ( " ERROR: failed to setup profiling \n " ) ) ;
return - 1 ;
}
# endif
0001-01-01 02:30:17 +02:30
# ifdef WITH_SSL
0001-01-01 02:30:17 +02:30
{
extern BOOL sslEnabled ;
sslEnabled = lp_ssl_enabled ( ) ;
if ( sslEnabled )
sslutil_init ( True ) ;
}
0001-01-01 02:30:17 +02:30
# endif /* WITH_SSL */
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
codepage_initialise ( lp_client_code_page ( ) ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
fstrcpy ( global_myworkgroup , lp_workgroup ( ) ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
CatchSignal ( SIGHUP , SIGNAL_CAST sig_hup ) ;
DEBUG ( 3 , ( " loaded services \n " ) ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( ! is_daemon & & ! is_a_socket ( 0 ) ) {
DEBUG ( 0 , ( " standard input is not a socket, assuming -D option \n " ) ) ;
is_daemon = True ;
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( is_daemon ) {
DEBUG ( 3 , ( " Becoming a daemon. \n " ) ) ;
become_daemon ( ) ;
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( ! directory_exist ( lp_lockdir ( ) , NULL ) ) {
mkdir ( lp_lockdir ( ) , 0755 ) ;
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( is_daemon ) {
pidfile_create ( " smbd " ) ;
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( ! message_init ( ) ) {
exit ( 1 ) ;
}
0001-01-01 02:30:17 +02:30
/* Setup the main smbd so that we can get messages. */
if ( lp_status ( - 1 ) ) {
claim_connection ( NULL , " " , MAXSTATUS , True ) ;
}
0001-01-01 02:30:17 +02:30
/* Attempt to migrate from an old 2.0.x machine account file. */
if ( ! migrate_from_old_password_file ( global_myworkgroup ) ) {
DEBUG ( 0 , ( " Failed to migrate from old MAC file. \n " ) ) ;
}
0001-01-01 02:30:17 +02:30
if ( ! open_sockets ( is_daemon , port ) )
0001-01-01 02:30:17 +02:30
exit ( 1 ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
/*
0001-01-01 02:30:17 +02:30
* everything after this point is run after the fork ( )
0001-01-01 02:30:17 +02:30
*/
0001-01-01 02:30:17 +02:30
if ( ! locking_init ( 0 ) ) {
0001-01-01 02:30:17 +02:30
exit ( 1 ) ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( ! print_backend_init ( ) ) {
exit ( 1 ) ;
}
0001-01-01 02:30:17 +02:30
if ( ! initialize_password_db ( False ) ) {
0001-01-01 02:30:17 +02:30
exit ( 1 ) ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
/* possibly reload the services file. */
reload_services ( True ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( ! pdb_generate_sam_sid ( ) ) {
0001-01-01 02:30:17 +02:30
DEBUG ( 0 , ( " ERROR: Samba cannot create a SAM SID. \n " ) ) ;
exit ( 1 ) ;
}
0001-01-01 02:30:17 +02:30
if ( * lp_rootdir ( ) ) {
if ( sys_chroot ( lp_rootdir ( ) ) = = 0 )
DEBUG ( 2 , ( " Changed root to %s \n " , lp_rootdir ( ) ) ) ;
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
/* Setup oplocks */
if ( ! init_oplocks ( ) ) {
0001-01-01 02:30:17 +02:30
exit ( 1 ) ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
totally rewrote the async signal, notification and oplock notification
handling in Samba. This was needed due to several limitations and
races in the previous code - as a side effect the new code is much
cleaner :)
in summary:
- changed sys_select() to avoid a signal/select race condition. It is a
rare race but once we have signals doing notification and oplocks it
is important.
- changed our main processing loop to take advantage of the new
sys_select semantics
- split the notify code into implementaion dependent and general
parts. Added the following structure that defines an implementation:
struct cnotify_fns {
void * (*register_notify)(connection_struct *conn, char *path, uint32 flags);
BOOL (*check_notify)(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *data, time_t t);
void (*remove_notify)(void *data);
};
then I wrote two implementations, one using hash/poll (like our old
code) and the other using the new Linux kernel change notify. It
should be easy to add other change notify implementations by creating
a sructure of the above type.
- fixed a bug in change notify where we were returning the wrong error
code.
- rewrote the core change notify code to be much simpler
- moved to real-time signals for leases and change notify
Amazingly, it all seems to work. I was very surprised!
0001-01-01 02:30:17 +02:30
/* Setup change notify */
if ( ! init_change_notify ( ) ) {
exit ( 1 ) ;
}
0001-01-01 02:30:17 +02:30
smbd_process ( ) ;
exit_server ( " normal exit " ) ;
return ( 0 ) ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
# undef OLD_NTDOMAIN