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;
- if (gensec_security->child_security != NULL) {
- return NT_STATUS_INVALID_PARAMETER;
+ if (gensec_security->subcontext) {
+ /*
+ * gensec modules are not allowed to call the sync version.
+ */
+ return NT_STATUS_INTERNAL_ERROR;
}
frame = talloc_stackframe();
tevent_loop_allow_nesting(ev);
}
- subreq = ops->update_send(frame, ev, gensec_security, in);
+ subreq = gensec_update_send(frame, ev, gensec_security, in);
if (subreq == NULL) {
status = NT_STATUS_NO_MEMORY;
goto fail;
if (!ok) {
goto fail;
}
- status = ops->update_recv(subreq, out_mem_ctx, out);
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
-
- /*
- * 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
- */
- status = gensec_verify_features(gensec_security);
+ status = gensec_update_recv(subreq, out_mem_ctx, out);
fail:
TALLOC_FREE(frame);
return status;
DATA_BLOB out;
};
+static void gensec_update_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state);
static void gensec_update_done(struct tevent_req *subreq);
/**
if (req == NULL) {
return NULL;
}
-
state->ops = gensec_security->ops;
state->gensec_security = gensec_security;
+ if (gensec_security->update_busy_ptr != NULL) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return tevent_req_post(req, ev);
+ }
+
if (gensec_security->child_security != NULL) {
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
return tevent_req_post(req, ev);
}
+ gensec_security->update_busy_ptr = &state->gensec_security;
+ tevent_req_set_cleanup_fn(req, gensec_update_cleanup);
+
subreq = state->ops->update_send(state, ev, gensec_security, in);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
tevent_req_set_callback(subreq, gensec_update_done, req);
+ DBG_DEBUG("%s[%p]: subreq: %p\n", state->ops->name,
+ state->gensec_security, subreq);
+
return req;
}
+static void gensec_update_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state)
+{
+ struct gensec_update_state *state =
+ tevent_req_data(req,
+ struct gensec_update_state);
+
+ if (state->gensec_security == NULL) {
+ return;
+ }
+
+ if (state->gensec_security->update_busy_ptr == &state->gensec_security) {
+ state->gensec_security->update_busy_ptr = NULL;
+ }
+
+ state->gensec_security = NULL;
+}
+
static void gensec_update_done(struct tevent_req *subreq)
{
struct tevent_req *req =
tevent_req_data(req,
struct gensec_update_state);
NTSTATUS status;
+ const char *debug_subreq = NULL;
+
+ if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) {
+ /*
+ * We need to call tevent_req_print()
+ * before calling the _recv function,
+ * before tevent_req_received() was called.
+ * in order to print the pointer value of
+ * the subreq state.
+ */
+ debug_subreq = tevent_req_print(state, subreq);
+ }
status = state->ops->update_recv(subreq, state, &state->out);
TALLOC_FREE(subreq);
state->status = status;
- if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- tevent_req_done(req);
+ if (GENSEC_UPDATE_IS_NTERROR(status)) {
+ DBG_INFO("%s[%p]: %s%s%s\n", state->ops->name,
+ state->gensec_security, nt_errstr(status),
+ debug_subreq ? " " : "",
+ debug_subreq ? debug_subreq : "");
+ tevent_req_nterror(req, status);
return;
}
- if (tevent_req_nterror(req, status)) {
+ DBG_DEBUG("%s[%p]: %s %s\n", state->ops->name,
+ state->gensec_security, nt_errstr(status),
+ debug_subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ tevent_req_done(req);
return;
}