s3:smbd: use new function cluster_probe_ok()
[nivanova/samba-autobuild/.git] / source3 / smbd / server.c
index ecda47c644a4dcb3b02092ca638654819f566452..8173a6294d905d431f5e7893477009f27f6fdee5 100644 (file)
@@ -31,6 +31,7 @@
 #include "secrets.h"
 #include "memcache.h"
 #include "ctdbd_conn.h"
+#include "util_cluster.h"
 #include "printing/queue_process.h"
 #include "rpc_server/rpc_service_setup.h"
 #include "rpc_server/rpc_config.h"
 #include "messages.h"
 #include "smbprofile.h"
 #include "lib/id_cache.h"
+#include "lib/param/param.h"
+#include "lib/background.h"
+#include "lib/conn_tdb.h"
+#include "../lib/util/pidfile.h"
+#include "lib/smbd_shim.h"
+#include "scavenger.h"
+
+struct smbd_open_socket;
+struct smbd_child_pid;
+
+struct smbd_parent_context {
+       bool interactive;
+
+       struct tevent_context *ev_ctx;
+       struct messaging_context *msg_ctx;
+
+       /* the list of listening sockets */
+       struct smbd_open_socket *sockets;
+
+       /* the list of current child processes */
+       struct smbd_child_pid *children;
+       size_t num_children;
+
+       struct tevent_timer *cleanup_te;
+};
+
+struct smbd_open_socket {
+       struct smbd_open_socket *prev, *next;
+       struct smbd_parent_context *parent;
+       int fd;
+       struct tevent_fd *fde;
+};
+
+struct smbd_child_pid {
+       struct smbd_child_pid *prev, *next;
+       pid_t pid;
+};
 
 extern void start_epmd(struct tevent_context *ev_ctx,
                       struct messaging_context *msg_ctx);
 
-extern void start_lsasd(struct event_context *ev_ctx,
+extern void start_lsasd(struct tevent_context *ev_ctx,
                        struct messaging_context *msg_ctx);
 
 #ifdef WITH_DFS
@@ -55,22 +93,20 @@ extern int dcelogin_atmost_once;
  What to do when smb.conf is updated.
  ********************************************************************/
 
-static void smb_conf_updated(struct messaging_context *msg,
-                            void *private_data,
-                            uint32_t msg_type,
-                            struct server_id server_id,
-                            DATA_BLOB *data)
+static void smbd_parent_conf_updated(struct messaging_context *msg,
+                                    void *private_data,
+                                    uint32_t msg_type,
+                                    struct server_id server_id,
+                                    DATA_BLOB *data)
 {
        struct tevent_context *ev_ctx =
                talloc_get_type_abort(private_data, struct tevent_context);
 
-       DEBUG(10,("smb_conf_updated: Got message saying smb.conf was "
+       DEBUG(10,("smbd_parent_conf_updated: Got message saying smb.conf was "
                  "updated. Reloading.\n"));
        change_to_root_user();
-       reload_services(msg, smbd_server_conn->sock, False);
-       if (am_parent) {
-               printing_subsystem_update(ev_ctx, msg, false);
-       }
+       reload_services(NULL, NULL, false);
+       printing_subsystem_update(ev_ctx, msg, false);
 }
 
 /*******************************************************************
@@ -115,20 +151,6 @@ static void  killkids(void)
        if(am_parent) kill(0,SIGTERM);
 }
 
-/****************************************************************************
- Process a sam sync message - not sure whether to do this here or
- somewhere else.
-****************************************************************************/
-
-static void msg_sam_sync(struct messaging_context *msg,
-                        void *private_data,
-                        uint32_t msg_type,
-                        struct server_id server_id,
-                        DATA_BLOB *data)
-{
-        DEBUG(10, ("** sam sync message received, ignoring\n"));
-}
-
 static void msg_exit_server(struct messaging_context *msg,
                            void *private_data,
                            uint32_t msg_type,
@@ -168,10 +190,32 @@ static void msg_inject_fault(struct messaging_context *msg,
                  procid_str_static(&src), sig));
 #endif
 
-       kill(sys_getpid(), sig);
+       kill(getpid(), sig);
 }
 #endif /* DEVELOPER */
 
+NTSTATUS messaging_send_to_children(struct messaging_context *msg_ctx,
+                                   uint32_t msg_type, DATA_BLOB* data)
+{
+       NTSTATUS status;
+       struct smbd_parent_context *parent = am_parent;
+       struct smbd_child_pid *child;
+
+       if (parent == NULL) {
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       for (child = parent->children; child != NULL; child = child->next) {
+               status = messaging_send(parent->msg_ctx,
+                                       pid_to_procid(child->pid),
+                                       msg_type, data);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+       }
+       return NT_STATUS_OK;
+}
+
 /*
  * Parent smbd process sets its own debug level first and then
  * sends a message to all the smbd children to adjust their debug
@@ -184,30 +228,161 @@ static void smbd_msg_debug(struct messaging_context *msg_ctx,
                           struct server_id server_id,
                           DATA_BLOB *data)
 {
-       struct child_pid *child;
-
        debug_message(msg_ctx, private_data, MSG_DEBUG, server_id, data);
 
-       for (child = children; child != NULL; child = child->next) {
-               messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
-                                  MSG_DEBUG,
-                                  data->data,
-                                  strlen((char *) data->data) + 1);
+       messaging_send_to_children(msg_ctx, MSG_DEBUG, data);
+}
+
+static void smbd_parent_id_cache_kill(struct messaging_context *msg_ctx,
+                                     void *private_data,
+                                     uint32_t msg_type,
+                                     struct server_id server_id,
+                                     DATA_BLOB* data)
+{
+       const char *msg = (data && data->data)
+               ? (const char *)data->data : "<NULL>";
+       struct id_cache_ref id;
+
+       if (!id_cache_ref_parse(msg, &id)) {
+               DEBUG(0, ("Invalid ?ID: %s\n", msg));
+               return;
        }
+
+       id_cache_delete_from_cache(&id);
+
+       messaging_send_to_children(msg_ctx, msg_type, data);
 }
 
-static void add_child_pid(pid_t pid)
+static void smbd_parent_id_cache_delete(struct messaging_context *ctx,
+                                       void* data,
+                                       uint32_t msg_type,
+                                       struct server_id srv_id,
+                                       DATA_BLOB* msg_data)
+{
+       id_cache_delete_message(ctx, data, msg_type, srv_id, msg_data);
+
+       messaging_send_to_children(ctx, msg_type, msg_data);
+}
+
+struct smbd_parent_notify_state {
+       struct tevent_context *ev;
+       struct messaging_context *msg;
+       uint32_t msgtype;
+       struct notify_context *notify;
+};
+
+static int smbd_parent_notify_cleanup(void *private_data);
+static void smbd_parent_notify_cleanup_done(struct tevent_req *req);
+static void smbd_parent_notify_proxy_done(struct tevent_req *req);
+
+static bool smbd_parent_notify_init(TALLOC_CTX *mem_ctx,
+                                   struct messaging_context *msg,
+                                   struct tevent_context *ev)
 {
-       struct child_pid *child;
+       struct smbd_parent_notify_state *state;
+       struct tevent_req *req;
 
-       child = SMB_MALLOC_P(struct child_pid);
+       state = talloc(mem_ctx, struct smbd_parent_notify_state);
+       if (state == NULL) {
+               return false;
+       }
+       state->msg = msg;
+       state->ev = ev;
+       state->msgtype = MSG_SMB_NOTIFY_CLEANUP;
+
+       state->notify = notify_init(state, msg, ev);
+       if (state->notify == NULL) {
+               goto fail;
+       }
+       req = background_job_send(
+               state, state->ev, state->msg, &state->msgtype, 1,
+               lp_parm_int(-1, "smbd", "notify cleanup interval", 60),
+               smbd_parent_notify_cleanup, state->notify);
+       if (req == NULL) {
+               goto fail;
+       }
+       tevent_req_set_callback(req, smbd_parent_notify_cleanup_done, state);
+
+       if (!lp_clustering()) {
+               return true;
+       }
+
+       req = notify_cluster_proxy_send(state, ev, state->notify);
+       if (req == NULL) {
+               goto fail;
+       }
+       tevent_req_set_callback(req, smbd_parent_notify_proxy_done, state);
+
+       return true;
+fail:
+       TALLOC_FREE(state);
+       return false;
+}
+
+static int smbd_parent_notify_cleanup(void *private_data)
+{
+       struct notify_context *notify = talloc_get_type_abort(
+               private_data, struct notify_context);
+       notify_cleanup(notify);
+       return lp_parm_int(-1, "smbd", "notify cleanup interval", 60);
+}
+
+static void smbd_parent_notify_cleanup_done(struct tevent_req *req)
+{
+       struct smbd_parent_notify_state *state = tevent_req_callback_data(
+               req, struct smbd_parent_notify_state);
+       NTSTATUS status;
+
+       status = background_job_recv(req);
+       TALLOC_FREE(req);
+       DEBUG(1, ("notify cleanup job ended with %s\n", nt_errstr(status)));
+
+       /*
+        * Provide self-healing: Whatever the error condition was, it
+        * will have printed it into log.smbd. Just retrying and
+        * spamming log.smbd once a minute should be fine.
+        */
+       req = background_job_send(
+               state, state->ev, state->msg, &state->msgtype, 1, 60,
+               smbd_parent_notify_cleanup, state->notify);
+       if (req == NULL) {
+               DEBUG(1, ("background_job_send failed\n"));
+               return;
+       }
+       tevent_req_set_callback(req, smbd_parent_notify_cleanup_done, state);
+}
+
+static void smbd_parent_notify_proxy_done(struct tevent_req *req)
+{
+       int ret;
+
+       ret = notify_cluster_proxy_recv(req);
+       TALLOC_FREE(req);
+       DEBUG(1, ("notify proxy job ended with %s\n", strerror(ret)));
+}
+
+static void smb_parent_force_tdis(struct messaging_context *ctx,
+                                 void* data,
+                                 uint32_t msg_type,
+                                 struct server_id srv_id,
+                                 DATA_BLOB* msg_data)
+{
+       messaging_send_to_children(ctx, msg_type, msg_data);
+}
+
+static void add_child_pid(struct smbd_parent_context *parent,
+                         pid_t pid)
+{
+       struct smbd_child_pid *child;
+
+       child = talloc_zero(parent, struct smbd_child_pid);
        if (child == NULL) {
                DEBUG(0, ("Could not add child struct -- malloc failed\n"));
                return;
        }
        child->pid = pid;
-       DLIST_ADD(children, child);
-       num_children += 1;
+       DLIST_ADD(parent->children, child);
+       parent->num_children += 1;
 }
 
 /*
@@ -221,29 +396,49 @@ static void add_child_pid(pid_t pid)
   network outage).  
 */
 
-static void cleanup_timeout_fn(struct event_context *event_ctx,
-                               struct timed_event *te,
+static void cleanup_timeout_fn(struct tevent_context *event_ctx,
+                               struct tevent_timer *te,
                                struct timeval now,
                                void *private_data)
 {
-       struct timed_event **cleanup_te = (struct timed_event **)private_data;
+       struct smbd_parent_context *parent =
+               talloc_get_type_abort(private_data,
+               struct smbd_parent_context);
+
+       parent->cleanup_te = NULL;
 
        DEBUG(1,("Cleaning up brl and lock database after unclean shutdown\n"));
-       message_send_all(smbd_messaging_context(), MSG_SMB_UNLOCK, NULL, 0, NULL);
-       messaging_send_buf(smbd_messaging_context(), procid_self(),
-                               MSG_SMB_BRL_VALIDATE, NULL, 0);
-       /* mark the cleanup as having been done */
-       (*cleanup_te) = NULL;
+       message_send_all(parent->msg_ctx, MSG_SMB_UNLOCK, NULL, 0, NULL);
+       messaging_send_buf(parent->msg_ctx,
+                          messaging_server_id(parent->msg_ctx),
+                          MSG_SMB_BRL_VALIDATE, NULL, 0);
 }
 
-static void remove_child_pid(struct tevent_context *ev_ctx,
+static void remove_child_pid(struct smbd_parent_context *parent,
                             pid_t pid,
                             bool unclean_shutdown)
 {
-       struct child_pid *child;
-       static struct timed_event *cleanup_te;
+       struct smbd_child_pid *child;
        struct server_id child_id;
 
+       child_id = pid_to_procid(pid);
+
+       for (child = parent->children; child != NULL; child = child->next) {
+               if (child->pid == pid) {
+                       struct smbd_child_pid *tmp = child;
+                       DLIST_REMOVE(parent->children, child);
+                       TALLOC_FREE(tmp);
+                       parent->num_children -= 1;
+                       break;
+               }
+       }
+
+       if (child == NULL) {
+               /* not all forked child processes are added to the children list */
+               DEBUG(2, ("Could not find child %d -- ignoring\n", (int)pid));
+               return;
+       }
+
        if (unclean_shutdown) {
                /* a child terminated uncleanly so tickle all
                   processes to see if they can grab any of the
@@ -251,51 +446,36 @@ static void remove_child_pid(struct tevent_context *ev_ctx,
                 */
                DEBUG(3,(__location__ " Unclean shutdown of pid %u\n",
                        (unsigned int)pid));
-               if (!cleanup_te) {
+               if (parent->cleanup_te == NULL) {
                        /* call the cleanup timer, but not too often */
                        int cleanup_time = lp_parm_int(-1, "smbd", "cleanuptime", 20);
-                       cleanup_te = event_add_timed(ev_ctx, NULL,
+                       parent->cleanup_te = tevent_add_timer(parent->ev_ctx,
+                                               parent,
                                                timeval_current_ofs(cleanup_time, 0),
                                                cleanup_timeout_fn,
-                                               &cleanup_te);
+                                               parent);
                        DEBUG(1,("Scheduled cleanup of brl and lock database after unclean shutdown\n"));
                }
        }
 
-       child_id = procid_self(); /* Just initialize pid and potentially vnn */
-       child_id.pid = pid;
-
        if (!serverid_deregister(child_id)) {
                DEBUG(1, ("Could not remove pid %d from serverid.tdb\n",
                          (int)pid));
        }
-
-       for (child = children; child != NULL; child = child->next) {
-               if (child->pid == pid) {
-                       struct child_pid *tmp = child;
-                       DLIST_REMOVE(children, child);
-                       SAFE_FREE(tmp);
-                       num_children -= 1;
-                       return;
-               }
-       }
-
-       /* not all forked child processes are added to the children list */
-       DEBUG(1, ("Could not find child %d -- ignoring\n", (int)pid));
 }
 
 /****************************************************************************
  Have we reached the process limit ?
 ****************************************************************************/
 
-static bool allowable_number_of_smbd_processes(void)
+static bool allowable_number_of_smbd_processes(struct smbd_parent_context *parent)
 {
        int max_processes = lp_max_smbd_processes();
 
        if (!max_processes)
                return True;
 
-       return num_children < max_processes;
+       return parent->num_children < max_processes;
 }
 
 static void smbd_sig_chld_handler(struct tevent_context *ev,
@@ -307,6 +487,9 @@ static void smbd_sig_chld_handler(struct tevent_context *ev,
 {
        pid_t pid;
        int status;
+       struct smbd_parent_context *parent =
+               talloc_get_type_abort(private_data,
+               struct smbd_parent_context);
 
        while ((pid = sys_waitpid(-1, &status, WNOHANG)) > 0) {
                bool unclean_shutdown = False;
@@ -324,41 +507,24 @@ static void smbd_sig_chld_handler(struct tevent_context *ev,
                if (WIFSIGNALED(status)) {
                        unclean_shutdown = True;
                }
-               remove_child_pid(ev, pid, unclean_shutdown);
+               remove_child_pid(parent, pid, unclean_shutdown);
        }
 }
 
-static void smbd_setup_sig_chld_handler(struct tevent_context *ev_ctx)
+static void smbd_setup_sig_chld_handler(struct smbd_parent_context *parent)
 {
        struct tevent_signal *se;
 
-       se = tevent_add_signal(ev_ctx,
-                              ev_ctx, /* mem_ctx */
+       se = tevent_add_signal(parent->ev_ctx,
+                              parent, /* mem_ctx */
                               SIGCHLD, 0,
                               smbd_sig_chld_handler,
-                              NULL);
+                              parent);
        if (!se) {
                exit_server("failed to setup SIGCHLD handler");
        }
 }
 
-struct smbd_open_socket;
-
-struct smbd_parent_context {
-       bool interactive;
-
-       /* the list of listening sockets */
-       struct smbd_open_socket *sockets;
-};
-
-struct smbd_open_socket {
-       struct smbd_open_socket *prev, *next;
-       struct smbd_parent_context *parent;
-       int fd;
-       struct tevent_fd *fde;
-       struct messaging_context *msg_ctx;
-};
-
 static void smbd_open_socket_close_fn(struct tevent_context *ev,
                                      struct tevent_fd *fde,
                                      int fd,
@@ -373,10 +539,9 @@ static void smbd_accept_connection(struct tevent_context *ev,
                                   uint16_t flags,
                                   void *private_data)
 {
-       struct smbd_server_connection *sconn = smbd_server_conn;
        struct smbd_open_socket *s = talloc_get_type_abort(private_data,
                                     struct smbd_open_socket);
-       struct messaging_context *msg_ctx = s->msg_ctx;
+       struct messaging_context *msg_ctx = s->parent->msg_ctx;
        struct sockaddr_storage addr;
        socklen_t in_addrlen = sizeof(addr);
        int fd;
@@ -384,25 +549,24 @@ static void smbd_accept_connection(struct tevent_context *ev,
        uint64_t unique_id;
 
        fd = accept(s->fd, (struct sockaddr *)(void *)&addr,&in_addrlen);
-       sconn->sock = fd;
        if (fd == -1 && errno == EINTR)
                return;
 
        if (fd == -1) {
-               DEBUG(0,("open_sockets_smbd: accept: %s\n",
+               DEBUG(0,("accept: %s\n",
                         strerror(errno)));
                return;
        }
 
        if (s->parent->interactive) {
-               smbd_process(ev, sconn);
+               reinit_after_fork(msg_ctx, ev, true);
+               smbd_process(ev, msg_ctx, fd, true);
                exit_server_cleanly("end of interactive mode");
                return;
        }
 
-       if (!allowable_number_of_smbd_processes()) {
+       if (!allowable_number_of_smbd_processes(s->parent)) {
                close(fd);
-               sconn->sock = -1;
                return;
        }
 
@@ -410,26 +574,14 @@ static void smbd_accept_connection(struct tevent_context *ev,
         * Generate a unique id in the parent process so that we use
         * the global random state in the parent.
         */
-       generate_random_buffer((uint8_t *)&unique_id, sizeof(unique_id));
+       unique_id = serverid_get_random_unique_id();
 
-       pid = sys_fork();
+       pid = fork();
        if (pid == 0) {
                NTSTATUS status = NT_STATUS_OK;
 
                /* Child code ... */
-               am_parent = 0;
-
-               set_my_unique_id(unique_id);
-
-               /* Stop zombies, the parent explicitly handles
-                * them, counting worker smbds. */
-               CatchChild();
-
-               /* close our standard file
-                  descriptors */
-               if (!debug_get_output_is_stdout()) {
-                       close_low_fds(False); /* Don't close stderr */
-               }
+               am_parent = NULL;
 
                /*
                 * Can't use TALLOC_FREE here. Nulling out the argument to it
@@ -438,9 +590,14 @@ static void smbd_accept_connection(struct tevent_context *ev,
                talloc_free(s->parent);
                s = NULL;
 
+               set_my_unique_id(unique_id);
+
+               /* Stop zombies, the parent explicitly handles
+                * them, counting worker smbds. */
+               CatchChild();
+
                status = reinit_after_fork(msg_ctx,
                                           ev,
-                                          procid_self(),
                                           true);
                if (!NT_STATUS_IS_OK(status)) {
                        if (NT_STATUS_EQUAL(status,
@@ -462,26 +619,14 @@ static void smbd_accept_connection(struct tevent_context *ev,
                        smb_panic("reinit_after_fork() failed");
                }
 
-               smbd_setup_sig_term_handler();
-               smbd_setup_sig_hup_handler(ev,
-                                          msg_ctx);
-
-               if (!serverid_register(procid_self(),
-                                      FLAG_MSG_GENERAL|FLAG_MSG_SMBD
-                                      |FLAG_MSG_DBWRAP
-                                      |FLAG_MSG_PRINT_GENERAL)) {
-                       exit_server_cleanly("Could not register myself in "
-                                           "serverid.tdb");
-               }
-
-               smbd_process(ev, smbd_server_conn);
+               smbd_process(ev, msg_ctx, fd, false);
         exit:
                exit_server_cleanly("end of child");
                return;
        }
 
        if (pid < 0) {
-               DEBUG(0,("smbd_accept_connection: sys_fork() failed: %s\n",
+               DEBUG(0,("smbd_accept_connection: fork() failed: %s\n",
                         strerror(errno)));
        }
 
@@ -495,10 +640,9 @@ static void smbd_accept_connection(struct tevent_context *ev,
                getpeername failure if we reopen the logs
                and use %I in the filename.
        */
-       sconn->sock = -1;
 
        if (pid != 0) {
-               add_child_pid(pid);
+               add_child_pid(s->parent, pid);
        }
 
        /* Force parent to check log size after
@@ -520,7 +664,6 @@ static void smbd_accept_connection(struct tevent_context *ev,
 
 static bool smbd_open_one_socket(struct smbd_parent_context *parent,
                                 struct tevent_context *ev_ctx,
-                                struct messaging_context *msg_ctx,
                                 const struct sockaddr_storage *ifss,
                                 uint16_t port)
 {
@@ -563,7 +706,6 @@ static bool smbd_open_one_socket(struct smbd_parent_context *parent,
                return false;
        }
 
-       s->msg_ctx = msg_ctx;
        s->fde = tevent_add_fd(ev_ctx,
                               s,
                               s->fd, TEVENT_FD_READ,
@@ -594,8 +736,8 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
                              const char *smb_ports)
 {
        int num_interfaces = iface_count();
-       int i;
-       const char *ports;
+       int i,j;
+       const char **ports;
        unsigned dns_port = 0;
 
 #ifdef HAVE_ATEXIT
@@ -603,18 +745,22 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
 #endif
 
        /* Stop zombies */
-       smbd_setup_sig_chld_handler(ev_ctx);
+       smbd_setup_sig_chld_handler(parent);
+
+       ports = lp_smb_ports();
 
        /* use a reasonable default set of ports - listing on 445 and 139 */
-       if (!smb_ports) {
-               ports = lp_smb_ports();
-               if (!ports || !*ports) {
-                       ports = talloc_strdup(talloc_tos(), SMB_PORTS);
-               } else {
-                       ports = talloc_strdup(talloc_tos(), ports);
+       if (smb_ports) {
+               ports = (const char **)str_list_make_v3(talloc_tos(), smb_ports, NULL);
+       }
+
+       for (j = 0; ports && ports[j]; j++) {
+               unsigned port = atoi(ports[j]);
+
+               if (port == 0 || port > 0xffff) {
+                       exit_server_cleanly("Invalid port in the config or on "
+                                           "the commandline specified!");
                }
-       } else {
-               ports = talloc_strdup(talloc_tos(), smb_ports);
        }
 
        if (lp_interfaces() && lp_bind_interfaces_only()) {
@@ -628,9 +774,6 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
                for(i = 0; i < num_interfaces; i++) {
                        const struct sockaddr_storage *ifss =
                                        iface_n_sockaddr_storage(i);
-                       char *tok;
-                       const char *ptr;
-
                        if (ifss == NULL) {
                                DEBUG(0,("open_sockets_smbd: "
                                        "interface %d has NULL IP address !\n",
@@ -638,12 +781,8 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
                                continue;
                        }
 
-                       for (ptr=ports;
-                            next_token_talloc(talloc_tos(),&ptr, &tok, " \t,");) {
-                               unsigned port = atoi(tok);
-                               if (port == 0 || port > 0xffff) {
-                                       continue;
-                               }
+                       for (j = 0; ports && ports[j]; j++) {
+                               unsigned port = atoi(ports[j]);
 
                                /* Keep the first port for mDNS service
                                 * registration.
@@ -654,7 +793,6 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
 
                                if (!smbd_open_one_socket(parent,
                                                          ev_ctx,
-                                                         msg_ctx,
                                                          ifss,
                                                          port)) {
                                        return false;
@@ -665,30 +803,21 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
                /* Just bind to 0.0.0.0 - accept connections
                   from anywhere. */
 
-               char *tok;
-               const char *ptr;
-               const char *sock_addr = lp_socket_address();
+               const char *sock_addr;
                char *sock_tok;
                const char *sock_ptr;
 
-               if (strequal(sock_addr, "0.0.0.0") ||
-                   strequal(sock_addr, "::")) {
 #if HAVE_IPV6
-                       sock_addr = "::,0.0.0.0";
+               sock_addr = "::,0.0.0.0";
 #else
-                       sock_addr = "0.0.0.0";
+               sock_addr = "0.0.0.0";
 #endif
-               }
 
                for (sock_ptr=sock_addr;
                     next_token_talloc(talloc_tos(), &sock_ptr, &sock_tok, " \t,"); ) {
-                       for (ptr=ports; next_token_talloc(talloc_tos(), &ptr, &tok, " \t,"); ) {
+                       for (j = 0; ports && ports[j]; j++) {
                                struct sockaddr_storage ss;
-
-                               unsigned port = atoi(tok);
-                               if (port == 0 || port > 0xffff) {
-                                       continue;
-                               }
+                               unsigned port = atoi(ports[j]);
 
                                /* Keep the first port for mDNS service
                                 * registration.
@@ -705,7 +834,6 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
 
                                if (!smbd_open_one_socket(parent,
                                                          ev_ctx,
-                                                         msg_ctx,
                                                          &ss,
                                                          port)) {
                                        return false;
@@ -726,8 +854,9 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
           operations until it has gone thru a full startup, which
           includes checking to see that smbd is listening. */
 
-       if (!serverid_register(procid_self(),
+       if (!serverid_register(messaging_server_id(msg_ctx),
                               FLAG_MSG_GENERAL|FLAG_MSG_SMBD
+                              |FLAG_MSG_PRINT_GENERAL
                               |FLAG_MSG_DBWRAP)) {
                DEBUG(0, ("open_sockets_smbd: Failed to register "
                          "myself in serverid.tdb\n"));
@@ -736,21 +865,23 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
 
         /* Listen to messages */
 
-       messaging_register(msg_ctx, NULL, MSG_SMB_SAM_SYNC, msg_sam_sync);
        messaging_register(msg_ctx, NULL, MSG_SHUTDOWN, msg_exit_server);
-       messaging_register(msg_ctx, NULL, MSG_SMB_FILE_RENAME,
-                          msg_file_was_renamed);
        messaging_register(msg_ctx, ev_ctx, MSG_SMB_CONF_UPDATED,
-                          smb_conf_updated);
+                          smbd_parent_conf_updated);
        messaging_register(msg_ctx, NULL, MSG_SMB_STAT_CACHE_DELETE,
                           smb_stat_cache_delete);
        messaging_register(msg_ctx, NULL, MSG_DEBUG, smbd_msg_debug);
        messaging_register(msg_ctx, ev_ctx, MSG_PRINTER_PCAP,
                           smb_pcap_updated);
-       brl_register_msgs(msg_ctx);
+       messaging_register(msg_ctx, NULL, MSG_SMB_BRL_VALIDATE,
+                          brl_revalidate);
+       messaging_register(msg_ctx, NULL, MSG_SMB_FORCE_TDIS,
+                          smb_parent_force_tdis);
 
-       id_cache_register_msgs(msg_ctx);
-       id_cache_register_kill_msg(msg_ctx);
+       messaging_register(msg_ctx, NULL,
+                          ID_CACHE_DELETE, smbd_parent_id_cache_delete);
+       messaging_register(msg_ctx, NULL,
+                          ID_CACHE_KILL, smbd_parent_id_cache_kill);
 
 #ifdef CLUSTER_SUPPORT
        if (lp_clustering()) {
@@ -783,6 +914,23 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
        return true;
 }
 
+
+/*
+  handle stdin becoming readable when we are in --foreground mode
+ */
+static void smbd_stdin_handler(struct tevent_context *ev,
+                              struct tevent_fd *fde,
+                              uint16_t flags,
+                              void *private_data)
+{
+       char c;
+       if (read(0, &c, 1) != 1) {
+               /* we have reached EOF on stdin, which means the
+                  parent has exited. Shutdown the server */
+               exit_server_cleanly("EOF on stdin");
+       }
+}
+
 static void smbd_parent_loop(struct tevent_context *ev_ctx,
                             struct smbd_parent_context *parent)
 {
@@ -825,6 +973,34 @@ static bool init_structs(void )
        return True;
 }
 
+static void smbd_parent_sig_term_handler(struct tevent_context *ev,
+                                        struct tevent_signal *se,
+                                        int signum,
+                                        int count,
+                                        void *siginfo,
+                                        void *private_data)
+{
+       exit_server_cleanly("termination signal");
+}
+
+static void smbd_parent_sig_hup_handler(struct tevent_context *ev,
+                                       struct tevent_signal *se,
+                                       int signum,
+                                       int count,
+                                       void *siginfo,
+                                       void *private_data)
+{
+       struct smbd_parent_context *parent =
+               talloc_get_type_abort(private_data,
+               struct smbd_parent_context);
+
+       change_to_root_user();
+       DEBUG(1,("parent: Reloading services after SIGHUP\n"));
+       reload_services(NULL, NULL, false);
+
+       printing_subsystem_update(parent->ev_ctx, parent->msg_ctx, true);
+}
+
 /****************************************************************************
  main program.
 ****************************************************************************/
@@ -872,9 +1048,26 @@ extern void build_options(bool screen);
        struct smbd_parent_context *parent = NULL;
        TALLOC_CTX *frame;
        NTSTATUS status;
-       uint64_t unique_id;
        struct tevent_context *ev_ctx;
        struct messaging_context *msg_ctx;
+       struct server_id server_id;
+       struct tevent_signal *se;
+       char *np_dir = NULL;
+       static const struct smbd_shim smbd_shim_fns =
+       {
+               .cancel_pending_lock_requests_by_fid = smbd_cancel_pending_lock_requests_by_fid,
+               .send_stat_cache_delete_message = smbd_send_stat_cache_delete_message,
+               .change_to_root_user = smbd_change_to_root_user,
+
+               .contend_level2_oplocks_begin = smbd_contend_level2_oplocks_begin,
+               .contend_level2_oplocks_end = smbd_contend_level2_oplocks_end,
+
+               .become_root = smbd_become_root,
+               .unbecome_root = smbd_unbecome_root,
+
+               .exit_server = smbd_exit_server,
+               .exit_server_cleanly = smbd_exit_server_cleanly,
+       };
 
        /*
         * Do this before any other talloc operation
@@ -886,6 +1079,8 @@ extern void build_options(bool screen);
 
        load_case_tables();
 
+       set_smbd_shim(&smbd_shim_fns);
+
        smbd_init_globals();
 
        TimeInit();
@@ -969,7 +1164,7 @@ extern void build_options(bool screen);
        gain_root_group_privilege();
 
        fault_setup();
-       dump_core_setup("smbd", lp_logfile());
+       dump_core_setup("smbd", lp_logfile(talloc_tos()));
 
        /* we are never interested in SIGPIPE */
        BlockSignals(True,SIGPIPE);
@@ -1020,6 +1215,10 @@ extern void build_options(bool screen);
                exit(1);
        }
 
+       if (!cluster_probe_ok()) {
+               exit(1);
+       }
+
        /* Init the security context and global current_user */
        init_sec_ctx();
 
@@ -1047,7 +1246,14 @@ extern void build_options(bool screen);
         * Reloading of the printers will not work here as we don't have a
         * server info and rpc services set up. It will be called later.
         */
-       if (!reload_services(NULL, -1, False)) {
+       if (!reload_services(NULL, NULL, false)) {
+               exit(1);
+       }
+
+       if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC
+           && !lp_parm_bool(-1, "server role check", "inhibit", false)) {
+               DEBUG(0, ("server role = 'active directory domain controller' not compatible with running smbd standalone. \n"));
+               DEBUGADD(0, ("You should start 'samba' instead, and it will control starting smbd if required\n"));
                exit(1);
        }
 
@@ -1089,8 +1295,7 @@ extern void build_options(bool screen);
                become_daemon(Fork, no_process_group, log_stdout);
        }
 
-        generate_random_buffer((uint8_t *)&unique_id, sizeof(unique_id));
-        set_my_unique_id(unique_id);
+        set_my_unique_id(serverid_get_random_unique_id());
 
 #if HAVE_SETPGID
        /*
@@ -1104,22 +1309,58 @@ extern void build_options(bool screen);
        if (!directory_exist(lp_lockdir()))
                mkdir(lp_lockdir(), 0755);
 
+       if (!directory_exist(lp_piddir()))
+               mkdir(lp_piddir(), 0755);
+
        if (is_daemon)
-               pidfile_create("smbd");
+               pidfile_create(lp_piddir(), "smbd");
 
        status = reinit_after_fork(msg_ctx,
                                   ev_ctx,
-                                  procid_self(), false);
+                                  false);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0,("reinit_after_fork() failed\n"));
                exit(1);
        }
 
-       smbd_server_conn->msg_ctx = msg_ctx;
+       if (!interactive) {
+               /*
+                * Do not initialize the parent-child-pipe before becoming a
+                * daemon: this is used to detect a died parent in the child
+                * process.
+                */
+               status = init_before_fork();
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("init_before_fork failed: %s\n", nt_errstr(status)));
+                       exit(1);
+               }
+       }
 
-       smbd_setup_sig_term_handler();
-       smbd_setup_sig_hup_handler(ev_ctx,
-                                  msg_ctx);
+       parent = talloc_zero(ev_ctx, struct smbd_parent_context);
+       if (!parent) {
+               exit_server("talloc(struct smbd_parent_context) failed");
+       }
+       parent->interactive = interactive;
+       parent->ev_ctx = ev_ctx;
+       parent->msg_ctx = msg_ctx;
+       am_parent = parent;
+
+       se = tevent_add_signal(parent->ev_ctx,
+                              parent,
+                              SIGTERM, 0,
+                              smbd_parent_sig_term_handler,
+                              parent);
+       if (!se) {
+               exit_server("failed to setup SIGTERM handler");
+       }
+       se = tevent_add_signal(parent->ev_ctx,
+                              parent,
+                              SIGHUP, 0,
+                              smbd_parent_sig_hup_handler,
+                              parent);
+       if (!se) {
+               exit_server("failed to setup SIGHUP handler");
+       }
 
        /* Setup all the TDB's - including CLEAR_IF_FIRST tdb's. */
 
@@ -1141,10 +1382,12 @@ extern void build_options(bool screen);
        }
 
        if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC) {
-               if (!open_schannel_session_store(NULL, lp_private_dir())) {
+               struct loadparm_context *lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers());
+               if (!open_schannel_session_store(NULL, lp_ctx)) {
                        DEBUG(0,("ERROR: Samba cannot open schannel store for secured NETLOGON operations.\n"));
                        exit(1);
                }
+               TALLOC_FREE(lp_ctx);
        }
 
        if(!get_global_sam_sid()) {
@@ -1152,12 +1395,21 @@ extern void build_options(bool screen);
                exit(1);
        }
 
-       if (!sessionid_init()) {
+       server_id = messaging_server_id(msg_ctx);
+       status = smbXsrv_version_global_init(&server_id);
+       if (!NT_STATUS_IS_OK(status)) {
                exit(1);
        }
 
-       if (!connections_init(True))
+       status = smbXsrv_session_global_init();
+       if (!NT_STATUS_IS_OK(status)) {
                exit(1);
+       }
+
+       status = smbXsrv_tcon_global_init();
+       if (!NT_STATUS_IS_OK(status)) {
+               exit(1);
+       }
 
        if (!locking_init())
                exit(1);
@@ -1166,7 +1418,11 @@ extern void build_options(bool screen);
                exit(1);
        }
 
-       if (!notify_internal_parent_init(ev_ctx)) {
+       if (!smbd_parent_notify_init(NULL, msg_ctx, ev_ctx)) {
+               exit(1);
+       }
+
+       if (!smbd_scavenger_init(NULL, msg_ctx, ev_ctx)) {
                exit(1);
        }
 
@@ -1186,7 +1442,7 @@ extern void build_options(bool screen);
                exit(1);
        }
 
-       status = init_system_info();
+       status = init_system_session_info();
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("ERROR: failed to setup system user info: %s.\n",
                          nt_errstr(status)));
@@ -1198,10 +1454,14 @@ extern void build_options(bool screen);
                return -1;
        }
 
-       if (!file_init(smbd_server_conn)) {
-               DEBUG(0, ("ERROR: file_init failed\n"));
+       if (!file_init_global()) {
+               DEBUG(0, ("ERROR: file_init_global() failed\n"));
                return -1;
        }
+       status = smbXsrv_open_global_init();
+       if (!NT_STATUS_IS_OK(status)) {
+               exit(1);
+       }
 
        /* This MUST be done before start_epmd() because otherwise
         * start_epmd() forks and races against dcesrv_ep_setup() to
@@ -1212,6 +1472,18 @@ extern void build_options(bool screen);
                return -1;
        }
 
+       np_dir = talloc_asprintf(talloc_tos(), "%s/np", lp_ncalrpc_dir());
+       if (!np_dir) {
+               DEBUG(0, ("%s: Out of memory\n", __location__));
+               return -1;
+       }
+
+       if (!directory_create_or_exist_strict(np_dir, geteuid(), 0700)) {
+               DEBUG(0, ("Failed to create pipe directory %s - %s\n",
+                         np_dir, strerror(errno)));
+               return -1;
+       }
+
        if (is_daemon && !interactive) {
                if (rpc_epmapper_daemon() == RPC_DAEMON_FORK) {
                        start_epmd(ev_ctx, msg_ctx);
@@ -1231,7 +1503,7 @@ extern void build_options(bool screen);
                        start_lsasd(ev_ctx, msg_ctx);
                }
 
-               if (!_lp_disable_spoolss() &&
+               if (!lp__disable_spoolss() &&
                    (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) {
                        bool bgq = lp_parm_bool(-1, "smbd", "backgroundqueue", true);
 
@@ -1239,7 +1511,7 @@ extern void build_options(bool screen);
                                exit(1);
                        }
                }
-       } else if (!_lp_disable_spoolss() &&
+       } else if (!lp__disable_spoolss() &&
                   (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) {
                if (!printing_subsystem_init(ev_ctx, msg_ctx, false, false)) {
                        exit(1);
@@ -1247,49 +1519,66 @@ extern void build_options(bool screen);
        }
 
        if (!is_daemon) {
+               int sock;
+
                /* inetd mode */
                TALLOC_FREE(frame);
 
                /* Started from inetd. fd 0 is the socket. */
                /* We will abort gracefully when the client or remote system
                   goes away */
-               smbd_server_conn->sock = dup(0);
+               sock = dup(0);
 
-               /* close our standard file descriptors */
-               if (!debug_get_output_is_stdout()) {
-                       close_low_fds(False); /* Don't close stderr */
-               }
+               /* close stdin, stdout (if not logging to it), but not stderr */
+               close_low_fds(true, !debug_get_output_is_stdout(), false);
 
 #ifdef HAVE_ATEXIT
                atexit(killkids);
 #endif
 
                /* Stop zombies */
-               smbd_setup_sig_chld_handler(ev_ctx);
+               smbd_setup_sig_chld_handler(parent);
 
-               smbd_process(ev_ctx, smbd_server_conn);
+               smbd_process(ev_ctx, msg_ctx, sock, true);
 
                exit_server_cleanly(NULL);
                return(0);
        }
 
-       parent = talloc_zero(ev_ctx, struct smbd_parent_context);
-       if (!parent) {
-               exit_server("talloc(struct smbd_parent_context) failed");
-       }
-       parent->interactive = interactive;
-
        if (!open_sockets_smbd(parent, ev_ctx, msg_ctx, ports))
                exit_server("open_sockets_smbd() failed");
 
        /* do a printer update now that all messaging has been set up,
         * before we allow clients to start connecting */
-       printing_subsystem_update(ev_ctx, msg_ctx, false);
+       if (!lp__disable_spoolss() &&
+           (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) {
+               printing_subsystem_update(ev_ctx, msg_ctx, false);
+       }
 
        TALLOC_FREE(frame);
        /* make sure we always have a valid stackframe */
        frame = talloc_stackframe();
 
+       if (!Fork) {
+               /* 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
+                  Only do this on a pipe or socket, no other device.
+               */
+               struct stat st;
+               if (fstat(0, &st) != 0) {
+                       return false;
+               }
+               if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) {
+                       tevent_add_fd(ev_ctx,
+                                       parent,
+                                       0,
+                                       TEVENT_FD_READ,
+                                       smbd_stdin_handler,
+                                       NULL);
+               }
+       }
+
        smbd_parent_loop(ev_ctx, parent);
 
        exit_server_cleanly(NULL);