From 99aea42520fc10564dbba013c365adb3059febad Mon Sep 17 00:00:00 2001 From: Gary Lockyer Date: Thu, 23 Aug 2018 09:35:52 +1200 Subject: [PATCH] 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 --- 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); }