X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source%2Fnmbd%2Fnmbd.c;h=dc03506194b278f422ab59ac2133675e8fec4149;hb=5c6c8e1fe93;hp=051991f46de7d2277d8e36aec0b01d7f5bb8e28b;hpb=b8d39651fb90ef170055735412417239a63afc5d;p=samba.git diff --git a/source/nmbd/nmbd.c b/source/nmbd/nmbd.c index 051991f46de..dc03506194b 100644 --- a/source/nmbd/nmbd.c +++ b/source/nmbd/nmbd.c @@ -3,10 +3,11 @@ 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 - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -15,8 +16,7 @@ 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 02139, USA. + along with this program. If not, see . */ @@ -26,14 +26,20 @@ int ClientNMB = -1; 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; @@ -42,6 +48,27 @@ BOOL found_lm_clients = False; time_t StartupTime = 0; +struct event_context *nmbd_event_context(void) +{ + static struct event_context *ctx; + + if (!ctx && !(ctx = event_context_init(NULL))) { + smb_panic("Could not init nmbd event context"); + } + return ctx; +} + +struct messaging_context *nmbd_messaging_context(void) +{ + static struct messaging_context *ctx; + + if (!ctx && !(ctx = messaging_init(NULL, server_id_self(), + nmbd_event_context()))) { + smb_panic("Could not init nmbd messaging context"); + } + return ctx; +} + /**************************************************************************** ** Handle a SIGTERM in band. **************************************************************************** */ @@ -51,10 +78,10 @@ static void terminate(void) DEBUG(0,("Got SIGTERM: going down...\n")); /* Write out wins.dat file if samba is a WINS server */ - wins_write_database(False); + wins_write_database(0,False); - /* Remove all SELF registered names. */ - release_my_names(); + /* Remove all SELF registered names from WINS */ + release_wins_names(); /* Announce all server entries as 0 time-to-live, 0 type. */ announce_my_servers_removed(); @@ -69,7 +96,11 @@ static void terminate(void) 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(struct messaging_context *msg, + void *private_data, + uint32_t msg_type, + struct server_id server_id, + DATA_BLOB *data) { terminate(); } @@ -78,75 +109,33 @@ static void nmbd_terminate(int msg_type, pid_t src, void *buf, size_t len) Catch a SIGTERM signal. **************************************************************************** */ -static VOLATILE sig_atomic_t got_sig_term; +static SIG_ATOMIC_T got_sig_term; static void sig_term(int sig) { got_sig_term = 1; - sys_select_signal(); + sys_select_signal(SIGTERM); } /**************************************************************************** ** Catch a SIGHUP signal. **************************************************************************** */ -static VOLATILE sig_atomic_t reload_after_sighup; +static SIG_ATOMIC_T reload_after_sighup; static void sig_hup(int sig) { reload_after_sighup = 1; - sys_select_signal(); + sys_select_signal(SIGHUP); } -#if DUMP_CORE -/**************************************************************************** ** - 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) ); - -#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 ) ); - } -#endif -#endif - - - DEBUG(0,("Dumping core in %s\n",dname)); - abort(); - return( True ); -} -#endif - /**************************************************************************** ** Possibly continue after a fault. **************************************************************************** */ static void fault_continue(void) { -#if DUMP_CORE dump_core(); -#endif } /**************************************************************************** ** @@ -191,8 +180,6 @@ static BOOL reload_interfaces(time_t t) 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; @@ -207,6 +194,11 @@ static BOOL reload_interfaces(time_t t) for (n=iface_count() - 1; n >= 0; n--) { struct interface *iface = get_interface(n); + if (!iface) { + DEBUG(2,("reload_interfaces: failed to get interface %d\n", n)); + continue; + } + /* * We don't want to add a loopback interface, in case * someone has added 127.0.0.1 for smbd, nmbd needs to @@ -228,7 +220,8 @@ static BOOL reload_interfaces(time_t 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); } } @@ -269,9 +262,8 @@ static BOOL reload_interfaces(time_t t) 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; @@ -285,7 +277,7 @@ static BOOL reload_nmbd_services(BOOL test) if ( test && !lp_file_list_changed() ) return(True); - ret = lp_load( dyn_CONFIGFILE, True , False, False); + ret = lp_load( dyn_CONFIGFILE, True , False, False, True); /* perhaps the config filename is now set */ if ( !test ) { @@ -293,16 +285,89 @@ static BOOL reload_nmbd_services(BOOL test) 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 = '\n" ); - dbgtext( "are conflicting settings. nmbd aborting.\n" ); + 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(struct messaging_context *msg, + void *private_data, + uint32_t msg_type, + struct server_id server_id, + DATA_BLOB *data) +{ + write_browse_list( 0, True ); + dump_all_namelists(); + reload_nmbd_services( True ); + reopen_logs(); + + if (data->data) { + /* 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*)data->data) = reload_interfaces(0); + } +} + +static void msg_nmbd_send_packet(struct messaging_context *msg, + void *private_data, + uint32_t msg_type, + struct server_id src, + DATA_BLOB *data) +{ + struct packet_struct *p = (struct packet_struct *)data->data; + struct subnet_record *subrec; + struct in_addr *local_ip; + + DEBUG(10, ("Received send_packet from %d\n", procid_to_pid(&src))); + + if (data->length != 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; } - exit(10); } - return(ret); + 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); } /**************************************************************************** ** @@ -312,13 +377,15 @@ static BOOL reload_nmbd_services(BOOL test) static void process(void) { BOOL run_election; + BOOL no_subnets; while( True ) { time_t t = time(NULL); + TALLOC_CTX *frame = talloc_stackframe(); /* Check for internal messages */ - message_dispatch(); + message_dispatch(nmbd_messaging_context()); /* * Check all broadcast subnets to see if @@ -333,8 +400,10 @@ static void process(void) * (nmbd_packets.c) */ - if(listen_for_packets(run_election)) + if(listen_for_packets(run_election)) { + TALLOC_FREE(frame); return; + } /* * Handle termination inband. @@ -519,23 +588,29 @@ static void process(void) */ if(reload_after_sighup) { + DATA_BLOB blob = data_blob_const(&no_subnets, + sizeof(no_subnets)); 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(nmbd_messaging_context(), + NULL, MSG_SMB_CONF_UPDATED, + procid_self(), &blob); + + if(no_subnets) { + TALLOC_FREE(frame); return; + } reload_after_sighup = 0; } /* check for new network interfaces */ - if(reload_interfaces(t)) + if(reload_interfaces(t)) { + TALLOC_FREE(frame); return; + } /* free up temp memory */ - lp_talloc_free(); + TALLOC_FREE(frame); } } @@ -554,11 +629,15 @@ static BOOL open_sockets(BOOL isdaemon, int port) */ 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; - ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3,0,True); + ClientDGRAM = open_socket_in(SOCK_DGRAM, DGRAM_PORT, + 3, interpret_addr(lp_socket_address()), + True); if ( ClientNMB == -1 ) return( False ); @@ -569,351 +648,220 @@ static BOOL open_sockets(BOOL isdaemon, int port) set_socket_options( ClientNMB, "SO_BROADCAST" ); set_socket_options( ClientDGRAM, "SO_BROADCAST" ); + /* Ensure we're non-blocking. */ + set_blocking( ClientNMB, False); + set_blocking( ClientDGRAM, False); + DEBUG( 3, ( "open_sockets: Broadcast sockets opened.\n" ) ); return( True ); } /**************************************************************************** ** - Initialise connect, service and file structs. + main program **************************************************************************** */ - -static BOOL init_structs(void) + int main(int argc, const char *argv[]) { - 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 1 && (*argv[1] != '-')) - { - argv++; - argc--; - } + reload_nmbd_services( True ); - fault_setup((void (*)(void *))fault_continue ); + if (strequal(lp_workgroup(),"*")) { + DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n")); + exit(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); + set_samba_nb_type(); - CatchSignal( SIGHUP, SIGNAL_CAST sig_hup ); - CatchSignal( SIGTERM, SIGNAL_CAST sig_term ); + 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(Fork, no_process_group); + } -#if defined(SIGFPE) - /* we are never interested in SIGFPE */ - BlockSignals(True,SIGFPE); +#if HAVE_SETPGID + /* + * If we're interactive we want to set our own process group for + * signal management. + */ + if (opt_interactive && !no_process_group) + setpgid( (pid_t)0, (pid_t)0 ); #endif - /* We no longer use USR2... */ -#if defined(SIGUSR2) - BlockSignals(True, SIGUSR2); + if (nmbd_messaging_context() == NULL) { + return 1; + } + +#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(); + } #endif - 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 && !opt_interactive) - { - DEBUG( 2, ( "Becoming a daemon.\n" ) ); - become_daemon(); - } + if (!directory_exist(lp_lockdir(), NULL)) { + mkdir(lp_lockdir(), 0755); + } -#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 ); + pidfile_create("nmbd"); + messaging_register(nmbd_messaging_context(), NULL, + MSG_FORCE_ELECTION, nmbd_message_election); +#if 0 + /* Until winsrepl is done. */ + messaging_register(nmbd_messaging_context(), NULL, + MSG_WINS_NEW_ENTRY, nmbd_wins_new_entry); #endif + messaging_register(nmbd_messaging_context(), NULL, + MSG_SHUTDOWN, nmbd_terminate); + messaging_register(nmbd_messaging_context(), NULL, + MSG_SMB_CONF_UPDATED, msg_reload_nmbd_services); + messaging_register(nmbd_messaging_context(), NULL, + MSG_SEND_PACKET, msg_nmbd_send_packet); -#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()) { - start_async_dns(); - } -#endif + TimeInit(); + + DEBUG( 3, ( "Opening sockets %d\n", global_nmb_port ) ); - 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 ) ) - 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")); - 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" ) ); - 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")); - exit(1); - } - - /* We can only take signals in the select. */ - BlockSignals( True, SIGTERM ); - - process(); - - if (dbf) - x_fclose(dbf); - return(0); + 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(p_lmhosts); + DEBUG(3,("Loaded hosts file %s\n", p_lmhosts)); + + /* 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); }