Remove sys_chroot() - libreplace already provides an alternative.
[kai/samba.git] / source3 / smbd / server.c
index 61e20ce2740d62428eddf12848baeedf3c10ed50..7583da65a52e79b5f81b3a84260a23848c6ff26e 100644 (file)
@@ -1,20 +1,22 @@
-/* 
+/*
    Unix SMB/CIFS implementation.
    Main SMB server routines
    Copyright (C) Andrew Tridgell               1992-1998
    Copyright (C) Martin Pool                   2002
    Copyright (C) Jelmer Vernooij               2002-2003
-   
+   Copyright (C) Volker Lendecke               1993-2007
+   Copyright (C) Jeremy Allison                        1993-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 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/>.
 */
@@ -25,14 +27,7 @@ static_decl_rpc;
 
 static int am_parent = 1;
 
-/* the last message the was processed */
-int last_message = -1;
-
-/* a useful macro to debug the last message processed */
-#define LAST_MESSAGE() smb_fn_name(last_message)
-
 extern struct auth_context *negprot_global_auth_context;
-extern pstring user_socket_options;
 extern SIG_ATOMIC_T got_sig_term;
 extern SIG_ATOMIC_T reload_after_sighup;
 static SIG_ATOMIC_T got_sig_cld;
@@ -57,7 +52,28 @@ int smbd_server_fd(void)
 static void smbd_set_server_fd(int fd)
 {
        server_fd = fd;
-       client_setfd(fd);
+}
+
+int get_client_fd(void)
+{
+       return server_fd;
+}
+
+int client_get_tcp_info(struct sockaddr_in *server, struct sockaddr_in *client)
+{
+       socklen_t length;
+       if (server_fd == -1) {
+               return -1;
+       }
+       length = sizeof(*server);
+       if (getsockname(server_fd, (struct sockaddr *)server, &length) != 0) {
+               return -1;
+       }
+       length = sizeof(*client);
+       if (getpeername(server_fd, (struct sockaddr *)client, &length) != 0) {
+               return -1;
+       }
+       return 0;
 }
 
 struct event_context *smbd_event_context(void)
@@ -74,13 +90,29 @@ struct messaging_context *smbd_messaging_context(void)
 {
        static struct messaging_context *ctx;
 
-       if (!ctx && !(ctx = messaging_init(NULL, server_id_self(),
-                                          smbd_event_context()))) {
-               smb_panic("Could not init smbd messaging context");
+       if (ctx == NULL) {
+               ctx = messaging_init(NULL, server_id_self(),
+                                    smbd_event_context());
+       }
+       if (ctx == NULL) {
+               DEBUG(0, ("Could not init smbd messaging context.\n"));
        }
        return ctx;
 }
 
+struct memcache *smbd_memcache(void)
+{
+       static struct memcache *cache;
+
+       if (!cache
+           && !(cache = memcache_init(NULL,
+                                      lp_max_stat_cache_size()*1024))) {
+
+               smb_panic("Could not init smbd memcache");
+       }
+       return cache;
+}
+
 /*******************************************************************
  What to do when smb.conf is updated.
  ********************************************************************/
@@ -180,7 +212,7 @@ static bool open_sockets_inetd(void)
        close_low_fds(False); /* Don't close stderr */
        
        set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
-       set_socket_options(smbd_server_fd(), user_socket_options);
+       set_socket_options(smbd_server_fd(), lp_socket_options());
 
        return True;
 }
@@ -256,10 +288,21 @@ static void add_child_pid(pid_t pid)
        num_children += 1;
 }
 
-static void remove_child_pid(pid_t pid)
+static void remove_child_pid(pid_t pid, bool unclean_shutdown)
 {
        struct child_pid *child;
 
+       if (unclean_shutdown) {
+               /* a child terminated uncleanly so tickle all processes to see 
+                  if they can grab any of the pending locks
+               */
+               DEBUG(3,(__location__ " Unclean shutdown of pid %u\n", pid));
+               messaging_send_buf(smbd_messaging_context(), procid_self(), 
+                                  MSG_SMB_BRL_VALIDATE, NULL, 0);
+               message_send_all(smbd_messaging_context(), 
+                                MSG_SMB_UNLOCK, NULL, 0, NULL);
+       }
+
        if (lp_max_smbd_processes() == 0) {
                /* Don't bother with the child list if we don't care anyway */
                return;
@@ -306,6 +349,8 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
        int maxfd = 0;
        int i;
        char *ports;
+       struct dns_reg_state * dns_reg = NULL;
+       unsigned dns_port = 0;
 
        if (!is_daemon) {
                return open_sockets_inetd();
@@ -347,9 +392,10 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
                /* Now open a listen socket for each of the
                   interfaces. */
                for(i = 0; i < num_interfaces; i++) {
+                       TALLOC_CTX *frame = NULL;
                        const struct sockaddr_storage *ifss =
                                        iface_n_sockaddr_storage(i);
-                       fstring tok;
+                       char *tok;
                        const char *ptr;
 
                        if (ifss == NULL) {
@@ -359,22 +405,34 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
                                continue;
                        }
 
-                       for (ptr=ports; next_token(&ptr, tok, " \t,",
-                                               sizeof(tok)); ) {
+                       frame = talloc_stackframe();
+                       for (ptr=ports;
+                                       next_token_talloc(frame,&ptr, &tok, " \t,");) {
                                unsigned port = atoi(tok);
                                if (port == 0 || port > 0xffff) {
                                        continue;
                                }
+
+                               /* Keep the first port for mDNS service
+                                * registration.
+                                */
+                               if (dns_port == 0) {
+                                       dns_port = port;
+                               }
+
                                s = fd_listenset[num_sockets] =
-                                       open_socket_in(SOCK_STREAM, port, 0,
-                                                       ifss, True);
+                                       open_socket_in(SOCK_STREAM,
+                                                       port,
+                                                       num_sockets == 0 ? 0 : 2,
+                                                       ifss,
+                                                       true);
                                if(s == -1) {
-                                       return false;
+                                       continue;
                                }
 
                                /* ready to listen */
                                set_socket_options(s,"SO_KEEPALIVE");
-                               set_socket_options(s,user_socket_options);
+                               set_socket_options(s,lp_socket_options());
 
                                /* Set server socket to
                                 * non-blocking for the accept. */
@@ -384,6 +442,7 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
                                        DEBUG(0,("open_sockets_smbd: listen: "
                                                "%s\n", strerror(errno)));
                                        close(s);
+                                       TALLOC_FREE(frame);
                                        return False;
                                }
                                FD_SET(s,&listen_set);
@@ -393,21 +452,25 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
                                if (num_sockets >= FD_SETSIZE) {
                                        DEBUG(0,("open_sockets_smbd: Too "
                                                "many sockets to bind to\n"));
+                                       TALLOC_FREE(frame);
                                        return False;
                                }
                        }
+                       TALLOC_FREE(frame);
                }
        } else {
                /* Just bind to 0.0.0.0 - accept connections
                   from anywhere. */
 
-               fstring tok;
+               TALLOC_CTX *frame = talloc_stackframe();
+               char *tok;
                const char *ptr;
                const char *sock_addr = lp_socket_address();
-               fstring sock_tok;
+               char *sock_tok;
                const char *sock_ptr;
 
-               if (strequal(sock_addr, "0.0.0.0") ||
+               if (sock_addr[0] == '\0' ||
+                               strequal(sock_addr, "0.0.0.0") ||
                                strequal(sock_addr, "::")) {
 #if HAVE_IPV6
                        sock_addr = "::,0.0.0.0";
@@ -416,31 +479,41 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
 #endif
                }
 
-               for (sock_ptr=sock_addr; next_token(&sock_ptr, sock_tok, " \t,",
-                                       sizeof(sock_tok)); ) {
-                       for (ptr=ports; next_token(&ptr, tok, " \t,",
-                                               sizeof(tok)); ) {
+               for (sock_ptr=sock_addr;
+                               next_token_talloc(frame, &sock_ptr, &sock_tok, " \t,"); ) {
+                       for (ptr=ports; next_token_talloc(frame, &ptr, &tok, " \t,"); ) {
                                struct sockaddr_storage ss;
 
                                unsigned port = atoi(tok);
                                if (port == 0 || port > 0xffff) {
                                        continue;
                                }
+
+                               /* Keep the first port for mDNS service
+                                * registration.
+                                */
+                               if (dns_port == 0) {
+                                       dns_port = port;
+                               }
+
                                /* open an incoming socket */
                                if (!interpret_string_addr(&ss, sock_tok,
                                                AI_NUMERICHOST|AI_PASSIVE)) {
-                                       return false;
+                                       continue;
                                }
 
-                               s = open_socket_in(SOCK_STREAM, port, 0,
-                                                  &ss, true);
+                               s = open_socket_in(SOCK_STREAM,
+                                               port,
+                                               num_sockets == 0 ? 0 : 2,
+                                               &ss,
+                                               true);
                                if (s == -1) {
-                                       return false;
+                                       continue;
                                }
 
                                /* ready to listen */
                                set_socket_options(s,"SO_KEEPALIVE");
-                               set_socket_options(s,user_socket_options);
+                               set_socket_options(s,lp_socket_options());
 
                                /* Set server socket to non-blocking
                                 * for the accept. */
@@ -451,6 +524,7 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
                                                "listen: %s\n",
                                                 strerror(errno)));
                                        close(s);
+                                       TALLOC_FREE(frame);
                                        return False;
                                }
 
@@ -463,21 +537,29 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
                                if (num_sockets >= FD_SETSIZE) {
                                        DEBUG(0,("open_sockets_smbd: Too "
                                                "many sockets to bind to\n"));
+                                       TALLOC_FREE(frame);
                                        return False;
                                }
                        }
                }
+               TALLOC_FREE(frame);
        }
 
        SAFE_FREE(ports);
 
+       if (num_sockets == 0) {
+               DEBUG(0,("open_sockets_smbd: No "
+                       "sockets available to bind to.\n"));
+               return false;
+       }
 
        /* 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);
+       claim_connection(NULL,"",
+                        FLAG_MSG_GENERAL|FLAG_MSG_SMBD|FLAG_MSG_DBWRAP);
 
         /* Listen to messages */
 
@@ -493,6 +575,12 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
                           MSG_SMB_STAT_CACHE_DELETE, smb_stat_cache_delete);
        brl_register_msgs(smbd_messaging_context());
 
+#ifdef CLUSTER_SUPPORT
+       if (lp_clustering()) {
+               ctdbd_register_reconfigure(messaging_ctdbd_connection());
+       }
+#endif
+
 #ifdef DEVELOPER
        messaging_register(smbd_messaging_context(), NULL,
                           MSG_SMB_INJECT_FAULT, msg_inject_fault);
@@ -511,10 +599,27 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
 
                if (got_sig_cld) {
                        pid_t pid;
+                       int status;
+
                        got_sig_cld = False;
 
-                       while ((pid = sys_waitpid(-1, NULL, WNOHANG)) > 0) {
-                               remove_child_pid(pid);
+                       while ((pid = sys_waitpid(-1, &status, WNOHANG)) > 0) {
+                               bool unclean_shutdown = False;
+                               
+                               /* If the child terminated normally, assume
+                                  it was an unclean shutdown unless the
+                                  status is 0 
+                               */
+                               if (WIFEXITED(status)) {
+                                       unclean_shutdown = WEXITSTATUS(status);
+                               }
+                               /* If the child terminated due to a signal
+                                  we always assume it was unclean.
+                               */
+                               if (WIFSIGNALED(status)) {
+                                       unclean_shutdown = True;
+                               }
+                               remove_child_pid(pid, unclean_shutdown);
                        }
                }
 
@@ -525,6 +630,12 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
                FD_ZERO(&w_fds);
                GetTimeOfDay(&now);
 
+               /* Kick off our mDNS registration. */
+               if (dns_port != 0) {
+                       dns_register_smbd(&dns_reg, dns_port, &maxfd,
+                                       &r_fds, &idle_timeout);
+               }
+
                event_add_to_select_args(smbd_event_context(), &now,
                                         &r_fds, &w_fds, &idle_timeout,
                                         &maxfd);
@@ -548,6 +659,20 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
 
                        continue;
                }
+               
+
+               /* 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");
+               }
+
+               /* process pending nDNS responses */
+               if (dns_register_smbd_reply(dns_reg, &r_fds, &idle_timeout)) {
+                       --num;
+               }
 
                if (run_events(smbd_event_context(), num, &r_fds, &w_fds)) {
                        continue;
@@ -580,7 +705,7 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
                                continue;
 
                        if (smbd_server_fd() == -1) {
-                               DEBUG(0,("open_sockets_smbd: accept: %s\n",
+                               DEBUG(2,("open_sockets_smbd: accept: %s\n",
                                         strerror(errno)));
                                continue;
                        }
@@ -594,6 +719,8 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
                        if (allowable_number_of_smbd_processes() &&
                            smbd_server_fd() != -1 &&
                            ((child = sys_fork())==0)) {
+                               char remaddr[INET6_ADDRSTRLEN];
+
                                /* Child code ... */
 
                                /* Stop zombies, the parent explicitly handles
@@ -604,30 +731,29 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
                                for(i = 0; i < num_sockets; i++)
                                        close(fd_listenset[i]);
 
+                               /* close our mDNS daemon handle */
+                               dns_register_close(&dns_reg);
+
                                /* close our standard file
                                   descriptors */
                                close_low_fds(False);
                                am_parent = 0;
 
                                set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
-                               set_socket_options(smbd_server_fd(),user_socket_options);
+                               set_socket_options(smbd_server_fd(),
+                                                  lp_socket_options());
 
                                /* this is needed so that we get decent entries
                                   in smbstatus for port 445 connects */
-                               set_remote_machine_name(get_peer_addr(smbd_server_fd()),
-                                                       False);
-
-                               /* Reset the state of the random
-                                * number generation system, so
-                                * children do not get the same random
-                                * numbers as each other */
-
-                               set_need_random_reseed();
-                               /* tdb needs special fork handling - remove
-                                * CLEAR_IF_FIRST flags */
-                               if (tdb_reopen_all(1) == -1) {
-                                       DEBUG(0,("tdb_reopen_all failed.\n"));
-                                       smb_panic("tdb_reopen_all failed");
+                               set_remote_machine_name(get_peer_addr(smbd_server_fd(),
+                                                               remaddr,
+                                                               sizeof(remaddr)),
+                                                               false);
+
+                               if (!reinit_after_fork(
+                                           smbd_messaging_context(), true)) {
+                                       DEBUG(0,("reinit_after_fork() failed\n"));
+                                       smb_panic("reinit_after_fork() failed");
                                }
 
                                return True;
@@ -711,13 +837,12 @@ void reload_printers(void)
 bool reload_services(bool test)
 {
        bool ret;
-       
+
        if (lp_loaded()) {
-               pstring fname;
-               pstrcpy(fname,lp_configfile());
-               if (file_exist(fname, NULL) &&
-                   !strcsequal(fname, dyn_CONFIGFILE)) {
-                       pstrcpy(dyn_CONFIGFILE, fname);
+               char *fname = lp_configfile();
+               if (file_exist(fname) &&
+                   !strcsequal(fname, get_dyn_CONFIGFILE())) {
+                       set_dyn_CONFIGFILE(fname);
                        test = False;
                }
        }
@@ -729,7 +854,7 @@ bool reload_services(bool test)
 
        lp_killunused(conn_snum_used);
 
-       ret = lp_load(dyn_CONFIGFILE, False, False, True, True);
+       ret = lp_load(get_dyn_CONFIGFILE(), False, False, True, True);
 
        reload_printers();
 
@@ -741,9 +866,9 @@ bool reload_services(bool test)
 
        load_interfaces();
 
-       if (smbd_server_fd() != -1) {      
+       if (smbd_server_fd() != -1) {
                set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
-               set_socket_options(smbd_server_fd(), user_socket_options);
+               set_socket_options(smbd_server_fd(), lp_socket_options());
        }
 
        mangle_reset_cache();
@@ -763,12 +888,13 @@ bool reload_services(bool test)
 enum server_exit_reason { SERVER_EXIT_NORMAL, SERVER_EXIT_ABNORMAL };
 
 static void exit_server_common(enum server_exit_reason how,
-       const char *const reason) NORETURN_ATTRIBUTE;
+       const char *const reason) _NORETURN_;
 
 static void exit_server_common(enum server_exit_reason how,
        const char *const reason)
 {
        static int firsttime=1;
+       bool had_open_conn;
 
        if (!firsttime)
                exit(0);
@@ -780,7 +906,7 @@ static void exit_server_common(enum server_exit_reason how,
                (negprot_global_auth_context->free)(&negprot_global_auth_context);
        }
 
-       conn_close_all();
+       had_open_conn = conn_close_all();
 
        invalidate_all_vuids();
 
@@ -798,6 +924,15 @@ static void exit_server_common(enum server_exit_reason how,
        }
 #endif
 
+#ifdef USE_DMAPI
+       /* Destroy Samba DMAPI session only if we are master smbd process */
+       if (am_parent) {
+               if (!dmapi_destroy_session()) {
+                       DEBUG(0,("Unable to close Samba DMAPI session\n"));
+               }
+       }
+#endif
+
        locking_end();
        printing_end();
 
@@ -821,7 +956,15 @@ static void exit_server_common(enum server_exit_reason how,
                        (reason ? reason : "normal exit")));
        }
 
-       exit(0);
+       /* if we had any open SMB connections when we exited then we
+          need to tell the parent smbd so that it can trigger a retry
+          of any locks we may have been holding or open files we were
+          blocking */
+       if (had_open_conn) {
+               exit(1);
+       } else {
+               exit(0);
+       }
 }
 
 void exit_server(const char *const explanation)
@@ -839,6 +982,34 @@ void exit_server_fault(void)
        exit_server("critical server fault");
 }
 
+
+/****************************************************************************
+received when we should release a specific IP
+****************************************************************************/
+static void release_ip(const char *ip, void *priv)
+{
+       char addr[INET6_ADDRSTRLEN];
+
+       if (strcmp(client_socket_addr(get_client_fd(),addr,sizeof(addr)), ip) == 0) {
+               /* we can't afford to do a clean exit - that involves
+                  database writes, which would potentially mean we
+                  are still running after the failover has finished -
+                  we have to get rid of this process ID straight
+                  away */
+               DEBUG(0,("Got release IP message for our IP %s - exiting immediately\n",
+                       ip));
+               /* note we must exit with non-zero status so the unclean handler gets
+                  called in the parent, so that the brl database is tickled */
+               _exit(1);
+       }
+}
+
+static void msg_release_ip(struct messaging_context *msg_ctx, void *private_data,
+                          uint32_t msg_type, struct server_id server_id, DATA_BLOB *data)
+{
+       release_ip((char *)data->data, NULL);
+}
+
 /****************************************************************************
  Initialise connect, service and file structs.
 ****************************************************************************/
@@ -862,7 +1033,8 @@ static bool init_structs(void )
 
        init_dptrs();
 
-       secrets_init();
+       if (!secrets_init())
+               return False;
 
        return True;
 }
@@ -895,6 +1067,30 @@ static bool deadtime_fn(const struct timeval *now, void *private_data)
        return True;
 }
 
+/*
+ * Do the recurring log file and smb.conf reload checks.
+ */
+
+static bool housekeeping_fn(const struct timeval *now, void *private_data)
+{
+       change_to_root_user();
+
+       /* update printer queue caches if necessary */
+       update_monitored_printq_cache();
+
+       /* check if we need to reload services */
+       check_reload(time(NULL));
+
+       /* Change machine password if neccessary. */
+       attempt_machine_password_change();
+
+        /*
+        * Force a log file check.
+        */
+        force_check_log_size();
+        check_log_size();
+       return true;
+}
 
 /****************************************************************************
  main program.
@@ -940,8 +1136,7 @@ extern void build_options(bool screen);
        POPT_COMMON_DYNCONFIG
        POPT_TABLEEND
        };
-
-       load_case_tables();
+       TALLOC_CTX *frame = talloc_stackframe(); /* Setup tos. */
 
        TimeInit();
 
@@ -979,11 +1174,20 @@ extern void build_options(bool screen);
        }
        poptFreeContext(pc);
 
+       if (interactive) {
+               Fork = False;
+               log_stdout = True;
+       }
+
+       setup_logging(argv[0],log_stdout);
+
        if (print_build_options) {
                build_options(True); /* Display output to screen as well as debug */
                exit(0);
        }
 
+       load_case_tables();
+
 #ifdef HAVE_SETLUID
        /* needed for SecureWare on SCO */
        setluid(0);
@@ -993,11 +1197,6 @@ extern void build_options(bool screen);
 
        set_remote_machine_name("smbd", False);
 
-       if (interactive) {
-               Fork = False;
-               log_stdout = True;
-       }
-
        if (interactive && (DEBUGLEVEL >= 9)) {
                talloc_enable_leak_report();
        }
@@ -1007,8 +1206,6 @@ extern void build_options(bool screen);
                exit(1);
        }
 
-       setup_logging(argv[0],log_stdout);
-
        /* we want to re-seed early to prevent time delays causing
            client problems at a later date. (tridge) */
        generate_random_buffer(NULL, 0);
@@ -1052,8 +1249,8 @@ extern void build_options(bool screen);
 
        reopen_logs();
 
-       DEBUG(0,( "smbd version %s started.\n", SAMBA_VERSION_STRING));
-       DEBUGADD( 0, ( "%s\n", COPYRIGHT_STARTUP_MESSAGE ) );
+       DEBUG(0,("smbd version %s started.\n", SAMBA_VERSION_STRING));
+       DEBUGADD(0,("%s\n", COPYRIGHT_STARTUP_MESSAGE));
 
        DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n",
                 (int)getuid(),(int)getgid(),(int)geteuid(),(int)getegid()));
@@ -1066,9 +1263,13 @@ extern void build_options(bool screen);
                exit(1);
        }
 
-       /*
-        * Do this before reload_services.
-        */
+       if (!lp_load_initial_only(get_dyn_CONFIGFILE())) {
+               DEBUG(0, ("error opening config file\n"));
+               exit(1);
+       }
+
+       if (smbd_messaging_context() == NULL)
+               exit(1);
 
        if (!reload_services(False))
                return(-1);     
@@ -1118,16 +1319,24 @@ extern void build_options(bool screen);
                setpgid( (pid_t)0, (pid_t)0);
 #endif
 
-       if (!directory_exist(lp_lockdir(), NULL))
+       if (!directory_exist(lp_lockdir()))
                mkdir(lp_lockdir(), 0755);
 
        if (is_daemon)
                pidfile_create("smbd");
 
+       if (!reinit_after_fork(smbd_messaging_context(), false)) {
+               DEBUG(0,("reinit_after_fork() failed\n"));
+               exit(1);
+       }
+
        /* Setup all the TDB's - including CLEAR_IF_FIRST tdb's. */
 
-       if (smbd_messaging_context() == NULL)
+       if (smbd_memcache() == NULL) {
                exit(1);
+       }
+
+       memcache_set_global(smbd_memcache());
 
        /* Initialise the password backed before the global_sam_sid
           to ensure that we fetch from ldap before we make a domain sid up */
@@ -1151,12 +1360,12 @@ extern void build_options(bool screen);
        if (!connections_init(True))
                exit(1);
 
-       if (!locking_init(0))
+       if (!locking_init())
                exit(1);
 
        namecache_enable();
 
-       if (!init_registry())
+       if (!W_ERROR_IS_OK(registry_init_full()))
                exit(1);
 
 #if 0
@@ -1177,14 +1386,10 @@ extern void build_options(bool screen);
           smbd is launched via inetd and we fork a copy of 
           ourselves here */
 
-       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
-        * session to work with.
-        */
-       dmapi_init_session();
+       if (is_daemon && !interactive
+           && lp_parm_bool(-1, "smbd", "backgroundqueue", true)) {
+               start_background_queue();
+       }
 
        if (!open_sockets_smbd(is_daemon, interactive, ports))
                exit(1);
@@ -1210,27 +1415,24 @@ extern void build_options(bool screen);
        }
 
        if (*lp_rootdir()) {
-               if (sys_chroot(lp_rootdir()) == 0)
+               if (chroot(lp_rootdir()) == 0)
                        DEBUG(2,("Changed root to %s\n", lp_rootdir()));
        }
 
        /* Setup oplocks */
        if (!init_oplocks(smbd_messaging_context()))
                exit(1);
-       
+
        /* 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);
+       messaging_register(smbd_messaging_context(), NULL,
+                          MSG_SMB_RELEASE_IP, msg_release_ip);
+       messaging_register(smbd_messaging_context(), NULL,
+                          MSG_SMB_CLOSE_FILE, msg_close_file);
 
        if ((lp_keepalive() != 0)
            && !(event_add_idle(smbd_event_context(), NULL,
@@ -1248,6 +1450,49 @@ extern void build_options(bool screen);
                exit(1);
        }
 
+       if (!(event_add_idle(smbd_event_context(), NULL,
+                            timeval_set(SMBD_SELECT_TIMEOUT, 0),
+                            "housekeeping", housekeeping_fn, NULL))) {
+               DEBUG(0, ("Could not add housekeeping event\n"));
+               exit(1);
+       }
+
+#ifdef CLUSTER_SUPPORT
+
+       if (lp_clustering()) {
+               /*
+                * We need to tell ctdb about our client's TCP
+                * connection, so that for failover ctdbd can send
+                * tickle acks, triggering a reconnection by the
+                * client.
+                */
+
+               struct sockaddr_in srv, clnt;
+
+               if (client_get_tcp_info(&srv, &clnt) == 0) {
+
+                       NTSTATUS status;
+
+                       status = ctdbd_register_ips(
+                               messaging_ctdbd_connection(),
+                               &srv, &clnt, release_ip, NULL);
+
+                       if (!NT_STATUS_IS_OK(status)) {
+                               DEBUG(0, ("ctdbd_register_ips failed: %s\n",
+                                         nt_errstr(status)));
+                       }
+               } else
+               {
+                       DEBUG(0,("Unable to get tcp info for "
+                                "CTDB_CONTROL_TCP_CLIENT: %s\n",
+                                strerror(errno)));
+               }
+       }
+
+#endif
+
+       TALLOC_FREE(frame);
+
        smbd_process();
 
        namecache_shutdown();