// // 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; }