RIP BOOL. Convert BOOL -> bool. I found a few interesting
[sfrench/samba-autobuild/.git] / source / smbd / server.c
index e95f3cf4a2b803c8a30fd5c1a77cb0d91b32a754..05bb3504c76805e4a81b0e662af7981903b4ced5 100644 (file)
@@ -4,11 +4,10 @@
    Copyright (C) Andrew Tridgell               1992-1998
    Copyright (C) Martin Pool                   2002
    Copyright (C) Jelmer Vernooij               2002-2003
-   Copyright (C) James Peach                   2007
    
    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,
@@ -17,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 <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
@@ -67,7 +65,7 @@ struct event_context *smbd_event_context(void)
        static struct event_context *ctx;
 
        if (!ctx && !(ctx = event_context_init(NULL))) {
-               smb_panic("Could not init smbd event context\n");
+               smb_panic("Could not init smbd event context");
        }
        return ctx;
 }
@@ -78,7 +76,7 @@ struct messaging_context *smbd_messaging_context(void)
 
        if (!ctx && !(ctx = messaging_init(NULL, server_id_self(),
                                           smbd_event_context()))) {
-               smb_panic("Could not init smbd messaging context\n");
+               smb_panic("Could not init smbd messaging context");
        }
        return ctx;
 }
@@ -166,33 +164,12 @@ static void msg_sam_sync(struct messaging_context *msg,
         DEBUG(10, ("** sam sync message received, ignoring\n"));
 }
 
-/****************************************************************************
- Process a sam sync replicate message - not sure whether to do this here or
- somewhere else.
-****************************************************************************/
-
-static void msg_sam_repl(struct messaging_context *msg,
-                        void *private_data,
-                        uint32_t msg_type,
-                        struct server_id server_id,
-                        DATA_BLOB *data)
-{
-        uint32 low_serial;
-
-        if (data->length != sizeof(low_serial))
-                return;
-
-        low_serial = *((uint32 *)data->data);
-
-        DEBUG(3, ("received sam replication message, serial = 0x%04x\n",
-                  low_serial));
-}
 
 /****************************************************************************
  Open the socket communication - inetd.
 ****************************************************************************/
 
-static BOOL open_sockets_inetd(void)
+static bool open_sockets_inetd(void)
 {
        /* Started from inetd. fd 0 is the socket. */
        /* We will abort gracefully when the client or remote system 
@@ -305,7 +282,7 @@ static void remove_child_pid(pid_t pid)
  Have we reached the process limit ?
 ****************************************************************************/
 
-static BOOL allowable_number_of_smbd_processes(void)
+static bool allowable_number_of_smbd_processes(void)
 {
        int max_processes = lp_max_smbd_processes();
 
@@ -319,20 +296,22 @@ static BOOL allowable_number_of_smbd_processes(void)
  Open the socket communication.
 ****************************************************************************/
 
-static BOOL open_sockets_smbd(enum smb_server_mode server_mode, const char *smb_ports)
+static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_ports)
 {
+       int num_interfaces = iface_count();
        int num_sockets = 0;
        int fd_listenset[FD_SETSIZE];
        fd_set listen_set;
        int s;
        int maxfd = 0;
        int i;
-       struct timeval idle_timeout = timeval_zero();
+       char *ports;
 
-       if (server_mode == SERVER_MODE_INETD) {
+       if (!is_daemon) {
                return open_sockets_inetd();
        }
 
+               
 #ifdef HAVE_ATEXIT
        {
                static int atexit_set;
@@ -345,28 +324,138 @@ static BOOL open_sockets_smbd(enum smb_server_mode server_mode, const char *smb_
 
        /* Stop zombies */
        CatchSignal(SIGCLD, sig_cld);
-
+                               
        FD_ZERO(&listen_set);
 
-       /* At this point, it doesn't matter what daemon mode we are in, we
-        * need some sockets to listen on.
-        */
-       num_sockets = smbd_sockinit(smb_ports, fd_listenset, &idle_timeout);
-       if (num_sockets == 0) {
-               return False;
+       /* use a reasonable default set of ports - listing on 445 and 139 */
+       if (!smb_ports) {
+               ports = lp_smb_ports();
+               if (!ports || !*ports) {
+                       ports = smb_xstrdup(SMB_PORTS);
+               } else {
+                       ports = smb_xstrdup(ports);
+               }
+       } else {
+               ports = smb_xstrdup(smb_ports);
        }
 
-       for (i = 0; i < num_sockets; ++i) {
-               FD_SET(fd_listenset[i], &listen_set);
-               maxfd = MAX(maxfd, fd_listenset[i]);
-       }
+       if (lp_interfaces() && lp_bind_interfaces_only()) {
+               /* We have been given an interfaces line, and been 
+                  told to only bind to those interfaces. Create a
+                  socket per interface and bind to only these.
+               */
+               
+               /* Now open a listen socket for each of the
+                  interfaces. */
+               for(i = 0; i < num_interfaces; i++) {
+                       const struct sockaddr_storage *ifss =
+                                       iface_n_sockaddr_storage(i);
+                       const struct in_addr *ifip;
+                       fstring tok;
+                       const char *ptr;
+
+                       if (ifss == NULL) {
+                               DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));
+                               continue;
+                       }
+
+                       /* For now only deal with IPv4. */
+                       if (ifss->ss_family != AF_INET) {
+                               continue;
+                       }
+
+                       ifip = &((const struct sockaddr_in *)ifss)->sin_addr;
+
+                       for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) {
+                               unsigned port = atoi(tok);
+                               if (port == 0 || port > 0xffff) {
+                                       continue;
+                               }
+                               s = fd_listenset[num_sockets] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True);
+                               if(s == -1)
+                                       return False;
+
+                               /* ready to listen */
+                               set_socket_options(s,"SO_KEEPALIVE"); 
+                               set_socket_options(s,user_socket_options);
+     
+                               /* Set server socket to non-blocking for the accept. */
+                               set_blocking(s,False); 
+                               if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
+                                       DEBUG(0,("listen: %s\n",strerror(errno)));
+                                       close(s);
+                                       return False;
+                               }
+                               FD_SET(s,&listen_set);
+                               maxfd = MAX( maxfd, s);
+
+                               num_sockets++;
+                               if (num_sockets >= FD_SETSIZE) {
+                                       DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n"));
+                                       return False;
+                               }
+                       }
+               }
+       } else {
+               /* Just bind to 0.0.0.0 - accept connections
+                  from anywhere. */
+
+               fstring tok;
+               const char *ptr;
+
+               num_interfaces = 1;
+               
+               for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) {
+                       unsigned port = atoi(tok);
+                       if (port == 0 || port > 0xffff) continue;
+                       /* open an incoming socket */
+                       s = open_socket_in(SOCK_STREAM, port, 0,
+                                          interpret_addr(lp_socket_address()),True);
+                       if (s == -1)
+                               return(False);
+               
+                       /* ready to listen */
+                       set_socket_options(s,"SO_KEEPALIVE"); 
+                       set_socket_options(s,user_socket_options);
+                       
+                       /* Set server socket to non-blocking for the accept. */
+                       set_blocking(s,False); 
+                       if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
+                               DEBUG(0,("open_sockets_smbd: listen: %s\n",
+                                        strerror(errno)));
+                               close(s);
+                               return False;
+                       }
+
+                       fd_listenset[num_sockets] = s;
+                       FD_SET(s,&listen_set);
+                       maxfd = MAX( maxfd, s);
+
+                       num_sockets++;
+
+                       if (num_sockets >= FD_SETSIZE) {
+                               DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n"));
+                               return False;
+                       }
+               }
+       } 
+
+       SAFE_FREE(ports);
+
+
+       /* Setup the main smbd so that we can get messages. Note that
+          do this after starting listening. This is needed as when in
+          clustered mode, ctdb won't allow us to start doing database
+          operations until it has gone thru a full startup, which
+          includes checking to see that smbd is listening. */
+       claim_connection(NULL,"",FLAG_MSG_GENERAL|FLAG_MSG_SMBD);
 
         /* Listen to messages */
 
        messaging_register(smbd_messaging_context(), NULL,
                           MSG_SMB_SAM_SYNC, msg_sam_sync);
-       messaging_register(smbd_messaging_context(), NULL,
-                          MSG_SMB_SAM_REPL, msg_sam_repl);
        messaging_register(smbd_messaging_context(), NULL,
                           MSG_SHUTDOWN, msg_exit_server);
        messaging_register(smbd_messaging_context(), NULL,
@@ -386,13 +475,10 @@ static BOOL open_sockets_smbd(enum smb_server_mode server_mode, const char *smb_
           for each incoming connection */
        DEBUG(2,("waiting for a connection\n"));
        while (1) {
-               struct timeval now;
+               struct timeval now, idle_timeout;
                fd_set r_fds, w_fds;
                int num;
                
-               /* Free up temporary memory from the main smbd. */
-               lp_TALLOC_FREE();
-
                /* Ensure we respond to PING and DEBUG messages from the main smbd. */
                message_dispatch(smbd_messaging_context());
 
@@ -405,6 +491,8 @@ static BOOL open_sockets_smbd(enum smb_server_mode server_mode, const char *smb_
                        }
                }
 
+               idle_timeout = timeval_zero();
+
                memcpy((char *)&r_fds, (char *)&listen_set, 
                       sizeof(listen_set));
                FD_ZERO(&w_fds);
@@ -417,7 +505,7 @@ static BOOL open_sockets_smbd(enum smb_server_mode server_mode, const char *smb_
                num = sys_select(maxfd+1,&r_fds,&w_fds,NULL,
                                 timeval_is_zero(&idle_timeout) ?
                                 NULL : &idle_timeout);
-               
+
                if (num == -1 && errno == EINTR) {
                        if (got_sig_term) {
                                exit_server_cleanly(NULL);
@@ -433,24 +521,11 @@ static BOOL open_sockets_smbd(enum smb_server_mode server_mode, const char *smb_
 
                        continue;
                }
-
+               
                if (run_events(smbd_event_context(), num, &r_fds, &w_fds)) {
                        continue;
                }
 
-#if 0
-               Deactivated for now, this needs to become a timed event
-               vl
-
-               /* If the idle timeout fired and we don't have any connected
-                * users, exit gracefully. We should be running under a process
-                * controller that will restart us if necessry.
-                */
-               if (num == 0 && count_all_current_connections() == 0) {
-                       exit_server_cleanly("idle timeout");
-               }
-#endif
-
                /* check if we need to reload services */
                check_reload(time(NULL));
 
@@ -486,13 +561,8 @@ static BOOL open_sockets_smbd(enum smb_server_mode server_mode, const char *smb_
                        /* Ensure child is set to blocking mode */
                        set_blocking(smbd_server_fd(),True);
 
-                       /* In interactive mode, return with a connected socket.
-                        * Foreground and daemon modes should fork worker
-                        * processes.
-                        */
-                       if (server_mode == SERVER_MODE_INTERACTIVE) {
+                       if (smbd_server_fd() != -1 && interactive)
                                return True;
-                       }
                        
                        if (allowable_number_of_smbd_processes() &&
                            smbd_server_fd() != -1 &&
@@ -530,7 +600,7 @@ static BOOL open_sockets_smbd(enum smb_server_mode server_mode, const char *smb_
                                 * CLEAR_IF_FIRST flags */
                                if (tdb_reopen_all(1) == -1) {
                                        DEBUG(0,("tdb_reopen_all failed.\n"));
-                                       smb_panic("tdb_reopen_all failed.");
+                                       smb_panic("tdb_reopen_all failed");
                                }
 
                                return True; 
@@ -611,9 +681,9 @@ void reload_printers(void)
  Reload the services file.
 **************************************************************************/
 
-BOOL reload_services(BOOL test)
+bool reload_services(bool test)
 {
-       BOOL ret;
+       bool ret;
        
        if (lp_loaded()) {
                pstring fname;
@@ -704,11 +774,8 @@ static void exit_server_common(enum server_exit_reason how,
        locking_end();
        printing_end();
 
-       server_encryption_shutdown();
-
        if (how != SERVER_EXIT_NORMAL) {
                int oldlevel = DEBUGLEVEL;
-               char *last_inbuf = get_InBuffer();
 
                DEBUGLEVEL = 10;
 
@@ -718,10 +785,6 @@ static void exit_server_common(enum server_exit_reason how,
                DEBUGSEP(0);
 
                log_stack_trace();
-               if (last_inbuf) {
-                       DEBUG(0,("Last message was %s\n", LAST_MESSAGE()));
-                       show_msg(last_inbuf);
-               }
 
                DEBUGLEVEL = oldlevel;
                dump_core();
@@ -753,7 +816,7 @@ void exit_server_fault(void)
  Initialise connect, service and file structs.
 ****************************************************************************/
 
-static BOOL init_structs(void )
+static bool init_structs(void )
 {
        /*
         * Set the machine NETBIOS name if not already
@@ -780,7 +843,7 @@ static BOOL init_structs(void )
 /*
  * Send keepalive packets to our client
  */
-static BOOL keepalive_fn(const struct timeval *now, void *private_data)
+static bool keepalive_fn(const struct timeval *now, void *private_data)
 {
        if (!send_keepalive(smbd_server_fd())) {
                DEBUG( 2, ( "Keepalive failed - exiting.\n" ) );
@@ -792,7 +855,7 @@ static BOOL keepalive_fn(const struct timeval *now, void *private_data)
 /*
  * Do the recurring check if we're idle
  */
-static BOOL deadtime_fn(const struct timeval *now, void *private_data)
+static bool deadtime_fn(const struct timeval *now, void *private_data)
 {
        if ((conn_num_open() == 0)
            || (conn_idle_all(now->tv_sec))) {
@@ -814,30 +877,28 @@ static BOOL deadtime_fn(const struct timeval *now, void *private_data)
    mkproto.h.  Mixing $(builddir) and $(srcdir) source files in the current
    prototype generation system is too complicated. */
 
-extern void build_options(BOOL screen);
+extern void build_options(bool screen);
 
  int main(int argc,const char *argv[])
 {
        /* shall I run as a daemon */
-       BOOL no_process_group = False;
-       BOOL log_stdout = False;
-       const char *ports = NULL;
-       const char *profile_level = NULL;
+       static bool is_daemon = False;
+       static bool interactive = False;
+       static bool Fork = True;
+       static bool no_process_group = False;
+       static bool log_stdout = False;
+       static char *ports = NULL;
+       static char *profile_level = NULL;
        int opt;
        poptContext pc;
-
-       enum smb_server_mode server_mode = SERVER_MODE_DAEMON;
+       bool print_build_options = False;
 
        struct poptOption long_options[] = {
        POPT_AUTOHELP
-       {"daemon", 'D', POPT_ARG_VAL, &server_mode, SERVER_MODE_DAEMON,
-               "Become a daemon (default)" },
-       {"interactive", 'i', POPT_ARG_VAL, &server_mode, SERVER_MODE_INTERACTIVE,
-               "Run interactive (not a daemon)"},
-       {"foreground", 'F', POPT_ARG_VAL, &server_mode, SERVER_MODE_FOREGROUND,
-               "Run daemon in foreground (for daemontools, etc.)" },
-       {"no-process-group", '\0', POPT_ARG_VAL, &no_process_group, True,
-               "Don't create a new process group" },
+       {"daemon", 'D', POPT_ARG_VAL, &is_daemon, True, "Become a daemon (default)" },
+       {"interactive", 'i', POPT_ARG_VAL, &interactive, True, "Run interactive (not a daemon)"},
+       {"foreground", 'F', POPT_ARG_VAL, &Fork, False, "Run daemon in foreground (for daemontools, etc.)" },
+       {"no-process-group", '\0', POPT_ARG_VAL, &no_process_group, True, "Don't create a new process group" },
        {"log-stdout", 'S', POPT_ARG_VAL, &log_stdout, True, "Log to stdout" },
        {"build-options", 'b', POPT_ARG_NONE, NULL, 'b', "Print build options" },
        {"port", 'p', POPT_ARG_STRING, &ports, 0, "Listen on the specified ports"},
@@ -856,18 +917,25 @@ extern void build_options(BOOL screen);
 #endif
 
        pc = poptGetContext("smbd", argc, argv, long_options, 0);
-       
        while((opt = poptGetNextOpt(pc)) != -1) {
                switch (opt)  {
                case 'b':
-                       build_options(True); /* Display output to screen as well as debug */ 
-                       exit(0);
+                       print_build_options = True;
                        break;
+               default:
+                       d_fprintf(stderr, "\nInvalid option %s: %s\n\n",
+                                 poptBadOption(pc, 0), poptStrerror(opt));
+                       poptPrintUsage(pc, stderr, 0);
+                       exit(1);
                }
        }
-
        poptFreeContext(pc);
 
+       if (print_build_options) {
+               build_options(True); /* Display output to screen as well as debug */
+               exit(0);
+       }
+
 #ifdef HAVE_SETLUID
        /* needed for SecureWare on SCO */
        setluid(0);
@@ -877,14 +945,16 @@ extern void build_options(BOOL screen);
 
        set_remote_machine_name("smbd", False);
 
-       if (server_mode == SERVER_MODE_INTERACTIVE) {
+       if (interactive) {
+               Fork = False;
                log_stdout = True;
-               if (DEBUGLEVEL >= 9) {
-                       talloc_enable_leak_report();
-               }
        }
 
-       if (log_stdout && server_mode == SERVER_MODE_DAEMON) {
+       if (interactive && (DEBUGLEVEL >= 9)) {
+               talloc_enable_leak_report();
+       }
+
+       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);
        }
@@ -974,19 +1044,21 @@ extern void build_options(BOOL screen);
 
        DEBUG(3,( "loaded services\n"));
 
-       if (is_a_socket(0)) {
-               if (server_mode == SERVER_MODE_DAEMON) {
-                       DEBUG(0,("standard input is a socket, "
-                                   "assuming -F option\n"));
-               }
-               server_mode = SERVER_MODE_INETD;
+       if (!is_daemon && !is_a_socket(0)) {
+               if (!interactive)
+                       DEBUG(0,("standard input is not a socket, assuming -D option\n"));
+
+               /*
+                * Setting is_daemon here prevents us from eventually calling
+                * the open_sockets_inetd()
+                */
+
+               is_daemon = True;
        }
 
-       if (server_mode == SERVER_MODE_DAEMON) {
+       if (is_daemon && !interactive) {
                DEBUG( 3, ( "Becoming a daemon.\n" ) );
-               become_daemon(True, no_process_group);
-       } else if (server_mode == SERVER_MODE_FOREGROUND) {
-               become_daemon(False, no_process_group);
+               become_daemon(Fork, no_process_group);
        }
 
 #if HAVE_SETPGID
@@ -994,18 +1066,15 @@ extern void build_options(BOOL screen);
         * If we're interactive we want to set our own process group for
         * signal management.
         */
-       if (server_mode == SERVER_MODE_INTERACTIVE && !no_process_group) {
+       if (interactive && !no_process_group)
                setpgid( (pid_t)0, (pid_t)0);
-       }
 #endif
 
        if (!directory_exist(lp_lockdir(), NULL))
                mkdir(lp_lockdir(), 0755);
 
-       if (server_mode != SERVER_MODE_INETD &&
-           server_mode != SERVER_MODE_INTERACTIVE) {
+       if (is_daemon)
                pidfile_create("smbd");
-       }
 
        /* Setup all the TDB's - including CLEAR_IF_FIRST tdb's. */
 
@@ -1055,19 +1124,13 @@ extern void build_options(BOOL screen);
                return -1;
        }
 
-       /* Setup the main smbd so that we can get messages. */
-       /* don't worry about general printing messages here */
-
-       claim_connection(NULL,"",FLAG_MSG_GENERAL|FLAG_MSG_SMBD);
-
        /* only start the background queue daemon if we are 
           running as a daemon -- bad things will happen if
           smbd is launched via inetd and we fork a copy of 
           ourselves here */
-       if (server_mode != SERVER_MODE_INETD &&
-           server_mode != SERVER_MODE_INTERACTIVE) {
+
+       if ( is_daemon && !interactive )
                start_background_queue(); 
-       }
 
        /* Always attempt to initialize DMAPI. We will only use it later if
         * lp_dmapi_support is set on the share, but we need a single global
@@ -1075,9 +1138,8 @@ extern void build_options(BOOL screen);
         */
        dmapi_init_session();
 
-       if (!open_sockets_smbd(server_mode, ports)) {
+       if (!open_sockets_smbd(is_daemon, interactive, ports))
                exit(1);
-       }
 
        /*
         * everything after this point is run after the fork()
@@ -1090,8 +1152,7 @@ extern void build_options(BOOL screen);
        /* Possibly reload the services file. Only worth doing in
         * daemon mode. In inetd mode, we know we only just loaded this.
         */
-       if (server_mode != SERVER_MODE_INETD &&
-           server_mode != SERVER_MODE_INTERACTIVE) {
+       if (is_daemon) {
                reload_services(True);
        }
 
@@ -1112,6 +1173,13 @@ extern void build_options(BOOL screen);
        /* Setup aio signal handler. */
        initialize_async_io_handler();
 
+       /*
+        * For clustering, we need to re-init our ctdbd connection after the
+        * fork
+        */
+       if (!NT_STATUS_IS_OK(messaging_reinit(smbd_messaging_context())))
+               exit(1);
+
        /* register our message handlers */
        messaging_register(smbd_messaging_context(), NULL,
                           MSG_SMB_FORCE_TDIS, msg_force_tdis);