Add MSVC project and solution files
[moonshot-firefox.git] / nsHttpMoonshot.cpp
index f67de0c..a09a0ce 100644 (file)
@@ -35,6 +35,7 @@
 #define FORCE_PR_LOG 1
 
 #include <stdlib.h>
+#include "nsAutoRef.h"
 #include "nsCOMPtr.h"
 #include "nsIHttpChannel.h"
 #include "nsIServiceManager.h"
@@ -58,6 +59,7 @@
 #include <ctype.h>
 
 
+#include "nsMoonshotSessionState.h"
 #include "nsHttpMoonshot.h"
 
 /* #define HAVE_GSS_C_NT_HOSTBASED_SERVICE 1 */
 #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"};
 
@@ -123,90 +133,15 @@ parse_oid(char *mechanism, gss_OID * oid)
         free(mechstr);
 }
 
-class nsMoonshotSessionState : public nsISupports
+gss_OID
+GetOID()
 {
-public:
-    NS_DECL_ISUPPORTS
-
-    nsMoonshotSessionState();
-
-    virtual ~nsMoonshotSessionState() {
-       OM_uint32 minor_status;
-       if (mCtx != GSS_C_NO_CONTEXT)
-               (void)gss_delete_sec_context(&minor_status, &mCtx, GSS_C_NO_BUFFER);
-       mCtx = GSS_C_NO_CONTEXT;
-       mech_oid = GSS_C_NO_OID;
-    }
-
-    NS_IMETHOD Reset() {
-       OM_uint32 minor_status;
-       if (mCtx != GSS_C_NO_CONTEXT)
-               (void)gss_delete_sec_context(&minor_status, &mCtx, GSS_C_NO_BUFFER);
-       mCtx = GSS_C_NO_CONTEXT;
-       context_state = 0;
-       return NS_OK;
-     }
-     gss_OID GetOID() { return (mech_oid); }
+    gss_OID mech_oid;
 
-  // TEST
-     int GetCount() { return ++count; }
-
-     gss_ctx_id_t mCtx;
-     int context_state;
-private:
-     gss_OID mech_oid;
-     int count;
-};
-
-nsMoonshotSessionState::nsMoonshotSessionState()
-{
-       OM_uint32 minstat, majstat;
-       //gss_buffer_desc buffer;
-       gss_OID_set mech_set;
-       //int mech_found = 0;
-       unsigned int i;
-       gss_OID item;
-       
-
-       mCtx = GSS_C_NO_CONTEXT;
-       mech_oid = &gss_krb5_mech_oid_desc;
-       context_state = 0;
-
-        //
-        // Now, look at the list of supported mechanisms,
-        // if SPNEGO is found, then use it.
-        // Otherwise, set the desired mechanism to krb5
-        //
-        // Using Kerberos directly (instead of negotiating
-        // with SPNEGO) may work in some cases depending
-        // on how smart the server side is.
-        //
-
-       // TEST
-       count = 0;
-       LOG(("nsMoonshotSessionState::nsMoonshotSessionState [count=%d]\n", count));
-
-       majstat = gss_indicate_mechs(&minstat, &mech_set);
-       if (GSS_ERROR(majstat))
-          return;
-
-       for (i=0; i<mech_set->count; i++) {
-          item = &mech_set->elements[i];
-          if (item->length == gss_spnego_mech_oid_desc.length &&
-               !memcmp(item->elements, gss_spnego_mech_oid_desc.elements,
-                       item->length)) {
-             mech_oid = &gss_spnego_mech_oid_desc;
-             break;
-          }
-       }
-       (void) gss_release_oid_set(&minstat, &mech_set);
-/* HACK: */
-       parse_oid("{1 3 6 1 4 1 5322 22 1 18}", &mech_oid);
+    parse_oid("{1 3 6 1 4 1 5322 22 1 18}", &mech_oid);
+    return mech_oid;
 }
 
-NS_IMPL_ISUPPORTS0(nsMoonshotSessionState)
-
-#if 1
 nsHttpMoonshot::nsHttpMoonshot()
 {
    NS_INIT_ISUPPORTS();
@@ -217,34 +152,18 @@ nsHttpMoonshot::nsHttpMoonshot()
 #endif /* PR_LOGGING */
 
 }
-#endif
 
-#if 1
 nsHttpMoonshot::~nsHttpMoonshot()
 {
 }
-#endif
 
 NS_IMETHODIMP
 nsHttpMoonshot::GetAuthFlags(PRUint32 *flags)
 {
-  //
-  // GSSAPI creds should not be reused across multiple requests.
-  // Only perform the negotiation when it is explicitly requested
-  // by the server.  Thus, do *NOT* use the "REUSABLE_CREDENTIALS"
-  // flag here.
-  //
   *flags = REQUEST_BASED; 
   return NS_OK;
 }
 
-//
-// Always set *identityInvalid == FALSE here.  This 
-// will prevent the browser from popping up the authentication
-// prompt window.  Because GSSAPI does not have an API
-// for fetching initial credentials (ex: A Kerberos TGT),
-// there is no correct way to get the users credentials.
-// 
 NS_IMETHODIMP
 nsHttpMoonshot::ChallengeReceived(nsIHttpChannel *httpChannel,
                                    const char *challenge,
@@ -254,21 +173,10 @@ nsHttpMoonshot::ChallengeReceived(nsIHttpChannel *httpChannel,
                                    PRBool *identityInvalid)
 {
     nsMoonshotSessionState *session = (nsMoonshotSessionState *) *sessionState;
-
-    *identityInvalid = PR_FALSE;
-    //
-    // 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 [ctx=%p]\n", session->mCtx));
-    }
+    if (session==NULL)
+        session = (nsMoonshotSessionState *) *continuationState;
+    *identityInvalid =
+       ((session==NULL) || (session->gss_state == GSS_CTX_EMPTY)) ? PR_TRUE : PR_FALSE;
 
     return NS_OK;
 }
@@ -368,9 +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;
-   nsMoonshotSessionState *session = (nsMoonshotSessionState *) *sessionState;
-   gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
-
+   nsCountedRef<nsMoonshotSessionState> session(static_cast<nsMoonshotSessionState *>(*sessionState));
+   if (!session)
+       session = static_cast<nsMoonshotSessionState *>(*continuationState);
 
    nsCOMPtr<nsIURI> uri;
    nsresult rv;
@@ -394,7 +302,7 @@ nsHttpMoonshot::GenerateCredentials_1_9_2(nsIHttpChannel *httpChannel,
        service.get()));
 
   // TEST
-   LOG(("nsHttpMoonshot::Count [count=%d]\n", session->GetCount()));
+//   LOG(("nsHttpMoonshot::Count [count=%d]\n", session->GetCount()));
 
    //
    // The correct service name for IIS servers is "HTTP/f.q.d.n", so
@@ -429,6 +337,16 @@ nsHttpMoonshot::GenerateCredentials_1_9_2(nsIHttpChannel *httpChannel,
       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
@@ -497,14 +415,21 @@ nsHttpMoonshot::GenerateCredentials_1_9_2(nsIHttpChannel *httpChannel,
         //}
    }
 
-   /* HACK */
+   if (session->gss_cred == GSS_C_NO_CREDENTIAL)
    {
        OM_uint32 maj_stat, min_stat;
        gss_buffer_desc tmp_token;
        gss_name_t gss_username = GSS_C_NO_NAME;
        gss_OID_set_desc mechs, *mechsp = GSS_C_NO_OID_SET;
+       const char *p, *u;
+
+       u = strdup(NS_LossyConvertUTF16toASCII(username).get());
+       p = strdup(NS_LossyConvertUTF16toASCII(password).get());
+
+       LOG(("Acquiring credentials for user '%s' using password '%s'\n",
+                                u, p));
 
-       tmp_token.value = (void *) "steve@local";
+       tmp_token.value = (void *) u;
        tmp_token.length = strlen((const char *)tmp_token.value);
        maj_stat = gss_import_name(&min_stat, &tmp_token,
                                   GSS_C_NT_USER_NAME,
@@ -516,28 +441,31 @@ nsHttpMoonshot::GenerateCredentials_1_9_2(nsIHttpChannel *httpChannel,
             return NS_ERROR_FAILURE;
        }
 
-       mechs.elements = session->GetOID();
+       mechs.elements = GetOID();
        mechs.count = 1;
        mechsp = &mechs;
 
-       tmp_token.value = (void *)"testing";
-       tmp_token.length = strlen((const char*)tmp_token.value);
+       tmp_token.value = (void *) p;
+       tmp_token.length = strlen(p);//strlen((const char*)tmp_token.value);
        maj_stat = gss_acquire_cred_with_password(&min_stat,
                                                  gss_username, &tmp_token, 0,
                                                  mechsp, GSS_C_INITIATE,
-                                                 &cred, NULL, NULL);
+                                                 &session->gss_cred, NULL, NULL);
        if (GSS_ERROR(maj_stat)) {
            LogGssError(maj_stat, min_stat, "gss_acquire_cred_with_password()");
            session->Reset();
            return NS_ERROR_FAILURE;
        }
+
+       LOG(("Acquired credential for user '%s' using password '%s'\n",
+            u, p));
    }
 
    major_status = gss_init_sec_context(&minor_status,
-                                   cred,
-                                   &session->mCtx,
+                                   session->gss_cred,
+                                   &session->gss_ctx,
                                    server,
-                                   session->GetOID(),
+                                   GetOID(),
                                    GSS_C_MUTUAL_FLAG,
                                    /* GSS_C_INDEFINITE */ 0,
                                    GSS_C_NO_CHANNEL_BINDINGS,
@@ -550,7 +478,7 @@ nsHttpMoonshot::GenerateCredentials_1_9_2(nsIHttpChannel *httpChannel,
    if (GSS_ERROR(major_status)) {
       LogGssError(major_status, minor_status, "gss_init_sec_context() failed");
       (void) gss_release_name(&minor_status, &server);
-      gss_release_cred(&minor_status, &cred);
+//      gss_release_cred(&minor_status, &cred);
       session->Reset();
       if (input_token.length > 0 && input_token.value != NULL)
              (void) gss_release_buffer(&minor_status, &input_token);
@@ -563,7 +491,14 @@ nsHttpMoonshot::GenerateCredentials_1_9_2(nsIHttpChannel *httpChannel,
        //
        // TEST
        // session->Reset();
-       session->context_state = 2;
+       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) {
        //
@@ -575,7 +510,12 @@ nsHttpMoonshot::GenerateCredentials_1_9_2(nsIHttpChannel *httpChannel,
        // next call.
        //
        // TEST
-       session->context_state = 1;
+       session->gss_state = GSS_CTX_IN_PROGRESS;
+      if (*continuationState != session)
+      {
+          // Assert continuationState==NULL
+          NS_ADDREF(*continuationState = session);
+      }
        LOG(("GSS Auth continuing"));
    } 
 
@@ -586,7 +526,7 @@ nsHttpMoonshot::GenerateCredentials_1_9_2(nsIHttpChannel *httpChannel,
    if (output_token.length == 0) {
       LOG(("No GSS output token to send, exiting"));
       (void) gss_release_name(&minor_status, &server);
-      gss_release_cred(&minor_status, &cred);
+//      gss_release_cred(&minor_status, &cred);
       return NS_ERROR_FAILURE;
    }
 
@@ -601,19 +541,19 @@ nsHttpMoonshot::GenerateCredentials_1_9_2(nsIHttpChannel *httpChannel,
    if (!encoded_token) {
       (void) gss_release_buffer(&minor_status, &output_token);
       (void) gss_release_name(&minor_status, &server);
-      gss_release_cred(&minor_status, &cred);
+//      gss_release_cred(&minor_status, &cred);
       return NS_ERROR_OUT_OF_MEMORY;
    }
 
    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);
       (void) gss_release_name(&minor_status, &server);
-      gss_release_cred(&minor_status, &cred);
+//      gss_release_cred(&minor_status, &cred);
       return NS_ERROR_OUT_OF_MEMORY;
    }
 
@@ -622,18 +562,9 @@ nsHttpMoonshot::GenerateCredentials_1_9_2(nsIHttpChannel *httpChannel,
 
    (void) gss_release_buffer(&minor_status, &output_token);
    (void) gss_release_name(&minor_status, &server);
-      gss_release_cred(&minor_status, &cred);
+//      gss_release_cred(&minor_status, &cred);
 
    LOG(("returning the call"));
 
    return NS_OK;
 }
-
-#if 0
-static NS_METHOD
-nsMoonshotConstructor(nsISupports *outer, REFNSIID iid, void **result)
-{
-    if (outer)
-       return NS_ERROR_NO_AGGREGATION;
-}
-#endif