From 867f2c201ad9fe77210bc90b3d338f18a65e585e Mon Sep 17 00:00:00 2001 From: "bienvenu%nventure.com" Date: Thu, 18 Aug 2005 15:22:33 +0000 Subject: [PATCH] implement sasl auth and ability to use gssapi on windows, patches by cneberg@gmail.com, simon@sxw.org.uk, r=darin, sr=bienvenu 280792, 303160, NPOB git-svn-id: svn://10.0.0.236/trunk@178163 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/extensions/auth/Makefile.in | 19 +- mozilla/extensions/auth/nsAuth.h | 15 +- mozilla/extensions/auth/nsAuthFactory.cpp | 132 ++++- mozilla/extensions/auth/nsAuthGSSAPI.cpp | 272 ++++++---- mozilla/extensions/auth/nsAuthGSSAPI.h | 29 +- .../extensions/auth/nsAuthModuleGSSAPI.cpp | 484 ------------------ mozilla/extensions/auth/nsAuthModuleGSSAPI.h | 83 --- mozilla/extensions/auth/nsAuthSSPI.cpp | 219 +++++++- mozilla/extensions/auth/nsAuthSSPI.h | 15 +- .../extensions/auth/nsHttpNegotiateAuth.cpp | 21 +- mozilla/extensions/auth/nsHttpNegotiateAuth.h | 2 +- 11 files changed, 533 insertions(+), 758 deletions(-) delete mode 100644 mozilla/extensions/auth/nsAuthModuleGSSAPI.cpp delete mode 100644 mozilla/extensions/auth/nsAuthModuleGSSAPI.h diff --git a/mozilla/extensions/auth/Makefile.in b/mozilla/extensions/auth/Makefile.in index 30dc3de6b4f..f0aff403fde 100644 --- a/mozilla/extensions/auth/Makefile.in +++ b/mozilla/extensions/auth/Makefile.in @@ -49,11 +49,11 @@ include $(DEPTH)/config/autoconf.mk MOZILLA_INTERNAL_API = 1 -MODULE = negotiateauth -LIBRARY_NAME = negotiateauth +MODULE = auth +LIBRARY_NAME = auth IS_COMPONENT = 1 EXPORT_LIBRARY = 1 -MODULE_NAME = nsNegotiateAuthModule +MODULE_NAME = nsAuthModule REQUIRES = \ xpcom \ @@ -63,7 +63,7 @@ REQUIRES = \ $(NULL) CPPSRCS = \ - nsNegotiateAuthFactory.cpp \ + nsAuthFactory.cpp \ nsHttpNegotiateAuth.cpp \ $(NULL) @@ -71,14 +71,13 @@ EXTRA_DSO_LDOPTS = \ $(MOZ_COMPONENT_LIBS) \ $(NULL) -ifeq (1,$(USE_GSSAPI)) -LOCAL_INCLUDES = -DUSE_GSSAPI $(GSSAPI_INCLUDES) -CPPSRCS += nsNegotiateAuthGSSAPI.cpp -endif +CPPSRCS += \ + nsAuthGSSAPI.cpp \ + nsAuthSASL.cpp ifeq ($(OS_ARCH),WINNT) -LOCAL_INCLUDES = -DUSE_SSPI -CPPSRCS += nsNegotiateAuthSSPI.cpp +LOCAL_INCLUDES += -DUSE_SSPI +CPPSRCS += nsAuthSSPI.cpp endif include $(topsrcdir)/config/rules.mk diff --git a/mozilla/extensions/auth/nsAuth.h b/mozilla/extensions/auth/nsAuth.h index eeb8fa45a26..0d4d01f807c 100644 --- a/mozilla/extensions/auth/nsAuth.h +++ b/mozilla/extensions/auth/nsAuth.h @@ -34,10 +34,17 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef nsNegotiateAuth_h__ -#define nsNegotiateAuth_h__ +#ifndef nsAuth_h__ +#define nsAuth_h__ -#if defined( MOZ_LOGGING) +/* types of packages */ +enum pType { + PACKAGE_TYPE_KERBEROS, + PACKAGE_TYPE_NEGOTIATE, + PACKAGE_TYPE_NTLM +}; + +#if defined(MOZ_LOGGING) #define FORCE_PR_LOG #endif @@ -57,4 +64,4 @@ extern PRLogModuleInfo* gNegotiateLog; #define LOG(args) #endif -#endif /* !defined( nsNegotiateAuth_h__ ) */ +#endif /* !defined( nsAuth_h__ ) */ diff --git a/mozilla/extensions/auth/nsAuthFactory.cpp b/mozilla/extensions/auth/nsAuthFactory.cpp index fc285adbdd5..2908b1224b9 100644 --- a/mozilla/extensions/auth/nsAuthFactory.cpp +++ b/mozilla/extensions/auth/nsAuthFactory.cpp @@ -35,7 +35,7 @@ * ***** END LICENSE BLOCK ***** */ #include "nsIGenericFactory.h" -#include "nsNegotiateAuth.h" +#include "nsAuth.h" //----------------------------------------------------------------------------- @@ -49,7 +49,6 @@ #include "nsHttpNegotiateAuth.h" NS_GENERIC_FACTORY_CONSTRUCTOR(nsHttpNegotiateAuth) - //----------------------------------------------------------------------------- #define NS_NEGOTIATEAUTH_CID \ @@ -59,12 +58,18 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsHttpNegotiateAuth) 0x407a, \ {0x87, 0x35, 0x00, 0x7f, 0xb2, 0x6b, 0xe4, 0xe8} \ } +#define NS_GSSAUTH_CID \ +{ /* dc8e21a0-03e4-11da-8cd6-0800200c9a66 */ \ + 0xdc8e21a0, \ + 0x03e4, \ + 0x11da, \ + {0x8c, 0xd6, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66} \ +} -#if defined( USE_GSSAPI ) -#include "nsNegotiateAuthGSSAPI.h" +#include "nsAuthGSSAPI.h" -#elif defined( USE_SSPI ) -#include "nsNegotiateAuthSSPI.h" +#if defined( USE_SSPI ) +#include "nsAuthSSPI.h" static NS_METHOD nsSysNTLMAuthConstructor(nsISupports *outer, REFNSIID iid, void **result) @@ -72,7 +77,23 @@ nsSysNTLMAuthConstructor(nsISupports *outer, REFNSIID iid, void **result) if (outer) return NS_ERROR_NO_AGGREGATION; - nsNegotiateAuth *auth = new nsNegotiateAuth(PR_TRUE); + nsAuthSSPI *auth = new nsAuthSSPI(PACKAGE_TYPE_NTLM); + if (!auth) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(auth); + nsresult rv = auth->QueryInterface(iid, result); + NS_RELEASE(auth); + return rv; +} + +static NS_METHOD +nsKerbSSPIAuthConstructor(nsISupports *outer, REFNSIID iid, void **result) +{ + if (outer) + return NS_ERROR_NO_AGGREGATION; + + nsAuthSSPI *auth = new nsAuthSSPI(PACKAGE_TYPE_KERBEROS); if (!auth) return NS_ERROR_OUT_OF_MEMORY; @@ -90,23 +111,97 @@ nsSysNTLMAuthConstructor(nsISupports *outer, REFNSIID iid, void **result) {0xb1, 0xfd, 0xab, 0x89, 0x5d, 0x39, 0x88, 0x33} \ } -#else -#error "missing implementation" +#define NS_NEGOTIATEAUTHSSPI_CID \ +{ /* 78d3b0c0-0241-11da-8cd6-0800200c9a66 */ \ + 0x78d3b0c0, \ + 0x0241, \ + 0x11da, \ + {0x8c, 0xd6, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66} \ +} + +#define NS_KERBAUTHSSPI_CID \ +{ /* 8c3a0e20-03e5-11da-8cd6-0800200c9a66 */ \ + 0x8c3a0e20, \ + 0x03e5, \ + 0x11da, \ + {0x8c, 0xd6, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66} \ +} + #endif -NS_GENERIC_FACTORY_CONSTRUCTOR(nsNegotiateAuth) +static NS_METHOD +nsKerbGSSAPIAuthConstructor(nsISupports *outer, REFNSIID iid, void **result) +{ + if (outer) + return NS_ERROR_NO_AGGREGATION; + nsAuthGSSAPI *auth = new nsAuthGSSAPI(PACKAGE_TYPE_KERBEROS); + if (!auth) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(auth); + nsresult rv = auth->QueryInterface(iid, result); + NS_RELEASE(auth); + return rv; +} + +static NS_METHOD +nsGSSAPIAuthConstructor(nsISupports *outer, REFNSIID iid, void **result) +{ + if (outer) + return NS_ERROR_NO_AGGREGATION; + + nsAuthGSSAPI *auth = new nsAuthGSSAPI(PACKAGE_TYPE_NEGOTIATE); + if (!auth) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(auth); + nsresult rv = auth->QueryInterface(iid, result); + NS_RELEASE(auth); + return rv; +} + + +#if defined( USE_SSPI ) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsAuthSSPI) +#endif + +#define NS_AUTHSASL_CID \ +{ /* 815e42e0-72cc-480f-934b-148e33c228a6 */ \ + 0x815e42e0, \ + 0x72cc, \ + 0x480f, \ + {0x93, 0x4b, 0x14, 0x8e, 0x33, 0xc2, 0x28, 0xa6} \ +} + +#include "nsAuthSASL.h" +NS_GENERIC_FACTORY_CONSTRUCTOR(nsAuthSASL) //----------------------------------------------------------------------------- static nsModuleComponentInfo components[] = { - { "nsNegotiateAuth", + { "nsAuthKerbGSS", + NS_GSSAUTH_CID, + NS_AUTH_MODULE_CONTRACTID_PREFIX "kerb-gss", + nsKerbGSSAPIAuthConstructor + }, + { "nsAuthNegoGSSAPI", NS_NEGOTIATEAUTH_CID, - NS_AUTH_MODULE_CONTRACTID_PREFIX "negotiate", - nsNegotiateAuthConstructor + NS_AUTH_MODULE_CONTRACTID_PREFIX "negotiate-gss", + nsGSSAPIAuthConstructor }, #if defined( USE_SSPI ) - { "nsNegotiateAuthNTLM", + { "nsAuthNegoSSPI", + NS_NEGOTIATEAUTHSSPI_CID, + NS_AUTH_MODULE_CONTRACTID_PREFIX "negotiate-sspi", + nsAuthSSPIConstructor + }, + { "nsAuthKerbSSPI", + NS_KERBAUTHSSPI_CID, + NS_AUTH_MODULE_CONTRACTID_PREFIX "kerb-sspi", + nsKerbSSPIAuthConstructor + }, + { "nsAuthSYSNTLM", NS_SYSNTLMAUTH_CID, NS_AUTH_MODULE_CONTRACTID_PREFIX "sys-ntlm", nsSysNTLMAuthConstructor @@ -116,6 +211,11 @@ static nsModuleComponentInfo components[] = { NS_HTTPNEGOTIATEAUTH_CID, NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX "negotiate", nsHttpNegotiateAuthConstructor + }, + { "nsAuthSASL", + NS_AUTHSASL_CID, + NS_AUTH_MODULE_CONTRACTID_PREFIX "sasl-gssapi", + nsAuthSASLConstructor } }; @@ -131,8 +231,6 @@ InitNegotiateAuth(nsIModule *self) gNegotiateLog = PR_NewLogModule("negotiateauth"); return NS_OK; } -#else -#define InitNegotiateAuth nsnull #endif -NS_IMPL_NSGETMODULE_WITH_CTOR(nsNegotiateAuthModule, components, InitNegotiateAuth) +NS_IMPL_NSGETMODULE_WITH_CTOR(nsAuthGSSAPIModule, components, InitNegotiateAuth) diff --git a/mozilla/extensions/auth/nsAuthGSSAPI.cpp b/mozilla/extensions/auth/nsAuthGSSAPI.cpp index d6dec9c4370..d131f6d243a 100644 --- a/mozilla/extensions/auth/nsAuthGSSAPI.cpp +++ b/mozilla/extensions/auth/nsAuthGSSAPI.cpp @@ -55,66 +55,14 @@ #include "nsIPrefService.h" #include "nsIPrefBranch.h" #include "nsIServiceManager.h" +#include "nsNativeCharsetUtils.h" -#include "nsNegotiateAuth.h" -#include "nsNegotiateAuthGSSAPI.h" +#include "nsAuthGSSAPI.h" #ifdef XP_MACOSX #include #endif -// function pointers for gss functions -// -typedef OM_uint32 (*gss_display_status_type)( - OM_uint32 *, - OM_uint32, - int, - gss_OID, - OM_uint32 *, - gss_buffer_t); - -typedef OM_uint32 (*gss_init_sec_context_type)( - OM_uint32 *, - gss_cred_id_t, - gss_ctx_id_t *, - gss_name_t, - gss_OID, - OM_uint32, - OM_uint32, - gss_channel_bindings_t, - gss_buffer_t, - gss_OID *, - gss_buffer_t, - OM_uint32 *, - OM_uint32 *); - -typedef OM_uint32 (*gss_indicate_mechs_type)( - OM_uint32 *, - gss_OID_set *); - -typedef OM_uint32 (*gss_release_oid_set_type)( - OM_uint32 *, - gss_OID_set *); - -typedef OM_uint32 (*gss_delete_sec_context_type)( - OM_uint32 *, - gss_ctx_id_t *, - gss_buffer_t); - -typedef OM_uint32 (*gss_import_name_type)( - OM_uint32 *, - gss_buffer_t, - gss_OID, - gss_name_t *); - -typedef OM_uint32 (*gss_release_buffer_type)( - OM_uint32 *, - gss_buffer_t); - -typedef OM_uint32 (*gss_release_name_type)( - OM_uint32 *, - gss_name_t *); - #ifdef XP_MACOSX typedef KLStatus (*KLCacheHasValidTickets_type)( KLPrincipal, @@ -146,7 +94,9 @@ static const char *gssFuncStr[] = { "gss_delete_sec_context", "gss_import_name", "gss_release_buffer", - "gss_release_name" + "gss_release_name", + "gss_wrap", + "gss_unwrap" }; #define gssFuncItems NS_ARRAY_LENGTH(gssFuncStr) @@ -163,6 +113,8 @@ static PRBool gssFunInit = PR_FALSE; #define gss_import_name_ptr ((gss_import_name_type)*gssFunPtr[5]) #define gss_release_buffer_ptr ((gss_release_buffer_type)*gssFunPtr[6]) #define gss_release_name_ptr ((gss_release_name_type)*gssFunPtr[7]) +#define gss_wrap_ptr ((gss_wrap_type)*gssFunPtr[8]) +#define gss_unwrap_ptr ((gss_unwrap_type)*gssFunPtr[9]) #ifdef XP_MACOSX static PRFuncPtr KLCacheHasValidTicketsPtr; @@ -189,9 +141,13 @@ gssInit() } else { const char *const libNames[] = { +#ifdef XP_WIN + "gssapi32" +#else "gss", "gssapi_krb5", "gssapi" +#endif }; for (size_t i = 0; i < NS_ARRAY_LENGTH(libNames) && !lib; ++i) { @@ -244,12 +200,13 @@ LogGssError(OM_uint32 maj_stat, OM_uint32 min_stat, const char *prefix) gss_buffer_desc status1_string; gss_buffer_desc status2_string; OM_uint32 ret; - nsCAutoString error(prefix); + nsCAutoString errorStr; + errorStr.Assign(prefix); if (!gssFunInit) return; - error += ": "; + errorStr += ": "; do { ret = gss_display_status_ptr(&new_stat, maj_stat, @@ -257,19 +214,21 @@ LogGssError(OM_uint32 maj_stat, OM_uint32 min_stat, const char *prefix) GSS_C_NULL_OID, &msg_ctx, &status1_string); - error += (const char *) status1_string.value; - error += '\n'; + errorStr.Append((const char *) status1_string.value, status1_string.length); + gss_release_buffer_ptr(&new_stat, &status1_string); + + errorStr += '\n'; ret = gss_display_status_ptr(&new_stat, min_stat, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &status2_string); - error += (const char *) status2_string.value; - error += '\n'; + errorStr.Append((const char *) status2_string.value, status2_string.length); + errorStr += '\n'; } while (!GSS_ERROR(ret) && msg_ctx != 0); - LOG(("%s\n", error.get())); + LOG(("%s\n", errorStr.get())); } #else /* PR_LOGGING */ @@ -280,19 +239,23 @@ LogGssError(OM_uint32 maj_stat, OM_uint32 min_stat, const char *prefix) //----------------------------------------------------------------------------- -nsNegotiateAuth::nsNegotiateAuth() +nsAuthGSSAPI::nsAuthGSSAPI(pType package) : mServiceFlags(REQ_DEFAULT) { - OM_uint32 minstat, majstat; + OM_uint32 minstat; + OM_uint32 majstat; gss_OID_set mech_set; gss_OID item; + unsigned int i; 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" }; - LOG(("entering nsNegotiateAuth::nsNegotiateAuth()\n")); + LOG(("entering nsAuthGSSAPI::nsAuthGSSAPI()\n")); + + mComplete = PR_FALSE; if (!gssFunInit && NS_FAILED(gssInit())) return; @@ -300,7 +263,12 @@ nsNegotiateAuth::nsNegotiateAuth() mCtx = GSS_C_NO_CONTEXT; mMechOID = &gss_krb5_mech_oid_desc; - // + // if the type is kerberos we accept it as default + // and exit + + if (package == PACKAGE_TYPE_KERBEROS) + return; + // Now, look at the list of supported mechanisms, // if SPNEGO is found, then use it. // Otherwise, set the desired mechanism to @@ -310,42 +278,45 @@ nsNegotiateAuth::nsNegotiateAuth() // Using Kerberos directly (instead of negotiating // with SPNEGO) may work in some cases depending // on how smart the server side is. - // + majstat = gss_indicate_mechs_ptr(&minstat, &mech_set); if (GSS_ERROR(majstat)) return; - for (i=0; icount; 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)) { - // ok, we found it - mMechOID = &gss_spnego_mech_oid_desc; - break; + if (mech_set) { + for (i=0; icount; 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)) { + // ok, we found it + mMechOID = &gss_spnego_mech_oid_desc; + break; + } } + gss_release_oid_set_ptr(&minstat, &mech_set); } - gss_release_oid_set_ptr(&minstat, &mech_set); } void -nsNegotiateAuth::Reset() +nsAuthGSSAPI::Reset() { if (gssFunInit && mCtx != GSS_C_NO_CONTEXT) { OM_uint32 minor_status; gss_delete_sec_context_ptr(&minor_status, &mCtx, GSS_C_NO_BUFFER); } mCtx = GSS_C_NO_CONTEXT; + mComplete = PR_FALSE; } -NS_IMPL_ISUPPORTS1(nsNegotiateAuth, nsIAuthModule) +NS_IMPL_ISUPPORTS1(nsAuthGSSAPI, nsIAuthModule) NS_IMETHODIMP -nsNegotiateAuth::Init(const char *serviceName, - PRUint32 serviceFlags, - const PRUnichar *domain, - const PRUnichar *username, - const PRUnichar *password) +nsAuthGSSAPI::Init(const char *serviceName, + PRUint32 serviceFlags, + const PRUnichar *domain, + const PRUnichar *username, + const PRUnichar *password) { // we don't expect to be passed any user credentials NS_ASSERTION(!domain && !username && !password, "unexpected credentials"); @@ -353,7 +324,7 @@ nsNegotiateAuth::Init(const char *serviceName, // it's critial that the caller supply a service name to be used NS_ENSURE_TRUE(serviceName && *serviceName, NS_ERROR_INVALID_ARG); - LOG(("entering nsNegotiateAuth::Init()\n")); + LOG(("entering nsAuthGSSAPI::Init()\n")); if (!gssFunInit) return NS_ERROR_NOT_INITIALIZED; @@ -364,10 +335,10 @@ nsNegotiateAuth::Init(const char *serviceName, } NS_IMETHODIMP -nsNegotiateAuth::GetNextToken(const void *inToken, - PRUint32 inTokenLen, - void **outToken, - PRUint32 *outTokenLen) +nsAuthGSSAPI::GetNextToken(const void *inToken, + PRUint32 inTokenLen, + void **outToken, + PRUint32 *outTokenLen) { OM_uint32 major_status, minor_status; OM_uint32 req_flags = 0; @@ -375,15 +346,24 @@ nsNegotiateAuth::GetNextToken(const void *inToken, gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; gss_buffer_t in_token_ptr = GSS_C_NO_BUFFER; gss_name_t server; + nsCAutoString userbuf; + nsresult rv; - LOG(("entering nsNegotiateAuth::GetNextToken()\n")); + LOG(("entering nsAuthGSSAPI::GetNextToken()\n")); if (!gssFunInit) return NS_ERROR_NOT_INITIALIZED; + // If they've called us again after we're complete, reset to start afresh. + if (mComplete) + Reset(); + if (mServiceFlags & REQ_DELEGATE) req_flags |= GSS_C_DELEG_FLAG; + if (mServiceFlags & REQ_MUTUAL_AUTH) + req_flags |= GSS_C_MUTUAL_FLAG; + input_token.value = (void *)mServiceName.get(); input_token.length = mServiceName.Length() + 1; @@ -420,8 +400,8 @@ nsNegotiateAuth::GetNextToken(const void *inToken, KLBoolean found; if (gssNativeImp && - (KLCacheHasValidTickets_ptr(NULL, kerberosVersion_V5, &found, NULL, - NULL) + (KLCacheHasValidTickets_ptr(NULL, kerberosVersion_V5, &found, NULL, + NULL) != klNoErr || !found)) { major_status = GSS_S_FAILURE; @@ -443,7 +423,6 @@ nsNegotiateAuth::GetNextToken(const void *inToken, nsnull, nsnull); - nsresult rv; if (GSS_ERROR(major_status)) { LogGssError(major_status, minor_status, "gss_init_sec_context() failed"); Reset(); @@ -451,10 +430,9 @@ nsNegotiateAuth::GetNextToken(const void *inToken, goto end; } if (major_status == GSS_S_COMPLETE) { - // - // We are done with this authentication, reset the context. - // - Reset(); + // Mark ourselves as being complete, so that if we're called again + // we know to start afresh. + mComplete = PR_TRUE; } else if (major_status == GSS_S_CONTINUE_NEEDED) { // @@ -463,22 +441,102 @@ nsNegotiateAuth::GetNextToken(const void *inToken, // next call. // } - - if (output_token.length == 0) { - LOG((" No GSS output token to send, exiting")); - rv = NS_ERROR_FAILURE; - goto end; - } - + *outTokenLen = output_token.length; - *outToken = nsMemory::Clone(output_token.value, output_token.length); - + if (output_token.length != 0) + *outToken = nsMemory::Clone(output_token.value, output_token.length); + else + *outToken = NULL; + gss_release_buffer_ptr(&minor_status, &output_token); - rv = NS_OK; + + if (major_status == GSS_S_COMPLETE) + rv = NS_SUCCESS_AUTH_FINISHED; + else + rv = NS_OK; end: gss_release_name_ptr(&minor_status, &server); - LOG((" leaving nsNegotiateAuth::GetNextToken [rv=%x]", rv)); + LOG((" leaving nsAuthGSSAPI::GetNextToken [rv=%x]", rv)); return rv; } + +NS_IMETHODIMP +nsAuthGSSAPI::Unwrap(const void *inToken, + PRUint32 inTokenLen, + void **outToken, + PRUint32 *outTokenLen) +{ + OM_uint32 major_status, minor_status; + + gss_buffer_desc input_token; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + + input_token.value = (void *) inToken; + input_token.length = inTokenLen; + + major_status = gss_unwrap_ptr(&minor_status, + mCtx, + &input_token, + &output_token, + NULL, + NULL); + if (GSS_ERROR(major_status)) { + LogGssError(major_status, minor_status, "gss_unwrap() failed"); + Reset(); + gss_release_buffer_ptr(&minor_status, &output_token); + return NS_ERROR_FAILURE; + } + + *outTokenLen = output_token.length; + + if (output_token.length) + *outToken = nsMemory::Clone(output_token.value, output_token.length); + else + *outToken = NULL; + + gss_release_buffer_ptr(&minor_status, &output_token); + + return NS_OK; +} + +NS_IMETHODIMP +nsAuthGSSAPI::Wrap(const void *inToken, + PRUint32 inTokenLen, + PRBool confidential, + void **outToken, + PRUint32 *outTokenLen) +{ + OM_uint32 major_status, minor_status; + + gss_buffer_desc input_token; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + + input_token.value = (void *) inToken; + input_token.length = inTokenLen; + + major_status = gss_wrap_ptr(&minor_status, + mCtx, + confidential, + GSS_C_QOP_DEFAULT, + &input_token, + NULL, + &output_token); + + if (GSS_ERROR(major_status)) { + LogGssError(major_status, minor_status, "gss_wrap() failed"); + Reset(); + gss_release_buffer_ptr(&minor_status, &output_token); + return NS_ERROR_FAILURE; + } + + *outTokenLen = output_token.length; + + /* it is not possible for output_token.length to be zero */ + *outToken = nsMemory::Clone(output_token.value, output_token.length); + gss_release_buffer_ptr(&minor_status, &output_token); + + return NS_OK; +} + diff --git a/mozilla/extensions/auth/nsAuthGSSAPI.h b/mozilla/extensions/auth/nsAuthGSSAPI.h index 8ec9a3df1a5..c6a0925126b 100644 --- a/mozilla/extensions/auth/nsAuthGSSAPI.h +++ b/mozilla/extensions/auth/nsAuthGSSAPI.h @@ -38,37 +38,30 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef nsGssapiAuth_h__ -#define nsGssapiAuth_h__ +#ifndef nsAuthGSSAPI_h__ +#define nsAuthGSSAPI_h__ +#include "nsAuth.h" #include "nsIAuthModule.h" #include "nsString.h" -#if defined(HAVE_GSSAPI_H) -#include -#elif defined(HAVE_GSSAPI_GSSAPI_H) -#include -#endif +#define GSS_USE_FUNCTION_POINTERS 1 -#if defined(HAVE_GSSAPI_GENERIC_H) -#include -#elif defined(HAVE_GSSAPI_GSSAPI_GENERIC_H) -#include -#endif +#include "gssapi.h" -// The nsNegotiateAuth class provides responses for the GSS-API Negotiate method +// The nsAuthGSSAPI class provides responses for the GSS-API Negotiate method // as specified by Microsoft in draft-brezak-spnego-http-04.txt -class nsNegotiateAuth : public nsIAuthModule +class nsAuthGSSAPI : public nsIAuthModule { public: NS_DECL_ISUPPORTS NS_DECL_NSIAUTHMODULE - nsNegotiateAuth(); + nsAuthGSSAPI(pType package); private: - ~nsNegotiateAuth() { Reset(); } + ~nsAuthGSSAPI() { Reset(); } void Reset(); gss_OID GetOID() { return mMechOID; } @@ -78,6 +71,8 @@ private: gss_OID mMechOID; nsCString mServiceName; PRUint32 mServiceFlags; + nsString mUsername; + PRBool mComplete; }; -#endif /* nsGssapiAuth_h__ */ +#endif /* nsAuthGSSAPI_h__ */ diff --git a/mozilla/extensions/auth/nsAuthModuleGSSAPI.cpp b/mozilla/extensions/auth/nsAuthModuleGSSAPI.cpp deleted file mode 100644 index d6dec9c4370..00000000000 --- a/mozilla/extensions/auth/nsAuthModuleGSSAPI.cpp +++ /dev/null @@ -1,484 +0,0 @@ -/* vim:set ts=4 sw=4 sts=4 et cindent: */ -/* ***** 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 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 (original author) - * Wyllys Ingersoll - * Christopher Nebergall - * Darin Fisher - * Mark Mentovai - * - * 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 ***** */ - -// -// 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 -// -// - -#include "prlink.h" -#include "nsCOMPtr.h" -#include "nsIPrefService.h" -#include "nsIPrefBranch.h" -#include "nsIServiceManager.h" - -#include "nsNegotiateAuth.h" -#include "nsNegotiateAuthGSSAPI.h" - -#ifdef XP_MACOSX -#include -#endif - -// function pointers for gss functions -// -typedef OM_uint32 (*gss_display_status_type)( - OM_uint32 *, - OM_uint32, - int, - gss_OID, - OM_uint32 *, - gss_buffer_t); - -typedef OM_uint32 (*gss_init_sec_context_type)( - OM_uint32 *, - gss_cred_id_t, - gss_ctx_id_t *, - gss_name_t, - gss_OID, - OM_uint32, - OM_uint32, - gss_channel_bindings_t, - gss_buffer_t, - gss_OID *, - gss_buffer_t, - OM_uint32 *, - OM_uint32 *); - -typedef OM_uint32 (*gss_indicate_mechs_type)( - OM_uint32 *, - gss_OID_set *); - -typedef OM_uint32 (*gss_release_oid_set_type)( - OM_uint32 *, - gss_OID_set *); - -typedef OM_uint32 (*gss_delete_sec_context_type)( - OM_uint32 *, - gss_ctx_id_t *, - gss_buffer_t); - -typedef OM_uint32 (*gss_import_name_type)( - OM_uint32 *, - gss_buffer_t, - gss_OID, - gss_name_t *); - -typedef OM_uint32 (*gss_release_buffer_type)( - OM_uint32 *, - gss_buffer_t); - -typedef OM_uint32 (*gss_release_name_type)( - OM_uint32 *, - gss_name_t *); - -#ifdef XP_MACOSX -typedef KLStatus (*KLCacheHasValidTickets_type)( - KLPrincipal, - KLKerberosVersion, - KLBoolean *, - KLPrincipal *, - char **); -#endif - -//----------------------------------------------------------------------------- - -// We define GSS_C_NT_HOSTBASED_SERVICE explicitly since it may be referenced -// by by a different name depending on the implementation of gss but always -// has the same value - -static gss_OID_desc gss_c_nt_hostbased_service = - { 10, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04" }; - -static const char kNegotiateAuthGssLib[] = - "network.negotiate-auth.gsslib"; -static const char kNegotiateAuthNativeImp[] = - "network.negotiate-auth.using-native-gsslib"; - -static const char *gssFuncStr[] = { - "gss_display_status", - "gss_init_sec_context", - "gss_indicate_mechs", - "gss_release_oid_set", - "gss_delete_sec_context", - "gss_import_name", - "gss_release_buffer", - "gss_release_name" -}; - -#define gssFuncItems NS_ARRAY_LENGTH(gssFuncStr) - -static PRFuncPtr gssFunPtr[gssFuncItems]; -static PRBool gssNativeImp = PR_TRUE; -static PRBool gssFunInit = PR_FALSE; - -#define gss_display_status_ptr ((gss_display_status_type)*gssFunPtr[0]) -#define gss_init_sec_context_ptr ((gss_init_sec_context_type)*gssFunPtr[1]) -#define gss_indicate_mechs_ptr ((gss_indicate_mechs_type)*gssFunPtr[2]) -#define gss_release_oid_set_ptr ((gss_release_oid_set_type)*gssFunPtr[3]) -#define gss_delete_sec_context_ptr ((gss_delete_sec_context_type)*gssFunPtr[4]) -#define gss_import_name_ptr ((gss_import_name_type)*gssFunPtr[5]) -#define gss_release_buffer_ptr ((gss_release_buffer_type)*gssFunPtr[6]) -#define gss_release_name_ptr ((gss_release_name_type)*gssFunPtr[7]) - -#ifdef XP_MACOSX -static PRFuncPtr KLCacheHasValidTicketsPtr; -#define KLCacheHasValidTickets_ptr \ - ((KLCacheHasValidTickets_type)*KLCacheHasValidTicketsPtr) -#endif - -static nsresult -gssInit() -{ - nsXPIDLCString libPath; - nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); - if (prefs) { - prefs->GetCharPref(kNegotiateAuthGssLib, getter_Copies(libPath)); - prefs->GetBoolPref(kNegotiateAuthNativeImp, &gssNativeImp); - } - - PRLibrary *lib = NULL; - - if (!libPath.IsEmpty()) { - LOG(("Attempting to load user specified library [%s]\n", libPath.get())); - gssNativeImp = PR_FALSE; - lib = PR_LoadLibrary(libPath.get()); - } - else { - const char *const libNames[] = { - "gss", - "gssapi_krb5", - "gssapi" - }; - - for (size_t i = 0; i < NS_ARRAY_LENGTH(libNames) && !lib; ++i) { - char *libName = PR_GetLibraryName(NULL, libNames[i]); - if (libName) { - lib = PR_LoadLibrary(libName); - PR_FreeLibraryName(libName); - } - } - } - - if (!lib) { - LOG(("Fail to load gssapi library\n")); - return NS_ERROR_FAILURE; - } - - LOG(("Attempting to load gss functions\n")); - - for (size_t i = 0; i < gssFuncItems; ++i) { - gssFunPtr[i] = PR_FindFunctionSymbol(lib, gssFuncStr[i]); - if (!gssFunPtr[i]) { - LOG(("Fail to load %s function from gssapi library\n", gssFuncStr[i])); - PR_UnloadLibrary(lib); - return NS_ERROR_FAILURE; - } - } -#ifdef XP_MACOSX - if (gssNativeImp && - !(KLCacheHasValidTicketsPtr = - PR_FindFunctionSymbol(lib, "KLCacheHasValidTickets"))) { - LOG(("Fail to load KLCacheHasValidTickets function from gssapi library\n")); - PR_UnloadLibrary(lib); - return NS_ERROR_FAILURE; - } -#endif - - gssFunInit = PR_TRUE; - return NS_OK; -} - -#if defined( PR_LOGGING ) - -// Generate proper GSSAPI error messages from the major and -// minor status codes. -void -LogGssError(OM_uint32 maj_stat, OM_uint32 min_stat, const 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); - - if (!gssFunInit) - return; - - error += ": "; - do { - ret = gss_display_status_ptr(&new_stat, - maj_stat, - GSS_C_GSS_CODE, - GSS_C_NULL_OID, - &msg_ctx, - &status1_string); - error += (const char *) status1_string.value; - error += '\n'; - ret = gss_display_status_ptr(&new_stat, - min_stat, - GSS_C_MECH_CODE, - GSS_C_NULL_OID, - &msg_ctx, - &status2_string); - error += (const char *) status2_string.value; - error += '\n'; - } while (!GSS_ERROR(ret) && msg_ctx != 0); - - LOG(("%s\n", error.get())); -} - -#else /* PR_LOGGING */ - -#define LogGssError(x,y,z) - -#endif /* PR_LOGGING */ - -//----------------------------------------------------------------------------- - -nsNegotiateAuth::nsNegotiateAuth() - : mServiceFlags(REQ_DEFAULT) -{ - OM_uint32 minstat, majstat; - gss_OID_set mech_set; - gss_OID item; - unsigned int i; - 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" }; - - LOG(("entering nsNegotiateAuth::nsNegotiateAuth()\n")); - - if (!gssFunInit && NS_FAILED(gssInit())) - return; - - mCtx = GSS_C_NO_CONTEXT; - mMechOID = &gss_krb5_mech_oid_desc; - - // - // Now, look at the list of supported mechanisms, - // if SPNEGO is found, then use it. - // Otherwise, set the desired mechanism to - // GSS_C_NO_OID and let the system try to use - // the default mechanism. - // - // Using Kerberos directly (instead of negotiating - // with SPNEGO) may work in some cases depending - // on how smart the server side is. - // - majstat = gss_indicate_mechs_ptr(&minstat, &mech_set); - if (GSS_ERROR(majstat)) - return; - - for (i=0; icount; 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)) { - // ok, we found it - mMechOID = &gss_spnego_mech_oid_desc; - break; - } - } - gss_release_oid_set_ptr(&minstat, &mech_set); -} - -void -nsNegotiateAuth::Reset() -{ - if (gssFunInit && mCtx != GSS_C_NO_CONTEXT) { - OM_uint32 minor_status; - gss_delete_sec_context_ptr(&minor_status, &mCtx, GSS_C_NO_BUFFER); - } - mCtx = GSS_C_NO_CONTEXT; -} - -NS_IMPL_ISUPPORTS1(nsNegotiateAuth, nsIAuthModule) - -NS_IMETHODIMP -nsNegotiateAuth::Init(const char *serviceName, - PRUint32 serviceFlags, - const PRUnichar *domain, - const PRUnichar *username, - const PRUnichar *password) -{ - // we don't expect to be passed any user credentials - NS_ASSERTION(!domain && !username && !password, "unexpected credentials"); - - // it's critial that the caller supply a service name to be used - NS_ENSURE_TRUE(serviceName && *serviceName, NS_ERROR_INVALID_ARG); - - LOG(("entering nsNegotiateAuth::Init()\n")); - - if (!gssFunInit) - return NS_ERROR_NOT_INITIALIZED; - - mServiceName = serviceName; - mServiceFlags = serviceFlags; - return NS_OK; -} - -NS_IMETHODIMP -nsNegotiateAuth::GetNextToken(const void *inToken, - PRUint32 inTokenLen, - void **outToken, - PRUint32 *outTokenLen) -{ - OM_uint32 major_status, minor_status; - OM_uint32 req_flags = 0; - 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; - - LOG(("entering nsNegotiateAuth::GetNextToken()\n")); - - if (!gssFunInit) - return NS_ERROR_NOT_INITIALIZED; - - if (mServiceFlags & REQ_DELEGATE) - req_flags |= GSS_C_DELEG_FLAG; - - input_token.value = (void *)mServiceName.get(); - input_token.length = mServiceName.Length() + 1; - - major_status = gss_import_name_ptr(&minor_status, - &input_token, - &gss_c_nt_hostbased_service, - &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 (inToken) { - input_token.length = inTokenLen; - input_token.value = (void *) inToken; - in_token_ptr = &input_token; - } - else if (mCtx != GSS_C_NO_CONTEXT) { - // If there is no input token, then we are starting a new - // authentication sequence. If we have already initialized our - // security context, then we're in trouble because it means that the - // first sequence failed. We need to bail or else we might end up in - // an infinite loop. - LOG(("Cannot restart authentication sequence!")); - return NS_ERROR_UNEXPECTED; - } - -#if defined(XP_MACOSX) - // Suppress Kerberos prompts to get credentials. See bug 240643. - // We can only use Mac OS X specific kerb functions if we are using - // the native lib - - KLBoolean found; - if (gssNativeImp && - (KLCacheHasValidTickets_ptr(NULL, kerberosVersion_V5, &found, NULL, - NULL) - != klNoErr || !found)) - { - major_status = GSS_S_FAILURE; - minor_status = 0; - } - else -#endif /* XP_MACOSX */ - major_status = gss_init_sec_context_ptr(&minor_status, - GSS_C_NO_CREDENTIAL, - &mCtx, - server, - mMechOID, - req_flags, - GSS_C_INDEFINITE, - GSS_C_NO_CHANNEL_BINDINGS, - in_token_ptr, - nsnull, - &output_token, - nsnull, - nsnull); - - nsresult rv; - if (GSS_ERROR(major_status)) { - LogGssError(major_status, minor_status, "gss_init_sec_context() failed"); - Reset(); - rv = NS_ERROR_FAILURE; - goto end; - } - if (major_status == GSS_S_COMPLETE) { - // - // We are done with this authentication, reset the context. - // - Reset(); - } - else if (major_status == GSS_S_CONTINUE_NEEDED) { - // - // The important thing is that we do NOT reset the - // context here because it will be needed on the - // next call. - // - } - - if (output_token.length == 0) { - LOG((" No GSS output token to send, exiting")); - rv = NS_ERROR_FAILURE; - goto end; - } - - *outTokenLen = output_token.length; - *outToken = nsMemory::Clone(output_token.value, output_token.length); - - gss_release_buffer_ptr(&minor_status, &output_token); - rv = NS_OK; - -end: - gss_release_name_ptr(&minor_status, &server); - - LOG((" leaving nsNegotiateAuth::GetNextToken [rv=%x]", rv)); - return rv; -} diff --git a/mozilla/extensions/auth/nsAuthModuleGSSAPI.h b/mozilla/extensions/auth/nsAuthModuleGSSAPI.h deleted file mode 100644 index 8ec9a3df1a5..00000000000 --- a/mozilla/extensions/auth/nsAuthModuleGSSAPI.h +++ /dev/null @@ -1,83 +0,0 @@ -/* vim:set ts=4 sw=4 et cindent: */ -/* ***** 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 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 (original author) - * Wyllys Ingersoll - * Christopher Nebergall - * Darin Fisher - * - * 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 ***** */ - -#ifndef nsGssapiAuth_h__ -#define nsGssapiAuth_h__ - -#include "nsIAuthModule.h" -#include "nsString.h" - -#if defined(HAVE_GSSAPI_H) -#include -#elif defined(HAVE_GSSAPI_GSSAPI_H) -#include -#endif - -#if defined(HAVE_GSSAPI_GENERIC_H) -#include -#elif defined(HAVE_GSSAPI_GSSAPI_GENERIC_H) -#include -#endif - -// The nsNegotiateAuth class provides responses for the GSS-API Negotiate method -// as specified by Microsoft in draft-brezak-spnego-http-04.txt - -class nsNegotiateAuth : public nsIAuthModule -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIAUTHMODULE - - nsNegotiateAuth(); - -private: - ~nsNegotiateAuth() { Reset(); } - - void Reset(); - gss_OID GetOID() { return mMechOID; } - -private: - gss_ctx_id_t mCtx; - gss_OID mMechOID; - nsCString mServiceName; - PRUint32 mServiceFlags; -}; - -#endif /* nsGssapiAuth_h__ */ diff --git a/mozilla/extensions/auth/nsAuthSSPI.cpp b/mozilla/extensions/auth/nsAuthSSPI.cpp index 458fd321522..d3b180c4ca2 100644 --- a/mozilla/extensions/auth/nsAuthSSPI.cpp +++ b/mozilla/extensions/auth/nsAuthSSPI.cpp @@ -45,16 +45,35 @@ // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsecure/html/http-sso-1.asp // -#include "nsNegotiateAuth.h" -#include "nsNegotiateAuthSSPI.h" +#include "nsAuthSSPI.h" #include "nsIServiceManager.h" #include "nsIDNSService.h" #include "nsIDNSRecord.h" #include "nsNetCID.h" #include "nsCOMPtr.h" +#define SEC_SUCCESS(Status) ((Status) >= 0) + +#ifndef KERB_WRAP_NO_ENCRYPT +#define KERB_WRAP_NO_ENCRYPT 0x80000001 +#endif + +#ifndef SECBUFFER_PADDING +#define SECBUFFER_PADDING 9 +#endif + +#ifndef SECBUFFER_STREAM +#define SECBUFFER_STREAM 10 +#endif + //----------------------------------------------------------------------------- +static const char *const pTypeName [] = { + "Kerberos", + "Negotiate", + "NTLM" +}; + #ifdef DEBUG #define CASE_(_x) case _x: return # _x; static const char *MapErrorCode(int rc) @@ -91,6 +110,8 @@ InitSSPI() { PSecurityFunctionTable (*initFun)(void); + LOG((" InitSSPI\n")); + sspi_lib = LoadLibrary("secur32.dll"); if (!sspi_lib) { sspi_lib = LoadLibrary("security.dll"); @@ -162,16 +183,16 @@ MakeSN(const char *principal, nsCString &result) //----------------------------------------------------------------------------- -nsNegotiateAuth::nsNegotiateAuth(PRBool useNTLM) +nsAuthSSPI::nsAuthSSPI(pType package) : mServiceFlags(REQ_DEFAULT) , mMaxTokenLen(0) - , mUseNTLM(useNTLM) + , mPackage(package) { memset(&mCred, 0, sizeof(mCred)); memset(&mCtxt, 0, sizeof(mCtxt)); } -nsNegotiateAuth::~nsNegotiateAuth() +nsAuthSSPI::~nsAuthSSPI() { Reset(); @@ -186,7 +207,7 @@ nsNegotiateAuth::~nsNegotiateAuth() } void -nsNegotiateAuth::Reset() +nsAuthSSPI::Reset() { if (mCtxt.dwLower || mCtxt.dwUpper) { (sspi->DeleteSecurityContext)(&mCtxt); @@ -194,21 +215,23 @@ nsNegotiateAuth::Reset() } } -NS_IMPL_ISUPPORTS1(nsNegotiateAuth, nsIAuthModule) +NS_IMPL_ISUPPORTS1(nsAuthSSPI, nsIAuthModule) NS_IMETHODIMP -nsNegotiateAuth::Init(const char *serviceName, - PRUint32 serviceFlags, - const PRUnichar *domain, - const PRUnichar *username, - const PRUnichar *password) +nsAuthSSPI::Init(const char *serviceName, + PRUint32 serviceFlags, + const PRUnichar *domain, + const PRUnichar *username, + const PRUnichar *password) { + LOG((" nsAuthSSPI::Init\n")); + // we don't expect to be passed any user credentials NS_ASSERTION(!domain && !username && !password, "unexpected credentials"); - // if we're configured for SPNEGO, then it's critial that the caller - // supply a service name to be used. - if (!mUseNTLM) + // if we're configured for SPNEGO (Negotiate) or Kerberos, then it's critical + // that the caller supply a service name to be used. + if (mPackage != PACKAGE_TYPE_NTLM) NS_ENSURE_TRUE(serviceName && *serviceName, NS_ERROR_INVALID_ARG); nsresult rv; @@ -221,11 +244,11 @@ nsNegotiateAuth::Init(const char *serviceName, } SEC_CHAR *package; - if (mUseNTLM) - package = "NTLM"; - else { - package = "Negotiate"; + package = (SEC_CHAR *) pTypeName[(int)mPackage]; + + if (mPackage != PACKAGE_TYPE_NTLM) + { rv = MakeSN(serviceName, mServiceName); if (NS_FAILED(rv)) return rv; @@ -261,10 +284,10 @@ nsNegotiateAuth::Init(const char *serviceName, } NS_IMETHODIMP -nsNegotiateAuth::GetNextToken(const void *inToken, - PRUint32 inTokenLen, - void **outToken, - PRUint32 *outTokenLen) +nsAuthSSPI::GetNextToken(const void *inToken, + PRUint32 inTokenLen, + void **outToken, + PRUint32 *outTokenLen) { SECURITY_STATUS rc; @@ -273,7 +296,7 @@ nsNegotiateAuth::GetNextToken(const void *inToken, SecBufferDesc ibd, obd; SecBuffer ib, ob; - LOG(("entering nsNegotiateAuth::GetNextToken()\n")); + LOG(("entering nsAuthSSPI::GetNextToken()\n")); if (mServiceFlags & REQ_DELEGATE) ctxReq |= ISC_REQ_DELEGATE; @@ -314,7 +337,8 @@ nsNegotiateAuth::GetNextToken(const void *inToken, memset(ob.pvBuffer, 0, ob.cbBuffer); SEC_CHAR *sn; - if (mUseNTLM) + + if (mPackage == PACKAGE_TYPE_NTLM) sn = NULL; else sn = (SEC_CHAR *) mServiceName.get(); @@ -334,6 +358,10 @@ nsNegotiateAuth::GetNextToken(const void *inToken, if (rc == SEC_I_CONTINUE_NEEDED || rc == SEC_E_OK) { *outToken = ob.pvBuffer; *outTokenLen = ob.cbBuffer; + + if (rc == SEC_E_OK) + return NS_SUCCESS_AUTH_FINISHED; + return NS_OK; } @@ -342,3 +370,144 @@ nsNegotiateAuth::GetNextToken(const void *inToken, nsMemory::Free(ob.pvBuffer); return NS_ERROR_FAILURE; } + +NS_IMETHODIMP +nsAuthSSPI::Unwrap(const void *inToken, + PRUint32 inTokenLen, + void **outToken, + PRUint32 *outTokenLen) +{ + SECURITY_STATUS rc; + SecBufferDesc ibd; + SecBuffer ib[2]; + + ibd.cBuffers = 2; + ibd.pBuffers = ib; + ibd.ulVersion = SECBUFFER_VERSION; + + // SSPI Buf + ib[0].BufferType = SECBUFFER_STREAM; + ib[0].cbBuffer = inTokenLen; + ib[0].pvBuffer = nsMemory::Alloc(ib[0].cbBuffer); + memcpy(ib[0].pvBuffer, inToken, inTokenLen); + + // app data + ib[1].BufferType = SECBUFFER_DATA; + ib[1].cbBuffer = 0; + ib[1].pvBuffer = NULL; + + rc = (sspi->DecryptMessage)( + &mCtxt, + &ibd, + 0, // no sequence numbers + NULL + ); + + if (SEC_SUCCESS(rc)) { + *outToken = ib[1].pvBuffer; + *outTokenLen = ib[1].cbBuffer; + } + else + nsMemory::Free(ib[1].pvBuffer); + + nsMemory::Free(ib[0].pvBuffer); + + return rc; +} + +// utility class used to free memory on exit +class secBuffers +{ +public: + + SecBuffer ib[3]; + + secBuffers() { memset(&ib, 0, sizeof(ib)); } + + ~secBuffers() + { + if (ib[0].pvBuffer) + nsMemory::Free(ib[0].pvBuffer); + + if (ib[1].pvBuffer) + nsMemory::Free(ib[1].pvBuffer); + + if (ib[2].pvBuffer) + nsMemory::Free(ib[2].pvBuffer); + } +}; + +NS_IMETHODIMP +nsAuthSSPI::Wrap(const void *inToken, + PRUint32 inTokenLen, + PRBool confidential, + void **outToken, + PRUint32 *outTokenLen) +{ + SECURITY_STATUS rc; + + SecBufferDesc ibd; + secBuffers bufs; + SecPkgContext_Sizes sizes; + + rc = (sspi->QueryContextAttributes)( + &mCtxt, + SECPKG_ATTR_SIZES, + &sizes); + + if (!SEC_SUCCESS(rc)) + return rc; + + ibd.cBuffers = 3; + ibd.pBuffers = bufs.ib; + ibd.ulVersion = SECBUFFER_VERSION; + + // SSPI + bufs.ib[0].cbBuffer = sizes.cbSecurityTrailer; + bufs.ib[0].BufferType = SECBUFFER_TOKEN; + bufs.ib[0].pvBuffer = nsMemory::Alloc(sizes.cbSecurityTrailer); + + if (!bufs.ib[0].pvBuffer) + return NS_ERROR_OUT_OF_MEMORY; + + // APP Data + bufs.ib[1].BufferType = SECBUFFER_DATA; + bufs.ib[1].pvBuffer = nsMemory::Alloc(inTokenLen); + bufs.ib[1].cbBuffer = inTokenLen; + + if (!bufs.ib[1].pvBuffer) + return NS_ERROR_OUT_OF_MEMORY; + + memcpy(bufs.ib[1].pvBuffer, inToken, inTokenLen); + + // SSPI + bufs.ib[2].BufferType = SECBUFFER_PADDING; + bufs.ib[2].cbBuffer = sizes.cbBlockSize; + bufs.ib[2].pvBuffer = nsMemory::Alloc(bufs.ib[2].cbBuffer); + + if (!bufs.ib[2].pvBuffer) + return NS_ERROR_OUT_OF_MEMORY; + + rc = (sspi->EncryptMessage)(&mCtxt, + confidential ? 0 : KERB_WRAP_NO_ENCRYPT, + &ibd, 0); + + if (SEC_SUCCESS(rc)) { + int len = bufs.ib[0].cbBuffer + bufs.ib[1].cbBuffer + bufs.ib[2].cbBuffer; + + *outToken = nsMemory::Alloc(len); + + if (!*outToken) + return NS_ERROR_OUT_OF_MEMORY; + + memcpy(outToken, bufs.ib[0].pvBuffer, bufs.ib[0].cbBuffer); + + memcpy(outToken + bufs.ib[0].cbBuffer, + bufs.ib[1].pvBuffer, bufs.ib[1].cbBuffer); + + memcpy(outToken + bufs.ib[0].cbBuffer + bufs.ib[1].cbBuffer, + bufs.ib[2].pvBuffer, bufs.ib[2].cbBuffer); + } + + return rc; +} diff --git a/mozilla/extensions/auth/nsAuthSSPI.h b/mozilla/extensions/auth/nsAuthSSPI.h index 0131bfb200c..152beda6917 100644 --- a/mozilla/extensions/auth/nsAuthSSPI.h +++ b/mozilla/extensions/auth/nsAuthSSPI.h @@ -35,9 +35,10 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef nsNegotiateAuthSSPI_h__ -#define nsNegotiateAuthSSPI_h__ +#ifndef nsAuthSSPI_h__ +#define nsAuthSSPI_h__ +#include "nsAuth.h" #include "nsIAuthModule.h" #include "nsString.h" @@ -56,16 +57,16 @@ // avoided when authenticating over the internet since it may use a lower-grade // version of password hashing depending on the version of Windows being used. -class nsNegotiateAuth : public nsIAuthModule +class nsAuthSSPI : public nsIAuthModule { public: NS_DECL_ISUPPORTS NS_DECL_NSIAUTHMODULE - nsNegotiateAuth(PRBool useNTLM = PR_FALSE); + nsAuthSSPI(pType package = PACKAGE_TYPE_NEGOTIATE); private: - ~nsNegotiateAuth(); + ~nsAuthSSPI(); void Reset(); @@ -75,7 +76,7 @@ private: nsCString mServiceName; PRUint32 mServiceFlags; PRUint32 mMaxTokenLen; - PRBool mUseNTLM; + pType mPackage; }; -#endif /* nsNegotiateAuthSSPI_h__ */ +#endif /* nsAuthSSPI_h__ */ diff --git a/mozilla/extensions/auth/nsHttpNegotiateAuth.cpp b/mozilla/extensions/auth/nsHttpNegotiateAuth.cpp index 5e3d68af78d..b7404fc68f1 100644 --- a/mozilla/extensions/auth/nsHttpNegotiateAuth.cpp +++ b/mozilla/extensions/auth/nsHttpNegotiateAuth.cpp @@ -51,7 +51,7 @@ #include #include -#include "nsNegotiateAuth.h" +#include "nsAuth.h" #include "nsHttpNegotiateAuth.h" #include "nsIHttpChannel.h" @@ -77,6 +77,7 @@ static const char kNegotiate[] = "Negotiate"; static const char kNegotiateAuthTrustedURIs[] = "network.negotiate-auth.trusted-uris"; static const char kNegotiateAuthDelegationURIs[] = "network.negotiate-auth.delegation-uris"; static const char kNegotiateAuthAllowProxies[] = "network.negotiate-auth.allow-proxies"; +static const char kNegotiateAuthSSPI[] = "network.auth.use-sspi"; #define kNegotiateLen (sizeof(kNegotiate)-1) @@ -175,11 +176,25 @@ nsHttpNegotiateAuth::ChallengeReceived(nsIHttpChannel *httpChannel, // service.Insert("HTTP@", 0); - rv = CallCreateInstance(NS_AUTH_MODULE_CONTRACTID_PREFIX "negotiate", &module); - if (NS_FAILED(rv)) + const char *contractID; + if (TestBoolPref(kNegotiateAuthSSPI)) { + LOG((" using negotiate-sspi\n")); + contractID = NS_AUTH_MODULE_CONTRACTID_PREFIX "negotiate-sspi"; + } + else { + LOG((" using negotiate-gss\n")); + contractID = NS_AUTH_MODULE_CONTRACTID_PREFIX "negotiate-gss"; + } + + rv = CallCreateInstance(contractID, &module); + + if (NS_FAILED(rv)) { + LOG((" Failed to load Negotiate Module \n")); return rv; + } rv = module->Init(service.get(), req_flags, nsnull, nsnull, nsnull); + if (NS_FAILED(rv)) { NS_RELEASE(module); return rv; diff --git a/mozilla/extensions/auth/nsHttpNegotiateAuth.h b/mozilla/extensions/auth/nsHttpNegotiateAuth.h index 7bde75f3760..3d9aebeb1c6 100644 --- a/mozilla/extensions/auth/nsHttpNegotiateAuth.h +++ b/mozilla/extensions/auth/nsHttpNegotiateAuth.h @@ -45,7 +45,7 @@ #include "nsIURI.h" #include "nsSubstring.h" -// The nsGssapiAuth class provides responses for the GSS-API Negotiate method +// The nsHttpNegotiateAuth class provides responses for the GSS-API Negotiate method // as specified by Microsoft in draft-brezak-spnego-http-04.txt class nsHttpNegotiateAuth : public nsIHttpAuthenticator