From e81550c8117166d0fbf69ba1d3957cb950c42961 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 5 Aug 2013 16:12:13 +0200 Subject: auth/gensec: make it possible to implement async backends Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett --- auth/gensec/gensec.c | 202 ++++++++++++++++++++++++++++++++---------- auth/gensec/gensec_internal.h | 7 ++ 2 files changed, 160 insertions(+), 49 deletions(-) (limited to 'auth') diff --git a/auth/gensec/gensec.c b/auth/gensec/gensec.c index d364a344a9..abcbcb9506 100644 --- a/auth/gensec/gensec.c +++ b/auth/gensec/gensec.c @@ -218,61 +218,92 @@ _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_ const DATA_BLOB in, DATA_BLOB *out) { NTSTATUS status; + const struct gensec_security_ops *ops = gensec_security->ops; + TALLOC_CTX *frame = NULL; + struct tevent_req *subreq = NULL; + bool ok; - status = gensec_security->ops->update(gensec_security, out_mem_ctx, - ev, in, out); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + if (ops->update_send == NULL) { - /* - * Because callers using the - * gensec_start_mech_by_auth_type() never call - * gensec_want_feature(), it isn't sensible for them - * to have to call gensec_have_feature() manually, and - * these are not points of negotiation, but are - * asserted by the client - */ - switch (gensec_security->dcerpc_auth_level) { - case DCERPC_AUTH_LEVEL_INTEGRITY: - if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { - DEBUG(0,("Did not manage to negotiate mandetory feature " - "SIGN for dcerpc auth_level %u\n", - gensec_security->dcerpc_auth_level)); - return NT_STATUS_ACCESS_DENIED; - } - break; - case DCERPC_AUTH_LEVEL_PRIVACY: - if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { - DEBUG(0,("Did not manage to negotiate mandetory feature " - "SIGN for dcerpc auth_level %u\n", - gensec_security->dcerpc_auth_level)); - return NT_STATUS_ACCESS_DENIED; + status = ops->update(gensec_security, out_mem_ctx, + ev, in, out); + if (!NT_STATUS_IS_OK(status)) { + return status; } - if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) { - DEBUG(0,("Did not manage to negotiate mandetory feature " - "SEAL for dcerpc auth_level %u\n", - gensec_security->dcerpc_auth_level)); - return NT_STATUS_ACCESS_DENIED; + + /* + * Because callers using the + * gensec_start_mech_by_auth_type() never call + * gensec_want_feature(), it isn't sensible for them + * to have to call gensec_have_feature() manually, and + * these are not points of negotiation, but are + * asserted by the client + */ + switch (gensec_security->dcerpc_auth_level) { + case DCERPC_AUTH_LEVEL_INTEGRITY: + if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { + DEBUG(0,("Did not manage to negotiate mandetory feature " + "SIGN for dcerpc auth_level %u\n", + gensec_security->dcerpc_auth_level)); + return NT_STATUS_ACCESS_DENIED; + } + break; + case DCERPC_AUTH_LEVEL_PRIVACY: + if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { + DEBUG(0,("Did not manage to negotiate mandetory feature " + "SIGN for dcerpc auth_level %u\n", + gensec_security->dcerpc_auth_level)); + return NT_STATUS_ACCESS_DENIED; + } + if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) { + DEBUG(0,("Did not manage to negotiate mandetory feature " + "SEAL for dcerpc auth_level %u\n", + gensec_security->dcerpc_auth_level)); + return NT_STATUS_ACCESS_DENIED; + } + break; + default: + break; } - break; - default: - break; + + return NT_STATUS_OK; } - return NT_STATUS_OK; + frame = talloc_stackframe(); + + subreq = ops->update_send(frame, ev, gensec_security, in); + if (subreq == NULL) { + goto fail; + } + ok = tevent_req_poll_ntstatus(subreq, ev, &status); + if (!ok) { + goto fail; + } + status = ops->update_recv(subreq, out_mem_ctx, out); + fail: + TALLOC_FREE(frame); + return status; } struct gensec_update_state { - struct tevent_immediate *im; + const struct gensec_security_ops *ops; + struct tevent_req *subreq; struct gensec_security *gensec_security; - DATA_BLOB in; DATA_BLOB out; + + /* + * only for sync backends, we should remove this + * once all backends are async. + */ + struct tevent_immediate *im; + DATA_BLOB in; }; static void gensec_update_async_trigger(struct tevent_context *ctx, struct tevent_immediate *im, void *private_data); +static void gensec_update_subreq_done(struct tevent_req *subreq); + /** * Next state function for the GENSEC state machine async version * @@ -298,17 +329,31 @@ _PUBLIC_ struct tevent_req *gensec_update_send(TALLOC_CTX *mem_ctx, return NULL; } - state->gensec_security = gensec_security; - state->in = in; - state->out = data_blob(NULL, 0); - state->im = tevent_create_immediate(state); - if (tevent_req_nomem(state->im, req)) { + state->ops = gensec_security->ops; + state->gensec_security = gensec_security; + + if (state->ops->update_send == NULL) { + state->in = in; + state->im = tevent_create_immediate(state); + if (tevent_req_nomem(state->im, req)) { + return tevent_req_post(req, ev); + } + + tevent_schedule_immediate(state->im, ev, + gensec_update_async_trigger, + req); + + return req; + } + + state->subreq = state->ops->update_send(state, ev, gensec_security, in); + if (tevent_req_nomem(state->subreq, req)) { return tevent_req_post(req, ev); } - tevent_schedule_immediate(state->im, ev, - gensec_update_async_trigger, - req); + tevent_req_set_callback(state->subreq, + gensec_update_subreq_done, + req); return req; } @@ -323,12 +368,71 @@ static void gensec_update_async_trigger(struct tevent_context *ctx, tevent_req_data(req, struct gensec_update_state); NTSTATUS status; - status = gensec_update(state->gensec_security, state, ctx, - state->in, &state->out); + status = state->ops->update(state->gensec_security, state, ctx, + state->in, &state->out); + if (tevent_req_nterror(req, status)) { + return; + } + + tevent_req_done(req); +} + +static void gensec_update_subreq_done(struct tevent_req *subreq) +{ + struct tevent_req *req = + tevent_req_callback_data(subreq, + struct tevent_req); + struct gensec_update_state *state = + tevent_req_data(req, + struct gensec_update_state); + NTSTATUS status; + + state->subreq = NULL; + + status = state->ops->update_recv(subreq, state, &state->out); + TALLOC_FREE(subreq); if (tevent_req_nterror(req, status)) { return; } + /* + * Because callers using the + * gensec_start_mech_by_authtype() never call + * gensec_want_feature(), it isn't sensible for them + * to have to call gensec_have_feature() manually, and + * these are not points of negotiation, but are + * asserted by the client + */ + switch (state->gensec_security->dcerpc_auth_level) { + case DCERPC_AUTH_LEVEL_INTEGRITY: + if (!gensec_have_feature(state->gensec_security, GENSEC_FEATURE_SIGN)) { + DEBUG(0,("Did not manage to negotiate mandetory feature " + "SIGN for dcerpc auth_level %u\n", + state->gensec_security->dcerpc_auth_level)); + tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); + return; + } + break; + case DCERPC_AUTH_LEVEL_PRIVACY: + if (!gensec_have_feature(state->gensec_security, GENSEC_FEATURE_SIGN)) { + DEBUG(0,("Did not manage to negotiate mandetory feature " + "SIGN for dcerpc auth_level %u\n", + state->gensec_security->dcerpc_auth_level)); + tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); + return; + } + if (!gensec_have_feature(state->gensec_security, GENSEC_FEATURE_SEAL)) { + DEBUG(0,("Did not manage to negotiate mandetory feature " + "SEAL for dcerpc auth_level %u\n", + state->gensec_security->dcerpc_auth_level)); + tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); + return; + } + break; + default: + break; + } + tevent_req_done(req); } diff --git a/auth/gensec/gensec_internal.h b/auth/gensec/gensec_internal.h index 41b6f0d6ef..c04164a3db 100644 --- a/auth/gensec/gensec_internal.h +++ b/auth/gensec/gensec_internal.h @@ -40,6 +40,13 @@ struct gensec_security_ops { NTSTATUS (*update)(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, struct tevent_context *ev, const DATA_BLOB in, DATA_BLOB *out); + struct tevent_req *(*update_send)(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct gensec_security *gensec_security, + const DATA_BLOB in); + NTSTATUS (*update_recv)(struct tevent_req *req, + TALLOC_CTX *out_mem_ctx, + DATA_BLOB *out); NTSTATUS (*seal_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx, uint8_t *data, size_t length, const uint8_t *whole_pdu, size_t pdu_length, -- cgit