auth/gensec: make sure there's only one pending gensec_update_send() per context
authorStefan Metzmacher <metze@samba.org>
Thu, 11 May 2017 11:28:10 +0000 (13:28 +0200)
committerAndrew Bartlett <abartlet@samba.org>
Sun, 21 May 2017 19:05:11 +0000 (21:05 +0200)
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
auth/gensec/gensec.c
auth/gensec/gensec_internal.h

index cf00a3632471f14ce8d2b63acfa2e166cdec886e..014516f2f6d11d1f11fe4bb2ab946ef2871ad82b 100644 (file)
@@ -403,6 +403,8 @@ struct gensec_update_state {
        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);
 
 /**
@@ -430,15 +432,22 @@ _PUBLIC_ struct tevent_req *gensec_update_send(TALLOC_CTX *mem_ctx,
        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);
@@ -448,6 +457,24 @@ _PUBLIC_ struct tevent_req *gensec_update_send(TALLOC_CTX *mem_ctx,
        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 =
index b3a84344d2dce1b664ecdd41c64ef642b68ced0d..c73be11ded69f3dfdcef735c0db75b971be7f2c1 100644 (file)
@@ -113,6 +113,12 @@ struct gensec_security {
 
        struct gensec_security *parent_security;
        struct gensec_security *child_security;
+
+       /*
+        * This is used to mark the context as being
+        * busy in an async gensec_update_send().
+        */
+       struct gensec_security **update_busy_ptr;
 };
 
 /* this structure is used by backends to determine the size of some critical types */