initial commit
authorDaniel Kouril <kouril@ics.muni.cz>
Wed, 30 Mar 2011 00:07:49 +0000 (20:07 -0400)
committerDaniel Kouril <kouril@ics.muni.cz>
Wed, 30 Mar 2011 00:09:00 +0000 (20:09 -0400)
Makefile.in [new file with mode: 0644]
install.js [new file with mode: 0644]
install.rdf [new file with mode: 0644]
nsHttpMoonshot.cpp [new file with mode: 0644]
nsHttpMoonshot.h [new file with mode: 0644]
nsHttpMoonshotModule.cpp [new file with mode: 0644]

diff --git a/Makefile.in b/Makefile.in
new file mode 100644 (file)
index 0000000..4d36ebb
--- /dev/null
@@ -0,0 +1,84 @@
+# vim:set ts=8 sw=8 sts=8 noet:
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is negotiateauth.
+#
+# The Initial Developer of the Original Code is
+# Daniel Kouril <kouril@ics.muni.cz>
+#
+# Portions created by the Initial Developer are Copyright (C) 2003
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Daniel Kouril <kouril@ics.muni.cz> (original author)
+#   Wyllys Ingersoll <wyllys.ingersoll@sun.com>
+#   Christopher Nebergall <cneberg@sandia.gov>
+#   Darin Fisher <darin@meer.net>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH          = ../..
+topsrcdir      = @top_srcdir@
+srcdir         = @srcdir@
+VPATH          = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE         = moonshot
+LIBRARY_NAME   = moonshot
+IS_COMPONENT   = 1
+#EXPORT_LIBRARY        = 1
+#MODULE_NAME   = module
+#LIBXUL_LIBRARY = 1
+
+REQUIRES       = \
+               xpcom \
+               string \
+               necko \
+               pref \
+               $(NULL)
+
+CPPSRCS                = \
+               nsHttpMoonshot.cpp \
+               nsHttpMoonshotModule.cpp \
+               $(NULL)
+
+EXTRA_DSO_LDOPTS = \
+               $(MOZ_COMPONENT_LIBS) \
+               -lgssapi_krb5 \
+#              -lxpcomglue_s \
+               $(NULL)
+
+# XXX:
+FORCE_SHARED_LIB = 1
+
+include $(topsrcdir)/config/rules.mk
+
+libs xpi::
+       mkdir -p xpi/components
+       cp lib$(LIBRARY_NAME).so $(XPIDL_GEN_DIR)/$(LIBRARY_NAME).xpt xpi/components
+       cp $(srcdir)/install.js $(srcdir)/install.rdf xpi
+       cd xpi && $(ZIP) -r ../$(LIBRARY_NAME).xpi *
diff --git a/install.js b/install.js
new file mode 100644 (file)
index 0000000..717293c
--- /dev/null
@@ -0,0 +1,23 @@
+// Moonshot
+
+var gVersion = "0.1";
+
+var err = initInstall("Moonshot Authentication Module", "MoonshotModule", gVersion);
+logComment("initInstall: " + err);
+
+var fDir = getComponentsFolder();
+logComment("fComponents: " + fDir);
+
+err = addFile("", gVersion, "components/moonshot.xpt", fDir, "", true);
+logComment("addFile: " + err);
+err = addFile("", gVersion, "components/libmoonshot.so", fDir, "", true);
+logComment("addFile: " + err);
+
+if (getLastError() == SUCCESS) {
+  err = performInstall(); 
+  logComment("performInstall: " + err);
+} else {
+  cancelInstall(err);
+}
+
+
diff --git a/install.rdf b/install.rdf
new file mode 100644 (file)
index 0000000..2f1e7ba
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>moonshot@cesnet.cz</em:id>
+    <em:type>2</em:type>
+    <em:name>Moonshot</em:name>
+    <em:version>0.1</em:version>
+    <em:creator>Michal Prochazka</em:creator>
+    <em:contributor></em:contributor>
+    <em:description>Test</em:description>
+    <em:targetApplication>
+      <Description>
+        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!-- Firefox -->
+        <em:minVersion>1.5</em:minVersion>
+        <em:maxVersion>4.0b3pre</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+  </Description>
+</RDF>
diff --git a/nsHttpMoonshot.cpp b/nsHttpMoonshot.cpp
new file mode 100644 (file)
index 0000000..f67de0c
--- /dev/null
@@ -0,0 +1,639 @@
+/* The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Negotiateauth
+ *
+ * The Initial Developer of the Original Code is Daniel Kouril.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Daniel Kouril <kouril@ics.muni.cz> (original author)
+ *   Wyllys Ingersoll <wyllys.ingersoll@sun.com>
+ *   Christopher Nebergall <cneberg@sandia.gov>
+ */
+
+//
+// GSSAPI Authentication Support Module
+//
+// Described by IETF Internet draft: draft-brezak-kerberos-http-00.txt
+// (formerly draft-brezak-spnego-http-04.txt)
+//
+// Also described here:
+// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsecure/html/http-sso-1.asp
+//
+//
+
+/* this #define must run before prlog.h is included */
+#define FORCE_PR_LOG 1
+
+#include <stdlib.h>
+#include "nsCOMPtr.h"
+#include "nsIHttpChannel.h"
+#include "nsIServiceManager.h"
+#include "nsISupportsPrimitives.h"
+#include "nsIURI.h"
+#include "plbase64.h"
+#include "plstr.h"
+#include "prprf.h"
+#include "prlog.h"
+#include "prmem.h"
+#include "nsISupportsUtils.h"
+
+/* XXX, just for debugging */
+#ifdef MOZILLA_INTERNAL_API
+#include "nsString.h"
+#else
+#include "nsStringAPI.h"
+#endif
+
+/* HACK: */
+#include <ctype.h>
+
+
+#include "nsHttpMoonshot.h"
+
+/* #define HAVE_GSS_C_NT_HOSTBASED_SERVICE 1 */
+#include <gssapi.h>
+#ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE 
+#ifndef HEIMDAL
+ #include <gssapi/gssapi_generic.h> 
+#endif
+#endif
+
+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_spnego_mech_oid_desc = 
+{6, (void *)"\x2b\x06\x01\x05\x05\x02"};
+
+// in order to do logging, the following environment variables need to be set:
+// 
+//      set NSPR_LOG_MODULES=negotiate:4
+//      set NSPR_LOG_FILE=negotiate.log
+
+#if defined(PR_LOGGING)
+
+    PRLogModuleInfo *gHttpLog = nsnull;
+    static PRLogModuleInfo* gNegotiateLog = nsnull;
+
+#endif
+
+ #define LOG4(args) PR_LOG(gNegotiateLog, 4, args)
+ #define LOG(args) LOG4(args)
+
+static void
+parse_oid(char *mechanism, gss_OID * oid)
+{
+    char   *mechstr = 0;
+    gss_buffer_desc tok;
+    OM_uint32 maj_stat, min_stat;
+    size_t i, mechlen = strlen(mechanism);
+
+    if (isdigit((int) mechanism[0])) {
+        mechstr = (char *)malloc(mechlen + 5);
+        if (!mechstr) {
+            fprintf(stderr, "Couldn't allocate mechanism scratch!\n");
+            return;
+        }
+        mechstr[0] = '{';
+        mechstr[1] = ' ';
+        for (i = 0; i < mechlen; i++)
+            mechstr[i + 2] = (mechanism[i] == '.') ? ' ' : mechanism[i];
+        mechstr[mechlen + 2] = ' ';
+        mechstr[mechlen + 3] = ' ';
+        mechstr[mechlen + 4] = '\0';
+        tok.value = mechstr;
+    } else
+        tok.value = mechanism;
+    tok.length = strlen((const char *)tok.value);
+    maj_stat = gss_str_to_oid(&min_stat, &tok, oid);
+    if (maj_stat != GSS_S_COMPLETE) {
+        //display_status("str_to_oid", maj_stat, min_stat);
+        return;
+    }
+    if (mechstr)
+        free(mechstr);
+}
+
+class nsMoonshotSessionState : public nsISupports
+{
+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); }
+
+  // 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);
+}
+
+NS_IMPL_ISUPPORTS0(nsMoonshotSessionState)
+
+#if 1
+nsHttpMoonshot::nsHttpMoonshot()
+{
+   NS_INIT_ISUPPORTS();
+
+#if defined(PR_LOGGING)
+   if (!gNegotiateLog)
+      gNegotiateLog = PR_NewLogModule("moonshot");
+#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,
+                                   PRBool isProxyAuth,
+                                   nsISupports **sessionState,
+                                   nsISupports **continuationState,
+                                   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));
+    }
+
+    return NS_OK;
+}
+
+#if 0
+NS_IMPL_ISUPPORTS2(nsHttpMoonshot, nsIHttpAuthenticator,
+                                    nsIHttpAuthenticator_1_9_2)
+#else
+NS_IMPL_ISUPPORTS1(nsHttpMoonshot, nsIHttpAuthenticator)
+#endif
+
+//
+// Generate proper GSSAPI error messages from the major and
+// minor status codes.
+//
+void
+nsHttpMoonshot::LogGssError(OM_uint32 maj_stat, OM_uint32 min_stat, char *prefix)
+{
+   OM_uint32 new_stat;
+   OM_uint32 msg_ctx = 0;
+   gss_buffer_desc status1_string;
+   gss_buffer_desc status2_string;
+   OM_uint32 ret;
+   nsCAutoString error(prefix);
+
+   error += ": ";
+   do {
+      ret = gss_display_status (&new_stat,
+                               maj_stat,
+                               GSS_C_GSS_CODE,
+                               GSS_C_NULL_OID,
+                               &msg_ctx,
+                               &status1_string);
+      error += (char *)status1_string.value;
+      error += "\n";
+      ret = gss_display_status (&new_stat,
+                               min_stat,
+                               GSS_C_MECH_CODE,
+                               GSS_C_NULL_OID,
+                               &msg_ctx,
+                               &status2_string);
+      error += (char *)status2_string.value;
+      error += "\n";
+
+   } while (!GSS_ERROR(ret) && msg_ctx != 0);
+
+   // LOG(("%s", ToNewCString(error)));
+   LOG(("%s\n", error.get()));
+}
+
+//
+// GenerateCredentials
+//
+// This routine is responsible for creating the correct authentication
+// blob to pass to the server that requested "Negotiate" authentication.
+//
+NS_IMETHODIMP
+nsHttpMoonshot::GenerateCredentials(nsIHttpChannel *httpChannel,
+                                     const char *challenge,
+                                     PRBool isProxyAuth,
+                                     const PRUnichar *domain,
+                                     const PRUnichar *user,
+                                     const PRUnichar *password,
+                                     nsISupports **sessionState,
+                                     nsISupports **continuationState,
+                                     char **creds)
+{
+    LOG(("nsHttpMoonshot::GenerateCredentials [challenge=%s]\n", challenge));
+
+    PRUint32 unused;
+    return GenerateCredentials_1_9_2(httpChannel,
+                                     challenge,
+                                     isProxyAuth,
+                                     domain,
+                                     user,
+                                     password,
+                                     sessionState,
+                                     continuationState,
+                                     &unused,
+                                     creds);
+}
+
+NS_IMETHODIMP
+nsHttpMoonshot::GenerateCredentials_1_9_2(nsIHttpChannel *httpChannel,
+                                               const char *challenge,
+                                               PRBool isProxyAuth,
+                                               const PRUnichar *domain,
+                                               const PRUnichar *username,
+                                               const PRUnichar *password,
+                                               nsISupports **sessionState,
+                                               nsISupports **continuationState,
+                                               PRUint32 *flags,
+                                               char **creds)
+{
+   OM_uint32 major_status, minor_status;
+   gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+   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;
+
+
+   nsCOMPtr<nsIURI> uri;
+   nsresult rv;
+   nsCAutoString service;
+   
+   LOG(("nsHttpMoonshot::GenerateCredentials() [challenge=%s]\n", challenge));
+
+   NS_ENSURE_ARG_POINTER(creds);
+
+   PRBool isGssapiAuth = !PL_strncasecmp(challenge, NEGOTIATE_AUTH,
+               strlen(NEGOTIATE_AUTH));
+   NS_ENSURE_TRUE(isGssapiAuth, NS_ERROR_UNEXPECTED);
+
+   rv = httpChannel->GetURI(getter_AddRefs(uri));
+   if (NS_FAILED(rv)) return rv;
+
+   rv = uri->GetAsciiHost(service);
+   if (NS_FAILED(rv)) return rv;
+   
+   LOG(("nsHttpMoonshot::GenerateCredentials() : hostname = %s\n", 
+       service.get()));
+
+  // TEST
+   LOG(("nsHttpMoonshot::Count [count=%d]\n", session->GetCount()));
+
+   //
+   // The correct service name for IIS servers is "HTTP/f.q.d.n", so
+   // construct the proper service name for passing to "gss_import_name".
+   //
+   // TODO: Possibly make this a configurable service name for use
+   // with non-standard servers that use stuff like "khttp/f.q.d.n" 
+   // instead.
+   //
+/* DK:   service.Insert(NS_LITERAL_CSTRING("HTTP@"), 0); */
+#if 0
+   service.Insert("HTTP@", 0);
+#else
+   service.Insert("host@", 0);
+#endif
+
+   input_token.value = (void *)service.get();
+   input_token.length = service.Length() + 1;
+
+   major_status = gss_import_name(&minor_status,
+                                 &input_token,
+#ifdef HAVE_GSS_C_NT_HOSTBASED_SERVICE
+                                 GSS_C_NT_HOSTBASED_SERVICE,
+#else
+                                gss_nt_service_name,
+#endif
+                                 &server);
+   input_token.value = NULL;
+   input_token.length = 0;
+   if (GSS_ERROR(major_status)) {
+      LogGssError(major_status, minor_status, "gss_import_name() failed");
+      return NS_ERROR_FAILURE;
+   }
+
+   //
+   // If the "Negotiate:" header had some data associated with it,
+   // that data should be used as the input to this call.  This may
+   // be a continuation of an earlier call because GSSAPI authentication
+   // often takes multiple round-trips to complete depending on the
+   // context flags given.  We want to use MUTUAL_AUTHENTICATION which
+   // generally *does* require multiple round-trips.  Don't assume
+   // auth can be completed in just 1 call.
+   //
+   unsigned int len = strlen(challenge);
+
+   if (len > strlen(NEGOTIATE_AUTH)) {
+       challenge += strlen(NEGOTIATE_AUTH);
+       while (*challenge == ' ') challenge++;
+       len = strlen(challenge);
+
+
+       if(len && (0 == (len & 3)) )
+       {
+         if( (char)'=' == challenge[len-1] )
+         {
+             if( (char)'=' == challenge[len-2] )
+             {
+                 len -= 2;
+             }
+             else
+             {
+                 len -= 1;
+             }
+         }
+     }
+
+
+       input_token.length = (len / 4) * 3 + ((len % 4) * 3) / 4;
+//        input_token.length = (len * 3)/4;
+       input_token.value = malloc(input_token.length + 1);
+       if (!input_token.value)
+               return (NS_ERROR_OUT_OF_MEMORY);
+
+       //
+       // Decode the response that followed the "Negotiate" token
+       //
+       if (PL_Base64Decode(challenge, len, (char *) input_token.value) == NULL) {
+               free(input_token.value);
+               return(NS_ERROR_UNEXPECTED);
+       }
+       in_token_ptr = &input_token;
+       LOG(("nsHttpMoonshot::GenerateCredentials() : Received GSS token of length %d\n", input_token.length));
+   } else {
+       //
+       // Starting over, clear out any existing context and don't
+       // use an input token.
+       //
+       // TEST
+/*     if (session->context_state == 2) {
+         *creds = (char *) malloc (strlen(NEGOTIATE_AUTH) + 1);
+         if (!(*creds)) {
+             return NS_ERROR_OUT_OF_MEMORY;
+         }
+
+         sprintf(*creds, "%s", NEGOTIATE_AUTH);
+         return NS_OK;
+       } else { */
+         session->Reset();
+         in_token_ptr = GSS_C_NO_BUFFER;
+        //}
+   }
+
+   /* HACK */
+   {
+       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;
+
+       tmp_token.value = (void *) "steve@local";
+       tmp_token.length = strlen((const char *)tmp_token.value);
+       maj_stat = gss_import_name(&min_stat, &tmp_token,
+                                  GSS_C_NT_USER_NAME,
+                                  &gss_username);
+
+       if (GSS_ERROR(maj_stat)) {
+           LogGssError(maj_stat, min_stat, "gss_import_name() failed");
+            session->Reset();
+            return NS_ERROR_FAILURE;
+       }
+
+       mechs.elements = session->GetOID();
+       mechs.count = 1;
+       mechsp = &mechs;
+
+       tmp_token.value = (void *)"testing";
+       tmp_token.length = 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);
+       if (GSS_ERROR(maj_stat)) {
+           LogGssError(maj_stat, min_stat, "gss_acquire_cred_with_password()");
+           session->Reset();
+           return NS_ERROR_FAILURE;
+       }
+   }
+
+   major_status = gss_init_sec_context(&minor_status,
+                                   cred,
+                                   &session->mCtx,
+                                   server,
+                                   session->GetOID(),
+                                   GSS_C_MUTUAL_FLAG,
+                                   /* GSS_C_INDEFINITE */ 0,
+                                   GSS_C_NO_CHANNEL_BINDINGS,
+                                   in_token_ptr,
+                                   nsnull,
+                                   &output_token,
+                                   nsnull,
+                                   nsnull);
+
+   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);
+      session->Reset();
+      if (input_token.length > 0 && input_token.value != NULL)
+             (void) gss_release_buffer(&minor_status, &input_token);
+      return NS_ERROR_FAILURE;
+   }
+
+   if (major_status == GSS_S_COMPLETE) {
+       //
+       // We are done with this authentication, reset the context. 
+       //
+       // TEST
+       // session->Reset();
+       session->context_state = 2;
+       LOG(("GSS Auth done"));
+   } else if (major_status == GSS_S_CONTINUE_NEEDED) {
+       //
+       // We could create a continuation state, but its not
+       // really necessary.
+       //
+       // The important thing is that we do NOT reset the
+       // session context here because it will be needed on the
+       // next call.
+       //
+       // TEST
+       session->context_state = 1;
+       LOG(("GSS Auth continuing"));
+   } 
+
+   // We don't need the input token data anymore.
+   if (input_token.length > 0 && input_token.value != NULL)
+       (void) gss_release_buffer(&minor_status, &input_token);
+
+   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);
+      return NS_ERROR_FAILURE;
+   }
+
+   //
+   // The token output from the gss_init_sec_context call is
+   // encoded and used as the Authentication response for the
+   // server.
+   //
+   char *encoded_token = PL_Base64Encode((char *)output_token.value,
+                                        output_token.length,
+                                        nsnull);
+   if (!encoded_token) {
+      (void) gss_release_buffer(&minor_status, &output_token);
+      (void) gss_release_name(&minor_status, &server);
+      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);
+   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);
+      return NS_ERROR_OUT_OF_MEMORY;
+   }
+
+   sprintf(*creds, "%s %s", NEGOTIATE_AUTH, encoded_token);
+   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);
+
+   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
diff --git a/nsHttpMoonshot.h b/nsHttpMoonshot.h
new file mode 100644 (file)
index 0000000..7e7affe
--- /dev/null
@@ -0,0 +1,77 @@
+/* The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Negotiateauth
+ *
+ * The Initial Developer of the Original Code is Daniel Kouril.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Daniel Kouril <kouril@ics.muni.cz> (original author)
+ *   Wyllys Ingersoll <wyllys.ingersoll@sun.com>
+ *   Christopher Nebergall <cneberg@sandia.gov>
+ */
+
+#ifndef nsMoonshot_h__
+#define nsMoonshot_h__
+
+#include "nsIHttpAuthenticator.h"
+
+#include <gssapi.h>
+#include <gssapi/gssapi_ext.h>
+
+#define NS_HTTPMOONSHOT_CID \
+{ /* 75c80fd0-accb-432c-af59-ec60668c3991 */         \
+    0x75c80fd0,                                      \
+    0xaccb,                                          \
+    0x432c,                                          \
+    {0xaf, 0x59, 0xec, 0x60, 0x66, 0x8c, 0x39, 0x91} \
+}
+
+#define NS_HTTP_AUTHENTICATOR_CONTRACTID       \
+       "@mozilla.org/network/http-authenticator;1?scheme=gssapi"
+
+#define NEGOTIATE_AUTH "GSSAPI"
+
+class nsHttpMoonshot : public nsIHttpAuthenticator
+#if 0
+,
+                        public nsIHttpAuthenticator_1_9_2
+#endif
+{
+   public:
+      NS_DECL_ISUPPORTS
+      NS_DECL_NSIHTTPAUTHENTICATOR
+#if 0
+      NS_DECL_NSIHTTPAUTHENTICATOR_1_9_2
+#endif
+
+
+      nsHttpMoonshot();
+      virtual ~nsHttpMoonshot();
+
+
+      NS_IMETHODIMP
+      GenerateCredentials_1_9_2(nsIHttpChannel *httpChannel,
+                                               const char *challenge,
+                                               PRBool isProxyAuth,
+                                               const PRUnichar *domain,
+                                               const PRUnichar *username,
+                                               const PRUnichar *password,
+                                               nsISupports **sessionState,
+                                               nsISupports **continuationState,
+                                               PRUint32 *flags,
+                                               char **creds);
+
+   private:
+      void LogGssError(OM_uint32 maj, OM_uint32 min, char *prefix);
+};
+#endif /* nsMoonshot_h__ */
diff --git a/nsHttpMoonshotModule.cpp b/nsHttpMoonshotModule.cpp
new file mode 100644 (file)
index 0000000..a657723
--- /dev/null
@@ -0,0 +1,40 @@
+/* The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Negotiateauth
+ *
+ * The Initial Developer of the Original Code is Daniel Kouril.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Daniel Kouril <kouril@ics.muni.cz> (original author)
+ *   Wyllys Ingersoll <wyllys.ingersoll@sun.com>
+ *   Christopher Nebergall <cneberg@sandia.gov>
+ */
+
+#include "nsISupportsUtils.h"
+#include "nsIGenericFactory.h"
+
+#include "nsHttpMoonshot.h"
+
+// macro expansion defines our factory constructor method
+// used by the components[] array below.
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsHttpMoonshot)
+
+static nsModuleComponentInfo components[] = {
+  { "HTTP Moonshot Auth Encoder", 
+    NS_HTTPMOONSHOT_CID,
+    NS_HTTP_AUTHENTICATOR_CONTRACTID,
+    nsHttpMoonshotConstructor,
+  },
+};
+
+NS_IMPL_NSGETMODULE(nsHttpMoonshotModule, components)