Windows port and Firefox 3.6 addon fixes:
authorKevin Wasserman <kevin.wasserman@painless-security.com>
Mon, 1 Aug 2011 18:16:09 +0000 (14:16 -0400)
committerSam Hartman <hartmans@debian.org>
Tue, 2 Aug 2011 14:07:14 +0000 (10:07 -0400)
malloc -> PR_Malloc
In 3.6, session state is deleted by firefox when ChallengeReceived()
sets identityInvalid true, so allocate session state as necessary in
GenerateCredentials() instead of ChallengeReceived().
Also, use continuation state instead of session state until
authentication completes.  If we don't do this, firefox
will sometimes restart the authentication in the middle of the
negotiation with a NULL username and password.
Use a smart pointer for session state to avoid leaking in error cases.

nsHttpMoonshot.cpp

index 0f709ab..a09a0ce 100644 (file)
@@ -35,6 +35,7 @@
 #define FORCE_PR_LOG 1
 
 #include <stdlib.h>
 #define FORCE_PR_LOG 1
 
 #include <stdlib.h>
+#include "nsAutoRef.h"
 #include "nsCOMPtr.h"
 #include "nsIHttpChannel.h"
 #include "nsIServiceManager.h"
 #include "nsCOMPtr.h"
 #include "nsIHttpChannel.h"
 #include "nsIServiceManager.h"
 #endif
 #endif
 
 #endif
 #endif
 
+NS_SPECIALIZE_TEMPLATE
+class nsAutoRefTraits<nsMoonshotSessionState> : public nsPointerRefTraits<nsMoonshotSessionState>
+{
+public:
+   static void Release(nsMoonshotSessionState *ptr) { ptr->Release(); }
+   static void AddRef(nsMoonshotSessionState *ptr) { ptr->AddRef(); }
+};
+
 static gss_OID_desc gss_krb5_mech_oid_desc =
 {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
 
 static gss_OID_desc gss_krb5_mech_oid_desc =
 {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
 
@@ -164,25 +173,10 @@ nsHttpMoonshot::ChallengeReceived(nsIHttpChannel *httpChannel,
                                    PRBool *identityInvalid)
 {
     nsMoonshotSessionState *session = (nsMoonshotSessionState *) *sessionState;
                                    PRBool *identityInvalid)
 {
     nsMoonshotSessionState *session = (nsMoonshotSessionState *) *sessionState;
-
-    //
-    // Use this opportunity to instantiate the session object
-    // that gets used later when we generate the credentials.
-    //
-    if (!session) {
-       session = new nsMoonshotSessionState();
-       if (!session)
-               return(NS_ERROR_OUT_OF_MEMORY);
-       NS_ADDREF(*sessionState = session);
-       LOG(("nsHttpMoonshot::A new session context established\n"));
-    } else {
-       LOG(("nsHttpMoonshot::Still using context from previous request\n"));
-    }
-
-    LOG(("nsHttpMoonshot:: gss_state = %d\n", session->gss_state));
-
+    if (session==NULL)
+        session = (nsMoonshotSessionState *) *continuationState;
     *identityInvalid =
     *identityInvalid =
-       (session->gss_state == GSS_CTX_EMPTY) ? PR_TRUE : PR_FALSE;
+       ((session==NULL) || (session->gss_state == GSS_CTX_EMPTY)) ? PR_TRUE : PR_FALSE;
 
     return NS_OK;
 }
 
     return NS_OK;
 }
@@ -282,8 +276,9 @@ nsHttpMoonshot::GenerateCredentials_1_9_2(nsIHttpChannel *httpChannel,
    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
    gss_buffer_t  in_token_ptr = GSS_C_NO_BUFFER;
    gss_name_t server;
    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
    gss_buffer_t  in_token_ptr = GSS_C_NO_BUFFER;
    gss_name_t server;
-   nsMoonshotSessionState *session = (nsMoonshotSessionState *) *sessionState;
-
+   nsCountedRef<nsMoonshotSessionState> session(static_cast<nsMoonshotSessionState *>(*sessionState));
+   if (!session)
+       session = static_cast<nsMoonshotSessionState *>(*continuationState);
 
    nsCOMPtr<nsIURI> uri;
    nsresult rv;
 
    nsCOMPtr<nsIURI> uri;
    nsresult rv;
@@ -342,6 +337,16 @@ nsHttpMoonshot::GenerateCredentials_1_9_2(nsIHttpChannel *httpChannel,
       return NS_ERROR_FAILURE;
    }
 
       return NS_ERROR_FAILURE;
    }
 
+   // Create session state if none added yet.
+   if (!session) {
+      session = new nsMoonshotSessionState();
+      if (!session)
+         return(NS_ERROR_OUT_OF_MEMORY);
+      LOG(("nsHttpMoonshot::A new session context established\n"));
+   } else {
+      LOG(("nsHttpMoonshot::Still using context from previous request\n"));
+   }
+
    //
    // If the "Negotiate:" header had some data associated with it,
    // that data should be used as the input to this call.  This may
    //
    // If the "Negotiate:" header had some data associated with it,
    // that data should be used as the input to this call.  This may
@@ -487,6 +492,13 @@ nsHttpMoonshot::GenerateCredentials_1_9_2(nsIHttpChannel *httpChannel,
        // TEST
        // session->Reset();
        session->gss_state = GSS_CTX_ESTABLISHED;
        // TEST
        // session->Reset();
        session->gss_state = GSS_CTX_ESTABLISHED;
+      if (*sessionState != session)
+      {
+         NS_ADDREF(*sessionState = session);
+         // clean up continuation state
+         if (*continuationState)
+            NS_RELEASE(*continuationState);
+      }
        LOG(("GSS Auth done"));
    } else if (major_status == GSS_S_CONTINUE_NEEDED) {
        //
        LOG(("GSS Auth done"));
    } else if (major_status == GSS_S_CONTINUE_NEEDED) {
        //
@@ -499,6 +511,11 @@ nsHttpMoonshot::GenerateCredentials_1_9_2(nsIHttpChannel *httpChannel,
        //
        // TEST
        session->gss_state = GSS_CTX_IN_PROGRESS;
        //
        // TEST
        session->gss_state = GSS_CTX_IN_PROGRESS;
+      if (*continuationState != session)
+      {
+          // Assert continuationState==NULL
+          NS_ADDREF(*continuationState = session);
+      }
        LOG(("GSS Auth continuing"));
    } 
 
        LOG(("GSS Auth continuing"));
    } 
 
@@ -531,7 +548,7 @@ nsHttpMoonshot::GenerateCredentials_1_9_2(nsIHttpChannel *httpChannel,
    LOG(("Sending a token of length %d\n", output_token.length));
 
    // allocate a buffer sizeof("Negotiate" + " " + b64output_token + "\0")
    LOG(("Sending a token of length %d\n", output_token.length));
 
    // allocate a buffer sizeof("Negotiate" + " " + b64output_token + "\0")
-   *creds = (char *) malloc (strlen(NEGOTIATE_AUTH) + 1 + strlen(encoded_token) + 1);
+   *creds = (char *) PR_Malloc (strlen(NEGOTIATE_AUTH) + 1 + strlen(encoded_token) + 1);
    if (!(*creds)) {
       PR_Free(encoded_token);
       (void) gss_release_buffer(&minor_status, &output_token);
    if (!(*creds)) {
       PR_Free(encoded_token);
       (void) gss_release_buffer(&minor_status, &output_token);