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