source4 smbd prefork: restart on non zero exit code
authorGary Lockyer <gary@catalyst.net.nz>
Tue, 4 Sep 2018 00:12:49 +0000 (12:12 +1200)
committerAndrew Bartlett <abartlet@samba.org>
Fri, 23 Nov 2018 07:25:19 +0000 (08:25 +0100)
Restart any pre-fork master or worker process that exits with a non
zero exit code.

Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source4/kdc/kdc-heimdal.c
source4/smbd/process_model.h
source4/smbd/process_prefork.c
source4/smbd/process_single.c
source4/smbd/process_standard.c
source4/smbd/service_stream.c
source4/smbd/service_task.c

index 67c07c3d81a5e9dfe9ec0f33bf7c14ab7181b075..b5de5a790d4093c6ee11a6e173acab3335857d15 100644 (file)
@@ -276,7 +276,8 @@ static NTSTATUS kdc_task_init(struct task_server *task)
                return NT_STATUS_INVALID_DOMAIN_ROLE;
        case ROLE_DOMAIN_PDC:
        case ROLE_DOMAIN_BDC:
-               task_server_terminate(task, "Cannot start KDC as a 'classic Samba' DC", true);
+               task_server_terminate(
+                   task, "Cannot start KDC as a 'classic Samba' DC", false);
                return NT_STATUS_INVALID_DOMAIN_ROLE;
        case ROLE_ACTIVE_DIRECTORY_DC:
                /* Yes, we want a KDC */
index 2a226cef8cbd33ec5b2636d7ea8365d955982c28..2892dd43c04e75e8464a259b30b9f243c234fcea 100644 (file)
@@ -65,12 +65,17 @@ struct model_ops {
                         const struct service_details*,
                         const int);
 
-       /* function to terminate a connection or task */
-       void (*terminate)(struct tevent_context *,
-                         struct loadparm_context *lp_ctx,
-                         const char *reason,
-                         bool fatal,
-                         void *process_context);
+       /* function to terminate a task */
+       void (*terminate_task)(struct tevent_context *,
+                              struct loadparm_context *lp_ctx,
+                              const char *reason,
+                              bool fatal,
+                              void *process_context);
+       /* function to terminate a connection */
+       void (*terminate_connection)(struct tevent_context *,
+                                    struct loadparm_context *lp_ctx,
+                                    const char *reason,
+                                    void *process_context);
 
        /* function to set a title for the connection or task */
        void (*set_title)(struct tevent_context *, const char *title);
index c470820efb8e0286459efc88f99fa0e93620ea18..d2627937b44f56fbf27ee7a251b03a1027ca14c9 100644 (file)
@@ -147,6 +147,33 @@ static void prefork_pipe_handler(struct tevent_context *event_ctx,
        exit(0);
 }
 
+static void prefork_restart(struct tevent_context *ev,
+                           struct restart_context *rc)
+{
+       if (rc->master != NULL) {
+               DBG_ERR("Restarting [%s] pre-fork master\n", rc->service_name);
+               prefork_new_task(ev,
+                                rc->master->lp_ctx,
+                                rc->service_name,
+                                rc->master->new_task_fn,
+                                rc->master->private_data,
+                                rc->service_details,
+                                rc->from_parent_fd);
+       } else if (rc->worker != NULL) {
+               struct process_details pd = initial_process_details;
+               DBG_ERR("Restarting [%s] pre-fork worker(%d)\n",
+                       rc->service_name,
+                       rc->worker->instance);
+               pd.instances = rc->worker->instance;
+               prefork_fork_worker(rc->worker->task,
+                                   ev,
+                                   rc->worker->ev2,
+                                   rc->service_details,
+                                   rc->service_name,
+                                   rc->worker->control_pipe,
+                                   &pd);
+       }
+}
 /*
   handle EOF on the child pipe in the parent, so we know when a
   process terminates without using SIGCHLD or waiting on all possible pids.
@@ -176,49 +203,26 @@ static void prefork_child_pipe_handler(struct tevent_context *ev,
                DBG_ERR("Parent %d, Child %d terminated, "
                        "unable to get status code from tfork\n",
                        getpid(), pid);
+               prefork_restart(ev, rc);
        } else if (WIFEXITED(status)) {
                status = WEXITSTATUS(status);
                DBG_ERR("Parent %d, Child %d exited with status %d\n",
                         getpid(), pid,  status);
+               if (status != 0) {
+                       prefork_restart(ev, rc);
+               }
        } else if (WIFSIGNALED(status)) {
                status = WTERMSIG(status);
                DBG_ERR("Parent %d, Child %d terminated with signal %d\n",
                        getpid(), pid, status);
                if (status == SIGABRT || status == SIGBUS || status == SIGFPE ||
-                   status == SIGILL || status == SIGSYS) {
-                       /*
-                        * Lets restart the process.
-                        *
-                        */
-                       tfork_destroy(&rc->t);
-                       if (rc->master != NULL) {
-                               DBG_ERR("Restarting [%s] pre-fork master\n",
-                                       rc->service_name);
-                               prefork_new_task(ev,
-                                                rc->master->lp_ctx,
-                                                rc->service_name,
-                                                rc->master->new_task_fn,
-                                                rc->master->private_data,
-                                                rc->service_details,
-                                                rc->from_parent_fd);
-                       } else if (rc->worker != NULL) {
-                               struct process_details pd =
-                                   initial_process_details;
-                               DBG_ERR("Restarting [%s] pre-fork worker(%d)\n",
-                                       rc->service_name,
-                                       rc->worker->instance);
-                               pd.instances = rc->worker->instance;
-                               prefork_fork_worker(rc->worker->task,
-                                                   ev,
-                                                   rc->worker->ev2,
-                                                   rc->service_details,
-                                                   rc->service_name,
-                                                   rc->worker->control_pipe,
-                                                   &pd);
-                       }
+                   status == SIGILL || status == SIGSYS || status == SIGSEGV) {
+
+                       prefork_restart(ev, rc);
                }
        }
        /* tfork allocates tfork structures with malloc */
+       tfork_destroy(&rc->t);
        free(rc->t);
        TALLOC_FREE(rc);
        return;
@@ -529,15 +533,31 @@ static void prefork_new_task(
 
 }
 
-
-/* called when a task goes down */
-static void prefork_terminate(struct tevent_context *ev,
-                             struct loadparm_context *lp_ctx,
-                             const char *reason,
-                             bool fatal,
-                             void *process_context)
+/*
+ * called when a task terminates
+ */
+static void prefork_terminate_task(struct tevent_context *ev,
+                                  struct loadparm_context *lp_ctx,
+                                  const char *reason,
+                                  bool fatal,
+                                  void *process_context)
 {
        DBG_DEBUG("called with reason[%s]\n", reason);
+       if (fatal == true) {
+               exit(127);
+       } else {
+               exit(0);
+       }
+}
+
+/*
+ * called when a connection completes
+ */
+static void prefork_terminate_connection(struct tevent_context *ev,
+                                        struct loadparm_context *lp_ctx,
+                                        const char *reason,
+                                        void *process_context)
+{
 }
 
 /* called to set a title of a task or connection */
@@ -550,7 +570,8 @@ static const struct model_ops prefork_ops = {
        .model_init             = prefork_model_init,
        .accept_connection      = prefork_accept_connection,
        .new_task               = prefork_new_task,
-       .terminate              = prefork_terminate,
+       .terminate_task         = prefork_terminate_task,
+       .terminate_connection   = prefork_terminate_connection,
        .set_title              = prefork_set_title,
 };
 
index 061f09673dd68acbe91fbced1cf1298b26d43913..12ed2e30a74621522b381c06c13a450bddec1910 100644 (file)
@@ -119,17 +119,28 @@ static void single_new_task(struct tevent_context *ev,
        }
 }
 
-
-/* called when a task goes down */
-static void single_terminate(struct tevent_context *ev,
-                            struct loadparm_context *lp_ctx,
-                            const char *reason,
-                            bool fatal,
-                            void *process_context)
+/*
+ * Called when a task goes down
+ */
+static void single_terminate_task(struct tevent_context *ev,
+                                 struct loadparm_context *lp_ctx,
+                                 const char *reason,
+                                 bool fatal,
+                                 void *process_context)
 {
        DBG_NOTICE("single_terminate: reason[%s]\n",reason);
 }
 
+/*
+ * Called when a connection has ended
+ */
+static void single_terminate_connection(struct tevent_context *ev,
+                                       struct loadparm_context *lp_ctx,
+                                       const char *reason,
+                                       void *process_context)
+{
+}
+
 /* called to set a title of a task or connection */
 static void single_set_title(struct tevent_context *ev, const char *title) 
 {
@@ -138,9 +149,10 @@ static void single_set_title(struct tevent_context *ev, const char *title)
 const struct model_ops single_ops = {
        .name                   = "single",
        .model_init             = single_model_init,
-       .new_task               = single_new_task,
+       .new_task               = single_new_task,
        .accept_connection      = single_accept_connection,
-       .terminate              = single_terminate,
+       .terminate_task         = single_terminate_task,
+       .terminate_connection   = single_terminate_connection,
        .set_title              = single_set_title,
 };
 
index 536a6be30078ca4a41536e8d3d3854dc7182a6f5..d25538716baf747924bc7e31ff3a6f530491b3e1 100644 (file)
@@ -510,15 +510,27 @@ static void standard_new_task(struct tevent_context *ev,
 
 
 /* called when a task goes down */
-static void standard_terminate(struct tevent_context *ev,
-                              struct loadparm_context *lp_ctx,
-                              const char *reason,
-                              bool fatal,
-                              void *process_context)
+static void standard_terminate_task(struct tevent_context *ev,
+                                   struct loadparm_context *lp_ctx,
+                                   const char *reason,
+                                   bool fatal,
+                                   void *process_context)
+{
+       if (fatal == true) {
+               exit(127);
+       }
+       exit(0);
+}
+
+/* called when a connection terminates*/
+static void standard_terminate_connection(struct tevent_context *ev,
+                                         struct loadparm_context *lp_ctx,
+                                         const char *reason,
+                                         void *process_context)
 {
        struct process_context *proc_ctx = NULL;
 
-       DBG_DEBUG("process terminating reason[%s]\n", reason);
+       DBG_DEBUG("connection terminating reason[%s]\n", reason);
        if (process_context == NULL) {
                smb_panic("Panicking process_context is NULL");
        }
@@ -547,7 +559,6 @@ static void standard_terminate(struct tevent_context *ev,
        /* terminate this process */
        exit(0);
 }
-
 /* called to set a title of a task or connection */
 static void standard_set_title(struct tevent_context *ev, const char *title) 
 {
@@ -562,9 +573,10 @@ static const struct model_ops standard_ops = {
        .name                   = "standard",
        .model_init             = standard_model_init,
        .accept_connection      = standard_accept_connection,
-       .new_task               = standard_new_task,
-       .terminate              = standard_terminate,
-       .set_title              = standard_set_title,
+       .new_task               = standard_new_task,
+       .terminate_task         = standard_terminate_task,
+       .terminate_connection   = standard_terminate_connection,
+       .set_title              = standard_set_title,
 };
 
 /*
index 336a0cb32aa7aaa79aca5176bd079cd95e778c09..d0ad45aca3ae0ece836e4d52ebe6cb0b0e715cd3 100644 (file)
@@ -57,7 +57,6 @@ void stream_terminate_connection(struct stream_connection *srv_conn, const char
        const struct model_ops *model_ops = srv_conn->model_ops;
        struct loadparm_context *lp_ctx = srv_conn->lp_ctx;
        void *process_context = srv_conn->process_context;
-       bool fatal = true;
        TALLOC_CTX *frame = NULL;
 
        if (!reason) reason = "unknown reason";
@@ -92,7 +91,8 @@ void stream_terminate_connection(struct stream_connection *srv_conn, const char
        srv_conn->event.fde = NULL;
        imessaging_cleanup(srv_conn->msg_ctx);
        TALLOC_FREE(srv_conn);
-       model_ops->terminate(event_ctx, lp_ctx, reason, fatal, process_context);
+       model_ops->terminate_connection(
+           event_ctx, lp_ctx, reason, process_context);
        TALLOC_FREE(frame);
 }
 
index cb1f4d5ad1fe62f7a8e726183900073dc2fdcf91..d911027db0a7c0d1625aa043a33666a09ebd264a 100644 (file)
@@ -54,7 +54,7 @@ void task_server_terminate(struct task_server *task, const char *reason, bool fa
 
        imessaging_cleanup(task->msg_ctx);
 
-       model_ops->terminate(
+       model_ops->terminate_task(
            event_ctx, task->lp_ctx, reason, fatal, task->process_context);
        /* don't free this above, it might contain the 'reason' being printed */
        talloc_free(task);