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