1996-06-04 10:42:03 +04:00
/*
Unix SMB / Netbios implementation .
Version 1.9 .
NBT netbios routines and daemon - version 2
Copyright ( C ) Andrew Tridgell 1994 - 1995
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 .
Revision History :
14 jan 96 : lkcl @ pires . co . uk
added multiple workgroup domain master support
*/
# include "includes.h"
extern int DEBUGLEVEL ;
extern pstring debugf ;
pstring servicesf = CONFIGFILE ;
extern pstring scope ;
int ClientNMB = - 1 ;
int ClientDGRAM = - 1 ;
extern pstring myhostname ;
static pstring host_file ;
extern pstring myname ;
/* are we running as a daemon ? */
static BOOL is_daemon = False ;
/* what server type are we currently */
time_t StartupTime = 0 ;
1996-06-06 15:43:09 +04:00
extern struct in_addr ipzero ;
1996-06-04 10:42:03 +04:00
1996-06-08 08:41:51 +04:00
/****************************************************************************
1996-07-04 23:19:26 +04:00
catch a sigterm
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-06-08 08:41:51 +04:00
static int sig_term ( )
{
1996-08-15 19:11:34 +04:00
BlockSignals ( True , SIGTERM ) ;
1996-06-08 08:41:51 +04:00
DEBUG ( 0 , ( " Got SIGTERM: going down... \n " ) ) ;
1996-07-09 22:11:47 +04:00
/* write out wins.dat file if samba is a WINS server */
1996-06-08 08:41:51 +04:00
dump_names ( ) ;
/* remove all samba names, with wins server if necessary. */
remove_my_names ( ) ;
1996-06-29 22:49:20 +04:00
/* announce all server entries as 0 time-to-live, 0 type */
1996-07-09 22:11:47 +04:00
/* XXXX don't care if we never receive a response back... yet */
1996-06-29 22:49:20 +04:00
remove_my_servers ( ) ;
1996-06-08 08:41:51 +04:00
/* XXXX other things: if we are a master browser, force an election? */
exit ( 0 ) ;
}
1996-06-04 10:42:03 +04:00
/****************************************************************************
catch a sighup
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int sig_hup ( void )
{
1996-08-15 19:11:34 +04:00
BlockSignals ( True , SIGHUP ) ;
1996-06-04 10:42:03 +04:00
DEBUG ( 0 , ( " Got SIGHUP (reload not implemented) \n " ) ) ;
dump_names ( ) ;
reload_services ( True ) ;
1996-08-01 21:49:40 +04:00
set_samba_nb_type ( ) ;
1996-08-15 19:11:34 +04:00
BlockSignals ( False , SIGHUP ) ;
1996-06-04 10:42:03 +04:00
# ifndef DONT_REINSTALL_SIG
signal ( SIGHUP , SIGNAL_CAST sig_hup ) ;
# endif
return ( 0 ) ;
}
/****************************************************************************
catch a sigpipe
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int sig_pipe ( void )
{
1996-08-15 19:11:34 +04:00
BlockSignals ( True , SIGPIPE ) ;
1996-06-04 10:42:03 +04:00
DEBUG ( 0 , ( " Got SIGPIPE \n " ) ) ;
if ( ! is_daemon )
exit ( 1 ) ;
1996-08-15 19:11:34 +04:00
BlockSignals ( False , SIGPIPE ) ;
1996-06-04 10:42:03 +04:00
return ( 0 ) ;
}
# if DUMP_CORE
/*******************************************************************
prepare to dump a core file - carefully !
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL dump_core ( void )
{
char * p ;
pstring dname ;
strcpy ( dname , debugf ) ;
if ( ( p = strrchr ( dname , ' / ' ) ) ) * p = 0 ;
strcat ( dname , " /corefiles " ) ;
mkdir ( dname , 0700 ) ;
sys_chown ( dname , getuid ( ) , getgid ( ) ) ;
chmod ( dname , 0700 ) ;
if ( chdir ( dname ) ) return ( False ) ;
umask ( ~ ( 0700 ) ) ;
# ifndef NO_GETRLIMIT
# ifdef RLIMIT_CORE
{
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 " , rlp . rlim_cur , rlp . rlim_max ) ) ;
}
# endif
# endif
DEBUG ( 0 , ( " Dumping core in %s \n " , dname ) ) ;
return ( True ) ;
}
# endif
/****************************************************************************
possibly continue after a fault
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void fault_continue ( void )
{
# if DUMP_CORE
dump_core ( ) ;
# endif
}
/*******************************************************************
expire old names from the namelist and server list
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-10-07 05:56:21 +04:00
static void expire_names_and_servers ( time_t t )
1996-06-04 10:42:03 +04:00
{
1996-06-04 19:14:47 +04:00
static time_t lastrun = 0 ;
if ( ! lastrun ) lastrun = t ;
1996-10-02 19:41:30 +04:00
if ( t < lastrun + 5 ) return ;
1996-06-04 19:14:47 +04:00
lastrun = t ;
1996-10-02 19:41:30 +04:00
expire_names ( t ) ;
1996-06-04 19:14:47 +04:00
expire_servers ( t ) ;
1996-06-04 10:42:03 +04:00
}
/*****************************************************************************
reload the services file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL reload_services ( BOOL test )
{
BOOL ret ;
extern fstring remote_machine ;
strcpy ( remote_machine , " nmbd " ) ;
if ( lp_loaded ( ) )
{
pstring fname ;
strcpy ( fname , lp_configfile ( ) ) ;
if ( file_exist ( fname , NULL ) & & ! strcsequal ( fname , servicesf ) )
1996-10-02 19:41:30 +04:00
{
strcpy ( servicesf , fname ) ;
test = False ;
}
1996-06-04 10:42:03 +04:00
}
if ( test & & ! lp_file_list_changed ( ) )
return ( True ) ;
ret = lp_load ( servicesf , True ) ;
/* perhaps the config filename is now set */
if ( ! test ) {
DEBUG ( 3 , ( " services not loaded \n " ) ) ;
reload_services ( True ) ;
}
1996-06-06 15:43:09 +04:00
load_interfaces ( ) ;
1996-06-29 22:49:20 +04:00
add_subnet_interfaces ( ) ;
1996-06-06 15:43:09 +04:00
1996-06-04 10:42:03 +04:00
return ( ret ) ;
}
/****************************************************************************
load a netbios hosts file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void load_hosts_file ( char * fname )
{
FILE * f = fopen ( fname , " r " ) ;
pstring line ;
if ( ! f ) {
DEBUG ( 2 , ( " Can't open lmhosts file %s \n " , fname ) ) ;
return ;
}
while ( ! feof ( f ) )
{
1996-08-16 17:03:26 +04:00
pstring ip , name , flags , extra ;
struct subnet_record * d ;
char * ptr ;
int count = 0 ;
struct in_addr ipaddr ;
enum name_source source = LMHOSTS ;
1996-06-04 10:42:03 +04:00
if ( ! fgets_slash ( line , sizeof ( pstring ) , f ) ) continue ;
if ( * line = = ' # ' ) continue ;
1996-08-16 17:03:26 +04:00
strcpy ( ip , " " ) ;
strcpy ( name , " " ) ;
strcpy ( flags , " " ) ;
ptr = line ;
if ( next_token ( & ptr , ip , NULL ) ) + + count ;
if ( next_token ( & ptr , name , NULL ) ) + + count ;
if ( next_token ( & ptr , flags , NULL ) ) + + count ;
if ( next_token ( & ptr , extra , NULL ) ) + + count ;
if ( count < = 0 ) continue ;
if ( count > 0 & & count < 2 ) {
1996-10-02 19:41:30 +04:00
DEBUG ( 0 , ( " Ill formed hosts line [%s] \n " , line ) ) ;
continue ;
1996-06-29 22:49:20 +04:00
}
1996-08-16 17:03:26 +04:00
if ( count > = 4 ) {
1996-10-02 19:41:30 +04:00
DEBUG ( 0 , ( " too many columns in %s (obsolete syntax) \n " , fname ) ) ;
continue ;
1996-08-16 17:03:26 +04:00
}
DEBUG ( 4 , ( " lmhost entry: %s %s %s \n " , ip , name , flags ) ) ;
if ( strchr ( flags , ' G ' ) | | strchr ( flags , ' S ' ) ) {
1996-10-02 19:41:30 +04:00
DEBUG ( 0 , ( " group flag in %s ignored (obsolete) \n " , fname ) ) ;
continue ;
1996-06-04 10:42:03 +04:00
}
1996-08-16 17:03:26 +04:00
if ( strchr ( flags , ' M ' ) ) {
1996-10-02 19:41:30 +04:00
source = SELF ;
strcpy ( myname , name ) ;
1996-08-16 17:03:26 +04:00
}
ipaddr = * interpret_addr2 ( ip ) ;
d = find_subnet ( ipaddr ) ;
if ( d ) {
1996-10-02 19:41:30 +04:00
add_netbios_entry ( d , name , 0x00 , NB_ACTIVE , 0 , source , ipaddr , True , True ) ;
add_netbios_entry ( d , name , 0x20 , NB_ACTIVE , 0 , source , ipaddr , True , True ) ;
1996-08-16 17:03:26 +04:00
}
1996-06-04 10:42:03 +04:00
}
1996-08-16 17:03:26 +04:00
1996-06-04 10:42:03 +04:00
fclose ( f ) ;
}
/****************************************************************************
The main select loop .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void process ( void )
{
BOOL run_election ;
while ( True )
1996-10-02 19:41:30 +04:00
{
time_t t = time ( NULL ) ;
1996-06-04 10:42:03 +04:00
run_election = check_elections ( ) ;
listen_for_packets ( run_election ) ;
run_packet_queue ( ) ;
1996-10-07 05:56:21 +04:00
run_elections ( t ) ;
1996-06-04 10:42:03 +04:00
1996-10-07 05:56:21 +04:00
announce_host ( t ) ;
1996-06-05 19:16:09 +04:00
1996-10-07 05:56:21 +04:00
announce_master ( t ) ;
1996-06-04 10:42:03 +04:00
1996-10-07 05:56:21 +04:00
announce_remote ( t ) ;
1996-08-16 17:03:26 +04:00
1996-10-07 05:56:21 +04:00
query_refresh_names ( t ) ;
1996-06-29 22:49:20 +04:00
1996-10-07 05:56:21 +04:00
expire_names_and_servers ( t ) ;
expire_netbios_response_entries ( t ) ;
1996-10-02 19:41:30 +04:00
refresh_my_names ( t ) ;
1996-06-04 10:42:03 +04:00
1996-10-07 05:56:21 +04:00
write_browse_list ( t ) ;
do_browser_lists ( t ) ;
check_master_browser ( t ) ;
1996-10-02 19:41:30 +04:00
}
1996-06-04 10:42:03 +04:00
}
/****************************************************************************
open the socket communication
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL open_sockets ( BOOL isdaemon , int port )
{
struct hostent * hp ;
/* get host info */
if ( ( hp = Get_Hostbyname ( myhostname ) ) = = 0 ) {
DEBUG ( 0 , ( " Get_Hostbyname: Unknown host. %s \n " , myhostname ) ) ;
return False ;
}
if ( isdaemon )
1996-08-19 15:17:29 +04:00
ClientNMB = open_socket_in ( SOCK_DGRAM , port , 0 , interpret_addr ( lp_socket_address ( ) ) ) ;
1996-06-04 10:42:03 +04:00
else
ClientNMB = 0 ;
1996-08-19 15:17:29 +04:00
ClientDGRAM = open_socket_in ( SOCK_DGRAM , DGRAM_PORT , 3 , interpret_addr ( lp_socket_address ( ) ) ) ;
1996-06-04 10:42:03 +04:00
if ( ClientNMB = = - 1 )
return ( False ) ;
signal ( SIGPIPE , SIGNAL_CAST sig_pipe ) ;
set_socket_options ( ClientNMB , " SO_BROADCAST " ) ;
set_socket_options ( ClientDGRAM , " SO_BROADCAST " ) ;
DEBUG ( 3 , ( " Sockets opened. \n " ) ) ;
return True ;
}
/****************************************************************************
initialise connect , service and file structs
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL init_structs ( )
{
1996-08-22 10:32:03 +04:00
extern fstring local_machine ;
char * p ;
1996-06-04 10:42:03 +04:00
if ( ! * myname ) {
strcpy ( myname , myhostname ) ;
p = strchr ( myname , ' . ' ) ;
if ( p ) * p = 0 ;
}
1996-08-19 15:17:29 +04:00
strupper ( myname ) ;
1996-06-04 10:42:03 +04:00
1996-08-22 10:32:03 +04:00
strcpy ( local_machine , myname ) ;
trim_string ( local_machine , " " , " " ) ;
p = strchr ( local_machine , ' ' ) ;
if ( p ) * p = 0 ;
strlower ( local_machine ) ;
1996-06-04 10:42:03 +04:00
return True ;
}
/****************************************************************************
usage on the program
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void usage ( char * pname )
{
DEBUG ( 0 , ( " Incorrect program usage - is the command line correct? \n " ) ) ;
1996-08-17 15:37:44 +04:00
printf ( " Usage: %s [-n name] [-D] [-p port] [-d debuglevel] [-l log basename] \n " , pname ) ;
1996-06-04 10:42:03 +04:00
printf ( " Version %s \n " , VERSION ) ;
printf ( " \t -D become a daemon \n " ) ;
printf ( " \t -p port listen on the specified port \n " ) ;
printf ( " \t -d debuglevel set the debuglevel \n " ) ;
printf ( " \t -l log basename. Basename for log/debug files \n " ) ;
printf ( " \t -n netbiosname. the netbios name to advertise for this host \n " ) ;
printf ( " \t -H hosts file load a netbios hosts file \n " ) ;
printf ( " \n " ) ;
}
/****************************************************************************
main program
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int main ( int argc , char * argv [ ] )
{
int port = NMB_PORT ;
int opt ;
extern FILE * dbf ;
extern char * optarg ;
1996-12-10 20:55:27 +03:00
char pidFile [ 100 ] = { 0 } ;
1996-06-04 10:42:03 +04:00
* host_file = 0 ;
StartupTime = time ( NULL ) ;
TimeInit ( ) ;
strcpy ( debugf , NMBLOGFILE ) ;
setup_logging ( argv [ 0 ] , False ) ;
charset_initialise ( ) ;
# ifdef LMHOSTSFILE
strcpy ( host_file , LMHOSTSFILE ) ;
# endif
/* this is for people who can't start the program correctly */
while ( argc > 1 & & ( * argv [ 1 ] ! = ' - ' ) ) {
argv + + ;
argc - - ;
}
fault_setup ( fault_continue ) ;
1996-07-04 23:19:26 +04:00
signal ( SIGHUP , SIGNAL_CAST sig_hup ) ;
1996-06-08 08:41:51 +04:00
signal ( SIGTERM , SIGNAL_CAST sig_term ) ;
1996-06-04 10:42:03 +04:00
1996-12-10 20:55:27 +03:00
while ( ( opt = getopt ( argc , argv , " s:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:f: " ) ) ! = EOF )
1996-06-04 10:42:03 +04:00
{
switch ( opt )
1996-10-02 19:41:30 +04:00
{
1996-12-10 20:55:27 +03:00
case ' f ' :
strncpy ( pidFile , optarg , sizeof ( pidFile ) ) ;
break ;
1996-10-02 19:41:30 +04:00
case ' s ' :
strcpy ( servicesf , optarg ) ;
break ;
case ' N ' :
case ' B ' :
case ' I ' :
case ' C ' :
case ' G ' :
DEBUG ( 0 , ( " Obsolete option '%c' used \n " , opt ) ) ;
break ;
case ' H ' :
strcpy ( host_file , optarg ) ;
break ;
case ' n ' :
strcpy ( myname , optarg ) ;
strupper ( myname ) ;
break ;
case ' l ' :
sprintf ( debugf , " %s.nmb " , optarg ) ;
break ;
case ' i ' :
strcpy ( scope , optarg ) ;
strupper ( scope ) ;
break ;
case ' D ' :
is_daemon = True ;
break ;
case ' d ' :
DEBUGLEVEL = atoi ( optarg ) ;
break ;
case ' p ' :
port = atoi ( optarg ) ;
break ;
case ' h ' :
usage ( argv [ 0 ] ) ;
exit ( 0 ) ;
break ;
default :
if ( ! is_a_socket ( 0 ) ) {
usage ( argv [ 0 ] ) ;
}
break ;
}
1996-06-04 10:42:03 +04:00
}
DEBUG ( 1 , ( " %s netbios nameserver version %s started \n " , timestring ( ) , VERSION ) ) ;
DEBUG ( 1 , ( " Copyright Andrew Tridgell 1994 \n " ) ) ;
1996-08-22 10:32:03 +04:00
get_myname ( myhostname , NULL ) ;
1996-06-04 10:42:03 +04:00
if ( ! reload_services ( False ) )
1996-10-02 19:41:30 +04:00
return ( - 1 ) ;
1996-08-19 15:17:29 +04:00
init_structs ( ) ;
1996-08-22 10:32:03 +04:00
reload_services ( True ) ;
1996-08-01 21:49:40 +04:00
set_samba_nb_type ( ) ;
1996-06-04 10:42:03 +04:00
if ( ! is_daemon & & ! is_a_socket ( 0 ) ) {
DEBUG ( 0 , ( " standard input is not a socket, assuming -D option \n " ) ) ;
is_daemon = True ;
}
if ( is_daemon ) {
DEBUG ( 2 , ( " %s becoming a daemon \n " , timestring ( ) ) ) ;
become_daemon ( ) ;
}
1996-12-10 20:55:27 +03:00
if ( * pidFile )
{
int fd ;
char buf [ 20 ] ;
if ( ( fd = open ( pidFile ,
O_NONBLOCK | O_CREAT | O_WRONLY | O_TRUNC , 0644 ) ) < 0 )
{
DEBUG ( 0 , ( " ERROR: can't open %s: %s \n " , pidFile , strerror ( errno ) ) ) ;
exit ( 1 ) ;
}
if ( fcntl_lock ( fd , F_SETLK , 0 , 1 , F_WRLCK ) = = False )
{
DEBUG ( 0 , ( " ERROR: nmbd is already running \n " ) ) ;
exit ( 1 ) ;
}
sprintf ( buf , " %u \n " , ( unsigned int ) getpid ( ) ) ;
if ( write ( fd , buf , strlen ( buf ) ) < 0 )
{
DEBUG ( 0 , ( " ERROR: can't write to %s: %s \n " , pidFile , strerror ( errno ) ) ) ;
exit ( 1 ) ;
}
/* Leave pid file open & locked for the duration... */
}
1996-06-04 10:42:03 +04:00
DEBUG ( 3 , ( " Opening sockets %d \n " , port ) ) ;
if ( ! open_sockets ( is_daemon , port ) ) return 1 ;
if ( * host_file ) {
load_hosts_file ( host_file ) ;
DEBUG ( 3 , ( " Loaded hosts file \n " ) ) ;
}
add_my_names ( ) ;
1996-08-17 15:37:44 +04:00
if ( strequal ( lp_workgroup ( ) , " * " ) ) {
DEBUG ( 0 , ( " ERROR: a workgroup name of * is no longer supported \n " ) ) ;
}
1996-10-02 19:41:30 +04:00
add_my_subnets ( lp_workgroup ( ) ) ;
1996-06-04 10:42:03 +04:00
DEBUG ( 3 , ( " Checked names \n " ) ) ;
1996-06-29 22:49:20 +04:00
load_netbios_names ( ) ;
DEBUG ( 3 , ( " Loaded names \n " ) ) ;
1996-10-07 05:56:21 +04:00
write_browse_list ( time ( NULL ) ) ;
1996-06-04 10:42:03 +04:00
DEBUG ( 3 , ( " Dumped names \n " ) ) ;
process ( ) ;
close_sockets ( ) ;
if ( dbf )
fclose ( dbf ) ;
return ( 0 ) ;
}