Allow for graceful restart if acceptor ignores reauth token
[mech_eap.orig] / util_sm.c
index 0366168..0788bcf 100644 (file)
--- a/util_sm.c
+++ b/util_sm.c
@@ -81,11 +81,11 @@ gssEapStateToString(enum gss_eap_state state)
 void
 gssEapSmTransition(gss_ctx_id_t ctx, enum gss_eap_state state)
 {
-    assert(state > ctx->state);
     assert(state <= GSSEAP_STATE_ESTABLISHED);
 
     fprintf(stderr, "GSS-EAP: state transition %s->%s\n",
-            gssEapStateToString(ctx->state), gssEapStateToString(state));
+            gssEapStateToString(GSSEAP_SM_STATE(ctx)),
+            gssEapStateToString(state));
 
     ctx->state = state;
 }
@@ -236,7 +236,7 @@ gssEapSmStep(OM_uint32 *minor,
         initialContextToken = 1;
     }
 
-    if (ctx->state == GSSEAP_STATE_ESTABLISHED) {
+    if (CTX_IS_ESTABLISHED(ctx)) {
         major = GSS_S_BAD_STATUS;
         *minor = GSSEAP_CONTEXT_ESTABLISHED;
         goto cleanup;
@@ -266,12 +266,24 @@ gssEapSmStep(OM_uint32 *minor,
         if ((smp->validStates & ctx->state) == 0)
             continue;
 
+        /*
+         * We special case the first call to gss_init_sec_context so that
+         * all token providers have the opportunity to generate an initial
+         * context token. Providers where inputTokenType is ITOK_TYPE_NONE
+         * are always called and generally act on state transition boundaries,
+         * for example to advance the state after a series of optional tokens
+         * (as is the case with the extension token exchange) or to generate
+         * a new token after the state was advanced by a provider which did
+         * not emit a token.
+         */
         if (smp->inputTokenType == ITOK_TYPE_NONE || initialContextToken) {
             processToken = 1;
         } else if ((smFlags & SM_FLAG_TRANSITED) == 0) {
+            /* Don't regurgitate a token which belonds to a previous state. */
             for (j = 0; j < innerInputTokens->count; j++) {
                 if ((inputTokenTypes[j] & ITOK_TYPE_MASK) == smp->inputTokenType) {
                     if (processToken) {
+                        /* Check for duplicate inner tokens */
                         major = GSS_S_DEFECTIVE_TOKEN;
                         *minor = GSSEAP_DUPLICATE_ITOK;
                         break;
@@ -298,8 +310,12 @@ gssEapSmStep(OM_uint32 *minor,
 
             if (inputTokenType != NULL)
                 *inputTokenType |= ITOK_FLAG_VERIFIED;
-            if (ctx->state != oldState)
+            if (smFlags & SM_FLAG_RESTART) {
+                assert(ctx->state < oldState);
+                i = 0;
+            } else if (ctx->state != oldState) {
                 smFlags |= SM_FLAG_TRANSITED;
+            }
 
             if (innerOutputToken.value != NULL) {
                 innerOutputTokens->elements[innerOutputTokens->count] = innerOutputToken;
@@ -321,6 +337,7 @@ gssEapSmStep(OM_uint32 *minor,
             }
         } else if ((smp->itokFlags & SM_ITOK_FLAG_REQUIRED) &&
             smp->inputTokenType != ITOK_TYPE_NONE) {
+            /* Check for required inner tokens */
             major = GSS_S_DEFECTIVE_TOKEN;
             *minor = GSSEAP_MISSING_REQUIRED_ITOK;
             break;