1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/extensions/auth/nsAuthSASL.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,151 @@ 1.4 +/* vim:set ts=4 sw=4 et cindent: */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsComponentManagerUtils.h" 1.10 +#include "nsNativeCharsetUtils.h" 1.11 +#include "nsIServiceManager.h" 1.12 +#include "nsIPrefService.h" 1.13 + 1.14 +#include "nsAuthSASL.h" 1.15 + 1.16 +static const char kNegotiateAuthSSPI[] = "network.auth.use-sspi"; 1.17 + 1.18 +nsAuthSASL::nsAuthSASL() 1.19 +{ 1.20 + mSASLReady = false; 1.21 +} 1.22 + 1.23 +void nsAuthSASL::Reset() 1.24 +{ 1.25 + mSASLReady = false; 1.26 +} 1.27 + 1.28 +/* Limitations apply to this class's thread safety. See the header file */ 1.29 +NS_IMPL_ISUPPORTS(nsAuthSASL, nsIAuthModule) 1.30 + 1.31 +NS_IMETHODIMP 1.32 +nsAuthSASL::Init(const char *serviceName, 1.33 + uint32_t serviceFlags, 1.34 + const char16_t *domain, 1.35 + const char16_t *username, 1.36 + const char16_t *password) 1.37 +{ 1.38 + nsresult rv; 1.39 + 1.40 + NS_ASSERTION(username, "SASL requires a username"); 1.41 + NS_ASSERTION(!domain && !password, "unexpected credentials"); 1.42 + 1.43 + mUsername = username; 1.44 + 1.45 + // If we're doing SASL, we should do mutual auth 1.46 + serviceFlags |= REQ_MUTUAL_AUTH; 1.47 + 1.48 + // Find out whether we should be trying SSPI or not 1.49 + const char *contractID = NS_AUTH_MODULE_CONTRACTID_PREFIX "kerb-gss"; 1.50 + 1.51 + nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); 1.52 + if (prefs) { 1.53 + bool val; 1.54 + rv = prefs->GetBoolPref(kNegotiateAuthSSPI, &val); 1.55 + if (NS_SUCCEEDED(rv) && val) 1.56 + contractID = NS_AUTH_MODULE_CONTRACTID_PREFIX "kerb-sspi"; 1.57 + } 1.58 + 1.59 + mInnerModule = do_CreateInstance(contractID, &rv); 1.60 + // if we can't create the GSSAPI module, then bail 1.61 + NS_ENSURE_SUCCESS(rv, rv); 1.62 + 1.63 + mInnerModule->Init(serviceName, serviceFlags, nullptr, nullptr, nullptr); 1.64 + 1.65 + return NS_OK; 1.66 +} 1.67 + 1.68 +NS_IMETHODIMP 1.69 +nsAuthSASL::GetNextToken(const void *inToken, 1.70 + uint32_t inTokenLen, 1.71 + void **outToken, 1.72 + uint32_t *outTokenLen) 1.73 +{ 1.74 + nsresult rv; 1.75 + void *unwrappedToken; 1.76 + char *message; 1.77 + uint32_t unwrappedTokenLen, messageLen; 1.78 + nsAutoCString userbuf; 1.79 + 1.80 + if (!mInnerModule) 1.81 + return NS_ERROR_NOT_INITIALIZED; 1.82 + 1.83 + if (mSASLReady) { 1.84 + // If the server COMPLETEs with an empty token, Cyrus sends us that token. 1.85 + // I don't think this is correct, but we need to handle that behaviour. 1.86 + // Cyrus ignores the contents of our reply token. 1.87 + if (inTokenLen == 0) { 1.88 + *outToken = nullptr; 1.89 + *outTokenLen = 0; 1.90 + return NS_OK; 1.91 + } 1.92 + // We've completed the GSSAPI portion of the handshake, and are 1.93 + // now ready to do the SASL security layer and authzid negotiation 1.94 + 1.95 + // Input packet from the server needs to be unwrapped. 1.96 + rv = mInnerModule->Unwrap(inToken, inTokenLen, &unwrappedToken, 1.97 + &unwrappedTokenLen); 1.98 + if (NS_FAILED(rv)) { 1.99 + Reset(); 1.100 + return rv; 1.101 + } 1.102 + 1.103 + // If we were doing security layers then we'd care what the 1.104 + // server had sent us. We're not, so all we had to do was make 1.105 + // sure that the signature was correct with the above unwrap() 1.106 + nsMemory::Free(unwrappedToken); 1.107 + 1.108 + NS_CopyUnicodeToNative(mUsername, userbuf); 1.109 + messageLen = userbuf.Length() + 4 + 1; 1.110 + message = (char *)nsMemory::Alloc(messageLen); 1.111 + if (!message) { 1.112 + Reset(); 1.113 + return NS_ERROR_OUT_OF_MEMORY; 1.114 + } 1.115 + message[0] = 0x01; // No security layer 1.116 + message[1] = 0x00; 1.117 + message[2] = 0x00; 1.118 + message[3] = 0x00; // Maxbuf must be zero if we've got no sec layer 1.119 + strcpy(message+4, userbuf.get()); 1.120 + // Userbuf should not be nullptr terminated, so trim the trailing nullptr 1.121 + // when wrapping the message 1.122 + rv = mInnerModule->Wrap((void *) message, messageLen-1, false, 1.123 + outToken, outTokenLen); 1.124 + nsMemory::Free(message); 1.125 + Reset(); // All done 1.126 + return NS_SUCCEEDED(rv) ? NS_SUCCESS_AUTH_FINISHED : rv; 1.127 + } 1.128 + rv = mInnerModule->GetNextToken(inToken, inTokenLen, outToken, 1.129 + outTokenLen); 1.130 + if (rv == NS_SUCCESS_AUTH_FINISHED) { 1.131 + mSASLReady = true; 1.132 + rv = NS_OK; 1.133 + } 1.134 + return rv; 1.135 +} 1.136 + 1.137 +NS_IMETHODIMP 1.138 +nsAuthSASL::Unwrap(const void *inToken, 1.139 + uint32_t inTokenLen, 1.140 + void **outToken, 1.141 + uint32_t *outTokenLen) 1.142 +{ 1.143 + return NS_ERROR_NOT_IMPLEMENTED; 1.144 +} 1.145 + 1.146 +NS_IMETHODIMP 1.147 +nsAuthSASL::Wrap(const void *inToken, 1.148 + uint32_t inTokenLen, 1.149 + bool confidential, 1.150 + void **outToken, 1.151 + uint32_t *outTokenLen) 1.152 +{ 1.153 + return NS_ERROR_NOT_IMPLEMENTED; 1.154 +}