mirror of
https://github.com/samba-team/samba.git
synced 2025-08-30 17:49:30 +03:00
auth/spnego: replace gensec_spnego_neg_loop() by real async processing of {start,step,finish}_fn()
Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Andreas Schneider <asn@samba.org>
This commit is contained in:
committed by
Andreas Schneider
parent
75e6728bcf
commit
832e9ff594
@ -159,60 +159,6 @@ static struct spnego_neg_state *gensec_spnego_neg_state(TALLOC_CTX *mem_ctx,
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS gensec_spnego_neg_loop(struct gensec_security *gensec_security,
|
|
||||||
struct spnego_state *spnego_state,
|
|
||||||
const const struct spnego_neg_ops *ops,
|
|
||||||
struct tevent_context *ev,
|
|
||||||
struct spnego_data *spnego_in,
|
|
||||||
TALLOC_CTX *out_mem_ctx,
|
|
||||||
DATA_BLOB *out)
|
|
||||||
{
|
|
||||||
struct spnego_neg_state *n = NULL;
|
|
||||||
NTSTATUS status;
|
|
||||||
DATA_BLOB sub_in = data_blob_null;
|
|
||||||
DATA_BLOB sub_out = data_blob_null;
|
|
||||||
|
|
||||||
*out = data_blob_null;
|
|
||||||
|
|
||||||
n = gensec_spnego_neg_state(out_mem_ctx, ops);
|
|
||||||
if (n == NULL) {
|
|
||||||
return NT_STATUS_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = n->ops->start_fn(gensec_security, spnego_state, n,
|
|
||||||
spnego_in, n, &sub_in);
|
|
||||||
if (GENSEC_UPDATE_IS_NTERROR(status)) {
|
|
||||||
TALLOC_FREE(n);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
|
|
||||||
status = gensec_update_ev(spnego_state->sub_sec_security,
|
|
||||||
n, ev, sub_in, &sub_out);
|
|
||||||
sub_in = data_blob_null;
|
|
||||||
if (NT_STATUS_IS_OK(status)) {
|
|
||||||
spnego_state->sub_sec_ready = true;
|
|
||||||
}
|
|
||||||
if (!GENSEC_UPDATE_IS_NTERROR(status)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sub_out = data_blob_null;
|
|
||||||
|
|
||||||
status = n->ops->step_fn(gensec_security, spnego_state, n,
|
|
||||||
spnego_in, status, n, &sub_in);
|
|
||||||
if (GENSEC_UPDATE_IS_NTERROR(status)) {
|
|
||||||
TALLOC_FREE(n);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
status = n->ops->finish_fn(gensec_security, spnego_state, n,
|
|
||||||
spnego_in, status, sub_out,
|
|
||||||
out_mem_ctx, out);
|
|
||||||
TALLOC_FREE(n);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gensec_spnego_update_sub_abort(struct spnego_state *spnego_state)
|
static void gensec_spnego_update_sub_abort(struct spnego_state *spnego_state)
|
||||||
{
|
{
|
||||||
spnego_state->sub_sec_ready = false;
|
spnego_state->sub_sec_ready = false;
|
||||||
@ -541,22 +487,6 @@ static const struct spnego_neg_ops gensec_spnego_create_negTokenInit_ops = {
|
|||||||
.finish_fn = gensec_spnego_create_negTokenInit_finish,
|
.finish_fn = gensec_spnego_create_negTokenInit_finish,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** create a negTokenInit
|
|
||||||
*
|
|
||||||
* This is the same packet, no matter if the client or server sends it first, but it is always the first packet
|
|
||||||
*/
|
|
||||||
static NTSTATUS gensec_spnego_create_negTokenInit(struct gensec_security *gensec_security,
|
|
||||||
struct spnego_state *spnego_state,
|
|
||||||
TALLOC_CTX *out_mem_ctx,
|
|
||||||
struct tevent_context *ev,
|
|
||||||
DATA_BLOB *out)
|
|
||||||
{
|
|
||||||
struct spnego_data *spnego_in = NULL;
|
|
||||||
return gensec_spnego_neg_loop(gensec_security, spnego_state,
|
|
||||||
&gensec_spnego_create_negTokenInit_ops,
|
|
||||||
ev, spnego_in, out_mem_ctx, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS gensec_spnego_client_negTokenInit_start(
|
static NTSTATUS gensec_spnego_client_negTokenInit_start(
|
||||||
struct gensec_security *gensec_security,
|
struct gensec_security *gensec_security,
|
||||||
struct spnego_state *spnego_state,
|
struct spnego_state *spnego_state,
|
||||||
@ -764,18 +694,6 @@ static const struct spnego_neg_ops gensec_spnego_client_negTokenInit_ops = {
|
|||||||
.finish_fn = gensec_spnego_client_negTokenInit_finish,
|
.finish_fn = gensec_spnego_client_negTokenInit_finish,
|
||||||
};
|
};
|
||||||
|
|
||||||
static NTSTATUS gensec_spnego_client_negTokenInit(struct gensec_security *gensec_security,
|
|
||||||
struct spnego_state *spnego_state,
|
|
||||||
struct tevent_context *ev,
|
|
||||||
struct spnego_data *spnego_in,
|
|
||||||
TALLOC_CTX *out_mem_ctx,
|
|
||||||
DATA_BLOB *out)
|
|
||||||
{
|
|
||||||
return gensec_spnego_neg_loop(gensec_security, spnego_state,
|
|
||||||
&gensec_spnego_client_negTokenInit_ops,
|
|
||||||
ev, spnego_in, out_mem_ctx, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS gensec_spnego_client_negTokenTarg_start(
|
static NTSTATUS gensec_spnego_client_negTokenTarg_start(
|
||||||
struct gensec_security *gensec_security,
|
struct gensec_security *gensec_security,
|
||||||
struct spnego_state *spnego_state,
|
struct spnego_state *spnego_state,
|
||||||
@ -1166,17 +1084,6 @@ static const struct spnego_neg_ops gensec_spnego_client_negTokenTarg_ops = {
|
|||||||
.finish_fn = gensec_spnego_client_negTokenTarg_finish,
|
.finish_fn = gensec_spnego_client_negTokenTarg_finish,
|
||||||
};
|
};
|
||||||
|
|
||||||
static NTSTATUS gensec_spnego_client_negTokenTarg(struct gensec_security *gensec_security,
|
|
||||||
struct spnego_state *spnego_state,
|
|
||||||
struct tevent_context *ev,
|
|
||||||
struct spnego_data *spnego_in,
|
|
||||||
TALLOC_CTX *out_mem_ctx,
|
|
||||||
DATA_BLOB *out)
|
|
||||||
{
|
|
||||||
return gensec_spnego_neg_loop(gensec_security, spnego_state,
|
|
||||||
&gensec_spnego_client_negTokenTarg_ops,
|
|
||||||
ev, spnego_in, out_mem_ctx, out);
|
|
||||||
}
|
|
||||||
/** create a server negTokenTarg
|
/** create a server negTokenTarg
|
||||||
*
|
*
|
||||||
* This is the case, where the client is the first one who sends data
|
* This is the case, where the client is the first one who sends data
|
||||||
@ -1440,18 +1347,6 @@ static const struct spnego_neg_ops gensec_spnego_server_negTokenInit_ops = {
|
|||||||
.finish_fn = gensec_spnego_server_negTokenInit_finish,
|
.finish_fn = gensec_spnego_server_negTokenInit_finish,
|
||||||
};
|
};
|
||||||
|
|
||||||
static NTSTATUS gensec_spnego_server_negTokenInit(struct gensec_security *gensec_security,
|
|
||||||
struct spnego_state *spnego_state,
|
|
||||||
struct tevent_context *ev,
|
|
||||||
struct spnego_data *spnego_in,
|
|
||||||
TALLOC_CTX *out_mem_ctx,
|
|
||||||
DATA_BLOB *out)
|
|
||||||
{
|
|
||||||
return gensec_spnego_neg_loop(gensec_security, spnego_state,
|
|
||||||
&gensec_spnego_server_negTokenInit_ops,
|
|
||||||
ev, spnego_in, out_mem_ctx, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS gensec_spnego_server_negTokenTarg_start(
|
static NTSTATUS gensec_spnego_server_negTokenTarg_start(
|
||||||
struct gensec_security *gensec_security,
|
struct gensec_security *gensec_security,
|
||||||
struct spnego_state *spnego_state,
|
struct spnego_state *spnego_state,
|
||||||
@ -1633,18 +1528,6 @@ static const struct spnego_neg_ops gensec_spnego_server_negTokenTarg_ops = {
|
|||||||
.finish_fn = gensec_spnego_server_negTokenTarg_finish,
|
.finish_fn = gensec_spnego_server_negTokenTarg_finish,
|
||||||
};
|
};
|
||||||
|
|
||||||
static NTSTATUS gensec_spnego_server_negTokenTarg(struct gensec_security *gensec_security,
|
|
||||||
struct spnego_state *spnego_state,
|
|
||||||
struct tevent_context *ev,
|
|
||||||
struct spnego_data *spnego_in,
|
|
||||||
TALLOC_CTX *out_mem_ctx,
|
|
||||||
DATA_BLOB *out)
|
|
||||||
{
|
|
||||||
return gensec_spnego_neg_loop(gensec_security, spnego_state,
|
|
||||||
&gensec_spnego_server_negTokenTarg_ops,
|
|
||||||
ev, spnego_in, out_mem_ctx, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct gensec_spnego_update_state {
|
struct gensec_spnego_update_state {
|
||||||
struct tevent_context *ev;
|
struct tevent_context *ev;
|
||||||
struct gensec_security *gensec;
|
struct gensec_security *gensec;
|
||||||
@ -1661,6 +1544,8 @@ struct gensec_spnego_update_state {
|
|||||||
DATA_BLOB out;
|
DATA_BLOB out;
|
||||||
} sub;
|
} sub;
|
||||||
|
|
||||||
|
struct spnego_neg_state *n;
|
||||||
|
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
DATA_BLOB out;
|
DATA_BLOB out;
|
||||||
};
|
};
|
||||||
@ -1965,9 +1850,8 @@ static void gensec_spnego_update_pre(struct tevent_req *req)
|
|||||||
struct gensec_spnego_update_state *state =
|
struct gensec_spnego_update_state *state =
|
||||||
tevent_req_data(req,
|
tevent_req_data(req,
|
||||||
struct gensec_spnego_update_state);
|
struct gensec_spnego_update_state);
|
||||||
struct gensec_security *gensec_security = state->gensec;
|
|
||||||
struct spnego_state *spnego_state = state->spnego;
|
struct spnego_state *spnego_state = state->spnego;
|
||||||
struct tevent_context *ev = state->ev;
|
const struct spnego_neg_ops *ops = NULL;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
|
||||||
state->sub.needed = false;
|
state->sub.needed = false;
|
||||||
@ -1986,65 +1870,29 @@ static void gensec_spnego_update_pre(struct tevent_req *req)
|
|||||||
case SPNEGO_CLIENT_START:
|
case SPNEGO_CLIENT_START:
|
||||||
if (state->spnego_in == NULL) {
|
if (state->spnego_in == NULL) {
|
||||||
/* client to produce negTokenInit */
|
/* client to produce negTokenInit */
|
||||||
status = gensec_spnego_create_negTokenInit(gensec_security,
|
ops = &gensec_spnego_create_negTokenInit_ops;
|
||||||
spnego_state, state, ev,
|
|
||||||
&spnego_state->out_frag);
|
|
||||||
if (GENSEC_UPDATE_IS_NTERROR(status)) {
|
|
||||||
tevent_req_nterror(req, status);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = gensec_spnego_client_negTokenInit(gensec_security,
|
ops = &gensec_spnego_client_negTokenInit_ops;
|
||||||
spnego_state, ev,
|
|
||||||
state->spnego_in, state,
|
|
||||||
&spnego_state->out_frag);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPNEGO_CLIENT_TARG:
|
case SPNEGO_CLIENT_TARG:
|
||||||
status = gensec_spnego_client_negTokenTarg(gensec_security,
|
ops = &gensec_spnego_client_negTokenTarg_ops;
|
||||||
spnego_state, ev,
|
|
||||||
state->spnego_in, state,
|
|
||||||
&spnego_state->out_frag);
|
|
||||||
if (GENSEC_UPDATE_IS_NTERROR(status)) {
|
|
||||||
tevent_req_nterror(req, status);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPNEGO_SERVER_START:
|
case SPNEGO_SERVER_START:
|
||||||
if (state->spnego_in == NULL) {
|
if (state->spnego_in == NULL) {
|
||||||
/* server to produce negTokenInit */
|
/* server to produce negTokenInit */
|
||||||
status = gensec_spnego_create_negTokenInit(gensec_security,
|
ops = &gensec_spnego_create_negTokenInit_ops;
|
||||||
spnego_state, state, ev,
|
|
||||||
&spnego_state->out_frag);
|
|
||||||
if (GENSEC_UPDATE_IS_NTERROR(status)) {
|
|
||||||
tevent_req_nterror(req, status);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = gensec_spnego_server_negTokenInit(gensec_security,
|
ops = &gensec_spnego_server_negTokenInit_ops;
|
||||||
spnego_state, ev,
|
|
||||||
state->spnego_in, state,
|
|
||||||
&spnego_state->out_frag);
|
|
||||||
if (GENSEC_UPDATE_IS_NTERROR(status)) {
|
|
||||||
tevent_req_nterror(req, status);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPNEGO_SERVER_TARG:
|
case SPNEGO_SERVER_TARG:
|
||||||
status = gensec_spnego_server_negTokenTarg(gensec_security,
|
ops = &gensec_spnego_server_negTokenTarg_ops;
|
||||||
spnego_state, ev,
|
|
||||||
state->spnego_in, state,
|
|
||||||
&spnego_state->out_frag);
|
|
||||||
if (GENSEC_UPDATE_IS_NTERROR(status)) {
|
|
||||||
tevent_req_nterror(req, status);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -2052,7 +1900,31 @@ static void gensec_spnego_update_pre(struct tevent_req *req)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spnego_state->out_status = status;
|
state->n = gensec_spnego_neg_state(state, ops);
|
||||||
|
if (tevent_req_nomem(state->n, req)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = ops->start_fn(state->gensec, spnego_state, state->n,
|
||||||
|
state->spnego_in, state, &state->sub.in);
|
||||||
|
if (GENSEC_UPDATE_IS_NTERROR(status)) {
|
||||||
|
tevent_req_nterror(req, status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NT_STATUS_IS_OK(status)) {
|
||||||
|
/*
|
||||||
|
* Call finish_fn() with an empty
|
||||||
|
* blob and NT_STATUS_OK.
|
||||||
|
*/
|
||||||
|
state->sub.status = NT_STATUS_OK;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* MORE_PROCESSING_REQUIRED =>
|
||||||
|
* we need to call gensec_update_send().
|
||||||
|
*/
|
||||||
|
state->sub.needed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gensec_spnego_update_done(struct tevent_req *subreq)
|
static void gensec_spnego_update_done(struct tevent_req *subreq)
|
||||||
@ -2080,6 +1952,7 @@ static void gensec_spnego_update_post(struct tevent_req *req)
|
|||||||
tevent_req_data(req,
|
tevent_req_data(req,
|
||||||
struct gensec_spnego_update_state);
|
struct gensec_spnego_update_state);
|
||||||
struct spnego_state *spnego_state = state->spnego;
|
struct spnego_state *spnego_state = state->spnego;
|
||||||
|
const struct spnego_neg_ops *ops = NULL;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
|
||||||
state->sub.in = data_blob_null;
|
state->sub.in = data_blob_null;
|
||||||
@ -2093,11 +1966,78 @@ static void gensec_spnego_update_post(struct tevent_req *req)
|
|||||||
goto respond;
|
goto respond;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
ops = state->n->ops;
|
||||||
* For now just handle the sync processing done
|
|
||||||
* in gensec_spnego_update_pre()
|
if (GENSEC_UPDATE_IS_NTERROR(state->sub.status)) {
|
||||||
*/
|
|
||||||
status = spnego_state->out_status;
|
|
||||||
|
/*
|
||||||
|
* gensec_update_recv() returned an error,
|
||||||
|
* let's see if the step_fn() want to
|
||||||
|
* handle it and negotiate something else.
|
||||||
|
*/
|
||||||
|
|
||||||
|
status = ops->step_fn(state->gensec,
|
||||||
|
spnego_state,
|
||||||
|
state->n,
|
||||||
|
state->spnego_in,
|
||||||
|
state->sub.status,
|
||||||
|
state,
|
||||||
|
&state->sub.in);
|
||||||
|
if (GENSEC_UPDATE_IS_NTERROR(status)) {
|
||||||
|
tevent_req_nterror(req, status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->sub.out = data_blob_null;
|
||||||
|
state->sub.status = NT_STATUS_INTERNAL_ERROR;
|
||||||
|
|
||||||
|
if (NT_STATUS_IS_OK(status)) {
|
||||||
|
/*
|
||||||
|
* Call finish_fn() with an empty
|
||||||
|
* blob and NT_STATUS_OK.
|
||||||
|
*/
|
||||||
|
state->sub.status = NT_STATUS_OK;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* MORE_PROCESSING_REQUIRED...
|
||||||
|
*/
|
||||||
|
state->sub.needed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->sub.needed) {
|
||||||
|
struct tevent_req *subreq = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We may need one more roundtrip...
|
||||||
|
*/
|
||||||
|
subreq = gensec_update_send(state, state->ev,
|
||||||
|
spnego_state->sub_sec_security,
|
||||||
|
state->sub.in);
|
||||||
|
if (tevent_req_nomem(subreq, req)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tevent_req_set_callback(subreq,
|
||||||
|
gensec_spnego_update_done,
|
||||||
|
req);
|
||||||
|
state->sub.needed = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = ops->finish_fn(state->gensec,
|
||||||
|
spnego_state,
|
||||||
|
state->n,
|
||||||
|
state->spnego_in,
|
||||||
|
state->sub.status,
|
||||||
|
state->sub.out,
|
||||||
|
spnego_state,
|
||||||
|
&spnego_state->out_frag);
|
||||||
|
TALLOC_FREE(state->n);
|
||||||
|
if (GENSEC_UPDATE_IS_NTERROR(status)) {
|
||||||
|
tevent_req_nterror(req, status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (NT_STATUS_IS_OK(status)) {
|
if (NT_STATUS_IS_OK(status)) {
|
||||||
bool reset_full = true;
|
bool reset_full = true;
|
||||||
|
Reference in New Issue
Block a user