예제 #1
0
NS_IMETHODIMP
nsMsgWindow::DisplayHTMLInMessagePane(const nsAString& title, const nsAString& body, bool clearMsgHdr)
{
  if (clearMsgHdr && mMsgWindowCommands)
    mMsgWindowCommands->ClearMsgPane();

  nsString htmlStr;
  htmlStr.Append(NS_LITERAL_STRING("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"></head><body>").get());
  htmlStr.Append(body);
  htmlStr.Append(NS_LITERAL_STRING("</body></html>").get());

  char *encodedHtml = PL_Base64Encode(NS_ConvertUTF16toUTF8(htmlStr).get(), 0, nsnull);
  if (!encodedHtml)
    return NS_ERROR_OUT_OF_MEMORY;

  nsCString dataSpec;
  dataSpec = "data:text/html;base64,";
  dataSpec += encodedHtml;

  PR_FREEIF(encodedHtml);

  nsCOMPtr <nsIDocShell> docShell;
  GetMessageWindowDocShell(getter_AddRefs(docShell));
  NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);

  nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
  NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);

  return webNav->LoadURI(NS_ConvertASCIItoUTF16(dataSpec).get(),
                         nsIWebNavigation::LOAD_FLAGS_NONE,
                         nsnull, nsnull, nsnull);
}
예제 #2
0
static int
ExportPublicKey(FILE *outFile, CERTCertificate *cert)
{
    char *data;
    SECKEYPublicKey *publicKey;
    SECItem *item;

    if (!cert)
        return -1;
    
    publicKey = CERT_ExtractPublicKey(cert);
    if (!publicKey)
        return -1;

    item = SECKEY_EncodeDERSubjectPublicKeyInfo(publicKey);
    SECKEY_DestroyPublicKey(publicKey);
    if (!item)
        return -1;
    
    data = PL_Base64Encode((const char*)item->data, item->len, NULL);
    SECITEM_FreeItem(item, PR_TRUE);
    if (!data)
        return -1;
    
    fputs("pubkey:\n", outFile);
    fputs(data, outFile);
    fputs("\n", outFile);
    PR_Free(data);
    
    return 0;
}
Btoa(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
    JSString *str;
    if (!argc)
        return JS_TRUE;

    str = JS_ValueToString(cx, argv[0]);
    if (!str)
        return JS_FALSE;

    char *bin_data = JS_GetStringBytes(str);
    size_t bin_dataLength = JS_GetStringLength(str);

    char *base64 = PL_Base64Encode(bin_data, bin_dataLength, nsnull);
    if (!base64)
        return JS_FALSE;

    PRUint32 base64Length = ((bin_dataLength + 2) / 3) * 4;
    str = JS_NewStringCopyN(cx, base64, base64Length);
    PR_Free(base64);
    if (!str)
        return JS_FALSE;

    *rval = STRING_TO_JSVAL(str);
    return JS_TRUE;
}
예제 #4
0
//----------------------------------------------------------------------------------------
void nsPersistentFileDescriptor::operator = (const nsFileSpec& inSpec)
//----------------------------------------------------------------------------------------
{
#if defined(XP_MAC)
    if (inSpec.Error())
        return;
    AliasHandle    aliasH;
    OSErr err = NewAlias(nil, inSpec.GetFSSpecPtr(), &aliasH);
    if (err != noErr)
        return;

    PRUint32 bytes = GetHandleSize((Handle) aliasH);
    HLock((Handle) aliasH);
    char* buf = PL_Base64Encode((const char*)*aliasH, bytes, nsnull);
    DisposeHandle((Handle) aliasH);

    mDescriptorString = buf;
    PR_Free(buf);
#elif  defined(XP_MACOSX)
    if (inSpec.Error())
        return;
    
    FSRef fileRef;
    Boolean isDir;
    OSErr err = ::FSPathMakeRef((const UInt8*)inSpec.GetCString(), &fileRef, &isDir);
    if (err != noErr)
        return;
    
    AliasHandle    aliasH;
    err = ::FSNewAlias(nsnull, &fileRef, &aliasH);
    if (err != noErr)
        return;

    PRUint32 bytes = ::GetHandleSize((Handle) aliasH);
    ::HLock((Handle)aliasH);
    char* buf = PL_Base64Encode((const char*)*aliasH, bytes, nsnull);
    ::DisposeHandle((Handle) aliasH);

    mDescriptorString = buf;
    PR_Free(buf);
#else
    mDescriptorString = inSpec.GetCString();
#endif // XP_MAC
} // nsPersistentFileDescriptor::operator =
nsresult nsCMSSecureMessage::
encode(const unsigned char *data, PRInt32 dataLen, char **_retval)
{
  nsresult rv = NS_OK;

  *_retval = PL_Base64Encode((const char *)data, dataLen, NULL);
  if (!*_retval) { rv = NS_ERROR_OUT_OF_MEMORY; goto loser; }

loser:
  return rv;
}
/**
 * Print base64-encoded token to the NSPR Log.
 * @param name Description of the token, will be printed in front
 * @param token The token to print
 * @param tokenLen length of the data in token
 */
static void LogToken(const char *name, const void *token, uint32_t tokenLen)
{
  if (!LOG_ENABLED())
    return;

  char *b64data = PL_Base64Encode((const char *) token, tokenLen, nullptr);
  if (b64data)
  {
    PR_LogPrint("%s: %s\n", name, b64data);
    PR_Free(b64data);
  }
}
예제 #7
0
nsresult
nsBase64Encoder::Finish(nsCSubstring& result)
{
  char* b64 = PL_Base64Encode(mData.get(), mData.Length(), nsnull);
  if (!b64)
    return NS_ERROR_OUT_OF_MEMORY;

  result.Assign(b64);
  PR_Free(b64);
  // Free unneeded memory and allow reusing the object
  mData.Truncate();
  return NS_OK;
}
예제 #8
0
NS_IMETHODIMP
nsAuthSambaNTLM::GetNextToken(const void *inToken,
                              PRUint32    inTokenLen,
                              void      **outToken,
                              PRUint32   *outTokenLen)
{
    if (!inToken) {
        /* someone wants our initial message */
        *outToken = nsMemory::Clone(mInitialMessage, mInitialMessageLen);
        if (!*outToken)
            return NS_ERROR_OUT_OF_MEMORY;
        *outTokenLen = mInitialMessageLen;
        return NS_OK;
    }

    /* inToken must be a type 2 message. Get ntlm_auth to generate our response */
    char* encoded = PL_Base64Encode(static_cast<const char*>(inToken), inTokenLen, nullptr);
    if (!encoded)
        return NS_ERROR_OUT_OF_MEMORY;

    nsCString request;
    request.AssignLiteral("TT ");
    request.Append(encoded);
    free(encoded);
    request.Append('\n');

    if (!WriteString(mToChildFD, request))
        return NS_ERROR_FAILURE;
    nsCString line;
    if (!ReadLine(mFromChildFD, line))
        return NS_ERROR_FAILURE;
    if (!StringBeginsWith(line, NS_LITERAL_CSTRING("KK "))) {
        // Something went wrong. Perhaps no credentials are accessible.
        return NS_ERROR_FAILURE;
    }
    PRUint8* buf = ExtractMessage(line, outTokenLen);
    if (!buf)
        return NS_ERROR_FAILURE;
    // *outToken has to be freed by nsMemory::Free, which may not be free() 
    *outToken = nsMemory::Clone(buf, *outTokenLen);
    if (!*outToken) {
        free(buf);
        return NS_ERROR_OUT_OF_MEMORY;
    }
    
    // We're done. Close our file descriptors now and reap the helper
    // process.
    Shutdown();
    return NS_SUCCESS_AUTH_FINISHED;
}
예제 #9
0
nsresult nsSecretDecoderRing::
encode(const unsigned char *data, PRInt32 dataLen, char **_retval)
{
  nsresult rv = NS_OK;

  char *result = PL_Base64Encode((const char *)data, dataLen, NULL);
  if (!result) { rv = NS_ERROR_OUT_OF_MEMORY; goto loser; }

  *_retval = NS_strdup(result);
  PR_DELETE(result);
  if (!*_retval) { rv = NS_ERROR_OUT_OF_MEMORY; goto loser; }

loser:
  return rv;
}
NS_IMETHODIMP
nsHttpBasicAuth::GenerateCredentials(nsIHttpAuthenticableChannel *authChannel,
                                     const char *challenge,
                                     bool isProxyAuth,
                                     const PRUnichar *domain,
                                     const PRUnichar *user,
                                     const PRUnichar *password,
                                     nsISupports **sessionState,
                                     nsISupports **continuationState,
                                     uint32_t *aFlags,
                                     char **creds)

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

    NS_ENSURE_ARG_POINTER(creds);

    *aFlags = 0;

    // we only know how to deal with Basic auth for http.
    bool isBasicAuth = !PL_strncasecmp(challenge, "basic", 5);
    NS_ENSURE_TRUE(isBasicAuth, NS_ERROR_UNEXPECTED);

    // we work with ASCII around here
    nsAutoCString userpass;
    LossyCopyUTF16toASCII(user, userpass);
    userpass.Append(':'); // always send a ':' (see bug 129565)
    if (password)
        LossyAppendUTF16toASCII(password, userpass);

    // plbase64.h provides this worst-case output buffer size calculation.
    // use calloc, since PL_Base64Encode does not null terminate.
    *creds = (char *) calloc(6 + ((userpass.Length() + 2)/3)*4 + 1, 1);
    if (!*creds)
        return NS_ERROR_OUT_OF_MEMORY;

    memcpy(*creds, "Basic ", 6);
    PL_Base64Encode(userpass.get(), userpass.Length(), *creds + 6);
    return NS_OK;
}
예제 #11
0
static
nsresult
Base64urlEncode(const PRUint8* aBytes,
                PRUint32 aNumBytes,
                nsCString& _result)
{
  // SetLength does not set aside space for NULL termination.  PL_Base64Encode
  // will not NULL terminate, however, nsCStrings must be NULL terminated.  As a
  // result, we set the capacity to be one greater than what we need, and the
  // length to our desired length.
  PRUint32 length = (aNumBytes + 2) / 3 * 4; // +2 due to integer math.
  NS_ENSURE_TRUE(_result.SetCapacity(length + 1), NS_ERROR_OUT_OF_MEMORY);
  _result.SetLength(length);
  (void)PL_Base64Encode(reinterpret_cast<const char*>(aBytes), aNumBytes,
                        _result.BeginWriting());

  // base64url encoding is defined in RFC 4648.  It replaces the last two
  // alphabet characters of base64 encoding with '-' and '_' respectively.
  _result.ReplaceChar('+', '-');
  _result.ReplaceChar('/', '_');
  return NS_OK;
}
static int do_send_mail(ews_session * session,
                        const char * content,
                        int len_content,
                        char ** pp_err_msg) {
    char * encoded_content = PL_Base64Encode(content,
                                             len_content,
                                             nullptr);

    ews_msg_item msg_item;
    memset(&msg_item, 0, sizeof(ews_msg_item));
    msg_item.item.item_type = EWS_Item_Message;
        
    msg_item.item.mime_content = encoded_content;
		
    int ret = ews_send_item(session,
                        &msg_item,
                        pp_err_msg);

    PR_Free(encoded_content);

    return ret;
}    
예제 #13
0
nsresult nsAbManager::AppendProperty(const char *aProperty, const PRUnichar *aValue, nsACString &aResult)
{
  NS_ENSURE_ARG_POINTER(aValue);

  aResult += aProperty;

  // if the string is not safe "as is", base64 encode it
  if (IsSafeLDIFString(aValue)) {
    aResult.AppendLiteral(": ");
    aResult.Append(NS_LossyConvertUTF16toASCII(aValue));
  }
  else {
    char *base64Str = PL_Base64Encode(NS_ConvertUTF16toUTF8(aValue).get(), 0, nsnull);
    if (!base64Str)
      return NS_ERROR_OUT_OF_MEMORY;

    aResult.AppendLiteral(":: ");
    aResult.Append(nsDependentCString(base64Str));
    PR_Free(base64Str);
  }

  return NS_OK;
}
NS_IMETHODIMP
nsHttpNTLMAuth::GenerateCredentials(nsIHttpAuthenticableChannel *authChannel,
                                    const char      *challenge,
                                    bool             isProxyAuth,
                                    const PRUnichar *domain,
                                    const PRUnichar *user,
                                    const PRUnichar *pass,
                                    nsISupports    **sessionState,
                                    nsISupports    **continuationState,
                                    uint32_t       *aFlags,
                                    char           **creds)

{
    LOG(("nsHttpNTLMAuth::GenerateCredentials\n"));

    *creds = nullptr;
    *aFlags = 0;

    // if user or password is empty, ChallengeReceived returned
    // identityInvalid = false, that means we are using default user
    // credentials; see  nsAuthSSPI::Init method for explanation of this
    // condition
    if (!user || !pass)
        *aFlags = USING_INTERNAL_IDENTITY;

    nsresult rv;
    nsCOMPtr<nsIAuthModule> module = do_QueryInterface(*continuationState, &rv);
    NS_ENSURE_SUCCESS(rv, rv);

    void *inBuf, *outBuf;
    uint32_t inBufLen, outBufLen;

    // initial challenge
    if (PL_strcasecmp(challenge, "NTLM") == 0) {
        // NTLM service name format is 'HTTP@host' for both http and https
        nsCOMPtr<nsIURI> uri;
        rv = authChannel->GetURI(getter_AddRefs(uri));
        if (NS_FAILED(rv))
            return rv;
        nsAutoCString serviceName, host;
        rv = uri->GetAsciiHost(host);
        if (NS_FAILED(rv))
            return rv;
        serviceName.AppendLiteral("HTTP@");
        serviceName.Append(host);
        // initialize auth module
        uint32_t reqFlags = nsIAuthModule::REQ_DEFAULT;
        if (isProxyAuth)
            reqFlags |= nsIAuthModule::REQ_PROXY_AUTH;

        rv = module->Init(serviceName.get(), reqFlags, domain, user, pass);
        if (NS_FAILED(rv))
            return rv;

// This update enables updated Windows machines (Win7 or patched previous
// versions) and Linux machines running Samba (updated for Channel
// Binding), to perform Channel Binding when authenticating using NTLMv2
// and an outer secure channel.
//
// Currently only implemented for Windows, linux support will be landing in
// a separate patch, update this #ifdef accordingly then.
#if defined (XP_WIN) /* || defined (LINUX) */
        // We should retrieve the server certificate and compute the CBT,
        // but only when we are using the native NTLM implementation and
        // not the internal one.
        // It is a valid case not having the security info object.  This
        // occures when we connect an https site through an ntlm proxy.
        // After the ssl tunnel has been created, we get here the second
        // time and now generate the CBT from now valid security info.
        nsCOMPtr<nsIChannel> channel = do_QueryInterface(authChannel, &rv);
        if (NS_FAILED(rv))
            return rv;

        nsCOMPtr<nsISupports> security;
        rv = channel->GetSecurityInfo(getter_AddRefs(security));
        if (NS_FAILED(rv))
            return rv;

        nsCOMPtr<nsISSLStatusProvider> statusProvider =
            do_QueryInterface(security);

        if (mUseNative && statusProvider) {
            nsCOMPtr<nsISSLStatus> status;
            rv = statusProvider->GetSSLStatus(getter_AddRefs(status));
            if (NS_FAILED(rv))
                return rv;

            nsCOMPtr<nsIX509Cert> cert;
            rv = status->GetServerCert(getter_AddRefs(cert));
            if (NS_FAILED(rv))
                return rv;

            uint32_t length;
            uint8_t* certArray;
            cert->GetRawDER(&length, &certArray);						
			
            // If there is a server certificate, we pass it along the
            // first time we call GetNextToken().
            inBufLen = length;
            inBuf = certArray;
        } else {
            // If there is no server certificate, we don't pass anything.
            inBufLen = 0;
            inBuf = nullptr;
        }
#else // Extended protection update is just for Linux and Windows machines.
        inBufLen = 0;
        inBuf = nullptr;
#endif
    }
    else {
        // decode challenge; skip past "NTLM " to the start of the base64
        // encoded data.
        int len = strlen(challenge);
        if (len < 6)
            return NS_ERROR_UNEXPECTED; // bogus challenge
        challenge += 5;
        len -= 5;

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

        // decode into the input secbuffer
        inBufLen = (len * 3)/4;      // sufficient size (see plbase64.h)
        inBuf = nsMemory::Alloc(inBufLen);
        if (!inBuf)
            return NS_ERROR_OUT_OF_MEMORY;

        if (PL_Base64Decode(challenge, len, (char *) inBuf) == nullptr) {
            nsMemory::Free(inBuf);
            return NS_ERROR_UNEXPECTED; // improper base64 encoding
        }
    }

    rv = module->GetNextToken(inBuf, inBufLen, &outBuf, &outBufLen);
    if (NS_SUCCEEDED(rv)) {
        // base64 encode data in output buffer and prepend "NTLM "
        int credsLen = 5 + ((outBufLen + 2)/3)*4;
        *creds = (char *) nsMemory::Alloc(credsLen + 1);
        if (!*creds)
            rv = NS_ERROR_OUT_OF_MEMORY;
        else {
            memcpy(*creds, "NTLM ", 5);
            PL_Base64Encode((char *) outBuf, outBufLen, *creds + 5);
            (*creds)[credsLen] = '\0'; // null terminate
        }
        // OK, we are done with |outBuf|
        nsMemory::Free(outBuf);
    }

    if (inBuf)
        nsMemory::Free(inBuf);

    return rv;
}
예제 #15
0
static int
SignFile(FILE *outFile, PRFileDesc *inFile, CERTCertificate *cert)
{
    SECItem data2sign;
    SECStatus rv;
    char *data;
    SECKEYPrivateKey *privKey;
    SECOidTag algID;
    PLArenaPool *arena;
    CERTSignedData sd;
    SECItem *result;

    if (outFile == NULL || inFile == NULL || cert == NULL)
        return -1;

    /* suck the file in */
    if (SECU_ReadDERFromFile(&data2sign, inFile, PR_FALSE,
                             PR_FALSE) != SECSuccess)
        return -1;

    privKey = NULL;    
    privKey = PK11_FindKeyByAnyCert(cert, NULL);

    algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, SEC_OID_SHA1);
    if (algID == SEC_OID_UNKNOWN)
        return -1;
    
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    
    PORT_Memset(&sd, 0, sizeof(CERTSignedData));
    
    rv = SEC_SignData(&(sd.signature), data2sign.data, data2sign.len, privKey, algID);
    if (rv != SECSuccess) {
        fprintf (stderr, "Could not sign.\n");
        return -1;
    }
    sd.signature.len = sd.signature.len << 3;
    
    rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, 0);
    if (rv != SECSuccess) {
        fprintf (stderr, "Could not set alg id.\n");
        return -1;
    }

    result = SEC_ASN1EncodeItem(arena, NULL, &sd, CERTSignatureDataTemplate);
    SECITEM_FreeItem(&(sd.signature), PR_FALSE);
    
    if (!result) {
        fprintf (stderr, "Could not encode.\n");
        return -1;
    }

    data = PL_Base64Encode((const char*)result->data, result->len, NULL);
    if (!data)
        return -1;
    
    fputs("signature:\n", outFile);
    fputs(data, outFile);
    fputs("\n", outFile);
    ExportPublicKey(outFile, cert);
    
    SECKEY_DestroyPrivateKey(privKey);
    PORT_FreeArena(arena, PR_FALSE);
    
    return 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 PRUnichar *domain,
                                         const PRUnichar *username,
                                         const PRUnichar *password,
                                         nsISupports **sessionState,
                                         nsISupports **continuationState,
                                         PRUint32 *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, *outToken;
    PRUint32 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--;

        inTokenLen = (len * 3)/4;
        inToken = malloc(inTokenLen);
        if (!inToken)
            return (NS_ERROR_OUT_OF_MEMORY);

        //
        // Decode the response that followed the "Negotiate" token
        //
        if (PL_Base64Decode(challenge, len, (char *) inToken) == NULL) {
            free(inToken);
            return(NS_ERROR_UNEXPECTED);
        }
    }
    else {
        //
        // Initializing, don't use an input token.
        //
        inToken = nullptr;
        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);

    nsMemory::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")
    *creds = (char *) nsMemory::Alloc(kNegotiateLen + 1 + strlen(encoded_token) + 1);
    if (NS_UNLIKELY(!*creds))
        rv = NS_ERROR_OUT_OF_MEMORY;
    else
        sprintf(*creds, "%s %s", kNegotiate, encoded_token);

    PR_Free(encoded_token);
    return rv;
}
예제 #17
0
NS_IMETHODIMP
nsHttpNTLMAuth::GenerateCredentials(nsIHttpChannel  *httpChannel,
                                    const char      *challenge,
                                    PRBool           isProxyAuth,
                                    const PRUnichar *domain,
                                    const PRUnichar *user,
                                    const PRUnichar *pass,
                                    nsISupports    **sessionState,
                                    nsISupports    **continuationState,
                                    PRUint32       *aFlags,
                                    char           **creds)

{
    LOG(("nsHttpNTLMAuth::GenerateCredentials\n"));

    *creds = nsnull;
    *aFlags = 0;

    // if user or password is empty, ChallengeReceived returned
    // identityInvalid = PR_FALSE, that means we are using default user
    // credentials; see  nsAuthSSPI::Init method for explanation of this 
    // condition
    if (!user || !pass)
        *aFlags = USING_INTERNAL_IDENTITY;

    nsresult rv;
    nsCOMPtr<nsIAuthModule> module = do_QueryInterface(*continuationState, &rv);
    NS_ENSURE_SUCCESS(rv, rv);

    void *inBuf, *outBuf;
    PRUint32 inBufLen, outBufLen;

    // initial challenge
    if (PL_strcasecmp(challenge, "NTLM") == 0) {
        // NTLM service name format is 'HTTP@host' for both http and https
        nsCOMPtr<nsIURI> uri;
        rv = httpChannel->GetURI(getter_AddRefs(uri));
        if (NS_FAILED(rv))
            return rv;
        nsCAutoString serviceName, host;
        rv = uri->GetAsciiHost(host);
        if (NS_FAILED(rv))
            return rv;
        serviceName.AppendLiteral("HTTP@");
        serviceName.Append(host);
        // initialize auth module
        rv = module->Init(serviceName.get(), nsIAuthModule::REQ_DEFAULT, domain, user, pass);
        if (NS_FAILED(rv))
            return rv;

        inBufLen = 0;
        inBuf = nsnull;
    }
    else {
        // decode challenge; skip past "NTLM " to the start of the base64
        // encoded data.
        int len = strlen(challenge);
        if (len < 6)
            return NS_ERROR_UNEXPECTED; // bogus challenge
        challenge += 5;
        len -= 5;

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

        // decode into the input secbuffer
        inBufLen = (len * 3)/4;      // sufficient size (see plbase64.h)
        inBuf = nsMemory::Alloc(inBufLen);
        if (!inBuf)
            return NS_ERROR_OUT_OF_MEMORY;

        if (PL_Base64Decode(challenge, len, (char *) inBuf) == nsnull) {
            nsMemory::Free(inBuf);
            return NS_ERROR_UNEXPECTED; // improper base64 encoding
        }
    }

    rv = module->GetNextToken(inBuf, inBufLen, &outBuf, &outBufLen);
    if (NS_SUCCEEDED(rv)) {
        // base64 encode data in output buffer and prepend "NTLM "
        int credsLen = 5 + ((outBufLen + 2)/3)*4;
        *creds = (char *) nsMemory::Alloc(credsLen + 1);
        if (!*creds)
            rv = NS_ERROR_OUT_OF_MEMORY;
        else {
            memcpy(*creds, "NTLM ", 5);
            PL_Base64Encode((char *) outBuf, outBufLen, *creds + 5);
            (*creds)[credsLen] = '\0'; // null terminate
        }
        // OK, we are done with |outBuf|
        nsMemory::Free(outBuf);
    }

    if (inBuf)
        nsMemory::Free(inBuf);

    return rv;
}