s3:winbind: talloc the static idmap child
[samba.git] / source3 / winbindd / winbindd.c
index 56c5b6ed8e2e6c5d152169f914755e53f33c6e7a..b87686f04c552433cb003eb2405e96485e86d3fe 100644 (file)
 */
 
 #include "includes.h"
-#include "popt_common.h"
+#include "lib/cmdline/cmdline.h"
 #include "winbindd.h"
 #include "nsswitch/winbind_client.h"
 #include "nsswitch/wb_reqtrans.h"
 #include "ntdomain.h"
-#include "../librpc/gen_ndr/srv_lsa.h"
-#include "../librpc/gen_ndr/srv_samr.h"
+#include "librpc/rpc/dcesrv_core.h"
+#include "librpc/gen_ndr/ndr_lsa_scompat.h"
+#include "librpc/gen_ndr/ndr_samr_scompat.h"
+#include "librpc/gen_ndr/ndr_winbind_scompat.h"
 #include "secrets.h"
 #include "rpc_client/cli_netlogon.h"
 #include "idmap.h"
 #include "libsmb/samlogon_cache.h"
 #include "libcli/auth/netlogon_creds_cli.h"
 #include "passdb.h"
+#include "lib/util/tevent_req_profile.h"
+#include "lib/gencache.h"
+#include "rpc_server/rpc_config.h"
+#include "lib/global_contexts.h"
+#include "source3/lib/substitute.h"
+#include "winbindd_traceid.h"
+#include "lib/util/util_process.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
 
 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 imessaging_context *winbind_imessaging_context(void)
-{
-       static struct imessaging_context *msg = NULL;
-       struct messaging_context *msg_ctx;
-       struct server_id myself;
-       struct loadparm_context *lp_ctx;
-
-       if (msg != NULL) {
-               return msg;
-       }
-
-       msg_ctx = server_messaging_context();
-       if (msg_ctx == NULL) {
-               smb_panic("server_messaging_context failed\n");
-       }
-       myself = messaging_server_id(msg_ctx);
-
-       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 = 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");
-       }
-       return msg;
-}
-
 /* Reload configuration */
 
-static bool reload_services_file(const char *lfile)
-{
-       bool ret;
-
-       if (lp_loaded()) {
-               char *fname = lp_next_configfile(talloc_tos());
-
-               if (file_exist(fname) && !strcsequal(fname,get_dyn_CONFIGFILE())) {
-                       set_dyn_CONFIGFILE(fname);
-               }
-               TALLOC_FREE(fname);
-       }
-
-       /* if this is a child, restore the logfile to the special
-          name - <domain>, idmap, etc. */
-       if (lfile && *lfile) {
-               lp_set_logfile(lfile);
-       }
-
-       reopen_logs();
-       ret = lp_load_global(get_dyn_CONFIGFILE());
-
-       reopen_logs();
-       load_interfaces();
-       winbindd_setup_max_fds();
-
-       return(ret);
-}
 
 
 static void winbindd_status(void)
@@ -147,103 +89,6 @@ static void winbindd_status(void)
        }
 }
 
-/* Flush client cache */
-
-static void flush_caches(void)
-{
-       /* We need to invalidate cached user list entries on a SIGHUP 
-           otherwise cached access denied errors due to restrict anonymous
-           hang around until the sequence number changes. */
-
-       if (!wcache_invalidate_cache()) {
-               DEBUG(0, ("invalidating the cache failed; revalidate the cache\n"));
-               if (!winbindd_cache_validate_and_initialize()) {
-                       exit(1);
-               }
-       }
-}
-
-static void flush_caches_noinit(void)
-{
-       /*
-        * We need to invalidate cached user list entries on a SIGHUP
-         * otherwise cached access denied errors due to restrict anonymous
-         * hang around until the sequence number changes.
-        * NB
-        * Skip uninitialized domains when flush cache.
-        * If domain is not initialized, it means it is never
-        * used or never become online. look, wcache_invalidate_cache()
-        * -> get_cache() -> init_dc_connection(). It causes a lot of traffic
-        * for unused domains and large traffic for primay domain's DC if there
-        * are many domains..
-        */
-
-       if (!wcache_invalidate_cache_noinit()) {
-               DEBUG(0, ("invalidating the cache failed; revalidate the cache\n"));
-               if (!winbindd_cache_validate_and_initialize()) {
-                       exit(1);
-               }
-       }
-}
-
-/* Handle the signal by unlinking socket and exiting */
-
-static void terminate(bool is_parent)
-{
-       if (is_parent) {
-               /* When parent goes away we should
-                * remove the socket file. Not so
-                * when children terminate.
-                */ 
-               char *path = NULL;
-
-               if (asprintf(&path, "%s/%s",
-                       lp_winbindd_socket_directory(), WINBINDD_SOCKET_NAME) > 0) {
-                       unlink(path);
-                       SAFE_FREE(path);
-               }
-       }
-
-       idmap_close();
-
-       gencache_stabilize();
-
-       netlogon_creds_cli_close_global_db();
-
-#if 0
-       if (interactive) {
-               TALLOC_CTX *mem_ctx = talloc_init("end_description");
-               char *description = talloc_describe_all(mem_ctx);
-
-               DEBUG(3, ("tallocs left:\n%s\n", description));
-               talloc_destroy(mem_ctx);
-       }
-#endif
-
-       if (is_parent) {
-               pidfile_unlink(lp_pid_directory(), "winbindd");
-       }
-
-       exit(0);
-}
-
-static void winbindd_sig_term_handler(struct tevent_context *ev,
-                                     struct tevent_signal *se,
-                                     int signum,
-                                     int count,
-                                     void *siginfo,
-                                     void *private_data)
-{
-       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, is_parent));
-       terminate(is_parent);
-}
-
 /*
   handle stdin becoming readable when we are in --foreground mode
  */
@@ -260,56 +105,8 @@ static void winbindd_stdin_handler(struct tevent_context *ev,
                   parent has exited. Shutdown the server */
                DEBUG(0,("EOF on stdin (is_parent=%d)\n",
                         (int)*is_parent));
-               terminate(*is_parent);
-       }
-}
-
-bool winbindd_setup_sig_term_handler(bool parent)
-{
-       struct tevent_signal *se;
-       bool *is_parent;
-
-       is_parent = talloc(server_event_context(), bool);
-       if (!is_parent) {
-               return false;
-       }
-
-       *is_parent = parent;
-
-       se = tevent_add_signal(server_event_context(),
-                              is_parent,
-                              SIGTERM, 0,
-                              winbindd_sig_term_handler,
-                              is_parent);
-       if (!se) {
-               DEBUG(0,("failed to setup SIGTERM handler"));
-               talloc_free(is_parent);
-               return false;
-       }
-
-       se = tevent_add_signal(server_event_context(),
-                              is_parent,
-                              SIGINT, 0,
-                              winbindd_sig_term_handler,
-                              is_parent);
-       if (!se) {
-               DEBUG(0,("failed to setup SIGINT handler"));
-               talloc_free(is_parent);
-               return false;
-       }
-
-       se = tevent_add_signal(server_event_context(),
-                              is_parent,
-                              SIGQUIT, 0,
-                              winbindd_sig_term_handler,
-                              is_parent);
-       if (!se) {
-               DEBUG(0,("failed to setup SIGINT handler"));
-               talloc_free(is_parent);
-               return false;
+               winbindd_terminate(*is_parent);
        }
-
-       return true;
 }
 
 bool winbindd_setup_stdin_handler(bool parent, bool foreground)
@@ -319,7 +116,7 @@ bool winbindd_setup_stdin_handler(bool parent, bool foreground)
        if (foreground) {
                struct stat st;
 
-               is_parent = talloc(server_event_context(), bool);
+               is_parent = talloc(global_event_context(), bool);
                if (!is_parent) {
                        return false;
                }
@@ -335,7 +132,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(server_event_context(),
+                       tevent_add_fd(global_event_context(),
                                        is_parent,
                                        0,
                                        TEVENT_FD_READ,
@@ -347,45 +144,6 @@ bool winbindd_setup_stdin_handler(bool parent, bool foreground)
        return true;
 }
 
-static void winbindd_sig_hup_handler(struct tevent_context *ev,
-                                    struct tevent_signal *se,
-                                    int signum,
-                                    int count,
-                                    void *siginfo,
-                                    void *private_data)
-{
-       const char *file = (const char *)private_data;
-
-       DEBUG(1,("Reloading services after SIGHUP\n"));
-       flush_caches_noinit();
-       reload_services_file(file);
-}
-
-bool winbindd_setup_sig_hup_handler(const char *lfile)
-{
-       struct tevent_signal *se;
-       char *file = NULL;
-
-       if (lfile) {
-               file = talloc_strdup(server_event_context(),
-                                    lfile);
-               if (!file) {
-                       return false;
-               }
-       }
-
-       se = tevent_add_signal(server_event_context(),
-                              server_event_context(),
-                              SIGHUP, 0,
-                              winbindd_sig_hup_handler,
-                              file);
-       if (!se) {
-               return false;
-       }
-
-       return true;
-}
-
 static void winbindd_sig_chld_handler(struct tevent_context *ev,
                                      struct tevent_signal *se,
                                      int signum,
@@ -404,8 +162,8 @@ static bool winbindd_setup_sig_chld_handler(void)
 {
        struct tevent_signal *se;
 
-       se = tevent_add_signal(server_event_context(),
-                              server_event_context(),
+       se = tevent_add_signal(global_event_context(),
+                              global_event_context(),
                               SIGCHLD, 0,
                               winbindd_sig_chld_handler,
                               NULL);
@@ -430,8 +188,8 @@ static bool winbindd_setup_sig_usr2_handler(void)
 {
        struct tevent_signal *se;
 
-       se = tevent_add_signal(server_event_context(),
-                              server_event_context(),
+       se = tevent_add_signal(global_event_context(),
+                              global_event_context(),
                               SIGUSR2, 0,
                               winbindd_sig_usr2_handler,
                               NULL);
@@ -442,18 +200,6 @@ static bool winbindd_setup_sig_usr2_handler(void)
        return true;
 }
 
-/* React on 'smbcontrol winbindd reload-config' in the same way as on SIGHUP*/
-static void msg_reload_services(struct messaging_context *msg,
-                               void *private_data,
-                               uint32_t msg_type,
-                               struct server_id server_id,
-                               DATA_BLOB *data)
-{
-        /* Flush various caches */
-       flush_caches();
-       reload_services_file((const char *) private_data);
-}
-
 /* React on 'smbcontrol winbindd shutdown' in the same way as on SIGTERM*/
 static void msg_shutdown(struct messaging_context *msg,
                         void *private_data,
@@ -463,7 +209,7 @@ static void msg_shutdown(struct messaging_context *msg,
 {
        /* only the parent waits for this message */
        DEBUG(0,("Got shutdown message\n"));
-       terminate(true);
+       winbindd_terminate(true);
 }
 
 
@@ -512,7 +258,7 @@ static void winbind_msg_validate_cache(struct messaging_context *msg_ctx,
        /* install default SIGCHLD handler: validation code uses fork/waitpid */
        CatchSignal(SIGCHLD, SIG_DFL);
 
-       setproctitle("validate cache child");
+       process_set_title("wb: check cache", "validate cache child");
 
        ret = (uint8_t)winbindd_validate_cache_nobackup();
        DEBUG(10, ("winbindd_msg_validata_cache: got return value %d\n", ret));
@@ -677,7 +423,18 @@ static struct tevent_req *process_request_send(
        enum winbindd_cmd cmd = cli_state->request->cmd;
        size_t i;
        bool ok;
+       static uint64_t request_index = 1;
 
+       /*
+        * debug traceid values:
+        * 0   .. inactive
+        * 1   .. not processing a winbind request, but in other code (timers)
+        * >=2 .. winbind request processing
+        */
+       if (debug_traceid_get() != 0) {
+               request_index = ++request_index == 0 ? 2 : request_index;
+               debug_traceid_set(request_index);
+       }
        req = tevent_req_create(mem_ctx, &state,
                                struct process_request_state);
        if (req == NULL) {
@@ -686,6 +443,11 @@ static struct tevent_req *process_request_send(
        state->cli_state = cli_state;
        state->ev = ev;
 
+       ok = tevent_req_set_profile(req);
+       if (!ok) {
+               return tevent_req_post(req, ev);
+       }
+
        SMB_ASSERT(cli_state->mem_ctx == NULL);
        cli_state->mem_ctx = talloc_named(cli_state, 0, "winbind request");
        if (tevent_req_nomem(cli_state->mem_ctx, req)) {
@@ -703,6 +465,9 @@ static struct tevent_req *process_request_send(
 
        /* Remember who asked us. */
        cli_state->pid = cli_state->request->pid;
+       memcpy(cli_state->client_name,
+              cli_state->request->client_name,
+              sizeof(cli_state->client_name));
 
        cli_state->cmd_name = "unknown request";
        cli_state->recv_fn = NULL;
@@ -729,8 +494,10 @@ static struct tevent_req *process_request_send(
                cli_state->cmd_name = atable->cmd_name;
                cli_state->recv_fn = atable->recv_req;
 
-               DEBUG(10, ("process_request: Handling async request %d:%s\n",
-                          (int)cli_state->pid, cli_state->cmd_name));
+               DBG_NOTICE("[%s (%d)] Handling async request: %s\n",
+                          cli_state->client_name,
+                          (int)cli_state->pid,
+                          cli_state->cmd_name);
 
                subreq = atable->send_req(
                        state,
@@ -753,6 +520,8 @@ static struct tevent_req *process_request_send(
        ok = false;
 
        if (i < ARRAY_SIZE(bool_dispatch_table)) {
+               cli_state->cmd_name = bool_dispatch_table[i].cmd_name;
+
                DBG_DEBUG("process_request: request fn %s\n",
                          bool_dispatch_table[i].cmd_name);
                ok = bool_dispatch_table[i].fn(cli_state);
@@ -792,10 +561,11 @@ static void process_request_done(struct tevent_req *subreq)
        status = cli_state->recv_fn(subreq, cli_state->response);
        TALLOC_FREE(subreq);
 
-       DBG_DEBUG("[%d:%s]: %s\n",
-                 (int)cli_state->pid,
-                 cli_state->cmd_name,
-                 nt_errstr(status));
+       DBG_NOTICE("[%s(%d):%s]: %s\n",
+                  cli_state->client_name,
+                  (int)cli_state->pid,
+                  cli_state->cmd_name,
+                  nt_errstr(status));
 
        ok = NT_STATUS_IS_OK(status);
        cli_state->response->result = ok ? WINBINDD_OK : WINBINDD_ERROR;
@@ -836,8 +606,10 @@ static void process_request_written(struct tevent_req *subreq)
                return;
        }
 
-       DBG_DEBUG("[%d:%s]: delivered response to client\n",
-                 (int)cli_state->pid, cli_state->cmd_name);
+       DBG_DEBUG("[%s(%d):%s]: delivered response to client\n",
+                 cli_state->client_name,
+                 (int)cli_state->pid,
+                 cli_state->cmd_name);
 
        TALLOC_FREE(cli_state->mem_ctx);
        cli_state->response = NULL;
@@ -847,7 +619,10 @@ static void process_request_written(struct tevent_req *subreq)
        tevent_req_done(req);
 }
 
-static NTSTATUS process_request_recv(struct tevent_req *req)
+static NTSTATUS process_request_recv(
+       struct tevent_req *req,
+       TALLOC_CTX *mem_ctx,
+       struct tevent_req_profile **profile)
 {
        NTSTATUS status;
 
@@ -856,6 +631,7 @@ static NTSTATUS process_request_recv(struct tevent_req *req)
                return status;
        }
 
+       *profile = tevent_req_move_profile(req, mem_ctx);
        tevent_req_received(req);
        return NT_STATUS_OK;
 }
@@ -892,14 +668,13 @@ static void new_connection(int listen_sock, bool privileged)
 
        if (sock == -1) {
                if (errno != EINTR) {
-                       DEBUG(0, ("Failed to accept socket - %s\n",
-                                 strerror(errno)));
+                       D_ERR("Failed to accept socket: %s\n", strerror(errno));
                }
                return;
        }
        smb_set_close_on_exec(sock);
 
-       DEBUG(6,("accepted socket %d\n", sock));
+       D_INFO("Accepted client socket %d\n", sock);
 
        /* Create new connection structure */
 
@@ -919,7 +694,7 @@ static void new_connection(int listen_sock, bool privileged)
 
        state->privileged = privileged;
 
-       req = wb_req_read_send(state, server_event_context(), state->sock,
+       req = wb_req_read_send(state, global_event_context(), state->sock,
                               WINBINDD_MAX_EXTRA_DATA);
        if (req == NULL) {
                TALLOC_FREE(state);
@@ -959,7 +734,7 @@ static void winbind_client_request_read(struct tevent_req *req)
                return;
        }
 
-       req = wait_for_read_send(state, server_event_context(), state->sock,
+       req = wait_for_read_send(state, global_event_context(), state->sock,
                                 true);
        if (req == NULL) {
                DEBUG(0, ("winbind_client_request_read[%d:%s]:"
@@ -971,7 +746,7 @@ static void winbind_client_request_read(struct tevent_req *req)
        tevent_req_set_callback(req, winbind_client_activity, state);
        state->io_req = req;
 
-       req = process_request_send(state, server_event_context(), state);
+       req = process_request_send(state, global_event_context(), state);
        if (req == NULL) {
                DBG_ERR("process_request_send failed\n");
                remove_client(state);
@@ -1015,9 +790,12 @@ static void winbind_client_processed(struct tevent_req *req)
 {
        struct winbindd_cli_state *cli_state = tevent_req_callback_data(
                req, struct winbindd_cli_state);
+       struct tevent_req_profile *profile = NULL;
+       struct timeval start, stop, diff;
+       int threshold;
        NTSTATUS status;
 
-       status = process_request_recv(req);
+       status = process_request_recv(req, cli_state, &profile);
        TALLOC_FREE(req);
        if (!NT_STATUS_IS_OK(status)) {
                DBG_DEBUG("process_request failed: %s\n", nt_errstr(status));
@@ -1025,9 +803,39 @@ static void winbind_client_processed(struct tevent_req *req)
                return;
        }
 
+       tevent_req_profile_get_start(profile, NULL, &start);
+       tevent_req_profile_get_stop(profile, NULL, &stop);
+       diff = tevent_timeval_until(&start, &stop);
+
+       threshold = lp_parm_int(-1, "winbind", "request profile threshold", 60);
+
+       if (diff.tv_sec >= threshold) {
+               int depth;
+               char *str;
+
+               depth = lp_parm_int(
+                       -1,
+                       "winbind",
+                       "request profile depth",
+                       INT_MAX);
+
+               DBG_ERR("request took %u.%.6u seconds\n",
+                       (unsigned)diff.tv_sec, (unsigned)diff.tv_usec);
+
+               str = tevent_req_profile_string(
+                       talloc_tos(), profile, 0, depth);
+               if (str != NULL) {
+                       /* No "\n", already contained in "str" */
+                       DEBUGADD(0, ("%s", str));
+               }
+               TALLOC_FREE(str);
+       }
+
+       TALLOC_FREE(profile);
+
        req = wb_req_read_send(
                cli_state,
-               server_event_context(),
+               global_event_context(),
                cli_state->sock,
                WINBINDD_MAX_EXTRA_DATA);
        if (req == NULL) {
@@ -1042,9 +850,6 @@ static void winbind_client_processed(struct tevent_req *req)
 
 static void remove_client(struct winbindd_cli_state *state)
 {
-       char c = 0;
-       int nwritten;
-
        /* It's a dead client - hold a funeral */
 
        if (state == NULL) {
@@ -1071,6 +876,9 @@ static void remove_client(struct winbindd_cli_state *state)
        TALLOC_FREE(state->io_req);
 
        if (state->sock != -1) {
+               char c = 0;
+               int nwritten;
+
                /* tell client, we are closing ... */
                nwritten = write(state->sock, &c, sizeof(c));
                if (nwritten == -1) {
@@ -1212,40 +1020,6 @@ static void winbindd_listen_fde_handler(struct tevent_context *ev,
  * Winbindd socket accessor functions
  */
 
-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;
@@ -1254,7 +1028,7 @@ static bool winbindd_setup_listeners(void)
        int rc;
        char *socket_path;
 
-       pub_state = talloc(server_event_context(),
+       pub_state = talloc(global_event_context(),
                           struct winbindd_listen_state);
        if (!pub_state) {
                goto failed;
@@ -1271,7 +1045,7 @@ static bool winbindd_setup_listeners(void)
                goto failed;
        }
 
-       fde = tevent_add_fd(server_event_context(), pub_state, pub_state->fd,
+       fde = tevent_add_fd(global_event_context(), pub_state, pub_state->fd,
                            TEVENT_FD_READ, winbindd_listen_fde_handler,
                            pub_state);
        if (fde == NULL) {
@@ -1280,7 +1054,7 @@ static bool winbindd_setup_listeners(void)
        }
        tevent_fd_set_auto_close(fde);
 
-       priv_state = talloc(server_event_context(),
+       priv_state = talloc(global_event_context(),
                            struct winbindd_listen_state);
        if (!priv_state) {
                goto failed;
@@ -1303,7 +1077,7 @@ static bool winbindd_setup_listeners(void)
                goto failed;
        }
 
-       fde = tevent_add_fd(server_event_context(), priv_state,
+       fde = tevent_add_fd(global_event_context(), priv_state,
                            priv_state->fd, TEVENT_FD_READ,
                            winbindd_listen_fde_handler, priv_state);
        if (fde == NULL) {
@@ -1312,7 +1086,7 @@ static bool winbindd_setup_listeners(void)
        }
        tevent_fd_set_auto_close(fde);
 
-       winbindd_scrub_clients_handler(server_event_context(), NULL,
+       winbindd_scrub_clients_handler(global_event_context(), NULL,
                                       timeval_current(), NULL);
        return true;
 failed:
@@ -1321,21 +1095,13 @@ failed:
        return false;
 }
 
-bool winbindd_use_idmap_cache(void)
-{
-       return !opt_nocache;
-}
-
-bool winbindd_use_cache(void)
-{
-       return !opt_nocache;
-}
-
 static void winbindd_register_handlers(struct messaging_context *msg_ctx,
                                       bool foreground)
 {
        bool scan_trusts = true;
        NTSTATUS status;
+       struct tevent_timer *te = NULL;
+
        /* Setup signal handlers */
 
        if (!winbindd_setup_sig_term_handler(true))
@@ -1362,7 +1128,8 @@ static void winbindd_register_handlers(struct messaging_context *msg_ctx,
        /* React on 'smbcontrol winbindd reload-config' in the same way
           as to SIGHUP signal */
        messaging_register(msg_ctx, NULL,
-                          MSG_SMB_CONF_UPDATED, msg_reload_services);
+                          MSG_SMB_CONF_UPDATED,
+                          winbindd_msg_reload_services_parent);
        messaging_register(msg_ctx, NULL,
                           MSG_SHUTDOWN, msg_shutdown);
 
@@ -1375,9 +1142,9 @@ 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(server_messaging_context(), NULL,
+       messaging_register(global_messaging_context(), NULL,
                           MSG_WINBIND_DOMAIN_OFFLINE, winbind_msg_domain_offline);
-       messaging_register(server_messaging_context(), NULL,
+       messaging_register(global_messaging_context(), NULL,
                           MSG_WINBIND_DOMAIN_ONLINE, winbind_msg_domain_online);
 
        messaging_register(msg_ctx, NULL,
@@ -1412,7 +1179,11 @@ static void winbindd_register_handlers(struct messaging_context *msg_ctx,
                exit(1);
        }
 
-       init_idmap_child();
+       status = init_idmap_child(global_event_context());
+       if (NT_STATUS_IS_ERR(status)) {
+               DBG_ERR("Unable to start idmap child: %s\n", nt_errstr(status));
+               exit(1);
+       }
        init_locator_child();
 
        smb_nscd_flush_user_cache();
@@ -1431,13 +1202,23 @@ static void winbindd_register_handlers(struct messaging_context *msg_ctx,
        }
 
        if (scan_trusts) {
-               if (tevent_add_timer(server_event_context(), NULL, timeval_zero(),
+               if (tevent_add_timer(global_event_context(), NULL, timeval_zero(),
                              rescan_trusted_domains, NULL) == NULL) {
                        DEBUG(0, ("Could not trigger rescan_trusted_domains()\n"));
                        exit(1);
                }
        }
 
+       te = tevent_add_timer(global_event_context(),
+                             NULL,
+                             timeval_zero(),
+                             winbindd_ping_offline_domains,
+                             NULL);
+       if (te == NULL) {
+               DBG_ERR("Failed to schedule winbindd_ping_offline_domains()\n");
+               exit(1);
+       }
+
        status = wb_irpc_register();
 
        if (!NT_STATUS_IS_OK(status)) {
@@ -1534,32 +1315,35 @@ static void winbindd_addr_changed(struct tevent_req *req)
 
 int main(int argc, const char **argv)
 {
-       static bool is_daemon = False;
-       static bool Fork = True;
        static bool log_stdout = False;
-       static bool no_process_group = False;
-       enum {
-               OPT_DAEMON = 1000,
-               OPT_FORK,
-               OPT_NO_PROCESS_GROUP,
-               OPT_LOG_STDOUT
-       };
+       struct samba_cmdline_daemon_cfg *cmdline_daemon_cfg = NULL;
        struct poptOption long_options[] = {
                POPT_AUTOHELP
-               { "stdout", 'S', POPT_ARG_NONE, NULL, OPT_LOG_STDOUT, "Log to stdout" },
-               { "foreground", 'F', POPT_ARG_NONE, NULL, OPT_FORK, "Daemon in foreground mode" },
-               { "no-process-group", 0, POPT_ARG_NONE, NULL, OPT_NO_PROCESS_GROUP, "Don't create a new process group" },
-               { "daemon", 'D', POPT_ARG_NONE, NULL, OPT_DAEMON, "Become a daemon (default)" },
-               { "interactive", 'i', POPT_ARG_NONE, NULL, 'i', "Interactive mode" },
-               { "no-caching", 'n', POPT_ARG_NONE, NULL, 'n', "Disable caching" },
+               {
+                       .longName   = "no-caching",
+                       .shortName  = 'n',
+                       .argInfo    = POPT_ARG_NONE,
+                       .arg        = NULL,
+                       .val        = 'n',
+                       .descrip    = "Disable caching",
+               },
                POPT_COMMON_SAMBA
+               POPT_COMMON_DAEMON
+               POPT_COMMON_VERSION
                POPT_TABLEEND
        };
+       const struct loadparm_substitution *lp_sub =
+               loadparm_s3_global_substitution();
        poptContext pc;
        int opt;
        TALLOC_CTX *frame;
        NTSTATUS status;
        bool ok;
+       const struct dcesrv_endpoint_server *ep_server = NULL;
+       struct dcesrv_context *dce_ctx = NULL;
+       size_t winbindd_socket_dir_len = 0;
+       char *winbindd_priv_socket_dir = NULL;
+       size_t winbindd_priv_socket_dir_len = 0;
 
        setproctitle_init(argc, discard_const(argv), environ);
 
@@ -1575,7 +1359,7 @@ int main(int argc, const char **argv)
         */
        umask(0);
 
-       setup_logging("winbindd", DEBUG_DEFAULT_STDOUT);
+       smb_init_locale();
 
        /* glibc (?) likes to print "User defined signal 1" and exit if a
           SIGUSR[12] is received before a handler is installed */
@@ -1583,51 +1367,28 @@ int main(int argc, const char **argv)
        CatchSignal(SIGUSR1, SIG_IGN);
        CatchSignal(SIGUSR2, SIG_IGN);
 
-       fault_setup();
-       dump_core_setup("winbindd", lp_logfile(talloc_tos()));
-
-       smb_init_locale();
-
-       /* Initialise for running in non-root mode */
-
-       sec_init();
-
-       set_remote_machine_name("winbindd", False);
-
-       /* Set environment variable so we don't recursively call ourselves.
-          This may also be useful interactively. */
-
-       if ( !winbind_off() ) {
-               DEBUG(0,("Failed to disable recusive winbindd calls.  Exiting.\n"));
+       ok = samba_cmdline_init(frame,
+                               SAMBA_CMDLINE_CONFIG_SERVER,
+                               true /* require_smbconf */);
+       if (!ok) {
+               DBG_ERR("Failed to setup cmdline parser\n");
+               TALLOC_FREE(frame);
                exit(1);
        }
 
-       /* Initialise samba/rpc client stuff */
+       cmdline_daemon_cfg = samba_cmdline_get_daemon_cfg();
 
-       pc = poptGetContext("winbindd", argc, argv, long_options, 0);
+       pc = samba_popt_get_context(getprogname(), argc, argv, long_options, 0);
+       if (pc == NULL) {
+               DBG_ERR("Failed to setup popt parser!\n");
+               TALLOC_FREE(frame);
+               exit(1);
+       }
 
        while ((opt = poptGetNextOpt(pc)) != -1) {
                switch (opt) {
-                       /* Don't become a daemon */
-               case OPT_DAEMON:
-                       is_daemon = True;
-                       break;
-               case 'i':
-                       interactive = True;
-                       log_stdout = True;
-                       Fork = False;
-                       break;
-                case OPT_FORK:
-                       Fork = false;
-                       break;
-               case OPT_NO_PROCESS_GROUP:
-                       no_process_group = true;
-                       break;
-               case OPT_LOG_STDOUT:
-                       log_stdout = true;
-                       break;
                case 'n':
-                       opt_nocache = true;
+                       winbindd_set_use_cache(false);
                        break;
                default:
                        d_fprintf(stderr, "\nInvalid option %s: %s\n\n",
@@ -1637,65 +1398,136 @@ int main(int argc, const char **argv)
                }
        }
 
-       /* We call dump_core_setup one more time because the command line can
-        * set the log file or the log-basename and this will influence where
-        * cores are stored. Without this call get_dyn_LOGFILEBASE will be
-        * the default value derived from build's prefix. For EOM this value
-        * is often not related to the path where winbindd is actually run
-        * in production.
-        */
-       dump_core_setup("winbindd", lp_logfile(talloc_tos()));
-       if (is_daemon && interactive) {
+       /* Set environment variable so we don't recursively call ourselves.
+          This may also be useful interactively. */
+       if ( !winbind_off() ) {
+               DEBUG(0,("Failed to disable recursive winbindd calls.  Exiting.\n"));
+               exit(1);
+       }
+
+       /* Initialise for running in non-root mode */
+       sec_init();
+
+       set_remote_machine_name("winbindd", False);
+
+       dump_core_setup("winbindd", lp_logfile(talloc_tos(), lp_sub));
+       if (cmdline_daemon_cfg->daemon && cmdline_daemon_cfg->interactive) {
                d_fprintf(stderr,"\nERROR: "
                          "Option -i|--interactive is not allowed together with -D|--daemon\n\n");
                poptPrintUsage(pc, stderr, 0);
                exit(1);
        }
 
-       if (log_stdout && Fork) {
+       log_stdout = (debug_get_log_type() == DEBUG_STDOUT);
+       if (cmdline_daemon_cfg->interactive) {
+               /*
+                * libcmdline POPT_DAEMON callback sets "fork" to false if "-i"
+                * for interactive is passed on the commandline. Set it back to
+                * true. TODO: check if this is correct, smbd and nmbd don't do
+                * this.
+                */
+               cmdline_daemon_cfg->fork = true;
+               log_stdout = true;
+       }
+
+       if (log_stdout && cmdline_daemon_cfg->fork) {
                d_fprintf(stderr, "\nERROR: "
-                         "Can't log to stdout (-S) unless daemon is in foreground +(-F) or interactive (-i)\n\n");
+                         "Can't log to stdout (-S) unless daemon is in "
+                         "foreground (-F) or interactive (-i)\n\n");
                poptPrintUsage(pc, stderr, 0);
                exit(1);
        }
 
        poptFreeContext(pc);
 
-       if (!override_logfile) {
-               char *lfile = NULL;
-               if (asprintf(&lfile,"%s/log.winbindd",
-                               get_dyn_LOGFILEBASE()) > 0) {
-                       lp_set_logfile(lfile);
-                       SAFE_FREE(lfile);
-               }
-       }
-
-       if (log_stdout) {
-               setup_logging("winbindd", DEBUG_STDOUT);
-       } else {
-               setup_logging("winbindd", DEBUG_FILE);
-       }
        reopen_logs();
 
-       DEBUG(0,("winbindd version %s started.\n", samba_version_string()));
-       DEBUGADD(0,("%s\n", COPYRIGHT_STARTUP_MESSAGE));
+       DBG_STARTUP_NOTICE("winbindd version %s started.\n"
+                       COPYRIGHT_STARTUP_MESSAGE "\n",
+               samba_version_string());
 
-       if (!lp_load_initial_only(get_dyn_CONFIGFILE())) {
-               DEBUG(0, ("error opening config file '%s'\n", get_dyn_CONFIGFILE()));
-               exit(1);
-       }
        /* After parsing the configuration file we setup the core path one more time
         * as the log file might have been set in the configuration and cores's
         * path is by default basename(lp_logfile()).
         */
-       dump_core_setup("winbindd", lp_logfile(talloc_tos()));
+       dump_core_setup("winbindd", lp_logfile(talloc_tos(), lp_sub));
+
+       if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
+               if (!lp_parm_bool(-1, "server role check", "inhibit", false)) {
+                       DBG_ERR("server role = 'active directory domain controller' not compatible with running the winbindd binary. \n");
+                       DEBUGADD(0, ("You should start 'samba' instead, and it will control starting the internal AD DC winbindd implementation, which is not the same as this one\n"));
+                       exit(1);
+               }
+               /* Main 'samba' daemon will notify */
+               daemon_sd_notifications(false);
+       }
+
+       if (lp_security() == SEC_ADS) {
+               const char *realm = lp_realm();
+               const char *workgroup = lp_workgroup();
+
+               if (workgroup == NULL || strlen(workgroup) == 0) {
+                       DBG_ERR("For 'secuirity = ADS' mode, the 'workgroup' "
+                               "parameter is required to be set!\n");
+                       exit(1);
+               }
+
+               if (realm == NULL || strlen(realm) == 0) {
+                       DBG_ERR("For 'secuirity = ADS' mode, the 'realm' "
+                               "parameter is required to be set!\n");
+                       exit(1);
+               }
+       }
+
+       winbindd_socket_dir_len = strlen(lp_winbindd_socket_directory());
+       if (winbindd_socket_dir_len > 0) {
+               size_t winbindd_socket_len =
+                       winbindd_socket_dir_len + 1 +
+                       strlen(WINBINDD_SOCKET_NAME);
+               struct sockaddr_un un = {
+                       .sun_family = AF_UNIX,
+               };
+               size_t sun_path_len = sizeof(un.sun_path);
+
+               if (winbindd_socket_len >= sun_path_len) {
+                       DBG_ERR("The winbind socket path [%s/%s] is too long "
+                               "(%zu >= %zu)\n",
+                               lp_winbindd_socket_directory(),
+                               WINBINDD_SOCKET_NAME,
+                               winbindd_socket_len,
+                               sun_path_len);
+                       exit(1);
+               }
+       } else {
+               DBG_ERR("'winbindd_socket_directory' parameter is empty\n");
+               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 the winbindd binary. \n"));
-               DEBUGADD(0, ("You should start 'samba' instead, and it will control starting the internal AD DC winbindd implementation, which is not the same as this one\n"));
+       winbindd_priv_socket_dir = get_winbind_priv_pipe_dir();
+       winbindd_priv_socket_dir_len = strlen(winbindd_priv_socket_dir);
+       if (winbindd_priv_socket_dir_len > 0) {
+               size_t winbindd_priv_socket_len =
+                       winbindd_priv_socket_dir_len + 1 +
+                       strlen(WINBINDD_SOCKET_NAME);
+               struct sockaddr_un un = {
+                       .sun_family = AF_UNIX,
+               };
+               size_t sun_path_len = sizeof(un.sun_path);
+
+               if (winbindd_priv_socket_len >= sun_path_len) {
+                       DBG_ERR("The winbind privileged socket path [%s/%s] is too long "
+                               "(%zu >= %zu)\n",
+                               winbindd_priv_socket_dir,
+                               WINBINDD_SOCKET_NAME,
+                               winbindd_priv_socket_len,
+                               sun_path_len);
+                       exit(1);
+               }
+       } else {
+               DBG_ERR("'winbindd_priv_socket_directory' parameter is empty\n");
                exit(1);
        }
+       TALLOC_FREE(winbindd_priv_socket_dir);
 
        if (!cluster_probe_ok()) {
                exit(1);
@@ -1703,11 +1535,11 @@ int main(int argc, const char **argv)
 
        /* Initialise messaging system */
 
-       if (server_messaging_context() == NULL) {
+       if (global_messaging_context() == NULL) {
                exit(1);
        }
 
-       if (!reload_services_file(NULL)) {
+       if (!winbindd_reload_services_file(NULL)) {
                DEBUG(0, ("error opening config file\n"));
                exit(1);
        }
@@ -1745,11 +1577,6 @@ int main(int argc, const char **argv)
                exit(1);
        }
 
-       /* Setup names. */
-
-       if (!init_names())
-               exit(1);
-
        load_interfaces();
 
        if (!secrets_init()) {
@@ -1776,18 +1603,26 @@ int main(int argc, const char **argv)
        BlockSignals(False, SIGHUP);
        BlockSignals(False, SIGCHLD);
 
-       if (!interactive)
-               become_daemon(Fork, no_process_group, log_stdout);
+       if (!interactive) {
+               become_daemon(cmdline_daemon_cfg->fork,
+                             cmdline_daemon_cfg->no_process_group,
+                             log_stdout);
+       } else {
+               daemon_status("winbindd", "Starting process ...");
+       }
 
        pidfile_create(lp_pid_directory(), "winbindd");
 
-#if HAVE_SETPGID
+#ifdef HAVE_SETPGID
        /*
         * If we're interactive we want to set our own process group for
         * signal management.
         */
-       if (interactive && !no_process_group)
+       if (cmdline_daemon_cfg->interactive &&
+           !cmdline_daemon_cfg->no_process_group)
+       {
                setpgid( (pid_t)0, (pid_t)0);
+       }
 #endif
 
        TimeInit();
@@ -1797,13 +1632,26 @@ int main(int argc, const char **argv)
         * winbindd-specific resources we must free yet. JRA.
         */
 
-       status = reinit_after_fork(server_messaging_context(),
-                                  server_event_context(),
-                                  false, NULL);
+       status = reinit_after_fork(global_messaging_context(),
+                                  global_event_context(),
+                                  false);
        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());
+
+       if (lp_winbind_debug_traceid()) {
+               winbind_debug_traceid_setup(global_event_context());
+               winbind_debug_call_depth_setup(debug_call_depth_addr());
+               tevent_thread_call_depth_set_callback(
+                       debuglevel_get() > 1 ? winbind_call_flow : NULL,
+                       NULL);
+       }
+       ok = initialize_password_db(true, global_event_context());
+       if (!ok) {
+               exit_daemon("Failed to initialize passdb backend! "
+                           "Check the 'passdb backend' variable in your "
+                           "smb.conf file.", EINVAL);
+       }
 
        /*
         * Do not initialize the parent-child-pipe before becoming
@@ -1815,9 +1663,10 @@ int main(int argc, const char **argv)
                exit_daemon(nt_errstr(status), map_errno_from_nt_status(status));
        }
 
-       winbindd_register_handlers(server_messaging_context(), !Fork);
+       winbindd_register_handlers(global_messaging_context(),
+                                  !cmdline_daemon_cfg->fork);
 
-       if (!messaging_parent_dgm_cleanup_init(server_messaging_context())) {
+       if (!messaging_parent_dgm_cleanup_init(global_messaging_context())) {
                exit(1);
        }
 
@@ -1826,11 +1675,34 @@ int main(int argc, const char **argv)
                exit_daemon("Winbindd failed to setup system user info", map_errno_from_nt_status(status));
        }
 
-       rpc_lsarpc_init(NULL);
-       rpc_samr_init(NULL);
+       DBG_INFO("Registering DCE/RPC endpoint servers\n");
+
+       ep_server = winbind_get_ep_server();
+       if (ep_server == NULL) {
+               DBG_ERR("Failed to get 'winbind' endpoint server\n");
+               exit(1);
+       }
+       status = dcerpc_register_ep_server(ep_server);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_ERR("Failed to register 'winbind' endpoint "
+                       "server: %s\n", nt_errstr(status));
+               exit(1);
+       }
+
+       dce_ctx = global_dcesrv_context();
+
+       DBG_INFO("Initializing DCE/RPC registered endpoint servers\n");
+
+       /* Init all registered ep servers */
+       status = dcesrv_init_registered_ep_servers(dce_ctx);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_ERR("Failed to init DCE/RPC endpoint servers: %s\n",
+                       nt_errstr(status));
+               exit(1);
+       }
 
-       winbindd_init_addrchange(NULL, server_event_context(),
-                                server_messaging_context());
+       winbindd_init_addrchange(NULL, global_event_context(),
+                                global_messaging_context());
 
        /* setup listen sockets */
 
@@ -1852,7 +1724,7 @@ int main(int argc, const char **argv)
        while (1) {
                frame = talloc_stackframe();
 
-               if (tevent_loop_once(server_event_context()) == -1) {
+               if (tevent_loop_once(global_event_context()) == -1) {
                        DEBUG(1, ("tevent_loop_once() failed: %s\n",
                                  strerror(errno)));
                        return 1;