more TLV cleanups
authorLuke Howard <lukeh@padl.com>
Tue, 8 Mar 2011 12:36:11 +0000 (23:36 +1100)
committerLuke Howard <lukeh@padl.com>
Tue, 8 Mar 2011 13:38:48 +0000 (00:38 +1100)
accept_sec_context.c
init_sec_context.c
util.h
util_sm.c

index 9627e88..5b3d53f 100644 (file)
@@ -179,8 +179,9 @@ eapGssSmAcceptIdentity(OM_uint32 *minor,
 
     wpabuf_free(reqData);
 
+    GSSEAP_SM_TRANSITION_NEXT(ctx);
+
     *minor = 0;
-    *smFlags |= SM_FLAG_TRANSITION;
 
     return GSS_S_CONTINUE_NEEDED;
 }
@@ -538,7 +539,7 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor,
         if (GSS_ERROR(major))
             goto cleanup;
 
-        *smFlags |= SM_FLAG_TRANSITION;
+        GSSEAP_SM_TRANSITION_NEXT(ctx);
     }
 
     major = GSS_S_CONTINUE_NEEDED;
@@ -636,9 +637,9 @@ eapGssSmAcceptCompleteInitiatorExts(OM_uint32 *minor,
                                     gss_buffer_t outputToken,
                                     OM_uint32 *smFlags)
 {
-    *minor = 0;
+    GSSEAP_SM_TRANSITION_NEXT(ctx);
 
-    *smFlags |= SM_FLAG_TRANSITION | SM_FLAG_STOP_EVAL;
+    *minor = 0;
 
     return GSS_S_CONTINUE_NEEDED;
 }
@@ -656,10 +657,10 @@ eapGssSmAcceptCompleteAcceptorExts(OM_uint32 *minor,
                                    gss_buffer_t outputToken,
                                    OM_uint32 *smFlags)
 {
-    *minor = 0;
+    GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
 
-    gssEapSmTransition(ctx, GSSEAP_STATE_ESTABLISHED);
-    *smFlags |= SM_FLAG_STOP_EVAL;
+    *minor = 0;
+    *smFlags |= SM_FLAG_FORCE_SEND_TOKEN;
 
     return GSS_S_COMPLETE;
 }
@@ -899,8 +900,7 @@ eapGssSmAcceptGssReauth(OM_uint32 *minor,
         major = acceptReadyKrb(minor, ctx, cred,
                                krbInitiator, mech, timeRec);
         if (major == GSS_S_COMPLETE) {
-            gssEapSmTransition(ctx, GSSEAP_STATE_ESTABLISHED);
-            *smFlags |= SM_FLAG_STOP_EVAL;
+            GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
         }
     }
 
index 4c82964..8104a63 100644 (file)
@@ -477,15 +477,13 @@ eapGssSmInitGssReauth(OM_uint32 *minor,
 
     ctx->gssFlags = gssFlags;
 
-    *smFlags |= SM_FLAG_STOP_EVAL;
-
     if (major == GSS_S_COMPLETE) {
         major = gssEapReauthComplete(minor, ctx, cred, actualMech, timeRec);
         if (GSS_ERROR(major))
             goto cleanup;
-        gssEapSmTransition(ctx, GSSEAP_STATE_ESTABLISHED);
+        GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
     } else {
-        gssEapSmTransition(ctx, GSSEAP_STATE_REAUTHENTICATE);
+        GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_REAUTHENTICATE);
     }
 
 cleanup:
@@ -563,9 +561,11 @@ eapGssSmInitIdentity(OM_uint32 *minor,
         return GSS_S_FAILURE;
     }
 
+    GSSEAP_SM_TRANSITION_NEXT(ctx);
+
     /* force sending of empty token */
     *minor = 0;
-    *smFlags |= SM_FLAG_TRANSITION | SM_FLAG_FORCE_SEND_TOKEN;
+    *smFlags |= SM_FLAG_FORCE_SEND_TOKEN;
 
     return GSS_S_CONTINUE_NEEDED;
 }
@@ -618,7 +618,7 @@ eapGssSmInitAuthenticate(OM_uint32 *minor,
 
         ctx->flags &= ~(CTX_FLAG_EAP_SUCCESS);
         major = GSS_S_CONTINUE_NEEDED;
-        *smFlags |= SM_FLAG_TRANSITION;
+        GSSEAP_SM_TRANSITION_NEXT(ctx);
     } else if (ctx->flags & CTX_FLAG_EAP_FAIL) {
         major = GSS_S_DEFECTIVE_CREDENTIAL;
         *minor = GSSEAP_PEER_AUTH_FAILURE;
@@ -718,9 +718,10 @@ eapGssSmInitCompleteInitiatorExts(OM_uint32 *minor,
                                   gss_buffer_t outputToken,
                                   OM_uint32 *smFlags)
 {
-    *minor = 0;
+    GSSEAP_SM_TRANSITION_NEXT(ctx);
 
-    *smFlags |= SM_FLAG_TRANSITION | SM_FLAG_STOP_EVAL;
+    *minor = 0;
+    *smFlags |= SM_FLAG_FORCE_SEND_TOKEN;
 
     return GSS_S_CONTINUE_NEEDED;
 }
@@ -738,10 +739,9 @@ eapGssSmInitCompleteAcceptorExts(OM_uint32 *minor,
                                  gss_buffer_t outputToken,
                                  OM_uint32 *smFlags)
 {
-    *minor = 0;
+    GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
 
-    gssEapSmTransition(ctx, GSSEAP_STATE_ESTABLISHED);
-    *smFlags |= SM_FLAG_STOP_EVAL;
+    *minor = 0;
 
     return GSS_S_COMPLETE;
 }
diff --git a/util.h b/util.h
index 85123d0..8afc97c 100644 (file)
--- a/util.h
+++ b/util.h
@@ -546,6 +546,15 @@ enum gss_eap_state {
 
 #define GSSEAP_STATE_NEXT(s)    ((s) << 1)
 
+#ifdef GSSEAP_DEBUG
+void gssEapSmTransition(gss_ctx_id_t ctx, enum gss_eap_state state);
+#define GSSEAP_SM_TRANSITION(ctx, state)    gssEapSmTransition((ctx), (state))
+#else
+#define GSSEAP_SM_TRANSITION(ctx, state)    do { (ctx)->state = (state); } while (0)
+#endif
+
+#define GSSEAP_SM_TRANSITION_NEXT(ctx)      GSSEAP_SM_TRANSITION((ctx), GSSEAP_STATE_NEXT((ctx)->state))
+
 /* state machine entry */
 struct gss_eap_sm {
     OM_uint32 inputTokenType;
@@ -565,9 +574,8 @@ struct gss_eap_sm {
                               OM_uint32 *);
 };
 
-#define SM_FLAG_TRANSITION                  0x00000001  /* transition to next state */
-#define SM_FLAG_FORCE_SEND_TOKEN            0x00000002  /* send token even if empty */
-#define SM_FLAG_STOP_EVAL                   0x00000004  /* no more handlers for this state */
+#define SM_FLAG_FORCE_SEND_TOKEN            0x00000001  /* send token even if empty */
+#define SM_FLAG_STOP_EVAL                   0x00000002  /* no more handlers for this state */
 
 #define SM_ITOK_FLAG_CRITICAL               0x00000001  /* sent tokens marked critical */
 #define SM_ITOK_FLAG_REQUIRED               0x00000002  /* received tokens must be present */
index fae6528..d800e82 100644 (file)
--- a/util_sm.c
+++ b/util_sm.c
 
 #include "gssapiP_eap.h"
 
+/* private flags */
+#define SM_FLAG_TRANSITED                   0x80000000
+
+#define SM_ASSERT_VALID(ctx, status)        do { \
+        assert(GSS_ERROR((status)) || \
+               ((status) == GSS_S_CONTINUE_NEEDED && ((ctx)->state > GSSEAP_STATE_INITIAL && (ctx)->state < GSSEAP_STATE_ESTABLISHED)) || \
+               ((status) == GSS_S_COMPLETE && (ctx)->state == GSSEAP_STATE_ESTABLISHED)); \
+    } while (0)
+
 static const char *
 gssEapStateToString(enum gss_eap_state state)
 {
@@ -68,19 +77,19 @@ gssEapStateToString(enum gss_eap_state state)
     return s;
 }
 
+#ifdef GSSEAP_DEBUG
 void
 gssEapSmTransition(gss_ctx_id_t ctx, enum gss_eap_state state)
 {
     assert(state > ctx->state);
     assert(state <= GSSEAP_STATE_ESTABLISHED);
 
-#ifdef GSSEAP_DEBUG
     fprintf(stderr, "GSS-EAP: state transition %s->%s\n",
             gssEapStateToString(ctx->state), gssEapStateToString(state));
-#endif
 
     ctx->state = state;
 }
+#endif
 
 static OM_uint32
 makeErrorToken(OM_uint32 *minor,
@@ -116,6 +125,56 @@ makeErrorToken(OM_uint32 *minor,
     return gss_add_buffer_set_member(minor, &errorBuffer, outputToken);
 }
 
+static OM_uint32
+allocInnerTokens(OM_uint32 *minor,
+                 size_t count,
+                 gss_buffer_set_t *pTokens,
+                 OM_uint32 **pTokenTypes)
+{
+    OM_uint32 major, tmpMinor;
+    gss_buffer_set_t tokens = GSS_C_NO_BUFFER_SET;
+    OM_uint32 *tokenTypes = NULL;
+
+    major = gss_create_empty_buffer_set(minor, &tokens);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    assert(tokens->count == 0);
+    assert(tokens->elements == NULL);
+
+    tokens->elements = (gss_buffer_desc *)GSSEAP_CALLOC(count, sizeof(gss_buffer_desc));
+    if (tokens->elements == NULL) {
+        major = GSS_S_FAILURE;
+        *minor = ENOMEM;
+        goto cleanup;
+    }
+
+    tokenTypes = (OM_uint32 *)GSSEAP_CALLOC(count, sizeof(OM_uint32));
+    if (tokenTypes == NULL) {
+        major = GSS_S_FAILURE;
+        *minor = ENOMEM;
+        goto cleanup;
+    }
+
+    major = GSS_S_COMPLETE;
+    *minor = 0;
+
+cleanup:
+    if (GSS_ERROR(major)) {
+        gss_release_buffer_set(&tmpMinor, &tokens);
+        tokens = GSS_C_NO_BUFFER_SET;
+        if (tokenTypes != NULL) {
+            GSSEAP_FREE(tokenTypes);
+            tokenTypes = NULL;
+        }
+    }
+
+    *pTokens = tokens;
+    *pTokenTypes = tokenTypes;
+
+    return major;
+}
+
 OM_uint32
 gssEapSmStep(OM_uint32 *minor,
              gss_cred_id_t cred,
@@ -183,111 +242,79 @@ gssEapSmStep(OM_uint32 *minor,
 
     assert(innerInputTokens != GSS_C_NO_BUFFER_SET);
 
-    major = gss_create_empty_buffer_set(minor, &innerOutputTokens);
+    major = allocInnerTokens(minor, smCount, &innerOutputTokens, &outputTokenTypes);
     if (GSS_ERROR(major))
         goto cleanup;
 
-    assert(innerOutputTokens->count == 0);
-    assert(innerOutputTokens->elements == NULL);
-
-    innerOutputTokens->elements = (gss_buffer_desc *)GSSEAP_CALLOC(smCount,
-                                                                   sizeof(gss_buffer_desc));
-    if (innerOutputTokens->elements == NULL) {
-        major = GSS_S_FAILURE;
-        *minor = ENOMEM;
-        goto cleanup;
-    }
-
-    outputTokenTypes = (OM_uint32 *)GSSEAP_CALLOC(smCount, sizeof(OM_uint32));
-    if (outputTokenTypes == NULL) {
-        major = GSS_S_FAILURE;
-        *minor = ENOMEM;
-        goto cleanup;
-    }
-
-    /*
-     * Process all the tokens that are valid for the current state. If
-     * the processToken function returns GSS_S_COMPLETE, the state is
-     * advanced until there is a token to send or the ESTABLISHED state
-     * is reached.
-     */
-    do {
-        major = GSS_S_COMPLETE;
-
-        for (i = 0; i < smCount; i++) {
-            struct gss_eap_sm *smp = &sm[i];
-            int processToken = 0;
-            gss_buffer_t innerInputToken = GSS_C_NO_BUFFER;
-            OM_uint32 *inputTokenType = NULL;
-            gss_buffer_desc innerOutputToken = GSS_C_EMPTY_BUFFER;
-
-            if ((smp->validStates & ctx->state) == 0)
-                continue;
-
-            if (smp->inputTokenType == ITOK_TYPE_NONE || initialContextToken) {
-                processToken = 1;
-            } else if ((smFlags & SM_FLAG_TRANSITION) == 0) {
-                for (j = 0; j < innerInputTokens->count; j++) {
-                    if ((inputTokenTypes[j] & ITOK_TYPE_MASK) == smp->inputTokenType) {
-                        processToken = 1;
-                        if (innerInputToken != GSS_C_NO_BUFFER) {
-                            major = GSS_S_DEFECTIVE_TOKEN;
-                            *minor = GSSEAP_DUPLICATE_ITOK;
-                            break;
-                        }
+    /* Process all the tokens that are valid for the current state. */
+    for (i = 0; i < smCount; i++) {
+        struct gss_eap_sm *smp = &sm[i];
+        int processToken = 0;
+        gss_buffer_t innerInputToken = GSS_C_NO_BUFFER;
+        OM_uint32 *inputTokenType = NULL;
+        gss_buffer_desc innerOutputToken = GSS_C_EMPTY_BUFFER;
+
+        if ((smp->validStates & ctx->state) == 0)
+            continue;
+
+        if (smp->inputTokenType == ITOK_TYPE_NONE || initialContextToken) {
+            processToken = 1;
+        } else if ((smFlags & SM_FLAG_TRANSITED) == 0) {
+            for (j = 0; j < innerInputTokens->count; j++) {
+                if ((inputTokenTypes[j] & ITOK_TYPE_MASK) == smp->inputTokenType) {
+                    processToken = 1;
+                    if (innerInputToken != GSS_C_NO_BUFFER) {
+                        major = GSS_S_DEFECTIVE_TOKEN;
+                        *minor = GSSEAP_DUPLICATE_ITOK;
+                        break;
                     }
-                    innerInputToken = &innerInputTokens->elements[j];
-                    inputTokenType = &inputTokenTypes[j];
                 }
+                innerInputToken = &innerInputTokens->elements[j];
+                inputTokenType = &inputTokenTypes[j];
             }
+        }
 
-#ifdef GSSEAP_DEBUG
-            fprintf(stderr, "GSS-EAP: state %d processToken %d inputTokenType %08x "
-                    "innerInputToken %p innerOutputTokensCount %zd\n",
-                    ctx->state, processToken, smp->inputTokenType,
-                    innerInputToken, innerOutputTokens->count);
-#endif
+        if (processToken) {
+            enum gss_eap_state oldState = ctx->state;
 
-            if (processToken) {
-                smFlags = 0;
-
-                major = smp->processToken(minor, cred, ctx, target, mech, reqFlags,
-                                         timeReq, chanBindings, innerInputToken,
-                                         &innerOutputToken, &smFlags);
-                if (GSS_ERROR(major))
-                    break;
-
-                if (inputTokenType != NULL)
-                    *inputTokenType |= ITOK_FLAG_VERIFIED;
-
-                if (innerOutputToken.value != NULL) {
-                    innerOutputTokens->elements[innerOutputTokens->count] = innerOutputToken;
-                    assert(smp->outputTokenType != ITOK_TYPE_NONE);
-                    outputTokenTypes[innerOutputTokens->count] = smp->outputTokenType;
-                    if (smp->itokFlags & SM_ITOK_FLAG_CRITICAL)
-                        outputTokenTypes[innerOutputTokens->count] |= ITOK_FLAG_CRITICAL;
-                    innerOutputTokens->count++;
-                }
-                if (smFlags & SM_FLAG_STOP_EVAL)
-                    break;
-            } else if ((smp->itokFlags & SM_ITOK_FLAG_REQUIRED) &&
-                smp->inputTokenType != ITOK_TYPE_NONE) {
-                major = GSS_S_DEFECTIVE_TOKEN;
-                *minor = GSSEAP_MISSING_REQUIRED_ITOK;
+            smFlags = 0;
+
+            major = smp->processToken(minor, cred, ctx, target, mech, reqFlags,
+                                      timeReq, chanBindings, innerInputToken,
+                                      &innerOutputToken, &smFlags);
+            if (GSS_ERROR(major))
                 break;
-            }
-        }
 
-        if (GSS_ERROR(major) || (smFlags & SM_FLAG_TRANSITION) == 0)
+            if (inputTokenType != NULL)
+                *inputTokenType |= ITOK_FLAG_VERIFIED;
+            if (ctx->state != oldState)
+                smFlags |= SM_FLAG_TRANSITED;
+
+            if (innerOutputToken.value != NULL) {
+                innerOutputTokens->elements[innerOutputTokens->count] = innerOutputToken;
+                assert(smp->outputTokenType != ITOK_TYPE_NONE);
+                outputTokenTypes[innerOutputTokens->count] = smp->outputTokenType;
+                if (smp->itokFlags & SM_ITOK_FLAG_CRITICAL)
+                    outputTokenTypes[innerOutputTokens->count] |= ITOK_FLAG_CRITICAL;
+                innerOutputTokens->count++;
+            }
+            /*
+             * Break out if explicitly requested, or if we made a state transition
+             * and have some tokens to send.
+             */
+            if ((smFlags & SM_FLAG_STOP_EVAL) ||
+                ((smFlags & SM_FLAG_TRANSITED) &&
+                 ((smFlags & SM_FLAG_FORCE_SEND_TOKEN) || innerOutputTokens->count != 0))) {
+                SM_ASSERT_VALID(ctx, major);
+                break;
+            }
+        } else if ((smp->itokFlags & SM_ITOK_FLAG_REQUIRED) &&
+            smp->inputTokenType != ITOK_TYPE_NONE) {
+            major = GSS_S_DEFECTIVE_TOKEN;
+            *minor = GSSEAP_MISSING_REQUIRED_ITOK;
             break;
-
-        gssEapSmTransition(ctx, GSSEAP_STATE_NEXT(ctx->state));
-
-        if (innerOutputTokens->count != 0 || (smFlags & SM_FLAG_FORCE_SEND_TOKEN)) {
-            assert(major == GSS_S_CONTINUE_NEEDED || ctx->state == GSSEAP_STATE_ESTABLISHED);
-            break; /* send any tokens if we have them */
         }
-    } while (ctx->state != GSSEAP_STATE_ESTABLISHED);
+    }
 
     assert(innerOutputTokens->count <= smCount);
 
@@ -321,15 +348,6 @@ gssEapSmStep(OM_uint32 *minor,
         outputTokenTypes[0] = ITOK_TYPE_CONTEXT_ERR | ITOK_FLAG_CRITICAL;
     }
 
-#ifdef GSSEAP_DEBUG
-    for (i = 0; i < innerOutputTokens->count; i++) {
-        fprintf(stderr, "GSS-EAP: type %08x length %zd value %p\n",
-                outputTokenTypes[i],
-                innerOutputTokens->elements[i].length,
-                innerOutputTokens->elements[i].value);
-    }
-#endif
-
     /* Format composite output token */
     if (innerOutputTokens->count != 0 ||            /* inner tokens to send */
         !CTX_IS_INITIATOR(ctx) ||                   /* any leg acceptor */
@@ -347,9 +365,7 @@ gssEapSmStep(OM_uint32 *minor,
         }
     }
 
-    assert(GSS_ERROR(major) ||
-           (major == GSS_S_CONTINUE_NEEDED && (ctx->state > GSSEAP_STATE_INITIAL && ctx->state < GSSEAP_STATE_ESTABLISHED)) ||
-           (major == GSS_S_COMPLETE && ctx->state == GSSEAP_STATE_ESTABLISHED));
+    SM_ASSERT_VALID(ctx, major);
 
 cleanup:
     gss_release_buffer_set(&tmpMinor, &innerInputTokens);