[PATCH] enable prefork for the KDC

Gary Lockyer gary at catalyst.net.nz
Mon Oct 29 02:09:38 UTC 2018


Patches to allow the kdc to run under pre-fork.

CI results: https://gitlab.com/catalyst-samba/samba/pipelines/34612485

Subsequent patch sets will:
* increase the default number of pre-fork workers from 1 to 4
* allow the netlogon process to run in pre-fork.
* add automated restart of failed pre-fork workers
* limit the number of connection processes started by the
  standard model.

Review appreciated

Thanks

Gary.

-------------- next part --------------
From 0b2cce9a0b0f99866da23ff6aa7bd7f370577f4c Mon Sep 17 00:00:00 2001
From: Gary Lockyer <gary at catalyst.net.nz>
Date: Mon, 27 Aug 2018 16:43:00 +1200
Subject: [PATCH 1/6] windbindd: reword error message

Reword the asprintf() out of memory message to make it clear where the
issue is.

Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
---
 source3/winbindd/winbindd_cm.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
index f3f8d547c7e..2e98c7634e8 100644
--- a/source3/winbindd/winbindd_cm.c
+++ b/source3/winbindd/winbindd_cm.c
@@ -241,7 +241,8 @@ static bool fork_child_dc_connect(struct winbindd_domain *domain)
 
 	if (!override_logfile) {
 		if (asprintf(&lfile, "%s/log.winbindd-dc-connect", get_dyn_LOGFILEBASE()) == -1) {
-			DEBUG(0, ("fork_child_dc_connect: out of memory.\n"));
+			DBG_ERR("fork_child_dc_connect: "
+				"out of memory in asprintf().\n");
 			_exit(1);
 		}
 	}
-- 
2.17.1


From 0c606d22889fce8aab4773b2600814a452727fa1 Mon Sep 17 00:00:00 2001
From: Gary Lockyer <gary at catalyst.net.nz>
Date: Thu, 23 Aug 2018 09:29:56 +1200
Subject: [PATCH 2/6] source4 smbd: Make the service_details structure
 constant.

Make the service_details structure a static const.

Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
---
 source4/cldap_server/cldap_server.c | 2 +-
 source4/dns_server/dns_server.c     | 2 +-
 source4/dsdb/dns/dns_update.c       | 2 +-
 source4/dsdb/kcc/kcc_service.c      | 2 +-
 source4/dsdb/repl/drepl_service.c   | 2 +-
 source4/echo_server/echo_server.c   | 2 +-
 source4/kdc/kdc-heimdal.c           | 2 +-
 source4/kdc/kdc-service-mit.c       | 2 +-
 source4/ldap_server/ldap_server.c   | 2 +-
 source4/nbt_server/nbt_server.c     | 2 +-
 source4/ntp_signd/ntp_signd.c       | 2 +-
 source4/rpc_server/service_rpc.c    | 2 +-
 source4/smb_server/service_smb.c    | 2 +-
 source4/smbd/service.c              | 2 +-
 source4/web_server/web_server.c     | 2 +-
 source4/winbind/winbindd.c          | 2 +-
 source4/wrepl_server/wrepl_server.c | 2 +-
 17 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/source4/cldap_server/cldap_server.c b/source4/cldap_server/cldap_server.c
index d93ac0b35b3..65d983f7295 100644
--- a/source4/cldap_server/cldap_server.c
+++ b/source4/cldap_server/cldap_server.c
@@ -248,7 +248,7 @@ static void cldapd_task_init(struct task_server *task)
 */
 NTSTATUS server_service_cldapd_init(TALLOC_CTX *ctx)
 {
-	struct service_details details = {
+	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
 		.inhibit_pre_fork = true
 	};
diff --git a/source4/dns_server/dns_server.c b/source4/dns_server/dns_server.c
index 9db11330e50..c7c1cdde038 100644
--- a/source4/dns_server/dns_server.c
+++ b/source4/dns_server/dns_server.c
@@ -923,7 +923,7 @@ static void dns_task_init(struct task_server *task)
 
 NTSTATUS server_service_dns_init(TALLOC_CTX *ctx)
 {
-	struct service_details details = {
+	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
 		.inhibit_pre_fork = true,
 	};
diff --git a/source4/dsdb/dns/dns_update.c b/source4/dsdb/dns/dns_update.c
index de873376201..08e7eb2224a 100644
--- a/source4/dsdb/dns/dns_update.c
+++ b/source4/dsdb/dns/dns_update.c
@@ -712,7 +712,7 @@ static void dnsupdate_task_init(struct task_server *task)
 */
 NTSTATUS server_service_dnsupdate_init(TALLOC_CTX *ctx)
 {
-	struct service_details details = {
+	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
 		.inhibit_pre_fork = true,
 	};
diff --git a/source4/dsdb/kcc/kcc_service.c b/source4/dsdb/kcc/kcc_service.c
index 76423780dc8..e1bbae2abc1 100644
--- a/source4/dsdb/kcc/kcc_service.c
+++ b/source4/dsdb/kcc/kcc_service.c
@@ -352,7 +352,7 @@ static void kccsrv_task_init(struct task_server *task)
 */
 NTSTATUS server_service_kcc_init(TALLOC_CTX *ctx)
 {
-	struct service_details details = {
+	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
 		.inhibit_pre_fork = true
 	};
diff --git a/source4/dsdb/repl/drepl_service.c b/source4/dsdb/repl/drepl_service.c
index 10772d47439..9789e784a13 100644
--- a/source4/dsdb/repl/drepl_service.c
+++ b/source4/dsdb/repl/drepl_service.c
@@ -533,7 +533,7 @@ static void dreplsrv_task_init(struct task_server *task)
 */
 NTSTATUS server_service_drepl_init(TALLOC_CTX *ctx)
 {
-	struct service_details details = {
+	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
 		.inhibit_pre_fork = true,
 	};
diff --git a/source4/echo_server/echo_server.c b/source4/echo_server/echo_server.c
index 90f8616ca11..657180f760c 100644
--- a/source4/echo_server/echo_server.c
+++ b/source4/echo_server/echo_server.c
@@ -324,7 +324,7 @@ static void echo_task_init(struct task_server *task)
  */
 NTSTATUS server_service_echo_init(TALLOC_CTX *ctx)
 {
-	struct service_details details = {
+	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
 		.inhibit_pre_fork = true
 	};
diff --git a/source4/kdc/kdc-heimdal.c b/source4/kdc/kdc-heimdal.c
index 83ace269d5d..8f09c41d74d 100644
--- a/source4/kdc/kdc-heimdal.c
+++ b/source4/kdc/kdc-heimdal.c
@@ -465,7 +465,7 @@ static void kdc_task_init(struct task_server *task)
 /* called at smbd startup - register ourselves as a server service */
 NTSTATUS server_service_kdc_init(TALLOC_CTX *ctx)
 {
-	struct service_details details = {
+	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
 		/* 
 		 * Need to prevent pre-forking on kdc.
diff --git a/source4/kdc/kdc-service-mit.c b/source4/kdc/kdc-service-mit.c
index 1d28fc4e6eb..5d111ee82d2 100644
--- a/source4/kdc/kdc-service-mit.c
+++ b/source4/kdc/kdc-service-mit.c
@@ -352,7 +352,7 @@ NTSTATUS server_service_mitkdc_init(TALLOC_CTX *mem_ctx);
 
 NTSTATUS server_service_mitkdc_init(TALLOC_CTX *mem_ctx)
 {
-	struct service_details details = {
+	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
 		/* 
 		 * Need to prevent pre-forking on kdc.
diff --git a/source4/ldap_server/ldap_server.c b/source4/ldap_server/ldap_server.c
index b5251e3623e..5b1db0c109a 100644
--- a/source4/ldap_server/ldap_server.c
+++ b/source4/ldap_server/ldap_server.c
@@ -1278,7 +1278,7 @@ failed:
 
 NTSTATUS server_service_ldap_init(TALLOC_CTX *ctx)
 {
-	struct service_details details = {
+	static const struct service_details details = {
 		.inhibit_fork_on_accept = false,
 		.inhibit_pre_fork = false
 	};
diff --git a/source4/nbt_server/nbt_server.c b/source4/nbt_server/nbt_server.c
index 6bdf9b45374..84cd507fe13 100644
--- a/source4/nbt_server/nbt_server.c
+++ b/source4/nbt_server/nbt_server.c
@@ -105,7 +105,7 @@ static void nbtd_task_init(struct task_server *task)
 */
 NTSTATUS server_service_nbtd_init(TALLOC_CTX *ctx)
 {
-	struct service_details details = {
+	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
 		.inhibit_pre_fork = true
 	};
diff --git a/source4/ntp_signd/ntp_signd.c b/source4/ntp_signd/ntp_signd.c
index 508adcf7b36..a392929c78b 100644
--- a/source4/ntp_signd/ntp_signd.c
+++ b/source4/ntp_signd/ntp_signd.c
@@ -549,7 +549,7 @@ static void ntp_signd_task_init(struct task_server *task)
 /* called at smbd startup - register ourselves as a server service */
 NTSTATUS server_service_ntp_signd_init(TALLOC_CTX *ctx)
 {
-	struct service_details details = {
+	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
 		.inhibit_pre_fork = true
 	};
diff --git a/source4/rpc_server/service_rpc.c b/source4/rpc_server/service_rpc.c
index eb75184a05f..f7d1a9f3c7d 100644
--- a/source4/rpc_server/service_rpc.c
+++ b/source4/rpc_server/service_rpc.c
@@ -142,7 +142,7 @@ failed:
 
 NTSTATUS server_service_rpc_init(TALLOC_CTX *ctx)
 {
-	struct service_details details = {
+	static const struct service_details details = {
 		/* 
 		 * This is a SNOWFLAKE, but sadly one that we
 		 * will have to keep for now.  The RPC server
diff --git a/source4/smb_server/service_smb.c b/source4/smb_server/service_smb.c
index 3f0f009ce3b..bea7eb9285b 100644
--- a/source4/smb_server/service_smb.c
+++ b/source4/smb_server/service_smb.c
@@ -94,7 +94,7 @@ failed:
 /* called at smbd startup - register ourselves as a server service */
 NTSTATUS server_service_smb_init(TALLOC_CTX *ctx)
 {
-	struct service_details details = {
+	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
 		.inhibit_pre_fork = true
 	};
diff --git a/source4/smbd/service.c b/source4/smbd/service.c
index e7808727a23..0874fce20fc 100644
--- a/source4/smbd/service.c
+++ b/source4/smbd/service.c
@@ -40,7 +40,7 @@ static struct registered_server {
 NTSTATUS register_server_service(TALLOC_CTX *ctx,
 				const char *name,
 				void (*task_init) (struct task_server *),
-				struct service_details *details)
+				const struct service_details *details)
 {
 	struct registered_server *srv;
 	srv = talloc(ctx, struct registered_server);
diff --git a/source4/web_server/web_server.c b/source4/web_server/web_server.c
index 9c4da2c23c9..d72524c8873 100644
--- a/source4/web_server/web_server.c
+++ b/source4/web_server/web_server.c
@@ -371,7 +371,7 @@ failed:
 /* called at smbd startup - register ourselves as a server service */
 NTSTATUS server_service_web_init(TALLOC_CTX *ctx)
 {
-	struct service_details details = {
+	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
 		.inhibit_pre_fork = true
 	};
diff --git a/source4/winbind/winbindd.c b/source4/winbind/winbindd.c
index 7fb0836b6a5..e422e623b84 100644
--- a/source4/winbind/winbindd.c
+++ b/source4/winbind/winbindd.c
@@ -89,7 +89,7 @@ NTSTATUS server_service_winbindd_init(TALLOC_CTX *);
 
 NTSTATUS server_service_winbindd_init(TALLOC_CTX *ctx)
 {
-	struct service_details details = {
+	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
 		.inhibit_pre_fork = true,
 	};
diff --git a/source4/wrepl_server/wrepl_server.c b/source4/wrepl_server/wrepl_server.c
index bd2ae2660a0..269fac0670d 100644
--- a/source4/wrepl_server/wrepl_server.c
+++ b/source4/wrepl_server/wrepl_server.c
@@ -508,7 +508,7 @@ static void wreplsrv_task_init(struct task_server *task)
 */
 NTSTATUS server_service_wrepl_init(TALLOC_CTX *ctx)
 {
-	struct service_details details = {
+	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
 		.inhibit_pre_fork = true
 	};
-- 
2.17.1


From cd89a3dbaf6a4982885e33f91a6196c339b056e3 Mon Sep 17 00:00:00 2001
From: Gary Lockyer <gary at catalyst.net.nz>
Date: Thu, 23 Aug 2018 09:35:52 +1200
Subject: [PATCH 3/6] source4 smdb: Add a post fork hook to the service API

Add a post fork hook to the service API this will be called:

 - standard process model
   immediately after the task_init.

- single process model
  immediately after the task_init

- prefork process model, inhibit_pre_fork = true
  immediately after the task_init

- prefork process model, inhibit_pre_fork = false
  after each service worker has forked. It is not run on the service
  master process.

The post fork hook is not called in the standard model if a new process
is forked on a new connection. It is instead called immediately after
the task_init.

The task_init hook has been changed to return an error code. This ensures
the post_fork code is only run if the task_init code completed successfully.

Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
---
 file_server/file_server.c           | 14 +++++---
 source4/cldap_server/cldap_server.c | 23 +++++++------
 source4/dns_server/dns_server.c     | 35 +++++++++++---------
 source4/dsdb/dns/dns_update.c       | 20 ++++++------
 source4/dsdb/kcc/kcc_service.c      | 23 +++++++------
 source4/dsdb/repl/drepl_service.c   | 27 +++++++++-------
 source4/echo_server/echo_server.c   | 18 +++++++----
 source4/kdc/kdc-heimdal.c           | 50 ++++++++++++++++-------------
 source4/kdc/kdc-service-mit.c       |  7 ++--
 source4/ldap_server/ldap_server.c   | 38 +++++++++++++++-------
 source4/nbt_server/nbt_server.c     | 22 +++++++------
 source4/ntp_signd/ntp_signd.c       | 24 +++++++++-----
 source4/rpc_server/service_rpc.c    | 13 +++++---
 source4/smb_server/service_smb.c    | 14 +++++---
 source4/smbd/process_model.h        |  2 +-
 source4/smbd/process_prefork.c      | 31 ++++++++++++++----
 source4/smbd/process_single.c       |  9 ++++--
 source4/smbd/process_standard.c     | 14 ++++++--
 source4/smbd/service.c              |  6 +---
 source4/smbd/service.h              | 26 ++++++++++++++-
 source4/smbd/service_task.c         | 20 +++++++-----
 source4/web_server/web_server.c     | 27 ++++++++++++----
 source4/winbind/winbindd.c          | 13 ++++----
 source4/wrepl_server/wrepl_server.c | 23 +++++++------
 24 files changed, 317 insertions(+), 182 deletions(-)

diff --git a/file_server/file_server.c b/file_server/file_server.c
index 1b6a01b0b56..4c216695a1f 100644
--- a/file_server/file_server.c
+++ b/file_server/file_server.c
@@ -53,7 +53,7 @@ static void file_server_smbd_done(struct tevent_req *subreq)
 /*
   startup a copy of smbd as a child daemon
 */
-static void s3fs_task_init(struct task_server *task)
+static NTSTATUS s3fs_task_init(struct task_server *task)
 {
 	struct tevent_req *subreq;
 	const char *smbd_path;
@@ -78,17 +78,19 @@ static void s3fs_task_init(struct task_server *task)
 	if (!winbind_off()) {
 		DEBUG(0,("Failed to re-disable recursive winbindd calls after forking smbd\n"));
 		task_server_terminate(task, "Failed to re-disable recursive winbindd calls", true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 	if (subreq == NULL) {
 		DEBUG(0, ("Failed to start smbd as child daemon\n"));
 		task_server_terminate(task, "Failed to startup s3fs smb task", true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	tevent_req_set_callback(subreq, file_server_smbd_done, task);
 
 	DEBUG(5,("Started file server child smbd\n"));
+
+	return NT_STATUS_OK;
 }
 
 /* called at smbd startup - register ourselves as a server service */
@@ -98,7 +100,9 @@ NTSTATUS server_service_s3fs_init(TALLOC_CTX *ctx)
 {
 	struct service_details details = {
 		.inhibit_fork_on_accept = true,
-		.inhibit_pre_fork = true
+		.inhibit_pre_fork = true,
+		.task_init = s3fs_task_init,
+		.post_fork = NULL
 	};
-	return register_server_service(ctx, "s3fs", s3fs_task_init, &details);
+	return register_server_service(ctx, "s3fs", &details);
 }
diff --git a/source4/cldap_server/cldap_server.c b/source4/cldap_server/cldap_server.c
index 65d983f7295..51183260833 100644
--- a/source4/cldap_server/cldap_server.c
+++ b/source4/cldap_server/cldap_server.c
@@ -185,7 +185,7 @@ static NTSTATUS cldapd_startup_interfaces(struct cldapd_server *cldapd, struct l
 /*
   startup the cldapd task
 */
-static void cldapd_task_init(struct task_server *task)
+static NTSTATUS cldapd_task_init(struct task_server *task)
 {
 	struct cldapd_server *cldapd;
 	NTSTATUS status;
@@ -195,18 +195,18 @@ static void cldapd_task_init(struct task_server *task)
 
 	if (iface_list_count(ifaces) == 0) {
 		task_server_terminate(task, "cldapd: no network interfaces configured", false);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	switch (lpcfg_server_role(task->lp_ctx)) {
 	case ROLE_STANDALONE:
 		task_server_terminate(task, "cldap_server: no CLDAP server required in standalone configuration", 
 				      false);
-		return;
+		return NT_STATUS_INVALID_DOMAIN_ROLE;
 	case ROLE_DOMAIN_MEMBER:
 		task_server_terminate(task, "cldap_server: no CLDAP server required in member server configuration",
 				      false);
-		return;
+		return NT_STATUS_INVALID_DOMAIN_ROLE;
 	case ROLE_ACTIVE_DIRECTORY_DC:
 		/* Yes, we want an CLDAP server */
 		break;
@@ -217,7 +217,7 @@ static void cldapd_task_init(struct task_server *task)
 	cldapd = talloc(task, struct cldapd_server);
 	if (cldapd == NULL) {
 		task_server_terminate(task, "cldapd: out of memory", true);
-		return;
+		return NT_STATUS_NO_MEMORY;
 	}
 
 	cldapd->task = task;
@@ -229,17 +229,19 @@ static void cldapd_task_init(struct task_server *task)
 				       0);
 	if (cldapd->samctx == NULL) {
 		task_server_terminate(task, "cldapd failed to open samdb", true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	/* start listening on the configured network interfaces */
 	status = cldapd_startup_interfaces(cldapd, task->lp_ctx, ifaces);
 	if (!NT_STATUS_IS_OK(status)) {
 		task_server_terminate(task, "cldapd failed to setup interfaces", true);
-		return;
+		return status;
 	}
 
 	irpc_add_name(task->msg_ctx, "cldap_server");
+
+	return NT_STATUS_OK;
 }
 
 
@@ -250,8 +252,9 @@ NTSTATUS server_service_cldapd_init(TALLOC_CTX *ctx)
 {
 	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
-		.inhibit_pre_fork = true
+		.inhibit_pre_fork = true,
+		.task_init = cldapd_task_init,
+		.post_fork = NULL
 	};
-	return register_server_service(ctx, "cldap", cldapd_task_init,
-				       &details);
+	return register_server_service(ctx, "cldap", &details);
 }
diff --git a/source4/dns_server/dns_server.c b/source4/dns_server/dns_server.c
index c7c1cdde038..43ea88158ce 100644
--- a/source4/dns_server/dns_server.c
+++ b/source4/dns_server/dns_server.c
@@ -790,7 +790,7 @@ static NTSTATUS dns_reload_zones(struct irpc_message *msg,
 	return NT_STATUS_OK;
 }
 
-static void dns_task_init(struct task_server *task)
+static NTSTATUS dns_task_init(struct task_server *task)
 {
 	struct dns_server *dns;
 	NTSTATUS status;
@@ -804,10 +804,10 @@ static void dns_task_init(struct task_server *task)
 	switch (lpcfg_server_role(task->lp_ctx)) {
 	case ROLE_STANDALONE:
 		task_server_terminate(task, "dns: no DNS required in standalone configuration", false);
-		return;
+		return NT_STATUS_INVALID_DOMAIN_ROLE;
 	case ROLE_DOMAIN_MEMBER:
 		task_server_terminate(task, "dns: no DNS required in member server configuration", false);
-		return;
+		return NT_STATUS_INVALID_DOMAIN_ROLE;
 	case ROLE_ACTIVE_DIRECTORY_DC:
 		/* Yes, we want a DNS */
 		break;
@@ -818,7 +818,7 @@ static void dns_task_init(struct task_server *task)
 
 		if (iface_list_count(ifaces) == 0) {
 			task_server_terminate(task, "dns: no network interfaces configured", false);
-			return;
+			return NT_STATUS_UNSUCCESSFUL;
 		}
 	}
 
@@ -827,7 +827,7 @@ static void dns_task_init(struct task_server *task)
 	dns = talloc_zero(task, struct dns_server);
 	if (dns == NULL) {
 		task_server_terminate(task, "dns: out of memory", true);
-		return;
+		return NT_STATUS_NO_MEMORY;
 	}
 
 	dns->task = task;
@@ -835,7 +835,7 @@ static void dns_task_init(struct task_server *task)
 	dns->server_credentials = cli_credentials_init(dns);
 	if (!dns->server_credentials) {
 		task_server_terminate(task, "Failed to init server credentials\n", true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	dns->samdb = samdb_connect(dns,
@@ -846,7 +846,7 @@ static void dns_task_init(struct task_server *task)
 				   0);
 	if (!dns->samdb) {
 		task_server_terminate(task, "dns: samdb_connect failed", true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	cli_credentials_set_conf(dns->server_credentials, task->lp_ctx);
@@ -865,7 +865,7 @@ static void dns_task_init(struct task_server *task)
 		TALLOC_FREE(dns_acc);
 		if (!dns_spn) {
 			task_server_terminate(task, "dns: talloc_asprintf failed", true);
-			return;
+			return NT_STATUS_UNSUCCESSFUL;
 		}
 		status = cli_credentials_set_stored_principal(dns->server_credentials, task->lp_ctx, dns_spn);
 		if (!NT_STATUS_IS_OK(status)) {
@@ -874,7 +874,7 @@ static void dns_task_init(struct task_server *task)
 							      "despite finding it in the samdb! %s\n",
 							      nt_errstr(status)),
 					      true);
-			return;
+			return status;
 		}
 	} else {
 		TALLOC_FREE(dns_spn);
@@ -884,41 +884,42 @@ static void dns_task_init(struct task_server *task)
 					      talloc_asprintf(task, "Failed to obtain server credentials, perhaps a standalone server?: %s\n",
 							      nt_errstr(status)),
 					      true);
-			return;
+			return status;
 		}
 	}
 
 	dns->tkeys = tkey_store_init(dns, TKEY_BUFFER_SIZE);
 	if (!dns->tkeys) {
 		task_server_terminate(task, "Failed to allocate tkey storage\n", true);
-		return;
+		return NT_STATUS_NO_MEMORY;
 	}
 
 	status = dns_server_reload_zones(dns);
 	if (!NT_STATUS_IS_OK(status)) {
 		task_server_terminate(task, "dns: failed to load DNS zones", true);
-		return;
+		return status;
 	}
 
 	status = dns_startup_interfaces(dns, ifaces, task->model_ops);
 	if (!NT_STATUS_IS_OK(status)) {
 		task_server_terminate(task, "dns failed to setup interfaces", true);
-		return;
+		return status;
 	}
 
 	/* Setup the IRPC interface and register handlers */
 	status = irpc_add_name(task->msg_ctx, "dnssrv");
 	if (!NT_STATUS_IS_OK(status)) {
 		task_server_terminate(task, "dns: failed to register IRPC name", true);
-		return;
+		return status;
 	}
 
 	status = IRPC_REGISTER(task->msg_ctx, irpc, DNSSRV_RELOAD_DNS_ZONES,
 			       dns_reload_zones, dns);
 	if (!NT_STATUS_IS_OK(status)) {
 		task_server_terminate(task, "dns: failed to setup reload handler", true);
-		return;
+		return status;
 	}
+	return NT_STATUS_OK;
 }
 
 NTSTATUS server_service_dns_init(TALLOC_CTX *ctx)
@@ -926,6 +927,8 @@ NTSTATUS server_service_dns_init(TALLOC_CTX *ctx)
 	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
 		.inhibit_pre_fork = true,
+		.task_init = dns_task_init,
+		.post_fork = NULL
 	};
-	return register_server_service(ctx, "dns", dns_task_init, &details);
+	return register_server_service(ctx, "dns", &details);
 }
diff --git a/source4/dsdb/dns/dns_update.c b/source4/dsdb/dns/dns_update.c
index 08e7eb2224a..20052f4e47f 100644
--- a/source4/dsdb/dns/dns_update.c
+++ b/source4/dsdb/dns/dns_update.c
@@ -633,14 +633,14 @@ static NTSTATUS dnsupdate_dnsupdate_RODC(struct irpc_message *msg,
 /*
   startup the dns update task
 */
-static void dnsupdate_task_init(struct task_server *task)
+static NTSTATUS dnsupdate_task_init(struct task_server *task)
 {
 	NTSTATUS status;
 	struct dnsupdate_service *service;
 
 	if (lpcfg_server_role(task->lp_ctx) != ROLE_ACTIVE_DIRECTORY_DC) {
 		/* not useful for non-DC */
-		return;
+		return NT_STATUS_INVALID_DOMAIN_ROLE;
 	}
 
 	task_server_set_title(task, "task[dnsupdate]");
@@ -648,7 +648,7 @@ static void dnsupdate_task_init(struct task_server *task)
 	service = talloc_zero(task, struct dnsupdate_service);
 	if (!service) {
 		task_server_terminate(task, "dnsupdate_task_init: out of memory", true);
-		return;
+		return NT_STATUS_NO_MEMORY;
 	}
 	service->task		= task;
 	task->private_data	= service;
@@ -658,7 +658,7 @@ static void dnsupdate_task_init(struct task_server *task)
 		task_server_terminate(task,
 				      "dnsupdate: Failed to obtain server credentials\n",
 				      true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	service->samdb = samdb_connect(service,
@@ -670,7 +670,7 @@ static void dnsupdate_task_init(struct task_server *task)
 	if (!service->samdb) {
 		task_server_terminate(task, "dnsupdate: Failed to connect to local samdb\n",
 				      true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	service->confupdate.interval	= lpcfg_parm_int(task->lp_ctx, NULL,
@@ -685,7 +685,7 @@ static void dnsupdate_task_init(struct task_server *task)
 		task_server_terminate(task, talloc_asprintf(task,
 				      "dnsupdate: Failed to confupdate schedule: %s\n",
 							    nt_errstr(status)), true);
-		return;
+		return status;
 	}
 
 	dnsupdate_check_names(service);
@@ -694,7 +694,7 @@ static void dnsupdate_task_init(struct task_server *task)
 		task_server_terminate(task, talloc_asprintf(task,
 				      "dnsupdate: Failed to nameupdate schedule: %s\n",
 							    nt_errstr(status)), true);
-		return;
+		return status;
 	}
 
 	irpc_add_name(task->msg_ctx, "dnsupdate");
@@ -704,6 +704,7 @@ static void dnsupdate_task_init(struct task_server *task)
 
 	/* create the intial file */
 	dnsupdate_rebuild(service);
+	return NT_STATUS_OK;
 
 }
 
@@ -715,7 +716,8 @@ NTSTATUS server_service_dnsupdate_init(TALLOC_CTX *ctx)
 	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
 		.inhibit_pre_fork = true,
+		.task_init = dnsupdate_task_init,
+		.post_fork = NULL
 	};
-	return register_server_service(ctx, "dnsupdate", dnsupdate_task_init,
-				       &details);
+	return register_server_service(ctx, "dnsupdate", &details);
 }
diff --git a/source4/dsdb/kcc/kcc_service.c b/source4/dsdb/kcc/kcc_service.c
index e1bbae2abc1..4710d5bcdf5 100644
--- a/source4/dsdb/kcc/kcc_service.c
+++ b/source4/dsdb/kcc/kcc_service.c
@@ -266,7 +266,7 @@ static NTSTATUS kccsrv_replica_get_info(struct irpc_message *msg, struct drsuapi
 /*
   startup the kcc service task
 */
-static void kccsrv_task_init(struct task_server *task)
+static NTSTATUS kccsrv_task_init(struct task_server *task)
 {
 	WERROR status;
 	struct kccsrv_service *service;
@@ -275,10 +275,10 @@ static void kccsrv_task_init(struct task_server *task)
 	switch (lpcfg_server_role(task->lp_ctx)) {
 	case ROLE_STANDALONE:
 		task_server_terminate(task, "kccsrv: no KCC required in standalone configuration", false);
-		return;
+		return NT_STATUS_INVALID_DOMAIN_ROLE;
 	case ROLE_DOMAIN_MEMBER:
 		task_server_terminate(task, "kccsrv: no KCC required in domain member configuration", false);
-		return;
+		return NT_STATUS_INVALID_DOMAIN_ROLE;
 	case ROLE_ACTIVE_DIRECTORY_DC:
 		/* Yes, we want a KCC */
 		break;
@@ -289,7 +289,7 @@ static void kccsrv_task_init(struct task_server *task)
 	service = talloc_zero(task, struct kccsrv_service);
 	if (!service) {
 		task_server_terminate(task, "kccsrv_task_init: out of memory", true);
-		return;
+		return NT_STATUS_NO_MEMORY;
 	}
 	service->task		= task;
 	service->startup_time	= timeval_current();
@@ -301,7 +301,7 @@ static void kccsrv_task_init(struct task_server *task)
 				      talloc_asprintf(task,
 						      "kccsrv: Failed to obtain server credentials: %s\n",
 						      win_errstr(status)), true);
-		return;
+		return werror_to_ntstatus(status);
 	}
 
 	status = kccsrv_connect_samdb(service, task->lp_ctx);
@@ -309,7 +309,7 @@ static void kccsrv_task_init(struct task_server *task)
 		task_server_terminate(task, talloc_asprintf(task,
 				      "kccsrv: Failed to connect to local samdb: %s\n",
 							    win_errstr(status)), true);
-		return;
+		return werror_to_ntstatus(status);
 	}
 
 	status = kccsrv_load_partitions(service);
@@ -317,7 +317,7 @@ static void kccsrv_task_init(struct task_server *task)
 		task_server_terminate(task, talloc_asprintf(task,
 				      "kccsrv: Failed to load partitions: %s\n",
 							    win_errstr(status)), true);
-		return;
+		return werror_to_ntstatus(status);
 	}
 
 	periodic_startup_interval =
@@ -338,13 +338,14 @@ static void kccsrv_task_init(struct task_server *task)
 		task_server_terminate(task, talloc_asprintf(task,
 				      "kccsrv: Failed to periodic schedule: %s\n",
 							    win_errstr(status)), true);
-		return;
+		return werror_to_ntstatus(status);
 	}
 
 	irpc_add_name(task->msg_ctx, "kccsrv");
 
 	IRPC_REGISTER(task->msg_ctx, drsuapi, DRSUAPI_DSEXECUTEKCC, kccsrv_execute_kcc, service);
 	IRPC_REGISTER(task->msg_ctx, drsuapi, DRSUAPI_DSREPLICAGETINFO, kccsrv_replica_get_info, service);
+	return NT_STATUS_OK;
 }
 
 /*
@@ -354,7 +355,9 @@ NTSTATUS server_service_kcc_init(TALLOC_CTX *ctx)
 {
 	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
-		.inhibit_pre_fork = true
+		.inhibit_pre_fork = true,
+		.task_init = kccsrv_task_init,
+		.post_fork = NULL
 	};
-	return register_server_service(ctx, "kcc", kccsrv_task_init, &details);
+	return register_server_service(ctx, "kcc", &details);
 }
diff --git a/source4/dsdb/repl/drepl_service.c b/source4/dsdb/repl/drepl_service.c
index 9789e784a13..350ed611aea 100644
--- a/source4/dsdb/repl/drepl_service.c
+++ b/source4/dsdb/repl/drepl_service.c
@@ -428,7 +428,7 @@ static NTSTATUS dreplsrv_replica_mod(struct irpc_message *msg,
 /*
   startup the dsdb replicator service task
 */
-static void dreplsrv_task_init(struct task_server *task)
+static NTSTATUS dreplsrv_task_init(struct task_server *task)
 {
 	WERROR status;
 	struct dreplsrv_service *service;
@@ -438,11 +438,11 @@ static void dreplsrv_task_init(struct task_server *task)
 	case ROLE_STANDALONE:
 		task_server_terminate(task, "dreplsrv: no DSDB replication required in standalone configuration",
 				      false);
-		return;
+		return NT_STATUS_INVALID_DOMAIN_ROLE;
 	case ROLE_DOMAIN_MEMBER:
 		task_server_terminate(task, "dreplsrv: no DSDB replication required in domain member configuration",
 				      false);
-		return;
+		return NT_STATUS_INVALID_DOMAIN_ROLE;
 	case ROLE_ACTIVE_DIRECTORY_DC:
 		/* Yes, we want DSDB replication */
 		break;
@@ -453,7 +453,7 @@ static void dreplsrv_task_init(struct task_server *task)
 	service = talloc_zero(task, struct dreplsrv_service);
 	if (!service) {
 		task_server_terminate(task, "dreplsrv_task_init: out of memory", true);
-		return;
+		return NT_STATUS_NO_MEMORY;
 	}
 	service->task		= task;
 	service->startup_time	= timeval_current();
@@ -464,7 +464,7 @@ static void dreplsrv_task_init(struct task_server *task)
 		task_server_terminate(task, talloc_asprintf(task,
 				      "dreplsrv: Failed to obtain server credentials: %s\n",
 							    win_errstr(status)), true);
-		return;
+		return werror_to_ntstatus(status);
 	}
 
 	status = dreplsrv_connect_samdb(service, task->lp_ctx);
@@ -472,7 +472,7 @@ static void dreplsrv_task_init(struct task_server *task)
 		task_server_terminate(task, talloc_asprintf(task,
 				      "dreplsrv: Failed to connect to local samdb: %s\n",
 							    win_errstr(status)), true);
-		return;
+		return werror_to_ntstatus(status);
 	}
 
 	status = dreplsrv_load_partitions(service);
@@ -480,7 +480,7 @@ static void dreplsrv_task_init(struct task_server *task)
 		task_server_terminate(task, talloc_asprintf(task,
 				      "dreplsrv: Failed to load partitions: %s\n",
 							    win_errstr(status)), true);
-		return;
+		return werror_to_ntstatus(status);
 	}
 
 	periodic_startup_interval	= lpcfg_parm_int(task->lp_ctx, NULL, "dreplsrv", "periodic_startup_interval", 15); /* in seconds */
@@ -491,7 +491,7 @@ static void dreplsrv_task_init(struct task_server *task)
 		task_server_terminate(task, talloc_asprintf(task,
 				      "dreplsrv: Failed to periodic schedule: %s\n",
 							    win_errstr(status)), true);
-		return;
+		return werror_to_ntstatus(status);
 	}
 
 	service->pending.im = tevent_create_immediate(service);
@@ -500,7 +500,7 @@ static void dreplsrv_task_init(struct task_server *task)
 				      "dreplsrv: Failed to create immediate "
 				      "task for future DsReplicaSync\n",
 				      true);
-		return;
+		return NT_STATUS_NO_MEMORY;
 	}
 
 	/* if we are a RODC then we do not send DSReplicaSync*/
@@ -512,7 +512,7 @@ static void dreplsrv_task_init(struct task_server *task)
 			task_server_terminate(task, talloc_asprintf(task,
 						  "dreplsrv: Failed to setup notify schedule: %s\n",
 									win_errstr(status)), true);
-			return;
+			return werror_to_ntstatus(status);
 		}
 	}
 
@@ -526,6 +526,8 @@ static void dreplsrv_task_init(struct task_server *task)
 	IRPC_REGISTER(task->msg_ctx, irpc, DREPL_TAKEFSMOROLE, drepl_take_FSMO_role, service);
 	IRPC_REGISTER(task->msg_ctx, irpc, DREPL_TRIGGER_REPL_SECRET, drepl_trigger_repl_secret, service);
 	imessaging_register(task->msg_ctx, service, MSG_DREPL_ALLOCATE_RID, dreplsrv_allocate_rid);
+
+	return NT_STATUS_OK;
 }
 
 /*
@@ -536,7 +538,8 @@ NTSTATUS server_service_drepl_init(TALLOC_CTX *ctx)
 	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
 		.inhibit_pre_fork = true,
+		.task_init = dreplsrv_task_init,
+		.post_fork = NULL,
 	};
-	return register_server_service(ctx, "drepl",  dreplsrv_task_init,
-				       &details);
+	return register_server_service(ctx, "drepl", &details);
 }
diff --git a/source4/echo_server/echo_server.c b/source4/echo_server/echo_server.c
index 657180f760c..f38999ae139 100644
--- a/source4/echo_server/echo_server.c
+++ b/source4/echo_server/echo_server.c
@@ -265,7 +265,7 @@ static NTSTATUS echo_startup_interfaces(struct echo_server *echo,
 
 /* Do the basic task initialization, check if the task should run */
 
-static void echo_task_init(struct task_server *task)
+static NTSTATUS echo_task_init(struct task_server *task)
 {
 	struct interface *ifaces;
 	struct echo_server *echo;
@@ -282,7 +282,7 @@ static void echo_task_init(struct task_server *task)
 	case ROLE_DOMAIN_MEMBER:
 		task_server_terminate(task, "echo: Not starting echo server " \
 				      "for domain members", false);
-		return;
+		return NT_STATUS_INVALID_DOMAIN_ROLE;
 	case ROLE_ACTIVE_DIRECTORY_DC:
 		/* Yes, we want to run the echo server */
 		break;
@@ -294,7 +294,7 @@ static void echo_task_init(struct task_server *task)
 		task_server_terminate(task,
 				      "echo: No network interfaces configured",
 				      false);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	task_server_set_title(task, "task[echo]");
@@ -302,7 +302,7 @@ static void echo_task_init(struct task_server *task)
 	echo = talloc_zero(task, struct echo_server);
 	if (echo == NULL) {
 		task_server_terminate(task, "echo: Out of memory", true);
-		return;
+		return NT_STATUS_NO_MEMORY;
 	}
 
 	echo->task = task;
@@ -312,8 +312,9 @@ static void echo_task_init(struct task_server *task)
 	if (!NT_STATUS_IS_OK(status)) {
 		task_server_terminate(task, "echo: Failed to set up interfaces",
 				      true);
-		return;
+		return status;
 	}
+	return NT_STATUS_OK;
 }
 
 /*
@@ -326,7 +327,10 @@ NTSTATUS server_service_echo_init(TALLOC_CTX *ctx)
 {
 	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
-		.inhibit_pre_fork = true
+		.inhibit_pre_fork = true,
+		.task_init = echo_task_init,
+		.post_fork = NULL
+
 	};
-	return register_server_service(ctx, "echo", echo_task_init, &details);
+	return register_server_service(ctx, "echo", &details);
 }
diff --git a/source4/kdc/kdc-heimdal.c b/source4/kdc/kdc-heimdal.c
index 8f09c41d74d..3beff5d95da 100644
--- a/source4/kdc/kdc-heimdal.c
+++ b/source4/kdc/kdc-heimdal.c
@@ -261,7 +261,7 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
 /*
   startup the kdc task
 */
-static void kdc_task_init(struct task_server *task)
+static NTSTATUS kdc_task_init(struct task_server *task)
 {
 	struct kdc_server *kdc;
 	krb5_kdc_configuration *kdc_config = NULL;
@@ -273,14 +273,14 @@ static void kdc_task_init(struct task_server *task)
 	switch (lpcfg_server_role(task->lp_ctx)) {
 	case ROLE_STANDALONE:
 		task_server_terminate(task, "kdc: no KDC required in standalone configuration", false);
-		return;
+		return NT_STATUS_INVALID_DOMAIN_ROLE;
 	case ROLE_DOMAIN_MEMBER:
 		task_server_terminate(task, "kdc: no KDC required in member server configuration", false);
-		return;
+		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);
-		return;
+		return NT_STATUS_INVALID_DOMAIN_ROLE;
 	case ROLE_ACTIVE_DIRECTORY_DC:
 		/* Yes, we want a KDC */
 		break;
@@ -290,7 +290,7 @@ static void kdc_task_init(struct task_server *task)
 
 	if (iface_list_count(ifaces) == 0) {
 		task_server_terminate(task, "kdc: no network interfaces configured", false);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	task_server_set_title(task, "task[kdc]");
@@ -298,7 +298,7 @@ static void kdc_task_init(struct task_server *task)
 	kdc = talloc_zero(task, struct kdc_server);
 	if (kdc == NULL) {
 		task_server_terminate(task, "kdc: out of memory", true);
-		return;
+		return NT_STATUS_NO_MEMORY;
 	}
 
 	kdc->task = task;
@@ -314,7 +314,7 @@ static void kdc_task_init(struct task_server *task)
 	if (!kdc->samdb) {
 		DEBUG(1,("kdc_task_init: unable to connect to samdb\n"));
 		task_server_terminate(task, "kdc: krb5_init_context samdb connect failed", true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	ldb_ret = samdb_rodc(kdc->samdb, &kdc->am_rodc);
@@ -322,7 +322,7 @@ static void kdc_task_init(struct task_server *task)
 		DEBUG(1, ("kdc_task_init: Cannot determine if we are an RODC: %s\n",
 			  ldb_errstring(kdc->samdb)));
 		task_server_terminate(task, "kdc: krb5_init_context samdb RODC connect failed", true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	kdc->proxy_timeout = lpcfg_parm_int(kdc->task->lp_ctx, NULL, "kdc", "proxy timeout", 5);
@@ -334,7 +334,7 @@ static void kdc_task_init(struct task_server *task)
 		DEBUG(1,("kdc_task_init: krb5_init_context failed (%s)\n",
 			 error_message(ret)));
 		task_server_terminate(task, "kdc: krb5_init_context failed", true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	krb5_add_et_list(kdc->smb_krb5_context->krb5_context, initialize_hdb_error_table_r);
@@ -343,14 +343,14 @@ static void kdc_task_init(struct task_server *task)
 				  &kdc_config);
 	if(ret) {
 		task_server_terminate(task, "kdc: failed to get KDC configuration", true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	kdc_config->logf = (krb5_log_facility *)kdc->smb_krb5_context->pvt_log_data;
 	kdc_config->db = talloc(kdc, struct HDB *);
 	if (!kdc_config->db) {
 		task_server_terminate(task, "kdc: out of memory", true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 	kdc_config->num_db = 1;
 
@@ -382,7 +382,7 @@ static void kdc_task_init(struct task_server *task)
 	kdc->base_ctx = talloc_zero(kdc, struct samba_kdc_base_context);
 	if (!kdc->base_ctx) {
 		task_server_terminate(task, "kdc: out of memory", true);
-		return;
+		return NT_STATUS_NO_MEMORY;
 	}
 
 	kdc->base_ctx->ev_ctx = task->event_ctx;
@@ -394,7 +394,7 @@ static void kdc_task_init(struct task_server *task)
 				       &kdc_config->db[0]);
 	if (!NT_STATUS_IS_OK(status)) {
 		task_server_terminate(task, "kdc: hdb_samba4_create_kdc (setup KDC database) failed", true);
-		return;
+		return status;
 	}
 
 	ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context,
@@ -402,13 +402,13 @@ static void kdc_task_init(struct task_server *task)
 				   &hdb_samba4_interface);
 	if(ret) {
 		task_server_terminate(task, "kdc: failed to register hdb plugin", true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	ret = krb5_kt_register(kdc->smb_krb5_context->krb5_context, &hdb_kt_ops);
 	if(ret) {
 		task_server_terminate(task, "kdc: failed to register keytab plugin", true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	kdc->keytab_name = talloc_asprintf(kdc, "HDB:samba4&%p", kdc->base_ctx);
@@ -416,7 +416,7 @@ static void kdc_task_init(struct task_server *task)
 		task_server_terminate(task,
 				      "kdc: Failed to set keytab name",
 				      true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	/* Register WinDC hooks */
@@ -425,21 +425,21 @@ static void kdc_task_init(struct task_server *task)
 				   &windc_plugin_table);
 	if(ret) {
 		task_server_terminate(task, "kdc: failed to register windc plugin", true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	ret = krb5_kdc_windc_init(kdc->smb_krb5_context->krb5_context);
 
 	if(ret) {
 		task_server_terminate(task, "kdc: failed to init windc plugin", true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	ret = krb5_kdc_pkinit_config(kdc->smb_krb5_context->krb5_context, kdc_config);
 
 	if(ret) {
 		task_server_terminate(task, "kdc: failed to init kdc pkinit subsystem", true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 	kdc->private_data = kdc_config;
 
@@ -448,17 +448,19 @@ static void kdc_task_init(struct task_server *task)
 					task->model_ops);
 	if (!NT_STATUS_IS_OK(status)) {
 		task_server_terminate(task, "kdc failed to setup interfaces", true);
-		return;
+		return status;
 	}
 
 	status = IRPC_REGISTER(task->msg_ctx, irpc, KDC_CHECK_GENERIC_KERBEROS,
 			       kdc_check_generic_kerberos, kdc);
 	if (!NT_STATUS_IS_OK(status)) {
 		task_server_terminate(task, "kdc failed to setup monitoring", true);
-		return;
+		return status;
 	}
 
 	irpc_add_name(task->msg_ctx, "kdc_server");
+
+	return NT_STATUS_OK;
 }
 
 
@@ -478,7 +480,9 @@ NTSTATUS server_service_kdc_init(TALLOC_CTX *ctx)
 		 * the master process is responsible for managing the worker
 		 * processes not performing work.
 		 */
-		.inhibit_pre_fork = true
+		.inhibit_pre_fork = true,
+		.task_init = kdc_task_init,
+		.post_fork = NULL
 	};
-	return register_server_service(ctx, "kdc", kdc_task_init, &details);
+	return register_server_service(ctx, "kdc", &details);
 }
diff --git a/source4/kdc/kdc-service-mit.c b/source4/kdc/kdc-service-mit.c
index 5d111ee82d2..8ae1c219dc7 100644
--- a/source4/kdc/kdc-service-mit.c
+++ b/source4/kdc/kdc-service-mit.c
@@ -365,8 +365,9 @@ NTSTATUS server_service_mitkdc_init(TALLOC_CTX *mem_ctx)
 		 * the master process is responsible for managing the worker
 		 * processes not performing work.
 		 */
-		.inhibit_pre_fork = true
+		.inhibit_pre_fork = true,
+		.task_init = mitkdc_task_init,
+		.post_fork = NULL
 	};
-	return register_server_service(mem_ctx, "kdc", mitkdc_task_init,
-				       &details);
+	return register_server_service(mem_ctx, "kdc", &details);
 }
diff --git a/source4/ldap_server/ldap_server.c b/source4/ldap_server/ldap_server.c
index 5b1db0c109a..f6329f05c5a 100644
--- a/source4/ldap_server/ldap_server.c
+++ b/source4/ldap_server/ldap_server.c
@@ -1122,7 +1122,7 @@ static NTSTATUS add_socket(struct task_server *task,
 /*
   open the ldap server sockets
 */
-static void ldapsrv_task_init(struct task_server *task)
+static NTSTATUS ldapsrv_task_init(struct task_server *task)
 {	
 	char *ldapi_path;
 #ifdef WITH_LDAPI_PRIV_SOCKET
@@ -1136,11 +1136,11 @@ static void ldapsrv_task_init(struct task_server *task)
 	case ROLE_STANDALONE:
 		task_server_terminate(task, "ldap_server: no LDAP server required in standalone configuration", 
 				      false);
-		return;
+		return NT_STATUS_INVALID_DOMAIN_ROLE;
 	case ROLE_DOMAIN_MEMBER:
 		task_server_terminate(task, "ldap_server: no LDAP server required in member server configuration", 
 				      false);
-		return;
+		return NT_STATUS_INVALID_DOMAIN_ROLE;
 	case ROLE_ACTIVE_DIRECTORY_DC:
 		/* Yes, we want an LDAP server */
 		break;
@@ -1149,14 +1149,20 @@ static void ldapsrv_task_init(struct task_server *task)
 	task_server_set_title(task, "task[ldapsrv]");
 
 	ldap_service = talloc_zero(task, struct ldapsrv_service);
-	if (ldap_service == NULL) goto failed;
+	if (ldap_service == NULL) {
+		status = NT_STATUS_NO_MEMORY;
+		goto failed;
+	}
 
 	ldap_service->task = task;
 
 	dns_host_name = talloc_asprintf(ldap_service, "%s.%s",
 					lpcfg_netbios_name(task->lp_ctx),
 					lpcfg_dnsdomain(task->lp_ctx));
-	if (dns_host_name == NULL) goto failed;
+	if (dns_host_name == NULL) {
+		status = NT_STATUS_NO_MEMORY;
+		goto failed;
+	}
 
 	status = tstream_tls_params_server(ldap_service,
 					   dns_host_name,
@@ -1175,7 +1181,10 @@ static void ldapsrv_task_init(struct task_server *task)
 	}
 
 	ldap_service->call_queue = tevent_queue_create(ldap_service, "ldapsrv_call_queue");
-	if (ldap_service->call_queue == NULL) goto failed;
+	if (ldap_service->call_queue == NULL) {
+		status = NT_STATUS_NO_MEMORY;
+		goto failed;
+	}
 
 	if (lpcfg_interfaces(task->lp_ctx) && lpcfg_bind_interfaces_only(task->lp_ctx)) {
 		struct interface *ifaces;
@@ -1202,6 +1211,7 @@ static void ldapsrv_task_init(struct task_server *task)
 		wcard = iface_list_wildcard(task);
 		if (wcard == NULL) {
 			DEBUG(0,("No wildcard addresses available\n"));
+			status = NT_STATUS_UNSUCCESSFUL;
 			goto failed;
 		}
 		for (i=0; wcard[i]; i++) {
@@ -1213,12 +1223,14 @@ static void ldapsrv_task_init(struct task_server *task)
 		}
 		talloc_free(wcard);
 		if (num_binds == 0) {
+			status = NT_STATUS_UNSUCCESSFUL;
 			goto failed;
 		}
 	}
 
 	ldapi_path = lpcfg_private_path(ldap_service, task->lp_ctx, "ldapi");
 	if (!ldapi_path) {
+		status = NT_STATUS_UNSUCCESSFUL;
 		goto failed;
 	}
 
@@ -1236,6 +1248,7 @@ static void ldapsrv_task_init(struct task_server *task)
 #ifdef WITH_LDAPI_PRIV_SOCKET
 	priv_dir = lpcfg_private_path(ldap_service, task->lp_ctx, "ldap_priv");
 	if (priv_dir == NULL) {
+		status = NT_STATUS_UNSUCCESSFUL;
 		goto failed;
 	}
 	/*
@@ -1245,11 +1258,12 @@ static void ldapsrv_task_init(struct task_server *task)
 	if (!directory_create_or_exist(priv_dir, 0750)) {
 		task_server_terminate(task, "Cannot create ldap "
 				      "privileged ldapi directory", true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 	ldapi_path = talloc_asprintf(ldap_service, "%s/ldapi", priv_dir);
 	talloc_free(priv_dir);
 	if (ldapi_path == NULL) {
+		status = NT_STATUS_NO_MEMORY;
 		goto failed;
 	}
 
@@ -1269,10 +1283,11 @@ static void ldapsrv_task_init(struct task_server *task)
 
 	/* register the server */
 	irpc_add_name(task->msg_ctx, "ldap_server");
-	return;
+	return NT_STATUS_OK;
 
 failed:
 	task_server_terminate(task, "Failed to startup ldap server task", true);
+	return status;
 }
 
 
@@ -1280,8 +1295,9 @@ NTSTATUS server_service_ldap_init(TALLOC_CTX *ctx)
 {
 	static const struct service_details details = {
 		.inhibit_fork_on_accept = false,
-		.inhibit_pre_fork = false
+		.inhibit_pre_fork = false,
+		.task_init = ldapsrv_task_init,
+		.post_fork = NULL
 	};
-	return register_server_service(ctx, "ldap", ldapsrv_task_init,
-				       &details);
+	return register_server_service(ctx, "ldap", &details);
 }
diff --git a/source4/nbt_server/nbt_server.c b/source4/nbt_server/nbt_server.c
index 84cd507fe13..00c255cf0d3 100644
--- a/source4/nbt_server/nbt_server.c
+++ b/source4/nbt_server/nbt_server.c
@@ -35,7 +35,7 @@ NTSTATUS server_service_nbtd_init(TALLOC_CTX *);
 /*
   startup the nbtd task
 */
-static void nbtd_task_init(struct task_server *task)
+static NTSTATUS nbtd_task_init(struct task_server *task)
 {
 	struct nbtd_server *nbtsrv;
 	NTSTATUS status;
@@ -45,12 +45,12 @@ static void nbtd_task_init(struct task_server *task)
 
 	if (iface_list_count(ifaces) == 0) {
 		task_server_terminate(task, "nbtd: no network interfaces configured", false);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	if (lpcfg_disable_netbios(task->lp_ctx)) {
 		task_server_terminate(task, "nbtd: 'disable netbios = yes' set in smb.conf, shutting down nbt server", false);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	task_server_set_title(task, "task[nbtd]");
@@ -58,7 +58,7 @@ static void nbtd_task_init(struct task_server *task)
 	nbtsrv = talloc(task, struct nbtd_server);
 	if (nbtsrv == NULL) {
 		task_server_terminate(task, "nbtd: out of memory", true);
-		return;
+		return NT_STATUS_NO_MEMORY;
 	}
 
 	nbtsrv->task            = task;
@@ -70,7 +70,7 @@ static void nbtd_task_init(struct task_server *task)
 	status = nbtd_startup_interfaces(nbtsrv, task->lp_ctx, ifaces);
 	if (!NT_STATUS_IS_OK(status)) {
 		task_server_terminate(task, "nbtd failed to setup interfaces", true);
-		return;
+		return status;
 	}
 
 	nbtsrv->sam_ctx = samdb_connect(nbtsrv,
@@ -81,14 +81,14 @@ static void nbtd_task_init(struct task_server *task)
 					0);
 	if (nbtsrv->sam_ctx == NULL) {
 		task_server_terminate(task, "nbtd failed to open samdb", true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	/* start the WINS server, if appropriate */
 	status = nbtd_winsserver_init(nbtsrv);
 	if (!NT_STATUS_IS_OK(status)) {
 		task_server_terminate(task, "nbtd failed to start WINS server", true);
-		return;
+		return status;
 	}
 
 	nbtd_register_irpc(nbtsrv);
@@ -97,6 +97,8 @@ static void nbtd_task_init(struct task_server *task)
 	nbtd_register_names(nbtsrv);
 
 	irpc_add_name(task->msg_ctx, "nbt_server");
+
+	return NT_STATUS_OK;
 }
 
 
@@ -107,7 +109,9 @@ NTSTATUS server_service_nbtd_init(TALLOC_CTX *ctx)
 {
 	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
-		.inhibit_pre_fork = true
+		.inhibit_pre_fork = true,
+		.task_init = nbtd_task_init,
+		.post_fork = NULL
 	};
-	return register_server_service(ctx, "nbt", nbtd_task_init, &details);
+	return register_server_service(ctx, "nbt", &details);
 }
diff --git a/source4/ntp_signd/ntp_signd.c b/source4/ntp_signd/ntp_signd.c
index a392929c78b..5999bf81540 100644
--- a/source4/ntp_signd/ntp_signd.c
+++ b/source4/ntp_signd/ntp_signd.c
@@ -489,7 +489,7 @@ static const struct stream_server_ops ntp_signd_stream_ops = {
 /*
   startup the ntp_signd task
 */
-static void ntp_signd_task_init(struct task_server *task)
+static NTSTATUS ntp_signd_task_init(struct task_server *task)
 {
 	struct ntp_signd_server *ntp_signd;
 	NTSTATUS status;
@@ -501,7 +501,7 @@ static void ntp_signd_task_init(struct task_server *task)
 					      lpcfg_ntp_signd_socket_directory(task->lp_ctx));
 		task_server_terminate(task,
 				      error, true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	task_server_set_title(task, "task[ntp_signd]");
@@ -509,7 +509,7 @@ static void ntp_signd_task_init(struct task_server *task)
 	ntp_signd = talloc(task, struct ntp_signd_server);
 	if (ntp_signd == NULL) {
 		task_server_terminate(task, "ntp_signd: out of memory", true);
-		return;
+		return NT_STATUS_NO_MEMORY;
 	}
 
 	ntp_signd->task = task;
@@ -523,10 +523,15 @@ static void ntp_signd_task_init(struct task_server *task)
 					 0);
 	if (ntp_signd->samdb == NULL) {
 		task_server_terminate(task, "ntp_signd failed to open samdb", true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	address = talloc_asprintf(ntp_signd, "%s/socket", lpcfg_ntp_signd_socket_directory(task->lp_ctx));
+	if (address == NULL) {
+		task_server_terminate(
+		    task, "ntp_signd out of memory in talloc_asprintf()", true);
+		return NT_STATUS_NO_MEMORY;
+	}
 
 	status = stream_setup_socket(ntp_signd->task,
 				     ntp_signd->task->event_ctx,
@@ -540,9 +545,11 @@ static void ntp_signd_task_init(struct task_server *task)
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0,("Failed to bind to %s - %s\n",
 			 address, nt_errstr(status)));
-		return;
+		return status;
 	}
 
+	return NT_STATUS_OK;
+
 }
 
 
@@ -551,8 +558,9 @@ NTSTATUS server_service_ntp_signd_init(TALLOC_CTX *ctx)
 {
 	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
-		.inhibit_pre_fork = true
+		.inhibit_pre_fork = true,
+		.task_init = ntp_signd_task_init,
+		.post_fork = NULL
 	};
-	return register_server_service(ctx, "ntp_signd", ntp_signd_task_init,
-				       &details);
+	return register_server_service(ctx, "ntp_signd", &details);
 }
diff --git a/source4/rpc_server/service_rpc.c b/source4/rpc_server/service_rpc.c
index f7d1a9f3c7d..07d6f700687 100644
--- a/source4/rpc_server/service_rpc.c
+++ b/source4/rpc_server/service_rpc.c
@@ -44,9 +44,9 @@ NTSTATUS server_service_rpc_init(TALLOC_CTX *);
 /*
   open the dcerpc server sockets
 */
-static void dcesrv_task_init(struct task_server *task)
+static NTSTATUS dcesrv_task_init(struct task_server *task)
 {
-	NTSTATUS status;
+	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
 	struct dcesrv_context *dce_ctx;
 	struct dcesrv_endpoint *e;
 	const struct model_ops *single_model_ops;
@@ -135,9 +135,10 @@ static void dcesrv_task_init(struct task_server *task)
 	}
 
 	irpc_add_name(task->msg_ctx, "rpc_server");
-	return;
+	return NT_STATUS_OK;
 failed:
 	task_server_terminate(task, "Failed to startup dcerpc server task", true);	
+	return status;
 }
 
 NTSTATUS server_service_rpc_init(TALLOC_CTX *ctx)
@@ -151,7 +152,9 @@ NTSTATUS server_service_rpc_init(TALLOC_CTX *ctx)
 		 * mode by defult to get a forking NETLOGON server
 		 */
 		.inhibit_fork_on_accept = false,
-		.inhibit_pre_fork = true
+		.inhibit_pre_fork = true,
+		.task_init = dcesrv_task_init,
+		.post_fork = NULL
 	};
-	return register_server_service(ctx, "rpc", dcesrv_task_init, &details);
+	return register_server_service(ctx, "rpc", &details);
 }
diff --git a/source4/smb_server/service_smb.c b/source4/smb_server/service_smb.c
index bea7eb9285b..37e8a61afb5 100644
--- a/source4/smb_server/service_smb.c
+++ b/source4/smb_server/service_smb.c
@@ -38,9 +38,9 @@
 /*
   open the smb server sockets
 */
-static void smbsrv_task_init(struct task_server *task)
+static NTSTATUS smbsrv_task_init(struct task_server *task)
 {	
-	NTSTATUS status;
+	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
 
 	task_server_set_title(task, "task[smbsrv]");
 
@@ -72,6 +72,7 @@ static void smbsrv_task_init(struct task_server *task)
 		wcard = iface_list_wildcard(task);
 		if (wcard == NULL) {
 			DEBUG(0,("No wildcard addresses available\n"));
+			status = NT_STATUS_UNSUCCESSFUL;
 			goto failed;
 		}
 		for (i=0; wcard[i]; i++) {
@@ -86,9 +87,10 @@ static void smbsrv_task_init(struct task_server *task)
 	}
 
 	irpc_add_name(task->msg_ctx, "smb_server");
-	return;
+	return NT_STATUS_OK;
 failed:
 	task_server_terminate(task, "Failed to startup smb server task", true);	
+	return status;
 }
 
 /* called at smbd startup - register ourselves as a server service */
@@ -96,9 +98,11 @@ NTSTATUS server_service_smb_init(TALLOC_CTX *ctx)
 {
 	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
-		.inhibit_pre_fork = true
+		.inhibit_pre_fork = true,
+		.task_init = smbsrv_task_init,
+		.post_fork = NULL
 	};
 	ntvfs_init(cmdline_lp_ctx);
 	share_init();
-	return register_server_service(ctx, "smb", smbsrv_task_init, &details);
+	return register_server_service(ctx, "smb", &details);
 }
diff --git a/source4/smbd/process_model.h b/source4/smbd/process_model.h
index 656a7f2e29c..17d70254cf2 100644
--- a/source4/smbd/process_model.h
+++ b/source4/smbd/process_model.h
@@ -58,7 +58,7 @@ struct model_ops {
 	void (*new_task)(struct tevent_context *, 
 			 struct loadparm_context *lp_ctx,
 			 const char *service_name,
-			 void (*)(struct tevent_context *, 
+			 struct task_server * (*)(struct tevent_context *,
 				  struct loadparm_context *, struct server_id, 
 				  void *, void *),
 			 void *,
diff --git a/source4/smbd/process_prefork.c b/source4/smbd/process_prefork.c
index f6fb80b986d..788aa976390 100644
--- a/source4/smbd/process_prefork.c
+++ b/source4/smbd/process_prefork.c
@@ -227,7 +227,7 @@ static void prefork_new_task(
 	struct tevent_context *ev,
 	struct loadparm_context *lp_ctx,
 	const char *service_name,
-	void (*new_task_fn)(struct tevent_context *,
+	struct task_server *(*new_task_fn)(struct tevent_context *,
 			    struct loadparm_context *lp_ctx,
 			    struct server_id , void *, void *),
 	void *private_data,
@@ -239,6 +239,7 @@ static void prefork_new_task(
 	int i, num_children;
 
 	struct tevent_context *ev2;
+	struct task_server *task = NULL;
 
 	t = tfork_create();
 	if (t == NULL) {
@@ -277,8 +278,14 @@ static void prefork_new_task(
 	setup_handlers(ev, from_parent_fd);
 
 	if (service_details->inhibit_pre_fork) {
-		new_task_fn(ev, lp_ctx, cluster_id(pid, 0), private_data, NULL);
-		/* The task does not support pre-fork */
+		task = new_task_fn(
+		    ev, lp_ctx, cluster_id(pid, 0), private_data, NULL);
+		/*
+		 * The task does not support pre-fork
+		 */
+		if (task != NULL && service_details->post_fork != NULL) {
+			service_details->post_fork(task);
+		}
 		tevent_loop_wait(ev);
 		TALLOC_FREE(ev);
 		exit(0);
@@ -298,7 +305,12 @@ static void prefork_new_task(
 	 * process accepting and handling requests, it's responsible for
 	 * monitoring and controlling the child work processes.
 	 */
-	new_task_fn(ev2, lp_ctx, cluster_id(pid, 0), private_data, NULL);
+	task = new_task_fn(ev2, lp_ctx, cluster_id(pid, 0), private_data, NULL);
+	if (task == NULL) {
+		TALLOC_FREE(ev);
+		TALLOC_FREE(ev2);
+		exit(0);
+	}
 
 	{
 		int default_children;
@@ -313,7 +325,9 @@ static void prefork_new_task(
 	}
 	DBG_NOTICE("Forking %d %s worker processes\n",
 		   num_children, service_name);
-	/* We are now free to spawn some worker processes */
+	/*
+	 * We are now free to spawn some worker processes
+	 */
 	for (i=0; i < num_children; i++) {
 		struct tfork* w = NULL;
 
@@ -335,7 +349,9 @@ static void prefork_new_task(
 			}
 			tevent_fd_set_auto_close(fde);
 		} else {
-			/* tfork uses malloc */
+			/*
+			 * tfork uses malloc
+			 */
 			free(w);
 
 			TALLOC_FREE(ev);
@@ -343,6 +359,9 @@ static void prefork_new_task(
 				     service_name);
 			prefork_reload_after_fork();
 			setup_handlers(ev2, from_parent_fd);
+			if (service_details->post_fork != NULL) {
+				service_details->post_fork(task);
+			}
 			tevent_loop_wait(ev2);
 			talloc_free(ev2);
 			exit(0);
diff --git a/source4/smbd/process_single.c b/source4/smbd/process_single.c
index 1859c96809e..242622b3b8f 100644
--- a/source4/smbd/process_single.c
+++ b/source4/smbd/process_single.c
@@ -92,7 +92,7 @@ static void single_accept_connection(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 task_server *(*new_task)(struct tevent_context *,
 				             struct loadparm_context *,
 					     struct server_id, void *, void *),
 			    void *private_data,
@@ -102,7 +102,7 @@ static void single_new_task(struct tevent_context *ev,
 	pid_t pid = getpid();
 	/* start our taskids at MAX_INT32, the first 2^31 tasks are is reserved for fd numbers */
 	static uint32_t taskid = INT32_MAX;
-       
+	struct task_server *task = NULL;
 	/*
 	 * We use the PID so we cannot collide in with cluster ids
 	 * generated in other single mode tasks, and, and won't
@@ -112,7 +112,10 @@ static void single_new_task(struct tevent_context *ev,
 	 * Using the pid unaltered makes debugging of which process
 	 * owns the messaging socket easier.
 	 */
-	new_task(ev, lp_ctx, cluster_id(pid, taskid++), private_data, NULL);
+	task = new_task(ev, lp_ctx, cluster_id(pid, taskid++), private_data, NULL);
+	if (task != NULL && service_details->post_fork != NULL) {
+		service_details->post_fork(task);
+	}
 }
 
 
diff --git a/source4/smbd/process_standard.c b/source4/smbd/process_standard.c
index 677345f2c83..62620096af5 100644
--- a/source4/smbd/process_standard.c
+++ b/source4/smbd/process_standard.c
@@ -393,7 +393,7 @@ static void standard_accept_connection(
 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 *),
+			      struct task_server *(*new_task)(struct tevent_context *, struct loadparm_context *lp_ctx, struct server_id , void *, void *),
 			      void *private_data,
 			      const struct service_details *service_details,
 			      int from_parent_fd)
@@ -404,6 +404,7 @@ static void standard_new_task(struct tevent_context *ev,
 	struct tevent_fd *fde = NULL;
 	struct tevent_signal *se = NULL;
 	struct process_context *proc_ctx = NULL;
+	struct task_server* task = NULL;
 
 	state = setup_standard_child_pipe(ev, service_name);
 	if (state == NULL) {
@@ -486,7 +487,16 @@ static void standard_new_task(struct tevent_context *ev,
 	proc_ctx->forked_on_accept = false;
 
 	/* setup this new task.  Cluster ID is PID based for this process model */
-	new_task(ev, lp_ctx, cluster_id(pid, 0), private_data, proc_ctx);
+	task = new_task(ev, lp_ctx, cluster_id(pid, 0), private_data, proc_ctx);
+	/*
+	 * Currently we don't support the post_fork functionality in the
+	 * standard model, i.e. it is only called here not after a new process
+	 * is forked in standard_accept_connection.
+	 */
+	if (task != NULL && service_details->post_fork != NULL) {
+		service_details->post_fork(task);
+	}
+
 
 	/* we can't return to the top level here, as that event context is gone,
 	   so we now process events in the new event context until there are no
diff --git a/source4/smbd/service.c b/source4/smbd/service.c
index 0874fce20fc..7c8d2cfe3a4 100644
--- a/source4/smbd/service.c
+++ b/source4/smbd/service.c
@@ -30,8 +30,7 @@
 static struct registered_server {
 	struct registered_server *next, *prev;
 	const char *service_name;
-	struct service_details *service_details;
-	void (*task_init)(struct task_server *);
+	const struct service_details *service_details;
 } *registered_servers;
 
 /*
@@ -39,14 +38,12 @@ static struct registered_server {
 */
 NTSTATUS register_server_service(TALLOC_CTX *ctx,
 				const char *name,
-				void (*task_init) (struct task_server *),
 				const struct service_details *details)
 {
 	struct registered_server *srv;
 	srv = talloc(ctx, struct registered_server);
 	NT_STATUS_HAVE_NO_MEMORY(srv);
 	srv->service_name = name;
-	srv->task_init = task_init;
 	srv->service_details =
 		talloc_memdup(ctx, details, sizeof(struct service_details));
 	NT_STATUS_HAVE_NO_MEMORY(srv->service_details);
@@ -70,7 +67,6 @@ static NTSTATUS server_service_init(const char *name,
 			return task_server_startup(event_context, lp_ctx,
 						   srv->service_name,
 						   model_ops,
-						   srv->task_init,
 						   srv->service_details,
 						   from_parent_fd);
 		}
diff --git a/source4/smbd/service.h b/source4/smbd/service.h
index 2d11f142aed..467cb34f6ca 100644
--- a/source4/smbd/service.h
+++ b/source4/smbd/service.h
@@ -40,7 +40,31 @@ struct service_details {
 	 * processes. In this mode pre-fork is equivalent to standard with
 	 * inhibit_fork_on_accept set.
 	 */
-	 bool inhibit_pre_fork;
+	bool inhibit_pre_fork;
+	/*
+	 * Initialise the server task.
+	 */
+	NTSTATUS (*task_init) (struct task_server *);
+	/*
+	 * post fork processing this is called:
+	 *   - standard process model
+	 *      immediately after the task_init.
+	 *
+	 *   - single process model
+	 *     immediately after the task_init
+	 *
+	 *   - prefork process model, inhibit_pre_fork = true
+	 *     immediately after the task_init
+	 *
+	 *   - prefork process model, inhibit_pre_fork = false
+	 *     after each service worker has forked. It is not run on the
+	 *      service master process.
+	 *
+	 *   The post fork hook is not called in the standard model if a new
+	 *   process is forked on a new connection. It is instead called
+	 *   immediately after the task_init.
+	 */
+	void (*post_fork) (struct task_server *);
 };
 
 #include "smbd/service_proto.h"
diff --git a/source4/smbd/service_task.c b/source4/smbd/service_task.c
index 729a1094e75..15e480ec043 100644
--- a/source4/smbd/service_task.c
+++ b/source4/smbd/service_task.c
@@ -62,7 +62,7 @@ void task_server_terminate(struct task_server *task, const char *reason, bool fa
 
 /* used for the callback from the process model code */
 struct task_state {
-	void (*task_init)(struct task_server *);
+	const struct service_details *service_details;
 	const struct model_ops *model_ops;
 };
 
@@ -71,17 +71,18 @@ struct task_state {
   called by the process model code when the new task starts up. This then calls
   the server specific startup code
 */
-static void task_server_callback(struct tevent_context *event_ctx,
+static struct task_server *task_server_callback(struct tevent_context *event_ctx,
 				 struct loadparm_context *lp_ctx,
 				 struct server_id server_id,
 				 void *private_data,
 				 void *context)
 {
-	struct task_state *state = talloc_get_type(private_data, struct task_state);
 	struct task_server *task;
+	NTSTATUS status = NT_STATUS_OK;
 
+	struct task_state *state = talloc_get_type(private_data, struct task_state);
 	task = talloc(event_ctx, struct task_server);
-	if (task == NULL) return;
+	if (task == NULL) return NULL;
 
 	task->event_ctx = event_ctx;
 	task->model_ops = state->model_ops;
@@ -95,10 +96,14 @@ static void task_server_callback(struct tevent_context *event_ctx,
 					task->event_ctx);
 	if (!task->msg_ctx) {
 		task_server_terminate(task, "imessaging_init() failed", true);
-		return;
+		return NULL;
 	}
 
-	state->task_init(task);
+	status = state->service_details->task_init(task);
+	if (!NT_STATUS_IS_OK(status)) {
+		return NULL;
+	}
+	return task;
 }
 
 /*
@@ -108,7 +113,6 @@ 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 *),
 			     const struct service_details *service_details,
 			     int from_parent_fd)
 {
@@ -117,7 +121,7 @@ NTSTATUS task_server_startup(struct tevent_context *event_ctx,
 	state = talloc(event_ctx, struct task_state);
 	NT_STATUS_HAVE_NO_MEMORY(state);
 
-	state->task_init = task_init;
+	state->service_details = service_details;
 	state->model_ops = model_ops;
 
 	state->model_ops->new_task(event_ctx, lp_ctx, service_name,
diff --git a/source4/web_server/web_server.c b/source4/web_server/web_server.c
index d72524c8873..7c2717368e3 100644
--- a/source4/web_server/web_server.c
+++ b/source4/web_server/web_server.c
@@ -293,7 +293,7 @@ static const struct stream_server_ops web_stream_ops = {
 /*
   startup the web server task
 */
-static void websrv_task_init(struct task_server *task)
+static NTSTATUS websrv_task_init(struct task_server *task)
 {
 	NTSTATUS status;
 	uint16_t port = lpcfg_web_port(task->lp_ctx);
@@ -304,7 +304,10 @@ static void websrv_task_init(struct task_server *task)
 	/* startup the Python processor - unfortunately we can't do this
 	   per connection as that wouldn't allow for session variables */
 	wdata = talloc_zero(task, struct web_server_data);
-	if (wdata == NULL) goto failed;
+	if (wdata == NULL) {
+		status = NT_STATUS_NO_MEMORY;
+		goto failed;
+	}
 
 	wdata->task = task;
 	task->private_data = wdata;
@@ -339,6 +342,7 @@ static void websrv_task_init(struct task_server *task)
 		wcard = iface_list_wildcard(task);
 		if (wcard == NULL) {
 			DEBUG(0,("No wildcard addresses available\n"));
+			status = NT_STATUS_UNSUCCESSFUL;
 			goto failed;
 		}
 		for (i=0; wcard[i]; i++) {
@@ -356,15 +360,22 @@ static void websrv_task_init(struct task_server *task)
 	}
 
 	wdata->tls_params = tls_initialise(wdata, task->lp_ctx);
-	if (wdata->tls_params == NULL) goto failed;
+	if (wdata->tls_params == NULL) {
+		status = NT_STATUS_UNSUCCESSFUL;
+		goto failed;
+	}
 
-	if (!wsgi_initialize(wdata)) goto failed;
+	if (!wsgi_initialize(wdata)) {
+		status = NT_STATUS_UNSUCCESSFUL;
+		goto failed;
+	}
 
 
-	return;
+	return NT_STATUS_OK;
 
 failed:
 	task_server_terminate(task, "websrv_task_init: failed to startup web server task", true);
+	return status;
 }
 
 
@@ -373,7 +384,9 @@ NTSTATUS server_service_web_init(TALLOC_CTX *ctx)
 {
 	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
-		.inhibit_pre_fork = true
+		.inhibit_pre_fork = true,
+		.task_init = websrv_task_init,
+		.post_fork = NULL
 	};
-	return register_server_service(ctx, "web", websrv_task_init, &details);
+	return register_server_service(ctx, "web", &details);
 }
diff --git a/source4/winbind/winbindd.c b/source4/winbind/winbindd.c
index e422e623b84..e68ddfb68e1 100644
--- a/source4/winbind/winbindd.c
+++ b/source4/winbind/winbindd.c
@@ -54,7 +54,7 @@ static void winbindd_done(struct tevent_req *subreq)
 /*
   startup a copy of winbindd as a child daemon
 */
-static void winbindd_task_init(struct task_server *task)
+static NTSTATUS winbindd_task_init(struct task_server *task)
 {
 	struct tevent_req *subreq;
 	const char *winbindd_path;
@@ -76,12 +76,13 @@ static void winbindd_task_init(struct task_server *task)
 	if (subreq == NULL) {
 		DEBUG(0, ("Failed to start winbindd as child daemon\n"));
 		task_server_terminate(task, "Failed to startup winbindd task", true);
-		return;
+		return NT_STATUS_UNSUCCESSFUL;
 	}
 
 	tevent_req_set_callback(subreq, winbindd_done, task);
 
 	DEBUG(5,("Started winbindd as a child daemon\n"));
+	return NT_STATUS_OK;
 }
 
 /* called at winbindd startup - register ourselves as a server service */
@@ -92,13 +93,13 @@ NTSTATUS server_service_winbindd_init(TALLOC_CTX *ctx)
 	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
 		.inhibit_pre_fork = true,
+		.task_init = winbindd_task_init,
+		.post_fork = NULL
 	};
 
-	NTSTATUS status = register_server_service(ctx, "winbindd",
-						  winbindd_task_init, &details);
+	NTSTATUS status = register_server_service(ctx, "winbindd", &details);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
-	return register_server_service(ctx, "winbind", winbindd_task_init,
-				       &details);
+	return register_server_service(ctx, "winbind", &details);
 }
diff --git a/source4/wrepl_server/wrepl_server.c b/source4/wrepl_server/wrepl_server.c
index 269fac0670d..d1e2869b009 100644
--- a/source4/wrepl_server/wrepl_server.c
+++ b/source4/wrepl_server/wrepl_server.c
@@ -446,13 +446,13 @@ static NTSTATUS wreplsrv_setup_partners(struct wreplsrv_service *service)
 /*
   startup the wrepl task
 */
-static void wreplsrv_task_init(struct task_server *task)
+static NTSTATUS wreplsrv_task_init(struct task_server *task)
 {
 	NTSTATUS status;
 	struct wreplsrv_service *service;
 
 	if (!lpcfg_we_are_a_wins_server(task->lp_ctx)) {
-		return;
+		return NT_STATUS_INVALID_DOMAIN_ROLE;
 	}
 
 	task_server_set_title(task, "task[wreplsrv]");
@@ -460,7 +460,7 @@ static void wreplsrv_task_init(struct task_server *task)
 	service = talloc_zero(task, struct wreplsrv_service);
 	if (!service) {
 		task_server_terminate(task, "wreplsrv_task_init: out of memory", true);
-		return;
+		return NT_STATUS_NO_MEMORY;
 	}
 	service->task		= task;
 	service->startup_time	= timeval_current();
@@ -472,7 +472,7 @@ static void wreplsrv_task_init(struct task_server *task)
 	status = wreplsrv_open_winsdb(service, task->lp_ctx);
 	if (!NT_STATUS_IS_OK(status)) {
 		task_server_terminate(task, "wreplsrv_task_init: wreplsrv_open_winsdb() failed", true);
-		return;
+		return status;
 	}
 
 	/*
@@ -481,7 +481,7 @@ static void wreplsrv_task_init(struct task_server *task)
 	status = wreplsrv_setup_partners(service);
 	if (!NT_STATUS_IS_OK(status)) {
 		task_server_terminate(task, "wreplsrv_task_init: wreplsrv_setup_partners() failed", true);
-		return;
+		return status;
 	}
 
 	/* 
@@ -491,16 +491,18 @@ static void wreplsrv_task_init(struct task_server *task)
 	status = wreplsrv_setup_sockets(service, task->lp_ctx);
 	if (!NT_STATUS_IS_OK(status)) {
 		task_server_terminate(task, "wreplsrv_task_init: wreplsrv_setup_sockets() failed", true);
-		return;
+		return status;
 	}
 
 	status = wreplsrv_setup_periodic(service);
 	if (!NT_STATUS_IS_OK(status)) {
 		task_server_terminate(task, "wreplsrv_task_init: wreplsrv_setup_periodic() failed", true);
-		return;
+		return status;
 	}
 
 	irpc_add_name(task->msg_ctx, "wrepl_server");
+
+	return NT_STATUS_OK;
 }
 
 /*
@@ -510,8 +512,9 @@ NTSTATUS server_service_wrepl_init(TALLOC_CTX *ctx)
 {
 	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
-		.inhibit_pre_fork = true
+		.inhibit_pre_fork = true,
+		.task_init = wreplsrv_task_init,
+		.post_fork = NULL
 	};
-	return register_server_service(ctx, "wrepl", wreplsrv_task_init,
-				       &details);
+	return register_server_service(ctx, "wrepl", &details);
 }
-- 
2.17.1


From 5b332153678dc50fa35ad6c5081b86d808916086 Mon Sep 17 00:00:00 2001
From: Gary Lockyer <gary at catalyst.net.nz>
Date: Thu, 23 Aug 2018 11:26:40 +1200
Subject: [PATCH 4/6] source4 smbd kdc: allow the kdc to run in prefork

Modify the kdc to allow it to run in the prefork process model. The
task_init function has been split up and code moved into the post_fork
function.

Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
---
 source4/kdc/kdc-heimdal.c | 89 +++++++++++++++++++++------------------
 1 file changed, 49 insertions(+), 40 deletions(-)

diff --git a/source4/kdc/kdc-heimdal.c b/source4/kdc/kdc-heimdal.c
index 3beff5d95da..dd2ab4cdb37 100644
--- a/source4/kdc/kdc-heimdal.c
+++ b/source4/kdc/kdc-heimdal.c
@@ -264,11 +264,8 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
 static NTSTATUS kdc_task_init(struct task_server *task)
 {
 	struct kdc_server *kdc;
-	krb5_kdc_configuration *kdc_config = NULL;
 	NTSTATUS status;
-	krb5_error_code ret;
 	struct interface *ifaces;
-	int ldb_ret;
 
 	switch (lpcfg_server_role(task->lp_ctx)) {
 	case ROLE_STANDALONE:
@@ -302,7 +299,40 @@ static NTSTATUS kdc_task_init(struct task_server *task)
 	}
 
 	kdc->task = task;
+	task->private_data = kdc;
 
+	/* start listening on the configured network interfaces */
+	status = kdc_startup_interfaces(kdc, task->lp_ctx, ifaces,
+					task->model_ops);
+	if (!NT_STATUS_IS_OK(status)) {
+		task_server_terminate(task, "kdc failed to setup interfaces", true);
+		return status;
+	}
+
+
+	return NT_STATUS_OK;
+}
+
+/*
+  initialise the kdc task after a fork
+*/
+static void kdc_post_fork(struct task_server *task)
+{
+	struct kdc_server *kdc;
+	krb5_kdc_configuration *kdc_config = NULL;
+	NTSTATUS status;
+	krb5_error_code ret;
+	int ldb_ret;
+
+	if (task == NULL) {
+		task_server_terminate(task, "kdc: Null task", true);
+		return;
+	}
+	if (task->private_data == NULL) {
+		task_server_terminate(task, "kdc: No kdc_server info", true);
+		return;
+	}
+	kdc = talloc_get_type_abort(task->private_data, struct kdc_server);
 
 	/* get a samdb connection */
 	kdc->samdb = samdb_connect(kdc,
@@ -314,7 +344,7 @@ static NTSTATUS kdc_task_init(struct task_server *task)
 	if (!kdc->samdb) {
 		DEBUG(1,("kdc_task_init: unable to connect to samdb\n"));
 		task_server_terminate(task, "kdc: krb5_init_context samdb connect failed", true);
-		return NT_STATUS_UNSUCCESSFUL;
+		return;
 	}
 
 	ldb_ret = samdb_rodc(kdc->samdb, &kdc->am_rodc);
@@ -322,7 +352,7 @@ static NTSTATUS kdc_task_init(struct task_server *task)
 		DEBUG(1, ("kdc_task_init: Cannot determine if we are an RODC: %s\n",
 			  ldb_errstring(kdc->samdb)));
 		task_server_terminate(task, "kdc: krb5_init_context samdb RODC connect failed", true);
-		return NT_STATUS_UNSUCCESSFUL;
+		return;
 	}
 
 	kdc->proxy_timeout = lpcfg_parm_int(kdc->task->lp_ctx, NULL, "kdc", "proxy timeout", 5);
@@ -334,7 +364,7 @@ static NTSTATUS kdc_task_init(struct task_server *task)
 		DEBUG(1,("kdc_task_init: krb5_init_context failed (%s)\n",
 			 error_message(ret)));
 		task_server_terminate(task, "kdc: krb5_init_context failed", true);
-		return NT_STATUS_UNSUCCESSFUL;
+		return;
 	}
 
 	krb5_add_et_list(kdc->smb_krb5_context->krb5_context, initialize_hdb_error_table_r);
@@ -343,14 +373,14 @@ static NTSTATUS kdc_task_init(struct task_server *task)
 				  &kdc_config);
 	if(ret) {
 		task_server_terminate(task, "kdc: failed to get KDC configuration", true);
-		return NT_STATUS_UNSUCCESSFUL;
+		return;
 	}
 
 	kdc_config->logf = (krb5_log_facility *)kdc->smb_krb5_context->pvt_log_data;
 	kdc_config->db = talloc(kdc, struct HDB *);
 	if (!kdc_config->db) {
 		task_server_terminate(task, "kdc: out of memory", true);
-		return NT_STATUS_UNSUCCESSFUL;
+		return;
 	}
 	kdc_config->num_db = 1;
 
@@ -382,7 +412,7 @@ static NTSTATUS kdc_task_init(struct task_server *task)
 	kdc->base_ctx = talloc_zero(kdc, struct samba_kdc_base_context);
 	if (!kdc->base_ctx) {
 		task_server_terminate(task, "kdc: out of memory", true);
-		return NT_STATUS_NO_MEMORY;
+		return;
 	}
 
 	kdc->base_ctx->ev_ctx = task->event_ctx;
@@ -394,7 +424,7 @@ static NTSTATUS kdc_task_init(struct task_server *task)
 				       &kdc_config->db[0]);
 	if (!NT_STATUS_IS_OK(status)) {
 		task_server_terminate(task, "kdc: hdb_samba4_create_kdc (setup KDC database) failed", true);
-		return status;
+		return;
 	}
 
 	ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context,
@@ -402,13 +432,13 @@ static NTSTATUS kdc_task_init(struct task_server *task)
 				   &hdb_samba4_interface);
 	if(ret) {
 		task_server_terminate(task, "kdc: failed to register hdb plugin", true);
-		return NT_STATUS_UNSUCCESSFUL;
+		return;
 	}
 
 	ret = krb5_kt_register(kdc->smb_krb5_context->krb5_context, &hdb_kt_ops);
 	if(ret) {
 		task_server_terminate(task, "kdc: failed to register keytab plugin", true);
-		return NT_STATUS_UNSUCCESSFUL;
+		return;
 	}
 
 	kdc->keytab_name = talloc_asprintf(kdc, "HDB:samba4&%p", kdc->base_ctx);
@@ -416,7 +446,7 @@ static NTSTATUS kdc_task_init(struct task_server *task)
 		task_server_terminate(task,
 				      "kdc: Failed to set keytab name",
 				      true);
-		return NT_STATUS_UNSUCCESSFUL;
+		return;
 	}
 
 	/* Register WinDC hooks */
@@ -425,42 +455,32 @@ static NTSTATUS kdc_task_init(struct task_server *task)
 				   &windc_plugin_table);
 	if(ret) {
 		task_server_terminate(task, "kdc: failed to register windc plugin", true);
-		return NT_STATUS_UNSUCCESSFUL;
+		return;
 	}
 
 	ret = krb5_kdc_windc_init(kdc->smb_krb5_context->krb5_context);
 
 	if(ret) {
 		task_server_terminate(task, "kdc: failed to init windc plugin", true);
-		return NT_STATUS_UNSUCCESSFUL;
+		return;
 	}
 
 	ret = krb5_kdc_pkinit_config(kdc->smb_krb5_context->krb5_context, kdc_config);
 
 	if(ret) {
 		task_server_terminate(task, "kdc: failed to init kdc pkinit subsystem", true);
-		return NT_STATUS_UNSUCCESSFUL;
+		return;
 	}
 	kdc->private_data = kdc_config;
 
-	/* start listening on the configured network interfaces */
-	status = kdc_startup_interfaces(kdc, task->lp_ctx, ifaces,
-					task->model_ops);
-	if (!NT_STATUS_IS_OK(status)) {
-		task_server_terminate(task, "kdc failed to setup interfaces", true);
-		return status;
-	}
-
 	status = IRPC_REGISTER(task->msg_ctx, irpc, KDC_CHECK_GENERIC_KERBEROS,
 			       kdc_check_generic_kerberos, kdc);
 	if (!NT_STATUS_IS_OK(status)) {
 		task_server_terminate(task, "kdc failed to setup monitoring", true);
-		return status;
+		return;
 	}
 
 	irpc_add_name(task->msg_ctx, "kdc_server");
-
-	return NT_STATUS_OK;
 }
 
 
@@ -469,20 +489,9 @@ NTSTATUS server_service_kdc_init(TALLOC_CTX *ctx)
 {
 	static const struct service_details details = {
 		.inhibit_fork_on_accept = true,
-		/* 
-		 * Need to prevent pre-forking on kdc.
-		 * The task_init function is run on the master process only
-		 * and the irpc process name is registered in it's event loop.
-		 * The child worker processes initialise their event loops on
-		 * fork, so are not listening for the irpc event.
-		 *
-		 * The master process does not wait on that event context
-		 * the master process is responsible for managing the worker
-		 * processes not performing work.
-		 */
-		.inhibit_pre_fork = true,
+		.inhibit_pre_fork = false,
 		.task_init = kdc_task_init,
-		.post_fork = NULL
+		.post_fork = kdc_post_fork
 	};
 	return register_server_service(ctx, "kdc", &details);
 }
-- 
2.17.1


From 5a0cfb64bd25ac3c56cd71988147912f00c5d5b1 Mon Sep 17 00:00:00 2001
From: Gary Lockyer <gary at catalyst.net.nz>
Date: Tue, 28 Aug 2018 07:46:59 +1200
Subject: [PATCH 5/6] kdc: Update debug calls

Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
---
 source4/kdc/kdc-heimdal.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/source4/kdc/kdc-heimdal.c b/source4/kdc/kdc-heimdal.c
index dd2ab4cdb37..407de92054e 100644
--- a/source4/kdc/kdc-heimdal.c
+++ b/source4/kdc/kdc-heimdal.c
@@ -78,8 +78,8 @@ static kdc_code kdc_process(struct kdc_server *kdc,
 		return KDC_ERROR;
 	}
 
-	DEBUG(10,("Received KDC packet of length %lu from %s\n",
-				(long)input->length - 4, pa));
+	DBG_DEBUG("Received KDC packet of length %lu from %s\n",
+		  (long)input->length - 4, pa);
 
 	ret = krb5_kdc_process_krb5_request(kdc->smb_krb5_context->krb5_context,
 					    kdc_config,
@@ -342,15 +342,16 @@ static void kdc_post_fork(struct task_server *task)
 				   NULL,
 				   0);
 	if (!kdc->samdb) {
-		DEBUG(1,("kdc_task_init: unable to connect to samdb\n"));
+		DBG_WARNING("kdc_task_init: unable to connect to samdb\n");
 		task_server_terminate(task, "kdc: krb5_init_context samdb connect failed", true);
 		return;
 	}
 
 	ldb_ret = samdb_rodc(kdc->samdb, &kdc->am_rodc);
 	if (ldb_ret != LDB_SUCCESS) {
-		DEBUG(1, ("kdc_task_init: Cannot determine if we are an RODC: %s\n",
-			  ldb_errstring(kdc->samdb)));
+		DBG_WARNING("kdc_task_init: "
+			    "Cannot determine if we are an RODC: %s\n",
+			    ldb_errstring(kdc->samdb));
 		task_server_terminate(task, "kdc: krb5_init_context samdb RODC connect failed", true);
 		return;
 	}
@@ -361,8 +362,8 @@ static void kdc_post_fork(struct task_server *task)
 
 	ret = smb_krb5_init_context(kdc, task->lp_ctx, &kdc->smb_krb5_context);
 	if (ret) {
-		DEBUG(1,("kdc_task_init: krb5_init_context failed (%s)\n",
-			 error_message(ret)));
+		DBG_WARNING("kdc_task_init: krb5_init_context failed (%s)\n",
+			    error_message(ret));
 		task_server_terminate(task, "kdc: krb5_init_context failed", true);
 		return;
 	}
-- 
2.17.1


From f9c0821faf7af7a335827a6f0c94bbd3da9b0809 Mon Sep 17 00:00:00 2001
From: Gary Lockyer <gary at catalyst.net.nz>
Date: Wed, 19 Sep 2018 15:01:22 +1200
Subject: [PATCH 6/6] WHATSNEW: KDC prefork support

Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
---
 WHATSNEW.txt | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index bdc3df78b23..7a7a88d4152 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -27,6 +27,11 @@ rebuild the Group Policy Objects from the XML after generalization.
 (The administrator needs to correct the values of XML entities between
 the backup and restore to account for the change in domain).
 
+kdc prefork
+-----------
+
+The KDC now supports the pre-fork process model and worker processes will be
+forked for the KDC when the pre-fork process model is selected for samba.
 
 REMOVED FEATURES
 ================
-- 
2.17.1

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20181029/d82968bf/signature.sig>


More information about the samba-technical mailing list