source4 smdb: Add a post fork hook to the service API
authorGary Lockyer <gary@catalyst.net.nz>
Wed, 22 Aug 2018 21:35:52 +0000 (09:35 +1200)
committerGary Lockyer <gary@samba.org>
Thu, 1 Nov 2018 22:49:24 +0000 (23:49 +0100)
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@catalyst.net.nz>
24 files changed:
file_server/file_server.c
source4/cldap_server/cldap_server.c
source4/dns_server/dns_server.c
source4/dsdb/dns/dns_update.c
source4/dsdb/kcc/kcc_service.c
source4/dsdb/repl/drepl_service.c
source4/echo_server/echo_server.c
source4/kdc/kdc-heimdal.c
source4/kdc/kdc-service-mit.c
source4/ldap_server/ldap_server.c
source4/nbt_server/nbt_server.c
source4/ntp_signd/ntp_signd.c
source4/rpc_server/service_rpc.c
source4/smb_server/service_smb.c
source4/smbd/process_model.h
source4/smbd/process_prefork.c
source4/smbd/process_single.c
source4/smbd/process_standard.c
source4/smbd/service.c
source4/smbd/service.h
source4/smbd/service_task.c
source4/web_server/web_server.c
source4/winbind/winbindd.c
source4/wrepl_server/wrepl_server.c

index 1b6a01b..4c21669 100644 (file)
@@ -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);
 }
index 65d983f..5118326 100644 (file)
@@ -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);
 }
index c7c1cdd..43ea881 100644 (file)
@@ -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);
 }
index 08e7eb2..20052f4 100644 (file)
@@ -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);
 }
index e1bbae2..4710d5b 100644 (file)
@@ -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);
 }
index 9789e78..350ed61 100644 (file)
@@ -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);
 }
index 657180f..f38999a 100644 (file)
@@ -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);
 }
index 8f09c41..3beff5d 100644 (file)
@@ -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);
 }
index 5d111ee..8ae1c21 100644 (file)
@@ -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);
 }
index 5b1db0c..f6329f0 100644 (file)
@@ -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);
 }
index 84cd507..00c255c 100644 (file)
@@ -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);
 }
index a392929..5999bf8 100644 (file)
@@ -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);
 }
index f7d1a9f..07d6f70 100644 (file)
@@ -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);
 }
index bea7eb9..37e8a61 100644 (file)
@@ -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);
 }
index 656a7f2..17d7025 100644 (file)
@@ -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 *,
index f6fb80b..788aa97 100644 (file)
@@ -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);
index 1859c96..242622b 100644 (file)
@@ -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);
+       }
 }
 
 
index 677345f..6262009 100644 (file)
@@ -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
index 0874fce..7c8d2cf 100644 (file)
@@ -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);
                }
index 2d11f14..467cb34 100644 (file)
@@ -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"
index 729a109..15e480e 100644 (file)
@@ -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,
index d72524c..7c27173 100644 (file)
@@ -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);
 }
index e422e62..e68ddfb 100644 (file)
@@ -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);
 }
index 269fac0..d1e2869 100644 (file)
@@ -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);
 }