s3: piddir creation fix part 2.
[ira/wip.git] / source3 / nmbd / nmbd.c
index 034944531797f77fdfceb97cef7e41185dbbbfe0..52d7ed9e4e7d4a948711214f9c02efc1d86501b0 100644 (file)
@@ -4,23 +4,27 @@
    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 3 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, see <http://www.gnu.org/licenses/>.
-   
 */
 
 #include "includes.h"
+#include "system/filesys.h"
+#include "popt_common.h"
+#include "nmbd/nmbd.h"
+#include "serverid.h"
+#include "messages.h"
 
 int ClientNMB       = -1;
 int ClientDGRAM     = -1;
@@ -40,92 +44,147 @@ 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;
+       return server_event_context();
 }
 
 /**************************************************************************** **
  Handle a SIGTERM in band.
  **************************************************************************** */
 
-static void terminate(void)
+static void terminate(struct messaging_context *msg)
 {
        DEBUG(0,("Got SIGTERM: going down...\n"));
-  
+
        /* Write out wins.dat file if samba is a WINS server */
        wins_write_database(0,False);
-  
+
        /* 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();
 
        /* If there was an async dns child - kill it. */
        kill_async_dns_child();
 
+       gencache_stabilize();
+       serverid_deregister(messaging_server_id(msg));
+
+       pidfile_unlink();
+
        exit(0);
 }
 
-/**************************************************************************** **
- Handle a SHUTDOWN message from smbcontrol.
- **************************************************************************** */
+static void nmbd_sig_term_handler(struct tevent_context *ev,
+                                 struct tevent_signal *se,
+                                 int signum,
+                                 int count,
+                                 void *siginfo,
+                                 void *private_data)
+{
+       struct messaging_context *msg = talloc_get_type_abort(
+               private_data, struct messaging_context);
 
-static void nmbd_terminate(struct messaging_context *msg,
-                          void *private_data,
-                          uint32_t msg_type,
-                          struct server_id server_id,
-                          DATA_BLOB *data)
+       terminate(msg);
+}
+
+/*
+  handle stdin becoming readable when we are in --foreground mode
+ */
+static void nmbd_stdin_handler(struct tevent_context *ev,
+                              struct tevent_fd *fde,
+                              uint16_t flags,
+                              void *private_data)
 {
-       terminate();
+       char c;
+       if (read(0, &c, 1) != 1) {
+               struct messaging_context *msg = talloc_get_type_abort(
+                       private_data, struct messaging_context);
+               
+               DEBUG(0,("EOF on stdin\n"));
+               terminate(msg);
+       }
 }
 
-/**************************************************************************** **
- Catch a SIGTERM signal.
- **************************************************************************** */
+static bool nmbd_setup_sig_term_handler(struct messaging_context *msg)
+{
+       struct tevent_signal *se;
+
+       se = tevent_add_signal(nmbd_event_context(),
+                              nmbd_event_context(),
+                              SIGTERM, 0,
+                              nmbd_sig_term_handler,
+                              msg);
+       if (!se) {
+               DEBUG(0,("failed to setup SIGTERM handler"));
+               return false;
+       }
 
-static SIG_ATOMIC_T got_sig_term;
+       return true;
+}
 
-static void sig_term(int sig)
+static bool nmbd_setup_stdin_handler(struct messaging_context *msg, bool foreground)
 {
-       got_sig_term = 1;
-       sys_select_signal(SIGTERM);
+       if (foreground) {
+               /* if we are running in the foreground then look for
+                  EOF on stdin, and exit if it happens. This allows
+                  us to die if the parent process dies
+               */
+               tevent_add_fd(nmbd_event_context(), nmbd_event_context(), 0, TEVENT_FD_READ, nmbd_stdin_handler, msg);
+       }
+
+       return true;
 }
 
-/**************************************************************************** **
- Catch a SIGHUP signal.
- **************************************************************************** */
+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);
+
+static void nmbd_sig_hup_handler(struct tevent_context *ev,
+                                struct tevent_signal *se,
+                                int signum,
+                                int count,
+                                void *siginfo,
+                                void *private_data)
+{
+       struct messaging_context *msg = talloc_get_type_abort(
+               private_data, struct messaging_context);
 
-static SIG_ATOMIC_T reload_after_sighup;
+       DEBUG(0,("Got SIGHUP dumping debug info.\n"));
+       msg_reload_nmbd_services(msg, NULL, MSG_SMB_CONF_UPDATED,
+                                messaging_server_id(msg), NULL);
+}
 
-static void sig_hup(int sig)
+static bool nmbd_setup_sig_hup_handler(struct messaging_context *msg)
 {
-       reload_after_sighup = 1;
-       sys_select_signal(SIGHUP);
+       struct tevent_signal *se;
+
+       se = tevent_add_signal(nmbd_event_context(),
+                              nmbd_event_context(),
+                              SIGHUP, 0,
+                              nmbd_sig_hup_handler,
+                              msg);
+       if (!se) {
+               DEBUG(0,("failed to setup SIGHUP handler"));
+               return false;
+       }
+
+       return true;
 }
 
 /**************************************************************************** **
Possibly continue after a fault.
Handle a SHUTDOWN message from smbcontrol.
  **************************************************************************** */
 
-static void fault_continue(void)
+static void nmbd_terminate(struct messaging_context *msg,
+                          void *private_data,
+                          uint32_t msg_type,
+                          struct server_id server_id,
+                          DATA_BLOB *data)
 {
-       dump_core();
+       terminate(msg);
 }
 
 /**************************************************************************** **
@@ -135,7 +194,7 @@ static void fault_continue(void)
 static void expire_names_and_servers(time_t t)
 {
        static time_t lastrun = 0;
-  
+
        if ( !lastrun )
                lastrun = t;
        if ( t < (lastrun + 5) )
@@ -207,8 +266,9 @@ static void reload_interfaces(time_t t)
                        continue;
                }
 
-               ip = ((struct sockaddr_in *)&iface->ip)->sin_addr;
-               nmask = ((struct sockaddr_in *)&iface->netmask)->sin_addr;
+               ip = ((const struct sockaddr_in *)(const void *)&iface->ip)->sin_addr;
+               nmask = ((const struct sockaddr_in *)(const void *)
+                        &iface->netmask)->sin_addr;
 
                /*
                 * We don't want to add a loopback interface, in case
@@ -216,7 +276,7 @@ static void reload_interfaces(time_t t)
                 * ignore it here. JRA.
                 */
 
-               if (is_loopback_addr(&iface->ip)) {
+               if (is_loopback_addr((const struct sockaddr *)(const void *)&iface->ip)) {
                        DEBUG(2,("reload_interfaces: Ignoring loopback "
                                "interface %s\n",
                                print_sockaddr(str, sizeof(str), &iface->ip) ));
@@ -255,8 +315,10 @@ static void reload_interfaces(time_t t)
                                        "ignoring non IPv4 interface.\n"));
                                continue;
                        }
-                       ip = ((struct sockaddr_in *)&iface->ip)->sin_addr;
-                       nmask = ((struct sockaddr_in *)&iface->netmask)->sin_addr;
+                       ip = ((struct sockaddr_in *)(void *)
+                             &iface->ip)->sin_addr;
+                       nmask = ((struct sockaddr_in *)(void *)
+                                &iface->netmask)->sin_addr;
                        if (ip_equal_v4(ip, subrec->myip) &&
                            ip_equal_v4(nmask, subrec->mask_ip)) {
                                break;
@@ -279,6 +341,7 @@ static void reload_interfaces(time_t t)
 
        /* We need to wait if there are no subnets... */
        if (FIRST_SUBNET == NULL) {
+               void (*saved_handler)(int);
 
                if (print_waiting_msg) {
                        DEBUG(0,("reload_interfaces: "
@@ -290,29 +353,20 @@ static void reload_interfaces(time_t t)
                 * Whilst we're waiting for an interface, allow SIGTERM to
                 * cause us to exit.
                 */
+               saved_handler = CatchSignal(SIGTERM, SIG_DFL);
 
-               BlockSignals(false, SIGTERM);
-
-               /* We only count IPv4 interfaces here. */
-               while (iface_count_v4() == 0 && !got_sig_term) {
+               /* We only count IPv4, non-loopback interfaces here. */
+               while (iface_count_v4_nl() == 0) {
                        sleep(5);
                        load_interfaces();
                }
 
-               /*
-                * Handle termination inband.
-                */
-
-               if (got_sig_term) {
-                       got_sig_term = 0;
-                       terminate();
-               }
+               CatchSignal(SIGTERM, saved_handler);
 
                /*
                 * We got an interface, go back to blocking term.
                 */
 
-               BlockSignals(true, SIGTERM);
                goto try_again;
        }
 }
@@ -329,7 +383,7 @@ static bool reload_nmbd_services(bool test)
 
        if ( lp_loaded() ) {
                const char *fname = lp_configfile();
-               if (file_exist(fname,NULL) && !strcsequal(fname,get_dyn_CONFIGFILE())) {
+               if (file_exist(fname) && !strcsequal(fname,get_dyn_CONFIGFILE())) {
                        set_dyn_CONFIGFILE(fname);
                        test = False;
                }
@@ -338,7 +392,7 @@ static bool reload_nmbd_services(bool test)
        if ( test && !lp_file_list_changed() )
                return(True);
 
-       ret = lp_load(get_dyn_CONFIGFILE(), True , False, False, True);
+       ret = lp_load_global(get_dyn_CONFIGFILE());
 
        /* perhaps the config filename is now set */
        if ( !test ) {
@@ -378,40 +432,41 @@ static void msg_nmbd_send_packet(struct messaging_context *msg,
        const struct sockaddr_storage *pss;
        const struct in_addr *local_ip;
 
-       DEBUG(10, ("Received send_packet from %d\n", procid_to_pid(&src)));
+       DEBUG(10, ("Received send_packet from %u\n", (unsigned int)procid_to_pid(&src)));
 
        if (data->length != sizeof(struct packet_struct)) {
-               DEBUG(2, ("Discarding invalid packet length from %d\n",
-                         procid_to_pid(&src)));
+               DEBUG(2, ("Discarding invalid packet length from %u\n",
+                         (unsigned int)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));
+               DEBUG(2, ("Discarding invalid packet type from %u: %d\n",
+                         (unsigned int)procid_to_pid(&src), p->packet_type));
                return;
        }
 
        in_addr_to_sockaddr_storage(&ss, p->ip);
-       pss = iface_ip(&ss);
+       pss = iface_ip((struct sockaddr *)(void *)&ss);
 
        if (pss == NULL) {
-               DEBUG(2, ("Could not find ip for packet from %d\n",
-                         procid_to_pid(&src)));
+               DEBUG(2, ("Could not find ip for packet from %u\n",
+                         (unsigned int)procid_to_pid(&src)));
                return;
        }
 
        local_ip = &((const struct sockaddr_in *)pss)->sin_addr;
        subrec = FIRST_SUBNET;
 
-       p->fd = (p->packet_type == NMB_PACKET) ?
+       p->recv_fd = -1;
+       p->send_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_v4(*local_ip, subrec->myip)) {
-                       p->fd = (p->packet_type == NMB_PACKET) ?
+                       p->send_fd = (p->packet_type == NMB_PACKET) ?
                                subrec->nmb_sock : subrec->dgram_sock;
                        break;
                }
@@ -430,7 +485,7 @@ static void msg_nmbd_send_packet(struct messaging_context *msg,
  The main select loop.
  **************************************************************************** */
 
-static void process(void)
+static void process(struct messaging_context *msg)
 {
        bool run_election;
 
@@ -438,10 +493,6 @@ static void process(void)
                time_t t = time(NULL);
                TALLOC_CTX *frame = talloc_stackframe();
 
-               /* Check for internal messages */
-
-               message_dispatch(nmbd_messaging_context());
-
                /*
                 * Check all broadcast subnets to see if
                 * we need to run an election on any of them.
@@ -455,20 +506,11 @@ static void process(void)
                 * (nmbd_packets.c)
                 */
 
-               if(listen_for_packets(run_election)) {
+               if (listen_for_packets(msg, run_election)) {
                        TALLOC_FREE(frame);
                        return;
                }
 
-               /*
-                * Handle termination inband.
-                */
-
-               if (got_sig_term) {
-                       got_sig_term = 0;
-                       terminate();
-               }
-
                /*
                 * Process all incoming packets
                 * read above. This calls the success and
@@ -632,25 +674,6 @@ static void process(void)
                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" ) );
-                       msg_reload_nmbd_services(nmbd_messaging_context(),
-                                                NULL, MSG_SMB_CONF_UPDATED,
-                                                procid_self(), NULL);
-
-                       reload_after_sighup = 0;
-               }
-
                /* check for new network interfaces */
 
                reload_interfaces(t);
@@ -733,14 +756,15 @@ static bool open_sockets(bool isdaemon, int port)
 
  int main(int argc, const char *argv[])
 {
-       static bool is_daemon;
-       static bool opt_interactive;
-       static bool Fork = true;
-       static bool no_process_group;
-       static bool log_stdout;
+       bool is_daemon = false;
+       bool opt_interactive = false;
+       bool Fork = true;
+       bool no_process_group = false;
+       bool log_stdout = false;
        poptContext pc;
        char *p_lmhosts = NULL;
        int opt;
+       struct messaging_context *msg;
        enum {
                OPT_DAEMON = 1000,
                OPT_INTERACTIVE,
@@ -755,12 +779,21 @@ static bool open_sockets(bool isdaemon, int port)
        {"foreground", 'F', POPT_ARG_NONE, NULL, OPT_FORK, "Run daemon in foreground (for daemontools & etc)" },
        {"no-process-group", 0, POPT_ARG_NONE, NULL, OPT_NO_PROCESS_GROUP, "Don't create a new process group" },
        {"log-stdout", 'S', POPT_ARG_NONE, NULL, OPT_LOG_STDOUT, "Log to stdout" },
-       {"hosts", 'H', POPT_ARG_STRING, &p_lmhosts, 'H', "Load a netbios hosts file"},
-       {"port", 'p', POPT_ARG_INT, &global_nmb_port, NMB_PORT, "Listen on the specified port" },
+       {"hosts", 'H', POPT_ARG_STRING, &p_lmhosts, 0, "Load a netbios hosts file"},
+       {"port", 'p', POPT_ARG_INT, &global_nmb_port, 0, "Listen on the specified port" },
        POPT_COMMON_SAMBA
        { NULL }
        };
-       TALLOC_CTX *frame = talloc_stackframe(); /* Setup tos. */
+       TALLOC_CTX *frame;
+       NTSTATUS status;
+
+       /*
+        * Do this before any other talloc operation
+        */
+       talloc_enable_null_tracking();
+       frame = talloc_stackframe();
+
+       setup_logging(argv[0], DEBUG_DEFAULT_STDOUT);
 
        load_case_tables();
 
@@ -794,32 +827,29 @@ static bool open_sockets(bool isdaemon, int port)
        poptFreeContext(pc);
 
        global_in_nmbd = true;
-       
+
        StartupTime = time(NULL);
-       
+
        sys_srandom(time(NULL) ^ sys_getpid());
-       
+
        if (!override_logfile) {
-               char *logfile = NULL;
-               if (asprintf(&logfile, "%s/log.nmbd", get_dyn_LOGFILEBASE()) < 0) {
+               char *lfile = NULL;
+               if (asprintf(&lfile, "%s/log.nmbd", get_dyn_LOGFILEBASE()) < 0) {
                        exit(1);
                }
-               lp_set_logfile(logfile);
-               SAFE_FREE(logfile);
+               lp_set_logfile(lfile);
+               SAFE_FREE(lfile);
        }
-       
-       fault_setup((void (*)(void *))fault_continue );
-       dump_core_setup("nmbd");
-       
+
+       fault_setup();
+       dump_core_setup("nmbd", lp_logfile());
+
        /* 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);
@@ -840,13 +870,27 @@ static bool open_sockets(bool isdaemon, int port)
                exit(1);
        }
 
-       setup_logging( argv[0], log_stdout );
+       if (log_stdout) {
+               setup_logging(argv[0], DEBUG_STDOUT);
+       } else {
+               setup_logging( argv[0], DEBUG_FILE);
+       }
 
        reopen_logs();
 
-       DEBUG(0,("nmbd version %s started.\n", SAMBA_VERSION_STRING));
+       DEBUG(0,("nmbd version %s started.\n", samba_version_string()));
        DEBUGADD(0,("%s\n", COPYRIGHT_STARTUP_MESSAGE));
 
+       if (!lp_load_initial_only(get_dyn_CONFIGFILE())) {
+               DEBUG(0, ("error opening config file '%s'\n", get_dyn_CONFIGFILE()));
+               exit(1);
+       }
+
+       msg = messaging_init(NULL, server_event_context());
+       if (msg == NULL) {
+               return 1;
+       }
+
        if ( !reload_nmbd_services(False) )
                return(-1);
 
@@ -866,10 +910,10 @@ static bool open_sockets(bool isdaemon, int port)
                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);
+               become_daemon(Fork, no_process_group, log_stdout);
        }
 
 #if HAVE_SETPGID
@@ -881,36 +925,62 @@ static bool open_sockets(bool isdaemon, int port)
                setpgid( (pid_t)0, (pid_t)0 );
 #endif
 
-       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();
+               start_async_dns(msg);
        }
 #endif
 
-       if (!directory_exist(lp_lockdir(), NULL)) {
+       if (!directory_exist(lp_lockdir())) {
                mkdir(lp_lockdir(), 0755);
        }
 
+       if (!directory_exist(lp_piddir())) {
+               mkdir(lp_piddir(), 0755);
+       }
+
        pidfile_create("nmbd");
-       messaging_register(nmbd_messaging_context(), NULL,
-                          MSG_FORCE_ELECTION, nmbd_message_election);
+
+       status = reinit_after_fork(msg, nmbd_event_context(),
+                                  false);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,("reinit_after_fork() failed\n"));
+               exit(1);
+       }
+
+       if (!nmbd_setup_sig_term_handler(msg))
+               exit(1);
+       if (!nmbd_setup_stdin_handler(msg, !Fork))
+               exit(1);
+       if (!nmbd_setup_sig_hup_handler(msg))
+               exit(1);
+
+       /* get broadcast messages */
+
+       if (!serverid_register(messaging_server_id(msg),
+                               FLAG_MSG_GENERAL |
+                               FLAG_MSG_NMBD |
+                               FLAG_MSG_DBWRAP)) {
+               DEBUG(1, ("Could not register myself in serverid.tdb\n"));
+               exit(1);
+       }
+
+       messaging_register(msg, 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);
+       messaging_register(msg, 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);
+       messaging_register(msg, NULL, MSG_SHUTDOWN,
+                          nmbd_terminate);
+       messaging_register(msg, NULL, MSG_SMB_CONF_UPDATED,
+                          msg_reload_nmbd_services);
+       messaging_register(msg, NULL, MSG_SEND_PACKET,
+                          msg_nmbd_send_packet);
 
        TimeInit();
 
@@ -959,14 +1029,20 @@ static bool open_sockets(bool isdaemon, int port)
                exit(1);
        }
 
-       /* We can only take signals in the select. */
-       BlockSignals( True, SIGTERM );
+       if (!initialize_nmbd_proxy_logon()) {
+               DEBUG(0,("ERROR: Failed setup nmbd_proxy_logon.\n"));
+               kill_async_dns_child();
+               exit(1);
+       }
+
+       if (!nmbd_init_packet_server()) {
+               kill_async_dns_child();
+                exit(1);
+        }
 
        TALLOC_FREE(frame);
-       process();
+       process(msg);
 
-       if (dbf)
-               x_fclose(dbf);
        kill_async_dns_child();
        return(0);
 }