diff options
| -rw-r--r-- | source3/nmbd/nmbd.c | 707 | 
1 files changed, 368 insertions, 339 deletions
diff --git a/source3/nmbd/nmbd.c b/source3/nmbd/nmbd.c index 9ed8dd92b6..62e3f1757b 100644 --- a/source3/nmbd/nmbd.c +++ b/source3/nmbd/nmbd.c @@ -2,6 +2,7 @@     Unix SMB/CIFS implementation.     NBT netbios routines and daemon - version 2     Copyright (C) Andrew Tridgell 1994-1998 +   Copyright (C) Jeremy Allison 1997-2002     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 @@ -17,11 +18,6 @@     along with this program; if not, write to the Free Software     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -   Revision History: - -   14 jan 96: lkcl@pires.co.uk -   added multiple workgroup domain master support -  */  #include "includes.h" @@ -47,136 +43,140 @@ BOOL found_lm_clients = False;  time_t StartupTime = 0;  /**************************************************************************** ** -  catch a sigterm + Handle a SIGTERM in band.   **************************************************************************** */ -static void sig_term(int sig) + +static void terminate(void)  { -  BlockSignals(True,SIGTERM); -   -  DEBUG(0,("Got SIGTERM: going down...\n")); +	DEBUG(0,("Got SIGTERM: going down...\n")); -  /* Write out wins.dat file if samba is a WINS server */ -  wins_write_database(False); +	/* Write out wins.dat file if samba is a WINS server */ +	wins_write_database(False); -  /* Remove all SELF registered names. */ -  release_my_names(); +	/* Remove all SELF registered names. */ +	release_my_names(); -  /* Announce all server entries as 0 time-to-live, 0 type. */ -  announce_my_servers_removed(); - -  /* If there was an async dns child - kill it. */ -  kill_async_dns_child(); +	/* Announce all server entries as 0 time-to-live, 0 type. */ +	announce_my_servers_removed(); -  exit(0); +	/* If there was an async dns child - kill it. */ +	kill_async_dns_child(); -} /* sig_term */ +	exit(0); +}  /**************************************************************************** ** - catch a sighup + Catch a SIGTERM signal.   **************************************************************************** */ -static VOLATILE sig_atomic_t reload_after_sighup = False; - -static void sig_hup(int sig) -{ -  BlockSignals( True, SIGHUP ); - -  DEBUG( 0, ( "Got SIGHUP dumping debug info.\n" ) ); -  write_browse_list( 0, True ); +static VOLATILE sig_atomic_t got_sig_term; -  dump_all_namelists(); - -  reload_after_sighup = True; +static void sig_term(int sig) +{ +	got_sig_term = 1; +	sys_select_signal(); +} -  BlockSignals(False,SIGHUP); +/**************************************************************************** ** + Catch a SIGHUP signal. + **************************************************************************** */ -} /* sig_hup */ +static VOLATILE sig_atomic_t reload_after_sighup; +static void sig_hup(int sig) +{ +	reload_after_sighup = 1; +	sys_select_signal(); +}  #if DUMP_CORE  /**************************************************************************** ** - prepare to dump a core file - carefully! + Prepare to dump a core file - carefully!   **************************************************************************** */ +  static BOOL dump_core(void)  { -  char *p; -  pstring dname; -  pstrcpy( dname, lp_logfile() ); -  if ((p=strrchr_m(dname,'/'))) -    *p=0; -  pstrcat( dname, "/corefiles" ); -  mkdir( dname, 0700 ); -  sys_chown( dname, getuid(), getgid() ); -  chmod( dname, 0700 ); -  if ( chdir(dname) ) -    return( False ); -  umask( ~(0700) ); +	char *p; +	pstring dname; +	pstrcpy( dname, lp_logfile() ); +	if ((p=strrchr_m(dname,'/'))) +		*p=0; +	pstrcat( dname, "/corefiles" ); +	mkdir( dname, 0700 ); +	sys_chown( dname, getuid(), getgid() ); +	chmod( dname, 0700 ); +	if ( chdir(dname) ) +		return( False ); +	umask( ~(0700) );  #ifdef HAVE_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", (int)rlp.rlim_cur, (int)rlp.rlim_max ) ); -  } +	{ +		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 ) ); +	}  #endif  #endif -  DEBUG(0,("Dumping core in %s\n",dname)); -  abort(); -  return( True ); -} /* dump_core */ +	DEBUG(0,("Dumping core in %s\n",dname)); +	abort(); +	return( True ); +}  #endif -  /**************************************************************************** ** - possibly continue after a fault + Possibly continue after a fault.   **************************************************************************** */ +  static void fault_continue(void)  {  #if DUMP_CORE -  dump_core(); +	dump_core();  #endif -} /* fault_continue */ +}  /**************************************************************************** ** - expire old names from the namelist and server list + Expire old names from the namelist and server list.   **************************************************************************** */ +  static void expire_names_and_servers(time_t t)  { -  static time_t lastrun = 0; +	static time_t lastrun = 0; -  if ( !lastrun ) -    lastrun = t; -  if ( t < (lastrun + 5) ) -    return; -  lastrun = t; +	if ( !lastrun ) +		lastrun = t; +	if ( t < (lastrun + 5) ) +		return; +	lastrun = t; -  /* -   * Expire any timed out names on all the broadcast -   * subnets and those registered with the WINS server. -   * (nmbd_namelistdb.c) -   */ -  expire_names(t); +	/* +	 * Expire any timed out names on all the broadcast +	 * subnets and those registered with the WINS server. +	 * (nmbd_namelistdb.c) +	 */ -  /* -   * Go through all the broadcast subnets and for each -   * workgroup known on that subnet remove any expired -   * server names. If a workgroup has an empty serverlist -   * and has itself timed out then remove the workgroup. -   * (nmbd_workgroupdb.c) -   */ -  expire_workgroups_and_servers(t); -} /* expire_names_and_servers */ +	expire_names(t); +	/* +	 * Go through all the broadcast subnets and for each +	 * workgroup known on that subnet remove any expired +	 * server names. If a workgroup has an empty serverlist +	 * and has itself timed out then remove the workgroup. +	 * (nmbd_workgroupdb.c) +	 */ + +	expire_workgroups_and_servers(t); +}  /************************************************************************** ** -reload the list of network interfaces + Reload the list of network interfaces.   ************************************************************************** */ +  static BOOL reload_interfaces(time_t t)  {  	static time_t lastt; @@ -253,293 +253,321 @@ static BOOL reload_interfaces(time_t t)  	return False;  } - -  /**************************************************************************** ** -  reload the services file + Reload the services file.   **************************************************************************** */ +  static BOOL reload_nmbd_services(BOOL test)  { -  BOOL ret; -  extern fstring remote_machine; +	BOOL ret; +	extern fstring remote_machine; -  fstrcpy( remote_machine, "nmbd" ); +	fstrcpy( remote_machine, "nmbd" ); -  if ( lp_loaded() ) -  { -    pstring fname; -    pstrcpy( fname,lp_configfile()); -    if (file_exist(fname,NULL) && !strcsequal(fname,dyn_CONFIGFILE)) -    { -      pstrcpy(dyn_CONFIGFILE,fname); -      test = False; -    } -  } +	if ( lp_loaded() ) { +		pstring fname; +		pstrcpy( fname,lp_configfile()); +		if (file_exist(fname,NULL) && !strcsequal(fname,dyn_CONFIGFILE)) { +			pstrcpy(dyn_CONFIGFILE,fname); +			test = False; +		} +	} -  if ( test && !lp_file_list_changed() ) -    return(True); +	if ( test && !lp_file_list_changed() ) +		return(True); -  ret = lp_load( dyn_CONFIGFILE, True , False, False); +	ret = lp_load( dyn_CONFIGFILE, True , False, False); -  /* perhaps the config filename is now set */ -  if ( !test ) -  { -    DEBUG( 3, ( "services not loaded\n" ) ); -    reload_nmbd_services( True ); -  } +	/* perhaps the config filename is now set */ +	if ( !test ) { +		DEBUG( 3, ( "services not loaded\n" ) ); +		reload_nmbd_services( True ); +	} -  /* Do a sanity check for a misconfigured nmbd */ -  if( lp_wins_support() && wins_srv_count() ) -    { -    if( DEBUGLVL(0) ) -      { -      dbgtext( "ERROR: 'wins support = true' and 'wins server = <server>'\n" ); -      dbgtext( "are conflicting settings.  nmbd aborting.\n" ); -      } -    exit(10); -    } +	/* Do a sanity check for a misconfigured nmbd */ +	if( lp_wins_support() && wins_srv_count() ) { +		if( DEBUGLVL(0) ) { +			dbgtext( "ERROR: 'wins support = true' and 'wins server = <server>'\n" ); +			dbgtext( "are conflicting settings.  nmbd aborting.\n" ); +		} +		exit(10); +	} -  return(ret); -} /* reload_nmbd_services */ +	return(ret); +}  /**************************************************************************** **   The main select loop.   **************************************************************************** */ +  static void process(void)  { -  BOOL run_election; +	BOOL run_election; -  while( True ) -  { -    time_t t = time(NULL); - -    /* check for internal messages */ -    message_dispatch(); - -    /* -     * Check all broadcast subnets to see if -     * we need to run an election on any of them. -     * (nmbd_elections.c) -     */ -    run_election = check_elections(); - -    /* -     * Read incoming UDP packets. -     * (nmbd_packets.c) -     */ -    if(listen_for_packets(run_election)) -      return; - -    /* -     * Process all incoming packets -     * read above. This calls the success and -     * failure functions registered when response -     * packets arrrive, and also deals with request -     * packets from other sources. -     * (nmbd_packets.c) -     */ -    run_packet_queue(); - -    /* -     * Run any elections - initiate becoming -     * a local master browser if we have won. -     * (nmbd_elections.c) -     */ -    run_elections(t); - -    /* -     * Send out any broadcast announcements -     * of our server names. This also announces -     * the workgroup name if we are a local -     * master browser. -     * (nmbd_sendannounce.c) -     */ -    announce_my_server_names(t); - -    /* -     * Send out any LanMan broadcast announcements -     * of our server names. -     * (nmbd_sendannounce.c) -     */ -    announce_my_lm_server_names(t); - -    /* -     * If we are a local master browser, periodically -     * announce ourselves to the domain master browser. -     * This also deals with syncronising the domain master -     * browser server lists with ourselves as a local -     * master browser. -     * (nmbd_sendannounce.c) -     */ -    announce_myself_to_domain_master_browser(t); - -    /* -     * Fullfill any remote announce requests. -     * (nmbd_sendannounce.c) -     */ -    announce_remote(t); - -    /* -     * Fullfill any remote browse sync announce requests. -     * (nmbd_sendannounce.c) -     */ -    browse_sync_remote(t); - -    /* -     * Scan the broadcast subnets, and WINS client -     * namelists and refresh any that need refreshing. -     * (nmbd_mynames.c) -     */ -    refresh_my_names(t); - -    /* -     * Scan the subnet namelists and server lists and -     * expire thos that have timed out. -     * (nmbd.c) -     */ -    expire_names_and_servers(t); - -    /* -     * Write out a snapshot of our current browse list into -     * the browse.dat file. This is used by smbd to service -     * incoming NetServerEnum calls - used to synchronise -     * browse lists over subnets. -     * (nmbd_serverlistdb.c) -     */ -    write_browse_list(t, False); - -    /* -     * If we are a domain master browser, we have a list of -     * local master browsers we should synchronise browse -     * lists with (these are added by an incoming local -     * master browser announcement packet). Expire any of -     * these that are no longer current, and pull the server -     * lists from each of these known local master browsers. -     * (nmbd_browsesync.c) -     */ -    dmb_expire_and_sync_browser_lists(t); - -    /* -     * Check that there is a local master browser for our -     * workgroup for all our broadcast subnets. If one -     * is not found, start an election (which we ourselves -     * may or may not participate in, depending on the -     * setting of the 'local master' parameter. -     * (nmbd_elections.c) -     */ -    check_master_browser_exists(t); - -    /* -     * If we are configured as a logon server, attempt to -     * register the special NetBIOS names to become such -     * (WORKGROUP<1c> name) on all broadcast subnets and -     * with the WINS server (if used). If we are configured -     * to become a domain master browser, attempt to register -     * the special NetBIOS name (WORKGROUP<1b> name) to -     * become such. -     * (nmbd_become_dmb.c) -     */ -    add_domain_names(t); - -    /* -     * If we are a WINS server, do any timer dependent -     * processing required. -     * (nmbd_winsserver.c) -     */ -    initiate_wins_processing(t); - -    /* -     * If we are a domain master browser, attempt to contact the -     * WINS server to get a list of all known WORKGROUPS/DOMAINS. -     * This will only work to a Samba WINS server. -     * (nmbd_browsesync.c) -     */ -    if (lp_enhanced_browsing()) { -	    collect_all_workgroup_names_from_wins_server(t); -    } +	while( True ) { +		time_t t = time(NULL); -    /* -     * Go through the response record queue and time out or re-transmit -     * and expired entries. -     * (nmbd_packets.c) -     */ -    retransmit_or_expire_response_records(t); - -    /* -     * check to see if any remote browse sync child processes have completed -     */ -    sync_check_completion(); - -    /* -     * regularly sync with any other DMBs we know about  -     */ -    if (lp_enhanced_browsing()) { -	    sync_all_dmbs(t); -    } +		/* Check for internal messages */ + +		message_dispatch(); + +		/* +		 * Check all broadcast subnets to see if +		 * we need to run an election on any of them. +		 * (nmbd_elections.c) +		 */ -    /* -     * clear the unexpected packet queue  -     */ -    clear_unexpected(t); +		run_election = check_elections(); -    /* -     * Reload the services file if we got a sighup. -     */ +		/* +		 * Read incoming UDP packets. +		 * (nmbd_packets.c) +		 */ -    if(reload_after_sighup) { -	    reload_nmbd_services( True ); -	    reopen_logs(); -	    if(reload_interfaces(0)) +		if(listen_for_packets(run_election))  			return; -	    reload_after_sighup = False; -    } -    /* check for new network interfaces */ -    if(reload_interfaces(t)) -		return; +		/* +		 * Handle termination inband. +		 */ -    /* free up temp memory */ -    lp_talloc_free(); -  } -} /* process */ +		if (got_sig_term) { +			got_sig_term = 0; +			terminate(); +		} + +		/* +		 * Process all incoming packets +		 * read above. This calls the success and +		 * failure functions registered when response +		 * packets arrrive, and also deals with request +		 * packets from other sources. +		 * (nmbd_packets.c) +		 */ + +		run_packet_queue(); + +		/* +		 * Run any elections - initiate becoming +		 * a local master browser if we have won. +		 * (nmbd_elections.c) +		 */ + +		run_elections(t); + +		/* +		 * Send out any broadcast announcements +		 * of our server names. This also announces +		 * the workgroup name if we are a local +		 * master browser. +		 * (nmbd_sendannounce.c) +		 */ + +		announce_my_server_names(t); +		/* +		 * Send out any LanMan broadcast announcements +		 * of our server names. +		 * (nmbd_sendannounce.c) +		 */ + +		announce_my_lm_server_names(t); + +		/* +		 * If we are a local master browser, periodically +		 * announce ourselves to the domain master browser. +		 * This also deals with syncronising the domain master +		 * browser server lists with ourselves as a local +		 * master browser. +		 * (nmbd_sendannounce.c) +		 */ + +		announce_myself_to_domain_master_browser(t); + +		/* +		 * Fullfill any remote announce requests. +		 * (nmbd_sendannounce.c) +		 */ + +		announce_remote(t); + +		/* +		 * Fullfill any remote browse sync announce requests. +		 * (nmbd_sendannounce.c) +		 */ + +		browse_sync_remote(t); + +		/* +		 * Scan the broadcast subnets, and WINS client +		 * namelists and refresh any that need refreshing. +		 * (nmbd_mynames.c) +		 */ + +		refresh_my_names(t); + +		/* +		 * Scan the subnet namelists and server lists and +		 * expire thos that have timed out. +		 * (nmbd.c) +		 */ + +		expire_names_and_servers(t); + +		/* +		 * Write out a snapshot of our current browse list into +		 * the browse.dat file. This is used by smbd to service +		 * incoming NetServerEnum calls - used to synchronise +		 * browse lists over subnets. +		 * (nmbd_serverlistdb.c) +		 */ + +		write_browse_list(t, False); + +		/* +		 * If we are a domain master browser, we have a list of +		 * local master browsers we should synchronise browse +		 * lists with (these are added by an incoming local +		 * master browser announcement packet). Expire any of +		 * these that are no longer current, and pull the server +		 * lists from each of these known local master browsers. +		 * (nmbd_browsesync.c) +		 */ + +		dmb_expire_and_sync_browser_lists(t); + +		/* +		 * Check that there is a local master browser for our +		 * workgroup for all our broadcast subnets. If one +		 * is not found, start an election (which we ourselves +		 * may or may not participate in, depending on the +		 * setting of the 'local master' parameter. +		 * (nmbd_elections.c) +		 */ + +		check_master_browser_exists(t); + +		/* +		 * If we are configured as a logon server, attempt to +		 * register the special NetBIOS names to become such +		 * (WORKGROUP<1c> name) on all broadcast subnets and +		 * with the WINS server (if used). If we are configured +		 * to become a domain master browser, attempt to register +		 * the special NetBIOS name (WORKGROUP<1b> name) to +		 * become such. +		 * (nmbd_become_dmb.c) +		 */ + +		add_domain_names(t); + +		/* +		 * If we are a WINS server, do any timer dependent +		 * processing required. +		 * (nmbd_winsserver.c) +		 */ + +		initiate_wins_processing(t); + +		/* +		 * If we are a domain master browser, attempt to contact the +		 * WINS server to get a list of all known WORKGROUPS/DOMAINS. +		 * This will only work to a Samba WINS server. +		 * (nmbd_browsesync.c) +		 */ + +		if (lp_enhanced_browsing()) +			collect_all_workgroup_names_from_wins_server(t); + +		/* +		 * Go through the response record queue and time out or re-transmit +		 * and expired entries. +		 * (nmbd_packets.c) +		 */ + +		retransmit_or_expire_response_records(t); + +		/* +		 * check to see if any remote browse sync child processes have completed +		 */ + +		sync_check_completion(); + +		/* +		 * regularly sync with any other DMBs we know about  +		 */ + +		if (lp_enhanced_browsing()) +			sync_all_dmbs(t); + +		/* +		 * clear the unexpected packet queue  +		 */ + +		clear_unexpected(t); + +		/* +		 * Reload the services file if we got a sighup. +		 */ + +		if(reload_after_sighup) { +			DEBUG( 0, ( "Got SIGHUP dumping debug info.\n" ) ); +			write_browse_list( 0, True ); +			dump_all_namelists(); +			reload_nmbd_services( True ); +			reopen_logs(); +			if(reload_interfaces(0)) +				return; +			reload_after_sighup = 0; +		} + +		/* check for new network interfaces */ + +		if(reload_interfaces(t)) +			return; + +		/* free up temp memory */ +			lp_talloc_free(); +	} +}  /**************************************************************************** ** - open the socket communication + Open the socket communication.   **************************************************************************** */ +  static BOOL open_sockets(BOOL isdaemon, int port)  { -  /* The sockets opened here will be used to receive broadcast -     packets *only*. Interface specific sockets are opened in -     make_subnet() in namedbsubnet.c. Thus we bind to the -     address "0.0.0.0". The parameter 'socket address' is -     now deprecated. -   */ - -  if ( isdaemon ) -    ClientNMB = open_socket_in(SOCK_DGRAM, port,0,0,True); -  else -    ClientNMB = 0; +	/* +	 * The sockets opened here will be used to receive broadcast +	 * packets *only*. Interface specific sockets are opened in +	 * make_subnet() in namedbsubnet.c. Thus we bind to the +	 * address "0.0.0.0". The parameter 'socket address' is +	 * now deprecated. +	 */ + +	if ( isdaemon ) +		ClientNMB = open_socket_in(SOCK_DGRAM, port,0,0,True); +	else +		ClientNMB = 0; -  ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3,0,True); +	ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3,0,True); -  if ( ClientNMB == -1 ) -    return( False ); +	if ( ClientNMB == -1 ) +		return( False ); -  /* we are never interested in SIGPIPE */ -  BlockSignals(True,SIGPIPE); +	/* we are never interested in SIGPIPE */ +	BlockSignals(True,SIGPIPE); -  set_socket_options( ClientNMB,   "SO_BROADCAST" ); -  set_socket_options( ClientDGRAM, "SO_BROADCAST" ); - -  DEBUG( 3, ( "open_sockets: Broadcast sockets opened.\n" ) ); -  return( True ); -} /* open_sockets */ +	set_socket_options( ClientNMB,   "SO_BROADCAST" ); +	set_socket_options( ClientDGRAM, "SO_BROADCAST" ); +	DEBUG( 3, ( "open_sockets: Broadcast sockets opened.\n" ) ); +	return( True ); +}  /**************************************************************************** ** - initialise connect, service and file structs + Initialise connect, service and file structs.   **************************************************************************** */ +  static BOOL init_structs(void)  {    extern fstring local_machine; @@ -626,11 +654,12 @@ static BOOL init_structs(void)      DEBUGADD( 5, ( "my_netbios_names[%d]=\"%s\"\n", n, my_netbios_names[n] ) );    return( True ); -} /* init_structs */ +}  /**************************************************************************** ** - usage on the program + Usage on the program.   **************************************************************************** */ +  static void usage(char *pname)  { @@ -649,7 +678,7 @@ static void usage(char *pname)    printf( "\t-p port               Listen on the specified port\n" );    printf( "\t-s configuration file Configuration file name\n" );    printf( "\n"); -} /* usage */ +}  /**************************************************************************** ** @@ -877,4 +906,4 @@ static void usage(char *pname)    if (dbf)      x_fclose(dbf);    return(0); -} /* main */ +}  | 
