Example #1
0
//
// GenerateCredentials
//
// This routine is responsible for creating the correct authentication
// blob to pass to the server that requested "Negotiate" authentication.
//
NS_IMETHODIMP
nsHttpNegotiateAuth::GenerateCredentials(nsIHttpAuthenticableChannel *authChannel,
                                         const char *challenge,
                                         bool isProxyAuth,
                                         const char16_t *domain,
                                         const char16_t *username,
                                         const char16_t *password,
                                         nsISupports **sessionState,
                                         nsISupports **continuationState,
                                         uint32_t *flags,
                                         char **creds)
{
    // ChallengeReceived must have been called previously.
    nsIAuthModule *module = (nsIAuthModule *) *continuationState;
    NS_ENSURE_TRUE(module, NS_ERROR_NOT_INITIALIZED);

    *flags = USING_INTERNAL_IDENTITY;

    LOG(("nsHttpNegotiateAuth::GenerateCredentials() [challenge=%s]\n", challenge));

    NS_ASSERTION(creds, "null param");

#ifdef DEBUG
    bool isGssapiAuth =
        !PL_strncasecmp(challenge, kNegotiate, kNegotiateLen);
    NS_ASSERTION(isGssapiAuth, "Unexpected challenge");
#endif

    //
    // If the "Negotiate:" header had some data associated with it,
    // that data should be used as the input to this call.  This may
    // be a continuation of an earlier call because GSSAPI authentication
    // often takes multiple round-trips to complete depending on the
    // context flags given.  We want to use MUTUAL_AUTHENTICATION which
    // generally *does* require multiple round-trips.  Don't assume
    // auth can be completed in just 1 call.
    //
    unsigned int len = strlen(challenge);

    void *inToken = nullptr, *outToken;
    uint32_t inTokenLen, outTokenLen;

    if (len > kNegotiateLen) {
        challenge += kNegotiateLen;
        while (*challenge == ' ')
            challenge++;
        len = strlen(challenge);

        // strip off any padding (see bug 230351)
        while (challenge[len - 1] == '=')
            len--;

        //
        // Decode the response that followed the "Negotiate" token
        //
        nsresult rv =
            Base64Decode(challenge, len, (char**)&inToken, &inTokenLen);

        if (NS_FAILED(rv)) {
            free(inToken);
            return rv;
        }
    }
    else {
        //
        // Initializing, don't use an input token.
        //
        inTokenLen = 0;
    }

    nsresult rv = module->GetNextToken(inToken, inTokenLen, &outToken, &outTokenLen);

    free(inToken);

    if (NS_FAILED(rv))
        return rv;

    if (outTokenLen == 0) {
        LOG(("  No output token to send, exiting"));
        return NS_ERROR_FAILURE;
    }

    //
    // base64 encode the output token.
    //
    char *encoded_token = PL_Base64Encode((char *)outToken, outTokenLen, nullptr);

    free(outToken);

    if (!encoded_token)
        return NS_ERROR_OUT_OF_MEMORY;

    LOG(("  Sending a token of length %d\n", outTokenLen));

    // allocate a buffer sizeof("Negotiate" + " " + b64output_token + "\0")
    const int bufsize = kNegotiateLen + 1 + strlen(encoded_token) + 1;
    *creds = (char *) moz_xmalloc(bufsize);
    if (MOZ_UNLIKELY(!*creds))
        rv = NS_ERROR_OUT_OF_MEMORY;
    else
        snprintf(*creds, bufsize, "%s %s", kNegotiate, encoded_token);

    PR_Free(encoded_token); // PL_Base64Encode() uses PR_Malloc().
    return rv;
}