summaryrefslogtreecommitdiff
path: root/auth
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2017-06-14 11:01:23 +0200
committerAndreas Schneider <asn@cryptomilk.org>2017-07-25 13:51:11 +0200
commit832e9ff59402f2c369aac0a9ee65364de75d057c (patch)
treeaba6818e1d4164e722e52b8c1faad5d68d49ece8 /auth
parent75e6728bcf25d24392f1dba28444c6696632107b (diff)
downloadsamba-832e9ff59402f2c369aac0a9ee65364de75d057c.tar.gz
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>
Diffstat (limited to 'auth')
-rw-r--r--auth/gensec/spnego.c274
1 files changed, 107 insertions, 167 deletions
diff --git a/auth/gensec/spnego.c b/auth/gensec/spnego.c
index d2cae261400..ce3e3c57863 100644
--- a/auth/gensec/spnego.c
+++ b/auth/gensec/spnego.c
@@ -159,60 +159,6 @@ static struct spnego_neg_state *gensec_spnego_neg_state(TALLOC_CTX *mem_ctx,
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)
{
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,
};
-/** 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(
struct gensec_security *gensec_security,
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,
};
-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(
struct gensec_security *gensec_security,
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,
};
-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
*
* 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,
};
-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(
struct gensec_security *gensec_security,
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,
};
-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 tevent_context *ev;
struct gensec_security *gensec;
@@ -1661,6 +1544,8 @@ struct gensec_spnego_update_state {
DATA_BLOB out;
} sub;
+ struct spnego_neg_state *n;
+
NTSTATUS status;
DATA_BLOB out;
};
@@ -1965,9 +1850,8 @@ static void gensec_spnego_update_pre(struct tevent_req *req)
struct gensec_spnego_update_state *state =
tevent_req_data(req,
struct gensec_spnego_update_state);
- struct gensec_security *gensec_security = state->gensec;
struct spnego_state *spnego_state = state->spnego;
- struct tevent_context *ev = state->ev;
+ const struct spnego_neg_ops *ops = NULL;
NTSTATUS status;
state->sub.needed = false;
@@ -1986,65 +1870,29 @@ static void gensec_spnego_update_pre(struct tevent_req *req)
case SPNEGO_CLIENT_START:
if (state->spnego_in == NULL) {
/* client to produce negTokenInit */
- status = gensec_spnego_create_negTokenInit(gensec_security,
- spnego_state, state, ev,
- &spnego_state->out_frag);
- if (GENSEC_UPDATE_IS_NTERROR(status)) {
- tevent_req_nterror(req, status);
- return;
- }
+ ops = &gensec_spnego_create_negTokenInit_ops;
break;
}
- status = gensec_spnego_client_negTokenInit(gensec_security,
- spnego_state, ev,
- state->spnego_in, state,
- &spnego_state->out_frag);
+ ops = &gensec_spnego_client_negTokenInit_ops;
break;
case SPNEGO_CLIENT_TARG:
- status = gensec_spnego_client_negTokenTarg(gensec_security,
- spnego_state, ev,
- state->spnego_in, state,
- &spnego_state->out_frag);
- if (GENSEC_UPDATE_IS_NTERROR(status)) {
- tevent_req_nterror(req, status);
- return;
- }
+ ops = &gensec_spnego_client_negTokenTarg_ops;
break;
case SPNEGO_SERVER_START:
if (state->spnego_in == NULL) {
/* server to produce negTokenInit */
- status = gensec_spnego_create_negTokenInit(gensec_security,
- spnego_state, state, ev,
- &spnego_state->out_frag);
- if (GENSEC_UPDATE_IS_NTERROR(status)) {
- tevent_req_nterror(req, status);
- return;
- }
+ ops = &gensec_spnego_create_negTokenInit_ops;
break;
}
- status = gensec_spnego_server_negTokenInit(gensec_security,
- spnego_state, ev,
- state->spnego_in, state,
- &spnego_state->out_frag);
- if (GENSEC_UPDATE_IS_NTERROR(status)) {
- tevent_req_nterror(req, status);
- return;
- }
+ ops = &gensec_spnego_server_negTokenInit_ops;
break;
case SPNEGO_SERVER_TARG:
- status = gensec_spnego_server_negTokenTarg(gensec_security,
- spnego_state, ev,
- state->spnego_in, state,
- &spnego_state->out_frag);
- if (GENSEC_UPDATE_IS_NTERROR(status)) {
- tevent_req_nterror(req, status);
- return;
- }
+ ops = &gensec_spnego_server_negTokenTarg_ops;
break;
default:
@@ -2052,7 +1900,31 @@ static void gensec_spnego_update_pre(struct tevent_req *req)
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)
@@ -2080,6 +1952,7 @@ static void gensec_spnego_update_post(struct tevent_req *req)
tevent_req_data(req,
struct gensec_spnego_update_state);
struct spnego_state *spnego_state = state->spnego;
+ const struct spnego_neg_ops *ops = NULL;
NTSTATUS status;
state->sub.in = data_blob_null;
@@ -2093,11 +1966,78 @@ static void gensec_spnego_update_post(struct tevent_req *req)
goto respond;
}
- /*
- * For now just handle the sync processing done
- * in gensec_spnego_update_pre()
- */
- status = spnego_state->out_status;
+ ops = state->n->ops;
+
+ if (GENSEC_UPDATE_IS_NTERROR(state->sub.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)) {
bool reset_full = true;