From 42ececdfae15a34205638cc6e3ec53d6f3ac2148 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 15 Oct 2005 19:18:05 +0000 Subject: r11093: Implement wb_queue_domain_send: If the domain is not yet initialized, do that first. And if a request is being processed, queue it. This correctly survived 3 endless loops with wbinfo's doing different things while starting up smbd. The number of indirections starts to become a bit scary, but what can you do without a decent programming language that provides closures :-) One thing that we might consider is to auto-generate async rpc requests that return composite_context structs instead of rpc_requests. Otherwise I'd have to write a lot of wrappers like composite_netr_LogonSamLogon_send. The alternative would be to write two versions of wb_queue_domain_send which I would like to avoid. This is cluttered enough already. Volker (This used to be commit 66c1b674f9870de73cce0e611909caf9eff34baa) --- source4/include/structs.h | 1 + source4/winbind/wb_async_helpers.c | 135 +++++++++++++++++++++---------------- source4/winbind/wb_connect_lsa.c | 16 +---- source4/winbind/wb_init_domain.c | 112 ++++++++++++++++++++++++++++++ source4/winbind/wb_pam_auth.c | 100 +++++++++++---------------- source4/winbind/wb_server.h | 3 + 6 files changed, 235 insertions(+), 132 deletions(-) diff --git a/source4/include/structs.h b/source4/include/structs.h index 68cae5d256..2925d4fec9 100644 --- a/source4/include/structs.h +++ b/source4/include/structs.h @@ -108,6 +108,7 @@ union netr_Validation; struct netr_SamBaseInfo; struct netr_SamInfo3; struct netr_UserSessionKey; +struct netr_LogonSamLogon; struct iface_struct; diff --git a/source4/winbind/wb_async_helpers.c b/source4/winbind/wb_async_helpers.c index 0480304abe..146a957727 100644 --- a/source4/winbind/wb_async_helpers.c +++ b/source4/winbind/wb_async_helpers.c @@ -66,6 +66,7 @@ struct composite_context *wb_finddcs_send(const char *domain_name, result = talloc_zero(NULL, struct composite_context); if (result == NULL) goto failed; result->state = COMPOSITE_STATE_IN_PROGRESS; + result->async.fn = NULL; result->event_ctx = event_ctx; state = talloc(result, struct finddcs_state); @@ -197,6 +198,7 @@ struct composite_context *wb_get_schannel_creds_send(struct cli_credentials *wks result = talloc_zero(NULL, struct composite_context); if (result == NULL) goto failed; result->state = COMPOSITE_STATE_IN_PROGRESS; + result->async.fn = NULL; result->event_ctx = ev; state = talloc(result, struct get_schannel_creds_state); @@ -384,6 +386,7 @@ struct composite_context *wb_lsa_lookupnames_send(struct dcerpc_pipe *lsa_pipe, result = talloc_zero(NULL, struct composite_context); if (result == NULL) goto failed; result->state = COMPOSITE_STATE_IN_PROGRESS; + result->async.fn = NULL; result->event_ctx = lsa_pipe->conn->event_ctx; state = talloc(result, struct lsa_lookupnames_state); @@ -506,94 +509,68 @@ struct cmd_lookupname_state { struct wb_sid_object *result; }; -static void cmd_lookupname_recv_init(struct composite_context *ctx); -static void cmd_lookupname_recv_sid(struct composite_context *ctx); +static struct composite_context *lookupname_send_req(void *p); +static NTSTATUS lookupname_recv_req(struct composite_context *ctx, void *p); struct composite_context *wb_cmd_lookupname_send(struct wbsrv_call *call, const char *name) { - struct composite_context *result, *ctx; struct cmd_lookupname_state *state; struct wbsrv_service *service = call->wbconn->listen_socket->service; - result = talloc_zero(call, struct composite_context); - if (result == NULL) goto failed; - result->state = COMPOSITE_STATE_IN_PROGRESS; - result->event_ctx = call->event_ctx; - - state = talloc(result, struct cmd_lookupname_state); - if (state == NULL) goto failed; - state->ctx = result; - result->private_data = state; - + state = talloc(NULL, struct cmd_lookupname_state); + state->domain = service->domains; state->call = call; state->name = talloc_strdup(state, name); - - state->domain = service->domains; - - if (state->domain->initialized) { - ctx = wb_lsa_lookupnames_send(state->domain->lsa_pipe, - state->domain->lsa_policy, - 1, &state->name); - if (ctx == NULL) goto failed; - ctx->async.fn = cmd_lookupname_recv_sid; - ctx->async.private_data = state; - return result; + state->ctx = wb_queue_domain_send(state, state->domain, + call->event_ctx, + call->wbconn->conn->msg_ctx, + lookupname_send_req, + lookupname_recv_req, + state); + if (state->ctx == NULL) { + talloc_free(state); + return NULL; } - - ctx = wb_init_domain_send(state->domain, - result->event_ctx, - call->wbconn->conn->msg_ctx); - if (ctx == NULL) goto failed; - ctx->async.fn = cmd_lookupname_recv_init; - ctx->async.private_data = state; - return result; - - failed: - talloc_free(result); - return NULL; + state->ctx->private_data = state; + return state->ctx; } -static void cmd_lookupname_recv_init(struct composite_context *ctx) +static struct composite_context *lookupname_send_req(void *p) { struct cmd_lookupname_state *state = - talloc_get_type(ctx->async.private_data, - struct cmd_lookupname_state); + talloc_get_type(p, struct cmd_lookupname_state); - state->ctx->status = wb_init_domain_recv(ctx); - if (!composite_is_ok(state->ctx)) return; - - ctx = wb_lsa_lookupnames_send(state->domain->lsa_pipe, - state->domain->lsa_policy, - 1, &state->name); - composite_continue(state->ctx, ctx, cmd_lookupname_recv_sid, state); + return wb_lsa_lookupnames_send(state->domain->lsa_pipe, + state->domain->lsa_policy, + 1, &state->name); } -static void cmd_lookupname_recv_sid(struct composite_context *ctx) +static NTSTATUS lookupname_recv_req(struct composite_context *ctx, void *p) { struct cmd_lookupname_state *state = - talloc_get_type(ctx->async.private_data, - struct cmd_lookupname_state); + talloc_get_type(p, struct cmd_lookupname_state); struct wb_sid_object **sids; + NTSTATUS status; - state->ctx->status = wb_lsa_lookupnames_recv(ctx, state, &sids); - if (!composite_is_ok(state->ctx)) return; - state->result = sids[0]; - composite_done(state->ctx); + status = wb_lsa_lookupnames_recv(ctx, state, &sids); + if (NT_STATUS_IS_OK(status)) { + state->result = sids[0]; + } + return status; } NTSTATUS wb_cmd_lookupname_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, struct wb_sid_object **sid) { + struct cmd_lookupname_state *state = + talloc_get_type(c->private_data, struct cmd_lookupname_state); NTSTATUS status = composite_wait(c); if (NT_STATUS_IS_OK(status)) { - struct cmd_lookupname_state *state = - talloc_get_type(c->private_data, - struct cmd_lookupname_state); *sid = talloc_steal(mem_ctx, state->result); } - talloc_free(c); + talloc_free(state); return status; } @@ -622,6 +599,7 @@ struct composite_context *wb_cmd_checkmachacc_send(struct wbsrv_call *call) result = talloc(call, struct composite_context); if (result == NULL) goto failed; result->state = COMPOSITE_STATE_IN_PROGRESS; + result->async.fn = NULL; result->event_ctx = call->event_ctx; state = talloc(result, struct cmd_checkmachacc_state); @@ -669,3 +647,46 @@ NTSTATUS wb_cmd_checkmachacc(struct wbsrv_call *call) struct composite_context *c = wb_cmd_checkmachacc_send(call); return wb_cmd_checkmachacc_recv(c); } + +static void composite_netr_LogonSamLogon_recv_rpc(struct rpc_request *req); + +struct composite_context *composite_netr_LogonSamLogon_send(struct dcerpc_pipe *p, + TALLOC_CTX *mem_ctx, + struct netr_LogonSamLogon *r) +{ + struct composite_context *result; + struct rpc_request *req; + + result = talloc(mem_ctx, struct composite_context); + if (result == NULL) goto failed; + result->state = COMPOSITE_STATE_IN_PROGRESS; + result->async.fn = NULL; + result->event_ctx = p->conn->event_ctx; + + req = dcerpc_netr_LogonSamLogon_send(p, mem_ctx, r); + if (req == NULL) goto failed; + req->async.callback = composite_netr_LogonSamLogon_recv_rpc; + req->async.private = result; + return result; + + failed: + talloc_free(result); + return NULL; +} + +static void composite_netr_LogonSamLogon_recv_rpc(struct rpc_request *req) +{ + struct composite_context *ctx = + talloc_get_type(req->async.private, struct composite_context); + + ctx->status = dcerpc_ndr_request_recv(req); + if (!composite_is_ok(ctx)) return; + composite_done(ctx); +} + +NTSTATUS composite_netr_LogonSamLogon_recv(struct composite_context *ctx) +{ + NTSTATUS status = composite_wait(ctx); + talloc_free(ctx); + return status; +} diff --git a/source4/winbind/wb_connect_lsa.c b/source4/winbind/wb_connect_lsa.c index ef7b525c2a..82fe3b2e74 100644 --- a/source4/winbind/wb_connect_lsa.c +++ b/source4/winbind/wb_connect_lsa.c @@ -23,21 +23,9 @@ #include "includes.h" #include "libcli/composite/composite.h" -#include "libcli/smb_composite/smb_composite.h" -#include "winbind/wb_async_helpers.h" -#include "winbind/wb_server.h" -#include "smbd/service_stream.h" - -#include "librpc/gen_ndr/nbt.h" -#include "librpc/gen_ndr/samr.h" -#include "lib/messaging/irpc.h" -#include "librpc/gen_ndr/irpc.h" -#include "librpc/gen_ndr/ndr_irpc.h" + #include "libcli/raw/libcliraw.h" -#include "librpc/gen_ndr/ndr_netlogon.h" #include "librpc/gen_ndr/ndr_lsa.h" -#include "libcli/auth/credentials.h" - /* Helper to initialize LSA with a specific auth methods. Verify by opening * the LSA policy. */ @@ -67,6 +55,7 @@ static struct composite_context *wb_init_lsa_send(struct smbcli_tree *tree, result = talloc(NULL, struct composite_context); if (result == NULL) goto failed; result->state = COMPOSITE_STATE_IN_PROGRESS; + result->async.fn = NULL; result->event_ctx = tree->session->transport->socket->event.ctx; state = talloc(result, struct init_lsa_state); @@ -205,6 +194,7 @@ struct composite_context *wb_connect_lsa_send(struct smbcli_tree *tree, result = talloc(NULL, struct composite_context); if (result == NULL) goto failed; result->state = COMPOSITE_STATE_IN_PROGRESS; + result->async.fn = NULL; result->event_ctx = tree->session->transport->socket->event.ctx; state = talloc(result, struct connect_lsa_state); diff --git a/source4/winbind/wb_init_domain.c b/source4/winbind/wb_init_domain.c index c9389ea7dd..fbe44244f4 100644 --- a/source4/winbind/wb_init_domain.c +++ b/source4/winbind/wb_init_domain.c @@ -26,6 +26,7 @@ #include "winbind/wb_async_helpers.h" #include "winbind/wb_server.h" #include "smbd/service_stream.h" +#include "dlinklist.h" #include "librpc/gen_ndr/nbt.h" #include "librpc/gen_ndr/samr.h" @@ -350,3 +351,114 @@ NTSTATUS wb_init_domain(struct wbsrv_domain *domain, wb_init_domain_send(domain, event_ctx, messaging_ctx); return wb_init_domain_recv(c); } + +struct queue_domain_state { + struct queue_domain_state *prev, *next; + struct composite_context *ctx; + struct wbsrv_domain *domain; + struct composite_context *(*send_fn)(void *p); + NTSTATUS (*recv_fn)(struct composite_context *c, + void *p); + void *private_data; +}; + +static void queue_domain_recv_init(struct composite_context *ctx); +static void queue_domain_recv_sub(struct composite_context *ctx); + +struct composite_context *wb_queue_domain_send(TALLOC_CTX *mem_ctx, + struct wbsrv_domain *domain, + struct event_context *event_ctx, + struct messaging_context *msg_ctx, + struct composite_context *(*send_fn)(void *p), + NTSTATUS (*recv_fn)(struct composite_context *c, + void *p), + void *private_data) +{ + struct composite_context *result, *ctx; + struct queue_domain_state *state; + + result = talloc(mem_ctx, struct composite_context); + if (result == NULL) goto failed; + result->state = COMPOSITE_STATE_IN_PROGRESS; + result->async.fn = NULL; + result->event_ctx = event_ctx; + + state = talloc(result, struct queue_domain_state); + if (state == NULL) goto failed; + state->ctx = result; + result->private_data = state; + + state->send_fn = send_fn; + state->recv_fn = recv_fn; + state->private_data = private_data; + state->domain = domain; + + if (domain->busy) { + DEBUG(0, ("Domain %s busy\n", domain->name)); + DLIST_ADD_END(domain->request_queue, state, + struct queue_domain_state *); + return result; + } + + domain->busy = True; + + if (!domain->initialized) { + ctx = wb_init_domain_send(domain, result->event_ctx, msg_ctx); + if (ctx == NULL) goto failed; + ctx->async.fn = queue_domain_recv_init; + ctx->async.private_data = state; + return result; + } + + ctx = state->send_fn(state->private_data); + if (ctx == NULL) goto failed; + ctx->async.fn = queue_domain_recv_sub; + ctx->async.private_data = state; + return result; + + failed: + talloc_free(result); + return NULL; +} + +static void queue_domain_recv_init(struct composite_context *ctx) +{ + struct queue_domain_state *state = + talloc_get_type(ctx->async.private_data, + struct queue_domain_state); + + state->ctx->status = wb_init_domain_recv(ctx); + if (!composite_is_ok(state->ctx)) return; + + ctx = state->send_fn(state->private_data); + composite_continue(state->ctx, ctx, queue_domain_recv_sub, state); +} + +static void queue_domain_recv_sub(struct composite_context *ctx) +{ + struct queue_domain_state *state = + talloc_get_type(ctx->async.private_data, + struct queue_domain_state); + + state->ctx->status = state->recv_fn(ctx, state->private_data); + state->domain->busy = False; + + if (state->domain->request_queue != NULL) { + struct queue_domain_state *s2; + s2 = state->domain->request_queue; + DLIST_REMOVE(state->domain->request_queue, s2); + ctx = s2->send_fn(s2->private_data); + composite_continue(s2->ctx, ctx, queue_domain_recv_sub, s2); + state->domain->busy = True; + } + + if (!composite_is_ok(state->ctx)) return; + composite_done(state->ctx); +} + +NTSTATUS wb_queue_domain_recv(struct composite_context *ctx) +{ + NTSTATUS status = composite_wait(ctx); + talloc_free(ctx); + return status; +} diff --git a/source4/winbind/wb_pam_auth.c b/source4/winbind/wb_pam_auth.c index f35ff4703d..ef43aededd 100644 --- a/source4/winbind/wb_pam_auth.c +++ b/source4/winbind/wb_pam_auth.c @@ -29,6 +29,7 @@ struct pam_auth_crap_state { struct composite_context *ctx; + struct event_context *event_ctx; struct wbsrv_domain *domain; const char *domain_name; const char *user_name; @@ -45,9 +46,8 @@ struct pam_auth_crap_state { DATA_BLOB info3; }; -static struct rpc_request *send_samlogon(struct pam_auth_crap_state *state); -static void pam_auth_crap_recv_init(struct composite_context *ctx); -static void pam_auth_crap_recv_samlogon(struct rpc_request *req); +static struct composite_context *crap_samlogon_send_req(void *p); +static NTSTATUS crap_samlogon_recv_req(struct composite_context *ctx, void *p); struct composite_context *wb_cmd_pam_auth_crap_send(struct wbsrv_call *call, const char *domain, @@ -57,22 +57,14 @@ struct composite_context *wb_cmd_pam_auth_crap_send(struct wbsrv_call *call, DATA_BLOB nt_resp, DATA_BLOB lm_resp) { - struct composite_context *result, *ctx; struct pam_auth_crap_state *state; struct wbsrv_service *service = call->wbconn->listen_socket->service; - result = talloc(NULL, struct composite_context); - if (result == NULL) goto failed; - result->state = COMPOSITE_STATE_IN_PROGRESS; - result->event_ctx = call->event_ctx; - result->async.fn = NULL; - - state = talloc(result, struct pam_auth_crap_state); + state = talloc(NULL, struct pam_auth_crap_state); if (state == NULL) goto failed; - state->ctx = result; - result->private_data = state; state->domain = service->domains; + state->event_ctx = call->event_ctx; state->domain_name = talloc_strdup(state, domain); if (state->domain_name == NULL) goto failed; @@ -94,45 +86,28 @@ struct composite_context *wb_cmd_pam_auth_crap_send(struct wbsrv_call *call, if ((lm_resp.data != NULL) && (state->lm_resp.data == NULL)) goto failed; - if (state->domain->initialized) { - struct rpc_request *req = send_samlogon(state); - if (req == NULL) goto failed; - req->async.callback = pam_auth_crap_recv_samlogon; - req->async.private = state; - return result; - } - - ctx = wb_init_domain_send(state->domain, result->event_ctx, - call->wbconn->conn->msg_ctx); - if (ctx == NULL) goto failed; - ctx->async.fn = pam_auth_crap_recv_init; - ctx->async.private_data = state; - return result; + state->ctx = wb_queue_domain_send(state, state->domain, + call->event_ctx, + call->wbconn->conn->msg_ctx, + crap_samlogon_send_req, + crap_samlogon_recv_req, + state); + if (state->ctx == NULL) goto failed; + state->ctx->private_data = state; + return state->ctx; failed: - talloc_free(result); + talloc_free(state); return NULL; } -static void pam_auth_crap_recv_init(struct composite_context *ctx) +static struct composite_context *crap_samlogon_send_req(void *p) { struct pam_auth_crap_state *state = - talloc_get_type(ctx->async.private_data, - struct pam_auth_crap_state); - struct rpc_request *req; - - state->ctx->status = wb_init_domain_recv(ctx); - if (!composite_is_ok(state->ctx)) return; - - req = send_samlogon(state); - composite_continue_rpc(state->ctx, req, - pam_auth_crap_recv_samlogon, state); -} - -static struct rpc_request *send_samlogon(struct pam_auth_crap_state *state) -{ + talloc_get_type(p, struct pam_auth_crap_state); state->creds_state = cli_credentials_get_netlogon_creds( state->domain->schannel_creds); + creds_client_authenticator(state->creds_state, &state->auth); state->ninfo.identity_info.account_name.string = state->user_name; @@ -165,42 +140,44 @@ static struct rpc_request *send_samlogon(struct pam_auth_crap_state *state) state->r.in.logon.network = &state->ninfo; state->r.out.return_authenticator = NULL; - return dcerpc_netr_LogonSamLogon_send(state->domain->netlogon_pipe, - state, &state->r); + return composite_netr_LogonSamLogon_send(state->domain->netlogon_pipe, + state, &state->r); } -static void pam_auth_crap_recv_samlogon(struct rpc_request *req) +static NTSTATUS crap_samlogon_recv_req(struct composite_context *ctx, + void *p) { struct pam_auth_crap_state *state = - talloc_get_type(req->async.private, - struct pam_auth_crap_state); + talloc_get_type(p, struct pam_auth_crap_state); struct netr_SamBaseInfo *base; DATA_BLOB tmp_blob; + NTSTATUS status; - state->ctx->status = dcerpc_ndr_request_recv(req); - if (!composite_is_ok(state->ctx)) return; - state->ctx->status = state->r.out.result; - if (!composite_is_ok(state->ctx)) return; + status = composite_netr_LogonSamLogon_recv(ctx); + if (!NT_STATUS_IS_OK(status)) return status; + + status = state->r.out.result; + if (!NT_STATUS_IS_OK(status)) return status; if ((state->r.out.return_authenticator == NULL) || (!creds_client_check(state->creds_state, &state->r.out.return_authenticator->cred))) { DEBUG(0, ("Credentials check failed!\n")); - composite_error(state->ctx, NT_STATUS_ACCESS_DENIED); - return; + return NT_STATUS_ACCESS_DENIED; } creds_decrypt_samlogon(state->creds_state, state->r.in.validation_level, &state->r.out.validation); - state->ctx->status = ndr_push_struct_blob( - &tmp_blob, state, state->r.out.validation.sam3, + status = ndr_push_struct_blob( + &tmp_blob, state, + state->r.out.validation.sam3, (ndr_push_flags_fn_t)ndr_push_netr_SamInfo3); - if (!composite_is_ok(state->ctx)) return; - + NT_STATUS_NOT_OK_RETURN(status); + state->info3 = data_blob_talloc(state, NULL, tmp_blob.length+4); - if (composite_nomem(state->info3.data, state->ctx)) return; + NT_STATUS_HAVE_NO_MEMORY(state->info3.data); SIVAL(state->info3.data, 0, 1); memcpy(state->info3.data+4, tmp_blob.data, tmp_blob.length); @@ -218,14 +195,13 @@ static void pam_auth_crap_recv_samlogon(struct rpc_request *req) break; } if (base == NULL) { - composite_error(state->ctx, NT_STATUS_INTERNAL_ERROR); - return; + return NT_STATUS_INTERNAL_ERROR; } state->user_session_key = base->key; state->lm_key = base->LMSessKey; - composite_done(state->ctx); + return NT_STATUS_OK; } NTSTATUS wb_cmd_pam_auth_crap_recv(struct composite_context *c, diff --git a/source4/winbind/wb_server.h b/source4/winbind/wb_server.h index df871f4c25..52e7256570 100644 --- a/source4/winbind/wb_server.h +++ b/source4/winbind/wb_server.h @@ -58,6 +58,9 @@ struct wbsrv_domain { struct dcerpc_pipe *netlogon_auth2_pipe; struct dcerpc_pipe *netlogon_pipe; struct cli_credentials *schannel_creds; + + BOOL busy; + struct queue_domain_state *request_queue; }; /* -- cgit