smbd: Remove source3/smbd/statcache.c
[samba.git] / source3 / smbd / server.c
index 20f34bc401bb8af171eefc5101676afbaada0cc9..6bdaca7a0a410286be5ac3cc9aa335c1eee9b77c 100644 (file)
 #include "includes.h"
 #include "system/filesys.h"
 #include "lib/util/server_id.h"
-#include "popt_common.h"
+#include "lib/util/close_low_fd.h"
+#include "lib/cmdline/cmdline.h"
+#include "locking/share_mode_lock.h"
 #include "smbd/smbd.h"
 #include "smbd/globals.h"
+#include "smbd/smbXsrv_open.h"
 #include "registry/reg_init_full.h"
 #include "libcli/auth/schannel.h"
 #include "secrets.h"
 #include "../lib/util/memcache.h"
 #include "ctdbd_conn.h"
+#include "lib/util/util_process.h"
 #include "util_cluster.h"
 #include "printing/queue_process.h"
-#include "rpc_server/rpc_service_setup.h"
 #include "rpc_server/rpc_config.h"
 #include "passdb.h"
 #include "auth.h"
 #include "lib/util/sys_rw.h"
 #include "cleanupdb.h"
 #include "g_lock.h"
-#include "rpc_server/epmd.h"
-#include "rpc_server/lsasd.h"
-#include "rpc_server/fssd.h"
-#include "rpc_server/mdssd.h"
+#include "lib/global_contexts.h"
+#include "source3/lib/substitute.h"
 
 #ifdef CLUSTER_SUPPORT
 #include "ctdb_protocol.h"
@@ -100,41 +101,27 @@ struct smbd_child_pid {
  What to do when smb.conf is updated.
  ********************************************************************/
 
+static NTSTATUS messaging_send_to_children(struct messaging_context *msg_ctx,
+                                          uint32_t msg_type, DATA_BLOB* data);
+
 static void smbd_parent_conf_updated(struct messaging_context *msg,
                                     void *private_data,
                                     uint32_t msg_type,
                                     struct server_id server_id,
                                     DATA_BLOB *data)
 {
-       struct tevent_context *ev_ctx =
-               talloc_get_type_abort(private_data, struct tevent_context);
        bool ok;
 
        DEBUG(10,("smbd_parent_conf_updated: Got message saying smb.conf was "
                  "updated. Reloading.\n"));
        change_to_root_user();
        reload_services(NULL, NULL, false);
-       printing_subsystem_update(ev_ctx, msg, false);
 
        ok = reinit_guest_session_info(NULL);
        if (!ok) {
                DBG_ERR("Failed to reinit guest info\n");
        }
-}
-
-/*******************************************************************
- Delete a statcache entry.
- ********************************************************************/
-
-static void smb_stat_cache_delete(struct messaging_context *msg,
-                                 void *private_data,
-                                 uint32_t msg_tnype,
-                                 struct server_id server_id,
-                                 DATA_BLOB *data)
-{
-       const char *name = (const char *)data->data;
-       DEBUG(10,("smb_stat_cache_delete: delete name %s\n", name));
-       stat_cache_delete(name);
+       messaging_send_to_children(msg, MSG_SMB_CONF_UPDATED, NULL);
 }
 
 /****************************************************************************
@@ -394,6 +381,7 @@ static void notifyd_sig_hup_handler(struct tevent_context *ev,
 {
        DBG_NOTICE("notifyd: Reloading services after SIGHUP\n");
        reload_services(NULL, NULL, false);
+       reopen_logs();
 }
 
 static bool smbd_notifyd_init(struct messaging_context *msg, bool interactive,
@@ -401,10 +389,10 @@ static bool smbd_notifyd_init(struct messaging_context *msg, bool interactive,
 {
        struct tevent_context *ev = messaging_tevent_context(msg);
        struct tevent_req *req;
+       struct tevent_signal *se = NULL;
        pid_t pid;
        NTSTATUS status;
        bool ok;
-       struct tevent_signal *se;
 
        if (interactive) {
                req = notifyd_req(msg, ev);
@@ -419,20 +407,24 @@ static bool smbd_notifyd_init(struct messaging_context *msg, bool interactive,
        }
 
        if (pid != 0) {
-               if (am_parent != 0) {
+               if (am_parent != NULL) {
                        add_child_pid(am_parent, pid);
                }
                *ppid = pid_to_procid(pid);
                return true;
        }
 
-       status = smbd_reinit_after_fork(msg, ev, true, "smbd-notifyd");
+       status = smbd_reinit_after_fork(msg, ev, true);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("%s: reinit_after_fork failed: %s\n",
                          __func__, nt_errstr(status)));
                exit(1);
        }
 
+       process_set_title("smbd-notifyd", "notifyd");
+
+       reopen_logs();
+
        /* Set up sighup handler for notifyd */
        se = tevent_add_signal(ev,
                               ev,
@@ -559,6 +551,17 @@ static void notifyd_started(struct tevent_req *req)
        }
 }
 
+static void cleanupd_sig_hup_handler(struct tevent_context *ev,
+                                    struct tevent_signal *se,
+                                    int signum,
+                                    int count,
+                                    void *siginfo,
+                                    void *pvt)
+{
+       DBG_NOTICE("cleanupd: Reloading services after SIGHUP\n");
+       reopen_logs();
+}
+
 static void cleanupd_stopped(struct tevent_req *req);
 
 static bool cleanupd_init(struct messaging_context *msg, bool interactive,
@@ -566,6 +569,7 @@ static bool cleanupd_init(struct messaging_context *msg, bool interactive,
 {
        struct tevent_context *ev = messaging_tevent_context(msg);
        struct server_id parent_id = messaging_server_id(msg);
+       struct tevent_signal *se = NULL;
        struct tevent_req *req;
        pid_t pid;
        NTSTATUS status;
@@ -626,7 +630,7 @@ static bool cleanupd_init(struct messaging_context *msg, bool interactive,
 
        close(up_pipe[0]);
 
-       status = smbd_reinit_after_fork(msg, ev, true, "cleanupd");
+       status = smbd_reinit_after_fork(msg, ev, true);
        if (!NT_STATUS_IS_OK(status)) {
                DBG_WARNING("reinit_after_fork failed: %s\n",
                            nt_errstr(status));
@@ -636,6 +640,19 @@ static bool cleanupd_init(struct messaging_context *msg, bool interactive,
                exit(1);
        }
 
+       process_set_title("smbd-cleanupd", "cleanupd");
+
+       se = tevent_add_signal(ev,
+                              ev,
+                              SIGHUP,
+                              0,
+                              cleanupd_sig_hup_handler,
+                              NULL);
+       if (se == NULL) {
+               DBG_ERR("Could not add SIGHUP handler\n");
+               exit(1);
+       }
+
        req = smbd_cleanupd_send(msg, ev, msg, parent_id.pid);
        if (req == NULL) {
                DBG_WARNING("smbd_cleanupd_send failed\n");
@@ -957,7 +974,7 @@ static void smbd_accept_connection(struct tevent_context *ev,
        smb_set_close_on_exec(fd);
 
        if (s->parent->interactive) {
-               reinit_after_fork(msg_ctx, ev, true, NULL);
+               reinit_after_fork(msg_ctx, ev, true);
                smbd_process(ev, msg_ctx, fd, true);
                exit_server_cleanly("end of interactive mode");
                return;
@@ -970,6 +987,7 @@ static void smbd_accept_connection(struct tevent_context *ev,
 
        pid = fork();
        if (pid == 0) {
+               char addrstr[INET6_ADDRSTRLEN];
                NTSTATUS status = NT_STATUS_OK;
 
                /*
@@ -983,7 +1001,7 @@ static void smbd_accept_connection(struct tevent_context *ev,
                 * them, counting worker smbds. */
                CatchChild();
 
-               status = smbd_reinit_after_fork(msg_ctx, ev, true, NULL);
+               status = smbd_reinit_after_fork(msg_ctx, ev, true);
                if (!NT_STATUS_IS_OK(status)) {
                        if (NT_STATUS_EQUAL(status,
                                            NT_STATUS_TOO_MANY_OPENED_FILES)) {
@@ -1007,6 +1025,9 @@ static void smbd_accept_connection(struct tevent_context *ev,
                        smb_panic("reinit_after_fork() failed");
                }
 
+               print_sockaddr(addrstr, sizeof(addrstr), &addr);
+               process_set_title("smbd[%s]", "client [%s]", addrstr);
+
                smbd_process(ev, msg_ctx, fd, false);
         exit:
                exit_server_cleanly("end of child");
@@ -1040,7 +1061,7 @@ static void smbd_accept_connection(struct tevent_context *ev,
         * writes only two messages for each child
         * started/finished. But each child writes,
         * say, 50 messages also in logserver.smb,
-        * begining with the debug_count of the
+        * beginning with the debug_count of the
         * parent, before the child opens its own log
         * file logserver.client. In a worst case
         * scenario the size of logserver.smb would be
@@ -1063,14 +1084,11 @@ static bool smbd_open_one_socket(struct smbd_parent_context *parent,
        }
 
        s->parent = parent;
-       s->fd = open_socket_in(SOCK_STREAM,
-                              port,
-                              parent->sockets == NULL ? 0 : 2,
-                              ifss,
-                              true);
-       if (s->fd == -1) {
-               DEBUG(0,("smbd_open_one_socket: open_socket_in: "
-                       "%s\n", strerror(errno)));
+
+       s->fd = open_socket_in(SOCK_STREAM, ifss, port, true);
+       if (s->fd < 0) {
+               int err = -(s->fd);
+               DBG_ERR("open_socket_in failed: %s\n", strerror(err));
                TALLOC_FREE(s);
                /*
                 * We ignore an error here, as we've done before
@@ -1247,11 +1265,11 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
        messaging_register(msg_ctx, NULL, MSG_SHUTDOWN, msg_exit_server);
        messaging_register(msg_ctx, ev_ctx, MSG_SMB_CONF_UPDATED,
                           smbd_parent_conf_updated);
-       messaging_register(msg_ctx, NULL, MSG_SMB_STAT_CACHE_DELETE,
-                          smb_stat_cache_delete);
        messaging_register(msg_ctx, NULL, MSG_DEBUG, smbd_msg_debug);
        messaging_register(msg_ctx, NULL, MSG_SMB_FORCE_TDIS,
                           smb_parent_send_to_children);
+       messaging_register(msg_ctx, NULL, MSG_SMB_FORCE_TDIS_DENIED,
+                          smb_parent_send_to_children);
        messaging_register(msg_ctx, NULL, MSG_SMB_KILL_CLIENT_IP,
                           smb_parent_send_to_children);
        messaging_register(msg_ctx, NULL, MSG_SMB_TELL_NUM_CHILDREN,
@@ -1375,9 +1393,6 @@ static bool init_structs(void )
         * set from the config file.
         */
 
-       if (!init_names())
-               return False;
-
        if (!secrets_init())
                return False;
 
@@ -1401,15 +1416,9 @@ static void smbd_parent_sig_hup_handler(struct tevent_context *ev,
                                        void *siginfo,
                                        void *private_data)
 {
-       struct smbd_parent_context *parent =
-               talloc_get_type_abort(private_data,
-               struct smbd_parent_context);
-
        change_to_root_user();
        DEBUG(1,("parent: Reloading services after SIGHUP\n"));
        reload_services(NULL, NULL, false);
-
-       printing_subsystem_update(parent->ev_ctx, parent->msg_ctx, true);
 }
 
 struct smbd_claim_version_state {
@@ -1419,7 +1428,7 @@ struct smbd_claim_version_state {
 
 static void smbd_claim_version_parser(struct server_id exclusive,
                                      size_t num_shared,
-                                     struct server_id *shared,
+                                     const struct server_id *shared,
                                      const uint8_t *data,
                                      size_t datalen,
                                      void *private_data)
@@ -1443,6 +1452,7 @@ static NTSTATUS smbd_claim_version(struct messaging_context *msg,
                                   const char *version)
 {
        const char *name = "samba_version_string";
+       const TDB_DATA key = string_term_tdb_data(name);
        struct smbd_claim_version_state state;
        struct g_lock_ctx *ctx;
        NTSTATUS status;
@@ -1453,8 +1463,12 @@ static NTSTATUS smbd_claim_version(struct messaging_context *msg,
                return NT_STATUS_UNSUCCESSFUL;
        }
 
-       status = g_lock_lock(ctx, string_term_tdb_data(name), G_LOCK_READ,
-                            (struct timeval) { .tv_sec = 60 });
+       status = g_lock_lock(ctx,
+                            key,
+                            G_LOCK_READ,
+                            (struct timeval) { .tv_sec = 60 },
+                            NULL,
+                            NULL);
        if (!NT_STATUS_IS_OK(status)) {
                DBG_WARNING("g_lock_lock(G_LOCK_READ) failed: %s\n",
                            nt_errstr(status));
@@ -1464,12 +1478,11 @@ static NTSTATUS smbd_claim_version(struct messaging_context *msg,
 
        state = (struct smbd_claim_version_state) { .mem_ctx = ctx };
 
-       status = g_lock_dump(ctx, string_term_tdb_data(name),
-                            smbd_claim_version_parser, &state);
+       status = g_lock_dump(ctx, key, smbd_claim_version_parser, &state);
        if (!NT_STATUS_IS_OK(status) &&
            !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
                DBG_ERR("Could not read samba_version_string\n");
-               g_lock_unlock(ctx, string_term_tdb_data(name));
+               g_lock_unlock(ctx, key);
                TALLOC_FREE(ctx);
                return status;
        }
@@ -1483,8 +1496,12 @@ static NTSTATUS smbd_claim_version(struct messaging_context *msg,
                return NT_STATUS_OK;
        }
 
-       status = g_lock_lock(ctx, string_term_tdb_data(name), G_LOCK_WRITE,
-                            (struct timeval) { .tv_sec = 60 });
+       status = g_lock_lock(ctx,
+                            key,
+                            G_LOCK_UPGRADE,
+                            (struct timeval) { .tv_sec = 60 },
+                            NULL,
+                            NULL);
        if (!NT_STATUS_IS_OK(status)) {
                DBG_WARNING("g_lock_lock(G_LOCK_WRITE) failed: %s\n",
                            nt_errstr(status));
@@ -1494,9 +1511,8 @@ static NTSTATUS smbd_claim_version(struct messaging_context *msg,
                return NT_STATUS_SXS_VERSION_CONFLICT;
        }
 
-       status = g_lock_write_data(ctx, string_term_tdb_data(name),
-                                  (const uint8_t *)version,
-                                  strlen(version)+1);
+       status = g_lock_write_data(
+               ctx, key, (const uint8_t *)version, strlen(version)+1);
        if (!NT_STATUS_IS_OK(status)) {
                DBG_WARNING("g_lock_write_data failed: %s\n",
                            nt_errstr(status));
@@ -1504,8 +1520,12 @@ static NTSTATUS smbd_claim_version(struct messaging_context *msg,
                return status;
        }
 
-       status = g_lock_lock(ctx, string_term_tdb_data(name), G_LOCK_READ,
-                            (struct timeval) { .tv_sec = 60 });
+       status = g_lock_lock(ctx,
+                            key,
+                            G_LOCK_DOWNGRADE,
+                            (struct timeval) { .tv_sec = 60 },
+                            NULL,
+                            NULL);
        if (!NT_STATUS_IS_OK(status)) {
                DBG_WARNING("g_lock_lock(G_LOCK_READ) failed: %s\n",
                            nt_errstr(status));
@@ -1532,66 +1552,15 @@ extern void build_options(bool screen);
  int main(int argc,const char *argv[])
 {
        /* shall I run as a daemon */
-       bool is_daemon = false;
-       bool interactive = false;
-       bool Fork = true;
-       bool no_process_group = false;
+       struct samba_cmdline_daemon_cfg *cmdline_daemon_cfg = NULL;
        bool log_stdout = false;
        char *ports = NULL;
        char *profile_level = NULL;
        int opt;
        poptContext pc;
-       bool print_build_options = False;
        struct server_id main_server_id = {0};
-        enum {
-               OPT_DAEMON = 1000,
-               OPT_INTERACTIVE,
-               OPT_FORK,
-               OPT_NO_PROCESS_GROUP,
-               OPT_LOG_STDOUT
-       };
        struct poptOption long_options[] = {
                POPT_AUTOHELP
-               {
-                       .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        = OPT_INTERACTIVE,
-                       .descrip    = "Run interactive (not a daemon) and log to stdout",
-               },
-               {
-                       .longName   = "foreground",
-                       .shortName  = 'F',
-                       .argInfo    = POPT_ARG_NONE,
-                       .arg        = NULL,
-                       .val        = OPT_FORK,
-                       .descrip    = "Run daemon in foreground (for daemontools, etc.)",
-               },
-               {
-                       .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   = "log-stdout",
-                       .shortName  = 'S',
-                       .argInfo    = POPT_ARG_NONE,
-                       .arg        = NULL,
-                       .val        = OPT_LOG_STDOUT,
-                       .descrip    = "Log to stdout" ,
-               },
                {
                        .longName   = "build-options",
                        .shortName  = 'b',
@@ -1617,6 +1586,8 @@ extern void build_options(bool screen);
                        .descrip    = "Set profiling level","PROFILE_LEVEL",
                },
                POPT_COMMON_SAMBA
+               POPT_COMMON_DAEMON
+               POPT_COMMON_VERSION
                POPT_TABLEEND
        };
        struct smbd_parent_context *parent = NULL;
@@ -1628,9 +1599,10 @@ extern void build_options(bool screen);
        struct tevent_signal *se;
        int profiling_level;
        char *np_dir = NULL;
+       const struct loadparm_substitution *lp_sub =
+               loadparm_s3_global_substitution();
        static const struct smbd_shim smbd_shim_fns =
        {
-               .send_stat_cache_delete_message = smbd_send_stat_cache_delete_message,
                .change_to_root_user = smbd_change_to_root_user,
                .become_authenticated_pipe_user = smbd_become_authenticated_pipe_user,
                .unbecome_authenticated_pipe_user = smbd_unbecome_authenticated_pipe_user,
@@ -1644,6 +1616,9 @@ extern void build_options(bool screen);
                .exit_server = smbd_exit_server,
                .exit_server_cleanly = smbd_exit_server_cleanly,
        };
+       bool ok;
+
+       setproctitle_init(argc, discard_const(argv), environ);
 
        /*
         * Do this before any other talloc operation
@@ -1651,8 +1626,6 @@ extern void build_options(bool screen);
        talloc_enable_null_tracking();
        frame = talloc_stackframe();
 
-       setup_logging(argv[0], DEBUG_DEFAULT_STDOUT);
-
        smb_init_locale();
 
        set_smbd_shim(&smbd_shim_fns);
@@ -1665,26 +1638,31 @@ extern void build_options(bool screen);
        set_auth_parameters(argc,argv);
 #endif
 
-       pc = poptGetContext("smbd", argc, argv, long_options, 0);
+       ok = samba_cmdline_init(frame,
+                               SAMBA_CMDLINE_CONFIG_SERVER,
+                               true /* require_smbconf */);
+       if (!ok) {
+               DBG_ERR("Failed to setup cmdline parser!\n");
+               exit(ENOMEM);
+       }
+
+       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 get popt context!\n");
+               exit(ENOMEM);
+       }
+
        while((opt = poptGetNextOpt(pc)) != -1) {
                switch (opt)  {
-               case OPT_DAEMON:
-                       is_daemon = true;
-                       break;
-               case OPT_INTERACTIVE:
-                       interactive = true;
-                       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 'b':
-                       print_build_options = True;
+                       build_options(true); /* Display output to screen as well as debug */
+                       exit(0);
                        break;
                default:
                        d_fprintf(stderr, "\nInvalid option %s: %s\n\n",
@@ -1695,20 +1673,10 @@ extern void build_options(bool screen);
        }
        poptFreeContext(pc);
 
-       if (interactive) {
-               Fork = False;
-               log_stdout = True;
-       }
+       log_stdout = (debug_get_log_type() == DEBUG_STDOUT);
 
-       if (log_stdout) {
-               setup_logging(argv[0], DEBUG_STDOUT);
-       } else {
-               setup_logging(argv[0], DEBUG_FILE);
-       }
-
-       if (print_build_options) {
-               build_options(True); /* Display output to screen as well as debug */
-               exit(0);
+        if (cmdline_daemon_cfg->interactive) {
+               log_stdout = True;
        }
 
 #ifdef HAVE_SETLUID
@@ -1718,11 +1686,11 @@ extern void build_options(bool screen);
 
        set_remote_machine_name("smbd", False);
 
-       if (interactive && (DEBUGLEVEL >= 9)) {
+       if (cmdline_daemon_cfg->interactive && (DEBUGLEVEL >= 9)) {
                talloc_enable_leak_report();
        }
 
-       if (log_stdout && Fork) {
+       if (log_stdout && cmdline_daemon_cfg->fork) {
                DEBUG(0,("ERROR: Can't log to stdout (-S) unless daemon is in foreground (-F) or interactive (-i)\n"));
                exit(1);
        }
@@ -1740,8 +1708,7 @@ extern void build_options(bool screen);
        gain_root_privilege();
        gain_root_group_privilege();
 
-       fault_setup();
-       dump_core_setup("smbd", lp_logfile(talloc_tos()));
+       dump_core_setup("smbd", lp_logfile(talloc_tos(), lp_sub));
 
        /* we are never interested in SIGPIPE */
        BlockSignals(True,SIGPIPE);
@@ -1756,8 +1723,11 @@ extern void build_options(bool screen);
        BlockSignals(True,SIGUSR2);
 #endif
 
-       /* POSIX demands that signals are inherited. If the invoking process has
-        * these signals masked, we will have problems, as we won't recieve them. */
+       /*
+        * POSIX demands that signals are inherited. If the invoking
+        * process has these signals masked, we will have problems, as
+        * we won't receive them.
+        */
        BlockSignals(False, SIGHUP);
        BlockSignals(False, SIGUSR1);
        BlockSignals(False, SIGTERM);
@@ -1779,7 +1749,7 @@ extern void build_options(bool screen);
        DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n",
                 (int)getuid(),(int)getgid(),(int)geteuid(),(int)getegid()));
 
-       /* Output the build options to the debug log */ 
+       /* Output the build options to the debug log */
        build_options(False);
 
        if (sizeof(uint16_t) < 2 || sizeof(uint32_t) < 4) {
@@ -1787,11 +1757,6 @@ extern void build_options(bool screen);
                exit(1);
        }
 
-       if (!lp_load_initial_only(get_dyn_CONFIGFILE())) {
-               DEBUG(0, ("error opening config file '%s'\n", get_dyn_CONFIGFILE()));
-               exit(1);
-       }
-
        /*
         * This calls unshare(CLONE_FS); on linux
         * in order to check if the running kernel/container
@@ -1833,11 +1798,14 @@ extern void build_options(bool screen);
                exit(1);
        }
 
-       if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC
-           && !lp_parm_bool(-1, "server role check", "inhibit", false)) {
-               DEBUG(0, ("server role = 'active directory domain controller' not compatible with running smbd standalone. \n"));
-               DEBUGADD(0, ("You should start 'samba' instead, and it will control starting smbd if required\n"));
-               exit(1);
+       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 smbd standalone. \n");
+                       DEBUGADD(0, ("You should start 'samba' instead, and it will control starting smbd if required\n"));
+                       exit(1);
+               }
+               /* Main 'samba' daemon will notify */
+               daemon_sd_notifications(false);
        }
 
        /* ...NOTE... Log files are working from this point! */
@@ -1859,23 +1827,27 @@ extern void build_options(bool screen);
        main_server_id = messaging_server_id(msg_ctx);
        set_profile_level(profiling_level, &main_server_id);
 
-       if (!is_daemon && !is_a_socket(0)) {
-               if (!interactive) {
+       if (!cmdline_daemon_cfg->daemon && !is_a_socket(0)) {
+               if (!cmdline_daemon_cfg->interactive) {
                        DEBUG(3, ("Standard input is not a socket, "
                                  "assuming -D option\n"));
                }
 
                /*
-                * Setting is_daemon here prevents us from eventually calling
+                * Setting "daemon" here prevents us from eventually calling
                 * the open_sockets_inetd()
                 */
 
-               is_daemon = True;
+               cmdline_daemon_cfg->daemon = true;
        }
 
-       if (is_daemon && !interactive) {
+       if (cmdline_daemon_cfg->daemon && !cmdline_daemon_cfg->interactive) {
                DEBUG(3, ("Becoming a daemon.\n"));
-               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("smbd", "Starting process ...");
        }
 
 #ifdef HAVE_SETPGID
@@ -1883,8 +1855,11 @@ extern void build_options(bool screen);
         * 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
 
        if (!directory_exist(lp_lock_directory()))
@@ -1893,15 +1868,15 @@ extern void build_options(bool screen);
        if (!directory_exist(lp_pid_directory()))
                mkdir(lp_pid_directory(), 0755);
 
-       if (is_daemon)
+       if (cmdline_daemon_cfg->daemon)
                pidfile_create(lp_pid_directory(), "smbd");
 
-       status = reinit_after_fork(msg_ctx, ev_ctx, false, NULL);
+       status = reinit_after_fork(msg_ctx, ev_ctx, false);
        if (!NT_STATUS_IS_OK(status)) {
                exit_daemon("reinit_after_fork() failed", map_errno_from_nt_status(status));
        }
 
-       if (!interactive) {
+       if (!cmdline_daemon_cfg->interactive) {
                /*
                 * Do not initialize the parent-child-pipe before becoming a
                 * daemon: this is used to detect a died parent in the child
@@ -1917,7 +1892,7 @@ extern void build_options(bool screen);
        if (!parent) {
                exit_server("talloc(struct smbd_parent_context) failed");
        }
-       parent->interactive = interactive;
+       parent->interactive = cmdline_daemon_cfg->interactive;
        parent->ev_ctx = ev_ctx;
        parent->msg_ctx = msg_ctx;
        am_parent = parent;
@@ -1957,7 +1932,7 @@ extern void build_options(bool screen);
                exit_daemon("smbd can not open secrets.tdb", EACCES);
        }
 
-       if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC) {
+       if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC || lp_server_role() == ROLE_IPA_DC) {
                struct loadparm_context *lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers());
                if (!open_schannel_session_store(NULL, lp_ctx)) {
                        exit_daemon("ERROR: Samba cannot open schannel store for secured NETLOGON operations.", EACCES);
@@ -1997,11 +1972,17 @@ extern void build_options(bool screen);
                exit_daemon("Samba cannot init leases", EACCES);
        }
 
-       if (!smbd_notifyd_init(msg_ctx, interactive, &parent->notifyd)) {
+       if (!smbd_notifyd_init(
+                   msg_ctx,
+                   cmdline_daemon_cfg->interactive,
+                   &parent->notifyd)) {
                exit_daemon("Samba cannot init notification", EACCES);
        }
 
-       if (!cleanupd_init(msg_ctx, interactive, &parent->cleanupd)) {
+       if (!cleanupd_init(
+                   msg_ctx,
+                   cmdline_daemon_cfg->interactive,
+                   &parent->cleanupd)) {
                exit_daemon("Samba cannot init the cleanupd", EACCES);
        }
 
@@ -2020,7 +2001,8 @@ extern void build_options(bool screen);
           after the fork on every single connection.  This is a small
           performance improvment and reduces the total number of system
           fds used. */
-       if (!share_info_db_init()) {
+       status = share_info_db_init();
+       if (!NT_STATUS_IS_OK(status)) {
                exit_daemon("ERROR: failed to load share info db.", EACCES);
        }
 
@@ -2075,59 +2057,12 @@ extern void build_options(bool screen);
                return -1;
        }
 
-       if (is_daemon && !interactive) {
-               if (rpc_epmapper_daemon() == RPC_DAEMON_FORK) {
-                       start_epmd(ev_ctx, msg_ctx);
-               }
-       }
-
-       status = dcesrv_ep_setup(ev_ctx, msg_ctx);
-       if (!NT_STATUS_IS_OK(status)) {
-               DBG_ERR("Failed to setup RPC server: %s\n", nt_errstr(status));
-               exit_daemon("Samba cannot setup ep pipe", EACCES);
-       }
-
-       if (is_daemon && !interactive) {
+       if (!cmdline_daemon_cfg->interactive) {
                daemon_ready("smbd");
        }
 
-       /* only start other daemons if we are running as a daemon
-        * -- bad things will happen if smbd is launched via inetd
-        *  and we fork a copy of ourselves here */
-       if (is_daemon && !interactive) {
-
-               if (rpc_lsasd_daemon() == RPC_DAEMON_FORK) {
-                       start_lsasd(ev_ctx, msg_ctx);
-               }
-
-               if (rpc_fss_daemon() == RPC_DAEMON_FORK) {
-                       start_fssd(ev_ctx, msg_ctx);
-               }
-
-               if (!lp__disable_spoolss() &&
-                   (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) {
-                       bool bgq = lp_parm_bool(-1, "smbd", "backgroundqueue", true);
-
-                       if (!printing_subsystem_init(ev_ctx, msg_ctx, true, bgq)) {
-                               exit_daemon("Samba failed to init printing subsystem", EACCES);
-                       }
-               }
-
-#ifdef WITH_SPOTLIGHT
-               if ((rpc_mdssvc_mode() == RPC_SERVICE_MODE_EXTERNAL) &&
-                   (rpc_mdssd_daemon() == RPC_DAEMON_FORK)) {
-                       start_mdssd(ev_ctx, msg_ctx);
-               }
-#endif
-       } else if (!lp__disable_spoolss() &&
-                  (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) {
-               if (!printing_subsystem_init(ev_ctx, msg_ctx, false, false)) {
-                       exit(1);
-               }
-       }
-
-       if (!is_daemon) {
-               int sock;
+       if (!cmdline_daemon_cfg->daemon) {
+               int ret, sock;
 
                /* inetd mode */
                TALLOC_FREE(frame);
@@ -2138,7 +2073,19 @@ extern void build_options(bool screen);
                sock = dup(0);
 
                /* close stdin, stdout (if not logging to it), but not stderr */
-               close_low_fds(true, !debug_get_output_is_stdout(), false);
+               ret = close_low_fd(0);
+               if (ret != 0) {
+                       DBG_ERR("close_low_fd(0) failed: %s\n", strerror(ret));
+                       return 1;
+               }
+               if (!debug_get_output_is_stdout()) {
+                       ret = close_low_fd(1);
+                       if (ret != 0) {
+                               DBG_ERR("close_low_fd(1) failed: %s\n",
+                                       strerror(ret));
+                               return 1;
+                       }
+               }
 
 #ifdef HAVE_ATEXIT
                atexit(killkids);
@@ -2156,18 +2103,11 @@ extern void build_options(bool screen);
        if (!open_sockets_smbd(parent, ev_ctx, msg_ctx, ports))
                exit_server("open_sockets_smbd() failed");
 
-       /* do a printer update now that all messaging has been set up,
-        * before we allow clients to start connecting */
-       if (!lp__disable_spoolss() &&
-           (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) {
-               printing_subsystem_update(ev_ctx, msg_ctx, false);
-       }
-
        TALLOC_FREE(frame);
        /* make sure we always have a valid stackframe */
        frame = talloc_stackframe();
 
-       if (!Fork) {
+       if (!cmdline_daemon_cfg->fork) {
                /* if we are running in the foreground then look for
                   EOF on stdin, and exit if it happens. This allows
                   us to die if the parent process dies
@@ -2175,7 +2115,7 @@ extern void build_options(bool screen);
                */
                struct stat st;
                if (fstat(0, &st) != 0) {
-                       return false;
+                       return 1;
                }
                if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) {
                        tevent_add_fd(ev_ctx,