1 /* vim:set ts=4 sw=2 et cindent: */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "nsComponentManagerUtils.h"
7 #include "nsNativeCharsetUtils.h"
8 #include "nsIPrefService.h"
9 #include "nsServiceManagerUtils.h"
10
11 #include "nsAuthSASL.h"
12
13 static const char kNegotiateAuthSSPI[] = "network.auth.use-sspi";
14
nsAuthSASL()15 nsAuthSASL::nsAuthSASL() { mSASLReady = false; }
16
Reset()17 void nsAuthSASL::Reset() { mSASLReady = false; }
18
19 /* Limitations apply to this class's thread safety. See the header file */
NS_IMPL_ISUPPORTS(nsAuthSASL,nsIAuthModule)20 NS_IMPL_ISUPPORTS(nsAuthSASL, nsIAuthModule)
21
22 NS_IMETHODIMP
23 nsAuthSASL::Init(const char* serviceName, uint32_t serviceFlags,
24 const char16_t* domain, const char16_t* username,
25 const char16_t* password) {
26 nsresult rv;
27
28 NS_ASSERTION(username, "SASL requires a username");
29 NS_ASSERTION(!domain && !password, "unexpected credentials");
30
31 mUsername = username;
32
33 // If we're doing SASL, we should do mutual auth
34 serviceFlags |= REQ_MUTUAL_AUTH;
35
36 // Find out whether we should be trying SSPI or not
37 const char* authType = "kerb-gss";
38
39 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
40 if (prefs) {
41 bool val;
42 rv = prefs->GetBoolPref(kNegotiateAuthSSPI, &val);
43 if (NS_SUCCEEDED(rv) && val) authType = "kerb-sspi";
44 }
45
46 MOZ_ALWAYS_TRUE(mInnerModule = nsIAuthModule::CreateInstance(authType));
47
48 mInnerModule->Init(serviceName, serviceFlags, nullptr, nullptr, nullptr);
49
50 return NS_OK;
51 }
52
53 NS_IMETHODIMP
GetNextToken(const void * inToken,uint32_t inTokenLen,void ** outToken,uint32_t * outTokenLen)54 nsAuthSASL::GetNextToken(const void* inToken, uint32_t inTokenLen,
55 void** outToken, uint32_t* outTokenLen) {
56 nsresult rv;
57 void* unwrappedToken;
58 char* message;
59 uint32_t unwrappedTokenLen, messageLen;
60 nsAutoCString userbuf;
61
62 if (!mInnerModule) return NS_ERROR_NOT_INITIALIZED;
63
64 if (mSASLReady) {
65 // If the server COMPLETEs with an empty token, Cyrus sends us that token.
66 // I don't think this is correct, but we need to handle that behaviour.
67 // Cyrus ignores the contents of our reply token.
68 if (inTokenLen == 0) {
69 *outToken = nullptr;
70 *outTokenLen = 0;
71 return NS_OK;
72 }
73 // We've completed the GSSAPI portion of the handshake, and are
74 // now ready to do the SASL security layer and authzid negotiation
75
76 // Input packet from the server needs to be unwrapped.
77 rv = mInnerModule->Unwrap(inToken, inTokenLen, &unwrappedToken,
78 &unwrappedTokenLen);
79 if (NS_FAILED(rv)) {
80 Reset();
81 return rv;
82 }
83
84 // If we were doing security layers then we'd care what the
85 // server had sent us. We're not, so all we had to do was make
86 // sure that the signature was correct with the above unwrap()
87 free(unwrappedToken);
88
89 NS_CopyUnicodeToNative(mUsername, userbuf);
90 messageLen = userbuf.Length() + 4 + 1;
91 message = (char*)moz_xmalloc(messageLen);
92 message[0] = 0x01; // No security layer
93 message[1] = 0x00;
94 message[2] = 0x00;
95 message[3] = 0x00; // Maxbuf must be zero if we've got no sec layer
96 strcpy(message + 4, userbuf.get());
97 // Userbuf should not be nullptr terminated, so trim the trailing nullptr
98 // when wrapping the message
99 rv = mInnerModule->Wrap((void*)message, messageLen - 1, false, outToken,
100 outTokenLen);
101 free(message);
102 Reset(); // All done
103 return NS_SUCCEEDED(rv) ? NS_SUCCESS_AUTH_FINISHED : rv;
104 }
105 rv = mInnerModule->GetNextToken(inToken, inTokenLen, outToken, outTokenLen);
106 if (rv == NS_SUCCESS_AUTH_FINISHED) {
107 mSASLReady = true;
108 rv = NS_OK;
109 }
110 return rv;
111 }
112
113 NS_IMETHODIMP
Unwrap(const void * inToken,uint32_t inTokenLen,void ** outToken,uint32_t * outTokenLen)114 nsAuthSASL::Unwrap(const void* inToken, uint32_t inTokenLen, void** outToken,
115 uint32_t* outTokenLen) {
116 return NS_ERROR_NOT_IMPLEMENTED;
117 }
118
119 NS_IMETHODIMP
Wrap(const void * inToken,uint32_t inTokenLen,bool confidential,void ** outToken,uint32_t * outTokenLen)120 nsAuthSASL::Wrap(const void* inToken, uint32_t inTokenLen, bool confidential,
121 void** outToken, uint32_t* outTokenLen) {
122 return NS_ERROR_NOT_IMPLEMENTED;
123 }
124