DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Header

Mercurial (dcc6d7a0dc00)

VCS Links

Line Code
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;
}