summaryrefslogtreecommitdiffstats
path: root/extensions/auth/nsAuthSASL.cpp
blob: 2c72cb0ac55ee04dd9410880fc14eab12eb29ac6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/* vim:set ts=4 sw=4 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "nsComponentManagerUtils.h"
#include "nsNativeCharsetUtils.h"
#include "nsIServiceManager.h"
#include "nsIPrefService.h"

#include "nsAuthSASL.h"

static const char kNegotiateAuthSSPI[] = "network.auth.use-sspi";

nsAuthSASL::nsAuthSASL()
{
    mSASLReady = false;
}

void nsAuthSASL::Reset() 
{
    mSASLReady = false;
}

/* Limitations apply to this class's thread safety. See the header file */
NS_IMPL_ISUPPORTS(nsAuthSASL, nsIAuthModule)

NS_IMETHODIMP
nsAuthSASL::Init(const char *serviceName,
                 uint32_t    serviceFlags,
                 const char16_t *domain,
                 const char16_t *username,
                 const char16_t *password)
{
    nsresult rv;
    
    NS_ASSERTION(username, "SASL requires a username");
    NS_ASSERTION(!domain && !password, "unexpected credentials");

    mUsername = username;
    
    // If we're doing SASL, we should do mutual auth
    serviceFlags |= REQ_MUTUAL_AUTH;
   
    // Find out whether we should be trying SSPI or not
    const char *contractID = NS_AUTH_MODULE_CONTRACTID_PREFIX "kerb-gss";
    
    nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
    if (prefs) {
        bool val;
        rv = prefs->GetBoolPref(kNegotiateAuthSSPI, &val);
        if (NS_SUCCEEDED(rv) && val)
            contractID = NS_AUTH_MODULE_CONTRACTID_PREFIX "kerb-sspi";
    }
    
    mInnerModule = do_CreateInstance(contractID, &rv);
    // if we can't create the GSSAPI module, then bail
    NS_ENSURE_SUCCESS(rv, rv);

    mInnerModule->Init(serviceName, serviceFlags, nullptr, nullptr, nullptr);

    return NS_OK;
}

NS_IMETHODIMP
nsAuthSASL::GetNextToken(const void *inToken,
                         uint32_t    inTokenLen,
                         void      **outToken,
                         uint32_t   *outTokenLen)
{
    nsresult rv;
    void *unwrappedToken;
    char *message;
    uint32_t unwrappedTokenLen, messageLen;
    nsAutoCString userbuf;
    
    if (!mInnerModule) 
        return NS_ERROR_NOT_INITIALIZED;

    if (mSASLReady) {
        // If the server COMPLETEs with an empty token, Cyrus sends us that token.
        // I don't think this is correct, but we need to handle that behaviour.
        // Cyrus ignores the contents of our reply token.
        if (inTokenLen == 0) {
            *outToken = nullptr;
            *outTokenLen = 0;
            return NS_OK;
        }
        // We've completed the GSSAPI portion of the handshake, and are
        // now ready to do the SASL security layer and authzid negotiation

        // Input packet from the server needs to be unwrapped.
        rv = mInnerModule->Unwrap(inToken, inTokenLen, &unwrappedToken, 
                                  &unwrappedTokenLen);
        if (NS_FAILED(rv)) {
            Reset();
            return rv;
        }
        
        // If we were doing security layers then we'd care what the
        // server had sent us. We're not, so all we had to do was make
        // sure that the signature was correct with the above unwrap()
        free(unwrappedToken);
        
        NS_CopyUnicodeToNative(mUsername, userbuf);
        messageLen = userbuf.Length() + 4 + 1;
        message = (char *)moz_xmalloc(messageLen);
        if (!message) {
          Reset();
          return NS_ERROR_OUT_OF_MEMORY;
        }
        message[0] = 0x01; // No security layer
        message[1] = 0x00;
        message[2] = 0x00;
        message[3] = 0x00; // Maxbuf must be zero if we've got no sec layer
        strcpy(message+4, userbuf.get());
        // Userbuf should not be nullptr terminated, so trim the trailing nullptr
        // when wrapping the message
        rv = mInnerModule->Wrap((void *) message, messageLen-1, false, 
                                outToken, outTokenLen);
        free(message);
        Reset(); // All done
        return NS_SUCCEEDED(rv) ? NS_SUCCESS_AUTH_FINISHED : rv;
    }
    rv = mInnerModule->GetNextToken(inToken, inTokenLen, outToken, 
                                    outTokenLen);
    if (rv == NS_SUCCESS_AUTH_FINISHED) {
        mSASLReady = true;
        rv = NS_OK;
    }
    return rv;
}

NS_IMETHODIMP
nsAuthSASL::Unwrap(const void *inToken,
                   uint32_t    inTokenLen,
                   void      **outToken,
                   uint32_t   *outTokenLen)
{
    return NS_ERROR_NOT_IMPLEMENTED;
}

NS_IMETHODIMP
nsAuthSASL::Wrap(const void *inToken,
                 uint32_t    inTokenLen,
                 bool        confidential,
                 void      **outToken,
                 uint32_t   *outTokenLen)
{
    return NS_ERROR_NOT_IMPLEMENTED;
}