winbind: enable "debug traceid" in main winbindd
[samba.git] / source3 / winbindd / winbindd.c
index 406aaaf4ecbb6c556662df370cb2215731b26f09..710df3c74d5b251ad0258c2467d1011a1d7dee56 100644 (file)
@@ -51,6 +51,8 @@
 #include "lib/gencache.h"
 #include "rpc_server/rpc_config.h"
 #include "lib/global_contexts.h"
+#include "source3/lib/substitute.h"
+#include "winbindd_traceid.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 = global_messaging_context();
-       if (msg_ctx == NULL) {
-               smb_panic("global_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, global_event_context());
-       talloc_unlink(NULL, lp_ctx);
-
-       if (msg == NULL) {
-               smb_panic("Could not init winbindd's messaging context.\n");
-       }
-       return msg;
-}
-
 /* Reload configuration */
 
-bool winbindd_reload_services_file(const char *lfile)
-{
-       const struct loadparm_substitution *lp_sub =
-               loadparm_s3_global_substitution();
-       bool ret;
-
-       if (lp_loaded()) {
-               char *fname = lp_next_configfile(talloc_tos(), lp_sub);
-
-               if (file_exist(fname) && !strcsequal(fname,get_dyn_CONFIGFILE())) {
-                       set_dyn_CONFIGFILE(fname);
-               }
-               TALLOC_FREE(fname);
-       }
-
-       reopen_logs();
-       ret = lp_load_global(get_dyn_CONFIGFILE());
-
-       /* if this is a child, restore the logfile to the special
-          name - <domain>, idmap, etc. */
-       if (lfile && *lfile) {
-               lp_set_logfile(lfile);
-       }
-
-       reopen_logs();
-       load_interfaces();
-       winbindd_setup_max_fds();
-
-       return(ret);
-}
 
 
 static void winbindd_status(void)
@@ -155,101 +88,6 @@ static void winbindd_status(void)
        }
 }
 
-/* Flush client cache */
-
-void winbindd_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();
-
-       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
  */
@@ -266,56 +104,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(global_event_context(), bool);
-       if (!is_parent) {
-               return false;
+               winbindd_terminate(*is_parent);
        }
-
-       *is_parent = parent;
-
-       se = tevent_add_signal(global_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(global_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(global_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;
-       }
-
-       return true;
 }
 
 bool winbindd_setup_stdin_handler(bool parent, bool foreground)
@@ -353,45 +143,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();
-       winbindd_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(global_event_context(),
-                                    lfile);
-               if (!file) {
-                       return false;
-               }
-       }
-
-       se = tevent_add_signal(global_event_context(),
-                              global_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,
@@ -457,7 +208,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);
 }
 
 
@@ -671,7 +422,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) {
@@ -1259,40 +1021,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(talloc_tos(), 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;
@@ -1368,21 +1096,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))
@@ -1486,6 +1206,16 @@ static void winbindd_register_handlers(struct messaging_context *msg_ctx,
                }
        }
 
+       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)) {
@@ -1582,49 +1312,10 @@ 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
-       };
+       struct samba_cmdline_daemon_cfg *cmdline_daemon_cfg = NULL;
        struct poptOption long_options[] = {
                POPT_AUTOHELP
-               {
-                       .longName   = "foreground",
-                       .shortName  = 'F',
-                       .argInfo    = POPT_ARG_NONE,
-                       .arg        = NULL,
-                       .val        = OPT_FORK,
-                       .descrip    = "Daemon in foreground mode",
-               },
-               {
-                       .longName   = "no-process-group",
-                       .shortName  = 0,
-                       .argInfo    = POPT_ARG_NONE,
-                       .arg        = NULL,
-                       .val        = OPT_NO_PROCESS_GROUP,
-                       .descrip    = "Don't create a new process group",
-               },
-               {
-                       .longName   = "daemon",
-                       .shortName  = 'D',
-                       .argInfo    = POPT_ARG_NONE,
-                       .arg        = NULL,
-                       .val        = OPT_DAEMON,
-                       .descrip    = "Become a daemon (default)",
-               },
-               {
-                       .longName   = "interactive",
-                       .shortName  = 'i',
-                       .argInfo    = POPT_ARG_NONE,
-                       .arg        = NULL,
-                       .val        = 'i',
-                       .descrip    = "Interactive mode",
-               },
                {
                        .longName   = "no-caching",
                        .shortName  = 'n',
@@ -1634,6 +1325,7 @@ int main(int argc, const char **argv)
                        .descrip    = "Disable caching",
                },
                POPT_COMMON_SAMBA
+               POPT_COMMON_DAEMON
                POPT_COMMON_VERSION
                POPT_TABLEEND
        };
@@ -1646,6 +1338,9 @@ int main(int argc, const char **argv)
        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);
 
@@ -1678,6 +1373,8 @@ int main(int argc, const char **argv)
                exit(1);
        }
 
+       cmdline_daemon_cfg = samba_cmdline_get_daemon_cfg();
+
        pc = samba_popt_get_context(getprogname(), argc, argv, long_options, 0);
        if (pc == NULL) {
                DBG_ERR("Failed to setup popt parser!\n");
@@ -1687,21 +1384,8 @@ int main(int argc, const char **argv)
 
        while ((opt = poptGetNextOpt(pc)) != -1) {
                switch (opt) {
-                       /* Don't become a daemon */
-               case OPT_DAEMON:
-                       is_daemon = True;
-                       break;
-               case 'i':
-                       interactive = True;
-                       break;
-                case OPT_FORK:
-                       Fork = false;
-                       break;
-               case OPT_NO_PROCESS_GROUP:
-                       no_process_group = true;
-                       break;
                case 'n':
-                       opt_nocache = true;
+                       winbindd_set_use_cache(false);
                        break;
                default:
                        d_fprintf(stderr, "\nInvalid option %s: %s\n\n",
@@ -1724,7 +1408,7 @@ int main(int argc, const char **argv)
        set_remote_machine_name("winbindd", False);
 
        dump_core_setup("winbindd", lp_logfile(talloc_tos(), lp_sub));
-       if (is_daemon && interactive) {
+       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);
@@ -1732,34 +1416,27 @@ int main(int argc, const char **argv)
        }
 
        log_stdout = (debug_get_log_type() == DEBUG_STDOUT);
-       if (interactive) {
-               Fork = true;
+       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 && Fork) {
+       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()));
@@ -1798,6 +1475,56 @@ int main(int argc, const char **argv)
                }
        }
 
+       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);
+       }
+
+       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 priviliged 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);
        }
@@ -1873,7 +1600,9 @@ int main(int argc, const char **argv)
        BlockSignals(False, SIGCHLD);
 
        if (!interactive) {
-               become_daemon(Fork, no_process_group, log_stdout);
+               become_daemon(cmdline_daemon_cfg->fork,
+                             cmdline_daemon_cfg->no_process_group,
+                             log_stdout);
        } else {
                daemon_status("winbindd", "Starting process ...");
        }
@@ -1885,8 +1614,11 @@ int main(int argc, const char **argv)
         * 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();
@@ -1903,6 +1635,9 @@ int main(int argc, const char **argv)
                exit_daemon("Winbindd reinit_after_fork() failed", map_errno_from_nt_status(status));
        }
 
+       if (lp_winbind_debug_traceid()) {
+               winbind_debug_traceid_setup(global_event_context());
+       }
        ok = initialize_password_db(true, global_event_context());
        if (!ok) {
                exit_daemon("Failed to initialize passdb backend! "
@@ -1920,7 +1655,8 @@ int main(int argc, const char **argv)
                exit_daemon(nt_errstr(status), map_errno_from_nt_status(status));
        }
 
-       winbindd_register_handlers(global_messaging_context(), !Fork);
+       winbindd_register_handlers(global_messaging_context(),
+                                  !cmdline_daemon_cfg->fork);
 
        if (!messaging_parent_dgm_cleanup_init(global_messaging_context())) {
                exit(1);
@@ -1933,34 +1669,6 @@ int main(int argc, const char **argv)
 
        DBG_INFO("Registering DCE/RPC endpoint servers\n");
 
-       /* Register the endpoint server to dispatch calls locally through
-        * the legacy api_struct */
-       ep_server = lsarpc_get_ep_server();
-       if (ep_server == NULL) {
-               DBG_ERR("Failed to get 'lsarpc' endpoint server\n");
-               exit(1);
-       }
-       status = dcerpc_register_ep_server(ep_server);
-       if (!NT_STATUS_IS_OK(status)) {
-               DBG_ERR("Failed to register 'lsarpc' endpoint "
-                       "server: %s\n", nt_errstr(status));
-               exit(1);
-       }
-
-       /* Register the endpoint server to dispatch calls locally through
-        * the legacy api_struct */
-       ep_server = samr_get_ep_server();
-       if (ep_server == NULL) {
-               DBG_ERR("Failed to get 'samr' endpoint server\n");
-               exit(1);
-       }
-       status = dcerpc_register_ep_server(ep_server);
-       if (!NT_STATUS_IS_OK(status)) {
-               DBG_ERR("Failed to register 'samr' endpoint "
-                       "server: %s\n", nt_errstr(status));
-               exit(1);
-       }
-
        ep_server = winbind_get_ep_server();
        if (ep_server == NULL) {
                DBG_ERR("Failed to get 'winbind' endpoint server\n");