diff --git a/source4/smbd/process_model.h b/source4/smbd/process_model.h index 4399d3689fb..d7bf3c87c7b 100644 --- a/source4/smbd/process_model.h +++ b/source4/smbd/process_model.h @@ -61,7 +61,8 @@ struct model_ops { void (*)(struct tevent_context *, struct loadparm_context *, struct server_id, void *), - void *); + void *, + int); /* function to terminate a connection or task */ void (*terminate)(struct tevent_context *, struct loadparm_context *lp_ctx, diff --git a/source4/smbd/process_single.c b/source4/smbd/process_single.c index f483e000be7..54169e9b0cc 100644 --- a/source4/smbd/process_single.c +++ b/source4/smbd/process_single.c @@ -85,11 +85,12 @@ static void single_accept_connection(struct tevent_context *ev, /* called to startup a new task */ -static void single_new_task(struct tevent_context *ev, +static void single_new_task(struct tevent_context *ev, struct loadparm_context *lp_ctx, const char *service_name, - void (*new_task)(struct tevent_context *, struct loadparm_context *, struct server_id, void *), - void *private_data) + void (*new_task)(struct tevent_context *, struct loadparm_context *, struct server_id, void *), + void *private_data, + int from_parent_fd) { pid_t pid = getpid(); /* start our taskids at MAX_INT32, the first 2^31 tasks are is reserved for fd numbers */ diff --git a/source4/smbd/process_standard.c b/source4/smbd/process_standard.c index 8d962d55130..c6cbfc23eda 100644 --- a/source4/smbd/process_standard.c +++ b/source4/smbd/process_standard.c @@ -42,22 +42,13 @@ struct standard_child_state { NTSTATUS process_model_standard_init(TALLOC_CTX *); -/* we hold a pipe open in the parent, and the any child - processes wait for EOF on that pipe. This ensures that - children die when the parent dies */ -static int child_pipe[2] = { -1, -1 }; +static int from_parent_fd; /* called when the process model is selected */ static void standard_model_init(void) { - int rc; - - rc = pipe(child_pipe); - if (rc < 0) { - smb_panic("Failed to initialize pipe!"); - } } static void sighup_signal_handler(struct tevent_context *ev, @@ -312,17 +303,12 @@ static void standard_accept_connection(struct tevent_context *ev, smb_panic("Failed to re-initialise imessaging after fork"); } - fde = tevent_add_fd(ev, ev, child_pipe[0], TEVENT_FD_READ, + fde = tevent_add_fd(ev, ev, from_parent_fd, TEVENT_FD_READ, standard_pipe_handler, NULL); if (fde == NULL) { smb_panic("Failed to add fd handler after fork"); } - if (child_pipe[1] != -1) { - close(child_pipe[1]); - child_pipe[1] = -1; - } - se = tevent_add_signal(ev, ev, SIGHUP, @@ -368,11 +354,12 @@ static void standard_accept_connection(struct tevent_context *ev, /* called to create a new server task */ -static void standard_new_task(struct tevent_context *ev, +static void standard_new_task(struct tevent_context *ev, struct loadparm_context *lp_ctx, const char *service_name, void (*new_task)(struct tevent_context *, struct loadparm_context *lp_ctx, struct server_id , void *), - void *private_data) + void *private_data, + int new_from_parent_fd) { pid_t pid; NTSTATUS status; @@ -384,6 +371,7 @@ static void standard_new_task(struct tevent_context *ev, if (state == NULL) { return; } + from_parent_fd = new_from_parent_fd; pid = fork(); @@ -421,15 +409,11 @@ static void standard_new_task(struct tevent_context *ev, smb_panic("Failed to re-initialise imessaging after fork"); } - fde = tevent_add_fd(ev, ev, child_pipe[0], TEVENT_FD_READ, + fde = tevent_add_fd(ev, ev, from_parent_fd, TEVENT_FD_READ, standard_pipe_handler, NULL); if (fde == NULL) { smb_panic("Failed to add fd handler after fork"); } - if (child_pipe[1] != -1) { - close(child_pipe[1]); - child_pipe[1] = -1; - } se = tevent_add_signal(ev, ev, diff --git a/source4/smbd/server.c b/source4/smbd/server.c index 249391c0dff..66f2794a38a 100644 --- a/source4/smbd/server.c +++ b/source4/smbd/server.c @@ -43,6 +43,11 @@ #include "lib/util/samba_modules.h" #include "nsswitch/winbind_client.h" #include "libds/common/roles.h" +#include "lib/util/tfork.h" + +#ifdef HAVE_PTHREAD +#include +#endif struct server_state { struct tevent_context *event_ctx; @@ -332,6 +337,20 @@ static int event_ctx_destructor(struct tevent_context *event_ctx) return 0; } +#ifdef HAVE_PTHREAD +static int to_children_fd = -1; +static void atfork_prepare(void) { +} +static void atfork_parent(void) { +} +static void atfork_child(void) { + if (to_children_fd != -1) { + close(to_children_fd); + to_children_fd = -1; + } +} +#endif + /* main server. */ @@ -608,12 +627,54 @@ static int binary_smbd_main(const char *binary_name, DEBUG(0,("%s: using '%s' process model\n", binary_name, model)); - status = server_service_startup(state->event_ctx, cmdline_lp_ctx, model, - lpcfg_server_services(cmdline_lp_ctx)); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(state); - exit_daemon("Samba failed to start services", - NT_STATUS_V(status)); + { + int child_pipe[2]; + int rc; + bool start_services = false; + + rc = pipe(child_pipe); + if (rc < 0) { + TALLOC_FREE(state); + exit_daemon("Samba failed to open process control pipe", + errno); + } + smb_set_close_on_exec(child_pipe[0]); + smb_set_close_on_exec(child_pipe[1]); + +#ifdef HAVE_PTHREAD + to_children_fd = child_pipe[1]; + pthread_atfork(atfork_prepare, atfork_parent, + atfork_child); + start_services = true; +#else + pid_t pid; + struct tfork *t = NULL; + t = tfork_create(); + if (t == NULL) { + exit_daemon( + "Samba unable to fork master process", + 0); + } + pid = tfork_child_pid(t); + if (pid == 0) { + start_services = false; + } else { + /* In the child process */ + start_services = true; + close(child_pipe[1]); + } +#endif + if (start_services) { + status = server_service_startup( + state->event_ctx, cmdline_lp_ctx, model, + lpcfg_server_services(cmdline_lp_ctx), + child_pipe[0]); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(state); + exit_daemon("Samba failed to start services", + NT_STATUS_V(status)); + } + } } if (opt_daemon) { diff --git a/source4/smbd/service.c b/source4/smbd/service.c index 403ae74964b..61ed684d00f 100644 --- a/source4/smbd/service.c +++ b/source4/smbd/service.c @@ -56,13 +56,16 @@ NTSTATUS register_server_service(TALLOC_CTX *ctx, static NTSTATUS server_service_init(const char *name, struct tevent_context *event_context, struct loadparm_context *lp_ctx, - const struct model_ops *model_ops) + const struct model_ops *model_ops, + int from_parent_fd) { struct registered_server *srv; for (srv=registered_servers; srv; srv=srv->next) { if (strcasecmp(name, srv->service_name) == 0) { - return task_server_startup(event_context, lp_ctx, srv->service_name, - model_ops, srv->task_init); + return task_server_startup(event_context, lp_ctx, + srv->service_name, + model_ops, srv->task_init, + from_parent_fd); } } return NT_STATUS_INVALID_SYSTEM_SERVICE; @@ -72,9 +75,10 @@ static NTSTATUS server_service_init(const char *name, /* startup all of our server services */ -NTSTATUS server_service_startup(struct tevent_context *event_ctx, +NTSTATUS server_service_startup(struct tevent_context *event_ctx, struct loadparm_context *lp_ctx, - const char *model, const char **server_services) + const char *model, const char **server_services, + int from_parent_fd) { int i; const struct model_ops *model_ops; @@ -93,7 +97,8 @@ NTSTATUS server_service_startup(struct tevent_context *event_ctx, for (i=0;server_services[i];i++) { NTSTATUS status; - status = server_service_init(server_services[i], event_ctx, lp_ctx, model_ops); + status = server_service_init(server_services[i], event_ctx, + lp_ctx, model_ops, from_parent_fd); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Failed to start service '%s' - %s\n", server_services[i], nt_errstr(status))); diff --git a/source4/smbd/service_task.c b/source4/smbd/service_task.c index 34f73d9f4b2..e0e98f644e1 100644 --- a/source4/smbd/service_task.c +++ b/source4/smbd/service_task.c @@ -101,7 +101,8 @@ NTSTATUS task_server_startup(struct tevent_context *event_ctx, struct loadparm_context *lp_ctx, const char *service_name, const struct model_ops *model_ops, - void (*task_init)(struct task_server *)) + void (*task_init)(struct task_server *), + int from_parent_fd) { struct task_state *state; @@ -110,8 +111,10 @@ NTSTATUS task_server_startup(struct tevent_context *event_ctx, state->task_init = task_init; state->model_ops = model_ops; - - model_ops->new_task(event_ctx, lp_ctx, service_name, task_server_callback, state); + + state->model_ops->new_task(event_ctx, lp_ctx, service_name, + task_server_callback, state, + from_parent_fd); return NT_STATUS_OK; }