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