NBT netbios routines and daemon - version 2
Copyright (C) Andrew Tridgell 1994-1998
Copyright (C) Jeremy Allison 1997-2002
+ Copyright (C) Jelmer Vernooij 2002,2003 (Conversion to popt)
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
int ClientDGRAM = -1;
int global_nmb_port = -1;
-extern pstring global_myname;
-extern fstring global_myworkgroup;
-extern char **my_netbios_names;
-
+extern BOOL rescan_listen_set;
+extern struct in_addr loopback_ip;
extern BOOL global_in_nmbd;
+extern BOOL override_logfile;
+
/* are we running as a daemon ? */
-static BOOL is_daemon = False;
+static BOOL is_daemon;
+
+/* fork or run in foreground ? */
+static BOOL Fork = True;
+
+/* log to standard output ? */
+static BOOL log_stdout;
/* have we found LanMan clients yet? */
BOOL found_lm_clients = False;
Handle a SHUTDOWN message from smbcontrol.
**************************************************************************** */
-static void nmbd_terminate(int msg_type, pid_t src, void *buf, size_t len)
+static void nmbd_terminate(int msg_type, struct process_id src,
+ void *buf, size_t len)
{
terminate();
}
static void sig_term(int sig)
{
got_sig_term = 1;
- sys_select_signal();
+ sys_select_signal(SIGTERM);
}
/**************************************************************************** **
static void sig_hup(int sig)
{
reload_after_sighup = 1;
- sys_select_signal();
+ sys_select_signal(SIGHUP);
}
#if DUMP_CORE
static time_t lastt;
int n;
struct subnet_record *subrec;
- extern BOOL rescan_listen_set;
- extern struct in_addr loopback_ip;
if (t && ((t - lastt) < NMBD_INTERFACES_RELOAD)) return False;
lastt = t;
DEBUG(2,("Found new interface %s\n",
inet_ntoa(iface->ip)));
subrec = make_normal_subnet(iface);
- if (subrec) register_my_workgroup_one_subnet(subrec);
+ if (subrec)
+ register_my_workgroup_one_subnet(subrec);
}
}
static BOOL reload_nmbd_services(BOOL test)
{
BOOL ret;
- extern fstring remote_machine;
- fstrcpy( remote_machine, "nmbd" );
+ set_remote_machine_name("nmbd", False);
if ( lp_loaded() ) {
pstring fname;
return(ret);
}
+/**************************************************************************** **
+ * React on 'smbcontrol nmbd reload-config' in the same way as to SIGHUP
+ * We use buf here to return BOOL result to process() when reload_interfaces()
+ * detects that there are no subnets.
+ **************************************************************************** */
+
+static void msg_reload_nmbd_services(int msg_type, struct process_id src,
+ void *buf, size_t len)
+{
+ write_browse_list( 0, True );
+ dump_all_namelists();
+ reload_nmbd_services( True );
+ reopen_logs();
+
+ if(buf) {
+ /* We were called from process() */
+ /* If reload_interfaces() returned True */
+ /* we need to shutdown if there are no subnets... */
+ /* pass this info back to process() */
+ *((BOOL*)buf) = reload_interfaces(0);
+ }
+}
+
+static void msg_nmbd_send_packet(int msg_type, struct process_id src,
+ void *buf, size_t len)
+{
+ struct packet_struct *p = (struct packet_struct *)buf;
+ struct subnet_record *subrec;
+ struct in_addr *local_ip;
+
+ DEBUG(10, ("Received send_packet from %d\n", procid_to_pid(&src)));
+
+ if (len != sizeof(struct packet_struct)) {
+ DEBUG(2, ("Discarding invalid packet length from %d\n",
+ procid_to_pid(&src)));
+ return;
+ }
+
+ if ((p->packet_type != NMB_PACKET) &&
+ (p->packet_type != DGRAM_PACKET)) {
+ DEBUG(2, ("Discarding invalid packet type from %d: %d\n",
+ procid_to_pid(&src), p->packet_type));
+ return;
+ }
+
+ local_ip = iface_ip(p->ip);
+
+ if (local_ip == NULL) {
+ DEBUG(2, ("Could not find ip for packet from %d\n",
+ procid_to_pid(&src)));
+ return;
+ }
+
+ subrec = FIRST_SUBNET;
+
+ p->fd = (p->packet_type == NMB_PACKET) ?
+ subrec->nmb_sock : subrec->dgram_sock;
+
+ for (subrec = FIRST_SUBNET; subrec != NULL;
+ subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+ if (ip_equal(*local_ip, subrec->myip)) {
+ p->fd = (p->packet_type == NMB_PACKET) ?
+ subrec->nmb_sock : subrec->dgram_sock;
+ break;
+ }
+ }
+
+ if (p->packet_type == DGRAM_PACKET) {
+ p->port = 138;
+ p->packet.dgram.header.source_ip.s_addr = local_ip->s_addr;
+ p->packet.dgram.header.source_port = 138;
+ }
+
+ send_packet(p);
+}
+
/**************************************************************************** **
The main select loop.
**************************************************************************** */
static void process(void)
{
BOOL run_election;
+ BOOL no_subnets;
while( True ) {
time_t t = time(NULL);
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))
+ msg_reload_nmbd_services(MSG_SMB_CONF_UPDATED,
+ pid_to_procid(0), (void*) &no_subnets, 0);
+ if(no_subnets)
return;
reload_after_sighup = 0;
}
*/
if ( isdaemon )
- ClientNMB = open_socket_in(SOCK_DGRAM, port,0,0,True);
+ ClientNMB = open_socket_in(SOCK_DGRAM, port,
+ 0, interpret_addr(lp_socket_address()),
+ True);
else
ClientNMB = 0;
return( True );
}
-/**************************************************************************** **
- Initialise connect, service and file structs.
- **************************************************************************** */
-
-static BOOL init_structs(void)
-{
- extern fstring local_machine;
- char *p, **ptr;
- int namecount;
- int n;
- int nodup;
- char *nbname;
-
- if (! *global_myname)
- {
- fstrcpy( global_myname, myhostname() );
- p = strchr_m( global_myname, '.' );
- if (p)
- *p = 0;
- }
- strupper( global_myname );
-
- /* Add any NETBIOS name aliases. Ensure that the first entry
- is equal to global_myname.
- */
- /* Work out the max number of netbios aliases that we have */
- ptr = lp_netbios_aliases();
- namecount = 0;
- if (ptr)
- for( ; *ptr; namecount++,ptr++ )
- ;
- if ( *global_myname )
- namecount++;
-
- /* Allocate space for the netbios aliases */
- my_netbios_names = (char **)malloc( sizeof(char *) * (namecount+1) );
- if( NULL == my_netbios_names )
- {
- DEBUG( 0, ( "init_structs: malloc fail.\n" ) );
- return( False );
- }
-
- /* Use the global_myname string first */
- namecount=0;
- if ( *global_myname )
- my_netbios_names[namecount++] = global_myname;
-
- ptr = lp_netbios_aliases();
- if (ptr)
- {
- while ( *ptr )
- {
- nbname = strdup(*ptr);
- if (nbname == NULL)
- {
- DEBUG(0,("init_structs: malloc fail when allocating names.\n"));
- return False;
- }
- strupper( nbname );
- /* Look for duplicates */
- nodup=1;
- for( n=0; n<namecount; n++ )
- {
- if( 0 == strcmp( nbname, my_netbios_names[n] ) )
- nodup=0;
- }
- if (nodup)
- my_netbios_names[namecount++] = nbname;
- else
- SAFE_FREE(nbname);
-
- ptr++;
- }
- }
-
- /* Terminate name list */
- my_netbios_names[namecount++] = NULL;
-
- fstrcpy( local_machine, global_myname );
- trim_string( local_machine, " ", " " );
- p = strchr_m( local_machine, ' ' );
- if (p)
- *p = 0;
- strlower( local_machine );
-
- DEBUG( 5, ("Netbios name list:-\n") );
- for( n=0; my_netbios_names[n]; n++ )
- DEBUGADD( 5, ( "my_netbios_names[%d]=\"%s\"\n", n, my_netbios_names[n] ) );
-
- return( True );
-}
-
-/**************************************************************************** **
- Usage on the program.
- **************************************************************************** */
-
-static void usage(char *pname)
-{
-
- printf( "Usage: %s [-DaiohV] [-H lmhosts file] [-d debuglevel] [-l log basename]\n", pname );
- printf( " [-n name] [-p port] [-s configuration file]\n" );
- printf( "\t-D Become a daemon (default)\n" );
- printf( "\t-a Append to log file (default)\n" );
- printf( "\t-i Run interactive (not a daemon)\n" );
- printf( "\t-o Overwrite log file, don't append\n" );
- printf( "\t-h Print usage\n" );
- printf( "\t-V Print version\n" );
- printf( "\t-H hosts file Load a netbios hosts file\n" );
- printf( "\t-d debuglevel Set the debuglevel\n" );
- printf( "\t-l log basename. Basename for log/debug files\n" );
- printf( "\t-n netbiosname. Primary netbios name\n" );
- printf( "\t-p port Listen on the specified port\n" );
- printf( "\t-s configuration file Configuration file name\n" );
- printf( "\n");
-}
-
-
/**************************************************************************** **
main program
**************************************************************************** */
- int main(int argc,char *argv[])
+ int main(int argc, const char *argv[])
{
- int opt;
- extern char *optarg;
- extern BOOL append_log;
- BOOL opt_interactive = False;
- pstring logfile;
+ pstring logfile;
+ static BOOL opt_interactive;
+ poptContext pc;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"daemon", 'D', POPT_ARG_VAL, &is_daemon, True, "Become a daemon(default)" },
+ {"interactive", 'i', POPT_ARG_VAL, &opt_interactive, True, "Run interactive (not a daemon)" },
+ {"foreground", 'F', POPT_ARG_VAL, &Fork, False, "Run daemon in foreground (for daemontools & etc)" },
+ {"log-stdout", 'S', POPT_ARG_VAL, &log_stdout, True, "Log to stdout" },
+ {"hosts", 'H', POPT_ARG_STRING, dyn_LMHOSTSFILE, 'H', "Load a netbios hosts file"},
+ {"port", 'p', POPT_ARG_INT, &global_nmb_port, NMB_PORT, "Listen on the specified port" },
+ POPT_COMMON_SAMBA
+ { NULL }
+ };
+
+ global_nmb_port = NMB_PORT;
+
+ pc = poptGetContext("nmbd", argc, argv, long_options, 0);
+ while (poptGetNextOpt(pc) != -1) {};
+ poptFreeContext(pc);
+
+ global_in_nmbd = True;
+
+ StartupTime = time(NULL);
+
+ sys_srandom(time(NULL) ^ sys_getpid());
+
+ if (!override_logfile) {
+ slprintf(logfile, sizeof(logfile)-1, "%s/log.nmbd", dyn_LOGFILEBASE);
+ lp_set_logfile(logfile);
+ }
+
+ fault_setup((void (*)(void *))fault_continue );
+
+ /* POSIX demands that signals are inherited. If the invoking process has
+ * these signals masked, we will have problems, as we won't receive them. */
+ BlockSignals(False, SIGHUP);
+ BlockSignals(False, SIGUSR1);
+ BlockSignals(False, SIGTERM);
+
+ CatchSignal( SIGHUP, SIGNAL_CAST sig_hup );
+ CatchSignal( SIGTERM, SIGNAL_CAST sig_term );
+
+#if defined(SIGFPE)
+ /* we are never interested in SIGFPE */
+ BlockSignals(True,SIGFPE);
+#endif
- append_log = True; /* Default, override with '-o' option. */
+ /* We no longer use USR2... */
+#if defined(SIGUSR2)
+ BlockSignals(True, SIGUSR2);
+#endif
- global_nmb_port = NMB_PORT;
- global_in_nmbd = True;
+ if ( opt_interactive ) {
+ Fork = False;
+ log_stdout = True;
+ }
- StartupTime = time(NULL);
+ if ( log_stdout && Fork ) {
+ DEBUG(0,("ERROR: Can't log to stdout (-S) unless daemon is in foreground (-F) or interactive (-i)\n"));
+ exit(1);
+ }
- sys_srandom(time(NULL) ^ sys_getpid());
+ setup_logging( argv[0], log_stdout );
- slprintf(logfile, sizeof(logfile)-1, "%s/log.nmbd", dyn_LOGFILEBASE);
- lp_set_logfile(logfile);
+ reopen_logs();
- /* this is for people who can't start the program correctly */
- while (argc > 1 && (*argv[1] != '-'))
- {
- argv++;
- argc--;
- }
+ DEBUG( 0, ( "Netbios nameserver version %s started.\n", SAMBA_VERSION_STRING) );
+ DEBUGADD( 0, ( "Copyright Andrew Tridgell and the Samba Team 1994-2004\n" ) );
- fault_setup((void (*)(void *))fault_continue );
+ if ( !reload_nmbd_services(False) )
+ return(-1);
- /* POSIX demands that signals are inherited. If the invoking process has
- * these signals masked, we will have problems, as we won't recieve them. */
- BlockSignals(False, SIGHUP);
- BlockSignals(False, SIGUSR1);
- BlockSignals(False, SIGTERM);
+ if(!init_names())
+ return -1;
- CatchSignal( SIGHUP, SIGNAL_CAST sig_hup );
- CatchSignal( SIGTERM, SIGNAL_CAST sig_term );
+ reload_nmbd_services( True );
-#if defined(SIGFPE)
- /* we are never interested in SIGFPE */
- BlockSignals(True,SIGFPE);
-#endif
+ if (strequal(lp_workgroup(),"*")) {
+ DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
+ exit(1);
+ }
- /* We no longer use USR2... */
-#if defined(SIGUSR2)
- BlockSignals(True, SIGUSR2);
-#endif
+ set_samba_nb_type();
- while( EOF !=
- (opt = getopt( argc, argv, "Vaos:T:I:C:bAB:N:Rn:l:d:Dp:hSH:G:f:i" )) )
- {
- switch (opt)
- {
- case 's':
- pstrcpy(dyn_CONFIGFILE, optarg);
- break;
- case 'N':
- case 'B':
- case 'I':
- case 'C':
- case 'G':
- DEBUG(0,("Obsolete option '%c' used\n",opt));
- break;
- case 'i':
- opt_interactive = True;
- break;
- case 'H':
- pstrcpy(dyn_LMHOSTSFILE, optarg);
- break;
- case 'n':
- pstrcpy(global_myname,optarg);
- strupper(global_myname);
- break;
- case 'l':
- slprintf(logfile, sizeof(logfile)-1, "%s/log.nmbd", optarg);
- lp_set_logfile(logfile);
- break;
- case 'a':
- append_log = True;
- break;
- case 'o':
- append_log = False;
- break;
- case 'D':
- is_daemon = True;
- break;
- case 'd':
- DEBUGLEVEL = atoi(optarg);
- break;
- case 'p':
- global_nmb_port = atoi(optarg);
- break;
- case 'h':
- usage(argv[0]);
- exit(0);
- break;
- case 'V':
- printf( "Version %s\n", VERSION );
- exit(0);
- break;
- default:
- if( !is_a_socket(0) )
- {
- DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
- usage(argv[0]);
- exit(0);
- }
- break;
- }
- }
-
- setup_logging( argv[0], opt_interactive );
-
- reopen_logs();
-
- DEBUG( 0, ( "Netbios nameserver version %s started.\n", VERSION ) );
- DEBUGADD( 0, ( "Copyright Andrew Tridgell and the Samba Team 1994-2002\n" ) );
-
- if ( !reload_nmbd_services(False) )
- return(-1);
-
- if(!init_structs())
- return -1;
-
- reload_nmbd_services( True );
-
- fstrcpy( global_myworkgroup, lp_workgroup() );
-
- if (strequal(global_myworkgroup,"*"))
- {
- DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
- exit(1);
- }
-
- set_samba_nb_type();
-
- 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 && !is_a_socket(0)) {
+ DEBUG(0,("standard input is not a socket, assuming -D option\n"));
+ is_daemon = True;
+ }
- if (is_daemon && !opt_interactive)
- {
- DEBUG( 2, ( "Becoming a daemon.\n" ) );
- become_daemon();
- }
+ if (is_daemon && !opt_interactive) {
+ DEBUG( 2, ( "Becoming a daemon.\n" ) );
+ become_daemon(Fork);
+ }
#if HAVE_SETPGID
- /*
- * If we're interactive we want to set our own process group for
- * signal management.
- */
- if (opt_interactive)
- setpgid( (pid_t)0, (pid_t)0 );
+ /*
+ * If we're interactive we want to set our own process group for
+ * signal management.
+ */
+ if (opt_interactive)
+ setpgid( (pid_t)0, (pid_t)0 );
#endif
#ifndef SYNC_DNS
- /* Setup the async dns. We do it here so it doesn't have all the other
- stuff initialised and thus chewing memory and sockets */
- if(lp_we_are_a_wins_server() && lp_dns_proxy()) {
- start_async_dns();
- }
+ /* Setup the async dns. We do it here so it doesn't have all the other
+ stuff initialised and thus chewing memory and sockets */
+ if(lp_we_are_a_wins_server() && lp_dns_proxy()) {
+ start_async_dns();
+ }
#endif
- if (!directory_exist(lp_lockdir(), NULL)) {
- mkdir(lp_lockdir(), 0755);
- }
-
- pidfile_create("nmbd");
- message_init();
- message_register(MSG_FORCE_ELECTION, nmbd_message_election);
- message_register(MSG_WINS_NEW_ENTRY, nmbd_wins_new_entry);
- message_register(MSG_SHUTDOWN, nmbd_terminate);
-
- DEBUG( 3, ( "Opening sockets %d\n", global_nmb_port ) );
-
- if ( !open_sockets( is_daemon, global_nmb_port ) ) {
- kill_async_dns_child();
- return 1;
- }
-
- /* Determine all the IP addresses we have. */
- load_interfaces();
-
- /* Create an nmbd subnet record for each of the above. */
- if( False == create_subnets() )
- {
- DEBUG(0,("ERROR: Failed when creating subnet lists. Exiting.\n"));
- kill_async_dns_child();
- exit(1);
- }
-
- /* Load in any static local names. */
- load_lmhosts_file(dyn_LMHOSTSFILE);
- DEBUG(3,("Loaded hosts file %s\n", dyn_LMHOSTSFILE));
-
- /* If we are acting as a WINS server, initialise data structures. */
- if( !initialise_wins() )
- {
- DEBUG( 0, ( "nmbd: Failed when initialising WINS server.\n" ) );
- kill_async_dns_child();
- exit(1);
- }
-
- /*
- * Register nmbd primary workgroup and nmbd names on all
- * the broadcast subnets, and on the WINS server (if specified).
- * Also initiate the startup of our primary workgroup (start
- * elections if we are setup as being able to be a local
- * master browser.
- */
-
- if( False == register_my_workgroup_and_names() )
- {
- DEBUG(0,("ERROR: Failed when creating my my workgroup. Exiting.\n"));
- kill_async_dns_child();
- exit(1);
- }
-
- /* We can only take signals in the select. */
- BlockSignals( True, SIGTERM );
-
- process();
-
- if (dbf)
- x_fclose(dbf);
- kill_async_dns_child();
- return(0);
+ if (!directory_exist(lp_lockdir(), NULL)) {
+ mkdir(lp_lockdir(), 0755);
+ }
+
+ pidfile_create("nmbd");
+ message_init();
+ message_register(MSG_FORCE_ELECTION, nmbd_message_election);
+ message_register(MSG_WINS_NEW_ENTRY, nmbd_wins_new_entry);
+ message_register(MSG_SHUTDOWN, nmbd_terminate);
+ message_register(MSG_SMB_CONF_UPDATED, msg_reload_nmbd_services);
+ message_register(MSG_SEND_PACKET, msg_nmbd_send_packet);
+
+ DEBUG( 3, ( "Opening sockets %d\n", global_nmb_port ) );
+
+ if ( !open_sockets( is_daemon, global_nmb_port ) ) {
+ kill_async_dns_child();
+ return 1;
+ }
+
+ /* Determine all the IP addresses we have. */
+ load_interfaces();
+
+ /* Create an nmbd subnet record for each of the above. */
+ if( False == create_subnets() ) {
+ DEBUG(0,("ERROR: Failed when creating subnet lists. Exiting.\n"));
+ kill_async_dns_child();
+ exit(1);
+ }
+
+ /* Load in any static local names. */
+ load_lmhosts_file(dyn_LMHOSTSFILE);
+ DEBUG(3,("Loaded hosts file %s\n", dyn_LMHOSTSFILE));
+
+ /* If we are acting as a WINS server, initialise data structures. */
+ if( !initialise_wins() ) {
+ DEBUG( 0, ( "nmbd: Failed when initialising WINS server.\n" ) );
+ kill_async_dns_child();
+ exit(1);
+ }
+
+ /*
+ * Register nmbd primary workgroup and nmbd names on all
+ * the broadcast subnets, and on the WINS server (if specified).
+ * Also initiate the startup of our primary workgroup (start
+ * elections if we are setup as being able to be a local
+ * master browser.
+ */
+
+ if( False == register_my_workgroup_and_names() ) {
+ DEBUG(0,("ERROR: Failed when creating my my workgroup. Exiting.\n"));
+ kill_async_dns_child();
+ exit(1);
+ }
+
+ /* We can only take signals in the select. */
+ BlockSignals( True, SIGTERM );
+
+ process();
+
+ if (dbf)
+ x_fclose(dbf);
+ kill_async_dns_child();
+ return(0);
}