diff --git a/mozilla/extensions/auth/nsAuthGSSAPI.cpp b/mozilla/extensions/auth/nsAuthGSSAPI.cpp index 972ef700936..0858be510f4 100644 --- a/mozilla/extensions/auth/nsAuthGSSAPI.cpp +++ b/mozilla/extensions/auth/nsAuthGSSAPI.cpp @@ -47,6 +47,13 @@ // 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" @@ -55,8 +62,151 @@ #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 *); + //----------------------------------------------------------------------------- +// 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]) + +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; + } + } + + gssFunInit = PR_TRUE; + return NS_OK; +} + #if defined( PR_LOGGING ) // Generate proper GSSAPI error messages from the major and @@ -71,22 +221,25 @@ LogGssError(OM_uint32 maj_stat, OM_uint32 min_stat, const char *prefix) OM_uint32 ret; nsCAutoString error(prefix); + if (!gssFunInit) + return; + error += ": "; do { - ret = gss_display_status (&new_stat, - maj_stat, - GSS_C_GSS_CODE, - GSS_C_NULL_OID, - &msg_ctx, - &status1_string); + 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 (&new_stat, - min_stat, - GSS_C_MECH_CODE, - GSS_C_NULL_OID, - &msg_ctx, - &status2_string); + 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); @@ -110,9 +263,14 @@ nsNegotiateAuth::nsNegotiateAuth() 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"}; + { 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"}; + { 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; @@ -128,7 +286,7 @@ nsNegotiateAuth::nsNegotiateAuth() // with SPNEGO) may work in some cases depending // on how smart the server side is. // - majstat = gss_indicate_mechs(&minstat, &mech_set); + majstat = gss_indicate_mechs_ptr(&minstat, &mech_set); if (GSS_ERROR(majstat)) return; @@ -142,15 +300,15 @@ nsNegotiateAuth::nsNegotiateAuth() break; } } - gss_release_oid_set(&minstat, &mech_set); + gss_release_oid_set_ptr(&minstat, &mech_set); } void nsNegotiateAuth::Reset() { - if (mCtx != GSS_C_NO_CONTEXT) { + if (gssFunInit && mCtx != GSS_C_NO_CONTEXT) { OM_uint32 minor_status; - gss_delete_sec_context(&minor_status, &mCtx, GSS_C_NO_BUFFER); + gss_delete_sec_context_ptr(&minor_status, &mCtx, GSS_C_NO_BUFFER); } mCtx = GSS_C_NO_CONTEXT; } @@ -159,10 +317,10 @@ NS_IMPL_ISUPPORTS1(nsNegotiateAuth, nsIAuthModule) NS_IMETHODIMP nsNegotiateAuth::Init(const char *serviceName, - PRUint32 serviceFlags, - const PRUnichar *domain, - const PRUnichar *username, - const PRUnichar *password) + 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"); @@ -170,6 +328,11 @@ 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")); + + if (!gssFunInit) + return NS_ERROR_NOT_INITIALIZED; + mServiceName = serviceName; mServiceFlags = serviceFlags; return NS_OK; @@ -177,9 +340,9 @@ nsNegotiateAuth::Init(const char *serviceName, NS_IMETHODIMP nsNegotiateAuth::GetNextToken(const void *inToken, - PRUint32 inTokenLen, - void **outToken, - PRUint32 *outTokenLen) + PRUint32 inTokenLen, + void **outToken, + PRUint32 *outTokenLen) { OM_uint32 major_status, minor_status; OM_uint32 req_flags = 0; @@ -190,19 +353,18 @@ nsNegotiateAuth::GetNextToken(const void *inToken, 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(&minor_status, + major_status = gss_import_name_ptr(&minor_status, &input_token, -#ifdef HAVE_GSS_C_NT_HOSTBASED_SERVICE - GSS_C_NT_HOSTBASED_SERVICE, -#else - gss_nt_service_name, -#endif + &gss_c_nt_hostbased_service, &server); input_token.value = NULL; input_token.length = 0; @@ -228,27 +390,32 @@ nsNegotiateAuth::GetNextToken(const void *inToken, #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 (KLCacheHasValidTickets(NULL, kerberosVersion_V5, &found, NULL, NULL) != klNoErr || !found) + if (gssNativeImp && + (KLCacheHasValidTickets(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(&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); + 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)) { @@ -280,11 +447,11 @@ nsNegotiateAuth::GetNextToken(const void *inToken, *outTokenLen = output_token.length; *outToken = nsMemory::Clone(output_token.value, output_token.length); - gss_release_buffer(&minor_status, &output_token); + gss_release_buffer_ptr(&minor_status, &output_token); rv = NS_OK; end: - gss_release_name(&minor_status, &server); + gss_release_name_ptr(&minor_status, &server); LOG((" leaving nsNegotiateAuth::GetNextToken [rv=%x]", rv)); return rv;