winbindd: winbindd_ccache_ntlm_auth() -> bool_dispatch_table
[samba.git] / source3 / winbindd / winbindd.c
index a1647c947fab0c4d396e4e9afc2a54965e10bfc2..acccd61128aa4d853dbbb5a966b5271580053843 100644 (file)
 #include "rpc_client/cli_netlogon.h"
 #include "idmap.h"
 #include "lib/addrchange.h"
-#include "serverid.h"
 #include "auth.h"
 #include "messages.h"
 #include "../lib/util/pidfile.h"
 #include "util_cluster.h"
+#include "source4/lib/messaging/irpc.h"
+#include "source4/lib/messaging/messaging.h"
+#include "lib/param/param.h"
+#include "lib/async_req/async_sock.h"
+#include "libsmb/samlogon_cache.h"
+#include "libcli/auth/netlogon_creds_cli.h"
+#include "passdb.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
 
+#define SCRUB_CLIENTS_INTERVAL 5
+
 static bool client_is_idle(struct winbindd_cli_state *state);
 static void remove_client(struct winbindd_cli_state *state);
+static void winbindd_setup_max_fds(void);
 
 static bool opt_nocache = False;
 static bool interactive = False;
 
 extern bool override_logfile;
 
-struct tevent_context *winbind_event_context(void)
+struct imessaging_context *winbind_imessaging_context(void)
 {
-       static struct tevent_context *ev = NULL;
+       static struct imessaging_context *msg = NULL;
+       struct messaging_context *msg_ctx;
+       struct server_id myself;
+       struct loadparm_context *lp_ctx;
 
-       if (ev != NULL) {
-               return ev;
+       if (msg != NULL) {
+               return msg;
        }
 
-       /*
-        * Note we MUST use the NULL context here, not the autofree context,
-        * to avoid side effects in forked children exiting.
-        */
-       ev = samba_tevent_context_init(NULL);
-       if (ev == NULL) {
-               smb_panic("Could not init winbindd's messaging context.\n");
+       msg_ctx = server_messaging_context();
+       if (msg_ctx == NULL) {
+               smb_panic("server_messaging_context failed\n");
        }
-       return ev;
-}
-
-struct messaging_context *winbind_messaging_context(void)
-{
-       static struct messaging_context *msg = NULL;
+       myself = messaging_server_id(msg_ctx);
 
-       if (msg != NULL) {
-               return msg;
+       lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers());
+       if (lp_ctx == NULL) {
+               smb_panic("Could not load smb.conf to init winbindd's imessaging context.\n");
        }
 
        /*
         * Note we MUST use the NULL context here, not the autofree context,
         * to avoid side effects in forked children exiting.
         */
-       msg = messaging_init(NULL, winbind_event_context());
+       msg = imessaging_init(NULL, lp_ctx, myself, server_event_context());
+       talloc_unlink(NULL, lp_ctx);
+
        if (msg == NULL) {
                smb_panic("Could not init winbindd's messaging context.\n");
        }
@@ -115,6 +121,7 @@ static bool reload_services_file(const char *lfile)
 
        reopen_logs();
        load_interfaces();
+       winbindd_setup_max_fds();
 
        return(ret);
 }
@@ -199,10 +206,10 @@ static void terminate(bool is_parent)
 
        idmap_close();
 
-       trustdom_cache_shutdown();
-
        gencache_stabilize();
 
+       netlogon_creds_cli_close_global_db();
+
 #if 0
        if (interactive) {
                TALLOC_CTX *mem_ctx = talloc_init("end_description");
@@ -214,9 +221,6 @@ static void terminate(bool is_parent)
 #endif
 
        if (is_parent) {
-               struct messaging_context *msg = winbind_messaging_context();
-               struct server_id self = messaging_server_id(msg);
-               serverid_deregister(self);
                pidfile_unlink(lp_pid_directory(), "winbindd");
        }
 
@@ -230,11 +234,14 @@ static void winbindd_sig_term_handler(struct tevent_context *ev,
                                      void *siginfo,
                                      void *private_data)
 {
-       bool *is_parent = talloc_get_type_abort(private_data, bool);
+       bool *p = talloc_get_type_abort(private_data, bool);
+       bool is_parent = *p;
+
+       TALLOC_FREE(p);
 
        DEBUG(0,("Got sig[%d] terminate (is_parent=%d)\n",
-                signum, (int)*is_parent));
-       terminate(*is_parent);
+                signum, is_parent));
+       terminate(is_parent);
 }
 
 /*
@@ -262,14 +269,14 @@ bool winbindd_setup_sig_term_handler(bool parent)
        struct tevent_signal *se;
        bool *is_parent;
 
-       is_parent = talloc(winbind_event_context(), bool);
+       is_parent = talloc(server_event_context(), bool);
        if (!is_parent) {
                return false;
        }
 
        *is_parent = parent;
 
-       se = tevent_add_signal(winbind_event_context(),
+       se = tevent_add_signal(server_event_context(),
                               is_parent,
                               SIGTERM, 0,
                               winbindd_sig_term_handler,
@@ -280,7 +287,7 @@ bool winbindd_setup_sig_term_handler(bool parent)
                return false;
        }
 
-       se = tevent_add_signal(winbind_event_context(),
+       se = tevent_add_signal(server_event_context(),
                               is_parent,
                               SIGINT, 0,
                               winbindd_sig_term_handler,
@@ -291,7 +298,7 @@ bool winbindd_setup_sig_term_handler(bool parent)
                return false;
        }
 
-       se = tevent_add_signal(winbind_event_context(),
+       se = tevent_add_signal(server_event_context(),
                               is_parent,
                               SIGQUIT, 0,
                               winbindd_sig_term_handler,
@@ -312,7 +319,7 @@ bool winbindd_setup_stdin_handler(bool parent, bool foreground)
        if (foreground) {
                struct stat st;
 
-               is_parent = talloc(winbind_event_context(), bool);
+               is_parent = talloc(server_event_context(), bool);
                if (!is_parent) {
                        return false;
                }
@@ -328,7 +335,7 @@ bool winbindd_setup_stdin_handler(bool parent, bool foreground)
                        return false;
                }
                if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) {
-                       tevent_add_fd(winbind_event_context(),
+                       tevent_add_fd(server_event_context(),
                                        is_parent,
                                        0,
                                        TEVENT_FD_READ,
@@ -360,15 +367,15 @@ bool winbindd_setup_sig_hup_handler(const char *lfile)
        char *file = NULL;
 
        if (lfile) {
-               file = talloc_strdup(winbind_event_context(),
+               file = talloc_strdup(server_event_context(),
                                     lfile);
                if (!file) {
                        return false;
                }
        }
 
-       se = tevent_add_signal(winbind_event_context(),
-                              winbind_event_context(),
+       se = tevent_add_signal(server_event_context(),
+                              server_event_context(),
                               SIGHUP, 0,
                               winbindd_sig_hup_handler,
                               file);
@@ -388,7 +395,7 @@ static void winbindd_sig_chld_handler(struct tevent_context *ev,
 {
        pid_t pid;
 
-       while ((pid = sys_waitpid(-1, NULL, WNOHANG)) > 0) {
+       while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) {
                winbind_child_died(pid);
        }
 }
@@ -397,8 +404,8 @@ static bool winbindd_setup_sig_chld_handler(void)
 {
        struct tevent_signal *se;
 
-       se = tevent_add_signal(winbind_event_context(),
-                              winbind_event_context(),
+       se = tevent_add_signal(server_event_context(),
+                              server_event_context(),
                               SIGCHLD, 0,
                               winbindd_sig_chld_handler,
                               NULL);
@@ -423,8 +430,8 @@ static bool winbindd_setup_sig_usr2_handler(void)
 {
        struct tevent_signal *se;
 
-       se = tevent_add_signal(winbind_event_context(),
-                              winbind_event_context(),
+       se = tevent_add_signal(server_event_context(),
+                              server_event_context(),
                               SIGUSR2, 0,
                               winbindd_sig_usr2_handler,
                               NULL);
@@ -466,7 +473,7 @@ static void winbind_msg_validate_cache(struct messaging_context *msg_ctx,
                                       struct server_id server_id,
                                       DATA_BLOB *data)
 {
-       uint8 ret;
+       uint8_t ret;
        pid_t child_pid;
        NTSTATUS status;
 
@@ -505,7 +512,9 @@ static void winbind_msg_validate_cache(struct messaging_context *msg_ctx,
        /* install default SIGCHLD handler: validation code uses fork/waitpid */
        CatchSignal(SIGCHLD, SIG_DFL);
 
-       ret = (uint8)winbindd_validate_cache_nobackup();
+       setproctitle("validate cache child");
+
+       ret = (uint8_t)winbindd_validate_cache_nobackup();
        DEBUG(10, ("winbindd_msg_validata_cache: got return value %d\n", ret));
        messaging_send_buf(msg_ctx, server_id, MSG_WINBIND_VALIDATE_CACHE, &ret,
                           (size_t)1);
@@ -525,18 +534,11 @@ static struct winbindd_dispatch_table {
 
        /* Miscellaneous */
 
-       { WINBINDD_INFO, winbindd_info, "INFO" },
-       { WINBINDD_INTERFACE_VERSION, winbindd_interface_version,
-         "INTERFACE_VERSION" },
-       { WINBINDD_DOMAIN_NAME, winbindd_domain_name, "DOMAIN_NAME" },
        { WINBINDD_DOMAIN_INFO, winbindd_domain_info, "DOMAIN_INFO" },
-       { WINBINDD_DC_INFO, winbindd_dc_info, "DC_INFO" },
-       { WINBINDD_NETBIOS_NAME, winbindd_netbios_name, "NETBIOS_NAME" },
        { WINBINDD_PRIV_PIPE_DIR, winbindd_priv_pipe_dir,
          "WINBINDD_PRIV_PIPE_DIR" },
 
        /* Credential cache access */
-       { WINBINDD_CCACHE_NTLMAUTH, winbindd_ccache_ntlm_auth, "NTLMAUTH" },
        { WINBINDD_CCACHE_SAVE, winbindd_ccache_save, "CCACHE_SAVE" },
 
        /* End of list */
@@ -544,6 +546,34 @@ static struct winbindd_dispatch_table {
        { WINBINDD_NUM_CMDS, NULL, "NONE" }
 };
 
+static struct winbindd_bool_dispatch_table {
+       enum winbindd_cmd cmd;
+       bool (*fn)(struct winbindd_cli_state *state);
+       const char *cmd_name;
+} bool_dispatch_table[] = {
+       { WINBINDD_INTERFACE_VERSION,
+         winbindd_interface_version,
+         "INTERFACE_VERSION" },
+       { WINBINDD_INFO,
+         winbindd_info,
+         "INFO" },
+       { WINBINDD_PING,
+         winbindd_ping,
+         "PING" },
+       { WINBINDD_DOMAIN_NAME,
+         winbindd_domain_name,
+         "DOMAIN_NAME" },
+       { WINBINDD_NETBIOS_NAME,
+         winbindd_netbios_name,
+         "NETBIOS_NAME" },
+       { WINBINDD_DC_INFO,
+         winbindd_dc_info,
+         "DC_INFO" },
+       { WINBINDD_CCACHE_NTLMAUTH,
+         winbindd_ccache_ntlm_auth,
+         "NTLMAUTH" },
+};
+
 struct winbindd_async_dispatch_table {
        enum winbindd_cmd cmd;
        const char *cmd_name;
@@ -556,24 +586,16 @@ struct winbindd_async_dispatch_table {
 };
 
 static struct winbindd_async_dispatch_table async_nonpriv_table[] = {
-       { WINBINDD_PING, "PING",
-         wb_ping_send, wb_ping_recv },
        { WINBINDD_LOOKUPSID, "LOOKUPSID",
          winbindd_lookupsid_send, winbindd_lookupsid_recv },
        { WINBINDD_LOOKUPSIDS, "LOOKUPSIDS",
          winbindd_lookupsids_send, winbindd_lookupsids_recv },
        { WINBINDD_LOOKUPNAME, "LOOKUPNAME",
          winbindd_lookupname_send, winbindd_lookupname_recv },
-       { WINBINDD_SID_TO_UID, "SID_TO_UID",
-         winbindd_sid_to_uid_send, winbindd_sid_to_uid_recv },
-       { WINBINDD_SID_TO_GID, "SID_TO_GID",
-         winbindd_sid_to_gid_send, winbindd_sid_to_gid_recv },
-       { WINBINDD_UID_TO_SID, "UID_TO_SID",
-         winbindd_uid_to_sid_send, winbindd_uid_to_sid_recv },
-       { WINBINDD_GID_TO_SID, "GID_TO_SID",
-         winbindd_gid_to_sid_send, winbindd_gid_to_sid_recv },
        { WINBINDD_SIDS_TO_XIDS, "SIDS_TO_XIDS",
          winbindd_sids_to_xids_send, winbindd_sids_to_xids_recv },
+       { WINBINDD_XIDS_TO_SIDS, "XIDS_TO_SIDS",
+         winbindd_xids_to_sids_send, winbindd_xids_to_sids_recv },
        { WINBINDD_GETPWSID, "GETPWSID",
          winbindd_getpwsid_send, winbindd_getpwsid_recv },
        { WINBINDD_GETPWNAM, "GETPWNAM",
@@ -656,6 +678,8 @@ static void process_request(struct winbindd_cli_state *state)
 {
        struct winbindd_dispatch_table *table = dispatch_table;
        struct winbindd_async_dispatch_table *atable;
+       size_t i;
+       bool ok;
 
        state->mem_ctx = talloc_named(state, 0, "winbind request");
        if (state->mem_ctx == NULL)
@@ -666,7 +690,8 @@ static void process_request(struct winbindd_cli_state *state)
 
        state->cmd_name = "unknown request";
        state->recv_fn = NULL;
-       state->last_access = time(NULL);
+       /* client is newest */
+       winbindd_promote_client(state);
 
        /* Process command */
 
@@ -694,7 +719,7 @@ static void process_request(struct winbindd_cli_state *state)
                DEBUG(10, ("process_request: Handling async request %d:%s\n",
                           (int)state->pid, state->cmd_name));
 
-               req = atable->send_req(state->mem_ctx, winbind_event_context(),
+               req = atable->send_req(state->mem_ctx, server_event_context(),
                                       state, state->request);
                if (req == NULL) {
                        DEBUG(0, ("process_request: atable->send failed for "
@@ -722,14 +747,32 @@ static void process_request(struct winbindd_cli_state *state)
                                  table->winbindd_cmd_name ));
                        state->cmd_name = table->winbindd_cmd_name;
                        table->fn(state);
+                       return;
+               }
+       }
+
+       for (i=0; i<ARRAY_SIZE(bool_dispatch_table); i++) {
+               if (bool_dispatch_table[i].cmd == state->request->cmd) {
                        break;
                }
        }
 
-       if (!table->fn) {
+       if (i == ARRAY_SIZE(bool_dispatch_table)) {
                DEBUG(10,("process_request: unknown request fn number %d\n",
                          (int)state->request->cmd ));
                request_error(state);
+               return;
+       }
+
+       DBG_DEBUG("process_request: request fn %s\n",
+                 bool_dispatch_table[i].cmd_name);
+
+       ok = bool_dispatch_table[i].fn(state);
+
+       if (ok) {
+               request_ok(state);
+       } else {
+               request_error(state);
        }
 }
 
@@ -777,14 +820,18 @@ static void request_finished(struct winbindd_cli_state *state);
 
 static void winbind_client_request_read(struct tevent_req *req);
 static void winbind_client_response_written(struct tevent_req *req);
+static void winbind_client_activity(struct tevent_req *req);
 
 static void request_finished(struct winbindd_cli_state *state)
 {
        struct tevent_req *req;
 
+       /* free client socket monitoring request */
+       TALLOC_FREE(state->io_req);
+
        TALLOC_FREE(state->request);
 
-       req = wb_resp_write_send(state, winbind_event_context(),
+       req = wb_resp_write_send(state, server_event_context(),
                                 state->out_queue, state->sock,
                                 state->response);
        if (req == NULL) {
@@ -794,6 +841,7 @@ static void request_finished(struct winbindd_cli_state *state)
                return;
        }
        tevent_req_set_callback(req, winbind_client_response_written, state);
+       state->io_req = req;
 }
 
 static void winbind_client_response_written(struct tevent_req *req)
@@ -803,6 +851,8 @@ static void winbind_client_response_written(struct tevent_req *req)
        ssize_t ret;
        int err;
 
+       state->io_req = NULL;
+
        ret = wb_resp_write_recv(req, &err);
        TALLOC_FREE(req);
        if (ret == -1) {
@@ -822,13 +872,14 @@ static void winbind_client_response_written(struct tevent_req *req)
        state->cmd_name = "no request";
        state->recv_fn = NULL;
 
-       req = wb_req_read_send(state, winbind_event_context(), state->sock,
+       req = wb_req_read_send(state, server_event_context(), state->sock,
                               WINBINDD_MAX_EXTRA_DATA);
        if (req == NULL) {
                remove_client(state);
                return;
        }
        tevent_req_set_callback(req, winbind_client_request_read, state);
+       state->io_req = req;
 }
 
 void request_error(struct winbindd_cli_state *state)
@@ -868,6 +919,7 @@ static void new_connection(int listen_sock, bool privileged)
                }
                return;
        }
+       smb_set_close_on_exec(sock);
 
        DEBUG(6,("accepted socket %d\n", sock));
 
@@ -887,11 +939,9 @@ static void new_connection(int listen_sock, bool privileged)
                return;
        }
 
-       state->last_access = time(NULL);        
-
        state->privileged = privileged;
 
-       req = wb_req_read_send(state, winbind_event_context(), state->sock,
+       req = wb_req_read_send(state, server_event_context(), state->sock,
                               WINBINDD_MAX_EXTRA_DATA);
        if (req == NULL) {
                TALLOC_FREE(state);
@@ -899,6 +949,7 @@ static void new_connection(int listen_sock, bool privileged)
                return;
        }
        tevent_req_set_callback(req, winbind_client_request_read, state);
+       state->io_req = req;
 
        /* Add to connection list */
 
@@ -912,6 +963,8 @@ static void winbind_client_request_read(struct tevent_req *req)
        ssize_t ret;
        int err;
 
+       state->io_req = NULL;
+
        ret = wb_req_read_recv(req, state, &state->request, &err);
        TALLOC_FREE(req);
        if (ret == -1) {
@@ -927,9 +980,53 @@ static void winbind_client_request_read(struct tevent_req *req)
                remove_client(state);
                return;
        }
+
+       req = wait_for_read_send(state, server_event_context(), state->sock,
+                                true);
+       if (req == NULL) {
+               DEBUG(0, ("winbind_client_request_read[%d:%s]:"
+                         " wait_for_read_send failed - removing client\n",
+                         (int)state->pid, state->cmd_name));
+               remove_client(state);
+               return;
+       }
+       tevent_req_set_callback(req, winbind_client_activity, state);
+       state->io_req = req;
+
        process_request(state);
 }
 
+static void winbind_client_activity(struct tevent_req *req)
+{
+       struct winbindd_cli_state *state =
+           tevent_req_callback_data(req, struct winbindd_cli_state);
+       int err;
+       bool has_data;
+
+       has_data = wait_for_read_recv(req, &err);
+
+       if (has_data) {
+               DEBUG(0, ("winbind_client_activity[%d:%s]:"
+                         "unexpected data from client - removing client\n",
+                         (int)state->pid, state->cmd_name));
+       } else {
+               if (err == EPIPE) {
+                       DEBUG(6, ("winbind_client_activity[%d:%s]: "
+                                 "client has closed connection - removing "
+                                 "client\n",
+                                 (int)state->pid, state->cmd_name));
+               } else {
+                       DEBUG(2, ("winbind_client_activity[%d:%s]: "
+                                 "client socket error (%s) - removing "
+                                 "client\n",
+                                 (int)state->pid, state->cmd_name,
+                                 strerror(err)));
+               }
+       }
+
+       remove_client(state);
+}
+
 /* Remove a client connection from client connection list */
 
 static void remove_client(struct winbindd_cli_state *state)
@@ -943,6 +1040,25 @@ static void remove_client(struct winbindd_cli_state *state)
                return;
        }
 
+       /*
+        * We need to remove a pending wb_req_read_*
+        * or wb_resp_write_* request before closing the
+        * socket.
+        *
+        * This is important as they might have used tevent_add_fd() and we
+        * use the epoll * backend on linux. So we must remove the tevent_fd
+        * before closing the fd.
+        *
+        * Otherwise we might hit a race with close_conns_after_fork() (via
+        * winbindd_reinit_after_fork()) where a file description
+        * is still open in a child, which means it's still active in
+        * the parents epoll queue, but the related tevent_fd is already
+        * already gone in the parent.
+        *
+        * See bug #11141.
+        */
+       TALLOC_FREE(state->io_req);
+
        if (state->sock != -1) {
                /* tell client, we are closing ... */
                nwritten = write(state->sock, &c, sizeof(c));
@@ -978,16 +1094,13 @@ static bool client_is_idle(struct winbindd_cli_state *state) {
 static bool remove_idle_client(void)
 {
        struct winbindd_cli_state *state, *remove_state = NULL;
-       time_t last_access = 0;
        int nidle = 0;
 
        for (state = winbindd_client_list(); state; state = state->next) {
                if (client_is_idle(state)) {
                        nidle++;
-                       if (!last_access || state->last_access < last_access) {
-                               last_access = state->last_access;
-                               remove_state = state;
-                       }
+                       /* list is sorted by access time */
+                       remove_state = state;
                }
        }
 
@@ -1001,6 +1114,60 @@ static bool remove_idle_client(void)
        return False;
 }
 
+/*
+ * Terminate all clients whose requests have taken longer than
+ * "winbind request timeout" seconds to process, or have been
+ * idle for more than "winbind request timeout" seconds.
+ */
+
+static void remove_timed_out_clients(void)
+{
+       struct winbindd_cli_state *state, *prev = NULL;
+       time_t curr_time = time(NULL);
+       int timeout_val = lp_winbind_request_timeout();
+
+       for (state = winbindd_client_list_tail(); state; state = prev) {
+               time_t expiry_time;
+
+               prev = winbindd_client_list_prev(state);
+               expiry_time = state->last_access + timeout_val;
+
+               if (curr_time <= expiry_time) {
+                       /* list is sorted, previous clients in
+                          list are newer */
+                       break;
+               }
+
+               if (client_is_idle(state)) {
+                       DEBUG(5,("Idle client timed out, "
+                                "shutting down sock %d, pid %u\n",
+                                state->sock,
+                                (unsigned int)state->pid));
+               } else {
+                       DEBUG(5,("Client request timed out, "
+                                "shutting down sock %d, pid %u\n",
+                                state->sock,
+                                (unsigned int)state->pid));
+               }
+
+               remove_client(state);
+       }
+}
+
+static void winbindd_scrub_clients_handler(struct tevent_context *ev,
+                                          struct tevent_timer *te,
+                                          struct timeval current_time,
+                                          void *private_data)
+{
+       remove_timed_out_clients();
+       if (tevent_add_timer(ev, ev,
+                            timeval_current_ofs(SCRUB_CLIENTS_INTERVAL, 0),
+                            winbindd_scrub_clients_handler, NULL) == NULL) {
+               DEBUG(0, ("winbindd: failed to reschedule client scrubber\n"));
+               exit(1);
+       }
+}
+
 struct winbindd_listen_state {
        bool privileged;
        int fd;
@@ -1026,6 +1193,7 @@ static void winbindd_listen_fde_handler(struct tevent_context *ev,
                        break;
                }
        }
+       remove_timed_out_clients();
        new_connection(s->fd, s->privileged);
 }
 
@@ -1038,14 +1206,44 @@ char *get_winbind_priv_pipe_dir(void)
        return state_path(WINBINDD_PRIV_SOCKET_SUBDIR);
 }
 
+static void winbindd_setup_max_fds(void)
+{
+       int num_fds = MAX_OPEN_FUDGEFACTOR;
+       int actual_fds;
+
+       num_fds += lp_winbind_max_clients();
+       /* Add some more to account for 2 sockets open
+          when the client transitions from unprivileged
+          to privileged socket
+       */
+       num_fds += lp_winbind_max_clients() / 10;
+
+       /* Add one socket per child process
+          (yeah there are child processes other than the
+          domain children but only domain children can vary
+          with configuration
+       */
+       num_fds += lp_winbind_max_domain_connections() *
+                  (lp_allow_trusted_domains() ? WINBIND_MAX_DOMAINS_HINT : 1);
+
+       actual_fds = set_maxfiles(num_fds);
+
+       if (actual_fds < num_fds) {
+               DEBUG(1, ("winbindd_setup_max_fds: Information only: "
+                         "requested %d open files, %d are available.\n",
+                         num_fds, actual_fds));
+       }
+}
+
 static bool winbindd_setup_listeners(void)
 {
        struct winbindd_listen_state *pub_state = NULL;
        struct winbindd_listen_state *priv_state = NULL;
        struct tevent_fd *fde;
        int rc;
+       char *socket_path;
 
-       pub_state = talloc(winbind_event_context(),
+       pub_state = talloc(server_event_context(),
                           struct winbindd_listen_state);
        if (!pub_state) {
                goto failed;
@@ -1062,7 +1260,7 @@ static bool winbindd_setup_listeners(void)
                goto failed;
        }
 
-       fde = tevent_add_fd(winbind_event_context(), pub_state, pub_state->fd,
+       fde = tevent_add_fd(server_event_context(), pub_state, pub_state->fd,
                            TEVENT_FD_READ, winbindd_listen_fde_handler,
                            pub_state);
        if (fde == NULL) {
@@ -1071,15 +1269,21 @@ static bool winbindd_setup_listeners(void)
        }
        tevent_fd_set_auto_close(fde);
 
-       priv_state = talloc(winbind_event_context(),
+       priv_state = talloc(server_event_context(),
                            struct winbindd_listen_state);
        if (!priv_state) {
                goto failed;
        }
 
+       socket_path = get_winbind_priv_pipe_dir();
+       if (socket_path == NULL) {
+               goto failed;
+       }
+
        priv_state->privileged = true;
        priv_state->fd = create_pipe_sock(
-               get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
+               socket_path, WINBINDD_SOCKET_NAME, 0750);
+       TALLOC_FREE(socket_path);
        if (priv_state->fd == -1) {
                goto failed;
        }
@@ -1088,7 +1292,7 @@ static bool winbindd_setup_listeners(void)
                goto failed;
        }
 
-       fde = tevent_add_fd(winbind_event_context(), priv_state,
+       fde = tevent_add_fd(server_event_context(), priv_state,
                            priv_state->fd, TEVENT_FD_READ,
                            winbindd_listen_fde_handler, priv_state);
        if (fde == NULL) {
@@ -1097,6 +1301,8 @@ static bool winbindd_setup_listeners(void)
        }
        tevent_fd_set_auto_close(fde);
 
+       winbindd_scrub_clients_handler(server_event_context(), NULL,
+                                      timeval_current(), NULL);
        return true;
 failed:
        TALLOC_FREE(pub_state);
@@ -1117,6 +1323,8 @@ bool winbindd_use_cache(void)
 static void winbindd_register_handlers(struct messaging_context *msg_ctx,
                                       bool foreground)
 {
+       bool scan_trusts = true;
+       NTSTATUS status;
        /* Setup signal handlers */
 
        if (!winbindd_setup_sig_term_handler(true))
@@ -1140,16 +1348,6 @@ static void winbindd_register_handlers(struct messaging_context *msg_ctx,
                exit(1);
        }
 
-       /* get broadcast messages */
-
-       if (!serverid_register(messaging_server_id(msg_ctx),
-                              FLAG_MSG_GENERAL |
-                              FLAG_MSG_WINBIND |
-                              FLAG_MSG_DBWRAP)) {
-               DEBUG(1, ("Could not register myself in serverid.tdb\n"));
-               exit(1);
-       }
-
        /* React on 'smbcontrol winbindd reload-config' in the same way
           as to SIGHUP signal */
        messaging_register(msg_ctx, NULL,
@@ -1166,14 +1364,11 @@ static void winbindd_register_handlers(struct messaging_context *msg_ctx,
                           MSG_WINBIND_ONLINESTATUS, winbind_msg_onlinestatus);
 
        /* Handle domain online/offline messages for domains */
-       messaging_register(winbind_messaging_context(), NULL,
+       messaging_register(server_messaging_context(), NULL,
                           MSG_WINBIND_DOMAIN_OFFLINE, winbind_msg_domain_offline);
-       messaging_register(winbind_messaging_context(), NULL,
+       messaging_register(server_messaging_context(), NULL,
                           MSG_WINBIND_DOMAIN_ONLINE, winbind_msg_domain_online);
 
-       messaging_register(msg_ctx, NULL,
-                          MSG_DUMP_EVENT_LIST, winbind_msg_dump_event_list);
-
        messaging_register(msg_ctx, NULL,
                           MSG_WINBIND_VALIDATE_CACHE,
                           winbind_msg_validate_cache);
@@ -1191,6 +1386,10 @@ static void winbindd_register_handlers(struct messaging_context *msg_ctx,
                           MSG_DEBUG,
                           winbind_msg_debug);
 
+       messaging_register(msg_ctx, NULL,
+                          MSG_WINBIND_DISCONNECT_DC,
+                          winbind_disconnect_dc_parent);
+
        netsamlogon_cache_init(); /* Non-critical */
 
        /* clear the cached list of trusted domains */
@@ -1208,14 +1407,32 @@ static void winbindd_register_handlers(struct messaging_context *msg_ctx,
        smb_nscd_flush_user_cache();
        smb_nscd_flush_group_cache();
 
-       if (lp_allow_trusted_domains()) {
-               if (tevent_add_timer(winbind_event_context(), NULL, timeval_zero(),
+       if (!lp_winbind_scan_trusted_domains()) {
+               scan_trusts = false;
+       }
+
+       if (!lp_allow_trusted_domains()) {
+               scan_trusts = false;
+       }
+
+       if (IS_DC) {
+               scan_trusts = false;
+       }
+
+       if (scan_trusts) {
+               if (tevent_add_timer(server_event_context(), NULL, timeval_zero(),
                              rescan_trusted_domains, NULL) == NULL) {
                        DEBUG(0, ("Could not trigger rescan_trusted_domains()\n"));
                        exit(1);
                }
        }
 
+       status = wb_irpc_register();
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("Could not register IRPC handlers\n"));
+               exit(1);
+       }
 }
 
 struct winbindd_addrchanged_state {
@@ -1333,6 +1550,8 @@ int main(int argc, const char **argv)
        NTSTATUS status;
        bool ok;
 
+       setproctitle_init(argc, discard_const(argv), environ);
+
        /*
         * Do this before any other talloc operation
         */
@@ -1356,7 +1575,7 @@ int main(int argc, const char **argv)
        fault_setup();
        dump_core_setup("winbindd", lp_logfile(talloc_tos()));
 
-       load_case_tables();
+       smb_init_locale();
 
        /* Initialise for running in non-root mode */
 
@@ -1473,7 +1692,7 @@ int main(int argc, const char **argv)
 
        /* Initialise messaging system */
 
-       if (winbind_messaging_context() == NULL) {
+       if (server_messaging_context() == NULL) {
                exit(1);
        }
 
@@ -1482,14 +1701,33 @@ int main(int argc, const char **argv)
                exit(1);
        }
 
-       ok = directory_create_or_exist(lp_lock_directory(), geteuid(), 0755);
+       {
+               size_t i;
+               const char *idmap_backend;
+               const char *invalid_backends[] = {
+                       "ad", "rfc2307", "rid",
+               };
+
+               idmap_backend = lp_idmap_default_backend();
+               for (i = 0; i < ARRAY_SIZE(invalid_backends); i++) {
+                       ok = strequal(idmap_backend, invalid_backends[i]);
+                       if (ok) {
+                               DBG_ERR("FATAL: Invalid idmap backend %s "
+                                       "configured as the default backend!\n",
+                                       idmap_backend);
+                               exit(1);
+                       }
+               }
+       }
+
+       ok = directory_create_or_exist(lp_lock_directory(), 0755);
        if (!ok) {
                DEBUG(0, ("Failed to create directory %s for lock files - %s\n",
                          lp_lock_directory(), strerror(errno)));
                exit(1);
        }
 
-       ok = directory_create_or_exist(lp_pid_directory(), geteuid(), 0755);
+       ok = directory_create_or_exist(lp_pid_directory(), 0755);
        if (!ok) {
                DEBUG(0, ("Failed to create directory %s for pid files - %s\n",
                          lp_pid_directory(), strerror(errno)));
@@ -1548,12 +1786,13 @@ int main(int argc, const char **argv)
         * winbindd-specific resources we must free yet. JRA.
         */
 
-       status = reinit_after_fork(winbind_messaging_context(),
-                                  winbind_event_context(),
-                                  false);
+       status = reinit_after_fork(server_messaging_context(),
+                                  server_event_context(),
+                                  false, NULL);
        if (!NT_STATUS_IS_OK(status)) {
                exit_daemon("Winbindd reinit_after_fork() failed", map_errno_from_nt_status(status));
        }
+       initialize_password_db(true, server_event_context());
 
        /*
         * Do not initialize the parent-child-pipe before becoming
@@ -1565,13 +1804,13 @@ int main(int argc, const char **argv)
                exit_daemon(nt_errstr(status), map_errno_from_nt_status(status));
        }
 
-       winbindd_register_handlers(winbind_messaging_context(), !Fork);
+       winbindd_register_handlers(server_messaging_context(), !Fork);
 
-       if (!messaging_parent_dgm_cleanup_init(winbind_messaging_context())) {
+       if (!messaging_parent_dgm_cleanup_init(server_messaging_context())) {
                exit(1);
        }
 
-       status = init_system_session_info();
+       status = init_system_session_info(NULL);
        if (!NT_STATUS_IS_OK(status)) {
                exit_daemon("Winbindd failed to setup system user info", map_errno_from_nt_status(status));
        }
@@ -1579,8 +1818,8 @@ int main(int argc, const char **argv)
        rpc_lsarpc_init(NULL);
        rpc_samr_init(NULL);
 
-       winbindd_init_addrchange(NULL, winbind_event_context(),
-                                winbind_messaging_context());
+       winbindd_init_addrchange(NULL, server_event_context(),
+                                server_messaging_context());
 
        /* setup listen sockets */
 
@@ -1588,17 +1827,21 @@ int main(int argc, const char **argv)
                exit_daemon("Winbindd failed to setup listeners", EPIPE);
        }
 
+       irpc_add_name(winbind_imessaging_context(), "winbind_server");
+
        TALLOC_FREE(frame);
 
        if (!interactive) {
                daemon_ready("winbindd");
        }
 
+       gpupdate_init();
+
        /* Loop waiting for requests */
        while (1) {
                frame = talloc_stackframe();
 
-               if (tevent_loop_once(winbind_event_context()) == -1) {
+               if (tevent_loop_once(server_event_context()) == -1) {
                        DEBUG(1, ("tevent_loop_once() failed: %s\n",
                                  strerror(errno)));
                        return 1;